[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210723004214.912295-5-phil@philpotter.co.uk>
Date: Fri, 23 Jul 2021 01:42:11 +0100
From: Phillip Potter <phil@...lpotter.co.uk>
To: gregkh@...uxfoundation.org
Cc: Larry.Finger@...inger.net, dan.carpenter@...cle.com,
linux-kernel@...r.kernel.org, linux-staging@...ts.linux.dev,
fabioaiuto83@...il.com
Subject: [PATCH 4/7] staging: rtl8188eu: introduce new os_dep dir for RTL8188eu driver
This patchset is split in order to keep the file sizes down. This os_dep
directory is part of the newer/better driver from GitHub modified by
Larry Finger. Import this as the basis for all future work going
forward.
Suggested-by: Larry Finger <Larry.Finger@...inger.net>
Signed-off-by: Phillip Potter <phil@...lpotter.co.uk>
---
.../staging/rtl8188eu/os_dep/ioctl_cfg80211.c | 7113 +++++++++
.../staging/rtl8188eu/os_dep/ioctl_cfg80211.h | 307 +
.../staging/rtl8188eu/os_dep/ioctl_linux.c | 12398 ++++++++++++++++
drivers/staging/rtl8188eu/os_dep/ioctl_mp.c | 2028 +++
drivers/staging/rtl8188eu/os_dep/mlme_linux.c | 726 +
drivers/staging/rtl8188eu/os_dep/os_intfs.c | 4311 ++++++
.../staging/rtl8188eu/os_dep/osdep_service.c | 1731 +++
drivers/staging/rtl8188eu/os_dep/recv_linux.c | 790 +
.../staging/rtl8188eu/os_dep/rtw_android.c | 1250 ++
.../staging/rtl8188eu/os_dep/rtw_cfgvendor.c | 1330 ++
.../staging/rtl8188eu/os_dep/rtw_cfgvendor.h | 229 +
drivers/staging/rtl8188eu/os_dep/rtw_proc.c | 3216 ++++
drivers/staging/rtl8188eu/os_dep/rtw_proc.h | 49 +
drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1345 ++
.../staging/rtl8188eu/os_dep/usb_ops_linux.c | 1082 ++
drivers/staging/rtl8188eu/os_dep/wifi_regd.c | 354 +
drivers/staging/rtl8188eu/os_dep/xmit_linux.c | 489 +
17 files changed, 38748 insertions(+)
create mode 100644 drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.h
create mode 100644 drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/ioctl_mp.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/mlme_linux.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/os_intfs.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/osdep_service.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/recv_linux.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/rtw_android.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.h
create mode 100644 drivers/staging/rtl8188eu/os_dep/rtw_proc.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/rtw_proc.h
create mode 100644 drivers/staging/rtl8188eu/os_dep/usb_intf.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/wifi_regd.c
create mode 100644 drivers/staging/rtl8188eu/os_dep/xmit_linux.c
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.c
new file mode 100644
index 000000000000..1d7ff707ecad
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.c
@@ -0,0 +1,7113 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _IOCTL_CFG80211_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#ifdef CONFIG_IOCTL_CFG80211
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#define STATION_INFO_SIGNAL BIT(NL80211_STA_INFO_SIGNAL)
+#define STATION_INFO_TX_BITRATE BIT(NL80211_STA_INFO_TX_BITRATE)
+#define STATION_INFO_RX_PACKETS BIT(NL80211_STA_INFO_RX_PACKETS)
+#define STATION_INFO_TX_PACKETS BIT(NL80211_STA_INFO_TX_PACKETS)
+#define STATION_INFO_TX_FAILED BIT(NL80211_STA_INFO_TX_FAILED)
+#define STATION_INFO_ASSOC_REQ_IES 0
+#endif /* Linux kernel >= 4.0.0 */
+
+#include <rtw_wifi_regd.h>
+
+#define RTW_MAX_MGMT_TX_CNT (8)
+#define RTW_MAX_MGMT_TX_MS_GAS (500)
+
+#define RTW_SCAN_IE_LEN_MAX 2304
+#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 5000 /* ms */
+#define RTW_MAX_NUM_PMKIDS 4
+
+#define RTW_CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
+
+#ifdef CONFIG_WAPI_SUPPORT
+
+#ifndef WLAN_CIPHER_SUITE_SMS4
+#define WLAN_CIPHER_SUITE_SMS4 0x00147201
+#endif
+
+#ifndef WLAN_AKM_SUITE_WAPI_PSK
+#define WLAN_AKM_SUITE_WAPI_PSK 0x000FAC04
+#endif
+
+#ifndef WLAN_AKM_SUITE_WAPI_CERT
+#define WLAN_AKM_SUITE_WAPI_CERT 0x000FAC12
+#endif
+
+#ifndef NL80211_WAPI_VERSION_1
+#define NL80211_WAPI_VERSION_1 (1 << 2)
+#endif
+
+#endif /* CONFIG_WAPI_SUPPORT */
+
+#ifdef CONFIG_RTW_80211R
+#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03
+#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
+#endif
+
+static const u32 rtw_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+#ifdef CONFIG_WAPI_SUPPORT
+ WLAN_CIPHER_SUITE_SMS4,
+#endif /* CONFIG_WAPI_SUPPORT */
+#ifdef CONFIG_IEEE80211W
+ WLAN_CIPHER_SUITE_AES_CMAC,
+#endif /* CONFIG_IEEE80211W */
+};
+
+#define RATETAB_ENT(_rate, _rateid, _flags) \
+ { \
+ .bitrate = (_rate), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = NL80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+ }
+
+#define CHAN5G(_channel, _flags) { \
+ .band = NL80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+/* if wowlan is not supported, kernel generate a disconnect at each suspend
+ * cf: /net/wireless/sysfs.c, so register a stub wowlan.
+ * Moreover wowlan has to be enabled via a the nl80211_set_wowlan callback.
+ * (from user space, e.g. iw phy0 wowlan enable)
+ */
+static const struct wiphy_wowlan_support wowlan_stub = {
+ .flags = WIPHY_WOWLAN_ANY,
+ .n_patterns = 0,
+ .pattern_max_len = 0,
+ .pattern_min_len = 0,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
+ .max_pkt_offset = 0,
+#endif
+};
+#endif
+
+static struct ieee80211_rate rtw_rates[] = {
+ RATETAB_ENT(10, 0x1, 0),
+ RATETAB_ENT(20, 0x2, 0),
+ RATETAB_ENT(55, 0x4, 0),
+ RATETAB_ENT(110, 0x8, 0),
+ RATETAB_ENT(60, 0x10, 0),
+ RATETAB_ENT(90, 0x20, 0),
+ RATETAB_ENT(120, 0x40, 0),
+ RATETAB_ENT(180, 0x80, 0),
+ RATETAB_ENT(240, 0x100, 0),
+ RATETAB_ENT(360, 0x200, 0),
+ RATETAB_ENT(480, 0x400, 0),
+ RATETAB_ENT(540, 0x800, 0),
+};
+
+#define rtw_a_rates (rtw_rates + 4)
+#define RTW_A_RATES_NUM 8
+#define rtw_g_rates (rtw_rates + 0)
+#define RTW_G_RATES_NUM 12
+
+#define RTW_2G_CHANNELS_NUM 14
+#define RTW_5G_CHANNELS_NUM 37
+
+static struct ieee80211_channel rtw_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel rtw_5ghz_a_channels[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(149, 0),
+ CHAN5G(153, 0), CHAN5G(157, 0),
+ CHAN5G(161, 0), CHAN5G(165, 0),
+ CHAN5G(184, 0), CHAN5G(188, 0),
+ CHAN5G(192, 0), CHAN5G(196, 0),
+ CHAN5G(200, 0), CHAN5G(204, 0),
+ CHAN5G(208, 0), CHAN5G(212, 0),
+ CHAN5G(216, 0),
+};
+
+
+static void rtw_2g_channels_init(struct ieee80211_channel *channels)
+{
+ memcpy((void *)channels, (void *)rtw_2ghz_channels,
+ sizeof(struct ieee80211_channel) * RTW_2G_CHANNELS_NUM
+ );
+}
+
+static void rtw_5g_channels_init(struct ieee80211_channel *channels)
+{
+ memcpy((void *)channels, (void *)rtw_5ghz_a_channels,
+ sizeof(struct ieee80211_channel) * RTW_5G_CHANNELS_NUM
+ );
+}
+
+static void rtw_2g_rates_init(struct ieee80211_rate *rates)
+{
+ memcpy(rates, rtw_g_rates,
+ sizeof(struct ieee80211_rate) * RTW_G_RATES_NUM
+ );
+}
+
+static void rtw_5g_rates_init(struct ieee80211_rate *rates)
+{
+ memcpy(rates, rtw_a_rates,
+ sizeof(struct ieee80211_rate) * RTW_A_RATES_NUM
+ );
+}
+
+static struct ieee80211_supported_band *rtw_spt_band_alloc(
+ enum nl80211_band band
+)
+{
+ struct ieee80211_supported_band *spt_band = NULL;
+ int n_channels, n_bitrates;
+
+ if (band == NL80211_BAND_2GHZ) {
+ n_channels = RTW_2G_CHANNELS_NUM;
+ n_bitrates = RTW_G_RATES_NUM;
+ } else if (band == NL80211_BAND_5GHZ) {
+ n_channels = RTW_5G_CHANNELS_NUM;
+ n_bitrates = RTW_A_RATES_NUM;
+ } else
+ goto exit;
+
+ spt_band = (struct ieee80211_supported_band *)rtw_zmalloc(
+ sizeof(struct ieee80211_supported_band)
+ + sizeof(struct ieee80211_channel) * n_channels
+ + sizeof(struct ieee80211_rate) * n_bitrates
+ );
+ if (!spt_band)
+ goto exit;
+
+ spt_band->channels = (struct ieee80211_channel *)(((u8 *)spt_band) + sizeof(struct ieee80211_supported_band));
+ spt_band->bitrates = (struct ieee80211_rate *)(((u8 *)spt_band->channels) + sizeof(struct ieee80211_channel) * n_channels);
+ spt_band->band = band;
+ spt_band->n_channels = n_channels;
+ spt_band->n_bitrates = n_bitrates;
+
+ if (band == NL80211_BAND_2GHZ) {
+ rtw_2g_channels_init(spt_band->channels);
+ rtw_2g_rates_init(spt_band->bitrates);
+ } else if (band == NL80211_BAND_5GHZ) {
+ rtw_5g_channels_init(spt_band->channels);
+ rtw_5g_rates_init(spt_band->bitrates);
+ }
+
+ /* spt_band.ht_cap */
+
+exit:
+
+ return spt_band;
+}
+
+static void rtw_spt_band_free(struct ieee80211_supported_band *spt_band)
+{
+ u32 size = 0;
+
+ if (!spt_band)
+ return;
+
+#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
+ if (spt_band->band == NL80211_BAND_2GHZ) {
+#else
+ if (spt_band->band == IEEE80211_BAND_2GHZ) {
+#endif
+ size = sizeof(struct ieee80211_supported_band)
+ + sizeof(struct ieee80211_channel) * RTW_2G_CHANNELS_NUM
+ + sizeof(struct ieee80211_rate) * RTW_G_RATES_NUM;
+#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
+ } else if (spt_band->band == NL80211_BAND_5GHZ) {
+#else
+ } else if (spt_band->band == IEEE80211_BAND_5GHZ) {
+#endif
+ size = sizeof(struct ieee80211_supported_band)
+ + sizeof(struct ieee80211_channel) * RTW_5G_CHANNELS_NUM
+ + sizeof(struct ieee80211_rate) * RTW_A_RATES_NUM;
+ } else {
+
+ }
+ rtw_mfree((u8 *)spt_band, size);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+static const struct ieee80211_txrx_stypes
+ rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ /* copy AP */
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+#if defined(RTW_DEDICATED_P2P_DEVICE)
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+#endif
+};
+#endif
+
+static u64 rtw_get_systime_us(void)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0))
+ u64 ts;
+ ts = ktime_get_boottime();
+ return do_div(ts, 1000);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ struct timespec ts;
+ get_monotonic_boottime(&ts);
+ return ((u64)ts.tv_sec * 1000000) + ts.tv_nsec / 1000;
+#else
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ return ((u64)tv.tv_sec * 1000000) + tv.tv_usec;
+#endif
+}
+
+/* Try to remove non target BSS's SR to reduce PBC overlap rate */
+static int rtw_cfg80211_clear_wps_sr_of_non_target_bss(_adapter *padapter, struct wlan_network *pnetwork, struct cfg80211_ssid *req_ssid)
+{
+ struct rtw_wdev_priv *wdev_data = adapter_wdev_data(padapter);
+ int ret = 0;
+ u8 *psr = NULL, sr = 0;
+ NDIS_802_11_SSID *pssid = &pnetwork->network.Ssid;
+ u32 wpsielen = 0;
+ u8 *wpsie = NULL;
+
+ if (pssid->SsidLength == req_ssid->ssid_len
+ && !memcmp(pssid->Ssid, req_ssid->ssid, req_ssid->ssid_len) )
+ goto exit;
+
+ wpsie = rtw_get_wps_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_
+ , pnetwork->network.IELength - _FIXED_IE_LENGTH_, NULL, &wpsielen);
+ if (wpsie && wpsielen > 0)
+ psr = rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_SELECTED_REGISTRAR, &sr, NULL);
+
+ if (psr && sr) {
+ if (0)
+ RTW_INFO("clear sr of non target bss:%s("MAC_FMT")\n"
+ , pssid->Ssid, MAC_ARG(pnetwork->network.MacAddress));
+ *psr = 0; /* clear sr */
+ ret = 1;
+ }
+
+exit:
+ return ret;
+}
+
+#define MAX_BSSINFO_LEN 1000
+struct cfg80211_bss *rtw_cfg80211_inform_bss(_adapter *padapter, struct wlan_network *pnetwork)
+{
+ struct ieee80211_channel *notify_channel;
+ struct cfg80211_bss *bss = NULL;
+ /* struct ieee80211_supported_band *band; */
+ u16 channel;
+ u32 freq;
+ u64 notify_timestamp;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+ /* u8 buf[MAX_BSSINFO_LEN]; */
+
+ u8 *pbuf;
+ size_t buf_size = MAX_BSSINFO_LEN;
+ size_t len, bssinf_len = 0;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ __le16 *fctrl;
+ u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ struct wireless_dev *wdev = padapter->rtw_wdev;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ pbuf = rtw_zmalloc(buf_size);
+ if (pbuf == NULL) {
+ RTW_INFO("%s pbuf allocate failed !!\n", __func__);
+ return bss;
+ }
+
+ /* RTW_INFO("%s\n", __func__); */
+
+ bssinf_len = pnetwork->network.IELength + sizeof(struct rtw_ieee80211_hdr_3addr);
+ if (bssinf_len > buf_size) {
+ RTW_INFO("%s IE Length too long > %zu byte\n", __func__, buf_size);
+ goto exit;
+ }
+
+#ifndef CONFIG_WAPI_SUPPORT
+ {
+ u16 wapi_len = 0;
+
+ if (rtw_get_wapi_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &wapi_len) > 0) {
+ if (wapi_len > 0) {
+ RTW_INFO("%s, no support wapi!\n", __func__);
+ goto exit;
+ }
+ }
+ }
+#endif /* !CONFIG_WAPI_SUPPORT */
+
+ channel = pnetwork->network.Configuration.DSConfig;
+ freq = rtw_ch2freq(channel);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_timestamp = rtw_get_systime_us();
+
+ notify_interval = le16_to_cpu(*(__le16 *)rtw_get_beacon_interval_from_ie(pnetwork->network.IEs));
+ notify_capability = le16_to_cpu(*(__le16 *)rtw_get_capability_from_ie(pnetwork->network.IEs));
+
+ notify_ie = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
+ notify_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
+
+ /* We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm) */
+ if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) {
+ notify_signal = 100 * translate_percentage_to_dbm(padapter->recvpriv.signal_strength); /* dbm */
+ } else {
+ notify_signal = 100 * translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength); /* dbm */
+ }
+
+ /* pbuf = buf; */
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pbuf;
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+ /* pmlmeext->mgnt_seq++; */
+
+ if (pnetwork->network.Reserved[0] == 1) { /* WIFI_BEACON */
+ memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+ set_frame_sub_type(pbuf, WIFI_BEACON);
+ } else {
+ memcpy(pwlanhdr->addr1, adapter_mac_addr(padapter), ETH_ALEN);
+ set_frame_sub_type(pbuf, WIFI_PROBERSP);
+ }
+
+ memcpy(pwlanhdr->addr2, pnetwork->network.MacAddress, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->network.MacAddress, ETH_ALEN);
+
+
+ /* pbuf += sizeof(struct rtw_ieee80211_hdr_3addr); */
+ len = sizeof(struct rtw_ieee80211_hdr_3addr);
+ memcpy((pbuf + len), pnetwork->network.IEs, pnetwork->network.IELength);
+ *((__le64 *)(pbuf + len)) = cpu_to_le64(notify_timestamp);
+
+ len += pnetwork->network.IELength;
+
+ #if defined(CONFIG_P2P) && 0
+ if(rtw_get_p2p_ie(pnetwork->network.IEs+12, pnetwork->network.IELength-12, NULL, NULL))
+ RTW_INFO("%s, got p2p_ie\n", __func__);
+ #endif
+
+ bss = cfg80211_inform_bss_frame(wiphy, notify_channel, (struct ieee80211_mgmt *)pbuf,
+ len, notify_signal, GFP_ATOMIC);
+ if (unlikely(!bss)) {
+ RTW_INFO(FUNC_ADPT_FMT" bss NULL\n", FUNC_ADPT_ARG(padapter));
+ goto exit;
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38))
+#ifndef COMPAT_KERNEL_RELEASE
+ /* patch for cfg80211, update beacon ies to information_elements */
+ if (pnetwork->network.Reserved[0] == 1) { /* WIFI_BEACON */
+
+ if (bss->len_information_elements != bss->len_beacon_ies) {
+ bss->information_elements = bss->beacon_ies;
+ bss->len_information_elements = bss->len_beacon_ies;
+ }
+ }
+#endif /* COMPAT_KERNEL_RELEASE */
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif
+
+exit:
+ if (pbuf)
+ rtw_mfree(pbuf, buf_size);
+ return bss;
+
+}
+
+/*
+ Check the given bss is valid by kernel API cfg80211_get_bss()
+ @padapter : the given adapter
+
+ return true if bss is valid, false for not found.
+*/
+int rtw_cfg80211_check_bss(_adapter *padapter)
+{
+ WLAN_BSSID_EX *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network);
+ struct cfg80211_bss *bss = NULL;
+ struct ieee80211_channel *notify_channel = NULL;
+ u32 freq;
+
+ if (!(pnetwork) || !(padapter->rtw_wdev))
+ return false;
+
+ freq = rtw_ch2freq(pnetwork->Configuration.DSConfig);
+ notify_channel = ieee80211_get_channel(padapter->rtw_wdev->wiphy, freq);
+ bss = cfg80211_get_bss(padapter->rtw_wdev->wiphy, notify_channel,
+ pnetwork->MacAddress, pnetwork->Ssid.Ssid,
+ pnetwork->Ssid.SsidLength,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ pnetwork->InfrastructureMode == Ndis802_11Infrastructure?IEEE80211_BSS_TYPE_ESS:IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY(pnetwork->Privacy));
+#else
+ pnetwork->InfrastructureMode == Ndis802_11Infrastructure?WLAN_CAPABILITY_ESS:WLAN_CAPABILITY_IBSS, pnetwork->InfrastructureMode == Ndis802_11Infrastructure?WLAN_CAPABILITY_ESS:WLAN_CAPABILITY_IBSS);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif
+
+ return bss != NULL;
+}
+
+void rtw_cfg80211_ibss_indicate_connect(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct wireless_dev *pwdev = padapter->rtw_wdev;
+ struct cfg80211_bss *bss = NULL;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+ struct wiphy *wiphy = pwdev->wiphy;
+ int freq = 2412;
+ struct ieee80211_channel *notify_channel;
+#endif
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+ freq = rtw_ch2freq(cur_network->network.Configuration.DSConfig);
+
+ if (0)
+ RTW_INFO("chan: %d, freq: %d\n", cur_network->network.Configuration.DSConfig, freq);
+#endif
+
+ if (pwdev->iftype != NL80211_IFTYPE_ADHOC)
+ return;
+
+ if (!rtw_cfg80211_check_bss(padapter)) {
+ WLAN_BSSID_EX *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network);
+ struct wlan_network *scanned = pmlmepriv->cur_network_scanned;
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ) {
+
+ memcpy(&cur_network->network, pnetwork, sizeof(WLAN_BSSID_EX));
+ if (cur_network) {
+ if (!rtw_cfg80211_inform_bss(padapter, cur_network))
+ RTW_INFO(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter));
+ else
+ RTW_INFO(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter));
+ } else {
+ RTW_INFO("cur_network is not exist!!!\n");
+ return ;
+ }
+ } else {
+ if (scanned == NULL)
+ rtw_warn_on(1);
+
+ if (!memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID))
+ && !memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS))
+ ) {
+ if (!rtw_cfg80211_inform_bss(padapter, scanned))
+ RTW_INFO(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter));
+ else {
+ /* RTW_INFO(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */
+ }
+ } else {
+ RTW_INFO("scanned & pnetwork compare fail\n");
+ rtw_warn_on(1);
+ }
+ }
+
+ if (!rtw_cfg80211_check_bss(padapter))
+ RTW_INFO(FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter));
+ }
+ /* notify cfg80211 that device joined an IBSS */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+ cfg80211_ibss_joined(padapter->pnetdev, cur_network->network.MacAddress, notify_channel, GFP_ATOMIC);
+#else
+ cfg80211_ibss_joined(padapter->pnetdev, cur_network->network.MacAddress, GFP_ATOMIC);
+#endif
+}
+
+void rtw_cfg80211_indicate_connect(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct wireless_dev *pwdev = padapter->rtw_wdev;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif
+ struct cfg80211_bss *bss = NULL;
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+ if (pwdev->iftype != NL80211_IFTYPE_STATION
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT
+ #endif
+ )
+ return;
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) )
+ return;
+
+#ifdef CONFIG_P2P
+ if (pwdinfo->driver_interface == DRIVER_CFG80211) {
+ #if !RTW_P2P_GROUP_INTERFACE
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ RTW_INFO("%s, role=%d, p2p_state=%d, pre_p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo));
+ }
+ #endif
+ }
+#endif /* CONFIG_P2P */
+
+ if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) != true) {
+ WLAN_BSSID_EX *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network);
+ struct wlan_network *scanned = pmlmepriv->cur_network_scanned;
+
+ /* RTW_INFO(FUNC_ADPT_FMT" BSS not found\n", FUNC_ADPT_ARG(padapter)); */
+
+ if (scanned == NULL) {
+ rtw_warn_on(1);
+ goto check_bss;
+ }
+
+ if (!memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS))
+ && !memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID))
+ ) {
+ if (!rtw_cfg80211_inform_bss(padapter, scanned))
+ RTW_INFO(FUNC_ADPT_FMT" inform fail !!\n", FUNC_ADPT_ARG(padapter));
+ else {
+ /* RTW_INFO(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */
+ }
+ } else {
+ RTW_INFO("scanned: %s("MAC_FMT"), cur: %s("MAC_FMT")\n",
+ scanned->network.Ssid.Ssid, MAC_ARG(scanned->network.MacAddress),
+ pnetwork->Ssid.Ssid, MAC_ARG(pnetwork->MacAddress)
+ );
+ rtw_warn_on(1);
+ }
+ }
+
+check_bss:
+ if (!rtw_cfg80211_check_bss(padapter))
+ RTW_INFO(FUNC_ADPT_FMT" BSS not found !!\n", FUNC_ADPT_ARG(padapter));
+
+ if (rtw_to_roam(padapter) > 0) {
+ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) || defined(COMPAT_KERNEL_RELEASE)
+ struct wiphy *wiphy = pwdev->wiphy;
+ struct ieee80211_channel *notify_channel;
+ u32 freq;
+ u16 channel = cur_network->network.Configuration.DSConfig;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+ struct cfg80211_roam_info roam_info = {};
+#endif
+
+ freq = rtw_ch2freq(channel);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+ #endif
+
+ RTW_INFO(FUNC_ADPT_FMT" call cfg80211_roamed\n", FUNC_ADPT_ARG(padapter));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))
+ roam_info.channel = notify_channel;
+ roam_info.bssid = cur_network->network.MacAddress;
+ roam_info.req_ie =
+ pmlmepriv->assoc_req+sizeof(struct rtw_ieee80211_hdr_3addr)+2;
+ roam_info.req_ie_len =
+ pmlmepriv->assoc_req_len-sizeof(struct rtw_ieee80211_hdr_3addr)-2;
+ roam_info.resp_ie =
+ pmlmepriv->assoc_rsp+sizeof(struct rtw_ieee80211_hdr_3addr)+6;
+ roam_info.resp_ie_len =
+ pmlmepriv->assoc_rsp_len-sizeof(struct rtw_ieee80211_hdr_3addr)-6;
+ cfg80211_roamed(padapter->pnetdev, &roam_info, GFP_ATOMIC);
+#else
+ cfg80211_roamed(padapter->pnetdev
+ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) || defined(COMPAT_KERNEL_RELEASE)
+ , notify_channel
+ #endif
+ , cur_network->network.MacAddress
+ , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2
+ , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2
+ , pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6
+ , pmlmepriv->assoc_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6
+ , GFP_ATOMIC);
+#endif
+#ifdef CONFIG_RTW_80211R
+ if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED))
+ rtw_set_ft_status(padapter, RTW_FT_ASSOCIATED_STA);
+#endif
+ } else {
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) || defined(COMPAT_KERNEL_RELEASE)
+ RTW_INFO("pwdev->sme_state(b)=%d\n", pwdev->sme_state);
+ #endif
+ cfg80211_connect_result(padapter->pnetdev, cur_network->network.MacAddress
+ , pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + 2
+ , pmlmepriv->assoc_req_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 2
+ , pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6
+ , pmlmepriv->assoc_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6
+ , WLAN_STATUS_SUCCESS, GFP_ATOMIC);
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) || defined(COMPAT_KERNEL_RELEASE)
+ RTW_INFO("pwdev->sme_state(a)=%d\n", pwdev->sme_state);
+ #endif
+ }
+}
+
+void rtw_cfg80211_indicate_disconnect(_adapter *padapter, u16 reason, u8 locally_generated)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wireless_dev *pwdev = padapter->rtw_wdev;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+ /*always replace privated definitions with wifi reserved value 0*/
+ if ((reason == WLAN_REASON_ACTIVE_ROAM) || (reason == WLAN_REASON_JOIN_WRONG_CHANNEL) || (reason == WLAN_REASON_EXPIRATION_CHK))
+ reason = 0;
+
+ if (pwdev->iftype != NL80211_IFTYPE_STATION
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ && pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT
+ #endif
+ )
+ return;
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) )
+ return;
+
+#ifdef CONFIG_P2P
+ if (pwdinfo->driver_interface == DRIVER_CFG80211) {
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ if (pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ #endif
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+
+ RTW_INFO("%s, role=%d, p2p_state=%d, pre_p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo));
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ #ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ if (!padapter->mlmepriv.not_indic_disco || padapter->ndev_unregistering) {
+ #else
+ {
+ #endif
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) || defined(COMPAT_KERNEL_RELEASE)
+ RTW_INFO("pwdev->sme_state(b)=%d\n", pwdev->sme_state);
+
+ if (pwdev->sme_state == CFG80211_SME_CONNECTING)
+ cfg80211_connect_result(padapter->pnetdev, NULL, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_ATOMIC/*GFP_KERNEL*/);
+ else if (pwdev->sme_state == CFG80211_SME_CONNECTED) {
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+ cfg80211_disconnected(padapter->pnetdev, reason, NULL, 0, locally_generated, GFP_ATOMIC);
+ #else
+ cfg80211_disconnected(padapter->pnetdev, 0, NULL, 0, GFP_ATOMIC);
+ #endif
+ }
+ RTW_INFO("pwdev->sme_state(a)=%d\n", pwdev->sme_state);
+ #else
+
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+ RTW_INFO(FUNC_ADPT_FMT" call cfg80211_disconnected\n", FUNC_ADPT_ARG(padapter));
+ cfg80211_disconnected(padapter->pnetdev, reason, NULL, 0, locally_generated, GFP_ATOMIC);
+ #else
+ RTW_INFO(FUNC_ADPT_FMT" call cfg80211_disconnected\n", FUNC_ADPT_ARG(padapter));
+ cfg80211_disconnected(padapter->pnetdev, 0, NULL, 0, GFP_ATOMIC);
+ #endif
+ } else {
+ RTW_INFO(FUNC_ADPT_FMT" call cfg80211_connect_result\n", FUNC_ADPT_ARG(padapter));
+ cfg80211_connect_result(padapter->pnetdev, NULL, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_ATOMIC);
+ }
+ #endif
+ }
+}
+
+
+#ifdef CONFIG_AP_MODE
+static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+ int ret = 0;
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ struct sta_info *psta = NULL, *pbcmc_sta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ RTW_INFO("%s\n", __func__);
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ /* sizeof(struct ieee_param) = 64 bytes; */
+ /* if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) */
+ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS
+#ifdef CONFIG_IEEE80211W
+ && param->u.crypt.idx > BIP_MAX_KEYID
+#endif /* CONFIG_IEEE80211W */
+ ) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (!psta) {
+ /* ret = -EINVAL; */
+ RTW_INFO("rtw_set_encryption(), sta has already been removed or never been added\n");
+ goto exit;
+ }
+ }
+
+ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) {
+ /* todo:clear default encryption keys */
+
+ RTW_INFO("clear default encryption keys, keyid=%d\n", param->u.crypt.idx);
+
+ goto exit;
+ }
+
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) {
+ RTW_INFO("r871x_set_encryption, crypt.alg = WEP\n");
+
+ wep_key_idx = param->u.crypt.idx;
+ wep_key_len = param->u.crypt.key_len;
+
+ RTW_INFO("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);
+
+ if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (wep_key_len > 0)
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+
+ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
+ /* wep default key has not been set, so use this key index as default key. */
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+ if (wep_key_len == 13) {
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ }
+
+ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+ }
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len;
+
+ rtw_ap_set_wep_key(padapter, param->u.crypt.key, wep_key_len, wep_key_idx, 1);
+
+ goto exit;
+
+ }
+
+
+ if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /* group key */
+ if (param->u.crypt.set_tx == 0) { /* group key */
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RTW_INFO("%s, set group_key, WEP\n", __func__);
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ RTW_INFO("%s, set group_key, TKIP\n", __func__);
+
+ psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ /* DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); */
+ /* set mic key */
+ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ RTW_INFO("%s, set group_key, CCMP\n", __func__);
+
+ psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ }
+#ifdef CONFIG_IEEE80211W
+ else if (strcmp(param->u.crypt.alg, "BIP") == 0) {
+ int no;
+
+ RTW_INFO("BIP key_len=%d , index=%d\n", param->u.crypt.key_len, param->u.crypt.idx);
+ /* save the IGTK key, length 16 bytes */
+ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ /* RTW_INFO("IGTK key below:\n");
+ for(no=0;no<16;no++)
+ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
+ RTW_INFO("\n"); */
+ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx;
+ padapter->securitypriv.binstallBIPkey = true;
+ RTW_INFO(" ~~~~set sta key:IGKT\n");
+ goto exit;
+ }
+#endif /* CONFIG_IEEE80211W */
+ else {
+ RTW_INFO("%s, set group_key, none\n", __func__);
+
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ }
+
+ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+ psecuritypriv->binstallGrpkey = true;
+
+ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* !!! */
+
+ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta) {
+ pbcmc_sta->ieee8021x_blocked = false;
+ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; /* rx will use bmc_sta's dot118021XPrivacy */
+ }
+
+ }
+
+ goto exit;
+
+ }
+
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ if (param->u.crypt.set_tx == 1) { /* pairwise key */
+ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RTW_INFO("%s, set pairwise key, WEP\n", __func__);
+
+ psta->dot118021XPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psta->dot118021XPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ RTW_INFO("%s, set pairwise key, TKIP\n", __func__);
+
+ psta->dot118021XPrivacy = _TKIP_;
+
+ /* DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); */
+ /* set mic key */
+ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+
+ RTW_INFO("%s, set pairwise key, CCMP\n", __func__);
+
+ psta->dot118021XPrivacy = _AES_;
+ } else {
+ RTW_INFO("%s, set pairwise key, none\n", __func__);
+
+ psta->dot118021XPrivacy = _NO_PRIVACY_;
+ }
+
+ rtw_ap_set_pairwise_key(padapter, psta);
+
+ psta->ieee8021x_blocked = false;
+
+ psta->bpairwise_key_installed = true;
+
+ } else { /* group key??? */
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ /* DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); */
+ /* set mic key */
+ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ } else
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+
+ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+ psecuritypriv->binstallGrpkey = true;
+
+ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* !!! */
+
+ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta) {
+ pbcmc_sta->ieee8021x_blocked = false;
+ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; /* rx will use bmc_sta's dot118021XPrivacy */
+ }
+
+ }
+
+ }
+
+ }
+
+exit:
+
+ return ret;
+
+}
+#endif
+
+static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+ int ret = 0;
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_P2P */
+
+
+ RTW_INFO("%s\n", __func__);
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ if (param_len < (u32)((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS
+#ifdef CONFIG_IEEE80211W
+ && param->u.crypt.idx > BIP_MAX_KEYID
+#endif /* CONFIG_IEEE80211W */
+ ) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+#ifdef CONFIG_WAPI_SUPPORT
+ if (strcmp(param->u.crypt.alg, "SMS4"))
+#endif
+ {
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RTW_INFO("wpa_set_encryption, crypt.alg = WEP\n");
+
+ wep_key_idx = param->u.crypt.idx;
+ wep_key_len = param->u.crypt.key_len;
+
+ if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
+ /* wep default key has not been set, so use this key index as default key. */
+
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+ if (wep_key_len == 13) {
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ }
+
+ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+ }
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len;
+
+ rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0, true);
+
+ goto exit;
+ }
+
+ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */
+ struct sta_info *psta, *pbcmc_sta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ /* RTW_INFO("%s, : dot11AuthAlgrthm == dot11AuthAlgrthm_8021X\n", __func__); */
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) ) { /* sta mode */
+#ifdef CONFIG_RTW_80211R
+ if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED))
+ psta = rtw_get_stainfo(pstapriv, pmlmepriv->assoc_bssid);
+ else
+#endif
+ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+ if (psta == NULL) {
+ /* DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
+ RTW_INFO("%s, : Obtain Sta_info fail\n", __func__);
+ } else {
+ /* Jeff: don't disable ieee8021x_blocked while clearing key */
+ if (strcmp(param->u.crypt.alg, "none") != 0)
+ psta->ieee8021x_blocked = false;
+
+
+ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled))
+ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+ if (param->u.crypt.set_tx == 1) { /* pairwise key */
+
+ RTW_INFO("%s, : param->u.crypt.set_tx ==1\n", __func__);
+
+ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
+ /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); */
+ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+ padapter->securitypriv.busetkipkey = false;
+ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
+ }
+ psta->bpairwise_key_installed = true;
+#ifdef CONFIG_RTW_80211R
+ psta->ft_pairwise_key_installed = true;
+#endif
+ /* DEBUG_ERR((" param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); */
+ RTW_INFO(" ~~~~set sta key:unicastkey\n");
+
+ rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, true);
+ } else { /* group key */
+ if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key,
+ (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+ padapter->securitypriv.binstallGrpkey = true;
+ if (param->u.crypt.idx < 4)
+ memcpy(padapter->securitypriv.iv_seq[param->u.crypt.idx], param->u.crypt.seq, 8);
+
+ /* DEBUG_ERR((" param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); */
+ RTW_INFO(" ~~~~set sta key:groupkey\n");
+
+ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
+ rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true);
+ }
+#ifdef CONFIG_IEEE80211W
+ else if (strcmp(param->u.crypt.alg, "BIP") == 0) {
+ int no;
+ /* RTW_INFO("BIP key_len=%d , index=%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */
+ /* save the IGTK key, length 16 bytes */
+ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key,
+ (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ /*RTW_INFO("IGTK key below:\n");
+ for(no=0;no<16;no++)
+ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
+ RTW_INFO("\n");*/
+ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx;
+ padapter->securitypriv.binstallBIPkey = true;
+ RTW_INFO(" ~~~~set sta key:IGKT\n");
+ }
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_P2P
+ if (pwdinfo->driver_interface == DRIVER_CFG80211) {
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE);
+ }
+#endif /* CONFIG_P2P */
+
+ }
+ }
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta == NULL) {
+ /* DEBUG_ERR( ("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */
+ } else {
+ /* Jeff: don't disable ieee8021x_blocked while clearing key */
+ if (strcmp(param->u.crypt.alg, "none") != 0)
+ pbcmc_sta->ieee8021x_blocked = false;
+
+ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled))
+ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+ }
+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { /* adhoc mode */
+ }
+ }
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (strcmp(param->u.crypt.alg, "SMS4") == 0) {
+ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo;
+ PRT_WAPI_STA_INFO pWapiSta;
+ u8 WapiASUEPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+ u8 WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+
+ if (param->u.crypt.set_tx == 1) {
+ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
+ if (!memcmp(pWapiSta->PeerMacAddr, param->sta_addr, 6)) {
+ memcpy(pWapiSta->lastTxUnicastPN, WapiASUEPNInitialValueSrc, 16);
+
+ pWapiSta->wapiUsk.bSet = true;
+ memcpy(pWapiSta->wapiUsk.dataKey, param->u.crypt.key, 16);
+ memcpy(pWapiSta->wapiUsk.micKey, param->u.crypt.key + 16, 16);
+ pWapiSta->wapiUsk.keyId = param->u.crypt.idx ;
+ pWapiSta->wapiUsk.bTxEnable = true;
+
+ memcpy(pWapiSta->lastRxUnicastPNBEQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPNBKQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPNVIQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPNVOQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPN, WapiAEPNInitialValueSrc, 16);
+ pWapiSta->wapiUskUpdate.bTxEnable = false;
+ pWapiSta->wapiUskUpdate.bSet = false;
+
+ if (psecuritypriv->sw_encrypt == false || psecuritypriv->sw_decrypt == false) {
+ /* set unicast key for ASUE */
+ rtw_wapi_set_key(padapter, &pWapiSta->wapiUsk, pWapiSta, false, false);
+ }
+ }
+ }
+ } else {
+ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
+ if (!memcmp(pWapiSta->PeerMacAddr, get_bssid(pmlmepriv), 6)) {
+ pWapiSta->wapiMsk.bSet = true;
+ memcpy(pWapiSta->wapiMsk.dataKey, param->u.crypt.key, 16);
+ memcpy(pWapiSta->wapiMsk.micKey, param->u.crypt.key + 16, 16);
+ pWapiSta->wapiMsk.keyId = param->u.crypt.idx ;
+ pWapiSta->wapiMsk.bTxEnable = false;
+ if (!pWapiSta->bSetkeyOk)
+ pWapiSta->bSetkeyOk = true;
+ pWapiSta->bAuthenticateInProgress = false;
+
+ memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16);
+
+ if (psecuritypriv->sw_decrypt == false) {
+ /* set rx broadcast key for ASUE */
+ rtw_wapi_set_key(padapter, &pWapiSta->wapiMsk, pWapiSta, true, false);
+ }
+ }
+
+ }
+ }
+ }
+#endif
+
+
+exit:
+
+ RTW_INFO("%s, ret=%d\n", __func__, ret);
+
+
+ return ret;
+}
+
+static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+ u8 key_index, const u8 *mac_addr,
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+ struct key_params *params)
+{
+ char *alg_name;
+ u32 param_len;
+ struct ieee_param *param = NULL;
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct wireless_dev *rtw_wdev = padapter->rtw_wdev;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#ifdef CONFIG_TDLS
+ struct sta_info *ptdls_sta;
+#endif /* CONFIG_TDLS */
+
+ RTW_INFO(FUNC_NDEV_FMT" adding key for %pM\n", FUNC_NDEV_ARG(ndev), mac_addr);
+ RTW_INFO("cipher=0x%x\n", params->cipher);
+ RTW_INFO("key_len=0x%x\n", params->key_len);
+ RTW_INFO("seq_len=0x%x\n", params->seq_len);
+ RTW_INFO("key_index=%d\n", key_index);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ RTW_INFO("pairwise=%d\n", pairwise);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+
+ param_len = sizeof(struct ieee_param) + params->key_len;
+ param = (struct ieee_param *)rtw_malloc(param_len);
+ if (param == NULL)
+ return -1;
+
+ memset(param, 0, param_len);
+
+ param->cmd = IEEE_CMD_SET_ENCRYPTION;
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+
+ switch (params->cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ /* todo: remove key */
+ /* remove = 1; */
+ alg_name = "none";
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ alg_name = "WEP";
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ alg_name = "CCMP";
+ break;
+#ifdef CONFIG_IEEE80211W
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ alg_name = "BIP";
+ break;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WAPI_SUPPORT
+ case WLAN_CIPHER_SUITE_SMS4:
+ alg_name = "SMS4";
+ if (pairwise == NL80211_KEYTYPE_PAIRWISE) {
+ if (key_index != 0 && key_index != 1) {
+ ret = -ENOTSUPP;
+ goto addkey_end;
+ }
+ memcpy((void *)param->sta_addr, (void *)mac_addr, ETH_ALEN);
+ } else
+ RTW_INFO("mac_addr is null\n");
+ RTW_INFO("rtw_wx_set_enc_ext: SMS4 case\n");
+ break;
+#endif
+
+ default:
+ ret = -ENOTSUPP;
+ goto addkey_end;
+ }
+
+ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+
+
+ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+ param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */
+ } else {
+ param->u.crypt.set_tx = 1; /* for wpa/wpa2 pairwise key */
+ }
+
+
+ /* param->u.crypt.idx = key_index - 1; */
+ param->u.crypt.idx = key_index;
+
+ if (params->seq_len && params->seq)
+ memcpy(param->u.crypt.seq, (u8 *)params->seq, params->seq_len);
+
+ if (params->key_len && params->key) {
+ param->u.crypt.key_len = params->key_len;
+ memcpy(param->u.crypt.key, (u8 *)params->key, params->key_len);
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) ) {
+#ifdef CONFIG_TDLS
+ if (rtw_tdls_is_driver_setup(padapter) == false && mac_addr) {
+ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, (void *)mac_addr);
+ if (ptdls_sta != NULL && ptdls_sta->tdls_sta_state) {
+ memcpy(ptdls_sta->tpk.tk, params->key, params->key_len);
+ rtw_tdls_set_key(padapter, ptdls_sta);
+ goto addkey_end;
+ }
+ }
+#endif /* CONFIG_TDLS */
+
+ ret = rtw_cfg80211_set_encryption(ndev, param, param_len);
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) ) {
+#ifdef CONFIG_AP_MODE
+ if (mac_addr)
+ memcpy(param->sta_addr, (void *)mac_addr, ETH_ALEN);
+
+ ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len);
+#endif
+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)
+ || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)
+ ) {
+ /* RTW_INFO("@@@@@@@@@@ fw_state=0x%x, iftype=%d\n", pmlmepriv->fw_state, rtw_wdev->iftype); */
+ ret = rtw_cfg80211_set_encryption(ndev, param, param_len);
+ } else
+ RTW_INFO("error! fw_state=0x%x, iftype=%d\n", pmlmepriv->fw_state, rtw_wdev->iftype);
+
+
+addkey_end:
+ if (param)
+ rtw_mfree((u8 *)param, param_len);
+
+ return ret;
+
+}
+
+static int cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+ u8 key_index, const u8 *mac_addr,
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+ void *cookie,
+ void (*callback)(void *cookie, struct key_params *))
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+ return 0;
+}
+
+static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ u8 key_index, bool pairwise, const u8 *mac_addr)
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+ u8 key_index, const u8 *mac_addr)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) */
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ RTW_INFO(FUNC_NDEV_FMT" key_index=%d\n", FUNC_NDEV_ARG(ndev), key_index);
+
+ if (key_index == psecuritypriv->dot11PrivacyKeyIndex) {
+ /* clear the flag of wep default key set. */
+ psecuritypriv->bWepDefaultKeyIdxSet = 0;
+ }
+
+ return 0;
+}
+
+static int cfg80211_rtw_set_default_key(struct wiphy *wiphy,
+ struct net_device *ndev, u8 key_index
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+ , bool unicast, bool multicast
+ #endif
+)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+#define SET_DEF_KEY_PARAM_FMT " key_index=%d"
+#define SET_DEF_KEY_PARAM_ARG , key_index
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+ #define SET_DEF_KEY_PARAM_FMT_2_6_38 ", unicast=%d, multicast=%d"
+ #define SET_DEF_KEY_PARAM_ARG_2_6_38 , unicast, multicast
+#else
+ #define SET_DEF_KEY_PARAM_FMT_2_6_38 ""
+ #define SET_DEF_KEY_PARAM_ARG_2_6_38
+#endif
+
+ RTW_INFO(FUNC_NDEV_FMT
+ SET_DEF_KEY_PARAM_FMT
+ SET_DEF_KEY_PARAM_FMT_2_6_38
+ "\n", FUNC_NDEV_ARG(ndev)
+ SET_DEF_KEY_PARAM_ARG
+ SET_DEF_KEY_PARAM_ARG_2_6_38
+ );
+
+ if ((key_index < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) { /* set wep default key */
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+ psecuritypriv->dot11PrivacyKeyIndex = key_index;
+
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (psecuritypriv->dot11DefKeylen[key_index] == 13) {
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ }
+
+ psecuritypriv->bWepDefaultKeyIdxSet = 1; /* set the flag to represent that wep default key has been set */
+ }
+
+ return 0;
+
+}
+#if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
+static int cfg80211_rtw_set_rekey_data(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_gtk_rekey_data *data)
+{
+ /*int i;*/
+ struct sta_info *psta;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+
+ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+ if (psta == NULL) {
+ RTW_INFO("%s, : Obtain Sta_info fail\n", __func__);
+ return -1;
+ }
+
+ memcpy(psta->kek, data->kek, NL80211_KEK_LEN);
+ /*printk("\ncfg80211_rtw_set_rekey_data KEK:");
+ for(i=0;i<NL80211_KEK_LEN; i++)
+ printk(" %02x ", psta->kek[i]);*/
+ memcpy(psta->kck, data->kck, NL80211_KCK_LEN);
+ /*printk("\ncfg80211_rtw_set_rekey_data KCK:");
+ for(i=0;i<NL80211_KCK_LEN; i++)
+ printk(" %02x ", psta->kck[i]);*/
+ memcpy(psta->replay_ctr, data->replay_ctr, NL80211_REPLAY_CTR_LEN);
+ psecuritypriv->binstallKCK_KEK = true;
+ /*printk("\nREPLAY_CTR: ");
+ for(i=0;i<RTW_REPLAY_CTR_LEN; i++)
+ printk(" %02x ", psta->replay_ctr[i]);*/
+
+ return 0;
+}
+#endif /*CONFIG_GTK_OL*/
+static int cfg80211_rtw_get_station(struct wiphy *wiphy,
+ struct net_device *ndev,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0))
+ u8 *mac,
+#else
+ const u8 *mac,
+#endif
+ struct station_info *sinfo)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ sinfo->filled = 0;
+
+ if (!mac) {
+ RTW_INFO(FUNC_NDEV_FMT" mac==%p\n", FUNC_NDEV_ARG(ndev), mac);
+ ret = -ENOENT;
+ goto exit;
+ }
+
+ psta = rtw_get_stainfo(pstapriv, (u8 *)mac);
+ if (psta == NULL) {
+ RTW_INFO("%s, sta_info is null\n", __func__);
+ ret = -ENOENT;
+ goto exit;
+ }
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO(FUNC_NDEV_FMT" mac="MAC_FMT"\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac));
+#endif
+
+ /* for infra./P2PClient mode */
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
+ && check_fwstate(pmlmepriv, _FW_LINKED)
+ ) {
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+
+ if (!memcmp((u8 *)mac, cur_network->network.MacAddress, ETH_ALEN) == false) {
+ RTW_INFO("%s, mismatch bssid="MAC_FMT"\n", __func__, MAC_ARG(cur_network->network.MacAddress));
+ ret = -ENOENT;
+ goto exit;
+ }
+
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength);
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter);
+
+ sinfo->filled |= STATION_INFO_RX_PACKETS;
+ sinfo->rx_packets = sta_rx_data_pkts(psta);
+
+ sinfo->filled |= STATION_INFO_TX_PACKETS;
+ sinfo->tx_packets = psta->sta_stats.tx_pkts;
+
+ sinfo->filled |= STATION_INFO_TX_FAILED;
+ sinfo->tx_failed = psta->sta_stats.tx_fail_cnt;
+
+ }
+
+ /* for Ad-Hoc/AP mode */
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)
+ || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)
+ || check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ && check_fwstate(pmlmepriv, _FW_LINKED)
+ ) {
+ /* TODO: should acquire station info... */
+ }
+
+exit:
+ return ret;
+}
+
+extern int netdev_open(struct net_device *pnetdev);
+
+static int cfg80211_rtw_change_iface(struct wiphy *wiphy,
+ struct net_device *ndev,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
+ enum nl80211_iftype type, u32 *flags,
+#else
+ enum nl80211_iftype type,
+#endif
+ struct vif_params *params)
+{
+ enum nl80211_iftype old_type;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct wireless_dev *rtw_wdev = padapter->rtw_wdev;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 is_p2p = false;
+#endif
+ int ret = 0;
+ u8 change = false;
+
+ RTW_INFO(FUNC_NDEV_FMT" type=%d, hw_port:%d\n", FUNC_NDEV_ARG(ndev), type, padapter->hw_port);
+
+ if (adapter_to_dvobj(padapter)->processing_dev_remove ) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+
+ RTW_INFO(FUNC_NDEV_FMT" call netdev_open\n", FUNC_NDEV_ARG(ndev));
+ if (netdev_open(ndev) != 0) {
+ RTW_INFO(FUNC_NDEV_FMT" call netdev_open fail\n", FUNC_NDEV_ARG(ndev));
+ ret = -EPERM;
+ goto exit;
+ }
+
+
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ RTW_INFO(FUNC_NDEV_FMT" call rtw_pwr_wakeup fail\n", FUNC_NDEV_ARG(ndev));
+ ret = -EPERM;
+ goto exit;
+ }
+
+ old_type = rtw_wdev->iftype;
+ RTW_INFO(FUNC_NDEV_FMT" old_iftype=%d, new_iftype=%d\n",
+ FUNC_NDEV_ARG(ndev), old_type, type);
+
+ if (old_type != type) {
+ change = true;
+ pmlmeext->action_public_rxseq = 0xffff;
+ pmlmeext->action_public_dialog_token = 0xff;
+ }
+
+ /* initial default type */
+ ndev->type = ARPHRD_ETHER;
+
+ /*
+ * Disable Power Save in moniter mode,
+ * and enable it after leaving moniter mode.
+ */
+ if (type == NL80211_IFTYPE_MONITOR) {
+ rtw_ps_deny(padapter, PS_DENY_MONITOR_MODE);
+ LeaveAllPowerSaveMode(padapter);
+ } else if (old_type == NL80211_IFTYPE_MONITOR) {
+ /* driver in moniter mode in last time */
+ rtw_ps_deny_cancel(padapter, PS_DENY_MONITOR_MODE);
+ }
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ networkType = Ndis802_11IBSS;
+ break;
+
+ #if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ case NL80211_IFTYPE_P2P_CLIENT:
+ is_p2p = true;
+ __attribute__ ((__fallthrough__));/* FALL THRU */
+ #endif
+ case NL80211_IFTYPE_STATION:
+ networkType = Ndis802_11Infrastructure;
+
+ #ifdef CONFIG_P2P
+ if (change && pwdinfo->driver_interface == DRIVER_CFG80211) {
+ if (is_p2p )
+ rtw_p2p_enable(padapter, P2P_ROLE_CLIENT);
+ #if !RTW_P2P_GROUP_INTERFACE
+ else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)
+ || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)
+ ) {
+ /* it means remove GC/GO and change mode from GC/GO to station(P2P DEVICE) */
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+ }
+ #endif
+ }
+ #endif /* CONFIG_P2P */
+
+ break;
+
+ #if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ case NL80211_IFTYPE_P2P_GO:
+ is_p2p = true;
+ __attribute__ ((__fallthrough__));/* FALL THRU */
+ #endif
+ case NL80211_IFTYPE_AP:
+ networkType = Ndis802_11APMode;
+
+ #ifdef CONFIG_P2P
+ if (change && pwdinfo->driver_interface == DRIVER_CFG80211) {
+ if (is_p2p )
+ rtw_p2p_enable(padapter, P2P_ROLE_GO);
+ #if !RTW_P2P_GROUP_INTERFACE
+ else if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ /* it means P2P Group created, we will be GO and change mode from P2P DEVICE to AP(GO) */
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ }
+ #endif
+ }
+ #endif /* CONFIG_P2P */
+
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ networkType = Ndis802_11Monitor;
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP; /* IEEE 802.11 + radiotap header : 803 */
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ rtw_wdev->iftype = type;
+
+ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) {
+ rtw_wdev->iftype = old_type;
+ ret = -EPERM;
+ goto exit;
+ }
+
+ rtw_setopmode_cmd(padapter, networkType, true);
+
+exit:
+
+ RTW_INFO(FUNC_NDEV_FMT" ret:%d\n", FUNC_NDEV_ARG(ndev), ret);
+ return ret;
+}
+
+void rtw_cfg80211_indicate_scan_done(_adapter *adapter, bool aborted)
+{
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
+ unsigned long irqL;
+
+#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
+ struct cfg80211_scan_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.aborted = aborted;
+#endif
+
+ _enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+ if (pwdev_priv->scan_request != NULL) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s with scan req\n", __func__);
+ #endif
+
+ /* avoid WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); */
+ if (pwdev_priv->scan_request->wiphy != pwdev_priv->rtw_wdev->wiphy)
+ RTW_INFO("error wiphy compare\n");
+ else
+#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
+ cfg80211_scan_done(pwdev_priv->scan_request, &info);
+#else
+ cfg80211_scan_done(pwdev_priv->scan_request, aborted);
+#endif
+
+ pwdev_priv->scan_request = NULL;
+ } else {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s without scan req\n", __func__);
+ #endif
+ }
+ _exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+}
+
+u32 rtw_cfg80211_wait_scan_req_empty(_adapter *adapter, u32 timeout_ms)
+{
+ struct rtw_wdev_priv *wdev_priv = adapter_wdev_data(adapter);
+ u8 empty = false;
+ u32 start;
+ u32 pass_ms;
+
+ start = jiffies;
+
+ while (rtw_get_passing_time_ms(start) <= timeout_ms) {
+
+ if (RTW_CANNOT_RUN(adapter))
+ break;
+
+ if (!wdev_priv->scan_request) {
+ empty = true;
+ break;
+ }
+
+ rtw_msleep_os(10);
+ }
+
+ pass_ms = rtw_get_passing_time_ms(start);
+
+ if (empty == false && pass_ms > timeout_ms)
+ RTW_INFO(FUNC_ADPT_FMT" pass_ms:%u, timeout\n"
+ , FUNC_ADPT_ARG(adapter), pass_ms);
+
+ return pass_ms;
+}
+
+void rtw_cfg80211_unlink_bss(_adapter *padapter, struct wlan_network *pnetwork)
+{
+ struct wireless_dev *pwdev = padapter->rtw_wdev;
+ struct wiphy *wiphy = pwdev->wiphy;
+ struct cfg80211_bss *bss = NULL;
+ WLAN_BSSID_EX select_network = pnetwork->network;
+
+ bss = cfg80211_get_bss(wiphy, NULL/*notify_channel*/,
+ select_network.MacAddress, select_network.Ssid.Ssid,
+ select_network.Ssid.SsidLength,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+ select_network.InfrastructureMode == Ndis802_11Infrastructure?IEEE80211_BSS_TYPE_ESS:IEEE80211_BSS_TYPE_IBSS,
+ IEEE80211_PRIVACY(select_network.Privacy));
+#else
+ select_network.InfrastructureMode == Ndis802_11Infrastructure?WLAN_CAPABILITY_ESS:WLAN_CAPABILITY_IBSS,
+ select_network.InfrastructureMode == Ndis802_11Infrastructure?WLAN_CAPABILITY_ESS:WLAN_CAPABILITY_IBSS);
+#endif
+
+ if (bss) {
+ cfg80211_unlink_bss(wiphy, bss);
+ RTW_INFO("%s(): cfg80211_unlink %s!! () ", __func__, select_network.Ssid.Ssid);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif
+ }
+ return;
+}
+
+/* if target wps scan ongoing, target_ssid is filled */
+static int rtw_cfg80211_is_target_wps_scan(struct cfg80211_scan_request *scan_req, struct cfg80211_ssid *target_ssid)
+{
+ int ret = 0;
+
+ if (scan_req->n_ssids != 1
+ || scan_req->ssids[0].ssid_len == 0
+ || scan_req->n_channels != 1
+ )
+ goto exit;
+
+ /* under target WPS scan */
+ memcpy(target_ssid, scan_req->ssids, sizeof(struct cfg80211_ssid));
+ ret = 1;
+
+exit:
+ return ret;
+}
+
+static void _rtw_cfg80211_surveydone_event_callback(_adapter *padapter, struct cfg80211_scan_request *scan_req)
+{
+ unsigned long irqL;
+ _list *plist, *phead;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u32 cnt = 0;
+ u32 wait_for_surveydone;
+ sint wait_status;
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
+ struct cfg80211_ssid target_ssid;
+ u8 target_wps_scan = 0;
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s\n", __func__);
+#endif
+
+ if (scan_req)
+ target_wps_scan = rtw_cfg80211_is_target_wps_scan(scan_req, &target_ssid);
+ else {
+ _enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+ if (pwdev_priv->scan_request != NULL)
+ target_wps_scan = rtw_cfg80211_is_target_wps_scan(pwdev_priv->scan_request, &target_ssid);
+ _exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+ }
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* report network only if the current channel set contains the channel to which this network belongs */
+ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0
+ && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig)
+ && rtw_validate_ssid(&(pnetwork->network.Ssid))
+ ) {
+ if (target_wps_scan)
+ rtw_cfg80211_clear_wps_sr_of_non_target_bss(padapter, pnetwork, &target_ssid);
+ rtw_cfg80211_inform_bss(padapter, pnetwork);
+ }
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+}
+
+inline void rtw_cfg80211_surveydone_event_callback(_adapter *padapter)
+{
+ _rtw_cfg80211_surveydone_event_callback(padapter, NULL);
+}
+
+static int rtw_cfg80211_set_probe_req_wpsp2pie(_adapter *padapter, char *buf, int len)
+{
+ int ret = 0;
+ uint wps_ielen = 0;
+ u8 *wps_ie;
+ u32 p2p_ielen = 0;
+ u8 *p2p_ie;
+ u32 wfd_ielen = 0;
+ u8 *wfd_ie;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, ielen=%d\n", __func__, len);
+#endif
+
+ if (len > 0) {
+ wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen);
+ if (wps_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("probe_req_wps_ielen=%d\n", wps_ielen);
+ #endif
+
+ if (pmlmepriv->wps_probe_req_ie) {
+ u32 free_len = pmlmepriv->wps_probe_req_ie_len;
+ pmlmepriv->wps_probe_req_ie_len = 0;
+ rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len);
+ pmlmepriv->wps_probe_req_ie = NULL;
+ }
+
+ pmlmepriv->wps_probe_req_ie = rtw_malloc(wps_ielen);
+ if (pmlmepriv->wps_probe_req_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+ memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen);
+ pmlmepriv->wps_probe_req_ie_len = wps_ielen;
+ }
+
+ /* buf += wps_ielen; */
+ /* len -= wps_ielen; */
+
+ #ifdef CONFIG_P2P
+ p2p_ie = rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ struct wifidirect_info *wdinfo = &padapter->wdinfo;
+ u32 attr_contentlen = 0;
+ u8 listen_ch_attr[5];
+
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("probe_req_p2p_ielen=%d\n", p2p_ielen);
+ #endif
+
+ if (pmlmepriv->p2p_probe_req_ie) {
+ u32 free_len = pmlmepriv->p2p_probe_req_ie_len;
+ pmlmepriv->p2p_probe_req_ie_len = 0;
+ rtw_mfree(pmlmepriv->p2p_probe_req_ie, free_len);
+ pmlmepriv->p2p_probe_req_ie = NULL;
+ }
+
+ pmlmepriv->p2p_probe_req_ie = rtw_malloc(p2p_ielen);
+ if (pmlmepriv->p2p_probe_req_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+ memcpy(pmlmepriv->p2p_probe_req_ie, p2p_ie, p2p_ielen);
+ pmlmepriv->p2p_probe_req_ie_len = p2p_ielen;
+
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, (u8 *)listen_ch_attr, (uint *) &attr_contentlen)
+ && attr_contentlen == 5) {
+ if (wdinfo->listen_channel != listen_ch_attr[4]) {
+ RTW_INFO(FUNC_ADPT_FMT" listen channel - country:%c%c%c, class:%u, ch:%u\n",
+ FUNC_ADPT_ARG(padapter), listen_ch_attr[0], listen_ch_attr[1], listen_ch_attr[2],
+ listen_ch_attr[3], listen_ch_attr[4]);
+ wdinfo->listen_channel = listen_ch_attr[4];
+ }
+ }
+ }
+ #endif /* CONFIG_P2P */
+
+ #ifdef CONFIG_WFD
+ wfd_ie = rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("probe_req_wfd_ielen=%d\n", wfd_ielen);
+ #endif
+
+ if (rtw_mlme_update_wfd_ie_data(pmlmepriv, MLME_PROBE_REQ_IE, wfd_ie, wfd_ielen) != _SUCCESS)
+ return -EINVAL;
+ }
+ #endif /* CONFIG_WFD */
+ }
+
+ return ret;
+
+}
+
+#ifdef CONFIG_CONCURRENT_MODE
+u8 rtw_cfg80211_scan_via_buddy(_adapter *padapter, struct cfg80211_scan_request *request)
+{
+ int i;
+ u8 ret = false;
+ _adapter *iface = NULL;
+ unsigned long irqL;
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ struct mlme_priv *buddy_mlmepriv;
+ struct rtw_wdev_priv *buddy_wdev_priv;
+
+ iface = dvobj->padapters[i];
+ if (iface == NULL)
+ continue;
+
+ if (iface == padapter)
+ continue;
+
+ if (rtw_is_adapter_up(iface) == false)
+ continue;
+
+ buddy_mlmepriv = &iface->mlmepriv;
+ if (!check_fwstate(buddy_mlmepriv, _FW_UNDER_SURVEY))
+ continue;
+
+ buddy_wdev_priv = adapter_wdev_data(iface);
+ _enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+ _enter_critical_bh(&buddy_wdev_priv->scan_req_lock, &irqL);
+ if (buddy_wdev_priv->scan_request) {
+ pmlmepriv->scanning_via_buddy_intf = true;
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ pwdev_priv->scan_request = request;
+ ret = true;
+ }
+ _exit_critical_bh(&buddy_wdev_priv->scan_req_lock, &irqL);
+ _exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+
+ if (ret )
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+void rtw_cfg80211_indicate_scan_done_for_buddy(_adapter *padapter, bool bscan_aborted)
+{
+ int i;
+ u8 ret = 0;
+ _adapter *iface = NULL;
+ unsigned long irqL;
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct mlme_priv *mlmepriv;
+ struct rtw_wdev_priv *wdev_priv;
+ bool indicate_buddy_scan;
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if ((iface) && rtw_is_adapter_up(iface)) {
+
+ if (iface == padapter)
+ continue;
+
+ mlmepriv = &(iface->mlmepriv);
+ wdev_priv = adapter_wdev_data(iface);
+
+ indicate_buddy_scan = false;
+ _enter_critical_bh(&wdev_priv->scan_req_lock, &irqL);
+ if (wdev_priv->scan_request && mlmepriv->scanning_via_buddy_intf ) {
+ mlmepriv->scanning_via_buddy_intf = false;
+ clr_fwstate(mlmepriv, _FW_UNDER_SURVEY);
+ indicate_buddy_scan = true;
+ }
+ _exit_critical_bh(&wdev_priv->scan_req_lock, &irqL);
+
+ if (indicate_buddy_scan ) {
+ rtw_cfg80211_surveydone_event_callback(iface);
+ rtw_indicate_scan_done(iface, bscan_aborted);
+ }
+
+ }
+ }
+}
+#endif /* CONFIG_CONCURRENT_MODE */
+
+static int cfg80211_rtw_scan(struct wiphy *wiphy
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+ , struct net_device *ndev
+ #endif
+ , struct cfg80211_scan_request *request)
+{
+ int i, chan_num = 0;
+ u8 _status = false;
+ int ret = 0;
+ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT];
+ struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+ struct rtw_ieee80211_channel *pch;
+ unsigned long irqL;
+ u8 *wps_ie = NULL;
+ uint wps_ielen = 0;
+ u8 *p2p_ie = NULL;
+ uint p2p_ielen = 0;
+ u8 survey_times = 3;
+ u8 survey_times_for_one_ch = 6;
+ struct cfg80211_ssid *ssids = request->ssids;
+ int social_channel = 0, j = 0;
+ bool need_indicate_scan_done = false;
+ bool ps_denied = false;
+
+ _adapter *padapter;
+ struct wireless_dev *wdev;
+ struct rtw_wdev_priv *pwdev_priv;
+ struct mlme_priv *pmlmepriv;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo;
+#endif /* CONFIG_P2P */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ wdev = request->wdev;
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ if (wdev == wiphy_to_pd_wdev(wiphy))
+ padapter = wiphy_to_adapter(wiphy);
+ else
+ #endif
+ if (wdev_to_ndev(wdev))
+ padapter = (_adapter *)rtw_netdev_priv(wdev_to_ndev(wdev));
+ else {
+ ret = -EINVAL;
+ goto exit;
+ }
+#else
+ if (ndev == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ padapter = (_adapter *)rtw_netdev_priv(ndev);
+ wdev = ndev_to_wdev(ndev);
+#endif
+
+ pwdev_priv = adapter_wdev_data(padapter);
+ pmlmepriv = &padapter->mlmepriv;
+#ifdef CONFIG_P2P
+ pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_P2P */
+
+ RTW_INFO(FUNC_ADPT_FMT"%s\n", FUNC_ADPT_ARG(padapter)
+ , wdev == wiphy_to_pd_wdev(wiphy) ? " PD" : "");
+
+#ifdef CONFIG_MP_INCLUDED
+ if (rtw_mi_mp_mode_check(padapter)) {
+ RTW_INFO("MP mode block Scan request\n");
+ ret = -EPERM;
+ goto exit;
+ }
+#endif
+
+ if (adapter_wdev_data(padapter)->block_scan ) {
+ RTW_INFO(FUNC_ADPT_FMT" wdev_priv.block_scan is set\n", FUNC_ADPT_ARG(padapter));
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+ }
+
+ rtw_ps_deny(padapter, PS_DENY_SCAN);
+ ps_denied = true;
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+ }
+
+#ifdef CONFIG_P2P
+ if (pwdinfo->driver_interface == DRIVER_CFG80211) {
+ if (ssids->ssid != NULL
+ && !memcmp(ssids->ssid, "DIRECT-", 7)
+ && rtw_get_p2p_ie((u8 *)request->ie, request->ie_len, NULL, NULL)
+ ) {
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ rtw_p2p_enable(padapter, P2P_ROLE_DEVICE);
+ else {
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo));
+ #endif
+ }
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+
+ if (request->n_channels == 3 &&
+ request->channels[0]->hw_value == 1 &&
+ request->channels[1]->hw_value == 6 &&
+ request->channels[2]->hw_value == 11
+ )
+ social_channel = 1;
+ }
+ }
+#endif /*CONFIG_P2P*/
+
+ if (request->ie && request->ie_len > 0)
+ rtw_cfg80211_set_probe_req_wpsp2pie(padapter, (u8 *)request->ie, request->ie_len);
+
+ if (rtw_is_scan_deny(padapter)) {
+ RTW_INFO(FUNC_ADPT_FMT ": scan deny\n", FUNC_ADPT_ARG(padapter));
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+ }
+
+ /* check fw state*/
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) ) {
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO(FUNC_ADPT_FMT" under WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter));
+#endif
+
+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS | _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ) {
+ RTW_INFO("%s, fwstate=0x%x\n", __func__, pmlmepriv->fw_state);
+
+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS))
+ RTW_INFO("AP mode process WPS\n");
+
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+ }
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) ) {
+ RTW_INFO("%s, fwstate=0x%x\n", __func__, pmlmepriv->fw_state);
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+ } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) ) {
+ RTW_INFO("%s, fwstate=0x%x\n", __func__, pmlmepriv->fw_state);
+ ret = -EBUSY;
+ goto check_need_indicate_scan_done;
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_LINKING | WIFI_UNDER_WPS)) {
+ RTW_INFO("%s exit due to buddy_intf's mlme state under linking or wps\n", __func__);
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+
+ } else if (rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_SURVEY)) {
+ bool scan_via_buddy = rtw_cfg80211_scan_via_buddy(padapter, request);
+
+ if (scan_via_buddy == false)
+ need_indicate_scan_done = true;
+
+ goto check_need_indicate_scan_done;
+ }
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ /* busy traffic check*/
+ if (rtw_mi_busy_traffic_check(padapter, true)) {
+ need_indicate_scan_done = true;
+ goto check_need_indicate_scan_done;
+ }
+
+#ifdef CONFIG_P2P
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+ rtw_free_network_queue(padapter, true);
+
+ if (social_channel == 0)
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+ else
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_SOCIAL_LAST);
+ }
+#endif /* CONFIG_P2P */
+
+
+ memset(ssid, 0, sizeof(NDIS_802_11_SSID) * RTW_SSID_SCAN_AMOUNT);
+ /* parsing request ssids, n_ssids */
+ for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("ssid=%s, len=%d\n", ssids[i].ssid, ssids[i].ssid_len);
+ #endif
+ memcpy(ssid[i].Ssid, ssids[i].ssid, ssids[i].ssid_len);
+ ssid[i].SsidLength = ssids[i].ssid_len;
+ }
+
+ /* parsing channels, n_channels */
+ memset(ch, 0, sizeof(struct rtw_ieee80211_channel) * RTW_CHANNEL_SCAN_AMOUNT);
+ for (i = 0; i < request->n_channels && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO(FUNC_ADPT_FMT CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(request->channels[i]));
+ #endif
+ ch[i].hw_value = request->channels[i]->hw_value;
+ ch[i].flags = request->channels[i]->flags;
+ }
+
+ if (request->n_channels == 1) {
+ for (i = 1; i < survey_times_for_one_ch; i++)
+ memcpy(&ch[i], &ch[0], sizeof(struct rtw_ieee80211_channel));
+ pch = ch;
+ chan_num = survey_times_for_one_ch;
+ } else if (request->n_channels <= 4) {
+ for (j = request->n_channels - 1; j >= 0; j--)
+ for (i = 0; i < survey_times; i++)
+ memcpy(&ch[j * survey_times + i], &ch[j], sizeof(struct rtw_ieee80211_channel));
+ pch = ch;
+ chan_num = survey_times * request->n_channels;
+ } else {
+ pch = ch;
+ chan_num = request->n_channels;
+ }
+
+ _enter_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ _status = rtw_sitesurvey_cmd(padapter, ssid, RTW_SSID_SCAN_AMOUNT, pch, chan_num);
+ if (_status == _SUCCESS)
+ pwdev_priv->scan_request = request;
+ else
+ ret = -1;
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ _exit_critical_bh(&pwdev_priv->scan_req_lock, &irqL);
+
+check_need_indicate_scan_done:
+ if (need_indicate_scan_done) {
+#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
+ struct cfg80211_scan_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.aborted = 0;
+#endif
+ _rtw_cfg80211_surveydone_event_callback(padapter, request);
+#if (KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE)
+ cfg80211_scan_done(request, &info);
+#else
+ cfg80211_scan_done(request, 0);
+#endif
+ }
+
+cancel_ps_deny:
+ if (ps_denied )
+ rtw_ps_deny_cancel(padapter, PS_DENY_SCAN);
+
+exit:
+ return ret;
+
+}
+
+static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ RTW_INFO("%s\n", __func__);
+ return 0;
+}
+
+
+
+static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, u32 wpa_version)
+{
+ RTW_INFO("%s, wpa_version=%d\n", __func__, wpa_version);
+
+ if (!wpa_version) {
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+ return 0;
+ }
+
+
+ if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK;
+
+ #ifdef CONFIG_WAPI_SUPPORT
+ if (wpa_version & NL80211_WAPI_VERSION_1)
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeWAPI;
+ #endif
+
+ return 0;
+
+}
+
+static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv,
+ enum nl80211_auth_type sme_auth_type)
+{
+ RTW_INFO("%s, nl80211_auth_type=%d\n", __func__, sme_auth_type);
+
+
+ switch (sme_auth_type) {
+ case NL80211_AUTHTYPE_AUTOMATIC:
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+
+ break;
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+
+ if (psecuritypriv->ndisauthtype > Ndis802_11AuthModeWPA)
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWAPI)
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI;
+#endif
+
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+
+ break;
+ default:
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+ /* return -ENOTSUPP; */
+ }
+
+ return 0;
+
+}
+
+static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 cipher, bool ucast)
+{
+ u32 ndisencryptstatus = Ndis802_11EncryptionDisabled;
+
+ u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm :
+ &psecuritypriv->dot118021XGrpPrivacy;
+
+ RTW_INFO("%s, ucast=%d, cipher=0x%x\n", __func__, ucast, cipher);
+
+
+ if (!cipher) {
+ *profile_cipher = _NO_PRIVACY_;
+ psecuritypriv->ndisencryptstatus = ndisencryptstatus;
+ return 0;
+ }
+
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ *profile_cipher = _NO_PRIVACY_;
+ ndisencryptstatus = Ndis802_11EncryptionDisabled;
+#ifdef CONFIG_WAPI_SUPPORT
+ if (psecuritypriv->dot11PrivacyAlgrthm == _SMS4_)
+ *profile_cipher = _SMS4_;
+#endif
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *profile_cipher = _WEP40_;
+ ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *profile_cipher = _WEP104_;
+ ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *profile_cipher = _TKIP_;
+ ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *profile_cipher = _AES_;
+ ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+#ifdef CONFIG_WAPI_SUPPORT
+ case WLAN_CIPHER_SUITE_SMS4:
+ *profile_cipher = _SMS4_;
+ ndisencryptstatus = Ndis802_11_EncrypteionWAPI;
+ break;
+#endif
+ default:
+ RTW_INFO("Unsupported cipher: 0x%x\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ if (ucast) {
+ psecuritypriv->ndisencryptstatus = ndisencryptstatus;
+
+ /* if(psecuritypriv->dot11PrivacyAlgrthm >= _AES_) */
+ /* psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; */
+ }
+
+ return 0;
+}
+
+static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv, u32 key_mgt)
+{
+ RTW_INFO("%s, key_mgt=0x%x\n", __func__, key_mgt);
+
+ if (key_mgt == WLAN_AKM_SUITE_8021X) {
+ /* *auth_type = UMAC_AUTH_TYPE_8021X; */
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ psecuritypriv->rsn_akm_suite_type = 1;
+ } else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ psecuritypriv->rsn_akm_suite_type = 2;
+ }
+#ifdef CONFIG_WAPI_SUPPORT
+ else if (key_mgt == WLAN_AKM_SUITE_WAPI_PSK)
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI;
+ else if (key_mgt == WLAN_AKM_SUITE_WAPI_CERT)
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI;
+#endif
+#ifdef CONFIG_RTW_80211R
+ else if (key_mgt == WLAN_AKM_SUITE_FT_8021X) {
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ psecuritypriv->rsn_akm_suite_type = 3;
+ } else if (key_mgt == WLAN_AKM_SUITE_FT_PSK) {
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ psecuritypriv->rsn_akm_suite_type = 4;
+ }
+#endif
+ else {
+ RTW_INFO("Invalid key mgt: 0x%x\n", key_mgt);
+ /* return -EINVAL; */
+ }
+
+ return 0;
+}
+
+static int rtw_cfg80211_set_wpa_ie(_adapter *padapter, u8 *pie, size_t ielen)
+{
+ u8 *buf = NULL, *pos = NULL;
+ u32 left;
+ int group_cipher = 0, pairwise_cipher = 0;
+ int ret = 0;
+ int wpa_ielen = 0;
+ int wpa2_ielen = 0;
+ u8 *pwpa, *pwpa2;
+ u8 null_addr[] = {0, 0, 0, 0, 0, 0};
+
+ if (pie == NULL || !ielen) {
+ /* Treat this as normal case, but need to clear WIFI_UNDER_WPS */
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ goto exit;
+ }
+
+ if (ielen > MAX_WPA_IE_LEN + MAX_WPS_IE_LEN + MAX_P2P_IE_LEN) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ buf = rtw_zmalloc(ielen);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(buf, pie , ielen);
+
+ /* dump */
+ {
+ int i;
+ RTW_INFO("set wpa_ie(length:%zu):\n", ielen);
+ for (i = 0; i < ielen; i = i + 8)
+ RTW_INFO("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]);
+ }
+
+ pos = buf;
+ if (ielen < RSN_HEADER_LEN) {
+ ret = -1;
+ goto exit;
+ }
+
+ pwpa = rtw_get_wpa_ie(buf, &wpa_ielen, ielen);
+ if (pwpa && wpa_ielen > 0) {
+ if (rtw_parse_wpa_ie(pwpa, wpa_ielen + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
+ memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], wpa_ielen + 2);
+
+ RTW_INFO("got wpa_ie, wpa_ielen:%u\n", wpa_ielen);
+ }
+ }
+
+ pwpa2 = rtw_get_wpa2_ie(buf, &wpa2_ielen, ielen);
+ if (pwpa2 && wpa2_ielen > 0) {
+ if (rtw_parse_wpa2_ie(pwpa2, wpa2_ielen + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
+ memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], wpa2_ielen + 2);
+
+ RTW_INFO("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen);
+ }
+ }
+
+ if (group_cipher == 0)
+ group_cipher = WPA_CIPHER_NONE;
+ if (pairwise_cipher == 0)
+ pairwise_cipher = WPA_CIPHER_NONE;
+
+ switch (group_cipher) {
+ case WPA_CIPHER_NONE:
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ break;
+ case WPA_CIPHER_WEP40:
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WPA_CIPHER_TKIP:
+ padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WPA_CIPHER_CCMP:
+ padapter->securitypriv.dot118021XGrpPrivacy = _AES_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ case WPA_CIPHER_WEP104:
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ }
+
+ switch (pairwise_cipher) {
+ case WPA_CIPHER_NONE:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ break;
+ case WPA_CIPHER_WEP40:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WPA_CIPHER_TKIP:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WPA_CIPHER_CCMP:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _AES_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ case WPA_CIPHER_WEP104:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ }
+
+ {/* handle wps_ie */
+ uint wps_ielen;
+ u8 *wps_ie;
+
+ wps_ie = rtw_get_wps_ie(buf, ielen, NULL, &wps_ielen);
+ if (wps_ie && wps_ielen > 0) {
+ RTW_INFO("got wps_ie, wps_ielen:%u\n", wps_ielen);
+ padapter->securitypriv.wps_ie_len = wps_ielen < MAX_WPS_IE_LEN ? wps_ielen : MAX_WPS_IE_LEN;
+ memcpy(padapter->securitypriv.wps_ie, wps_ie, padapter->securitypriv.wps_ie_len);
+ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ } else
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ }
+
+ #ifdef CONFIG_P2P
+ {/* check p2p_ie for assoc req; */
+ uint p2p_ielen = 0;
+ u8 *p2p_ie;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ p2p_ie = rtw_get_p2p_ie(buf, ielen, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s p2p_assoc_req_ielen=%d\n", __func__, p2p_ielen);
+ #endif
+
+ if (pmlmepriv->p2p_assoc_req_ie) {
+ u32 free_len = pmlmepriv->p2p_assoc_req_ie_len;
+ pmlmepriv->p2p_assoc_req_ie_len = 0;
+ rtw_mfree(pmlmepriv->p2p_assoc_req_ie, free_len);
+ pmlmepriv->p2p_assoc_req_ie = NULL;
+ }
+
+ pmlmepriv->p2p_assoc_req_ie = rtw_malloc(p2p_ielen);
+ if (pmlmepriv->p2p_assoc_req_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ goto exit;
+ }
+ memcpy(pmlmepriv->p2p_assoc_req_ie, p2p_ie, p2p_ielen);
+ pmlmepriv->p2p_assoc_req_ie_len = p2p_ielen;
+ }
+ }
+ #endif /* CONFIG_P2P */
+
+ #ifdef CONFIG_WFD
+ {
+ uint wfd_ielen = 0;
+ u8 *wfd_ie;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ wfd_ie = rtw_get_wfd_ie(buf, ielen, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s wfd_assoc_req_ielen=%d\n", __func__, wfd_ielen);
+ #endif
+
+ if (rtw_mlme_update_wfd_ie_data(pmlmepriv, MLME_ASSOC_REQ_IE, wfd_ie, wfd_ielen) != _SUCCESS)
+ goto exit;
+ }
+ }
+ #endif /* CONFIG_WFD */
+
+ /* TKIP and AES disallow multicast packets until installing group key */
+ if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_
+ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_
+ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
+ /* WPS open need to enable multicast */
+ /* || check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) ) */
+ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr);
+
+
+exit:
+ if (buf)
+ rtw_mfree(buf, ielen);
+ if (ret)
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+
+ return ret;
+}
+
+static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_ibss_params *params)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ NDIS_802_11_SSID ndis_ssid;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ struct cfg80211_chan_def *pch_def;
+#endif
+ struct ieee80211_channel *pch;
+ int ret = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ pch_def = (struct cfg80211_chan_def *)(¶ms->chandef);
+ pch = (struct ieee80211_channel *) pch_def->chan;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+ pch = (struct ieee80211_channel *)(params->channel);
+#endif
+
+ if (!params->ssid || !params->ssid_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (params->ssid_len > IW_ESSID_MAX_SIZE) {
+ ret = -E2BIG;
+ goto exit;
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ rtw_ps_deny(padapter, PS_DENY_JOIN);
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -EPERM;
+ goto cancel_ps_deny;
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_LINKING)) {
+ RTW_INFO("%s, but buddy_intf is under linking\n", __func__);
+ ret = -EINVAL;
+ goto cancel_ps_deny;
+ }
+ rtw_mi_buddy_scan_abort(padapter, true); /* OR rtw_mi_scan_abort(padapter, true);*/
+#endif /*CONFIG_CONCURRENT_MODE*/
+
+
+ memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID));
+ ndis_ssid.SsidLength = params->ssid_len;
+ memcpy(ndis_ssid.Ssid, (u8 *)params->ssid, params->ssid_len);
+
+ /* RTW_INFO("ssid=%s, len=%zu\n", ndis_ssid.Ssid, params->ssid_len); */
+
+ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+
+ ret = rtw_cfg80211_set_auth_type(psecuritypriv, NL80211_AUTHTYPE_OPEN_SYSTEM);
+ rtw_set_802_11_authentication_mode(padapter, psecuritypriv->ndisauthtype);
+
+ RTW_INFO("%s: center_freq = %d\n", __func__, pch->center_freq);
+ pmlmeext->cur_channel = rtw_freq2ch(pch->center_freq);
+
+ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+cancel_ps_deny:
+ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN);
+exit:
+ return ret;
+}
+
+static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct wireless_dev *rtw_wdev = padapter->rtw_wdev;
+ enum nl80211_iftype old_type;
+ int ret = 0;
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ #ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ padapter->mlmepriv.not_indic_disco = true;
+ #endif
+
+ old_type = rtw_wdev->iftype;
+
+ rtw_set_to_roam(padapter, 0);
+
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ rtw_scan_abort(padapter);
+ LeaveAllPowerSaveMode(padapter);
+
+ rtw_wdev->iftype = NL80211_IFTYPE_STATION;
+
+ if (rtw_set_802_11_infrastructure_mode(padapter, Ndis802_11Infrastructure) == false) {
+ rtw_wdev->iftype = old_type;
+ ret = -EPERM;
+ goto leave_ibss;
+ }
+ rtw_setopmode_cmd(padapter, Ndis802_11Infrastructure, true);
+ }
+
+leave_ibss:
+ #ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ padapter->mlmepriv.not_indic_disco = false;
+ #endif
+
+ return 0;
+}
+
+static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
+{
+ int ret = 0;
+ unsigned long irqL;
+ _list *phead;
+ struct wlan_network *pnetwork = NULL;
+ NDIS_802_11_AUTHENTICATION_MODE authmode;
+ NDIS_802_11_SSID ndis_ssid;
+ u8 *dst_ssid, *src_ssid;
+ u8 *dst_bssid, *src_bssid;
+ /* u8 matched_by_bssid=false; */
+ /* u8 matched_by_ssid=false; */
+ u8 matched = false;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ _queue *queue = &pmlmepriv->scanned_queue;
+
+#ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ padapter->mlmepriv.not_indic_disco = true;
+#endif
+
+ RTW_INFO("=>"FUNC_NDEV_FMT" - Start to Connection\n", FUNC_NDEV_ARG(ndev));
+ RTW_INFO("privacy=%d, key=%p, key_len=%d, key_idx=%d, auth_type=%d\n",
+ sme->privacy, sme->key, sme->key_len, sme->key_idx, sme->auth_type);
+
+
+ if (adapter_wdev_data(padapter)->block ) {
+ ret = -EBUSY;
+ RTW_INFO("%s wdev_priv.block is set\n", __func__);
+ goto exit;
+ }
+
+#ifdef CONFIG_PLATFORM_MSTAR_SCAN_BEFORE_CONNECT
+ printk("MStar Android!\n");
+ if (adapter_wdev_data(padapter)->bandroid_scan == false) {
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+#endif /* CONFIG_P2P */
+ {
+ ret = -EBUSY;
+ printk("Android hasn't attached yet!\n");
+ goto exit;
+ }
+ }
+#endif
+
+ if (!sme->ssid || !sme->ssid_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (sme->ssid_len > IW_ESSID_MAX_SIZE) {
+ ret = -E2BIG;
+ goto exit;
+ }
+
+ rtw_ps_deny(padapter, PS_DENY_JOIN);
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -EPERM;
+ goto cancel_ps_deny;
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ ret = -EPERM;
+ goto cancel_ps_deny;
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) ) {
+ ret = -EBUSY;
+ RTW_INFO("%s, fw_state=0x%x, goto exit\n", __func__, pmlmepriv->fw_state);
+ goto cancel_ps_deny;
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_LINKING)) {
+ ret = -EINVAL;
+ goto cancel_ps_deny;
+ }
+#endif
+
+ rtw_mi_scan_abort(padapter, true);
+
+ memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID));
+ ndis_ssid.SsidLength = sme->ssid_len;
+ memcpy(ndis_ssid.Ssid, (u8 *)sme->ssid, sme->ssid_len);
+
+ RTW_INFO("ssid=%s, len=%zu\n", ndis_ssid.Ssid, sme->ssid_len);
+
+
+ if (sme->bssid)
+ RTW_INFO("bssid="MAC_FMT"\n", MAC_ARG(sme->bssid));
+
+
+ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+
+#ifdef CONFIG_WAPI_SUPPORT
+ padapter->wapiInfo.bWapiEnable = false;
+#endif
+
+ ret = rtw_cfg80211_set_wpa_version(psecuritypriv, sme->crypto.wpa_versions);
+ if (ret < 0)
+ goto cancel_ps_deny;
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) {
+ padapter->wapiInfo.bWapiEnable = true;
+ padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN;
+ padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN;
+ }
+#endif
+
+ ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type);
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_WAPI)
+ padapter->mlmeextpriv.mlmext_info.auth_algo = psecuritypriv->dot11AuthAlgrthm;
+#endif
+
+
+ if (ret < 0)
+ goto cancel_ps_deny;
+
+ RTW_INFO("%s, ie_len=%zu\n", __func__, sme->ie_len);
+
+ ret = rtw_cfg80211_set_wpa_ie(padapter, (u8 *)sme->ie, sme->ie_len);
+ if (ret < 0)
+ goto cancel_ps_deny;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ ret = rtw_cfg80211_set_cipher(psecuritypriv, sme->crypto.ciphers_pairwise[0], true);
+ if (ret < 0)
+ goto cancel_ps_deny;
+ }
+
+ /* For WEP Shared auth */
+ if (sme->key_len > 0 && sme->key) {
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ NDIS_802_11_WEP *pwep = NULL;
+ RTW_INFO("%s(): Shared/Auto WEP\n", __func__);
+
+ wep_key_idx = sme->key_idx;
+ wep_key_len = sme->key_len;
+
+ if (sme->key_idx > WEP_KEYS) {
+ ret = -EINVAL;
+ goto cancel_ps_deny;
+ }
+
+ if (wep_key_len > 0) {
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+ wep_total_len = wep_key_len + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial);
+ pwep = (NDIS_802_11_WEP *) rtw_malloc(wep_total_len);
+ if (pwep == NULL) {
+ RTW_INFO(" wpa_set_encryption: pwep allocate fail !!!\n");
+ ret = -ENOMEM;
+ goto cancel_ps_deny;
+ }
+
+ memset(pwep, 0, wep_total_len);
+
+ pwep->KeyLength = wep_key_len;
+ pwep->Length = wep_total_len;
+
+ if (wep_key_len == 13) {
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+ }
+ } else {
+ ret = -EINVAL;
+ goto cancel_ps_deny;
+ }
+
+ pwep->KeyIndex = wep_key_idx;
+ pwep->KeyIndex |= 0x80000000;
+
+ memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength);
+
+ if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
+ ret = -EOPNOTSUPP ;
+
+ if (pwep)
+ rtw_mfree((u8 *)pwep, wep_total_len);
+
+ if (ret < 0)
+ goto cancel_ps_deny;
+ }
+
+ ret = rtw_cfg80211_set_cipher(psecuritypriv, sme->crypto.cipher_group, false);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_akm_suites) {
+ ret = rtw_cfg80211_set_key_mgt(psecuritypriv, sme->crypto.akm_suites[0]);
+ if (ret < 0)
+ goto cancel_ps_deny;
+ }
+#ifdef CONFIG_8011R
+ else {
+ /*It could be a connection without RSN IEs*/
+ psecuritypriv->rsn_akm_suite_type = 0;
+ }
+#endif
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_WAPI_PSK)
+ padapter->wapiInfo.bWapiPSK = true;
+ else if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_WAPI_CERT)
+ padapter->wapiInfo.bWapiPSK = false;
+#endif
+
+ authmode = psecuritypriv->ndisauthtype;
+ rtw_set_802_11_authentication_mode(padapter, authmode);
+
+ /* rtw_set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */
+
+ if (rtw_set_802_11_connect(padapter, (u8 *)sme->bssid, &ndis_ssid) == false) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+ RTW_INFO("set ssid:dot11AuthAlgrthm=%d, dot11PrivacyAlgrthm=%d, dot118021XGrpPrivacy=%d\n", psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+ psecuritypriv->dot118021XGrpPrivacy);
+
+cancel_ps_deny:
+ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN);
+
+exit:
+ RTW_INFO("<=%s, ret %d\n", __func__, ret);
+
+#ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ padapter->mlmepriv.not_indic_disco = false;
+#endif
+
+ return ret;
+}
+
+static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev,
+ u16 reason_code)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+
+ RTW_INFO(FUNC_NDEV_FMT" - Start to Disconnect\n", FUNC_NDEV_ARG(ndev));
+
+#ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ padapter->mlmepriv.not_indic_disco = true;
+#endif
+
+ rtw_set_to_roam(padapter, 0);
+
+ /* if(check_fwstate(&padapter->mlmepriv, _FW_LINKED)) */
+ {
+ rtw_scan_abort(padapter);
+ LeaveAllPowerSaveMode(padapter);
+ rtw_disassoc_cmd(padapter, 500, false);
+ rtw_sta_mstatus_report(padapter);
+
+ RTW_INFO("%s...call rtw_indicate_disconnect\n", __func__);
+
+ rtw_free_assoc_resources(padapter, 1);
+ rtw_indicate_disconnect(padapter, 0, true);
+
+ rtw_pwr_wakeup(padapter);
+ }
+
+#ifdef SUPPLICANT_RTK_VERSION_LOWER_THAN_JB42
+ padapter->mlmepriv.not_indic_disco = false;
+#endif
+
+ RTW_INFO(FUNC_NDEV_FMT" return 0\n", FUNC_NDEV_ARG(ndev));
+ return 0;
+}
+
+static int cfg80211_rtw_set_txpower(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ struct wireless_dev *wdev,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) || defined(COMPAT_KERNEL_RELEASE)
+ enum nl80211_tx_power_setting type, int mbm)
+#else
+ enum tx_power_setting type, int dbm)
+#endif
+{
+ RTW_INFO("%s\n", __func__);
+ return 0;
+}
+
+static int cfg80211_rtw_get_txpower(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ struct wireless_dev *wdev,
+#endif
+ int *dbm)
+{
+ RTW_INFO("%s\n", __func__);
+
+ *dbm = (12);
+
+ return 0;
+}
+
+inline bool rtw_cfg80211_pwr_mgmt(_adapter *adapter)
+{
+ struct rtw_wdev_priv *rtw_wdev_priv = adapter_wdev_data(adapter);
+ return rtw_wdev_priv->power_mgmt;
+}
+
+static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *ndev,
+ bool enabled, int timeout)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct rtw_wdev_priv *rtw_wdev_priv = adapter_wdev_data(padapter);
+
+ RTW_INFO(FUNC_NDEV_FMT" enabled:%u, timeout:%d\n", FUNC_NDEV_ARG(ndev),
+ enabled, timeout);
+
+ rtw_wdev_priv->power_mgmt = enabled;
+
+#ifdef CONFIG_LPS
+ if (!enabled)
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE_CFG80211_PWRMGMT, 1);
+#endif
+
+ return 0;
+}
+
+static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_pmksa *pmksa)
+{
+ u8 index, blInserted = false;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_priv *mlme = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ u8 strZeroMacAddress[ETH_ALEN] = { 0x00 };
+
+ RTW_INFO(FUNC_NDEV_FMT" "MAC_FMT" "KEY_FMT"\n", FUNC_NDEV_ARG(ndev)
+ , MAC_ARG(pmksa->bssid), KEY_ARG(pmksa->pmkid));
+
+ if (!memcmp((u8 *)pmksa->bssid, strZeroMacAddress, ETH_ALEN) )
+ return -EINVAL;
+
+ if (check_fwstate(mlme, _FW_LINKED) == false) {
+ RTW_INFO(FUNC_NDEV_FMT" not set pmksa cause not in linked state\n", FUNC_NDEV_ARG(ndev));
+ return -EINVAL;
+ }
+
+ blInserted = false;
+
+ /* overwrite PMKID */
+ for (index = 0 ; index < NUM_PMKID_CACHE; index++) {
+ if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN) ) {
+ /* BSSID is matched, the same AP => rewrite with new PMKID. */
+ RTW_INFO(FUNC_NDEV_FMT" BSSID exists in the PMKList.\n", FUNC_NDEV_ARG(ndev));
+
+ memcpy(psecuritypriv->PMKIDList[index].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN);
+ psecuritypriv->PMKIDList[index].bUsed = true;
+ psecuritypriv->PMKIDIndex = index + 1;
+ blInserted = true;
+ break;
+ }
+ }
+
+ if (!blInserted) {
+ /* Find a new entry */
+ RTW_INFO(FUNC_NDEV_FMT" Use the new entry index = %d for this PMKID.\n",
+ FUNC_NDEV_ARG(ndev), psecuritypriv->PMKIDIndex);
+
+ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, (u8 *)pmksa->bssid, ETH_ALEN);
+ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN);
+
+ psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true;
+ psecuritypriv->PMKIDIndex++ ;
+ if (psecuritypriv->PMKIDIndex == 16)
+ psecuritypriv->PMKIDIndex = 0;
+ }
+
+ return 0;
+}
+
+static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_pmksa *pmksa)
+{
+ u8 index, bMatched = false;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ RTW_INFO(FUNC_NDEV_FMT" "MAC_FMT" "KEY_FMT"\n", FUNC_NDEV_ARG(ndev)
+ , MAC_ARG(pmksa->bssid), KEY_ARG(pmksa->pmkid));
+
+ for (index = 0 ; index < NUM_PMKID_CACHE; index++) {
+ if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN) ) {
+ /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */
+ memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, ETH_ALEN);
+ memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN);
+ psecuritypriv->PMKIDList[index].bUsed = false;
+ bMatched = true;
+ RTW_INFO(FUNC_NDEV_FMT" clear id:%hhu\n", FUNC_NDEV_ARG(ndev), index);
+ break;
+ }
+ }
+
+ if (false == bMatched) {
+ RTW_INFO(FUNC_NDEV_FMT" do not have matched BSSID\n"
+ , FUNC_NDEV_ARG(ndev));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy,
+ struct net_device *ndev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+ psecuritypriv->PMKIDIndex = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_AP_MODE
+void rtw_cfg80211_indicate_sta_assoc(_adapter *padapter, u8 *pmgmt_frame, uint frame_len)
+{
+ s32 freq;
+ int channel;
+ struct wireless_dev *pwdev = padapter->rtw_wdev;
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct net_device *ndev = padapter->pnetdev;
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+#if defined(RTW_USE_CFG80211_STA_EVENT) || defined(COMPAT_KERNEL_RELEASE)
+ {
+ struct station_info sinfo;
+ u8 ie_offset;
+ if (get_frame_sub_type(pmgmt_frame) == WIFI_ASSOCREQ)
+ ie_offset = _ASOCREQ_IE_OFFSET_;
+ else /* WIFI_REASSOCREQ */
+ ie_offset = _REASOCREQ_IE_OFFSET_;
+
+ memset(&sinfo, 0, sizeof(sinfo));
+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset;
+ sinfo.assoc_req_ies_len = frame_len - WLAN_HDR_A3_LEN - ie_offset;
+ cfg80211_new_sta(ndev, get_addr2_ptr(pmgmt_frame), &sinfo, GFP_ATOMIC);
+ }
+#else /* defined(RTW_USE_CFG80211_STA_EVENT) */
+ channel = pmlmeext->cur_channel;
+ freq = rtw_ch2freq(channel);
+
+ #ifdef COMPAT_KERNEL_RELEASE
+ rtw_cfg80211_rx_mgmt(pwdev, freq, 0, pmgmt_frame, frame_len, GFP_ATOMIC);
+ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
+ rtw_cfg80211_rx_mgmt(pwdev, freq, 0, pmgmt_frame, frame_len, GFP_ATOMIC);
+ #else /* COMPAT_KERNEL_RELEASE */
+ {
+ /* to avoid WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION) when calling cfg80211_send_rx_assoc() */
+ #ifndef CONFIG_PLATFORM_MSTAR
+ pwdev->iftype = NL80211_IFTYPE_STATION;
+ #endif /* CONFIG_PLATFORM_MSTAR */
+ RTW_INFO("iftype=%d before call cfg80211_send_rx_assoc()\n", pwdev->iftype);
+ rtw_cfg80211_send_rx_assoc(padapter, NULL, pmgmt_frame, frame_len);
+ RTW_INFO("iftype=%d after call cfg80211_send_rx_assoc()\n", pwdev->iftype);
+ pwdev->iftype = NL80211_IFTYPE_AP;
+ /* cfg80211_rx_action(padapter->pnetdev, freq, pmgmt_frame, frame_len, GFP_ATOMIC); */
+ }
+ #endif /* COMPAT_KERNEL_RELEASE */
+#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
+
+}
+
+void rtw_cfg80211_indicate_sta_disassoc(_adapter *padapter, unsigned char *da, unsigned short reason)
+{
+ s32 freq;
+ int channel;
+ u8 *pmgmt_frame;
+ uint frame_len;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ unsigned short *fctrl;
+ u8 mgmt_buf[128] = {0};
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wireless_dev *wdev = padapter->rtw_wdev;
+ struct net_device *ndev = padapter->pnetdev;
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+#if defined(RTW_USE_CFG80211_STA_EVENT) || defined(COMPAT_KERNEL_RELEASE)
+ cfg80211_del_sta(ndev, da, GFP_ATOMIC);
+#else /* defined(RTW_USE_CFG80211_STA_EVENT) */
+ channel = pmlmeext->cur_channel;
+ freq = rtw_ch2freq(channel);
+
+ pmgmt_frame = mgmt_buf;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pmgmt_frame;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, adapter_mac_addr(padapter), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, da, ETH_ALEN);
+ memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ set_frame_sub_type(pmgmt_frame, WIFI_DEAUTH);
+
+ pmgmt_frame += sizeof(struct rtw_ieee80211_hdr_3addr);
+ frame_len = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ reason = cpu_to_le16(reason);
+ pmgmt_frame = rtw_set_fixed_ie(pmgmt_frame, _RSON_CODE_ , (unsigned char *)&reason, &frame_len);
+
+ #ifdef COMPAT_KERNEL_RELEASE
+ rtw_cfg80211_rx_mgmt(wdev, freq, 0, mgmt_buf, frame_len, GFP_ATOMIC);
+ #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER)
+ rtw_cfg80211_rx_mgmt(wdev, freq, 0, mgmt_buf, frame_len, GFP_ATOMIC);
+ #else /* COMPAT_KERNEL_RELEASE */
+ cfg80211_send_disassoc(padapter->pnetdev, mgmt_buf, frame_len);
+ /* cfg80211_rx_action(padapter->pnetdev, freq, mgmt_buf, frame_len, GFP_ATOMIC); */
+ #endif /* COMPAT_KERNEL_RELEASE */
+#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
+}
+
+static int rtw_cfg80211_monitor_if_open(struct net_device *ndev)
+{
+ int ret = 0;
+
+ RTW_INFO("%s\n", __func__);
+
+ return ret;
+}
+
+static int rtw_cfg80211_monitor_if_close(struct net_device *ndev)
+{
+ int ret = 0;
+
+ RTW_INFO("%s\n", __func__);
+
+ return ret;
+}
+
+static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_device *ndev)
+{
+ int ret = 0;
+ int rtap_len;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ u16 frame_ctl;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct rtw_ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *rtap_hdr;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ if (skb)
+ rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, skb->truesize);
+
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+ goto fail;
+
+ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+ if (unlikely(rtap_hdr->it_version))
+ goto fail;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (unlikely(skb->len < rtap_len))
+ goto fail;
+
+ if (rtap_len != 14) {
+ RTW_INFO("radiotap len (should be 14): %d\n", rtap_len);
+ goto fail;
+ }
+
+ /* Skip the ratio tap header */
+ skb_pull(skb, rtap_len);
+
+ dot11_hdr = (struct rtw_ieee80211_hdr *)skb->data;
+ frame_ctl = le16_to_cpu(dot11_hdr->frame_ctl);
+ /* Check if the QoS bit is set */
+ if ((frame_ctl & RTW_IEEE80211_FCTL_FTYPE) == RTW_IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame
+ * which has 4 MAC addresses
+ */
+ if (le16_to_cpu(dot11_hdr->frame_ctl) & 0x0080)
+ qos_len = 2;
+ if ((le16_to_cpu(dot11_hdr->frame_ctl) & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ * for two MAC addresses
+ */
+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char *)skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+
+ RTW_INFO("should be eapol packet\n");
+
+ /* Use the real net device to transmit the packet */
+ ret = _rtw_xmit_entry(skb, padapter->pnetdev);
+
+ return ret;
+
+ } else if ((frame_ctl & (RTW_IEEE80211_FCTL_FTYPE | RTW_IEEE80211_FCTL_STYPE))
+ == (RTW_IEEE80211_FTYPE_MGMT | RTW_IEEE80211_STYPE_ACTION)
+ ) {
+ /* only for action frames */
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ /* u8 category, action, OUI_Subtype, dialogToken=0; */
+ /* unsigned char *frame_body; */
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ u8 *buf = skb->data;
+ u32 len = skb->len;
+ u8 category, action;
+ int type = -1;
+
+ if (rtw_action_frame_parse(buf, len, &category, &action) == false) {
+ RTW_INFO(FUNC_NDEV_FMT" frame_control:0x%x\n", FUNC_NDEV_ARG(ndev),
+ le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)buf)->frame_ctl));
+ goto fail;
+ }
+
+ RTW_INFO("RTW_Tx:da="MAC_FMT" via "FUNC_NDEV_FMT"\n",
+ MAC_ARG(GetAddr1Ptr(buf)), FUNC_NDEV_ARG(ndev));
+ #ifdef CONFIG_P2P
+ type = rtw_p2p_check_frames(padapter, buf, len, true);
+ if (type >= 0)
+ goto dump;
+ #endif
+ if (category == RTW_WLAN_CATEGORY_PUBLIC)
+ RTW_INFO("RTW_Tx:%s\n", action_public_str(action));
+ else
+ RTW_INFO("RTW_Tx:category(%u), action(%u)\n", category, action);
+
+dump:
+ /* starting alloc mgmt frame to dump it */
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ goto fail;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+ pattrib->retry_ctrl = false;
+
+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+ memcpy(pframe, (void *)buf, len);
+ pattrib->pktlen = len;
+
+#ifdef CONFIG_P2P
+ if (type >= 0)
+ rtw_xframe_chk_wfd_ie(pmgntframe);
+#endif /* CONFIG_P2P */
+
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+ /* update seq number */
+ pmlmeext->mgnt_seq = GetSequence(pwlanhdr);
+ pattrib->seqnum = pmlmeext->mgnt_seq;
+ pmlmeext->mgnt_seq++;
+
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ dump_mgntframe(padapter, pmgntframe);
+
+ } else
+ RTW_INFO("frame_ctl=0x%x\n", frame_ctl & (RTW_IEEE80211_FCTL_FTYPE | RTW_IEEE80211_FCTL_STYPE));
+
+
+fail:
+
+ rtw_skb_free(skb);
+
+ return 0;
+
+}
+
+static void rtw_cfg80211_monitor_if_set_multicast_list(struct net_device *ndev)
+{
+ RTW_INFO("%s\n", __func__);
+}
+
+static int rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr)
+{
+ int ret = 0;
+
+ RTW_INFO("%s\n", __func__);
+
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+static const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
+ .ndo_open = rtw_cfg80211_monitor_if_open,
+ .ndo_stop = rtw_cfg80211_monitor_if_close,
+ .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+ .ndo_set_multicast_list = rtw_cfg80211_monitor_if_set_multicast_list,
+ #endif
+ .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address,
+};
+#endif
+
+static int rtw_cfg80211_add_monitor_if(_adapter *padapter, char *name, struct net_device **ndev)
+{
+ int ret = 0;
+ struct net_device *mon_ndev = NULL;
+ struct wireless_dev *mon_wdev = NULL;
+ struct rtw_netdev_priv_indicator *pnpi;
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
+
+ if (!name) {
+ RTW_INFO(FUNC_ADPT_FMT" without specific name\n", FUNC_ADPT_ARG(padapter));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (pwdev_priv->pmon_ndev) {
+ RTW_INFO(FUNC_ADPT_FMT" monitor interface exist: "NDEV_FMT"\n",
+ FUNC_ADPT_ARG(padapter), NDEV_ARG(pwdev_priv->pmon_ndev));
+ ret = -EBUSY;
+ goto out;
+ }
+
+ mon_ndev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator));
+ if (!mon_ndev) {
+ RTW_INFO(FUNC_ADPT_FMT" allocate ndev fail\n", FUNC_ADPT_ARG(padapter));
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(mon_ndev->name, name, IFNAMSIZ);
+ mon_ndev->name[IFNAMSIZ - 1] = 0;
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(4, 11, 9))
+ mon_ndev->needs_free_netdev = false;
+ mon_ndev->priv_destructor = rtw_ndev_destructor;
+#else
+ mon_ndev->destructor = rtw_ndev_destructor;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+ mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops;
+#else
+ mon_ndev->open = rtw_cfg80211_monitor_if_open;
+ mon_ndev->stop = rtw_cfg80211_monitor_if_close;
+ mon_ndev->hard_start_xmit = rtw_cfg80211_monitor_if_xmit_entry;
+ mon_ndev->set_mac_address = rtw_cfg80211_monitor_if_set_mac_address;
+#endif
+
+ pnpi = netdev_priv(mon_ndev);
+ pnpi->priv = padapter;
+ pnpi->sizeof_priv = sizeof(_adapter);
+
+ /* wdev */
+ mon_wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev));
+ if (!mon_wdev) {
+ RTW_INFO(FUNC_ADPT_FMT" allocate mon_wdev fail\n", FUNC_ADPT_ARG(padapter));
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mon_wdev->wiphy = padapter->rtw_wdev->wiphy;
+ mon_wdev->netdev = mon_ndev;
+ mon_wdev->iftype = NL80211_IFTYPE_MONITOR;
+ mon_ndev->ieee80211_ptr = mon_wdev;
+
+ ret = register_netdevice(mon_ndev);
+ if (ret)
+ goto out;
+
+ *ndev = pwdev_priv->pmon_ndev = mon_ndev;
+ memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ + 1);
+
+out:
+ if (ret && mon_wdev) {
+ rtw_mfree((u8 *)mon_wdev, sizeof(struct wireless_dev));
+ mon_wdev = NULL;
+ }
+
+ if (ret && mon_ndev) {
+ free_netdev(mon_ndev);
+ *ndev = mon_ndev = NULL;
+ }
+
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static struct wireless_dev *
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+static struct net_device *
+#else
+static int
+#endif
+ cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
+ const char *name,
+#else
+ char *name,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ unsigned char name_assign_type,
+#endif
+ enum nl80211_iftype type,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
+ u32 *flags,
+#endif
+ struct vif_params *params)
+{
+ int ret = 0;
+ struct wireless_dev *wdev = NULL;
+ struct net_device *ndev = NULL;
+ _adapter *padapter;
+ struct dvobj_priv *dvobj = wiphy_to_dvobj(wiphy);
+
+ rtw_set_rtnl_lock_holder(dvobj, current);
+
+ RTW_INFO(FUNC_WIPHY_FMT" name:%s, type:%d\n", FUNC_WIPHY_ARG(wiphy), name, type);
+
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ padapter = wiphy_to_adapter(wiphy); /* TODO: get ap iface ? */
+ ret = rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev);
+ if (ret == 0)
+ wdev = ndev->ieee80211_ptr;
+ break;
+
+#if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+#endif
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_AP:
+ padapter = dvobj_get_unregisterd_adapter(dvobj);
+ if (!padapter) {
+ RTW_WARN("adapter pool empty!\n");
+ ret = -ENODEV;
+ break;
+ }
+ if (rtw_os_ndev_init(padapter, name) != _SUCCESS) {
+ RTW_WARN("ndev init fail!\n");
+ ret = -ENODEV;
+ break;
+ }
+ #if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ if (type == NL80211_IFTYPE_P2P_CLIENT || type == NL80211_IFTYPE_P2P_GO)
+ rtw_p2p_enable(padapter, P2P_ROLE_DEVICE);
+ #endif
+ ndev = padapter->pnetdev;
+ wdev = ndev->ieee80211_ptr;
+ break;
+
+#if defined(CONFIG_P2P) && defined(RTW_DEDICATED_P2P_DEVICE)
+ case NL80211_IFTYPE_P2P_DEVICE:
+ ret = rtw_pd_iface_alloc(wiphy, name, &wdev);
+ break;
+#endif
+
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ default:
+ ret = -ENODEV;
+ RTW_INFO("Unsupported interface type\n");
+ break;
+ }
+
+ if (ndev)
+ RTW_INFO(FUNC_WIPHY_FMT" ndev:%p, ret:%d\n", FUNC_WIPHY_ARG(wiphy), ndev, ret);
+ else
+ RTW_INFO(FUNC_WIPHY_FMT" wdev:%p, ret:%d\n", FUNC_WIPHY_ARG(wiphy), wdev, ret);
+
+ rtw_set_rtnl_lock_holder(dvobj, NULL);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ return wdev ? wdev : ERR_PTR(ret);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+ return ndev ? ndev : ERR_PTR(ret);
+#else
+ return ret;
+#endif
+}
+
+static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct wireless_dev *wdev
+#else
+ struct net_device *ndev
+#endif
+)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct net_device *ndev = wdev_to_ndev(wdev);
+#endif
+ int ret = 0;
+ struct dvobj_priv *dvobj = wiphy_to_dvobj(wiphy);
+ _adapter *adapter;
+ struct rtw_wdev_priv *pwdev_priv;
+
+ rtw_set_rtnl_lock_holder(dvobj, current);
+
+ if (ndev) {
+ adapter = (_adapter *)rtw_netdev_priv(ndev);
+ pwdev_priv = adapter_wdev_data(adapter);
+
+ if (ndev == pwdev_priv->pmon_ndev) {
+ unregister_netdevice(ndev);
+ pwdev_priv->pmon_ndev = NULL;
+ pwdev_priv->ifname_mon[0] = '\0';
+ RTW_INFO(FUNC_NDEV_FMT" remove monitor ndev\n", FUNC_NDEV_ARG(ndev));
+ } else {
+ RTW_INFO(FUNC_NDEV_FMT" unregister ndev\n", FUNC_NDEV_ARG(ndev));
+ rtw_os_ndev_unregister(adapter);
+ }
+ } else
+#if defined(CONFIG_P2P) && defined(RTW_DEDICATED_P2P_DEVICE)
+ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ if (wdev == wiphy_to_pd_wdev(wiphy))
+ rtw_pd_iface_free(wiphy);
+ else {
+ RTW_ERR(FUNC_WIPHY_FMT" unknown P2P Device wdev:%p\n", FUNC_WIPHY_ARG(wiphy), wdev);
+ rtw_warn_on(1);
+ }
+ } else
+#endif
+ {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+exit:
+ rtw_set_rtnl_lock_holder(dvobj, NULL);
+ return ret;
+}
+
+static int rtw_add_beacon(_adapter *adapter, const u8 *head, size_t head_len, const u8 *tail, size_t tail_len)
+{
+ int ret = 0;
+ u8 *pbuf = NULL;
+ uint len, wps_ielen = 0;
+ uint p2p_ielen = 0;
+ u8 *p2p_ie;
+ u8 got_p2p_ie = false;
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+ /* struct sta_priv *pstapriv = &padapter->stapriv; */
+
+
+ RTW_INFO("%s beacon_head_len=%zu, beacon_tail_len=%zu\n", __func__, head_len, tail_len);
+
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ if (head_len < 24)
+ return -EINVAL;
+
+
+ pbuf = rtw_zmalloc(head_len + tail_len);
+ if (!pbuf)
+ return -ENOMEM;
+
+
+ /* memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2); */
+
+ /* if((pstapriv->max_num_sta>NUM_STA) || (pstapriv->max_num_sta<=0)) */
+ /* pstapriv->max_num_sta = NUM_STA; */
+
+
+ memcpy(pbuf, (void *)head + 24, head_len - 24); /* 24=beacon header len. */
+ memcpy(pbuf + head_len - 24, (void *)tail, tail_len);
+
+ len = head_len + tail_len - 24;
+
+ /* check wps ie if inclued */
+ if (rtw_get_wps_ie(pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, &wps_ielen))
+ RTW_INFO("add bcn, wps_ielen=%d\n", wps_ielen);
+
+#ifdef CONFIG_P2P
+ if (adapter->wdinfo.driver_interface == DRIVER_CFG80211) {
+ /* check p2p if enable */
+ if (rtw_get_p2p_ie(pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL, &p2p_ielen)) {
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+ struct wifidirect_info *pwdinfo = &(adapter->wdinfo);
+
+ RTW_INFO("got p2p_ie, len=%d\n", p2p_ielen);
+
+ got_p2p_ie = true;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ RTW_INFO("Enable P2P function for the first time\n");
+ rtw_p2p_enable(adapter, P2P_ROLE_GO);
+
+ adapter->stapriv.expire_to = 3; /* 3x2 = 6 sec in p2p mode */
+ } else {
+ RTW_INFO("enter GO Mode, p2p_ielen=%d\n", p2p_ielen);
+
+ rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+ pwdinfo->intent = 15;
+ }
+ }
+ }
+#endif /* CONFIG_P2P */
+
+ /* pbss_network->IEs will not include p2p_ie, wfd ie */
+ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, P2P_OUI, 4);
+ rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, WFD_OUI, 4);
+
+ if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) {
+#ifdef CONFIG_P2P
+ /* check p2p if enable */
+ if (got_p2p_ie ) {
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+ struct wifidirect_info *pwdinfo = &(adapter->wdinfo);
+ pwdinfo->operating_channel = pmlmeext->cur_channel;
+ }
+#endif /* CONFIG_P2P */
+ ret = 0;
+ } else
+ ret = -EINVAL;
+
+
+ rtw_mfree(pbuf, head_len + tail_len);
+
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE)
+static int cfg80211_rtw_add_beacon(struct wiphy *wiphy, struct net_device *ndev,
+ struct beacon_parameters *info)
+{
+ int ret = 0;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev);
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+ ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len);
+
+ return ret;
+}
+
+static int cfg80211_rtw_set_beacon(struct wiphy *wiphy, struct net_device *ndev,
+ struct beacon_parameters *info)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv);
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ pmlmeext->bstart_bss = true;
+
+ cfg80211_rtw_add_beacon(wiphy, ndev, info);
+
+ return 0;
+}
+
+static int cfg80211_rtw_del_beacon(struct wiphy *wiphy, struct net_device *ndev)
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ return 0;
+}
+#else
+static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_ap_settings *settings)
+{
+ int ret = 0;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev);
+
+ RTW_INFO(FUNC_NDEV_FMT" hidden_ssid:%d, auth_type:%d\n", FUNC_NDEV_ARG(ndev),
+ settings->hidden_ssid, settings->auth_type);
+
+ ret = rtw_add_beacon(adapter, settings->beacon.head, settings->beacon.head_len,
+ settings->beacon.tail, settings->beacon.tail_len);
+
+ adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode = settings->hidden_ssid;
+
+ if (settings->ssid && settings->ssid_len) {
+ WLAN_BSSID_EX *pbss_network = &adapter->mlmepriv.cur_network.network;
+ WLAN_BSSID_EX *pbss_network_ext = &adapter->mlmeextpriv.mlmext_info.network;
+
+ if (0)
+ RTW_INFO(FUNC_ADPT_FMT" ssid:(%s,%zu), from ie:(%s,%d)\n", FUNC_ADPT_ARG(adapter),
+ settings->ssid, settings->ssid_len,
+ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength);
+
+ memcpy(pbss_network->Ssid.Ssid, (void *)settings->ssid, settings->ssid_len);
+ pbss_network->Ssid.SsidLength = settings->ssid_len;
+ memcpy(pbss_network_ext->Ssid.Ssid, (void *)settings->ssid, settings->ssid_len);
+ pbss_network_ext->Ssid.SsidLength = settings->ssid_len;
+
+ if (0)
+ RTW_INFO(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter),
+ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength,
+ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength);
+ }
+
+ return ret;
+}
+
+static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_beacon_data *info)
+{
+ int ret = 0;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev);
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len);
+
+ return ret;
+}
+
+static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+ return 0;
+}
+
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) */
+
+#if CONFIG_RTW_MACADDR_ACL && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+static int cfg80211_rtw_set_mac_acl(struct wiphy *wiphy, struct net_device *ndev,
+ const struct cfg80211_acl_data *params)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(ndev);
+ u8 acl_mode = RTW_ACL_MODE_DISABLED;
+ int ret = -1;
+ int i;
+
+ if (!params) {
+ RTW_WARN(FUNC_ADPT_FMT" params NULL\n", FUNC_ADPT_ARG(adapter));
+ goto exit;
+ }
+
+ RTW_INFO(FUNC_ADPT_FMT" acl_policy:%d, entry_num:%d\n"
+ , FUNC_ADPT_ARG(adapter), params->acl_policy, params->n_acl_entries);
+
+ if (params->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED)
+ acl_mode = RTW_ACL_MODE_ACCEPT_UNLESS_LISTED;
+ else if (params->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED)
+ acl_mode = RTW_ACL_MODE_DENY_UNLESS_LISTED;
+
+ if (!params->n_acl_entries) {
+ if (acl_mode != RTW_ACL_MODE_DISABLED)
+ RTW_WARN(FUNC_ADPT_FMT" acl_policy:%d with no entry\n"
+ , FUNC_ADPT_ARG(adapter), params->acl_policy);
+ acl_mode = RTW_ACL_MODE_DISABLED;
+ goto exit;
+ }
+
+ for (i = 0; i < params->n_acl_entries; i++)
+ rtw_acl_add_sta(adapter, params->mac_addrs[i].addr);
+
+ ret = 0;
+
+exit:
+ rtw_set_macaddr_acl(adapter, acl_mode);
+ return ret;
+}
+#endif /* CONFIG_RTW_MACADDR_ACL && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) */
+
+static int cfg80211_rtw_add_station(struct wiphy *wiphy, struct net_device *ndev,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0))
+ u8 *mac,
+#else
+ const u8 *mac,
+#endif
+ struct station_parameters *params)
+{
+ int ret = 0;
+#ifdef CONFIG_TDLS
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct sta_info *psta;
+#endif /* CONFIG_TDLS */
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+#ifdef CONFIG_TDLS
+ psta = rtw_get_stainfo(pstapriv, (u8 *)mac);
+ if (psta == NULL) {
+ psta = rtw_alloc_stainfo(pstapriv, (u8 *)mac);
+ if (psta == NULL) {
+ RTW_INFO("[%s] Alloc station for "MAC_FMT" fail\n", __func__, MAC_ARG(mac));
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+ }
+#endif /* CONFIG_TDLS */
+
+exit:
+ return ret;
+}
+
+static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0))
+ u8 *mac
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))
+ const u8 *mac
+#else
+ struct station_del_parameters *params
+#endif
+)
+{
+ int ret = 0;
+ unsigned long irqL;
+ _list *phead, *plist;
+ u8 updated = false;
+ const u8 *target_mac;
+ struct sta_info *psta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ RTW_INFO("+"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))
+ target_mac = mac;
+#else
+ target_mac = params->mac;
+#endif
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true) {
+ RTW_INFO("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", __func__);
+ return -EINVAL;
+ }
+
+
+ if (!target_mac) {
+ RTW_INFO("flush all sta, and cam_entry\n");
+
+ flush_all_cam_entry(padapter); /* clear CAM */
+
+ ret = rtw_sta_flush(padapter, true);
+
+ return ret;
+ }
+
+
+ RTW_INFO("free sta macaddr =" MAC_FMT "\n", MAC_ARG(target_mac));
+
+ if (target_mac[0] == 0xff && target_mac[1] == 0xff &&
+ target_mac[2] == 0xff && target_mac[3] == 0xff &&
+ target_mac[4] == 0xff && target_mac[5] == 0xff)
+ return -EINVAL;
+
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* check asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+
+ plist = get_next(plist);
+
+ if (!memcmp((u8 *)target_mac, psta->hwaddr, ETH_ALEN)) {
+ if (psta->dot8021xalg == 1 && psta->bpairwise_key_installed == false)
+ RTW_INFO("%s, sta's dot8021xalg = 1 and key_installed = false\n", __func__);
+ else {
+ RTW_INFO("free psta=%p, aid=%d\n", psta, psta->aid);
+
+ list_del_init(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+
+ /* _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); */
+ if (check_fwstate(pmlmepriv, (WIFI_AP_STATE)) )
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_PREV_AUTH_NOT_VALID, true);
+ else
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING, true);
+ /* _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); */
+
+ psta = NULL;
+
+ break;
+ }
+
+ }
+
+ }
+
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+
+ RTW_INFO("-"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ return ret;
+
+}
+
+static int cfg80211_rtw_change_station(struct wiphy *wiphy, struct net_device *ndev,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0))
+ u8 *mac,
+#else
+ const u8 *mac,
+#endif
+ struct station_parameters *params)
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ return 0;
+}
+
+static struct sta_info *rtw_sta_info_get_by_idx(const int idx, struct sta_priv *pstapriv)
+
+{
+
+ _list *phead, *plist;
+ struct sta_info *psta = NULL;
+ int i = 0;
+
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* check asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ if (idx == i)
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ plist = get_next(plist);
+ i++;
+ }
+ return psta;
+}
+
+static int cfg80211_rtw_dump_station(struct wiphy *wiphy, struct net_device *ndev,
+ int idx, u8 *mac, struct station_info *sinfo)
+{
+
+ int ret = 0;
+ unsigned long irqL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ psta = rtw_sta_info_get_by_idx(idx, pstapriv);
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (NULL == psta) {
+ RTW_INFO("Station is not found\n");
+ ret = -ENOENT;
+ goto exit;
+ }
+ memcpy(mac, psta->hwaddr, ETH_ALEN);
+ sinfo->filled = 0;
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = psta->rssi;
+
+exit:
+ return ret;
+}
+
+static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev,
+ struct bss_parameters *params)
+{
+ u8 i;
+
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+/*
+ RTW_INFO("use_cts_prot=%d\n", params->use_cts_prot);
+ RTW_INFO("use_short_preamble=%d\n", params->use_short_preamble);
+ RTW_INFO("use_short_slot_time=%d\n", params->use_short_slot_time);
+ RTW_INFO("ap_isolate=%d\n", params->ap_isolate);
+
+ RTW_INFO("basic_rates_len=%d\n", params->basic_rates_len);
+ for(i = 0; i < params->basic_rates_len; i++)
+ RTW_INFO("basic_rates=%d\n", params->basic_rates[i]);
+*/
+ return 0;
+
+}
+
+static int cfg80211_rtw_set_channel(struct wiphy *wiphy
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ , struct net_device *ndev
+ #endif
+ , struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+#else
+ _adapter *padapter = wiphy_to_adapter(wiphy);
+#endif
+ int chan_target = (u8) ieee80211_frequency_to_channel(chan->center_freq);
+ int chan_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ int chan_width = CHANNEL_WIDTH_20;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+#endif
+
+ switch (channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ chan_width = CHANNEL_WIDTH_20;
+ chan_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ chan_width = CHANNEL_WIDTH_40;
+ chan_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ chan_width = CHANNEL_WIDTH_40;
+ chan_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+ default:
+ chan_width = CHANNEL_WIDTH_20;
+ chan_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+
+ set_channel_bwmode(padapter, chan_target, chan_offset, chan_width);
+
+ return 0;
+}
+
+static int cfg80211_rtw_set_monitor_channel(struct wiphy *wiphy
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ , struct cfg80211_chan_def *chandef
+#else
+ , struct ieee80211_channel *chan
+ , enum nl80211_channel_type channel_type
+#endif
+)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ struct ieee80211_channel *chan = chandef->chan;
+#endif
+
+ _adapter *padapter = wiphy_to_adapter(wiphy);
+ int target_channal = chan->hw_value;
+ int target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ int target_width = CHANNEL_WIDTH_20;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("center_freq %u Mhz ch %u width %u freq1 %u freq2 %u\n"
+ , chan->center_freq
+ , chan->hw_value
+ , chandef->width
+ , chandef->center_freq1
+ , chandef->center_freq2);
+#endif /* CONFIG_DEBUG_CFG80211 */
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ target_width = CHANNEL_WIDTH_20;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ target_width = CHANNEL_WIDTH_40;
+ if (chandef->center_freq1 > chan->center_freq)
+ target_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ else
+ target_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ target_width = CHANNEL_WIDTH_80;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ target_width = CHANNEL_WIDTH_80_80;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ target_width = CHANNEL_WIDTH_160;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+#endif
+ default:
+ target_width = CHANNEL_WIDTH_20;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+#else
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("center_freq %u Mhz ch %u channel_type %u\n"
+ , chan->center_freq
+ , chan->hw_value
+ , channel_type);
+#endif /* CONFIG_DEBUG_CFG80211 */
+
+ switch (channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ target_width = CHANNEL_WIDTH_20;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ target_width = CHANNEL_WIDTH_40;
+ target_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ target_width = CHANNEL_WIDTH_40;
+ target_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+ default:
+ target_width = CHANNEL_WIDTH_20;
+ target_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+#endif
+
+ set_channel_bwmode(padapter, target_channal, target_offset, target_width);
+
+ return 0;
+}
+
+static int cfg80211_rtw_auth(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_auth_request *req)
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ return 0;
+}
+
+static int cfg80211_rtw_assoc(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_assoc_request *req)
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+ return 0;
+}
+#endif /* CONFIG_AP_MODE */
+
+void rtw_cfg80211_rx_probe_request(_adapter *adapter, union recv_frame *rframe)
+{
+ struct wireless_dev *wdev = adapter->rtw_wdev;
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
+ u8 *frame = get_recvframe_data(rframe);
+ uint frame_len = rframe->u.hdr.len;
+ s32 freq;
+ u8 ch, sch = rtw_get_oper_ch(adapter);
+
+ ch = rframe->u.hdr.attrib.ch ? rframe->u.hdr.attrib.ch : sch;
+ freq = rtw_ch2freq(ch);
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("RTW_Rx: probe request, ch=%d(%d)\n", ch, sch);
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ rtw_cfg80211_rx_mgmt(wdev, freq, 0, frame, frame_len, GFP_ATOMIC);
+#else
+ cfg80211_rx_action(adapter->pnetdev, freq, frame, frame_len, GFP_ATOMIC);
+#endif
+}
+
+void rtw_cfg80211_rx_action_p2p(_adapter *adapter, union recv_frame *rframe)
+{
+ struct wireless_dev *wdev = adapter->rtw_wdev;
+ u8 *frame = get_recvframe_data(rframe);
+ uint frame_len = rframe->u.hdr.len;
+ s32 freq;
+ u8 ch, sch = rtw_get_oper_ch(adapter);
+ u8 category, action;
+ int type;
+
+ ch = rframe->u.hdr.attrib.ch ? rframe->u.hdr.attrib.ch : sch;
+ freq = rtw_ch2freq(ch);
+
+ RTW_INFO("RTW_Rx:ch=%d(%d)\n", ch, sch);
+#ifdef CONFIG_P2P
+ type = rtw_p2p_check_frames(adapter, frame, frame_len, false);
+ if (type >= 0)
+ goto indicate;
+#endif
+ rtw_action_frame_parse(frame, frame_len, &category, &action);
+ RTW_INFO("RTW_Rx:category(%u), action(%u)\n", category, action);
+
+indicate:
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ rtw_cfg80211_rx_mgmt(wdev, freq, 0, frame, frame_len, GFP_ATOMIC);
+#else
+ cfg80211_rx_action(adapter->pnetdev, freq, frame, frame_len, GFP_ATOMIC);
+#endif
+}
+
+void rtw_cfg80211_rx_p2p_action_public(_adapter *adapter, union recv_frame *rframe)
+{
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct wireless_dev *wdev = adapter->rtw_wdev;
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
+ u8 *frame = get_recvframe_data(rframe);
+ uint frame_len = rframe->u.hdr.len;
+ s32 freq;
+ u8 ch, sch = rtw_get_oper_ch(adapter);
+ u8 category, action;
+ int type;
+
+ ch = rframe->u.hdr.attrib.ch ? rframe->u.hdr.attrib.ch : sch;
+ freq = rtw_ch2freq(ch);
+
+ RTW_INFO("RTW_Rx:ch=%d(%d)\n", ch, sch);
+ #ifdef CONFIG_P2P
+ type = rtw_p2p_check_frames(adapter, frame, frame_len, false);
+ if (type >= 0) {
+ switch (type) {
+ case P2P_GO_NEGO_CONF:
+ if (0) {
+ RTW_INFO(FUNC_ADPT_FMT" Nego confirm. state=%u, status=%u, iaddr="MAC_FMT"\n"
+ , FUNC_ADPT_ARG(adapter), pwdev_priv->nego_info.state, pwdev_priv->nego_info.status
+ , MAC_ARG(pwdev_priv->nego_info.iface_addr));
+ }
+ if (pwdev_priv->nego_info.state == 2
+ && pwdev_priv->nego_info.status == 0
+ && rtw_check_invalid_mac_address(pwdev_priv->nego_info.iface_addr, false) == false
+ ) {
+ _adapter *intended_iface = dvobj_get_adapter_by_addr(dvobj, pwdev_priv->nego_info.iface_addr);
+
+ if (intended_iface) {
+ RTW_INFO(FUNC_ADPT_FMT" Nego confirm. Allow only "ADPT_FMT" to scan for 2000 ms\n"
+ , FUNC_ADPT_ARG(adapter), ADPT_ARG(intended_iface));
+ /* allow only intended_iface to do scan for 2000 ms */
+ rtw_mi_set_scan_deny(adapter, 2000);
+ rtw_clear_scan_deny(intended_iface);
+ }
+ }
+ break;
+ case P2P_PROVISION_DISC_RESP:
+ case P2P_INVIT_RESP:
+ #if !RTW_P2P_GROUP_INTERFACE
+ rtw_mi_buddy_set_scan_deny(adapter, 2000);
+ #endif
+ break;
+ }
+ goto indicate;
+ }
+ #endif
+ rtw_action_frame_parse(frame, frame_len, &category, &action);
+ RTW_INFO("RTW_Rx:category(%u), action(%u)\n", category, action);
+
+indicate:
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ if (rtw_cfg80211_redirect_pd_wdev(dvobj_to_wiphy(dvobj), get_ra(frame), &wdev))
+ if (0)
+ RTW_INFO("redirect to pd_wdev:%p\n", wdev);
+ #endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ rtw_cfg80211_rx_mgmt(wdev, freq, 0, frame, frame_len, GFP_ATOMIC);
+#else
+ cfg80211_rx_action(adapter->pnetdev, freq, frame, frame_len, GFP_ATOMIC);
+#endif
+}
+
+void rtw_cfg80211_rx_action(_adapter *adapter, union recv_frame *rframe, const char *msg)
+{
+ struct wireless_dev *wdev = adapter->rtw_wdev;
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter);
+ u8 *frame = get_recvframe_data(rframe);
+ uint frame_len = rframe->u.hdr.len;
+ s32 freq;
+ u8 ch, sch = rtw_get_oper_ch(adapter);
+ u8 category, action;
+
+ ch = rframe->u.hdr.attrib.ch ? rframe->u.hdr.attrib.ch : sch;
+ freq = rtw_ch2freq(ch);
+
+ rtw_action_frame_parse(frame, frame_len, &category, &action);
+
+ if (action == ACT_PUBLIC_GAS_INITIAL_REQ) {
+ rtw_mi_set_scan_deny(adapter, 200);
+ rtw_mi_scan_abort(adapter, false); /*rtw_scan_abort_no_wait*/
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ rtw_cfg80211_rx_mgmt(wdev, freq, 0, frame, frame_len, GFP_ATOMIC);
+#else
+ cfg80211_rx_action(adapter->pnetdev, freq, frame, frame_len, GFP_ATOMIC);
+#endif
+
+ RTW_INFO("RTW_Rx:ch=%d(%d)\n", ch, sch);
+ if (msg)
+ RTW_INFO("RTW_Rx:%s\n", msg);
+ else
+ RTW_INFO("RTW_Rx:category(%u), action(%u)\n", category, action);
+}
+
+#ifdef CONFIG_P2P
+void rtw_cfg80211_issue_p2p_provision_request(_adapter *padapter, const u8 *buf, size_t len)
+{
+ u16 wps_devicepassword_id = 0x0000;
+ uint wps_devicepassword_id_len = 0;
+ u8 wpsie[255] = { 0x00 }, p2p_ie[255] = { 0x00 };
+ uint p2p_ielen = 0;
+ uint wpsielen = 0;
+ u32 devinfo_contentlen = 0;
+ u8 devinfo_content[64] = { 0x00 };
+ u16 capability = 0;
+ uint capability_len = 0;
+
+ unsigned char category = RTW_WLAN_CATEGORY_PUBLIC;
+ u8 action = P2P_PUB_ACTION_ACTION;
+ u8 dialogToken = 1;
+ __be32 p2poui = cpu_to_be32(P2POUI);
+ u8 oui_subtype = P2P_PROVISION_DISC_REQ;
+ u32 p2pielen = 0;
+#ifdef CONFIG_WFD
+ u32 wfdielen = 0;
+#endif
+
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ __le16 *fctrl;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 *frame_body = (unsigned char *)(buf + sizeof(struct rtw_ieee80211_hdr_3addr));
+ size_t frame_body_len = len - sizeof(struct rtw_ieee80211_hdr_3addr);
+ __be16 be_tmp;
+
+ RTW_INFO("[%s] In\n", __func__);
+
+ /* prepare for building provision_request frame */
+ memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, GetAddr1Ptr(buf), ETH_ALEN);
+ memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, GetAddr1Ptr(buf), ETH_ALEN);
+
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON;
+
+ rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen);
+ rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *)&be_tmp, &wps_devicepassword_id_len);
+ wps_devicepassword_id = be16_to_cpu(be_tmp);
+
+ switch (wps_devicepassword_id) {
+ case WPS_DPID_PIN:
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL;
+ break;
+ case WPS_DPID_USER_SPEC:
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA;
+ break;
+ case WPS_DPID_MACHINE_SPEC:
+ break;
+ case WPS_DPID_REKEY:
+ break;
+ case WPS_DPID_PBC:
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON;
+ break;
+ case WPS_DPID_REGISTRAR_SPEC:
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD;
+ break;
+ default:
+ break;
+ }
+
+ if (rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, p2p_ie, &p2p_ielen)) {
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, devinfo_content, &devinfo_contentlen);
+ rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&capability, &capability_len);
+ }
+
+ /* start to build provision_request frame */
+ memset(wpsie, 0, sizeof(wpsie));
+ memset(p2p_ie, 0, sizeof(p2p_ie));
+ p2p_ielen = 0;
+
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL)
+ return;
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+
+ fctrl = &(pwlanhdr->frame_ctl);
+ *(fctrl) = 0;
+
+ memcpy(pwlanhdr->addr1, pwdinfo->tx_prov_disc_info.peerDevAddr, ETH_ALEN);
+ memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pwdinfo->tx_prov_disc_info.peerDevAddr, ETH_ALEN);
+
+ SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+ pmlmeext->mgnt_seq++;
+ set_frame_sub_type(pframe, WIFI_ACTION);
+
+ pframe += sizeof(struct rtw_ieee80211_hdr_3addr);
+ pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr);
+
+ pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen));
+ pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen));
+
+
+ /* build_prov_disc_request_p2p_ie */
+ /* P2P OUI */
+ p2pielen = 0;
+ p2p_ie[p2pielen++] = 0x50;
+ p2p_ie[p2pielen++] = 0x6F;
+ p2p_ie[p2pielen++] = 0x9A;
+ p2p_ie[p2pielen++] = 0x09; /* WFA P2P v1.0 */
+
+ /* Commented by Albert 20110301 */
+ /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */
+ /* 1. P2P Capability */
+ /* 2. Device Info */
+ /* 3. Group ID ( When joining an operating P2P Group ) */
+
+ /* P2P Capability ATTR */
+ /* Type: */
+ p2p_ie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+ /* Length: */
+ /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); */
+ RTW_PUT_LE16(p2p_ie + p2pielen, 0x0002);
+ p2pielen += 2;
+
+ /* Value: */
+ /* Device Capability Bitmap, 1 byte */
+ /* Group Capability Bitmap, 1 byte */
+ memcpy(p2p_ie + p2pielen, &capability, 2);
+ p2pielen += 2;
+
+
+ /* Device Info ATTR */
+ /* Type: */
+ p2p_ie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+ /* Length: */
+ /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+ /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+ /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); */
+ RTW_PUT_LE16(p2p_ie + p2pielen, devinfo_contentlen);
+ p2pielen += 2;
+
+ /* Value: */
+ memcpy(p2p_ie + p2pielen, devinfo_content, devinfo_contentlen);
+ p2pielen += devinfo_contentlen;
+
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2p_ie, &p2p_ielen);
+ /* p2pielen = build_prov_disc_request_p2p_ie( pwdinfo, pframe, NULL, 0, pwdinfo->tx_prov_disc_info.peerDevAddr); */
+ /* pframe += p2pielen; */
+ pattrib->pktlen += p2p_ielen;
+
+ wpsielen = 0;
+ /* WPS OUI */
+ *(__be32 *)(wpsie) = cpu_to_be32(WPSOUI);
+ wpsielen += 4;
+
+ /* WPS version */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+ wpsielen += 2;
+
+ /* Value: */
+ wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */
+
+ /* Config Method */
+ /* Type: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+ wpsielen += 2;
+
+ /* Length: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+ wpsielen += 2;
+
+ /* Value: */
+ *(__be16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request);
+ wpsielen += 2;
+
+ pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen);
+
+
+#ifdef CONFIG_WFD
+ wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe);
+ pframe += wfdielen;
+ pattrib->pktlen += wfdielen;
+#endif
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ /* dump_mgntframe(padapter, pmgntframe); */
+ if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS)
+ RTW_INFO("%s, ack to\n", __func__);
+}
+
+#ifdef CONFIG_RTW_80211R
+static s32 cfg80211_rtw_update_ft_ies(struct wiphy *wiphy,
+ struct net_device *ndev,
+ struct cfg80211_update_ft_ies_params *ftie)
+{
+ _adapter *padapter = NULL;
+ struct mlme_priv *pmlmepriv = NULL;
+ ft_priv *pftpriv = NULL;
+ unsigned long irqL;
+ u8 *p;
+ u8 *pie = NULL;
+ u32 ie_len = 0;
+
+ if (ndev == NULL)
+ return -EINVAL;
+
+ padapter = (_adapter *)rtw_netdev_priv(ndev);
+ pmlmepriv = &(padapter->mlmepriv);
+ pftpriv = &pmlmepriv->ftpriv;
+
+ p = (u8 *)ftie->ie;
+ if (ftie->ie_len <= sizeof(pftpriv->updated_ft_ies)) {
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ memcpy(pftpriv->updated_ft_ies, ftie->ie, ftie->ie_len);
+ pftpriv->updated_ft_ies_len = ftie->ie_len;
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ } else {
+ RTW_ERR("FTIEs parsing fail!\n");
+ return -EINVAL;
+ }
+
+ if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_status(padapter, RTW_FT_AUTHENTICATED_STA)) {
+ RTW_INFO("auth success, start reassoc\n");
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ rtw_set_ft_status(padapter, RTW_FT_ASSOCIATING_STA);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ start_clnt_assoc(padapter);
+ }
+
+ return 0;
+}
+#endif
+
+inline void rtw_cfg80211_set_is_roch(_adapter *adapter, bool val)
+{
+ adapter->cfg80211_wdinfo.is_ro_ch = val;
+ rtw_mi_update_iface_status(&(adapter->mlmepriv), 0);
+}
+
+inline bool rtw_cfg80211_get_is_roch(_adapter *adapter)
+{
+ return adapter->cfg80211_wdinfo.is_ro_ch;
+}
+
+static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct wireless_dev *wdev,
+#else
+ struct net_device *ndev,
+#endif
+ struct ieee80211_channel *channel,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ enum nl80211_channel_type channel_type,
+#endif
+ unsigned int duration, u64 *cookie)
+{
+ s32 err = 0;
+ u8 remain_ch = (u8) ieee80211_frequency_to_channel(channel->center_freq);
+ u8 union_ch = 0, union_bw = 0, union_offset = 0;
+ u8 i;
+ u8 ready_on_channel = false;
+ _adapter *padapter = NULL;
+ _adapter *iface;
+ struct dvobj_priv *dvobj;
+ struct rtw_wdev_priv *pwdev_priv;
+ struct mlme_ext_priv *pmlmeext;
+ struct wifidirect_info *pwdinfo;
+ struct cfg80211_wifidirect_info *pcfg80211_wdinfo;
+ u8 is_p2p_find = false;
+
+#ifndef CONFIG_RADIO_WORK
+#define RTW_ROCH_DURATION_ENLARGE
+#define RTW_ROCH_BACK_OP
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ if (wdev == wiphy_to_pd_wdev(wiphy))
+ padapter = wiphy_to_adapter(wiphy);
+ else
+ #endif
+ if (wdev_to_ndev(wdev))
+ padapter = (_adapter *)rtw_netdev_priv(wdev_to_ndev(wdev));
+ else {
+ err = -EINVAL;
+ goto exit;
+ }
+#else
+ struct wireless_dev *wdev;
+
+ if (ndev == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+ padapter = (_adapter *)rtw_netdev_priv(ndev);
+ wdev = ndev_to_wdev(ndev);
+#endif
+
+ dvobj = adapter_to_dvobj(padapter);
+ pwdev_priv = adapter_wdev_data(padapter);
+ pmlmeext = &padapter->mlmeextpriv;
+ pwdinfo = &padapter->wdinfo;
+ pcfg80211_wdinfo = &padapter->cfg80211_wdinfo;
+#ifdef CONFIG_CONCURRENT_MODE
+ is_p2p_find = (duration < (pwdinfo->ext_listen_interval)) ? true : false;
+#endif
+
+ *cookie = ATOMIC_INC_RETURN(&pcfg80211_wdinfo->ro_ch_cookie_gen);
+
+ RTW_INFO(FUNC_ADPT_FMT"%s ch:%u duration:%d, cookie:0x%llx\n"
+ , FUNC_ADPT_ARG(padapter), wdev == wiphy_to_pd_wdev(wiphy) ? " PD" : ""
+ , remain_ch, duration, *cookie);
+
+ if (rtw_ch_set_search_ch(pmlmeext->channel_set, remain_ch) < 0) {
+ RTW_WARN(FUNC_ADPT_FMT" invalid ch:%u\n", FUNC_ADPT_ARG(padapter), remain_ch);
+ err = -EFAULT;
+ goto exit;
+ }
+
+#ifdef CONFIG_MP_INCLUDED
+ if (rtw_mi_mp_mode_check(padapter)) {
+ RTW_INFO("MP mode block remain_on_channel request\n");
+ err = -EFAULT;
+ goto exit;
+ }
+#endif
+
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ rtw_scan_abort(padapter);
+#ifdef CONFIG_CONCURRENT_MODE
+ /*don't scan_abort during p2p_listen.*/
+ if (is_p2p_find)
+ rtw_mi_buddy_scan_abort(padapter, true);
+#endif /*CONFIG_CONCURRENT_MODE*/
+
+ if (rtw_cfg80211_get_is_roch(padapter) ) {
+ _cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer);
+ p2p_cancel_roch_cmd(padapter, 0, NULL, RTW_CMDF_WAIT_ACK);
+ }
+
+ /* if(!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) */
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ rtw_p2p_enable(padapter, P2P_ROLE_DEVICE);
+ padapter->wdinfo.listen_channel = remain_ch;
+ RTW_INFO(FUNC_ADPT_FMT" init listen_channel %u\n"
+ , FUNC_ADPT_ARG(padapter), padapter->wdinfo.listen_channel);
+ } else if (rtw_p2p_chk_state(pwdinfo , P2P_STATE_LISTEN)
+ && (time_after_eq((unsigned long)jiffies, (unsigned long)pwdev_priv->probe_resp_ie_update_time)
+ && rtw_get_passing_time_ms(pwdev_priv->probe_resp_ie_update_time) < 50)
+ ) {
+ if (padapter->wdinfo.listen_channel != remain_ch) {
+ padapter->wdinfo.listen_channel = remain_ch;
+ RTW_INFO(FUNC_ADPT_FMT" update listen_channel %u\n"
+ , FUNC_ADPT_ARG(padapter), padapter->wdinfo.listen_channel);
+ }
+ } else {
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo));
+ #endif
+ }
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if (check_fwstate(&iface->mlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS) ) {
+ RTW_INFO(ADPT_FMT"- _FW_UNDER_LINKING |WIFI_UNDER_WPS (mlme state:0x%x)\n", ADPT_ARG(iface), get_fwstate(&iface->mlmepriv));
+ remain_ch = iface->mlmeextpriv.cur_channel;
+ }
+ }
+
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+
+ #ifdef RTW_ROCH_DURATION_ENLARGE
+ if (duration < 400)
+ duration = duration * 3; /* extend from exper */
+ #endif
+
+#if defined(RTW_ROCH_BACK_OP) && defined(CONFIG_CONCURRENT_MODE)
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ if (is_p2p_find) /* p2p_find , duration<1000 */
+ duration = duration + pwdinfo->ext_listen_interval;
+ else /* p2p_listen, duration=5000 */
+ duration = pwdinfo->ext_listen_interval + (pwdinfo->ext_listen_interval / 4);
+ }
+#endif /*defined (RTW_ROCH_BACK_OP) && defined(CONFIG_CONCURRENT_MODE) */
+
+ rtw_cfg80211_set_is_roch(padapter, true);
+ pcfg80211_wdinfo->ro_ch_wdev = wdev;
+ pcfg80211_wdinfo->remain_on_ch_cookie = *cookie;
+ pcfg80211_wdinfo->last_ro_ch_time = jiffies;
+ memcpy(&pcfg80211_wdinfo->remain_on_ch_channel, channel, sizeof(struct ieee80211_channel));
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ pcfg80211_wdinfo->remain_on_ch_type = channel_type;
+ #endif
+ pcfg80211_wdinfo->restore_channel = rtw_get_oper_ch(padapter);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED) && (0 != rtw_mi_get_union_chan(padapter))) {
+ if ((remain_ch != rtw_mi_get_union_chan(padapter)) && !check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ if (ATOMIC_READ(&pwdev_priv->switch_ch_to) == 1 ||
+ (remain_ch != pmlmeext->cur_channel)) {
+
+ rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500);
+ ATOMIC_SET(&pwdev_priv->switch_ch_to, 0);
+
+ #ifdef RTW_ROCH_BACK_OP
+ RTW_INFO("%s, set switch ch timer, duration=%d\n", __func__, duration - pwdinfo->ext_listen_interval);
+ _set_timer(&pwdinfo->ap_p2p_switch_timer, duration - pwdinfo->ext_listen_interval);
+ #endif
+ }
+ }
+ ready_on_channel = true;
+ } else
+#endif /* CONFIG_CONCURRENT_MODE */
+ {
+ if (remain_ch != rtw_get_oper_ch(padapter))
+ ready_on_channel = true;
+ }
+
+ if (ready_on_channel ) {
+ #ifndef RTW_SINGLE_WIPHY
+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED))
+ #endif
+ {
+ #ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_get_oper_ch(padapter) != remain_ch)
+ #endif
+ {
+ /* if (!padapter->mlmepriv.LinkDetectInfo.bBusyTraffic) */
+ set_channel_bwmode(padapter, remain_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+ }
+ }
+ }
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_ScanNotify(padapter, true);
+#endif
+
+ RTW_INFO("%s, set ro ch timer, duration=%d\n", __func__, duration);
+ _set_timer(&pcfg80211_wdinfo->remain_on_ch_timer, duration);
+
+ rtw_cfg80211_ready_on_channel(wdev, *cookie, channel, channel_type, duration, GFP_KERNEL);
+
+exit:
+ return err;
+}
+
+static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct wireless_dev *wdev,
+#else
+ struct net_device *ndev,
+#endif
+ u64 cookie)
+{
+ s32 err = 0;
+ _adapter *padapter;
+ struct rtw_wdev_priv *pwdev_priv;
+ struct wifidirect_info *pwdinfo;
+ struct cfg80211_wifidirect_info *pcfg80211_wdinfo;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ if (wdev == wiphy_to_pd_wdev(wiphy))
+ padapter = wiphy_to_adapter(wiphy);
+ else
+ #endif
+ if (wdev_to_ndev(wdev))
+ padapter = (_adapter *)rtw_netdev_priv(wdev_to_ndev(wdev));
+ else {
+ err = -EINVAL;
+ goto exit;
+ }
+#else
+ struct wireless_dev *wdev;
+
+ if (ndev == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+ padapter = (_adapter *)rtw_netdev_priv(ndev);
+ wdev = ndev_to_wdev(ndev);
+#endif
+
+ pwdev_priv = adapter_wdev_data(padapter);
+ pwdinfo = &padapter->wdinfo;
+ pcfg80211_wdinfo = &padapter->cfg80211_wdinfo;
+
+ RTW_INFO(FUNC_ADPT_FMT"%s cookie:0x%llx\n"
+ , FUNC_ADPT_ARG(padapter), wdev == wiphy_to_pd_wdev(wiphy) ? " PD" : ""
+ , cookie);
+
+ if (rtw_cfg80211_get_is_roch(padapter) ) {
+ _cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer);
+ p2p_cancel_roch_cmd(padapter, cookie, wdev, RTW_CMDF_WAIT_ACK);
+ }
+
+exit:
+ return err;
+}
+
+inline int rtw_cfg80211_iface_has_p2p_group_cap(_adapter *adapter)
+{
+ struct wiphy *wiphy = adapter_to_wiphy(adapter);
+ struct rtw_wdev_priv *wdev_data = adapter_wdev_data(adapter);
+
+#if RTW_P2P_GROUP_INTERFACE
+ if (is_primary_adapter(adapter))
+ return 0;
+#endif
+ return 1;
+}
+
+inline int rtw_cfg80211_is_p2p_scan(_adapter *adapter)
+{
+#if RTW_P2P_GROUP_INTERFACE
+ if (rtw_cfg80211_iface_has_p2p_group_cap(adapter))
+#endif
+ {
+ struct wifidirect_info *wdinfo = &adapter->wdinfo;
+
+ return rtw_p2p_chk_state(wdinfo, P2P_STATE_SCAN)
+ || rtw_p2p_chk_state(wdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+ }
+
+#if RTW_P2P_GROUP_INTERFACE
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ if (wiphy_to_pd_wdev(adapter_to_wiphy(adapter))) /* pd_wdev exist */
+ return rtw_cfg80211_is_scan_by_pd_wdev(adapter);
+ #endif
+ {
+ /*
+ * For 2 RTW_P2P_GROUP_INTERFACE cases:
+ * 1. RTW_DEDICATED_P2P_DEVICE defined but upper layer don't use pd_wdev or
+ * 2. RTW_DEDICATED_P2P_DEVICE not defined
+ */
+ struct rtw_wdev_priv *wdev_data = adapter_wdev_data(adapter);
+ unsigned long irqL;
+ int is_p2p_scan = 0;
+
+ _enter_critical_bh(&wdev_data->scan_req_lock, &irqL);
+ if (wdev_data->scan_request
+ && wdev_data->scan_request->ssids
+ && wdev_data->scan_request->ie
+ ) {
+ if (!memcmp(wdev_data->scan_request->ssids->ssid, "DIRECT-", 7)
+ && rtw_get_p2p_ie((u8 *)wdev_data->scan_request->ie, wdev_data->scan_request->ie_len, NULL, NULL))
+ is_p2p_scan = 1;
+ }
+ _exit_critical_bh(&wdev_data->scan_req_lock, &irqL);
+
+ return is_p2p_scan;
+ }
+#endif
+}
+
+#if defined(RTW_DEDICATED_P2P_DEVICE)
+int rtw_pd_iface_alloc(struct wiphy *wiphy, const char *name, struct wireless_dev **pd_wdev)
+{
+ struct rtw_wiphy_data *wiphy_data = rtw_wiphy_priv(wiphy);
+ struct wireless_dev *wdev = NULL;
+ struct rtw_netdev_priv_indicator *npi;
+ _adapter *primary_adpt = wiphy_to_adapter(wiphy);
+ int ret = 0;
+
+ if (wiphy_data->pd_wdev) {
+ RTW_WARN(FUNC_WIPHY_FMT" pd_wdev already exists\n", FUNC_WIPHY_ARG(wiphy));
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev));
+ if (!wdev) {
+ RTW_WARN(FUNC_WIPHY_FMT" allocate wdev fail\n", FUNC_WIPHY_ARG(wiphy));
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_P2P_DEVICE;
+ memcpy(wdev->address, adapter_mac_addr(primary_adpt), ETH_ALEN);
+
+ wiphy_data->pd_wdev = wdev;
+ *pd_wdev = wdev;
+
+ RTW_INFO(FUNC_WIPHY_FMT" pd_wdev:%p, addr="MAC_FMT" added\n"
+ , FUNC_WIPHY_ARG(wiphy), wdev, MAC_ARG(wdev_address(wdev)));
+
+exit:
+ if (ret && wdev) {
+ rtw_mfree((u8 *)wdev, sizeof(struct wireless_dev));
+ wdev = NULL;
+ }
+
+ return ret;
+}
+
+void rtw_pd_iface_free(struct wiphy *wiphy)
+{
+ struct dvobj_priv *dvobj = wiphy_to_dvobj(wiphy);
+ struct rtw_wiphy_data *wiphy_data = rtw_wiphy_priv(wiphy);
+ u8 rtnl_lock_needed;
+
+ if (!wiphy_data->pd_wdev)
+ goto exit;
+
+ RTW_INFO(FUNC_WIPHY_FMT" pd_wdev:%p, addr="MAC_FMT"\n"
+ , FUNC_WIPHY_ARG(wiphy), wiphy_data->pd_wdev
+ , MAC_ARG(wdev_address(wiphy_data->pd_wdev)));
+
+ rtnl_lock_needed = rtw_rtnl_lock_needed(dvobj);
+ if (rtnl_lock_needed)
+ rtnl_lock();
+ cfg80211_unregister_wdev(wiphy_data->pd_wdev);
+ if (rtnl_lock_needed)
+ rtnl_unlock();
+
+ rtw_mfree((u8 *)wiphy_data->pd_wdev, sizeof(struct wireless_dev));
+ wiphy_data->pd_wdev = NULL;
+
+exit:
+ return;
+}
+
+static int cfg80211_rtw_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ _adapter *adapter = wiphy_to_adapter(wiphy);
+
+ RTW_INFO(FUNC_WIPHY_FMT" wdev=%p\n", FUNC_WIPHY_ARG(wiphy), wdev);
+
+ rtw_p2p_enable(adapter, P2P_ROLE_DEVICE);
+ return 0;
+}
+
+static void cfg80211_rtw_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ _adapter *adapter = wiphy_to_adapter(wiphy);
+
+ RTW_INFO(FUNC_WIPHY_FMT" wdev=%p\n", FUNC_WIPHY_ARG(wiphy), wdev);
+
+ if (rtw_cfg80211_is_p2p_scan(adapter))
+ rtw_scan_abort(adapter);
+
+ rtw_p2p_enable(adapter, P2P_ROLE_DISABLE);
+}
+
+inline int rtw_cfg80211_redirect_pd_wdev(struct wiphy *wiphy, u8 *ra, struct wireless_dev **wdev)
+{
+ struct wireless_dev *pd_wdev = wiphy_to_pd_wdev(wiphy);
+
+ if (pd_wdev && pd_wdev != *wdev
+ && !memcmp(wdev_address(pd_wdev), ra, ETH_ALEN)
+ ) {
+ *wdev = pd_wdev;
+ return 1;
+ }
+ return 0;
+}
+
+inline int rtw_cfg80211_is_scan_by_pd_wdev(_adapter *adapter)
+{
+ struct wiphy *wiphy = adapter_to_wiphy(adapter);
+ struct rtw_wdev_priv *wdev_data = adapter_wdev_data(adapter);
+ struct wireless_dev *wdev = NULL;
+ unsigned long irqL;
+
+ _enter_critical_bh(&wdev_data->scan_req_lock, &irqL);
+ if (wdev_data->scan_request)
+ wdev = wdev_data->scan_request->wdev;
+ _exit_critical_bh(&wdev_data->scan_req_lock, &irqL);
+
+ if (wdev && wdev == wiphy_to_pd_wdev(wiphy))
+ return 1;
+
+ return 0;
+}
+#endif /* RTW_DEDICATED_P2P_DEVICE */
+#endif /* CONFIG_P2P */
+
+inline void rtw_cfg80211_set_is_mgmt_tx(_adapter *adapter, u8 val)
+{
+ struct rtw_wdev_priv *wdev_priv = adapter_wdev_data(adapter);
+
+ wdev_priv->is_mgmt_tx = val;
+ rtw_mi_update_iface_status(&(adapter->mlmepriv), 0);
+}
+
+inline u8 rtw_cfg80211_get_is_mgmt_tx(_adapter *adapter)
+{
+ struct rtw_wdev_priv *wdev_priv = adapter_wdev_data(adapter);
+
+ return wdev_priv->is_mgmt_tx;
+}
+
+static int _cfg80211_rtw_mgmt_tx(_adapter *padapter, u8 tx_ch, u8 no_cck, const u8 *buf, size_t len, int wait_ack)
+{
+ struct xmit_frame *pmgntframe;
+ struct pkt_attrib *pattrib;
+ unsigned char *pframe;
+ int ret = _FAIL;
+ bool ack = true;
+ struct rtw_ieee80211_hdr *pwlanhdr;
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_P2P */
+ /* struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; */
+
+ rtw_mi_set_scan_deny(padapter, 1000);
+ rtw_mi_scan_abort(padapter, true);
+
+ rtw_cfg80211_set_is_mgmt_tx(padapter, 1);
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_ScanNotify(padapter, true);
+#endif
+
+#ifdef CONFIG_P2P
+ if (rtw_cfg80211_get_is_roch(padapter) ) {
+ #ifdef CONFIG_CONCURRENT_MODE
+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ RTW_INFO("%s, extend ro ch time\n", __func__);
+ _set_timer(&padapter->cfg80211_wdinfo.remain_on_ch_timer, pwdinfo->ext_listen_period);
+ }
+ #endif /* CONFIG_CONCURRENT_MODE */
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_MCC_MODE
+ if (MCC_EN(padapter)) {
+ if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC))
+ /* don't set channel, issue frame directly */
+ goto issue_mgmt_frame;
+ }
+#endif /* CONFIG_MCC_MODE */
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ u8 union_ch = rtw_mi_get_union_chan(padapter);
+ u8 co_channel = 0xff;
+ co_channel = rtw_get_oper_ch(padapter);
+
+ if (tx_ch != union_ch) {
+ u16 ext_listen_period;
+
+ if (ATOMIC_READ(&pwdev_priv->switch_ch_to) == 1) {
+ rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500);
+ ATOMIC_SET(&pwdev_priv->switch_ch_to, 0);
+ /* RTW_INFO("%s, set switch ch timer, period=%d\n", __func__, pwdinfo->ext_listen_period); */
+ /* _set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_period); */
+ }
+
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED))
+ ext_listen_period = 500;/*500ms*/
+#ifdef CONFIG_P2P
+ else
+ ext_listen_period = pwdinfo->ext_listen_period;
+
+ _set_timer(&pwdinfo->ap_p2p_switch_timer, ext_listen_period);
+#endif
+ RTW_INFO("%s, set switch ch timer, period=%d\n", __func__, ext_listen_period);
+ }
+
+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED))
+ pmlmeext->cur_channel = tx_ch;
+
+ if (tx_ch != co_channel)
+ set_channel_bwmode(padapter, tx_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+ } else
+#endif /* CONFIG_CONCURRENT_MODE */
+ /* if (tx_ch != pmlmeext->cur_channel) { */
+ if (tx_ch != rtw_get_oper_ch(padapter)) {
+ if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED))
+ pmlmeext->cur_channel = tx_ch;
+ set_channel_bwmode(padapter, tx_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+ }
+
+issue_mgmt_frame:
+ /* starting alloc mgmt frame to dump it */
+ pmgntframe = alloc_mgtxmitframe(pxmitpriv);
+ if (pmgntframe == NULL) {
+ /* ret = -ENOMEM; */
+ ret = _FAIL;
+ goto exit;
+ }
+
+ /* update attribute */
+ pattrib = &pmgntframe->attrib;
+ update_mgntframe_attrib(padapter, pattrib);
+
+ if (no_cck && IS_CCK_RATE(pattrib->rate)) {
+ /* force OFDM 6M rate*/
+ pattrib->rate = MGN_6M;
+ pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G);
+ }
+
+ pattrib->retry_ctrl = false;
+
+ memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+ pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+ memcpy(pframe, (void *)buf, len);
+ pattrib->pktlen = len;
+
+ pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
+ /* update seq number */
+ pmlmeext->mgnt_seq = GetSequence(pwlanhdr);
+ pattrib->seqnum = pmlmeext->mgnt_seq;
+ pmlmeext->mgnt_seq++;
+
+#ifdef CONFIG_P2P
+ rtw_xframe_chk_wfd_ie(pmgntframe);
+#endif /* CONFIG_P2P */
+
+ pattrib->last_txcmdsz = pattrib->pktlen;
+
+ if (wait_ack) {
+ if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS) {
+ ack = false;
+ ret = _FAIL;
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, ack == _FAIL\n", __func__);
+#endif
+ } else {
+
+#ifdef CONFIG_XMIT_ACK
+ rtw_msleep_os(50);
+#endif
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, ack=%d, ok!\n", __func__, ack);
+#endif
+ ret = _SUCCESS;
+ }
+ } else {
+ dump_mgntframe(padapter, pmgntframe);
+ ret = _SUCCESS;
+ }
+exit:
+ rtw_cfg80211_set_is_mgmt_tx(padapter, 0);
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_ScanNotify(padapter, false);
+#endif
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, ret=%d\n", __func__, ret);
+#endif
+
+ return ret;
+
+}
+
+static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct wireless_dev *wdev,
+#else
+ struct net_device *ndev,
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)) || defined(COMPAT_KERNEL_RELEASE)
+ struct ieee80211_channel *chan,
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+ bool offchan,
+ #endif
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ enum nl80211_channel_type channel_type,
+ #endif
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ bool channel_type_valid,
+ #endif
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+ unsigned int wait,
+ #endif
+ const u8 *buf, size_t len,
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ bool no_cck,
+ #endif
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+ bool dont_wait_for_ack,
+ #endif
+#else
+ struct cfg80211_mgmt_tx_params *params,
+#endif
+ u64 *cookie)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(COMPAT_KERNEL_RELEASE)
+ struct ieee80211_channel *chan = params->chan;
+ bool offchan = params->offchan;
+ unsigned int wait = params->wait;
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+ bool no_cck = params->no_cck;
+ bool dont_wait_for_ack = params->dont_wait_for_ack;
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
+ bool no_cck = 0;
+#endif
+ int ret = 0;
+ int tx_ret;
+ int wait_ack = 1;
+ u32 dump_limit = RTW_MAX_MGMT_TX_CNT;
+ u32 dump_cnt = 0;
+ bool ack = true;
+ u8 tx_ch;
+ u8 category, action;
+ u8 frame_styp;
+ int type = (-1);
+ u32 start = jiffies;
+ _adapter *padapter;
+ struct dvobj_priv *dvobj;
+ struct rtw_wdev_priv *pwdev_priv;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ if (wdev == wiphy_to_pd_wdev(wiphy))
+ padapter = wiphy_to_adapter(wiphy);
+ else
+ #endif
+ if (wdev_to_ndev(wdev))
+ padapter = (_adapter *)rtw_netdev_priv(wdev_to_ndev(wdev));
+ else {
+ ret = -EINVAL;
+ goto exit;
+ }
+#else
+ struct wireless_dev *wdev;
+
+ if (ndev == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ padapter = (_adapter *)rtw_netdev_priv(ndev);
+ wdev = ndev_to_wdev(ndev);
+#endif
+
+ if (chan == NULL) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ tx_ch = (u8)ieee80211_frequency_to_channel(chan->center_freq);
+
+ dvobj = adapter_to_dvobj(padapter);
+ pwdev_priv = adapter_wdev_data(padapter);
+
+ /* cookie generation */
+ *cookie = (unsigned long) buf;
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO(FUNC_ADPT_FMT"%s len=%zu, ch=%d"
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ ", ch_type=%d"
+ #endif
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ ", channel_type_valid=%d"
+ #endif
+ "\n", FUNC_ADPT_ARG(padapter), wdev == wiphy_to_pd_wdev(wiphy) ? " PD" : ""
+ , len, tx_ch
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ , channel_type
+ #endif
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+ , channel_type_valid
+ #endif
+ );
+#endif /* CONFIG_DEBUG_CFG80211 */
+
+ /* indicate ack before issue frame to avoid racing with rsp frame */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ rtw_cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, GFP_KERNEL);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 36))
+ cfg80211_action_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL);
+#endif
+
+ frame_styp = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)buf)->frame_ctl) & IEEE80211_FCTL_STYPE;
+ if (IEEE80211_STYPE_PROBE_RESP == frame_styp) {
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("RTW_Tx: probe_resp tx_ch=%d, no_cck=%u, da="MAC_FMT"\n", tx_ch, no_cck, MAC_ARG(GetAddr1Ptr(buf)));
+#endif /* CONFIG_DEBUG_CFG80211 */
+ wait_ack = 0;
+ goto dump;
+ }
+
+ if (rtw_action_frame_parse(buf, len, &category, &action) == false) {
+ RTW_INFO(FUNC_ADPT_FMT" frame_control:0x%x\n", FUNC_ADPT_ARG(padapter),
+ le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)buf)->frame_ctl));
+ goto exit;
+ }
+
+ RTW_INFO("RTW_Tx:tx_ch=%d, no_cck=%u, da="MAC_FMT"\n", tx_ch, no_cck, MAC_ARG(GetAddr1Ptr(buf)));
+#ifdef CONFIG_P2P
+ type = rtw_p2p_check_frames(padapter, buf, len, true);
+ if (type >= 0) {
+ no_cck = 1; /* force no CCK for P2P frames */
+ goto dump;
+ }
+#endif
+ if (category == RTW_WLAN_CATEGORY_PUBLIC)
+ RTW_INFO("RTW_Tx:%s\n", action_public_str(action));
+ else
+ RTW_INFO("RTW_Tx:category(%u), action(%u)\n", category, action);
+
+dump:
+
+ rtw_ps_deny(padapter, PS_DENY_MGNT_TX);
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -EFAULT;
+ goto cancel_ps_deny;
+ }
+
+ while (1) {
+ u32 sleep_ms = 0;
+ u32 retry_guarantee_ms = 0;
+
+ dump_cnt++;
+ tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, no_cck, buf, len, wait_ack);
+
+ switch (action) {
+ case ACT_PUBLIC_GAS_INITIAL_REQ:
+ case ACT_PUBLIC_GAS_INITIAL_RSP:
+ sleep_ms = 50;
+ retry_guarantee_ms = RTW_MAX_MGMT_TX_MS_GAS;
+ }
+
+ if (tx_ret == _SUCCESS
+ || (dump_cnt >= dump_limit && rtw_get_passing_time_ms(start) >= retry_guarantee_ms))
+ break;
+
+ if (sleep_ms > 0)
+ rtw_msleep_os(sleep_ms);
+ }
+
+ if (tx_ret != _SUCCESS || dump_cnt > 1) {
+ RTW_INFO(FUNC_ADPT_FMT" %s (%d/%d) in %d ms\n", FUNC_ADPT_ARG(padapter),
+ tx_ret == _SUCCESS ? "OK" : "FAIL", dump_cnt, dump_limit, rtw_get_passing_time_ms(start));
+ }
+
+ switch (type) {
+ case P2P_GO_NEGO_CONF:
+ if (0) {
+ RTW_INFO(FUNC_ADPT_FMT" Nego confirm. state=%u, status=%u, iaddr="MAC_FMT"\n"
+ , FUNC_ADPT_ARG(padapter), pwdev_priv->nego_info.state, pwdev_priv->nego_info.status
+ , MAC_ARG(pwdev_priv->nego_info.iface_addr));
+ }
+ if (pwdev_priv->nego_info.state == 2
+ && pwdev_priv->nego_info.status == 0
+ && rtw_check_invalid_mac_address(pwdev_priv->nego_info.iface_addr, false) == false
+ ) {
+ _adapter *intended_iface = dvobj_get_adapter_by_addr(dvobj, pwdev_priv->nego_info.iface_addr);
+
+ if (intended_iface) {
+ RTW_INFO(FUNC_ADPT_FMT" Nego confirm. Allow only "ADPT_FMT" to scan for 2000 ms\n"
+ , FUNC_ADPT_ARG(padapter), ADPT_ARG(intended_iface));
+ /* allow only intended_iface to do scan for 2000 ms */
+ rtw_mi_set_scan_deny(padapter, 2000);
+ rtw_clear_scan_deny(intended_iface);
+ }
+ }
+ break;
+ case P2P_INVIT_RESP:
+ if (pwdev_priv->invit_info.flags & BIT(0)
+ && pwdev_priv->invit_info.status == 0
+ ) {
+ RTW_INFO(FUNC_ADPT_FMT" agree with invitation of persistent group\n",
+ FUNC_ADPT_ARG(padapter));
+ #if !RTW_P2P_GROUP_INTERFACE
+ rtw_mi_buddy_set_scan_deny(padapter, 5000);
+ #endif
+ rtw_pwr_wakeup_ex(padapter, 5000);
+ }
+ break;
+ }
+
+cancel_ps_deny:
+ rtw_ps_deny_cancel(padapter, PS_DENY_MGNT_TX);
+exit:
+ return ret;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
+static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct wireless_dev *wdev,
+#else
+ struct net_device *ndev,
+#endif
+ u16 frame_type, bool reg)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ struct net_device *ndev = wdev_to_ndev(wdev);
+#endif
+ _adapter *adapter;
+
+ struct rtw_wdev_priv *pwdev_priv;
+
+ if (ndev == NULL)
+ goto exit;
+
+ adapter = (_adapter *)rtw_netdev_priv(ndev);
+ pwdev_priv = adapter_wdev_data(adapter);
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO(FUNC_ADPT_FMT" frame_type:%x, reg:%d\n", FUNC_ADPT_ARG(adapter),
+ frame_type, reg);
+#endif
+
+ /* Wait QC Verify */
+ return;
+
+ switch (frame_type) {
+ case IEEE80211_STYPE_PROBE_REQ: /* 0x0040 */
+ SET_CFG80211_REPORT_MGMT(pwdev_priv, IEEE80211_STYPE_PROBE_REQ, reg);
+ break;
+ case IEEE80211_STYPE_ACTION: /* 0x00D0 */
+ SET_CFG80211_REPORT_MGMT(pwdev_priv, IEEE80211_STYPE_ACTION, reg);
+ break;
+ default:
+ break;
+ }
+
+exit:
+ return;
+}
+#endif
+
+#if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+static int cfg80211_rtw_tdls_mgmt(struct wiphy *wiphy,
+ struct net_device *ndev,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+ const u8 *peer,
+#else
+ u8 *peer,
+#endif
+ u8 action_code,
+ u8 dialog_token,
+ u16 status_code,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+ u32 peer_capability,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
+ bool initiator,
+#endif
+ const u8 *buf,
+ size_t len)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ int ret = 0;
+ struct tdls_txmgmt txmgmt;
+
+ if (hal_chk_wl_func(padapter, WL_FUNC_TDLS) == false) {
+ RTW_INFO("Discard tdls action:%d, since hal doesn't support tdls\n", action_code);
+ goto discard;
+ }
+
+ if (rtw_tdls_is_driver_setup(padapter)) {
+ RTW_INFO("Discard tdls action:%d, let driver to set up direct link\n", action_code);
+ goto discard;
+ }
+
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+ memcpy(txmgmt.peer, peer, ETH_ALEN);
+ txmgmt.action_code = action_code;
+ txmgmt.dialog_token = dialog_token;
+ txmgmt.status_code = status_code;
+ txmgmt.len = len;
+ txmgmt.buf = (u8 *)rtw_malloc(txmgmt.len);
+ if (txmgmt.buf == NULL) {
+ ret = -ENOMEM;
+ goto bad;
+ }
+ memcpy(txmgmt.buf, (void *)buf, txmgmt.len);
+
+ /* Debug purpose */
+ RTW_INFO("%s %d\n", __func__, __LINE__);
+ RTW_INFO("peer:"MAC_FMT", action code:%d, dialog:%d, status code:%d\n",
+ MAC_ARG(txmgmt.peer), txmgmt.action_code,
+ txmgmt.dialog_token, txmgmt.status_code);
+ if (txmgmt.len > 0) {
+ int i = 0;
+ for (; i < len; i++)
+ printk("%02x ", *(txmgmt.buf + i));
+ RTW_INFO("len:%d\n", (u32)txmgmt.len);
+ }
+
+ switch (txmgmt.action_code) {
+ case TDLS_SETUP_REQUEST:
+ issue_tdls_setup_req(padapter, &txmgmt, true);
+ break;
+ case TDLS_SETUP_RESPONSE:
+ issue_tdls_setup_rsp(padapter, &txmgmt);
+ break;
+ case TDLS_SETUP_CONFIRM:
+ issue_tdls_setup_cfm(padapter, &txmgmt);
+ break;
+ case TDLS_TEARDOWN:
+ issue_tdls_teardown(padapter, &txmgmt, true);
+ break;
+ case TDLS_DISCOVERY_REQUEST:
+ issue_tdls_dis_req(padapter, &txmgmt);
+ break;
+ case TDLS_DISCOVERY_RESPONSE:
+ issue_tdls_dis_rsp(padapter, &txmgmt, pmlmeinfo->enc_algo ? true : false);
+ break;
+ }
+
+bad:
+ if (txmgmt.buf)
+ rtw_mfree(txmgmt.buf, txmgmt.len);
+
+discard:
+ return ret;
+}
+
+static int cfg80211_rtw_tdls_oper(struct wiphy *wiphy,
+ struct net_device *ndev,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+ const u8 *peer,
+#else
+ u8 *peer,
+#endif
+ enum nl80211_tdls_operation oper)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+ struct tdls_txmgmt txmgmt;
+ struct sta_info *ptdls_sta = NULL;
+
+ RTW_INFO(FUNC_NDEV_FMT", nl80211_tdls_operation:%d\n", FUNC_NDEV_ARG(ndev), oper);
+
+ if (hal_chk_wl_func(padapter, WL_FUNC_TDLS) == false) {
+ RTW_INFO("Discard tdls oper:%d, since hal doesn't support tdls\n", oper);
+ return 0;
+ }
+
+#ifdef CONFIG_LPS
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1);
+#endif /* CONFIG_LPS */
+
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+ if (peer)
+ memcpy(txmgmt.peer, peer, ETH_ALEN);
+
+ if (rtw_tdls_is_driver_setup(padapter)) {
+ /* these two cases are done by driver itself */
+ if (oper == NL80211_TDLS_ENABLE_LINK || oper == NL80211_TDLS_DISABLE_LINK)
+ return 0;
+ }
+
+ switch (oper) {
+ case NL80211_TDLS_DISCOVERY_REQ:
+ issue_tdls_dis_req(padapter, &txmgmt);
+ break;
+ case NL80211_TDLS_SETUP:
+#ifdef CONFIG_WFD
+ if (_AES_ != padapter->securitypriv.dot11PrivacyAlgrthm) {
+ if (padapter->wdinfo.wfd_tdls_weaksec )
+ issue_tdls_setup_req(padapter, &txmgmt, true);
+ else
+ RTW_INFO("[%s] Current link is not AES, SKIP sending the tdls setup request!!\n", __func__);
+ } else
+#endif /* CONFIG_WFD */
+ {
+ issue_tdls_setup_req(padapter, &txmgmt, true);
+ }
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), txmgmt.peer);
+ if (ptdls_sta != NULL) {
+ txmgmt.status_code = _RSON_TDLS_TEAR_UN_RSN_;
+ issue_tdls_teardown(padapter, &txmgmt, true);
+ } else
+ RTW_INFO("TDLS peer not found\n");
+ break;
+ case NL80211_TDLS_ENABLE_LINK:
+ RTW_INFO(FUNC_NDEV_FMT", NL80211_TDLS_ENABLE_LINK;mac:"MAC_FMT"\n", FUNC_NDEV_ARG(ndev), MAC_ARG(peer));
+ ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), (u8 *)peer);
+ if (ptdls_sta != NULL) {
+ ptdlsinfo->link_established = true;
+ ptdls_sta->tdls_sta_state |= TDLS_LINKED_STATE;
+ ptdls_sta->state |= _FW_LINKED;
+ rtw_tdls_cmd(padapter, txmgmt.peer, TDLS_ESTABLISHED);
+ }
+ break;
+ case NL80211_TDLS_DISABLE_LINK:
+ RTW_INFO(FUNC_NDEV_FMT", NL80211_TDLS_DISABLE_LINK;mac:"MAC_FMT"\n", FUNC_NDEV_ARG(ndev), MAC_ARG(peer));
+ ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), (u8 *)peer);
+ if (ptdls_sta != NULL)
+ rtw_tdls_cmd(padapter, (u8 *)peer, TDLS_TEARDOWN_STA_LOCALLY);
+ break;
+ }
+ return 0;
+}
+#endif /* CONFIG_TDLS */
+
+#if defined(CONFIG_PNO_SUPPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *request)
+{
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 ret;
+
+ if (padapter->bup == false) {
+ RTW_INFO("%s: net device is down.\n", __func__);
+ return -EIO;
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) ||
+ check_fwstate(pmlmepriv, _FW_LINKED) ||
+ check_fwstate(pmlmepriv, _FW_UNDER_LINKING) ) {
+ RTW_INFO("%s: device is busy.\n", __func__);
+ rtw_scan_abort(padapter);
+ }
+
+ if (request == NULL) {
+ RTW_INFO("%s: invalid cfg80211_requests parameters.\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = rtw_android_cfg80211_pno_setup(dev, request->ssids,
+ request->n_ssids, request->interval);
+
+ if (ret < 0) {
+ RTW_INFO("%s ret: %d\n", __func__, ret);
+ goto exit;
+ }
+
+ ret = rtw_android_pno_enable(dev, true);
+ if (ret < 0) {
+ RTW_INFO("%s ret: %d\n", __func__, ret);
+ goto exit;
+ }
+exit:
+ return ret;
+}
+
+static int cfg80211_rtw_sched_scan_stop(struct wiphy *wiphy,
+ struct net_device *dev)
+{
+ return rtw_android_pno_enable(dev, false);
+}
+#endif /* CONFIG_PNO_SUPPORT */
+
+static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf, int len)
+{
+ int ret = 0;
+ uint wps_ielen = 0;
+ u8 *wps_ie;
+ u32 p2p_ielen = 0;
+ u8 wps_oui[8] = {0x0, 0x50, 0xf2, 0x04};
+ u8 *p2p_ie;
+ u32 wfd_ielen = 0;
+ u8 *wfd_ie;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+
+ RTW_INFO(FUNC_NDEV_FMT" ielen=%d\n", FUNC_NDEV_ARG(ndev), len);
+
+ if (len > 0) {
+ wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen);
+ if (wps_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("bcn_wps_ielen=%d\n", wps_ielen);
+ #endif
+
+ if (pmlmepriv->wps_beacon_ie) {
+ u32 free_len = pmlmepriv->wps_beacon_ie_len;
+ pmlmepriv->wps_beacon_ie_len = 0;
+ rtw_mfree(pmlmepriv->wps_beacon_ie, free_len);
+ pmlmepriv->wps_beacon_ie = NULL;
+ }
+
+ pmlmepriv->wps_beacon_ie = rtw_malloc(wps_ielen);
+ if (pmlmepriv->wps_beacon_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+
+ memcpy(pmlmepriv->wps_beacon_ie, wps_ie, wps_ielen);
+ pmlmepriv->wps_beacon_ie_len = wps_ielen;
+
+ update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true);
+
+ }
+
+ /* buf += wps_ielen; */
+ /* len -= wps_ielen; */
+
+ #ifdef CONFIG_P2P
+ p2p_ie = rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("bcn_p2p_ielen=%d\n", p2p_ielen);
+ #endif
+
+ if (pmlmepriv->p2p_beacon_ie) {
+ u32 free_len = pmlmepriv->p2p_beacon_ie_len;
+ pmlmepriv->p2p_beacon_ie_len = 0;
+ rtw_mfree(pmlmepriv->p2p_beacon_ie, free_len);
+ pmlmepriv->p2p_beacon_ie = NULL;
+ }
+
+ pmlmepriv->p2p_beacon_ie = rtw_malloc(p2p_ielen);
+ if (pmlmepriv->p2p_beacon_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+
+ memcpy(pmlmepriv->p2p_beacon_ie, p2p_ie, p2p_ielen);
+ pmlmepriv->p2p_beacon_ie_len = p2p_ielen;
+
+ }
+ #endif /* CONFIG_P2P */
+
+
+ #ifdef CONFIG_WFD
+ wfd_ie = rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("bcn_wfd_ielen=%d\n", wfd_ielen);
+ #endif
+
+ if (rtw_mlme_update_wfd_ie_data(pmlmepriv, MLME_BEACON_IE, wfd_ie, wfd_ielen) != _SUCCESS)
+ return -EINVAL;
+ }
+ #endif /* CONFIG_WFD */
+
+ pmlmeext->bstart_bss = true;
+
+ }
+
+ return ret;
+
+}
+
+static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net, char *buf, int len)
+{
+ int ret = 0;
+ uint wps_ielen = 0;
+ u8 *wps_ie;
+ u32 p2p_ielen = 0;
+ u8 *p2p_ie;
+ u32 wfd_ielen = 0;
+ u8 *wfd_ie;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, ielen=%d\n", __func__, len);
+#endif
+
+ if (len > 0) {
+ wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen);
+ if (wps_ie) {
+ uint attr_contentlen = 0;
+ __be16 uconfig_method, *puconfig_method = NULL;
+
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("probe_resp_wps_ielen=%d\n", wps_ielen);
+ #endif
+
+ if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+ u8 sr = 0;
+ rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL);
+
+ if (sr != 0)
+ RTW_INFO("%s, got sr\n", __func__);
+ else {
+ RTW_INFO("GO mode process WPS under site-survey, sr no set\n");
+ return ret;
+ }
+ }
+
+ if (pmlmepriv->wps_probe_resp_ie) {
+ u32 free_len = pmlmepriv->wps_probe_resp_ie_len;
+ pmlmepriv->wps_probe_resp_ie_len = 0;
+ rtw_mfree(pmlmepriv->wps_probe_resp_ie, free_len);
+ pmlmepriv->wps_probe_resp_ie = NULL;
+ }
+
+ pmlmepriv->wps_probe_resp_ie = rtw_malloc(wps_ielen);
+ if (pmlmepriv->wps_probe_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+
+ /* add PUSH_BUTTON config_method by driver self in wpsie of probe_resp at GO Mode */
+ puconfig_method = (__be16 *)rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_CONF_METHOD , NULL, &attr_contentlen);
+ if (puconfig_method != NULL) {
+ /* struct registry_priv *pregistrypriv = &padapter->registrypriv; */
+ struct wireless_dev *wdev = padapter->rtw_wdev;
+
+ #ifdef CONFIG_DEBUG_CFG80211
+ /* printk("config_method in wpsie of probe_resp = 0x%x\n", be16_to_cpu(*puconfig_method)); */
+ #endif
+
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ /* for WIFI-DIRECT LOGO 4.2.2, AUTO GO can't set PUSH_BUTTON flags */
+ if (wdev->iftype == NL80211_IFTYPE_P2P_GO) {
+ uconfig_method = cpu_to_be16(WPS_CM_PUSH_BUTTON);
+
+ *puconfig_method &= ~uconfig_method;
+ }
+ #endif
+ }
+
+ memcpy(pmlmepriv->wps_probe_resp_ie, wps_ie, wps_ielen);
+ pmlmepriv->wps_probe_resp_ie_len = wps_ielen;
+
+ }
+
+ /* buf += wps_ielen; */
+ /* len -= wps_ielen; */
+
+ #ifdef CONFIG_P2P
+ p2p_ie = rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen);
+ if (p2p_ie) {
+ u8 is_GO = false;
+ u32 attr_contentlen = 0;
+ u16 cap_attr = 0;
+ __le16 le_tmp;
+
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("probe_resp_p2p_ielen=%d\n", p2p_ielen);
+ #endif
+
+ /* Check P2P Capability ATTR */
+ if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&le_tmp, (uint *)&attr_contentlen)) {
+ u8 grp_cap = 0;
+ /* RTW_INFO( "[%s] Got P2P Capability Attr!!\n", __func__ ); */
+ cap_attr = le16_to_cpu(le_tmp);
+ grp_cap = (u8)((cap_attr >> 8) & 0xff);
+
+ is_GO = (grp_cap & BIT(0)) ? true : false;
+
+ if (is_GO)
+ RTW_INFO("Got P2P Capability Attr, grp_cap=0x%x, is_GO\n", grp_cap);
+ }
+
+
+ if (is_GO == false) {
+ if (pmlmepriv->p2p_probe_resp_ie) {
+ u32 free_len = pmlmepriv->p2p_probe_resp_ie_len;
+ pmlmepriv->p2p_probe_resp_ie_len = 0;
+ rtw_mfree(pmlmepriv->p2p_probe_resp_ie, free_len);
+ pmlmepriv->p2p_probe_resp_ie = NULL;
+ }
+
+ pmlmepriv->p2p_probe_resp_ie = rtw_malloc(p2p_ielen);
+ if (pmlmepriv->p2p_probe_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+ memcpy(pmlmepriv->p2p_probe_resp_ie, p2p_ie, p2p_ielen);
+ pmlmepriv->p2p_probe_resp_ie_len = p2p_ielen;
+ } else {
+ if (pmlmepriv->p2p_go_probe_resp_ie) {
+ u32 free_len = pmlmepriv->p2p_go_probe_resp_ie_len;
+ pmlmepriv->p2p_go_probe_resp_ie_len = 0;
+ rtw_mfree(pmlmepriv->p2p_go_probe_resp_ie, free_len);
+ pmlmepriv->p2p_go_probe_resp_ie = NULL;
+ }
+
+ pmlmepriv->p2p_go_probe_resp_ie = rtw_malloc(p2p_ielen);
+ if (pmlmepriv->p2p_go_probe_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+
+ }
+ memcpy(pmlmepriv->p2p_go_probe_resp_ie, p2p_ie, p2p_ielen);
+ pmlmepriv->p2p_go_probe_resp_ie_len = p2p_ielen;
+ }
+
+ }
+ #endif /* CONFIG_P2P */
+
+
+ #ifdef CONFIG_WFD
+ wfd_ie = rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ #ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("probe_resp_wfd_ielen=%d\n", wfd_ielen);
+ #endif
+
+ if (rtw_mlme_update_wfd_ie_data(pmlmepriv, MLME_PROBE_RESP_IE, wfd_ie, wfd_ielen) != _SUCCESS)
+ return -EINVAL;
+ }
+ #endif /* CONFIG_WFD */
+
+ }
+
+ return ret;
+
+}
+
+static int rtw_cfg80211_set_assoc_resp_wpsp2pie(struct net_device *net, char *buf, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 *ie;
+ u32 ie_len;
+
+ RTW_INFO("%s, ielen=%d\n", __func__, len);
+
+ if (len <= 0)
+ goto exit;
+
+ ie = rtw_get_wps_ie(buf, len, NULL, &ie_len);
+ if (ie && ie_len) {
+ if (pmlmepriv->wps_assoc_resp_ie) {
+ u32 free_len = pmlmepriv->wps_assoc_resp_ie_len;
+
+ pmlmepriv->wps_assoc_resp_ie_len = 0;
+ rtw_mfree(pmlmepriv->wps_assoc_resp_ie, free_len);
+ pmlmepriv->wps_assoc_resp_ie = NULL;
+ }
+
+ pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
+ if (pmlmepriv->wps_assoc_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ memcpy(pmlmepriv->wps_assoc_resp_ie, ie, ie_len);
+ pmlmepriv->wps_assoc_resp_ie_len = ie_len;
+ }
+
+ ie = rtw_get_p2p_ie(buf, len, NULL, &ie_len);
+ if (ie && ie_len) {
+ if (pmlmepriv->p2p_assoc_resp_ie) {
+ u32 free_len = pmlmepriv->p2p_assoc_resp_ie_len;
+
+ pmlmepriv->p2p_assoc_resp_ie_len = 0;
+ rtw_mfree(pmlmepriv->p2p_assoc_resp_ie, free_len);
+ pmlmepriv->p2p_assoc_resp_ie = NULL;
+ }
+
+ pmlmepriv->p2p_assoc_resp_ie = rtw_malloc(ie_len);
+ if (pmlmepriv->p2p_assoc_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ memcpy(pmlmepriv->p2p_assoc_resp_ie, ie, ie_len);
+ pmlmepriv->p2p_assoc_resp_ie_len = ie_len;
+ }
+
+#ifdef CONFIG_WFD
+ ie = rtw_get_wfd_ie(buf, len, NULL, &ie_len);
+ if (rtw_mlme_update_wfd_ie_data(pmlmepriv, MLME_ASSOC_RESP_IE, ie, ie_len) != _SUCCESS)
+ return -EINVAL;
+#endif
+
+exit:
+ return ret;
+}
+
+int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len,
+ int type)
+{
+ int ret = 0;
+ uint wps_ielen = 0;
+ u32 p2p_ielen = 0;
+
+#ifdef CONFIG_DEBUG_CFG80211
+ RTW_INFO("%s, ielen=%d\n", __func__, len);
+#endif
+
+ if ((rtw_get_wps_ie(buf, len, NULL, &wps_ielen) && (wps_ielen > 0))
+ #ifdef CONFIG_P2P
+ || (rtw_get_p2p_ie(buf, len, NULL, &p2p_ielen) && (p2p_ielen > 0))
+ #endif
+ ) {
+ if (net != NULL) {
+ switch (type) {
+ case 0x1: /* BEACON */
+ ret = rtw_cfg80211_set_beacon_wpsp2pie(net, buf, len);
+ break;
+ case 0x2: /* PROBE_RESP */
+ ret = rtw_cfg80211_set_probe_resp_wpsp2pie(net, buf, len);
+ #ifdef CONFIG_P2P
+ if (ret == 0)
+ adapter_wdev_data((_adapter *)rtw_netdev_priv(net))->probe_resp_ie_update_time = jiffies;
+ #endif
+ break;
+ case 0x4: /* ASSOC_RESP */
+ ret = rtw_cfg80211_set_assoc_resp_wpsp2pie(net, buf, len);
+ break;
+ }
+ }
+ }
+
+ return ret;
+
+}
+
+static void rtw_cfg80211_init_ht_capab_ex(_adapter *padapter, struct ieee80211_sta_ht_cap *ht_cap, enum nl80211_band band, u8 rf_type)
+{
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+ u8 stbc_rx_enable = false;
+
+ rtw_ht_use_default_setting(padapter);
+
+ /* RX LDPC */
+ if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX))
+ ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
+ /* TX STBC */
+ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX))
+ ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
+
+ /* RX STBC */
+ if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) {
+ /*rtw_rx_stbc 0: disable, bit(0):enable 2.4g, bit(1):enable 5g*/
+ if (band == NL80211_BAND_2GHZ)
+ stbc_rx_enable = (pregistrypriv->rx_stbc & BIT(0)) ? true : false;
+ if (band == NL80211_BAND_5GHZ)
+ stbc_rx_enable = (pregistrypriv->rx_stbc & BIT(1)) ? true : false;
+
+ if (stbc_rx_enable) {
+ switch (rf_type) {
+ case RF_1T1R:
+ ht_cap->cap |= IEEE80211_HT_CAP_RX_STBC_1R;/*RX STBC One spatial stream*/
+ break;
+
+ case RF_2T2R:
+ case RF_1T2R:
+ ht_cap->cap |= IEEE80211_HT_CAP_RX_STBC_1R;/* Only one spatial-stream STBC RX is supported */
+ break;
+ case RF_3T3R:
+ case RF_3T4R:
+ case RF_4T4R:
+ ht_cap->cap |= IEEE80211_HT_CAP_RX_STBC_1R;/* Only one spatial-stream STBC RX is supported */
+ break;
+ default:
+ RTW_INFO("[warning] rf_type %d is not expected\n", rf_type);
+ break;
+ }
+ }
+ }
+}
+
+static void rtw_cfg80211_init_ht_capab(_adapter *padapter, struct ieee80211_sta_ht_cap *ht_cap, enum nl80211_band band, u8 rf_type)
+{
+ struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter);
+ u8 rx_nss = 0;
+
+ ht_cap->ht_supported = true;
+
+ ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
+ rtw_cfg80211_init_ht_capab_ex(padapter, ht_cap, band, rf_type);
+
+ /*
+ *Maximum length of AMPDU that the STA can receive.
+ *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+ */
+ ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+
+ /*Minimum MPDU start spacing , */
+ ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+
+ ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+ rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num);
+ switch (rx_nss) {
+ case 1:
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ break;
+ case 2:
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0xFF;
+ break;
+ case 3:
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0xFF;
+ ht_cap->mcs.rx_mask[2] = 0xFF;
+ break;
+ case 4:
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0xFF;
+ ht_cap->mcs.rx_mask[2] = 0xFF;
+ ht_cap->mcs.rx_mask[3] = 0xFF;
+ break;
+ default:
+ rtw_warn_on(1);
+ RTW_INFO("%s, error rf_type=%d\n", __func__, rf_type);
+ };
+
+ ht_cap->mcs.rx_highest =
+ cpu_to_le16(rtw_mcs_rate(rf_type,
+ hal_is_bw_support(padapter,
+ CHANNEL_WIDTH_40),
+ hal_is_bw_support(padapter,
+ CHANNEL_WIDTH_40) ?
+ ht_cap->cap & IEEE80211_HT_CAP_SGI_40 :
+ ht_cap->cap & IEEE80211_HT_CAP_SGI_20,
+ ht_cap->mcs.rx_mask));
+}
+
+void rtw_cfg80211_init_wdev_data(_adapter *padapter)
+{
+#ifdef CONFIG_CONCURRENT_MODE
+ struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter);
+
+ ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
+#endif
+}
+
+void rtw_cfg80211_init_wiphy(_adapter *padapter)
+{
+ u8 rf_type;
+ struct ieee80211_supported_band *bands;
+ struct wireless_dev *pwdev = padapter->rtw_wdev;
+ struct wiphy *wiphy = pwdev->wiphy;
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+ RTW_INFO("%s:rf_type=%d\n", __func__, rf_type);
+
+ if (IsSupported24G(padapter->registrypriv.wireless_mode)) {
+ bands = wiphy->bands[NL80211_BAND_2GHZ];
+ if (bands)
+ rtw_cfg80211_init_ht_capab(padapter, &bands->ht_cap, NL80211_BAND_2GHZ, rf_type);
+ }
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+ if (is_supported_5g(padapter->registrypriv.wireless_mode)) {
+ bands = wiphy->bands[NL80211_BAND_5GHZ];
+ if (bands)
+ rtw_cfg80211_init_ht_capab(padapter, &bands->ht_cap, NL80211_BAND_5GHZ, rf_type);
+ }
+#endif
+ /* init regulary domain */
+ rtw_regd_init(padapter);
+
+ /* copy mac_addr to wiphy */
+ memcpy(wiphy->perm_addr, adapter_mac_addr(padapter), ETH_ALEN);
+
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+static struct ieee80211_iface_limit rtw_limits[] = {
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ #if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
+ #endif
+ },
+ #ifdef CONFIG_AP_MODE
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP)
+ #if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ | BIT(NL80211_IFTYPE_P2P_GO)
+ #endif
+ },
+ #endif
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+ }
+ #endif
+};
+
+static struct ieee80211_iface_combination rtw_combinations[] = {
+ {
+ .limits = rtw_limits,
+ .n_limits = ARRAY_SIZE(rtw_limits),
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ .max_interfaces = 3,
+ #else
+ .max_interfaces = 2,
+ #endif
+ .num_different_channels = 1,
+ },
+};
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) */
+
+static void rtw_cfg80211_preinit_wiphy(_adapter *adapter, struct wiphy *wiphy)
+{
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct registry_priv *regsty = dvobj_to_regsty(dvobj);
+
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT;
+ wiphy->max_scan_ie_len = RTW_SCAN_IE_LEN_MAX;
+ wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS;
+
+#if CONFIG_RTW_MACADDR_ACL && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ wiphy->max_acl_mac_addrs = NUM_ACL;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) || defined(COMPAT_KERNEL_RELEASE)
+ wiphy->max_remain_on_channel_duration = RTW_MAX_REMAIN_ON_CHANNEL_DURATION;
+#endif
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_ADHOC)
+#ifdef CONFIG_AP_MODE
+ | BIT(NL80211_IFTYPE_AP)
+ #ifdef CONFIG_WIFI_MONITOR
+ | BIT(NL80211_IFTYPE_MONITOR)
+ #endif
+#endif
+#if defined(CONFIG_P2P) && ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE))
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
+ | BIT(NL80211_IFTYPE_P2P_GO)
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ | BIT(NL80211_IFTYPE_P2P_DEVICE)
+ #endif
+#endif
+ ;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+#ifdef CONFIG_AP_MODE
+ wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes;
+#endif /* CONFIG_AP_MODE */
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ #ifdef CONFIG_WIFI_MONITOR
+ wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
+ #endif
+#endif
+
+#if defined(RTW_SINGLE_WIPHY) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ wiphy->iface_combinations = rtw_combinations;
+ wiphy->n_iface_combinations = ARRAY_SIZE(rtw_combinations);
+#endif
+
+ wiphy->cipher_suites = rtw_cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites);
+
+ if (IsSupported24G(adapter->registrypriv.wireless_mode))
+ wiphy->bands[NL80211_BAND_2GHZ] = rtw_spt_band_alloc(NL80211_BAND_2GHZ);
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+ if (is_supported_5g(adapter->registrypriv.wireless_mode))
+ wiphy->bands[NL80211_BAND_5GHZ] = rtw_spt_band_alloc(NL80211_BAND_5GHZ);
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0))
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
+ /* remove WIPHY_FLAG_OFFCHAN_TX, because we not support this feature */
+ /* wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME; */
+#endif
+
+#if defined(CONFIG_PM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0))
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#else // kernel >= 4.12
+ wiphy->max_sched_scan_reqs = 1;
+#endif
+#ifdef CONFIG_PNO_SUPPORT
+ wiphy->max_sched_scan_ssids = MAX_PNO_LIST_COUNT;
+#endif
+#endif
+
+#if defined(CONFIG_PM) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
+ wiphy->wowlan = wowlan_stub;
+#else
+ wiphy->wowlan = &wowlan_stub;
+#endif
+#endif
+
+#if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+#ifndef CONFIG_TDLS_DRIVER_SETUP
+ wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP; /* Driver handles key exchange */
+ wiphy->flags |= NL80211_ATTR_HT_CAPABILITY;
+#endif /* CONFIG_TDLS_DRIVER_SETUP */
+#endif /* CONFIG_TDLS */
+
+ if (regsty->power_mgnt != PS_MODE_ACTIVE)
+ wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ else
+ wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ /* wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; */
+#endif
+}
+
+#ifdef CONFIG_RFKILL_POLL
+void rtw_cfg80211_init_rfkill(struct wiphy *wiphy)
+{
+ wiphy_rfkill_set_hw_state(wiphy, 0);
+ wiphy_rfkill_start_polling(wiphy);
+}
+
+void rtw_cfg80211_deinit_rfkill(struct wiphy *wiphy)
+{
+ wiphy_rfkill_stop_polling(wiphy);
+}
+
+static void cfg80211_rtw_rfkill_poll(struct wiphy *wiphy)
+{
+ _adapter *padapter = NULL;
+ bool blocked = false;
+ u8 valid = 0;
+
+ padapter = wiphy_to_adapter(wiphy);
+
+ if (adapter_to_dvobj(padapter)->processing_dev_remove ) {
+ /*RTW_INFO("cfg80211_rtw_rfkill_poll: device is removed!\n");*/
+ return;
+ }
+
+ blocked = rtw_hal_rfkill_poll(padapter, &valid);
+ /*RTW_INFO("cfg80211_rtw_rfkill_poll: valid=%d, blocked=%d\n",
+ valid, blocked);*/
+
+ if (valid)
+ wiphy_rfkill_set_hw_state(wiphy, blocked);
+}
+#endif
+
+static struct cfg80211_ops rtw_cfg80211_ops = {
+ .change_virtual_intf = cfg80211_rtw_change_iface,
+ .add_key = cfg80211_rtw_add_key,
+ .get_key = cfg80211_rtw_get_key,
+ .del_key = cfg80211_rtw_del_key,
+ .set_default_key = cfg80211_rtw_set_default_key,
+#if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
+ .set_rekey_data = cfg80211_rtw_set_rekey_data,
+#endif /*CONFIG_GTK_OL*/
+ .get_station = cfg80211_rtw_get_station,
+ .scan = cfg80211_rtw_scan,
+ .set_wiphy_params = cfg80211_rtw_set_wiphy_params,
+ .connect = cfg80211_rtw_connect,
+ .disconnect = cfg80211_rtw_disconnect,
+ .join_ibss = cfg80211_rtw_join_ibss,
+ .leave_ibss = cfg80211_rtw_leave_ibss,
+ .set_tx_power = cfg80211_rtw_set_txpower,
+ .get_tx_power = cfg80211_rtw_get_txpower,
+ .set_power_mgmt = cfg80211_rtw_set_power_mgmt,
+ .set_pmksa = cfg80211_rtw_set_pmksa,
+ .del_pmksa = cfg80211_rtw_del_pmksa,
+ .flush_pmksa = cfg80211_rtw_flush_pmksa,
+
+#ifdef CONFIG_AP_MODE
+ .add_virtual_intf = cfg80211_rtw_add_virtual_intf,
+ .del_virtual_intf = cfg80211_rtw_del_virtual_intf,
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE)
+ .add_beacon = cfg80211_rtw_add_beacon,
+ .set_beacon = cfg80211_rtw_set_beacon,
+ .del_beacon = cfg80211_rtw_del_beacon,
+#else
+ .start_ap = cfg80211_rtw_start_ap,
+ .change_beacon = cfg80211_rtw_change_beacon,
+ .stop_ap = cfg80211_rtw_stop_ap,
+#endif
+
+#if CONFIG_RTW_MACADDR_ACL && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ .set_mac_acl = cfg80211_rtw_set_mac_acl,
+#endif
+
+ .add_station = cfg80211_rtw_add_station,
+ .del_station = cfg80211_rtw_del_station,
+ .change_station = cfg80211_rtw_change_station,
+ .dump_station = cfg80211_rtw_dump_station,
+ .change_bss = cfg80211_rtw_change_bss,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+ .set_channel = cfg80211_rtw_set_channel,
+#endif
+ /* .auth = cfg80211_rtw_auth, */
+ /* .assoc = cfg80211_rtw_assoc, */
+#endif /* CONFIG_AP_MODE */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ .set_monitor_channel = cfg80211_rtw_set_monitor_channel,
+#endif
+
+#ifdef CONFIG_P2P
+ .remain_on_channel = cfg80211_rtw_remain_on_channel,
+ .cancel_remain_on_channel = cfg80211_rtw_cancel_remain_on_channel,
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ .start_p2p_device = cfg80211_rtw_start_p2p_device,
+ .stop_p2p_device = cfg80211_rtw_stop_p2p_device,
+ #endif
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_RTW_80211R
+ .update_ft_ies = cfg80211_rtw_update_ft_ies,
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) || defined(COMPAT_KERNEL_RELEASE)
+ .mgmt_tx = cfg80211_rtw_mgmt_tx,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
+ .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register,
+#endif
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
+ .action = cfg80211_rtw_mgmt_tx,
+#endif
+
+#if defined(CONFIG_TDLS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ .tdls_mgmt = cfg80211_rtw_tdls_mgmt,
+ .tdls_oper = cfg80211_rtw_tdls_oper,
+#endif /* CONFIG_TDLS */
+
+#if defined(CONFIG_PNO_SUPPORT) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ .sched_scan_start = cfg80211_rtw_sched_scan_start,
+ .sched_scan_stop = cfg80211_rtw_sched_scan_stop,
+#endif /* CONFIG_PNO_SUPPORT */
+#ifdef CONFIG_RFKILL_POLL
+ .rfkill_poll = cfg80211_rtw_rfkill_poll,
+#endif
+};
+
+struct wiphy *rtw_wiphy_alloc(_adapter *padapter, struct device *dev)
+{
+ struct wiphy *wiphy;
+ struct rtw_wiphy_data *wiphy_data;
+
+ /* wiphy */
+ wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wiphy_data));
+ if (!wiphy) {
+ RTW_INFO("Couldn't allocate wiphy device\n");
+ goto exit;
+ }
+ set_wiphy_dev(wiphy, dev);
+
+ /* wiphy_data */
+ wiphy_data = rtw_wiphy_priv(wiphy);
+ wiphy_data->dvobj = adapter_to_dvobj(padapter);
+#ifndef RTW_SINGLE_WIPHY
+ wiphy_data->adapter = padapter;
+#endif
+
+ rtw_cfg80211_preinit_wiphy(padapter, wiphy);
+
+ RTW_INFO(FUNC_WIPHY_FMT"\n", FUNC_WIPHY_ARG(wiphy));
+
+exit:
+ return wiphy;
+}
+
+void rtw_wiphy_free(struct wiphy *wiphy)
+{
+ if (!wiphy)
+ return;
+
+ RTW_INFO(FUNC_WIPHY_FMT"\n", FUNC_WIPHY_ARG(wiphy));
+
+ if (wiphy->bands[NL80211_BAND_2GHZ]) {
+ rtw_spt_band_free(wiphy->bands[NL80211_BAND_2GHZ]);
+ wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+ }
+ if (wiphy->bands[NL80211_BAND_5GHZ]) {
+ rtw_spt_band_free(wiphy->bands[NL80211_BAND_5GHZ]);
+ wiphy->bands[NL80211_BAND_5GHZ] = NULL;
+ }
+
+ wiphy_free(wiphy);
+}
+
+int rtw_wiphy_register(struct wiphy *wiphy)
+{
+ RTW_INFO(FUNC_WIPHY_FMT"\n", FUNC_WIPHY_ARG(wiphy));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT)
+ rtw_cfgvendor_attach(wiphy);
+#endif
+
+ return wiphy_register(wiphy);
+}
+
+void rtw_wiphy_unregister(struct wiphy *wiphy)
+{
+ RTW_INFO(FUNC_WIPHY_FMT"\n", FUNC_WIPHY_ARG(wiphy));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT)
+ rtw_cfgvendor_detach(wiphy);
+#endif
+
+ #if defined(RTW_DEDICATED_P2P_DEVICE)
+ rtw_pd_iface_free(wiphy);
+ #endif
+
+ return wiphy_unregister(wiphy);
+}
+
+int rtw_wdev_alloc(_adapter *padapter, struct wiphy *wiphy)
+{
+ int ret = 0;
+ struct net_device *pnetdev = padapter->pnetdev;
+ struct wireless_dev *wdev;
+ struct rtw_wdev_priv *pwdev_priv;
+
+ RTW_INFO("%s(padapter=%p)\n", __func__, padapter);
+
+ /* wdev */
+ wdev = (struct wireless_dev *)rtw_zmalloc(sizeof(struct wireless_dev));
+ if (!wdev) {
+ RTW_INFO("Couldn't allocate wireless device\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ wdev->wiphy = wiphy;
+ wdev->netdev = pnetdev;
+
+ wdev->iftype = NL80211_IFTYPE_STATION; /* will be init in rtw_hal_init() */
+ /* Must sync with _rtw_init_mlme_priv() */
+ /* pmlmepriv->fw_state = WIFI_STATION_STATE */
+ /* wdev->iftype = NL80211_IFTYPE_MONITOR; */ /* for rtw_setopmode_cmd() in cfg80211_rtw_change_iface() */
+ padapter->rtw_wdev = wdev;
+ pnetdev->ieee80211_ptr = wdev;
+
+ /* init pwdev_priv */
+ pwdev_priv = adapter_wdev_data(padapter);
+ pwdev_priv->rtw_wdev = wdev;
+ pwdev_priv->pmon_ndev = NULL;
+ pwdev_priv->ifname_mon[0] = '\0';
+ pwdev_priv->padapter = padapter;
+ pwdev_priv->scan_request = NULL;
+ spin_lock_init(&pwdev_priv->scan_req_lock);
+
+ pwdev_priv->p2p_enabled = false;
+ pwdev_priv->probe_resp_ie_update_time = jiffies;
+ pwdev_priv->provdisc_req_issued = false;
+ rtw_wdev_invit_info_init(&pwdev_priv->invit_info);
+ rtw_wdev_nego_info_init(&pwdev_priv->nego_info);
+
+ pwdev_priv->bandroid_scan = false;
+
+ if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE)
+ pwdev_priv->power_mgmt = true;
+ else
+ pwdev_priv->power_mgmt = false;
+
+ _rtw_mutex_init(&pwdev_priv->roch_mutex);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ ATOMIC_SET(&pwdev_priv->switch_ch_to, 1);
+#endif
+
+exit:
+ return ret;
+}
+
+void rtw_wdev_free(struct wireless_dev *wdev)
+{
+ if (!wdev)
+ return;
+
+ RTW_INFO("%s(wdev=%p)\n", __func__, wdev);
+
+ if (wdev_to_ndev(wdev)) {
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(wdev_to_ndev(wdev));
+ struct rtw_wdev_priv *wdev_priv = adapter_wdev_data(adapter);
+
+ _rtw_mutex_free(&wdev_priv->roch_mutex);
+ }
+
+ rtw_mfree((u8 *)wdev, sizeof(struct wireless_dev));
+}
+
+void rtw_wdev_unregister(struct wireless_dev *wdev)
+{
+ struct net_device *ndev;
+ _adapter *adapter;
+ struct rtw_wdev_priv *pwdev_priv;
+
+ if (!wdev)
+ return;
+
+ RTW_INFO("%s(wdev=%p)\n", __func__, wdev);
+
+ ndev = wdev_to_ndev(wdev);
+ if (!ndev)
+ return;
+
+ adapter = (_adapter *)rtw_netdev_priv(ndev);
+ pwdev_priv = adapter_wdev_data(adapter);
+
+ rtw_cfg80211_indicate_scan_done(adapter, true);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+ if (wdev->current_bss) {
+ u8 locally_generated = 1;
+ RTW_INFO(FUNC_ADPT_FMT" clear current_bss by cfg80211_disconnected\n", FUNC_ADPT_ARG(adapter));
+ cfg80211_disconnected(adapter->pnetdev, 0, NULL, 0, locally_generated, GFP_ATOMIC);
+ }
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))) || defined(COMPAT_KERNEL_RELEASE)
+ if (wdev->current_bss) {
+ RTW_INFO(FUNC_ADPT_FMT" clear current_bss by cfg80211_disconnected\n", FUNC_ADPT_ARG(adapter));
+ cfg80211_disconnected(adapter->pnetdev, 0, NULL, 0, GFP_ATOMIC);
+ }
+#endif
+
+ if (pwdev_priv->pmon_ndev) {
+ RTW_INFO("%s, unregister monitor interface\n", __func__);
+ unregister_netdev(pwdev_priv->pmon_ndev);
+ }
+}
+
+int rtw_cfg80211_ndev_res_alloc(_adapter *adapter)
+{
+ int ret = _FAIL;
+
+#if !defined(RTW_SINGLE_WIPHY)
+ struct wiphy *wiphy;
+ struct device *dev = dvobj_to_dev(adapter_to_dvobj(adapter));
+
+ wiphy = rtw_wiphy_alloc(adapter, dev);
+ if (wiphy == NULL)
+ goto exit;
+
+ adapter->wiphy = wiphy;
+#endif
+
+ if (rtw_wdev_alloc(adapter, adapter_to_wiphy(adapter)) == 0)
+ ret = _SUCCESS;
+
+#if !defined(RTW_SINGLE_WIPHY)
+ if (ret != _SUCCESS) {
+ rtw_wiphy_free(wiphy);
+ adapter->wiphy = NULL;
+ }
+#endif
+
+exit:
+ return ret;
+}
+
+void rtw_cfg80211_ndev_res_free(_adapter *adapter)
+{
+ rtw_wdev_free(adapter->rtw_wdev);
+#if !defined(RTW_SINGLE_WIPHY)
+ rtw_wiphy_free(adapter_to_wiphy(adapter));
+ adapter->wiphy = NULL;
+#endif
+}
+
+int rtw_cfg80211_ndev_res_register(_adapter *adapter)
+{
+ int ret = _FAIL;
+
+#if !defined(RTW_SINGLE_WIPHY)
+ if (rtw_wiphy_register(adapter_to_wiphy(adapter)) < 0) {
+ RTW_INFO("%s rtw_wiphy_register fail for if%d\n", __func__, (adapter->iface_id + 1));
+ goto exit;
+ }
+
+#ifdef CONFIG_RFKILL_POLL
+ rtw_cfg80211_init_rfkill(adapter_to_wiphy(adapter));
+#endif
+#endif
+
+ ret = _SUCCESS;
+
+exit:
+ return ret;
+}
+
+void rtw_cfg80211_ndev_res_unregister(_adapter *adapter)
+{
+ rtw_wdev_unregister(adapter->rtw_wdev);
+}
+
+int rtw_cfg80211_dev_res_alloc(struct dvobj_priv *dvobj)
+{
+ int ret = _FAIL;
+
+#if defined(RTW_SINGLE_WIPHY)
+ struct wiphy *wiphy;
+ struct device *dev = dvobj_to_dev(dvobj);
+
+ wiphy = rtw_wiphy_alloc(dvobj_get_primary_adapter(dvobj), dev);
+ if (wiphy == NULL)
+ goto exit;
+
+ dvobj->wiphy = wiphy;
+#endif
+
+ ret = _SUCCESS;
+
+exit:
+ return ret;
+}
+
+void rtw_cfg80211_dev_res_free(struct dvobj_priv *dvobj)
+{
+#if defined(RTW_SINGLE_WIPHY)
+ rtw_wiphy_free(dvobj_to_wiphy(dvobj));
+ dvobj->wiphy = NULL;
+#endif
+}
+
+int rtw_cfg80211_dev_res_register(struct dvobj_priv *dvobj)
+{
+ int ret = _FAIL;
+
+#if defined(RTW_SINGLE_WIPHY)
+ if (rtw_wiphy_register(dvobj_to_wiphy(dvobj)) != 0)
+ goto exit;
+
+#ifdef CONFIG_RFKILL_POLL
+ rtw_cfg80211_init_rfkill(dvobj_to_wiphy(dvobj));
+#endif
+#endif
+
+ ret = _SUCCESS;
+
+exit:
+ return ret;
+}
+
+void rtw_cfg80211_dev_res_unregister(struct dvobj_priv *dvobj)
+{
+#if defined(RTW_SINGLE_WIPHY)
+#ifdef CONFIG_RFKILL_POLL
+ rtw_cfg80211_deinit_rfkill(dvobj_to_wiphy(dvobj));
+#endif
+ rtw_wiphy_unregister(dvobj_to_wiphy(dvobj));
+#endif
+}
+
+#endif /* CONFIG_IOCTL_CFG80211 */
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.h b/drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.h
new file mode 100644
index 000000000000..a4baf5d4c995
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_cfg80211.h
@@ -0,0 +1,307 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#ifndef __IOCTL_CFG80211_H__
+#define __IOCTL_CFG80211_H__
+
+
+#if defined(RTW_USE_CFG80211_STA_EVENT)
+ #undef CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER
+#endif
+
+#ifndef RTW_P2P_GROUP_INTERFACE
+ #define RTW_P2P_GROUP_INTERFACE 0
+#endif
+
+/*
+* (RTW_P2P_GROUP_INTERFACE, RTW_DEDICATED_P2P_DEVICE)
+* (0, 0): wlan0 + p2p0(PD+PG)
+* (1, 0): wlan0(with PD) + dynamic PGs
+* (1, 1): wlan0 (with dynamic PD wdev) + dynamic PGs
+*/
+
+#if RTW_P2P_GROUP_INTERFACE
+ #ifndef CONFIG_RTW_DYNAMIC_NDEV
+ #define CONFIG_RTW_DYNAMIC_NDEV
+ #endif
+ #ifndef RTW_SINGLE_WIPHY
+ #define RTW_SINGLE_WIPHY
+ #endif
+ #ifndef CONFIG_RADIO_WORK
+ #define CONFIG_RADIO_WORK
+ #endif
+ #ifndef RTW_DEDICATED_P2P_DEVICE
+ #define RTW_DEDICATED_P2P_DEVICE
+ #endif
+#endif
+
+#if !defined(CONFIG_P2P) && RTW_P2P_GROUP_INTERFACE
+ #error "RTW_P2P_GROUP_INTERFACE can't be enabled when CONFIG_P2P is disabled\n"
+#endif
+
+#if !RTW_P2P_GROUP_INTERFACE && defined(RTW_DEDICATED_P2P_DEVICE)
+ #error "RTW_DEDICATED_P2P_DEVICE can't be enabled when RTW_P2P_GROUP_INTERFACE is disabled\n"
+#endif
+
+#if defined(RTW_DEDICATED_P2P_DEVICE) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
+ #error "RTW_DEDICATED_P2P_DEVICE can't be enabled when kernel < 3.7.0\n"
+#endif
+
+struct rtw_wdev_invit_info {
+ u8 state; /* 0: req, 1:rep */
+ u8 peer_mac[ETH_ALEN];
+ u8 group_bssid[ETH_ALEN];
+ u8 active;
+ u8 token;
+ u8 flags;
+ u8 status;
+ u8 req_op_ch;
+ u8 rsp_op_ch;
+};
+
+#define rtw_wdev_invit_info_init(invit_info) \
+ do { \
+ (invit_info)->state = 0xff; \
+ memset((invit_info)->peer_mac, 0, ETH_ALEN); \
+ memset((invit_info)->group_bssid, 0, ETH_ALEN); \
+ (invit_info)->active = 0xff; \
+ (invit_info)->token = 0; \
+ (invit_info)->flags = 0x00; \
+ (invit_info)->status = 0xff; \
+ (invit_info)->req_op_ch = 0; \
+ (invit_info)->rsp_op_ch = 0; \
+ } while (0)
+
+struct rtw_wdev_nego_info {
+ u8 state; /* 0: req, 1:rep, 2:conf */
+ u8 iface_addr[ETH_ALEN];
+ u8 peer_mac[ETH_ALEN];
+ u8 peer_iface_addr[ETH_ALEN];
+ u8 active;
+ u8 token;
+ u8 status;
+ u8 req_intent;
+ u8 req_op_ch;
+ u8 req_listen_ch;
+ u8 rsp_intent;
+ u8 rsp_op_ch;
+ u8 conf_op_ch;
+};
+
+#define rtw_wdev_nego_info_init(nego_info) \
+ do { \
+ (nego_info)->state = 0xff; \
+ memset((nego_info)->iface_addr, 0, ETH_ALEN); \
+ memset((nego_info)->peer_mac, 0, ETH_ALEN); \
+ memset((nego_info)->peer_iface_addr, 0, ETH_ALEN); \
+ (nego_info)->active = 0xff; \
+ (nego_info)->token = 0; \
+ (nego_info)->status = 0xff; \
+ (nego_info)->req_intent = 0xff; \
+ (nego_info)->req_op_ch = 0; \
+ (nego_info)->req_listen_ch = 0; \
+ (nego_info)->rsp_intent = 0xff; \
+ (nego_info)->rsp_op_ch = 0; \
+ (nego_info)->conf_op_ch = 0; \
+ } while (0)
+
+struct rtw_wdev_priv {
+ struct wireless_dev *rtw_wdev;
+
+ _adapter *padapter;
+
+ struct cfg80211_scan_request *scan_request;
+ _lock scan_req_lock;
+
+ struct net_device *pmon_ndev;/* for monitor interface */
+ char ifname_mon[IFNAMSIZ + 1]; /* interface name for monitor interface */
+
+ u8 p2p_enabled;
+ u32 probe_resp_ie_update_time;
+
+ u8 provdisc_req_issued;
+
+ struct rtw_wdev_invit_info invit_info;
+ struct rtw_wdev_nego_info nego_info;
+
+ u8 bandroid_scan;
+ bool block;
+ bool block_scan;
+ bool power_mgmt;
+
+ /* report mgmt_frame registered */
+ u16 report_mgmt;
+
+ u8 is_mgmt_tx;
+
+ _mutex roch_mutex;
+
+#ifdef CONFIG_CONCURRENT_MODE
+ ATOMIC_T switch_ch_to;
+#endif
+
+};
+
+#define wdev_to_ndev(w) ((w)->netdev)
+#define wdev_to_wiphy(w) ((w)->wiphy)
+#define ndev_to_wdev(n) ((n)->ieee80211_ptr)
+
+struct rtw_wiphy_data {
+ struct dvobj_priv *dvobj;
+
+#ifndef RTW_SINGLE_WIPHY
+ _adapter *adapter;
+#endif
+
+#if defined(RTW_DEDICATED_P2P_DEVICE)
+ struct wireless_dev *pd_wdev; /* P2P device wdev */
+#endif
+};
+
+#define rtw_wiphy_priv(wiphy) ((struct rtw_wiphy_data *)wiphy_priv(wiphy))
+#define wiphy_to_dvobj(wiphy) (((struct rtw_wiphy_data *)wiphy_priv(wiphy))->dvobj)
+#ifdef RTW_SINGLE_WIPHY
+#define wiphy_to_adapter(wiphy) (dvobj_get_primary_adapter(wiphy_to_dvobj(wiphy)))
+#else
+#define wiphy_to_adapter(wiphy) (((struct rtw_wiphy_data *)wiphy_priv(wiphy))->adapter)
+#endif
+
+#if defined(RTW_DEDICATED_P2P_DEVICE)
+#define wiphy_to_pd_wdev(wiphy) (rtw_wiphy_priv(wiphy)->pd_wdev)
+#else
+#define wiphy_to_pd_wdev(wiphy) NULL
+#endif
+
+#define WIPHY_FMT "%s"
+#define WIPHY_ARG(wiphy) wiphy_name(wiphy)
+#define FUNC_WIPHY_FMT "%s("WIPHY_FMT")"
+#define FUNC_WIPHY_ARG(wiphy) __func__, WIPHY_ARG(wiphy)
+
+#define SET_CFG80211_REPORT_MGMT(w, t, v) (w->report_mgmt |= (v ? BIT(t >> 4) : 0))
+#define GET_CFG80211_REPORT_MGMT(w, t) ((w->report_mgmt & BIT(t >> 4)) > 0)
+
+struct wiphy *rtw_wiphy_alloc(_adapter *padapter, struct device *dev);
+void rtw_wiphy_free(struct wiphy *wiphy);
+int rtw_wiphy_register(struct wiphy *wiphy);
+void rtw_wiphy_unregister(struct wiphy *wiphy);
+
+int rtw_wdev_alloc(_adapter *padapter, struct wiphy *wiphy);
+void rtw_wdev_free(struct wireless_dev *wdev);
+void rtw_wdev_unregister(struct wireless_dev *wdev);
+
+int rtw_cfg80211_ndev_res_alloc(_adapter *adapter);
+void rtw_cfg80211_ndev_res_free(_adapter *adapter);
+int rtw_cfg80211_ndev_res_register(_adapter *adapter);
+void rtw_cfg80211_ndev_res_unregister(_adapter *adapter);
+
+int rtw_cfg80211_dev_res_alloc(struct dvobj_priv *dvobj);
+void rtw_cfg80211_dev_res_free(struct dvobj_priv *dvobj);
+int rtw_cfg80211_dev_res_register(struct dvobj_priv *dvobj);
+void rtw_cfg80211_dev_res_unregister(struct dvobj_priv *dvobj);
+
+void rtw_cfg80211_init_wdev_data(_adapter *padapter);
+void rtw_cfg80211_init_wiphy(_adapter *padapter);
+
+void rtw_cfg80211_unlink_bss(_adapter *padapter, struct wlan_network *pnetwork);
+void rtw_cfg80211_surveydone_event_callback(_adapter *padapter);
+struct cfg80211_bss *rtw_cfg80211_inform_bss(_adapter *padapter, struct wlan_network *pnetwork);
+int rtw_cfg80211_check_bss(_adapter *padapter);
+void rtw_cfg80211_ibss_indicate_connect(_adapter *padapter);
+void rtw_cfg80211_indicate_connect(_adapter *padapter);
+void rtw_cfg80211_indicate_disconnect(_adapter *padapter, u16 reason, u8 locally_generated);
+void rtw_cfg80211_indicate_scan_done(_adapter *adapter, bool aborted);
+u32 rtw_cfg80211_wait_scan_req_empty(_adapter *adapter, u32 timeout_ms);
+
+#ifdef CONFIG_CONCURRENT_MODE
+u8 rtw_cfg80211_scan_via_buddy(_adapter *padapter, struct cfg80211_scan_request *request);
+void rtw_cfg80211_indicate_scan_done_for_buddy(_adapter *padapter, bool bscan_aborted);
+#endif
+
+#ifdef CONFIG_AP_MODE
+void rtw_cfg80211_indicate_sta_assoc(_adapter *padapter, u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_indicate_sta_disassoc(_adapter *padapter, unsigned char *da, unsigned short reason);
+#endif /* CONFIG_AP_MODE */
+
+#ifdef CONFIG_P2P
+void rtw_cfg80211_set_is_roch(_adapter *adapter, bool val);
+bool rtw_cfg80211_get_is_roch(_adapter *adapter);
+
+int rtw_cfg80211_iface_has_p2p_group_cap(_adapter *adapter);
+int rtw_cfg80211_is_p2p_scan(_adapter *adapter);
+#if defined(RTW_DEDICATED_P2P_DEVICE)
+int rtw_cfg80211_redirect_pd_wdev(struct wiphy *wiphy, u8 *ra, struct wireless_dev **wdev);
+int rtw_cfg80211_is_scan_by_pd_wdev(_adapter *adapter);
+int rtw_pd_iface_alloc(struct wiphy *wiphy, const char *name, struct wireless_dev **pd_wdev);
+void rtw_pd_iface_free(struct wiphy *wiphy);
+#endif
+#endif /* CONFIG_P2P */
+
+void rtw_cfg80211_set_is_mgmt_tx(_adapter *adapter, u8 val);
+u8 rtw_cfg80211_get_is_mgmt_tx(_adapter *adapter);
+
+void rtw_cfg80211_issue_p2p_provision_request(_adapter *padapter, const u8 *buf, size_t len);
+
+void rtw_cfg80211_rx_p2p_action_public(_adapter *padapter, union recv_frame *rframe);
+void rtw_cfg80211_rx_action_p2p(_adapter *padapter, union recv_frame *rframe);
+void rtw_cfg80211_rx_action(_adapter *adapter, union recv_frame *rframe, const char *msg);
+void rtw_cfg80211_rx_probe_request(_adapter *padapter, union recv_frame *rframe);
+
+int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len, int type);
+
+bool rtw_cfg80211_pwr_mgmt(_adapter *adapter);
+
+#ifdef CONFIG_RFKILL_POLL
+void rtw_cfg80211_init_rfkill(struct wiphy *wiphy);
+void rtw_cfg80211_deinit_rfkill(struct wiphy *wiphy);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE)
+#define rtw_cfg80211_rx_mgmt(wdev, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt(wdev_to_ndev(wdev), freq, buf, len, gfp)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define rtw_cfg80211_rx_mgmt(wdev, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt(wdev_to_ndev(wdev), freq, sig_dbm, buf, len, gfp)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0))
+#define rtw_cfg80211_rx_mgmt(wdev, freq, sig_dbm, buf, len, gfp) cfg80211_rx_mgmt(wdev, freq, sig_dbm, buf, len, gfp)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3 , 18 , 0))
+#define rtw_cfg80211_rx_mgmt(wdev , freq , sig_dbm , buf , len , gfp) cfg80211_rx_mgmt(wdev , freq , sig_dbm , buf , len , 0 , gfp)
+#else
+#define rtw_cfg80211_rx_mgmt(wdev , freq , sig_dbm , buf , len , gfp) cfg80211_rx_mgmt(wdev , freq , sig_dbm , buf , len , 0)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(COMPAT_KERNEL_RELEASE)
+#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len) cfg80211_send_rx_assoc((adapter)->pnetdev, buf, len)
+#else
+#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len) cfg80211_send_rx_assoc((adapter)->pnetdev, bss, buf, len)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define rtw_cfg80211_mgmt_tx_status(wdev, cookie, buf, len, ack, gfp) cfg80211_mgmt_tx_status(wdev_to_ndev(wdev), cookie, buf, len, ack, gfp)
+#else
+#define rtw_cfg80211_mgmt_tx_status(wdev, cookie, buf, len, ack, gfp) cfg80211_mgmt_tx_status(wdev, cookie, buf, len, ack, gfp)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define rtw_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel(wdev_to_ndev(wdev), cookie, chan, channel_type, duration, gfp)
+#define rtw_cfg80211_remain_on_channel_expired(wdev, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired(wdev_to_ndev(wdev), cookie, chan, chan_type, gfp)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0))
+#define rtw_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, duration, gfp)
+#define rtw_cfg80211_remain_on_channel_expired(wdev, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired(wdev, cookie, chan, chan_type, gfp)
+#else
+#define rtw_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type, duration, gfp) cfg80211_ready_on_channel(wdev, cookie, chan, duration, gfp)
+#define rtw_cfg80211_remain_on_channel_expired(wdev, cookie, chan, chan_type, gfp) cfg80211_remain_on_channel_expired(wdev, cookie, chan, gfp)
+#endif
+
+#ifdef CONFIG_RTW_80211R
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
+#define rtw_cfg80211_ft_event(adapter, parm) cfg80211_ft_event((adapter)->pnetdev, parm)
+#else
+ #error "Cannot support FT for KERNEL_VERSION < 3.10\n"
+#endif
+#endif
+
+#if (KERNEL_VERSION(4, 7, 0) >= LINUX_VERSION_CODE)
+#define NUM_NL80211_BANDS IEEE80211_NUM_BANDS
+#endif
+
+#include "rtw_cfgvendor.h"
+
+#endif /* __IOCTL_CFG80211_H__ */
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
new file mode 100644
index 000000000000..654e2baee932
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
@@ -0,0 +1,12398 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _IOCTL_LINUX_C_
+
+#include <drv_types.h>
+#include <rtw_mp.h>
+#include <rtw_mp_ioctl.h>
+#include <rtw_mlme.h>
+#include "../../hal/phydm_precomp.h"
+#ifdef RTW_HALMAC
+#include "../../hal/hal_halmac.h"
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27))
+#define iwe_stream_add_event(a, b, c, d, e) iwe_stream_add_event(b, c, d, e)
+#define iwe_stream_add_point(a, b, c, d, e) iwe_stream_add_point(b, c, d, e)
+#endif
+
+extern int rtw_ht_enable;
+
+#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV+30)
+
+#define SCAN_ITEM_SIZE 768
+#define MAX_CUSTOM_LEN 64
+#define RATE_COUNT 4
+
+/* combo scan */
+#define WEXT_CSCAN_AMOUNT 9
+#define WEXT_CSCAN_BUF_LEN 360
+#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00"
+#define WEXT_CSCAN_HEADER_SIZE 12
+#define WEXT_CSCAN_SSID_SECTION 'S'
+#define WEXT_CSCAN_CHANNEL_SECTION 'C'
+#define WEXT_CSCAN_NPROBE_SECTION 'N'
+#define WEXT_CSCAN_ACTV_DWELL_SECTION 'A'
+#define WEXT_CSCAN_PASV_DWELL_SECTION 'P'
+#define WEXT_CSCAN_HOME_DWELL_SECTION 'H'
+#define WEXT_CSCAN_TYPE_SECTION 'T'
+
+
+extern u8 key_2char2num(u8 hch, u8 lch);
+extern u8 str_2char2num(u8 hch, u8 lch);
+extern void macstr2num(u8 *dst, u8 *src);
+extern u8 convert_ip_addr(u8 hch, u8 mch, u8 lch);
+
+static u32 rtw_rates[] = {1000000, 2000000, 5500000, 11000000,
+ 6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000};
+
+static const char *const iw_operation_mode[] = {
+ "Auto", "Ad-Hoc", "Managed", "Master", "Repeater", "Secondary", "Monitor"
+};
+
+static int hex2num_i(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int hex2byte_i(const char *hex)
+{
+ int a, b;
+ a = hex2num_i(*hex++);
+ if (a < 0)
+ return -1;
+ b = hex2num_i(*hex++);
+ if (b < 0)
+ return -1;
+ return (a << 4) | b;
+}
+
+/**
+ * hwaddr_aton - Convert ASCII string to MAC address
+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+static int hwaddr_aton_i(const char *txt, u8 *addr)
+{
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ int a, b;
+
+ a = hex2num_i(*txt++);
+ if (a < 0)
+ return -1;
+ b = hex2num_i(*txt++);
+ if (b < 0)
+ return -1;
+ *addr++ = (a << 4) | b;
+ if (i < 5 && *txt++ != ':')
+ return -1;
+ }
+
+ return 0;
+}
+
+static void indicate_wx_custom_event(_adapter *padapter, char *msg)
+{
+ u8 *buff, *p;
+ union iwreq_data wrqu;
+
+ if (strlen(msg) > IW_CUSTOM_MAX) {
+ RTW_INFO("%s strlen(msg):%zu > IW_CUSTOM_MAX:%u\n", __func__ , strlen(msg), IW_CUSTOM_MAX);
+ return;
+ }
+
+ buff = rtw_zmalloc(IW_CUSTOM_MAX + 1);
+ if (!buff)
+ return;
+
+ memcpy(buff, msg, strlen(msg));
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(msg);
+
+ RTW_INFO("%s %s\n", __func__, buff);
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, IWEVCUSTOM, &wrqu, buff);
+#endif
+
+ rtw_mfree(buff, IW_CUSTOM_MAX + 1);
+
+}
+
+
+static void request_wps_pbc_event(_adapter *padapter)
+{
+ u8 *buff, *p;
+ union iwreq_data wrqu;
+
+
+ buff = rtw_malloc(IW_CUSTOM_MAX);
+ if (!buff)
+ return;
+
+ memset(buff, 0, IW_CUSTOM_MAX);
+
+ p = buff;
+
+ p += sprintf(p, "WPS_PBC_START.request=true");
+
+ memset(&wrqu, 0, sizeof(wrqu));
+
+ wrqu.data.length = p - buff;
+
+ wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? wrqu.data.length : IW_CUSTOM_MAX;
+
+ RTW_INFO("%s\n", __func__);
+
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, IWEVCUSTOM, &wrqu, buff);
+#endif
+
+ if (buff)
+ rtw_mfree(buff, IW_CUSTOM_MAX);
+
+}
+
+#ifdef CONFIG_SUPPORT_HW_WPS_PBC
+void rtw_request_wps_pbc_event(_adapter *padapter)
+{
+#ifdef RTK_DMP_PLATFORM
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12))
+ kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_NET_PBC);
+#else
+ kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_NET_PBC);
+#endif
+#else
+
+ if (padapter->pid[0] == 0) {
+ /* 0 is the default value and it means the application monitors the HW PBC doesn't privde its pid to driver. */
+ return;
+ }
+
+ rtw_signal_process(padapter->pid[0], SIGUSR1);
+
+#endif
+
+ rtw_led_control(padapter, LED_CTL_START_WPS_BOTTON);
+}
+#endif/* #ifdef CONFIG_SUPPORT_HW_WPS_PBC */
+
+void indicate_wx_scan_complete_event(_adapter *padapter)
+{
+ union iwreq_data wrqu;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+
+ /* RTW_INFO("+rtw_indicate_wx_scan_complete_event\n"); */
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, SIOCGIWSCAN, &wrqu, NULL);
+#endif
+}
+
+
+void rtw_indicate_wx_assoc_event(_adapter *padapter)
+{
+ union iwreq_data wrqu;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network));
+
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
+ memcpy(wrqu.ap_addr.sa_data, pnetwork->MacAddress, ETH_ALEN);
+ else
+ memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN);
+
+ RTW_INFO("assoc success\n");
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+void rtw_indicate_wx_disassoc_event(_adapter *padapter)
+{
+ union iwreq_data wrqu;
+
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+
+#ifndef CONFIG_IOCTL_CFG80211
+ RTW_INFO("indicate disassoc\n");
+ wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
+#endif
+}
+
+/*
+uint rtw_is_cckrates_included(u8 *rate)
+{
+ u32 i = 0;
+
+ while(rate[i]!=0)
+ {
+ if ( (((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
+ (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22) )
+ return true;
+ i++;
+ }
+
+ return false;
+}
+
+uint rtw_is_cckratesonly_included(u8 *rate)
+{
+ u32 i = 0;
+
+ while(rate[i]!=0)
+ {
+ if ( (((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+ (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22) )
+ return false;
+ i++;
+ }
+
+ return true;
+}
+*/
+
+static int search_p2p_wfd_ie(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop)
+{
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#ifdef CONFIG_WFD
+ if (SCAN_RESULT_ALL == pwdinfo->wfd_info->scan_result_type) {
+
+ } else if ((SCAN_RESULT_P2P_ONLY == pwdinfo->wfd_info->scan_result_type) ||
+ (SCAN_RESULT_WFD_TYPE == pwdinfo->wfd_info->scan_result_type))
+#endif /* CONFIG_WFD */
+ {
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ u32 blnGotP2PIE = false;
+
+ /* User is doing the P2P device discovery */
+ /* The prefix of SSID should be "DIRECT-" and the IE should contains the P2P IE. */
+ /* If not, the driver should ignore this AP and go to the next AP. */
+
+ /* Verifying the SSID */
+ if (!memcmp(pnetwork->network.Ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN)) {
+ u32 p2pielen = 0;
+
+ /* Verifying the P2P IE */
+ if (rtw_bss_ex_get_p2p_ie(&pnetwork->network, NULL, &p2pielen))
+ blnGotP2PIE = true;
+ }
+
+ if (blnGotP2PIE == false)
+ return false;
+
+ }
+ }
+
+#ifdef CONFIG_WFD
+ if (SCAN_RESULT_WFD_TYPE == pwdinfo->wfd_info->scan_result_type) {
+ u32 blnGotWFD = false;
+ u8 *wfd_ie;
+ uint wfd_ielen = 0;
+
+ wfd_ie = rtw_bss_ex_get_wfd_ie(&pnetwork->network, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ u8 *wfd_devinfo;
+ uint wfd_devlen;
+
+ wfd_devinfo = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, NULL, &wfd_devlen);
+ if (wfd_devinfo) {
+ if (pwdinfo->wfd_info->wfd_device_type == WFD_DEVINFO_PSINK) {
+ /* the first two bits will indicate the WFD device type */
+ if ((wfd_devinfo[1] & 0x03) == WFD_DEVINFO_SOURCE) {
+ /* If this device is Miracast PSink device, the scan reuslt should just provide the Miracast source. */
+ blnGotWFD = true;
+ }
+ } else if (pwdinfo->wfd_info->wfd_device_type == WFD_DEVINFO_SOURCE) {
+ /* the first two bits will indicate the WFD device type */
+ if ((wfd_devinfo[1] & 0x03) == WFD_DEVINFO_PSINK) {
+ /* If this device is Miracast source device, the scan reuslt should just provide the Miracast PSink. */
+ /* Todo: How about the SSink?! */
+ blnGotWFD = true;
+ }
+ }
+ }
+ }
+
+ if (blnGotWFD == false)
+ return false;
+ }
+#endif /* CONFIG_WFD */
+
+#endif /* CONFIG_P2P */
+ return true;
+}
+static inline char *iwe_stream_mac_addr_proess(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ /* AP MAC address */
+ iwe->cmd = SIOCGIWAP;
+ iwe->u.ap_addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(iwe->u.ap_addr.sa_data, pnetwork->network.MacAddress, ETH_ALEN);
+ start = iwe_stream_add_event(info, start, stop, iwe, IW_EV_ADDR_LEN);
+ return start;
+}
+static inline char *iwe_stream_essid_proess(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+
+ /* Add the ESSID */
+ iwe->cmd = SIOCGIWESSID;
+ iwe->u.data.flags = 1;
+ iwe->u.data.length = min((u16)pnetwork->network.Ssid.SsidLength, (u16)32);
+ start = iwe_stream_add_point(info, start, stop, iwe, pnetwork->network.Ssid.Ssid);
+ return start;
+}
+
+static inline char *iwe_stream_chan_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ if (pnetwork->network.Configuration.DSConfig < 1 /*|| pnetwork->network.Configuration.DSConfig>14*/)
+ pnetwork->network.Configuration.DSConfig = 1;
+
+ /* Add frequency/channel */
+ iwe->cmd = SIOCGIWFREQ;
+ iwe->u.freq.m = rtw_ch2freq(pnetwork->network.Configuration.DSConfig) * 100000;
+ iwe->u.freq.e = 1;
+ iwe->u.freq.i = pnetwork->network.Configuration.DSConfig;
+ start = iwe_stream_add_event(info, start, stop, iwe, IW_EV_FREQ_LEN);
+ return start;
+}
+static inline char *iwe_stream_mode_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe, u16 cap)
+{
+ /* Add mode */
+ if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
+ iwe->cmd = SIOCGIWMODE;
+ if (cap & WLAN_CAPABILITY_BSS)
+ iwe->u.mode = IW_MODE_MASTER;
+ else
+ iwe->u.mode = IW_MODE_ADHOC;
+
+ start = iwe_stream_add_event(info, start, stop, iwe, IW_EV_UINT_LEN);
+ }
+ return start;
+}
+static inline char *iwe_stream_encryption_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe, u16 cap)
+{
+
+ /* Add encryption capability */
+ iwe->cmd = SIOCGIWENCODE;
+ if (cap & WLAN_CAPABILITY_PRIVACY)
+ iwe->u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe->u.data.flags = IW_ENCODE_DISABLED;
+ iwe->u.data.length = 0;
+ start = iwe_stream_add_point(info, start, stop, iwe, pnetwork->network.Ssid.Ssid);
+ return start;
+
+}
+
+static inline char *iwe_stream_protocol_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ u16 ht_cap = false, vht_cap = false;
+ u32 ht_ielen = 0, vht_ielen = 0;
+ char *p;
+ u8 ie_offset = (pnetwork->network.Reserved[0] == 2 ? 0 : 12); /* Probe Request */
+
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(&pnetwork->network.IEs[ie_offset], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength - ie_offset);
+ if (p && ht_ielen > 0)
+ ht_cap = true;
+
+ /* Add the protocol name */
+ iwe->cmd = SIOCGIWNAME;
+ if ((rtw_is_cckratesonly_included((u8 *)&pnetwork->network.SupportedRates))) {
+ if (ht_cap )
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11bn");
+ else
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11b");
+ } else if ((rtw_is_cckrates_included((u8 *)&pnetwork->network.SupportedRates))) {
+ if (ht_cap )
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11bgn");
+ else
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11bg");
+ } else {
+ if (pnetwork->network.Configuration.DSConfig > 14) {
+ if (ht_cap )
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11an");
+ else
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11a");
+ } else {
+ if (ht_cap )
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11gn");
+ else
+ snprintf(iwe->u.name, IFNAMSIZ, "IEEE 802.11g");
+ }
+ }
+ start = iwe_stream_add_event(info, start, stop, iwe, IW_EV_CHAR_LEN);
+ return start;
+}
+
+static inline char *iwe_stream_rate_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ u32 ht_ielen = 0, vht_ielen = 0;
+ char *p;
+ u16 max_rate = 0, rate, ht_cap = false, vht_cap = false;
+ u32 i = 0;
+ u8 bw_40MHz = 0, short_GI = 0, bw_160MHz = 0, vht_highest_rate = 0;
+ u16 mcs_rate = 0, vht_data_rate = 0;
+ char custom[MAX_CUSTOM_LEN] = {0};
+ u8 ie_offset = (pnetwork->network.Reserved[0] == 2 ? 0 : 12); /* Probe Request */
+
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(&pnetwork->network.IEs[ie_offset], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength - ie_offset);
+ if (p && ht_ielen > 0) {
+ struct rtw_ieee80211_ht_cap *pht_capie;
+
+ ht_cap = true;
+ pht_capie = (struct rtw_ieee80211_ht_cap *)(p + 2);
+ memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
+ bw_40MHz = (le16_to_cpu(pht_capie->cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
+ short_GI = (le16_to_cpu(pht_capie->cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
+ }
+
+ /*Add basic and extended rates */
+ p = custom;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+ while (pnetwork->network.SupportedRates[i] != 0) {
+ rate = pnetwork->network.SupportedRates[i] & 0x7F;
+ if (rate > max_rate)
+ max_rate = rate;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
+ i++;
+ }
+ if (ht_cap ) {
+ if (mcs_rate & 0x8000) /* MCS15 */
+ max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130);
+
+ else if (mcs_rate & 0x0080) /* MCS7 */
+ max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65);
+ else { /* default MCS7 */
+ /* RTW_INFO("wx_get_scan, mcs_rate_bitmap=0x%x\n", mcs_rate); */
+ max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65);
+ }
+
+ max_rate = max_rate * 2; /* Mbps/2; */
+ }
+
+ iwe->cmd = SIOCGIWRATE;
+ iwe->u.bitrate.fixed = iwe->u.bitrate.disabled = 0;
+ iwe->u.bitrate.value = max_rate * 500000;
+ start = iwe_stream_add_event(info, start, stop, iwe, IW_EV_PARAM_LEN);
+ return start ;
+}
+
+static inline char *iwe_stream_wpa_wpa2_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ int buf_size = MAX_WPA_IE_LEN * 2;
+ /* u8 pbuf[buf_size]={0}; */
+ u8 *pbuf = rtw_zmalloc(buf_size);
+
+ u8 wpa_ie[255] = {0}, rsn_ie[255] = {0};
+ u16 i, wpa_len = 0, rsn_len = 0;
+ u8 *p;
+ sint out_len = 0;
+
+
+ if (pbuf) {
+ p = pbuf;
+
+ /* parsing WPA/WPA2 IE */
+ if (pnetwork->network.Reserved[0] != 2) { /* Probe Request */
+ out_len = rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, rsn_ie, &rsn_len, wpa_ie, &wpa_len);
+
+ if (wpa_len > 0) {
+
+ memset(pbuf, 0, buf_size);
+ p += sprintf(p, "wpa_ie=");
+ for (i = 0; i < wpa_len; i++)
+ p += sprintf(p, "%02x", wpa_ie[i]);
+
+ if (wpa_len > 100) {
+ printk("-----------------Len %d----------------\n", wpa_len);
+ for (i = 0; i < wpa_len; i++)
+ printk("%02x ", wpa_ie[i]);
+ printk("\n");
+ printk("-----------------Len %d----------------\n", wpa_len);
+ }
+
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = strlen(pbuf);
+ start = iwe_stream_add_point(info, start, stop, iwe, pbuf);
+
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = wpa_len;
+ start = iwe_stream_add_point(info, start, stop, iwe, wpa_ie);
+ }
+ if (rsn_len > 0) {
+
+ memset(pbuf, 0, buf_size);
+ p += sprintf(p, "rsn_ie=");
+ for (i = 0; i < rsn_len; i++)
+ p += sprintf(p, "%02x", rsn_ie[i]);
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = strlen(pbuf);
+ start = iwe_stream_add_point(info, start, stop, iwe, pbuf);
+
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = rsn_len;
+ start = iwe_stream_add_point(info, start, stop, iwe, rsn_ie);
+ }
+ }
+
+ rtw_mfree(pbuf, buf_size);
+ }
+ return start;
+}
+
+static inline char *iwe_stream_wps_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ /* parsing WPS IE */
+ uint cnt = 0, total_ielen;
+ u8 *wpsie_ptr = NULL;
+ uint wps_ielen = 0;
+ u8 ie_offset = (pnetwork->network.Reserved[0] == 2 ? 0 : 12);
+
+ u8 *ie_ptr = pnetwork->network.IEs + ie_offset;
+ total_ielen = pnetwork->network.IELength - ie_offset;
+
+ if (pnetwork->network.Reserved[0] == 2) { /* Probe Request */
+ ie_ptr = pnetwork->network.IEs;
+ total_ielen = pnetwork->network.IELength;
+ } else { /* Beacon or Probe Respones */
+ ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
+ total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
+ }
+ while (cnt < total_ielen) {
+ if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen > 2)) {
+ wpsie_ptr = &ie_ptr[cnt];
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = (u16)wps_ielen;
+ start = iwe_stream_add_point(info, start, stop, iwe, wpsie_ptr);
+ }
+ cnt += ie_ptr[cnt + 1] + 2; /* goto next */
+ }
+ return start;
+}
+
+static inline char *iwe_stream_wapi_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+#ifdef CONFIG_WAPI_SUPPORT
+ char *p;
+
+ if (pnetwork->network.Reserved[0] != 2) { /* Probe Request */
+ sint out_len_wapi = 0;
+ /* here use static for stack size */
+ static u8 buf_wapi[MAX_WAPI_IE_LEN * 2] = {0};
+ static u8 wapi_ie[MAX_WAPI_IE_LEN] = {0};
+ u16 wapi_len = 0;
+ u16 i;
+
+ out_len_wapi = rtw_get_wapi_ie(pnetwork->network.IEs , pnetwork->network.IELength, wapi_ie, &wapi_len);
+
+ RTW_INFO("rtw_wx_get_scan: %s ", pnetwork->network.Ssid.Ssid);
+ RTW_INFO("rtw_wx_get_scan: ssid = %d ", wapi_len);
+
+
+ if (wapi_len > 0) {
+ p = buf_wapi;
+ /* memset(buf_wapi, 0, MAX_WAPI_IE_LEN*2); */
+ p += sprintf(p, "wapi_ie=");
+ for (i = 0; i < wapi_len; i++)
+ p += sprintf(p, "%02x", wapi_ie[i]);
+
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = strlen(buf_wapi);
+ start = iwe_stream_add_point(info, start, stop, iwe, buf_wapi);
+
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = wapi_len;
+ start = iwe_stream_add_point(info, start, stop, iwe, wapi_ie);
+ }
+ }
+#endif/* #ifdef CONFIG_WAPI_SUPPORT */
+ return start;
+}
+
+static inline char *iwe_stream_rssi_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ u8 ss, sq;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ /* Add quality statistics */
+ iwe->cmd = IWEVQUAL;
+ iwe->u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED
+#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR)
+ | IW_QUAL_NOISE_UPDATED
+#else
+ | IW_QUAL_NOISE_INVALID
+#endif
+#ifdef CONFIG_SIGNAL_DISPLAY_DBM
+ | IW_QUAL_DBM
+#endif
+ ;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+ is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) {
+ ss = padapter->recvpriv.signal_strength;
+ sq = padapter->recvpriv.signal_qual;
+ } else {
+ ss = pnetwork->network.PhyInfo.SignalStrength;
+ sq = pnetwork->network.PhyInfo.SignalQuality;
+ }
+
+
+#ifdef CONFIG_SIGNAL_DISPLAY_DBM
+ iwe->u.qual.level = (u8) translate_percentage_to_dbm(ss); /* dbm */
+#else
+#ifdef CONFIG_SIGNAL_SCALE_MAPPING
+ iwe->u.qual.level = (u8)ss; /* % */
+#else
+ {
+ /* Do signal scale mapping when using percentage as the unit of signal strength, since the scale mapping is skipped in odm */
+
+ HAL_DATA_TYPE *pHal = GET_HAL_DATA(padapter);
+
+ iwe->u.qual.level = (u8)odm_signal_scale_mapping(&pHal->odmpriv, ss);
+ }
+#endif
+#endif
+
+ iwe->u.qual.qual = (u8)sq; /* signal quality */
+
+#ifdef CONFIG_PLATFORM_ROCKCHIPS
+ iwe->u.qual.noise = -100; /* noise level suggest by zhf@...kchips */
+#else
+#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR)
+ {
+ s16 tmp_noise = 0;
+ rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(pnetwork->network.Configuration.DSConfig), &(tmp_noise));
+ iwe->u.qual.noise = tmp_noise ;
+ }
+#else
+ iwe->u.qual.noise = 0; /* noise level */
+#endif
+#endif /* CONFIG_PLATFORM_ROCKCHIPS */
+
+ /* RTW_INFO("iqual=%d, ilevel=%d, inoise=%d, iupdated=%d\n", iwe.u.qual.qual, iwe.u.qual.level , iwe.u.qual.noise, iwe.u.qual.updated); */
+
+ start = iwe_stream_add_event(info, start, stop, iwe, IW_EV_QUAL_LEN);
+ return start;
+}
+
+static inline char *iwe_stream_net_rsv_process(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop, struct iw_event *iwe)
+{
+ u8 buf[32] = {0};
+ u8 *p, *pos;
+ int len;
+ p = buf;
+ pos = pnetwork->network.Reserved;
+
+ p += sprintf(p, "fm=%02X%02X", pos[1], pos[0]);
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = strlen(buf);
+ start = iwe_stream_add_point(info, start, stop, iwe, buf);
+ return start;
+}
+
+static char *translate_scan(_adapter *padapter,
+ struct iw_request_info *info, struct wlan_network *pnetwork,
+ char *start, char *stop)
+{
+ struct iw_event iwe;
+ u16 cap = 0;
+ __le16 le_tmp;
+
+ memset(&iwe, 0, sizeof(iwe));
+ if (false == search_p2p_wfd_ie(padapter, info, pnetwork, start, stop))
+ return start;
+
+ start = iwe_stream_mac_addr_proess(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_essid_proess(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_protocol_process(padapter, info, pnetwork, start, stop, &iwe);
+ if (pnetwork->network.Reserved[0] != 2) { /* Probe Request */
+ memcpy((u8 *)&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
+ cap = le16_to_cpu(le_tmp);
+ }
+
+ start = iwe_stream_mode_process(padapter, info, pnetwork, start, stop, &iwe, cap);
+ start = iwe_stream_chan_process(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_encryption_process(padapter, info, pnetwork, start, stop, &iwe, cap);
+ start = iwe_stream_rate_process(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_wpa_wpa2_process(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_wps_process(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_wapi_process(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_rssi_process(padapter, info, pnetwork, start, stop, &iwe);
+ start = iwe_stream_net_rsv_process(padapter, info, pnetwork, start, stop, &iwe);
+
+ return start;
+}
+
+static int wpa_set_auth_algs(struct net_device *dev, u32 value)
+{
+ _adapter *padapter = (_adapter *) rtw_netdev_priv(dev);
+ int ret = 0;
+
+ if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) {
+ RTW_INFO("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value);
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+ } else if (value & AUTH_ALG_SHARED_KEY) {
+ RTW_INFO("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value);
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+#ifdef CONFIG_PLATFORM_MT53XX
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+#else
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+#endif
+ } else if (value & AUTH_ALG_OPEN_SYSTEM) {
+ RTW_INFO("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n");
+ /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */
+ if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) {
+#ifdef CONFIG_PLATFORM_MT53XX
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+#else
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+#endif
+ }
+
+ } else if (value & AUTH_ALG_LEAP)
+ RTW_INFO("wpa_set_auth_algs, AUTH_ALG_LEAP\n");
+ else {
+ RTW_INFO("wpa_set_auth_algs, error!\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+
+}
+
+static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+ int ret = 0;
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_P2P */
+
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ if (param_len < (u32)((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+
+ if (param->u.crypt.idx >= WEP_KEYS
+#ifdef CONFIG_IEEE80211W
+ && param->u.crypt.idx > BIP_MAX_KEYID
+#endif /* CONFIG_IEEE80211W */
+ ) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+#ifdef CONFIG_WAPI_SUPPORT
+ if (strcmp(param->u.crypt.alg, "SMS4"))
+#endif
+ {
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RTW_INFO("wpa_set_encryption, crypt.alg = WEP\n");
+
+ wep_key_idx = param->u.crypt.idx;
+ wep_key_len = param->u.crypt.key_len;
+
+ if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
+ /* wep default key has not been set, so use this key index as default key.*/
+
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+ if (wep_key_len == 13) {
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ }
+
+ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+ }
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len;
+
+ psecuritypriv->key_mask |= BIT(wep_key_idx);
+
+ goto exit;
+ }
+
+ if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */
+ struct sta_info *psta, *pbcmc_sta;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) ) { /* sta mode */
+ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+ if (psta == NULL) {
+ /* DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
+ } else {
+ /* Jeff: don't disable ieee8021x_blocked while clearing key */
+ if (strcmp(param->u.crypt.alg, "none") != 0)
+ psta->ieee8021x_blocked = false;
+
+ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled))
+ psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+ if (param->u.crypt.set_tx == 1) { /* pairwise key */
+ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
+ /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); */
+ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+ padapter->securitypriv.busetkipkey = false;
+ /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
+ }
+
+ /* DEBUG_ERR((" param->u.crypt.key_len=%d\n",param->u.crypt.key_len)); */
+ RTW_INFO(" ~~~~set sta key:unicastkey\n");
+
+ rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, true);
+
+ psta->bpairwise_key_installed = true;
+
+ } else { /* group key */
+ if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key,
+ (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ /* only TKIP group key need to install this */
+ if (param->u.crypt.key_len > 16) {
+ memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+ }
+ padapter->securitypriv.binstallGrpkey = true;
+ /* DEBUG_ERR((" param->u.crypt.key_len=%d\n", param->u.crypt.key_len)); */
+ if (param->u.crypt.idx < 4)
+ memcpy(padapter->securitypriv.iv_seq[param->u.crypt.idx], param->u.crypt.seq, 8);
+ RTW_INFO(" ~~~~set sta key:groupkey\n");
+
+ padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
+
+ rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true);
+ }
+#ifdef CONFIG_IEEE80211W
+ else if (strcmp(param->u.crypt.alg, "BIP") == 0) {
+ int no;
+ /* printk("BIP key_len=%d , index=%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */
+ /* save the IGTK key, length 16 bytes */
+ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key,
+ (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ /*printk("IGTK key below:\n");
+ for(no=0;no<16;no++)
+ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
+ printk("\n");*/
+ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx;
+ padapter->securitypriv.binstallBIPkey = true;
+ RTW_INFO(" ~~~~set sta key:IGKT\n");
+ }
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE);
+#endif /* CONFIG_P2P */
+
+ }
+ }
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta == NULL) {
+ /* DEBUG_ERR( ("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */
+ } else {
+ /* Jeff: don't disable ieee8021x_blocked while clearing key */
+ if (strcmp(param->u.crypt.alg, "none") != 0)
+ pbcmc_sta->ieee8021x_blocked = false;
+
+ if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
+ (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled))
+ pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+ }
+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { /* adhoc mode */
+ }
+ }
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (strcmp(param->u.crypt.alg, "SMS4") == 0) {
+ PRT_WAPI_T pWapiInfo = &padapter->wapiInfo;
+ PRT_WAPI_STA_INFO pWapiSta;
+ u8 WapiASUEPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+ u8 WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+ u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ;
+
+ if (param->u.crypt.set_tx == 1) {
+ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
+ if (!memcmp(pWapiSta->PeerMacAddr, param->sta_addr, 6)) {
+ memcpy(pWapiSta->lastTxUnicastPN, WapiASUEPNInitialValueSrc, 16);
+
+ pWapiSta->wapiUsk.bSet = true;
+ memcpy(pWapiSta->wapiUsk.dataKey, param->u.crypt.key, 16);
+ memcpy(pWapiSta->wapiUsk.micKey, param->u.crypt.key + 16, 16);
+ pWapiSta->wapiUsk.keyId = param->u.crypt.idx ;
+ pWapiSta->wapiUsk.bTxEnable = true;
+
+ memcpy(pWapiSta->lastRxUnicastPNBEQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPNBKQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPNVIQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPNVOQueue, WapiAEPNInitialValueSrc, 16);
+ memcpy(pWapiSta->lastRxUnicastPN, WapiAEPNInitialValueSrc, 16);
+ pWapiSta->wapiUskUpdate.bTxEnable = false;
+ pWapiSta->wapiUskUpdate.bSet = false;
+
+ if (psecuritypriv->sw_encrypt == false || psecuritypriv->sw_decrypt == false) {
+ /* set unicast key for ASUE */
+ rtw_wapi_set_key(padapter, &pWapiSta->wapiUsk, pWapiSta, false, false);
+ }
+ }
+ }
+ } else {
+ list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
+ if (!memcmp(pWapiSta->PeerMacAddr, get_bssid(pmlmepriv), 6)) {
+ pWapiSta->wapiMsk.bSet = true;
+ memcpy(pWapiSta->wapiMsk.dataKey, param->u.crypt.key, 16);
+ memcpy(pWapiSta->wapiMsk.micKey, param->u.crypt.key + 16, 16);
+ pWapiSta->wapiMsk.keyId = param->u.crypt.idx ;
+ pWapiSta->wapiMsk.bTxEnable = false;
+ if (!pWapiSta->bSetkeyOk)
+ pWapiSta->bSetkeyOk = true;
+ pWapiSta->bAuthenticateInProgress = false;
+
+ memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16);
+
+ if (psecuritypriv->sw_decrypt == false) {
+ /* set rx broadcast key for ASUE */
+ rtw_wapi_set_key(padapter, &pWapiSta->wapiMsk, pWapiSta, true, false);
+ }
+ }
+
+ }
+ }
+ }
+#endif
+
+exit:
+
+
+ return ret;
+}
+
+static int rtw_set_wpa_ie(_adapter *padapter, char *pie, unsigned short ielen)
+{
+ u8 *buf = NULL, *pos = NULL;
+ u32 left;
+ int group_cipher = 0, pairwise_cipher = 0;
+ int ret = 0;
+ u8 null_addr[] = {0, 0, 0, 0, 0, 0};
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_P2P */
+
+ if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL)) {
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ if (pie == NULL)
+ return ret;
+ else
+ return -EINVAL;
+ }
+
+ if (ielen) {
+ buf = rtw_zmalloc(ielen);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(buf, pie , ielen);
+
+ /* dump */
+ {
+ int i;
+ RTW_INFO("\n wpa_ie(length:%d):\n", ielen);
+ for (i = 0; i < ielen; i = i + 8)
+ RTW_INFO("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
+ buf[i], buf[i + 1], buf[i + 2],
+ buf[i + 3], buf[i + 4], buf[i + 5],
+ buf[i + 6], buf[i + 7]);
+ }
+
+ pos = buf;
+ if (ielen < RSN_HEADER_LEN) {
+ ret = -1;
+ goto exit;
+ }
+
+ if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
+ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
+ }
+
+ if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
+ memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
+ }
+
+ if (group_cipher == 0)
+ group_cipher = WPA_CIPHER_NONE;
+ if (pairwise_cipher == 0)
+ pairwise_cipher = WPA_CIPHER_NONE;
+
+ switch (group_cipher) {
+ case WPA_CIPHER_NONE:
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ break;
+ case WPA_CIPHER_WEP40:
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WPA_CIPHER_TKIP:
+ padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WPA_CIPHER_CCMP:
+ padapter->securitypriv.dot118021XGrpPrivacy = _AES_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ case WPA_CIPHER_WEP104:
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ }
+
+ switch (pairwise_cipher) {
+ case WPA_CIPHER_NONE:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ break;
+ case WPA_CIPHER_WEP40:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ case WPA_CIPHER_TKIP:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case WPA_CIPHER_CCMP:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _AES_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ case WPA_CIPHER_WEP104:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ break;
+ }
+
+ _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+ {/* set wps_ie */
+ u16 cnt = 0;
+ u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+ while (cnt < ielen) {
+ eid = buf[cnt];
+
+ if ((eid == _VENDOR_SPECIFIC_IE_) && (!memcmp(&buf[cnt + 2], wps_oui, 4) )) {
+ RTW_INFO("SET WPS_IE\n");
+
+ padapter->securitypriv.wps_ie_len = ((buf[cnt + 1] + 2) < MAX_WPS_IE_LEN) ? (buf[cnt + 1] + 2) : MAX_WPS_IE_LEN;
+
+ memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len);
+
+ set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
+
+#ifdef CONFIG_P2P
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK))
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_ING);
+#endif /* CONFIG_P2P */
+ cnt += buf[cnt + 1] + 2;
+
+ break;
+ } else {
+ cnt += buf[cnt + 1] + 2; /* goto next */
+ }
+ }
+ }
+ }
+
+ /* TKIP and AES disallow multicast packets until installing group key */
+ if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_
+ || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_
+ || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
+ /* WPS open need to enable multicast
+ * || check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) ) */
+ rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr);
+
+
+exit:
+
+ if (buf)
+ rtw_mfree(buf, ielen);
+
+ return ret;
+}
+
+static int rtw_wx_get_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u16 cap;
+ u32 ht_ielen = 0;
+ char *p;
+ u8 ht_cap = false, vht_cap = false;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network;
+ NDIS_802_11_RATES_EX *prates = NULL;
+
+
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) ) {
+ /* parsing HT_CAP_IE */
+ p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength - 12);
+ if (p && ht_ielen > 0)
+ ht_cap = true;
+
+ prates = &pcur_bss->SupportedRates;
+
+ if (rtw_is_cckratesonly_included((u8 *)prates) ) {
+ if (ht_cap )
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
+ } else if ((rtw_is_cckrates_included((u8 *)prates)) ) {
+ if (ht_cap )
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg");
+ } else {
+ if (pcur_bss->Configuration.DSConfig > 14) {
+ if (ht_cap )
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a");
+ } else {
+ if (ht_cap )
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn");
+ else
+ snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g");
+ }
+ }
+ } else {
+ /* prates = &padapter->registrypriv.dev_network.SupportedRates; */
+ /* snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); */
+ snprintf(wrqu->name, IFNAMSIZ, "unassociated");
+ }
+
+
+ return 0;
+}
+
+static int rtw_wx_set_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ int exp = 1, freq = 0, div = 0;
+
+
+
+ if (wrqu->freq.m <= 1000) {
+ if (wrqu->freq.flags == IW_FREQ_AUTO) {
+ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, wrqu->freq.m) > 0) {
+ padapter->mlmeextpriv.cur_channel = wrqu->freq.m;
+ RTW_INFO("%s: channel is auto, set to channel %d\n", __func__, wrqu->freq.m);
+ } else {
+ padapter->mlmeextpriv.cur_channel = 1;
+ RTW_INFO("%s: channel is auto, Channel Plan don't match just set to channel 1\n", __func__);
+ }
+ } else {
+ padapter->mlmeextpriv.cur_channel = wrqu->freq.m;
+ RTW_INFO("%s: set to channel %d\n", __func__, padapter->mlmeextpriv.cur_channel);
+ }
+ } else {
+ while (wrqu->freq.e) {
+ exp *= 10;
+ wrqu->freq.e--;
+ }
+
+ freq = wrqu->freq.m;
+
+ while (!(freq % 10)) {
+ freq /= 10;
+ exp *= 10;
+ }
+
+ /* freq unit is MHz here */
+ div = 1000000 / exp;
+
+ if (div)
+ freq /= div;
+ else {
+ div = exp / 1000000;
+ freq *= div;
+ }
+
+ /* If freq is invalid, rtw_freq2ch() will return channel 1 */
+ padapter->mlmeextpriv.cur_channel = rtw_freq2ch(freq);
+ RTW_INFO("%s: set to channel %d\n", __func__, padapter->mlmeextpriv.cur_channel);
+ }
+
+ set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+
+
+ return 0;
+}
+
+static int rtw_wx_get_freq(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) != true) {
+
+ wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000;
+ wrqu->freq.e = 1;
+ wrqu->freq.i = pcur_bss->Configuration.DSConfig;
+
+ } else {
+ wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000;
+ wrqu->freq.e = 1;
+ wrqu->freq.i = padapter->mlmeextpriv.cur_channel;
+ }
+
+ return 0;
+}
+
+static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType ;
+ int ret = 0;
+
+
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ if (!rtw_is_hw_init_completed(padapter)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ /* initial default type */
+ dev->type = ARPHRD_ETHER;
+
+ if (wrqu->mode == IW_MODE_MONITOR) {
+ rtw_ps_deny(padapter, PS_DENY_MONITOR_MODE);
+ LeaveAllPowerSaveMode(padapter);
+ } else {
+ rtw_ps_deny_cancel(padapter, PS_DENY_MONITOR_MODE);
+ }
+
+ switch (wrqu->mode) {
+ case IW_MODE_MONITOR:
+ networkType = Ndis802_11Monitor;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
+ dev->type = ARPHRD_IEEE80211_RADIOTAP; /* IEEE 802.11 + radiotap header : 803 */
+ RTW_INFO("set_mode = IW_MODE_MONITOR\n");
+#else
+ RTW_INFO("kernel version < 2.6.24 not support IW_MODE_MONITOR\n");
+#endif
+ break;
+
+ case IW_MODE_AUTO:
+ networkType = Ndis802_11AutoUnknown;
+ RTW_INFO("set_mode = IW_MODE_AUTO\n");
+ break;
+ case IW_MODE_ADHOC:
+ networkType = Ndis802_11IBSS;
+ RTW_INFO("set_mode = IW_MODE_ADHOC\n");
+ break;
+ case IW_MODE_MASTER:
+ networkType = Ndis802_11APMode;
+ RTW_INFO("set_mode = IW_MODE_MASTER\n");
+ /* rtw_setopmode_cmd(padapter, networkType,true); */
+ break;
+ case IW_MODE_INFRA:
+ networkType = Ndis802_11Infrastructure;
+ RTW_INFO("set_mode = IW_MODE_INFRA\n");
+ break;
+
+ default:
+ ret = -EINVAL;;
+ goto exit;
+ }
+
+ /*
+ if(Ndis802_11APMode == networkType)
+ {
+ rtw_setopmode_cmd(padapter, networkType,true);
+ }
+ else
+ {
+ rtw_setopmode_cmd(padapter, Ndis802_11AutoUnknown,true);
+ }
+ */
+
+ if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) {
+
+ ret = -EPERM;
+ goto exit;
+
+ }
+
+ rtw_setopmode_cmd(padapter, networkType, true);
+
+ if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) )
+ rtw_indicate_connect(padapter);
+
+exit:
+
+
+ return ret;
+
+}
+
+static int rtw_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) )
+ wrqu->mode = IW_MODE_INFRA;
+ else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ))
+
+ wrqu->mode = IW_MODE_ADHOC;
+ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) )
+ wrqu->mode = IW_MODE_MASTER;
+ else if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE) )
+ wrqu->mode = IW_MODE_MONITOR;
+ else
+ wrqu->mode = IW_MODE_AUTO;
+
+
+ return 0;
+
+}
+
+
+static int rtw_wx_set_pmkid(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 j, blInserted = false;
+ int intReturn = false;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct iw_pmksa *pPMK = (struct iw_pmksa *) extra;
+ u8 strZeroMacAddress[ETH_ALEN] = { 0x00 };
+ u8 strIssueBssid[ETH_ALEN] = { 0x00 };
+
+ memcpy(strIssueBssid, pPMK->bssid.sa_data, ETH_ALEN);
+ if (pPMK->cmd == IW_PMKSA_ADD) {
+ RTW_INFO("[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n");
+ if (!memcmp(strIssueBssid, strZeroMacAddress, ETH_ALEN) )
+ return intReturn ;
+ else
+ intReturn = true;
+ blInserted = false;
+
+ /* overwrite PMKID */
+ for (j = 0 ; j < NUM_PMKID_CACHE; j++) {
+ if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN) ) {
+ /* BSSID is matched, the same AP => rewrite with new PMKID. */
+
+ RTW_INFO("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n");
+
+ memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+ psecuritypriv->PMKIDList[j].bUsed = true;
+ psecuritypriv->PMKIDIndex = j + 1;
+ blInserted = true;
+ break;
+ }
+ }
+
+ if (!blInserted) {
+ /* Find a new entry */
+ RTW_INFO("[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n",
+ psecuritypriv->PMKIDIndex);
+
+ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
+ memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
+
+ psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true;
+ psecuritypriv->PMKIDIndex++ ;
+ if (psecuritypriv->PMKIDIndex == 16)
+ psecuritypriv->PMKIDIndex = 0;
+ }
+ } else if (pPMK->cmd == IW_PMKSA_REMOVE) {
+ RTW_INFO("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n");
+ intReturn = true;
+ for (j = 0 ; j < NUM_PMKID_CACHE; j++) {
+ if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN) ) {
+ /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */
+ memset(psecuritypriv->PMKIDList[j].Bssid, 0x00, ETH_ALEN);
+ psecuritypriv->PMKIDList[j].bUsed = false;
+ break;
+ }
+ }
+ } else if (pPMK->cmd == IW_PMKSA_FLUSH) {
+ RTW_INFO("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n");
+ memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+ psecuritypriv->PMKIDIndex = 0;
+ intReturn = true;
+ }
+ return intReturn ;
+}
+
+static int rtw_wx_get_sens(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+#ifdef CONFIG_PLATFORM_ROCKCHIPS
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ /*
+ * 20110311 Commented by Jeff
+ * For rockchip platform's wpa_driver_wext_get_rssi
+ */
+ if (check_fwstate(pmlmepriv, _FW_LINKED) ) {
+ /* wrqu->sens.value=-padapter->recvpriv.signal_strength; */
+ wrqu->sens.value = -padapter->recvpriv.rssi;
+ /* RTW_INFO("%s: %d\n", __func__, wrqu->sens.value); */
+ wrqu->sens.fixed = 0; /* no auto select */
+ } else
+#endif
+ {
+ wrqu->sens.value = 0;
+ wrqu->sens.fixed = 0; /* no auto select */
+ wrqu->sens.disabled = 1;
+ }
+ return 0;
+}
+
+static int rtw_wx_get_range(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ u16 val;
+ int i;
+
+
+
+ wrqu->data.length = sizeof(*range);
+ memset(range, 0, sizeof(*range));
+
+ /* Let's try to keep this struct in the same order as in
+ * linux/include/wireless.h
+ */
+
+ /* TODO: See what values we can set, and remove the ones we can't
+ * set, or fill them with some default data.
+ */
+
+ /* ~5 Mb/s real (802.11b) */
+ range->throughput = 5 * 1000 * 1000;
+
+ /* TODO: Not used in 802.11b?
+ * range->min_nwid; Minimal NWID we are able to set */
+ /* TODO: Not used in 802.11b?
+ * range->max_nwid; Maximal NWID we are able to set */
+
+ /* Old Frequency (backward compat - moved lower ) */
+ /* range->old_num_channels;
+ * range->old_num_frequency;
+ * range->old_freq[6]; Filler to keep "version" at the same offset */
+
+ /* signal level threshold range */
+
+ /* Quality of link & SNR stuff */
+ /* Quality range (link, level, noise)
+ * If the quality is absolute, it will be in the range [0 ; max_qual],
+ * if the quality is dBm, it will be in the range [max_qual ; 0].
+ * Don't forget that we use 8 bit arithmetics...
+ *
+ * If percentage range is 0~100
+ * Signal strength dbm range logical is -100 ~ 0
+ * but usually value is -90 ~ -20
+ * When CONFIG_SIGNAL_SCALE_MAPPING is defined, dbm range is -95 ~ -45
+ */
+ range->max_qual.qual = 100;
+#ifdef CONFIG_SIGNAL_DISPLAY_DBM
+ range->max_qual.level = (u8)-100;
+ range->max_qual.noise = (u8)-100;
+ range->max_qual.updated = IW_QUAL_ALL_UPDATED; /* Updated all three */
+ range->max_qual.updated |= IW_QUAL_DBM;
+#else /* !CONFIG_SIGNAL_DISPLAY_DBM */
+ /* percent values between 0 and 100. */
+ range->max_qual.level = 100;
+ range->max_qual.noise = 100;
+ range->max_qual.updated = IW_QUAL_ALL_UPDATED; /* Updated all three */
+#endif /* !CONFIG_SIGNAL_DISPLAY_DBM */
+
+ /* This should contain the average/typical values of the quality
+ * indicator. This should be the threshold between a "good" and
+ * a "bad" link (example : monitor going from green to orange).
+ * Currently, user space apps like quality monitors don't have any
+ * way to calibrate the measurement. With this, they can split
+ * the range between 0 and max_qual in different quality level
+ * (using a geometric subdivision centered on the average).
+ * I expect that people doing the user space apps will feedback
+ * us on which value we need to put in each driver... */
+ range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
+#ifdef CONFIG_SIGNAL_DISPLAY_DBM
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
+ range->avg_qual.level = (u8)-70;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_ALL_UPDATED; /* Updated all three */
+ range->avg_qual.updated |= IW_QUAL_DBM;
+#else /* !CONFIG_SIGNAL_DISPLAY_DBM */
+ /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ range->avg_qual.level = 30;
+ range->avg_qual.noise = 100;
+ range->avg_qual.updated = IW_QUAL_ALL_UPDATED; /* Updated all three */
+#endif /* !CONFIG_SIGNAL_DISPLAY_DBM */
+
+ range->num_bitrates = RATE_COUNT;
+
+ for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
+ range->bitrate[i] = rtw_rates[i];
+
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->pm_capa = 0;
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 16;
+
+ /* range->retry_capa; What retry options are supported
+ * range->retry_flags; How to decode max/min retry limit
+ * range->r_time_flags; How to decode max/min retry life
+ * range->min_retry; Minimal number of retries
+ * range->max_retry; Maximal number of retries
+ * range->min_r_time; Minimal retry lifetime
+ * range->max_r_time; Maximal retry lifetime */
+
+ for (i = 0, val = 0; i < MAX_CHANNEL_NUM; i++) {
+
+ /* Include only legal frequencies for some countries */
+ if (pmlmeext->channel_set[i].ChannelNum != 0) {
+ range->freq[val].i = pmlmeext->channel_set[i].ChannelNum;
+ range->freq[val].m = rtw_ch2freq(pmlmeext->channel_set[i].ChannelNum) * 100000;
+ range->freq[val].e = 1;
+ val++;
+ }
+
+ if (val == IW_MAX_FREQUENCIES)
+ break;
+ }
+
+ range->num_channels = val;
+ range->num_frequency = val;
+
+ /* Commented by Albert 2009/10/13
+ * The following code will proivde the security capability to network manager.
+ * If the driver doesn't provide this capability to network manager,
+ * the WPA/WPA2 routers can't be choosen in the network manager. */
+
+ /*
+ #define IW_SCAN_CAPA_NONE 0x00
+ #define IW_SCAN_CAPA_ESSID 0x01
+ #define IW_SCAN_CAPA_BSSID 0x02
+ #define IW_SCAN_CAPA_CHANNEL 0x04
+ #define IW_SCAN_CAPA_MODE 0x08
+ #define IW_SCAN_CAPA_RATE 0x10
+ #define IW_SCAN_CAPA_TYPE 0x20
+ #define IW_SCAN_CAPA_TIME 0x40
+ */
+
+#if WIRELESS_EXT > 17
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+#endif
+
+#ifdef IW_SCAN_CAPA_ESSID /* WIRELESS_EXT > 21 */
+ range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE | IW_SCAN_CAPA_BSSID |
+ IW_SCAN_CAPA_CHANNEL | IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE;
+#endif
+
+
+
+ return 0;
+
+}
+
+/* set bssid flow
+ * s1. rtw_set_802_11_infrastructure_mode()
+ * s2. rtw_set_802_11_authentication_mode()
+ * s3. set_802_11_encryption_mode()
+ * s4. rtw_set_802_11_bssid() */
+static int rtw_wx_set_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *awrq,
+ char *extra)
+{
+ unsigned long irqL;
+ uint ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct sockaddr *temp = (struct sockaddr *)awrq;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ _list *phead;
+ u8 *dst_bssid, *src_bssid;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ NDIS_802_11_AUTHENTICATION_MODE authmode;
+
+ /*
+ #ifdef CONFIG_CONCURRENT_MODE
+ if(padapter->adapter_type > PRIMARY_IFACE)
+ {
+ ret = -EINVAL;
+ goto exit;
+ }
+ #endif
+ */
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ) {
+ RTW_INFO("set bssid, but buddy_intf is under scanning or linking\n");
+
+ ret = -EINVAL;
+
+ goto exit;
+ }
+#endif
+
+ rtw_ps_deny(padapter, PS_DENY_JOIN);
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+ if (!padapter->bup) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+
+ if (temp->sa_family != ARPHRD_ETHER) {
+ ret = -EINVAL;
+ goto cancel_ps_deny;
+ }
+
+ authmode = padapter->securitypriv.ndisauthtype;
+ _enter_critical_bh(&queue->lock, &irqL);
+ phead = get_list_head(queue);
+ pmlmepriv->pscanned = get_next(phead);
+
+ while (1) {
+
+ if ((rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) ) {
+ break;
+ }
+
+ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+
+ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+ dst_bssid = pnetwork->network.MacAddress;
+
+ src_bssid = temp->sa_data;
+
+ if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN)) ) {
+ if (!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode)) {
+ ret = -1;
+ _exit_critical_bh(&queue->lock, &irqL);
+ goto cancel_ps_deny;
+ }
+
+ break;
+ }
+
+ }
+ _exit_critical_bh(&queue->lock, &irqL);
+
+ rtw_set_802_11_authentication_mode(padapter, authmode);
+ /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */
+ if (rtw_set_802_11_bssid(padapter, temp->sa_data) == false) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+cancel_ps_deny:
+ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN);
+
+exit:
+ return ret;
+}
+
+static int rtw_wx_get_wap(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network;
+
+ wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+
+ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+
+
+ if (((check_fwstate(pmlmepriv, _FW_LINKED)) ) ||
+ ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) ) ||
+ ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) ))
+
+ memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN);
+ else
+ memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
+
+
+ return 0;
+
+}
+
+static int rtw_wx_set_mlme(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ u16 reason;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+
+
+ if (mlme == NULL)
+ return -1;
+
+ RTW_INFO("%s\n", __func__);
+
+ reason = mlme->reason_code;
+
+
+ RTW_INFO("%s, cmd=%d, reason=%d\n", __func__, mlme->cmd, reason);
+
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+ break;
+
+ case IW_MLME_DISASSOC:
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ u8 _status = false;
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT];
+
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_P2P */
+
+
+#ifdef DBG_IOCTL
+ RTW_INFO("DBG_IOCTL %s:%d\n", __func__, __LINE__);
+#endif
+
+#ifdef CONFIG_MP_INCLUDED
+ if (rtw_mi_mp_mode_check(padapter)) {
+ RTW_INFO("MP mode block Scan request\n");
+ ret = -EPERM;
+ goto exit;
+ }
+#endif
+ if (rtw_is_scan_deny(padapter)) {
+ indicate_wx_scan_complete_event(padapter);
+ goto exit;
+ }
+
+ rtw_ps_deny(padapter, PS_DENY_SCAN);
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+ if (!rtw_is_adapter_up(padapter)) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+#ifndef CONFIG_DOSCAN_IN_BUSYTRAFFIC
+ /* When Busy Traffic, driver do not site survey. So driver return success. */
+ /* wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout. */
+ /* modify by thomas 2011-02-22. */
+ if (rtw_mi_busy_traffic_check(padapter, false)) {
+ indicate_wx_scan_complete_event(padapter);
+ goto cancel_ps_deny;
+ }
+#endif
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+ RTW_INFO("AP mode process WPS\n");
+ indicate_wx_scan_complete_event(padapter);
+ goto cancel_ps_deny;
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ) {
+ indicate_wx_scan_complete_event(padapter);
+ goto cancel_ps_deny;
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_buddy_check_fwstate(padapter,
+ _FW_UNDER_SURVEY | _FW_UNDER_LINKING | WIFI_UNDER_WPS)) {
+
+ indicate_wx_scan_complete_event(padapter);
+ goto cancel_ps_deny;
+ }
+#endif
+
+#ifdef CONFIG_P2P
+ if (pwdinfo->p2p_state != P2P_STATE_NONE) {
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_FULL);
+ rtw_free_network_queue(padapter, true);
+ }
+#endif /* CONFIG_P2P */
+
+ memset(ssid, 0, sizeof(NDIS_802_11_SSID) * RTW_SSID_SCAN_AMOUNT);
+
+#if WIRELESS_EXT >= 17
+ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE);
+
+ memcpy(ssid[0].Ssid, req->essid, len);
+ ssid[0].SsidLength = len;
+
+ RTW_INFO("IW_SCAN_THIS_ESSID, ssid=%s, len=%d\n", req->essid, req->essid_len);
+
+ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, 1, NULL, 0);
+
+ } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE)
+ RTW_INFO("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n");
+
+ } else
+#endif
+
+ if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE
+ && !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)
+ ) {
+ int len = wrqu->data.length - WEXT_CSCAN_HEADER_SIZE;
+ char *pos = extra + WEXT_CSCAN_HEADER_SIZE;
+ char section;
+ char sec_len;
+ int ssid_index = 0;
+
+ /* RTW_INFO("%s COMBO_SCAN header is recognized\n", __func__); */
+
+ while (len >= 1) {
+ section = *(pos++);
+ len -= 1;
+
+ switch (section) {
+ case WEXT_CSCAN_SSID_SECTION:
+ /* RTW_INFO("WEXT_CSCAN_SSID_SECTION\n"); */
+ if (len < 1) {
+ len = 0;
+ break;
+ }
+
+ sec_len = *(pos++);
+ len -= 1;
+
+ if (sec_len > 0 && sec_len <= len) {
+ ssid[ssid_index].SsidLength = sec_len;
+ memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength);
+ /* RTW_INFO("%s COMBO_SCAN with specific ssid:%s, %d\n", __func__ */
+ /* , ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength); */
+ ssid_index++;
+ }
+
+ pos += sec_len;
+ len -= sec_len;
+ break;
+
+
+ case WEXT_CSCAN_CHANNEL_SECTION:
+ /* RTW_INFO("WEXT_CSCAN_CHANNEL_SECTION\n"); */
+ pos += 1;
+ len -= 1;
+ break;
+ case WEXT_CSCAN_ACTV_DWELL_SECTION:
+ /* RTW_INFO("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); */
+ pos += 2;
+ len -= 2;
+ break;
+ case WEXT_CSCAN_PASV_DWELL_SECTION:
+ /* RTW_INFO("WEXT_CSCAN_PASV_DWELL_SECTION\n"); */
+ pos += 2;
+ len -= 2;
+ break;
+ case WEXT_CSCAN_HOME_DWELL_SECTION:
+ /* RTW_INFO("WEXT_CSCAN_HOME_DWELL_SECTION\n"); */
+ pos += 2;
+ len -= 2;
+ break;
+ case WEXT_CSCAN_TYPE_SECTION:
+ /* RTW_INFO("WEXT_CSCAN_TYPE_SECTION\n"); */
+ pos += 1;
+ len -= 1;
+ break;
+ default:
+ /* RTW_INFO("Unknown CSCAN section %c\n", section); */
+ len = 0; /* stop parsing */
+ }
+ /* RTW_INFO("len:%d\n", len); */
+
+ }
+
+ /* jeff: it has still some scan paramater to parse, we only do this now... */
+ _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT, NULL, 0);
+
+ } else
+
+ _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0, NULL, 0);
+
+ if (_status == false)
+ ret = -1;
+
+cancel_ps_deny:
+ rtw_ps_deny_cancel(padapter, PS_DENY_SCAN);
+
+exit:
+#ifdef DBG_IOCTL
+ RTW_INFO("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret);
+#endif
+
+ return ret;
+}
+
+static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ unsigned long irqL;
+ _list *plist, *phead;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ char *ev = extra;
+ char *stop = ev + wrqu->data.length;
+ u32 ret = 0;
+ u32 cnt = 0;
+ u32 wait_for_surveydone;
+ sint wait_status;
+
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_P2P */
+
+
+#ifdef DBG_IOCTL
+ RTW_INFO("DBG_IOCTL %s:%d\n", __func__, __LINE__);
+#endif
+
+ if (adapter_to_pwrctl(padapter)->brfoffbyhw && rtw_is_drv_stopped(padapter)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+#ifdef CONFIG_P2P
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+ wait_for_surveydone = 200;
+ else {
+ /* P2P is disabled */
+ wait_for_surveydone = 100;
+ }
+#else
+ {
+ wait_for_surveydone = 100;
+ }
+#endif /* CONFIG_P2P */
+
+ wait_status = _FW_UNDER_SURVEY
+#ifndef CONFIG_ANDROID
+ | _FW_UNDER_LINKING
+#endif
+ ;
+
+ while (check_fwstate(pmlmepriv, wait_status) )
+ return -EAGAIN;
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ if ((stop - ev) < SCAN_ITEM_SIZE) {
+ ret = -E2BIG;
+ break;
+ }
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* report network only if the current channel set contains the channel to which this network belongs */
+ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0
+ && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig)
+ && rtw_validate_ssid(&(pnetwork->network.Ssid))
+ )
+ ev = translate_scan(padapter, a, pnetwork, ev, stop);
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ wrqu->data.length = ev - extra;
+ wrqu->data.flags = 0;
+
+exit:
+
+
+#ifdef DBG_IOCTL
+ RTW_INFO("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret);
+#endif
+
+ return ret ;
+
+}
+
+/* set ssid flow
+ * s1. rtw_set_802_11_infrastructure_mode()
+ * s2. set_802_11_authenticaion_mode()
+ * s3. set_802_11_encryption_mode()
+ * s4. rtw_set_802_11_ssid() */
+static int rtw_wx_set_essid(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ unsigned long irqL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ _queue *queue = &pmlmepriv->scanned_queue;
+ _list *phead;
+ s8 status = true;
+ struct wlan_network *pnetwork = NULL;
+ NDIS_802_11_AUTHENTICATION_MODE authmode;
+ NDIS_802_11_SSID ndis_ssid;
+ u8 *dst_ssid, *src_ssid;
+
+ uint ret = 0, len;
+
+
+#ifdef DBG_IOCTL
+ RTW_INFO("DBG_IOCTL %s:%d\n", __func__, __LINE__);
+#endif
+#ifdef CONFIG_WEXT_DONT_JOIN_BYSSID
+ RTW_INFO("%s: CONFIG_WEXT_DONT_JOIN_BYSSID be defined!! only allow bssid joining\n", __func__);
+ return -EPERM;
+#endif
+
+#if WIRELESS_EXT <= 20
+ if ((wrqu->essid.length - 1) > IW_ESSID_MAX_SIZE) {
+#else
+ if (wrqu->essid.length > IW_ESSID_MAX_SIZE) {
+#endif
+ ret = -E2BIG;
+ goto exit;
+ }
+
+
+
+ rtw_ps_deny(padapter, PS_DENY_JOIN);
+ if (_FAIL == rtw_pwr_wakeup(padapter)) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+ if (!padapter->bup) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) {
+ RTW_INFO("set ssid, but buddy_intf is under scanning or linking\n");
+ ret = -EINVAL;
+ goto cancel_ps_deny;
+ }
+#endif
+ authmode = padapter->securitypriv.ndisauthtype;
+ RTW_INFO("=>%s\n", __func__);
+ if (wrqu->essid.flags && wrqu->essid.length) {
+ /* Commented by Albert 20100519 */
+ /* We got the codes in "set_info" function of iwconfig source code. */
+ /* ========================================= */
+ /* wrq.u.essid.length = strlen(essid) + 1; */
+ /* if(we_kernel_version > 20) */
+ /* wrq.u.essid.length--; */
+ /* ========================================= */
+ /* That means, if the WIRELESS_EXT less than or equal to 20, the correct ssid len should subtract 1. */
+#if WIRELESS_EXT <= 20
+ len = ((wrqu->essid.length - 1) < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length - 1) : IW_ESSID_MAX_SIZE;
+#else
+ len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? wrqu->essid.length : IW_ESSID_MAX_SIZE;
+#endif
+
+ if (wrqu->essid.length != 33)
+ RTW_INFO("ssid=%s, len=%d\n", extra, wrqu->essid.length);
+
+ memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID));
+ ndis_ssid.SsidLength = len;
+ memcpy(ndis_ssid.Ssid, extra, len);
+ src_ssid = ndis_ssid.Ssid;
+
+ _enter_critical_bh(&queue->lock, &irqL);
+ phead = get_list_head(queue);
+ pmlmepriv->pscanned = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, pmlmepriv->pscanned) ) {
+ break;
+ }
+
+ pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);
+
+ pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);
+
+ dst_ssid = pnetwork->network.Ssid.Ssid;
+
+
+ if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength) ) &&
+ (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) {
+
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ) {
+ if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
+ continue;
+ }
+
+ if (rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode) == false) {
+ ret = -1;
+ _exit_critical_bh(&queue->lock, &irqL);
+ goto cancel_ps_deny;
+ }
+
+ break;
+ }
+ }
+ _exit_critical_bh(&queue->lock, &irqL);
+ rtw_set_802_11_authentication_mode(padapter, authmode);
+ /* set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus); */
+ if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) {
+ ret = -1;
+ goto cancel_ps_deny;
+ }
+ }
+
+cancel_ps_deny:
+ rtw_ps_deny_cancel(padapter, PS_DENY_JOIN);
+
+exit:
+ RTW_INFO("<=%s, ret %d\n", __func__, ret);
+
+#ifdef DBG_IOCTL
+ RTW_INFO("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret);
+#endif
+
+
+ return ret;
+}
+
+static int rtw_wx_get_essid(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ u32 len, ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network;
+
+
+
+ if ((check_fwstate(pmlmepriv, _FW_LINKED) ) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) )) {
+ len = pcur_bss->Ssid.SsidLength;
+
+ wrqu->essid.length = len;
+
+ memcpy(extra, pcur_bss->Ssid.Ssid, len);
+
+ wrqu->essid.flags = 1;
+ } else {
+ ret = -1;
+ goto exit;
+ }
+
+exit:
+
+
+ return ret;
+
+}
+
+static int rtw_wx_set_rate(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
+{
+ int i, ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 datarates[NumRates];
+ u32 target_rate = wrqu->bitrate.value;
+ u32 fixed = wrqu->bitrate.fixed;
+ u32 ratevalue = 0;
+ u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
+
+
+
+ if (target_rate == -1) {
+ ratevalue = 11;
+ goto set_rate;
+ }
+ target_rate = target_rate / 100000;
+
+ switch (target_rate) {
+ case 10:
+ ratevalue = 0;
+ break;
+ case 20:
+ ratevalue = 1;
+ break;
+ case 55:
+ ratevalue = 2;
+ break;
+ case 60:
+ ratevalue = 3;
+ break;
+ case 90:
+ ratevalue = 4;
+ break;
+ case 110:
+ ratevalue = 5;
+ break;
+ case 120:
+ ratevalue = 6;
+ break;
+ case 180:
+ ratevalue = 7;
+ break;
+ case 240:
+ ratevalue = 8;
+ break;
+ case 360:
+ ratevalue = 9;
+ break;
+ case 480:
+ ratevalue = 10;
+ break;
+ case 540:
+ ratevalue = 11;
+ break;
+ default:
+ ratevalue = 11;
+ break;
+ }
+
+set_rate:
+
+ for (i = 0; i < NumRates; i++) {
+ if (ratevalue == mpdatarate[i]) {
+ datarates[i] = mpdatarate[i];
+ if (fixed == 0)
+ break;
+ } else
+ datarates[i] = 0xff;
+
+ }
+
+ if (rtw_setdatarate_cmd(padapter, datarates) != _SUCCESS) {
+ ret = -1;
+ }
+
+
+ return ret;
+}
+
+static int rtw_wx_get_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ u16 max_rate = 0;
+
+ max_rate = rtw_get_cur_max_rate((_adapter *)rtw_netdev_priv(dev));
+
+ if (max_rate == 0)
+ return -EPERM;
+
+ wrqu->bitrate.fixed = 0; /* no auto select */
+ wrqu->bitrate.value = max_rate * 100000;
+
+ return 0;
+}
+
+static int rtw_wx_set_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+ if (wrqu->rts.disabled)
+ padapter->registrypriv.rts_thresh = 2347;
+ else {
+ if (wrqu->rts.value < 0 ||
+ wrqu->rts.value > 2347)
+ return -EINVAL;
+
+ padapter->registrypriv.rts_thresh = wrqu->rts.value;
+ }
+
+ RTW_INFO("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh);
+
+
+ return 0;
+
+}
+
+static int rtw_wx_get_rts(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+ RTW_INFO("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh);
+
+ wrqu->rts.value = padapter->registrypriv.rts_thresh;
+ wrqu->rts.fixed = 0; /* no auto select */
+ /* wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); */
+
+
+ return 0;
+}
+
+static int rtw_wx_set_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+ if (wrqu->frag.disabled)
+ padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
+ else {
+ if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
+ wrqu->frag.value > MAX_FRAG_THRESHOLD)
+ return -EINVAL;
+
+ padapter->xmitpriv.frag_len = wrqu->frag.value & ~0x1;
+ }
+
+ RTW_INFO("%s, frag_len=%d\n", __func__, padapter->xmitpriv.frag_len);
+
+
+ return 0;
+
+}
+
+static int rtw_wx_get_frag(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+
+ RTW_INFO("%s, frag_len=%d\n", __func__, padapter->xmitpriv.frag_len);
+
+ wrqu->frag.value = padapter->xmitpriv.frag_len;
+ wrqu->frag.fixed = 0; /* no auto select */
+ /* wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); */
+
+
+ return 0;
+}
+
+static int rtw_wx_get_retry(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); */
+
+
+ wrqu->retry.value = 7;
+ wrqu->retry.fixed = 0; /* no auto select */
+ wrqu->retry.disabled = 1;
+
+ return 0;
+
+}
+
+static int rtw_wx_set_enc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ u32 key, ret = 0;
+ u32 keyindex_provided;
+ NDIS_802_11_WEP wep;
+ NDIS_802_11_AUTHENTICATION_MODE authmode;
+
+ struct iw_point *erq = &(wrqu->encoding);
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ RTW_INFO("+rtw_wx_set_enc, flags=0x%x\n", erq->flags);
+
+ memset(&wep, 0, sizeof(NDIS_802_11_WEP));
+
+ key = erq->flags & IW_ENCODE_INDEX;
+
+
+ if (erq->flags & IW_ENCODE_DISABLED) {
+ RTW_INFO("EncryptionDisabled\n");
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ authmode = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisauthtype = authmode;
+
+ goto exit;
+ }
+
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ keyindex_provided = 1;
+ } else {
+ keyindex_provided = 0;
+ key = padapter->securitypriv.dot11PrivacyKeyIndex;
+ RTW_INFO("rtw_wx_set_enc, key=%d\n", key);
+ }
+
+ /* set authentication mode */
+ if (erq->flags & IW_ENCODE_OPEN) {
+ RTW_INFO("rtw_wx_set_enc():IW_ENCODE_OPEN\n");
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
+
+#ifdef CONFIG_PLATFORM_MT53XX
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+#else
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+#endif
+
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ authmode = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisauthtype = authmode;
+ } else if (erq->flags & IW_ENCODE_RESTRICTED) {
+ RTW_INFO("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n");
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+#ifdef CONFIG_PLATFORM_MT53XX
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+#else
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+#endif
+
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+ authmode = Ndis802_11AuthModeShared;
+ padapter->securitypriv.ndisauthtype = authmode;
+ } else {
+ RTW_INFO("rtw_wx_set_enc():erq->flags=0x%x\n", erq->flags);
+
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;/* Ndis802_11EncryptionDisabled; */
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ authmode = Ndis802_11AuthModeOpen;
+ padapter->securitypriv.ndisauthtype = authmode;
+ }
+
+ wep.KeyIndex = key;
+ if (erq->length > 0) {
+ wep.KeyLength = erq->length <= 5 ? 5 : 13;
+
+ wep.Length = wep.KeyLength + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial);
+ } else {
+ wep.KeyLength = 0 ;
+
+ if (keyindex_provided == 1) { /* set key_id only, no given KeyMaterial(erq->length==0). */
+ padapter->securitypriv.dot11PrivacyKeyIndex = key;
+
+ RTW_INFO("(keyindex_provided == 1), keyid=%d, key_len=%d\n", key, padapter->securitypriv.dot11DefKeylen[key]);
+
+ switch (padapter->securitypriv.dot11DefKeylen[key]) {
+ case 5:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+ break;
+ case 13:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+ break;
+ default:
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ break;
+ }
+
+ goto exit;
+
+ }
+
+ }
+
+ wep.KeyIndex |= 0x80000000;
+
+ memcpy(wep.KeyMaterial, keybuf, wep.KeyLength);
+
+ if (rtw_set_802_11_add_wep(padapter, &wep) == false) {
+ if (rf_on == pwrpriv->rf_pwrstate)
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+
+exit:
+
+
+ return ret;
+
+}
+
+static int rtw_wx_get_enc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *keybuf)
+{
+ uint key, ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *erq = &(wrqu->encoding);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) != true) {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != true) {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ return 0;
+ }
+ }
+
+
+ key = erq->flags & IW_ENCODE_INDEX;
+
+ if (key) {
+ if (key > WEP_KEYS)
+ return -EINVAL;
+ key--;
+ } else
+ key = padapter->securitypriv.dot11PrivacyKeyIndex;
+
+ erq->flags = key + 1;
+
+ /* if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen) */
+ /* { */
+ /* erq->flags |= IW_ENCODE_OPEN; */
+ /* } */
+
+ switch (padapter->securitypriv.ndisencryptstatus) {
+ case Ndis802_11EncryptionNotSupported:
+ case Ndis802_11EncryptionDisabled:
+
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+
+ break;
+
+ case Ndis802_11Encryption1Enabled:
+
+ erq->length = padapter->securitypriv.dot11DefKeylen[key];
+
+ if (erq->length) {
+ memcpy(keybuf, padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]);
+
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen)
+ erq->flags |= IW_ENCODE_OPEN;
+ else if (padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared)
+ erq->flags |= IW_ENCODE_RESTRICTED;
+ } else {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ }
+
+ break;
+
+ case Ndis802_11Encryption2Enabled:
+ case Ndis802_11Encryption3Enabled:
+
+ erq->length = 16;
+ erq->flags |= (IW_ENCODE_ENABLED | IW_ENCODE_OPEN | IW_ENCODE_NOKEY);
+
+ break;
+
+ default:
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+
+ break;
+
+ }
+
+
+ return ret;
+
+}
+
+static int rtw_wx_get_power(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); */
+
+ wrqu->power.value = 0;
+ wrqu->power.fixed = 0; /* no auto select */
+ wrqu->power.disabled = 1;
+
+ return 0;
+
+}
+
+static int rtw_wx_set_gen_ie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ ret = rtw_set_wpa_ie(padapter, extra, wrqu->data.length);
+
+ return ret;
+}
+
+static int rtw_wx_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_param *param = (struct iw_param *)&(wrqu->param);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ u32 value = param->value;
+ int ret = 0;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+
+ case IW_AUTH_WPA_VERSION:
+#ifdef CONFIG_WAPI_SUPPORT
+#ifndef CONFIG_IOCTL_CFG80211
+ padapter->wapiInfo.bWapiEnable = false;
+ if (value == IW_AUTH_WAPI_VERSION_1) {
+ padapter->wapiInfo.bWapiEnable = true;
+ psecuritypriv->dot11PrivacyAlgrthm = _SMS4_;
+ psecuritypriv->dot118021XGrpPrivacy = _SMS4_;
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI;
+ pmlmeinfo->auth_algo = psecuritypriv->dot11AuthAlgrthm;
+ padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN;
+ padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN;
+ }
+#endif
+#endif
+ break;
+ case IW_AUTH_CIPHER_PAIRWISE:
+
+ break;
+ case IW_AUTH_CIPHER_GROUP:
+
+ break;
+ case IW_AUTH_KEY_MGMT:
+#ifdef CONFIG_WAPI_SUPPORT
+#ifndef CONFIG_IOCTL_CFG80211
+ RTW_INFO("rtw_wx_set_auth: IW_AUTH_KEY_MGMT case\n");
+ if (value == IW_AUTH_KEY_MGMT_WAPI_PSK)
+ padapter->wapiInfo.bWapiPSK = true;
+ else
+ padapter->wapiInfo.bWapiPSK = false;
+ RTW_INFO("rtw_wx_set_auth: IW_AUTH_KEY_MGMT bwapipsk %d\n", padapter->wapiInfo.bWapiPSK);
+#endif
+#endif
+ /*
+ * ??? does not use these parameters
+ */
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES: {
+ if (param->value) {
+ /* wpa_supplicant is enabling the tkip countermeasure. */
+ padapter->securitypriv.btkip_countermeasure = true;
+ } else {
+ /* wpa_supplicant is disabling the tkip countermeasure. */
+ padapter->securitypriv.btkip_countermeasure = false;
+ }
+ break;
+ }
+ case IW_AUTH_DROP_UNENCRYPTED: {
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+
+ if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) {
+ break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */
+ /* then it needn't reset it; */
+ }
+
+ if (param->value) {
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ }
+
+ break;
+ }
+
+ case IW_AUTH_80211_AUTH_ALG:
+
+#if defined(CONFIG_ANDROID) || 1
+ /*
+ * It's the starting point of a link layer connection using wpa_supplicant
+ */
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+ LeaveAllPowerSaveMode(padapter);
+ rtw_disassoc_cmd(padapter, 500, false);
+ RTW_INFO("%s...call rtw_indicate_disconnect\n ", __func__);
+ rtw_indicate_disconnect(padapter, 0, false);
+ rtw_free_assoc_resources(padapter, 1);
+ }
+#endif
+
+
+ ret = wpa_set_auth_algs(dev, (u32)param->value);
+
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+
+ /* if(param->value) */
+ /* padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; */ /* 802.1x */
+ /* else */
+ /* padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; */ /* open system */
+
+ /* _disassociate(priv); */
+
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ /* ieee->ieee802_1x = param->value; */
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ /* ieee->privacy_invoked = param->value; */
+ break;
+
+#ifdef CONFIG_WAPI_SUPPORT
+#ifndef CONFIG_IOCTL_CFG80211
+ case IW_AUTH_WAPI_ENABLED:
+ break;
+#endif
+#endif
+
+ default:
+ return -EOPNOTSUPP;
+
+ }
+
+ return ret;
+
+}
+
+static int rtw_wx_set_enc_ext(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ char *alg_name;
+ u32 param_len;
+ struct ieee_param *param = NULL;
+ struct iw_point *pencoding = &wrqu->encoding;
+ struct iw_encode_ext *pext = (struct iw_encode_ext *)extra;
+ int ret = 0;
+
+ param_len = sizeof(struct ieee_param) + pext->key_len;
+ param = (struct ieee_param *)rtw_malloc(param_len);
+ if (param == NULL)
+ return -1;
+
+ memset(param, 0, param_len);
+
+ param->cmd = IEEE_CMD_SET_ENCRYPTION;
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+
+
+ switch (pext->alg) {
+ case IW_ENCODE_ALG_NONE:
+ /* todo: remove key */
+ /* remove = 1; */
+ alg_name = "none";
+ break;
+ case IW_ENCODE_ALG_WEP:
+ alg_name = "WEP";
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ alg_name = "CCMP";
+ break;
+#ifdef CONFIG_IEEE80211W
+ case IW_ENCODE_ALG_AES_CMAC:
+ alg_name = "BIP";
+ break;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WAPI_SUPPORT
+#ifndef CONFIG_IOCTL_CFG80211
+ case IW_ENCODE_ALG_SM4:
+ alg_name = "SMS4";
+ memcpy(param->sta_addr, pext->addr.sa_data, ETH_ALEN);
+ RTW_INFO("rtw_wx_set_enc_ext: SMS4 case\n");
+ break;
+#endif
+#endif
+ default:
+ ret = -1;
+ goto exit;
+ }
+
+ strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+
+ if (pext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ param->u.crypt.set_tx = 1;
+
+ /* cliW: WEP does not have group key
+ * just not checking GROUP key setting
+ */
+ if ((pext->alg != IW_ENCODE_ALG_WEP) &&
+ ((pext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+#ifdef CONFIG_IEEE80211W
+ || (pext->ext_flags & IW_ENCODE_ALG_AES_CMAC)
+#endif /* CONFIG_IEEE80211W */
+ ))
+ param->u.crypt.set_tx = 0;
+
+ param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1 ;
+
+ if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+#ifdef CONFIG_WAPI_SUPPORT
+#ifndef CONFIG_IOCTL_CFG80211
+ if (pext->alg == IW_ENCODE_ALG_SM4)
+ memcpy(param->u.crypt.seq, pext->rx_seq, 16);
+ else
+#endif /* CONFIG_IOCTL_CFG80211 */
+#endif /* CONFIG_WAPI_SUPPORT */
+ memcpy(param->u.crypt.seq, pext->rx_seq, 8);
+ }
+
+ if (pext->key_len) {
+ param->u.crypt.key_len = pext->key_len;
+ /* memcpy(param + 1, pext + 1, pext->key_len); */
+ memcpy(param->u.crypt.key, pext + 1, pext->key_len);
+ }
+
+ if (pencoding->flags & IW_ENCODE_DISABLED) {
+ /* todo: remove key */
+ /* remove = 1; */
+ }
+
+ ret = wpa_set_encryption(dev, param, param_len);
+
+exit:
+ if (param)
+ rtw_mfree((u8 *)param, param_len);
+
+ return ret;
+}
+
+
+static int rtw_wx_get_nick(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); */
+ /* struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); */
+ /* struct security_priv *psecuritypriv = &padapter->securitypriv; */
+
+ if (extra) {
+ wrqu->data.length = 14;
+ wrqu->data.flags = 1;
+ memcpy(extra, "<WIFI@...LTEK>", 14);
+ }
+
+ /* rtw_signal_process(pid, SIGUSR1); */ /* for test */
+
+ /* dump debug info here */
+ return 0;
+}
+
+static int rtw_wx_read32(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter;
+ struct iw_point *p;
+ u16 len;
+ u32 addr;
+ u32 data32;
+ u32 bytes;
+ u8 *ptmp;
+ int ret;
+
+
+ ret = 0;
+ padapter = (PADAPTER)rtw_netdev_priv(dev);
+ p = &wrqu->data;
+ len = p->length;
+ if (0 == len)
+ return -EINVAL;
+
+ ptmp = (u8 *)rtw_malloc(len);
+ if (NULL == ptmp)
+ return -ENOMEM;
+
+ if (copy_from_user(ptmp, p->pointer, len)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ bytes = 0;
+ addr = 0;
+ sscanf(ptmp, "%d,%x", &bytes, &addr);
+
+ switch (bytes) {
+ case 1:
+ data32 = rtw_read8(padapter, addr);
+ sprintf(extra, "0x%02X", data32);
+ break;
+ case 2:
+ data32 = rtw_read16(padapter, addr);
+ sprintf(extra, "0x%04X", data32);
+ break;
+ case 4:
+ data32 = rtw_read32(padapter, addr);
+ sprintf(extra, "0x%08X", data32);
+ break;
+ default:
+ RTW_INFO("%s: usage> read [bytes],[address(hex)]\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ RTW_INFO("%s: addr=0x%08X data=%s\n", __func__, addr, extra);
+
+exit:
+ rtw_mfree(ptmp, len);
+
+ return 0;
+}
+
+static int rtw_wx_write32(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+ u32 addr;
+ u32 data32;
+ u32 bytes;
+
+
+ bytes = 0;
+ addr = 0;
+ data32 = 0;
+ sscanf(extra, "%d,%x,%x", &bytes, &addr, &data32);
+
+ switch (bytes) {
+ case 1:
+ rtw_write8(padapter, addr, (u8)data32);
+ RTW_INFO("%s: addr=0x%08X data=0x%02X\n", __func__, addr, (u8)data32);
+ break;
+ case 2:
+ rtw_write16(padapter, addr, (u16)data32);
+ RTW_INFO("%s: addr=0x%08X data=0x%04X\n", __func__, addr, (u16)data32);
+ break;
+ case 4:
+ rtw_write32(padapter, addr, data32);
+ RTW_INFO("%s: addr=0x%08X data=0x%08X\n", __func__, addr, data32);
+ break;
+ default:
+ RTW_INFO("%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtw_wx_read_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u32 path, addr, data32;
+
+
+ path = *(u32 *)extra;
+ addr = *((u32 *)extra + 1);
+ data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF);
+ /* RTW_INFO("%s: path=%d addr=0x%02x data=0x%05x\n", __func__, path, addr, data32); */
+ /*
+ * IMPORTANT!!
+ * Only when wireless private ioctl is at odd order,
+ * "extra" would be copied to user space.
+ */
+ sprintf(extra, "0x%05x", data32);
+
+ return 0;
+}
+
+static int rtw_wx_write_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u32 path, addr, data32;
+
+
+ path = *(u32 *)extra;
+ addr = *((u32 *)extra + 1);
+ data32 = *((u32 *)extra + 2);
+ /* RTW_INFO("%s: path=%d addr=0x%02x data=0x%05x\n", __func__, path, addr, data32); */
+ rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32);
+
+ return 0;
+}
+
+static int rtw_wx_priv_null(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ return -1;
+}
+
+static int dummy(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+ /* _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); */
+ /* struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); */
+
+ /* RTW_INFO("cmd_code=%x, fwstate=0x%x\n", a->cmd, get_fwstate(pmlmepriv)); */
+
+ return -1;
+
+}
+
+static int rtw_wx_set_channel_plan(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ u8 channel_plan_req = (u8)(*((int *)wrqu));
+
+ if (_SUCCESS != rtw_set_channel_plan(padapter, channel_plan_req))
+ return -EPERM;
+
+ return 0;
+}
+
+static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev,
+ struct iw_request_info *a,
+ union iwreq_data *wrqu, char *b)
+{
+#ifdef CONFIG_PLATFORM_MT53XX
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+#endif
+ return 0;
+}
+
+static int rtw_wx_get_sensitivity(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *buf)
+{
+#ifdef CONFIG_PLATFORM_MT53XX
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ /* Modified by Albert 20110914 */
+ /* This is in dbm format for MTK platform. */
+ wrqu->qual.level = padapter->recvpriv.rssi;
+ RTW_INFO(" level = %u\n", wrqu->qual.level);
+#endif
+ return 0;
+}
+
+static int rtw_wx_set_mtk_wps_ie(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+#ifdef CONFIG_PLATFORM_MT53XX
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ return rtw_set_wpa_ie(padapter, wrqu->data.pointer, wrqu->data.length);
+#else
+ return 0;
+#endif
+}
+
+/*
+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra);
+*/
+/*
+ * For all data larger than 16 octets, we need to use a
+ * pointer to memory allocated in user space.
+ */
+static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+#ifdef CONFIG_DRVEXT_MODULE
+ u8 res;
+ struct drvext_handler *phandler;
+ struct drvext_oidparam *poidparam;
+ int ret;
+ u16 len;
+ u8 *pparmbuf, bset;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *p = &wrqu->data;
+
+ if ((!p->length) || (!p->pointer)) {
+ ret = -EINVAL;
+ goto _rtw_drvext_hdl_exit;
+ }
+
+
+ bset = (u8)(p->flags & 0xFFFF);
+ len = p->length;
+ pparmbuf = (u8 *)rtw_malloc(len);
+ if (pparmbuf == NULL) {
+ ret = -ENOMEM;
+ goto _rtw_drvext_hdl_exit;
+ }
+
+ if (bset) { /* set info */
+ if (copy_from_user(pparmbuf, p->pointer, len)) {
+ rtw_mfree(pparmbuf, len);
+ ret = -EFAULT;
+ goto _rtw_drvext_hdl_exit;
+ }
+ } else { /* query info */
+
+ }
+
+
+ /* */
+ poidparam = (struct drvext_oidparam *)pparmbuf;
+
+
+
+ /* check subcode */
+ if (poidparam->subcode >= MAX_DRVEXT_HANDLERS) {
+ ret = -EINVAL;
+ goto _rtw_drvext_hdl_exit;
+ }
+
+
+ if (poidparam->subcode >= MAX_DRVEXT_OID_SUBCODES) {
+ ret = -EINVAL;
+ goto _rtw_drvext_hdl_exit;
+ }
+
+
+ phandler = drvextoidhandlers + poidparam->subcode;
+
+ if (poidparam->len != phandler->parmsize) {
+ ret = -EINVAL;
+ goto _rtw_drvext_hdl_exit;
+ }
+
+
+ res = phandler->handler(&padapter->drvextpriv, bset, poidparam->data);
+
+ if (res == 0) {
+ ret = 0;
+
+ if (bset == 0x00) {/* query info */
+ /* memcpy(p->pointer, pparmbuf, len); */
+ if (copy_to_user(p->pointer, pparmbuf, len))
+ ret = -EFAULT;
+ }
+ } else
+ ret = -EFAULT;
+
+
+_rtw_drvext_hdl_exit:
+
+ return ret;
+
+#endif
+
+ return 0;
+
+}
+
+static void rtw_dbg_mode_hdl(_adapter *padapter, u32 id, u8 *pdata, u32 len)
+{
+ pRW_Reg RegRWStruct;
+ struct rf_reg_param *prfreg;
+ u8 path;
+ u8 offset;
+ u32 value;
+
+ RTW_INFO("%s\n", __func__);
+
+ switch (id) {
+ case GEN_MP_IOCTL_SUBCODE(MP_START):
+ RTW_INFO("871x_driver is only for normal mode, can't enter mp mode\n");
+ break;
+ case GEN_MP_IOCTL_SUBCODE(READ_REG):
+ RegRWStruct = (pRW_Reg)pdata;
+ switch (RegRWStruct->width) {
+ case 1:
+ RegRWStruct->value = rtw_read8(padapter, RegRWStruct->offset);
+ break;
+ case 2:
+ RegRWStruct->value = rtw_read16(padapter, RegRWStruct->offset);
+ break;
+ case 4:
+ RegRWStruct->value = rtw_read32(padapter, RegRWStruct->offset);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(WRITE_REG):
+ RegRWStruct = (pRW_Reg)pdata;
+ switch (RegRWStruct->width) {
+ case 1:
+ rtw_write8(padapter, RegRWStruct->offset, (u8)RegRWStruct->value);
+ break;
+ case 2:
+ rtw_write16(padapter, RegRWStruct->offset, (u16)RegRWStruct->value);
+ break;
+ case 4:
+ rtw_write32(padapter, RegRWStruct->offset, (u32)RegRWStruct->value);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(READ_RF_REG):
+
+ prfreg = (struct rf_reg_param *)pdata;
+
+ path = (u8)prfreg->path;
+ offset = (u8)prfreg->offset;
+
+ value = rtw_hal_read_rfreg(padapter, path, offset, 0xffffffff);
+
+ prfreg->value = value;
+
+ break;
+ case GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG):
+
+ prfreg = (struct rf_reg_param *)pdata;
+
+ path = (u8)prfreg->path;
+ offset = (u8)prfreg->offset;
+ value = prfreg->value;
+
+ rtw_hal_write_rfreg(padapter, path, offset, 0xffffffff, value);
+ break;
+ case GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO):
+ RTW_INFO("==> trigger gpio 0\n");
+ rtw_hal_set_hwreg(padapter, HW_VAR_TRIGGER_GPIO_0, NULL);
+ break;
+#ifdef CONFIG_BT_COEXIST
+ case GEN_MP_IOCTL_SUBCODE(SET_DM_BT):
+ RTW_INFO("==> set dm_bt_coexist:%x\n", *(u8 *)pdata);
+ rtw_hal_set_hwreg(padapter, HW_VAR_BT_SET_COEXIST, pdata);
+ break;
+ case GEN_MP_IOCTL_SUBCODE(DEL_BA):
+ RTW_INFO("==> delete ba:%x\n", *(u8 *)pdata);
+ rtw_hal_set_hwreg(padapter, HW_VAR_BT_ISSUE_DELBA, pdata);
+ break;
+#endif
+#ifdef DBG_CONFIG_ERROR_DETECT
+ case GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS):
+ *pdata = rtw_hal_sreset_get_wifi_status(padapter);
+ break;
+#endif
+
+ default:
+ break;
+ }
+}
+
+#ifdef MP_IOCTL_HDL
+static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ u32 BytesRead, BytesWritten, BytesNeeded;
+ struct oid_par_priv oid_par;
+ struct mp_ioctl_handler *phandler;
+ struct mp_ioctl_param *poidparam;
+ uint status = 0;
+ u16 len;
+ u8 *pparmbuf = NULL, bset;
+ PADAPTER padapter = (PADAPTER)rtw_netdev_priv(dev);
+ struct iw_point *p = &wrqu->data;
+
+ /* RTW_INFO("+rtw_mp_ioctl_hdl\n"); */
+
+ /* mutex_lock(&ioctl_mutex); */
+
+ if ((!p->length) || (!p->pointer)) {
+ ret = -EINVAL;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ pparmbuf = NULL;
+ bset = (u8)(p->flags & 0xFFFF);
+ len = p->length;
+ pparmbuf = (u8 *)rtw_malloc(len);
+ if (pparmbuf == NULL) {
+ ret = -ENOMEM;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ if (copy_from_user(pparmbuf, p->pointer, len)) {
+ ret = -EFAULT;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ poidparam = (struct mp_ioctl_param *)pparmbuf;
+
+ if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
+ ret = -EINVAL;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ /* RTW_INFO("%s: %d\n", __func__, poidparam->subcode); */
+#ifdef CONFIG_MP_INCLUDED
+ if (padapter->registrypriv.mp_mode == 1) {
+ phandler = mp_ioctl_hdl + poidparam->subcode;
+
+ if ((phandler->paramsize != 0) && (poidparam->len < phandler->paramsize)) {
+ ret = -EINVAL;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+ if (phandler->handler) {
+ oid_par.adapter_context = padapter;
+ oid_par.oid = phandler->oid;
+ oid_par.information_buf = poidparam->data;
+ oid_par.information_buf_len = poidparam->len;
+ oid_par.dbg = 0;
+
+ BytesWritten = 0;
+ BytesNeeded = 0;
+
+ if (bset) {
+ oid_par.bytes_rw = &BytesRead;
+ oid_par.bytes_needed = &BytesNeeded;
+ oid_par.type_of_oid = SET_OID;
+ } else {
+ oid_par.bytes_rw = &BytesWritten;
+ oid_par.bytes_needed = &BytesNeeded;
+ oid_par.type_of_oid = QUERY_OID;
+ }
+
+ status = phandler->handler(&oid_par);
+
+ /* todo:check status, BytesNeeded, etc. */
+ } else {
+ RTW_INFO("rtw_mp_ioctl_hdl(): err!, subcode=%d, oid=%d, handler=%p\n",
+ poidparam->subcode, phandler->oid, phandler->handler);
+ ret = -EFAULT;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+ } else
+#endif
+ {
+ rtw_dbg_mode_hdl(padapter, poidparam->subcode, poidparam->data, poidparam->len);
+ }
+
+ if (bset == 0x00) {/* query info */
+ if (copy_to_user(p->pointer, pparmbuf, len))
+ ret = -EFAULT;
+ }
+
+ if (status) {
+ ret = -EFAULT;
+ goto _rtw_mp_ioctl_hdl_exit;
+ }
+
+_rtw_mp_ioctl_hdl_exit:
+
+ if (pparmbuf)
+ rtw_mfree(pparmbuf, len);
+
+ /* mutex_unlock(&ioctl_mutex); */
+
+ return ret;
+}
+#endif
+static int rtw_get_ap_info(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int bssid_match, ret = 0;
+ u32 cnt = 0, wpa_ielen;
+ unsigned long irqL;
+ _list *plist, *phead;
+ unsigned char *pbuf;
+ u8 bssid[ETH_ALEN];
+ char data[32];
+ struct wlan_network *pnetwork = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct iw_point *pdata = &wrqu->data;
+
+ RTW_INFO("+rtw_get_aplist_info\n");
+
+ if (rtw_is_drv_stopped(padapter) || (pdata == NULL)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ while ((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING))) ) {
+ rtw_msleep_os(30);
+ cnt++;
+ if (cnt > 100)
+ break;
+ }
+
+
+ /* pdata->length = 0; */ /* ? */
+ pdata->flags = 0;
+ if (pdata->length >= 32) {
+ if (copy_from_user(data, pdata->pointer, 32)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* if(hwaddr_aton_i(pdata->pointer, bssid)) */
+ if (hwaddr_aton_i(data, bssid)) {
+ RTW_INFO("Invalid BSSID '%s'.\n", (u8 *)data);
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ return -EINVAL;
+ }
+
+
+ if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN) ) { /* BSSID match, then check if supporting wpa/wpa2 */
+ RTW_INFO("BSSID:" MAC_FMT "\n", MAC_ARG(bssid));
+
+ pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
+ if (pbuf && (wpa_ielen > 0)) {
+ pdata->flags = 1;
+ break;
+ }
+
+ pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
+ if (pbuf && (wpa_ielen > 0)) {
+ pdata->flags = 2;
+ break;
+ }
+
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (pdata->length >= 34) {
+ if (copy_to_user((u8 *)pdata->pointer + 32, (u8 *)&pdata->flags, 1)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+exit:
+
+ return ret;
+
+}
+
+static int rtw_set_pid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = rtw_netdev_priv(dev);
+ int *pdata = (int *)wrqu;
+ int selector;
+
+ if (rtw_is_drv_stopped(padapter) || (pdata == NULL)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ selector = *pdata;
+ if (selector < 3 && selector >= 0) {
+ padapter->pid[selector] = *(pdata + 1);
+#ifdef CONFIG_GLOBAL_UI_PID
+ ui_pid[selector] = *(pdata + 1);
+#endif
+ RTW_INFO("%s set pid[%d]=%d\n", __func__, selector , padapter->pid[selector]);
+ } else
+ RTW_INFO("%s selector %d error\n", __func__, selector);
+
+exit:
+
+ return ret;
+
+}
+
+static int rtw_wps_start(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ u32 u32wps_start = 0;
+ unsigned int uintRet = 0;
+
+ if (RTW_CANNOT_RUN(padapter) || (NULL == pdata)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ uintRet = copy_from_user((void *) &u32wps_start, pdata->pointer, 4);
+ if (u32wps_start == 0)
+ u32wps_start = *extra;
+
+ RTW_INFO("[%s] wps_start = %d\n", __func__, u32wps_start);
+
+ if (u32wps_start == 1) /* WPS Start */
+ rtw_led_control(padapter, LED_CTL_START_WPS);
+ else if (u32wps_start == 2) /* WPS Stop because of wps success */
+ rtw_led_control(padapter, LED_CTL_STOP_WPS);
+ else if (u32wps_start == 3) /* WPS Stop because of wps fail */
+ rtw_led_control(padapter, LED_CTL_STOP_WPS_FAIL);
+
+#ifdef CONFIG_INTEL_WIDI
+ process_intel_widi_wps_status(padapter, u32wps_start);
+#endif /* CONFIG_INTEL_WIDI */
+
+exit:
+
+ return ret;
+
+}
+
+#ifdef CONFIG_P2P
+static int rtw_wext_p2p_enable(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ enum P2P_ROLE init_role = P2P_ROLE_DISABLE;
+
+ if (*extra == '0')
+ init_role = P2P_ROLE_DISABLE;
+ else if (*extra == '1')
+ init_role = P2P_ROLE_DEVICE;
+ else if (*extra == '2')
+ init_role = P2P_ROLE_CLIENT;
+ else if (*extra == '3')
+ init_role = P2P_ROLE_GO;
+
+ if (_FAIL == rtw_p2p_enable(padapter, init_role)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ /* set channel/bandwidth */
+ if (init_role != P2P_ROLE_DISABLE) {
+ u8 channel, ch_offset;
+ u16 bwmode;
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN)) {
+ /* Stay at the listen state and wait for discovery. */
+ channel = pwdinfo->listen_channel;
+ pwdinfo->operating_channel = pwdinfo->listen_channel;
+ ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ bwmode = CHANNEL_WIDTH_20;
+ }
+#ifdef CONFIG_CONCURRENT_MODE
+ else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
+
+ _set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_interval);
+
+ channel = rtw_mi_get_union_chan(padapter);
+ ch_offset = rtw_mi_get_union_offset(padapter);
+ bwmode = rtw_mi_get_union_bw(padapter);
+
+ pwdinfo->operating_channel = channel;
+ }
+#endif
+ else {
+ pwdinfo->operating_channel = pmlmeext->cur_channel;
+
+ channel = pwdinfo->operating_channel;
+ ch_offset = pmlmeext->cur_ch_offset;
+ bwmode = pmlmeext->cur_bwmode;
+ }
+
+ set_channel_bwmode(padapter, channel, ch_offset, bwmode);
+ }
+
+exit:
+ return ret;
+
+}
+
+static int rtw_p2p_set_go_nego_ssid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ RTW_INFO("[%s] ssid = %s, len = %zu\n", __func__, extra, strlen(extra));
+ memcpy(pwdinfo->nego_ssid, extra, strlen(extra));
+ pwdinfo->nego_ssidlen = strlen(extra);
+
+ return ret;
+
+}
+
+
+static int rtw_p2p_set_intent(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 intent = pwdinfo->intent;
+
+ extra[wrqu->data.length] = 0x00;
+
+ intent = rtw_atoi(extra);
+
+ if (intent <= 15)
+ pwdinfo->intent = intent;
+ else
+ ret = -1;
+
+ RTW_INFO("[%s] intent = %d\n", __func__, intent);
+
+ return ret;
+
+}
+
+static int rtw_p2p_set_listen_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 listen_ch = pwdinfo->listen_channel; /* Listen channel number */
+
+ extra[wrqu->data.length] = 0x00;
+ listen_ch = rtw_atoi(extra);
+
+ if ((listen_ch == 1) || (listen_ch == 6) || (listen_ch == 11)) {
+ pwdinfo->listen_channel = listen_ch;
+ set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+ } else
+ ret = -1;
+
+ RTW_INFO("[%s] listen_ch = %d\n", __func__, pwdinfo->listen_channel);
+
+ return ret;
+
+}
+
+static int rtw_p2p_set_op_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* Commented by Albert 20110524
+ * This function is used to set the operating channel if the driver will become the group owner */
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 op_ch = pwdinfo->operating_channel; /* Operating channel number */
+
+ extra[wrqu->data.length] = 0x00;
+
+ op_ch = (u8) rtw_atoi(extra);
+ if (op_ch > 0)
+ pwdinfo->operating_channel = op_ch;
+ else
+ ret = -1;
+
+ RTW_INFO("[%s] op_ch = %d\n", __func__, pwdinfo->operating_channel);
+
+ return ret;
+
+}
+
+
+static int rtw_p2p_profilefound(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ /* Comment by Albert 2010/10/13 */
+ /* Input data format: */
+ /* Ex: 0 */
+ /* Ex: 1XX:XX:XX:XX:XX:XXYYSSID */
+ /* 0 => Reflush the profile record list. */
+ /* 1 => Add the profile list */
+ /* XX:XX:XX:XX:XX:XX => peer's MAC Address ( ex: 00:E0:4C:00:00:01 ) */
+ /* YY => SSID Length */
+ /* SSID => SSID for persistence group */
+
+ RTW_INFO("[%s] In value = %s, len = %d\n", __func__, extra, wrqu->data.length - 1);
+
+
+ /* The upper application should pass the SSID to driver by using this rtw_p2p_profilefound function. */
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ if (extra[0] == '0') {
+ /* Remove all the profile information of wifidirect_info structure. */
+ memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
+ pwdinfo->profileindex = 0;
+ } else {
+ if (pwdinfo->profileindex >= P2P_MAX_PERSISTENT_GROUP_NUM)
+ ret = -1;
+ else {
+ int jj, kk;
+
+ /* Add this profile information into pwdinfo->profileinfo */
+ /* Ex: 1XX:XX:XX:XX:XX:XXYYSSID */
+ for (jj = 0, kk = 1; jj < ETH_ALEN; jj++, kk += 3)
+ pwdinfo->profileinfo[pwdinfo->profileindex].peermac[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ /* pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen = ( extra[18] - '0' ) * 10 + ( extra[19] - '0' ); */
+ /* memcpy( pwdinfo->profileinfo[pwdinfo->profileindex].ssid, &extra[20], pwdinfo->profileinfo[pwdinfo->profileindex].ssidlen ); */
+ pwdinfo->profileindex++;
+ }
+ }
+ }
+
+ return ret;
+
+}
+
+static int rtw_p2p_setDN(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+ memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
+ memcpy(pwdinfo->device_name, extra, wrqu->data.length - 1);
+ pwdinfo->device_name_len = wrqu->data.length - 1;
+
+ return ret;
+
+}
+
+
+static int rtw_p2p_get_status(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ if (padapter->bShowGetP2PState) {
+ RTW_INFO("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+ }
+
+ /* Commented by Albert 2010/10/12 */
+ /* Because of the output size limitation, I had removed the "Role" information. */
+ /* About the "Role" information, we will use the new private IOCTL to get the "Role" information. */
+ sprintf(extra, "\n\nStatus=%.2d\n", rtw_p2p_state(pwdinfo));
+ wrqu->data.length = strlen(extra);
+
+ return ret;
+
+}
+
+/* Commented by Albert 20110520
+ * This function will return the config method description
+ * This config method description will show us which config method the remote P2P device is intented to use
+ * by sending the provisioning discovery request frame. */
+
+static int rtw_p2p_get_req_cm(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ sprintf(extra, "\n\nCM=%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req);
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+
+static int rtw_p2p_get_role(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+
+ RTW_INFO("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+
+ sprintf(extra, "\n\nRole=%.2d\n", rtw_p2p_role(pwdinfo));
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+
+static int rtw_p2p_get_peer_ifaddr(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+
+ RTW_INFO("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+
+ sprintf(extra, "\nMAC %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+ pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2],
+ pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+static int rtw_p2p_get_peer_devaddr(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ RTW_INFO("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->rx_prov_disc_info.peerDevAddr[0], pwdinfo->rx_prov_disc_info.peerDevAddr[1],
+ pwdinfo->rx_prov_disc_info.peerDevAddr[2], pwdinfo->rx_prov_disc_info.peerDevAddr[3],
+ pwdinfo->rx_prov_disc_info.peerDevAddr[4], pwdinfo->rx_prov_disc_info.peerDevAddr[5]);
+ sprintf(extra, "\n%.2X%.2X%.2X%.2X%.2X%.2X",
+ pwdinfo->rx_prov_disc_info.peerDevAddr[0], pwdinfo->rx_prov_disc_info.peerDevAddr[1],
+ pwdinfo->rx_prov_disc_info.peerDevAddr[2], pwdinfo->rx_prov_disc_info.peerDevAddr[3],
+ pwdinfo->rx_prov_disc_info.peerDevAddr[4], pwdinfo->rx_prov_disc_info.peerDevAddr[5]);
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+static int rtw_p2p_get_peer_devaddr_by_invitation(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ RTW_INFO("[%s] Role = %d, Status = %d, peer addr = %.2X:%.2X:%.2X:%.2X:%.2X:%.2X\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo),
+ pwdinfo->p2p_peer_device_addr[0], pwdinfo->p2p_peer_device_addr[1],
+ pwdinfo->p2p_peer_device_addr[2], pwdinfo->p2p_peer_device_addr[3],
+ pwdinfo->p2p_peer_device_addr[4], pwdinfo->p2p_peer_device_addr[5]);
+ sprintf(extra, "\nMAC %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+ pwdinfo->p2p_peer_device_addr[0], pwdinfo->p2p_peer_device_addr[1],
+ pwdinfo->p2p_peer_device_addr[2], pwdinfo->p2p_peer_device_addr[3],
+ pwdinfo->p2p_peer_device_addr[4], pwdinfo->p2p_peer_device_addr[5]);
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+static int rtw_p2p_get_groupid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ sprintf(extra, "\n%.2X:%.2X:%.2X:%.2X:%.2X:%.2X %s",
+ pwdinfo->groupid_info.go_device_addr[0], pwdinfo->groupid_info.go_device_addr[1],
+ pwdinfo->groupid_info.go_device_addr[2], pwdinfo->groupid_info.go_device_addr[3],
+ pwdinfo->groupid_info.go_device_addr[4], pwdinfo->groupid_info.go_device_addr[5],
+ pwdinfo->groupid_info.ssid);
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+static int rtw_p2p_get_op_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+
+ RTW_INFO("[%s] Op_ch = %02x\n", __func__, pwdinfo->operating_channel);
+
+ sprintf(extra, "\n\nOp_ch=%.2d\n", pwdinfo->operating_channel);
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+static int rtw_p2p_get_wps_configmethod(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra, char *subcmd)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u16 attr_content;
+ __be16 be_tmp;
+ uint attr_contentlen = 0;
+ u8 attr_content_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 };
+
+ /* Commented by Albert 20110727 */
+ /* The input data is the MAC address which the application wants to know its WPS config method. */
+ /* After knowing its WPS config method, the application can decide the config method for provisioning discovery. */
+ /* Format: iwpriv wlanx p2p_get_wpsCM 00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, subcmd);
+
+ macstr2num(peerMAC, subcmd);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ u8 *wpsie;
+ uint wpsie_len = 0;
+
+ /* The mac address is matched. */
+
+ wpsie = rtw_get_wps_ie_from_scan_queue(&pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &wpsie_len, pnetwork->network.Reserved[0]);
+ if (wpsie) {
+ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_CONF_METHOD, (u8 *)&be_tmp, &attr_contentlen);
+ if (attr_contentlen) {
+ attr_content = be16_to_cpu(be_tmp);
+ sprintf(attr_content_str, "\n\nM=%.4d", attr_content);
+ blnMatch = 1;
+ }
+ }
+ break;
+ }
+ plist = get_next(plist);
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(attr_content_str, "\n\nM=0000");
+
+ wrqu->data.length = strlen(attr_content_str);
+ memcpy(extra, attr_content_str, wrqu->data.length);
+
+ return ret;
+
+}
+
+#ifdef CONFIG_WFD
+static int rtw_p2p_get_peer_wfd_port(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ RTW_INFO("[%s] p2p_state = %d\n", __func__, rtw_p2p_state(pwdinfo));
+
+ sprintf(extra, "\n\nPort=%d\n", pwdinfo->wfd_info->peer_rtsp_ctrlport);
+ RTW_INFO("[%s] remote port = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport);
+
+ wrqu->data.length = strlen(extra);
+ return ret;
+
+}
+
+static int rtw_p2p_get_peer_wfd_preferred_connection(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ sprintf(extra, "\n\nwfd_pc=%d\n", pwdinfo->wfd_info->wfd_pc);
+ RTW_INFO("[%s] wfd_pc = %d\n", __func__, pwdinfo->wfd_info->wfd_pc);
+
+ wrqu->data.length = strlen(extra);
+ pwdinfo->wfd_info->wfd_pc = false; /* Reset the WFD preferred connection to P2P */
+ return ret;
+
+}
+
+static int rtw_p2p_get_peer_wfd_session_available(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ sprintf(extra, "\n\nwfd_sa=%d\n", pwdinfo->wfd_info->peer_session_avail);
+ RTW_INFO("[%s] wfd_sa = %d\n", __func__, pwdinfo->wfd_info->peer_session_avail);
+
+ wrqu->data.length = strlen(extra);
+ pwdinfo->wfd_info->peer_session_avail = true; /* Reset the WFD session available */
+ return ret;
+
+}
+#endif /* CONFIG_WFD */
+
+static int rtw_p2p_get_go_device_address(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra, char *subcmd)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ u8 attr_content[100] = { 0x00 };
+ u8 go_devadd_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 };
+
+ /* Commented by Albert 20121209 */
+ /* The input data is the GO's interface address which the application wants to know its device address. */
+ /* Format: iwpriv wlanx p2p_get2 go_devadd=00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, subcmd);
+
+ macstr2num(peerMAC, subcmd);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_bss_ex_get_p2p_ie(&pnetwork->network, NULL, &p2pielen);
+ if (p2pie) {
+ while (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+
+ memset(attr_content, 0x00, 100);
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ blnMatch = 1;
+ break;
+
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ blnMatch = 1;
+ break;
+ }
+
+ /* Get the next P2P IE */
+ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, BSS_EX_TLV_IES_LEN(&pnetwork->network) - (p2pie + p2pielen - BSS_EX_TLV_IES(&pnetwork->network)), NULL, &p2pielen);
+ }
+ }
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(go_devadd_str, "\n\ndev_add=NULL");
+ else {
+ sprintf(go_devadd_str, "\n\ndev_add=%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+ attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]);
+ }
+
+ wrqu->data.length = strlen(go_devadd_str);
+ memcpy(extra, go_devadd_str, wrqu->data.length);
+
+ return ret;
+
+}
+
+static int rtw_p2p_get_device_type(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra, char *subcmd)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 dev_type[8] = { 0x00 };
+ uint dev_type_len = 0;
+ u8 dev_type_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 }; /* +9 is for the str "dev_type=", we have to clear it at wrqu->data.pointer */
+
+ /* Commented by Albert 20121209 */
+ /* The input data is the MAC address which the application wants to know its device type. */
+ /* Such user interface could know the device type. */
+ /* Format: iwpriv wlanx p2p_get2 dev_type=00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, subcmd);
+
+ macstr2num(peerMAC, subcmd);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ u8 *wpsie;
+ uint wpsie_len = 0;
+
+ /* The mac address is matched. */
+
+ wpsie = rtw_get_wps_ie_from_scan_queue(&pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &wpsie_len, pnetwork->network.Reserved[0]);
+ if (wpsie) {
+ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_PRIMARY_DEV_TYPE, dev_type, &dev_type_len);
+ if (dev_type_len) {
+ u16 type;
+ __be16 be_tmp;
+
+ memcpy(&be_tmp, dev_type, 2);
+ type = be16_to_cpu(be_tmp);
+ sprintf(dev_type_str, "\n\nN=%.2d", type);
+ blnMatch = 1;
+ }
+ }
+ break;
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(dev_type_str, "\n\nN=00");
+
+ wrqu->data.length = strlen(dev_type_str);
+ memcpy(extra, dev_type_str, wrqu->data.length);
+
+ return ret;
+
+}
+
+static int rtw_p2p_get_device_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra, char *subcmd)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 dev_name[WPS_MAX_DEVICE_NAME_LEN] = { 0x00 };
+ uint dev_len = 0;
+ u8 dev_name_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 };
+
+ /* Commented by Albert 20121225 */
+ /* The input data is the MAC address which the application wants to know its device name. */
+ /* Such user interface could show peer device's device name instead of ssid. */
+ /* Format: iwpriv wlanx p2p_get2 devN=00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, subcmd);
+
+ macstr2num(peerMAC, subcmd);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ u8 *wpsie;
+ uint wpsie_len = 0;
+
+ /* The mac address is matched. */
+
+ wpsie = rtw_get_wps_ie_from_scan_queue(&pnetwork->network.IEs[0], pnetwork->network.IELength, NULL, &wpsie_len, pnetwork->network.Reserved[0]);
+ if (wpsie) {
+ rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_DEVICE_NAME, dev_name, &dev_len);
+ if (dev_len) {
+ sprintf(dev_name_str, "\n\nN=%s", dev_name);
+ blnMatch = 1;
+ }
+ }
+ break;
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(dev_name_str, "\n\nN=0000");
+
+ wrqu->data.length = strlen(dev_name_str);
+ memcpy(extra, dev_name_str, wrqu->data.length);
+
+ return ret;
+
+}
+
+static int rtw_p2p_get_invitation_procedure(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra, char *subcmd)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 blnMatch = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ u8 attr_content[2] = { 0x00 };
+ u8 inv_proc_str[P2P_PRIVATE_IOCTL_SET_LEN] = { 0x00 };
+
+ /* Commented by Ouden 20121226 */
+ /* The application wants to know P2P initation procedure is support or not. */
+ /* Format: iwpriv wlanx p2p_get2 InvProc=00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, subcmd);
+
+ macstr2num(peerMAC, subcmd);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ /* Commented by Albert 20121226 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_bss_ex_get_p2p_ie(&pnetwork->network, NULL, &p2pielen);
+ if (p2pie) {
+ while (p2pie) {
+ /* memset( attr_content, 0x00, 2); */
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_CAPABILITY, attr_content, &attr_contentlen)) {
+ /* Handle the P2P capability attribute */
+ blnMatch = 1;
+ break;
+
+ }
+
+ /* Get the next P2P IE */
+ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, BSS_EX_TLV_IES_LEN(&pnetwork->network) - (p2pie + p2pielen - BSS_EX_TLV_IES(&pnetwork->network)), NULL, &p2pielen);
+ }
+ }
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (!blnMatch)
+ sprintf(inv_proc_str, "\nIP=-1");
+ else {
+ if ((attr_content[0] & 0x20) == 0x20)
+ sprintf(inv_proc_str, "\nIP=1");
+ else
+ sprintf(inv_proc_str, "\nIP=0");
+ }
+
+ wrqu->data.length = strlen(inv_proc_str);
+ memcpy(extra, inv_proc_str, wrqu->data.length);
+
+ return ret;
+
+}
+
+static int rtw_p2p_connect(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ int jj, kk;
+ u8 peerMACStr[ETH_ALEN * 2] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ unsigned long irqL;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+
+ /* Commented by Albert 20110304 */
+ /* The input data contains two informations. */
+ /* 1. First information is the MAC address which wants to formate with */
+ /* 2. Second information is the WPS PINCode or "pbc" string for push button method */
+ /* Format: 00:E0:4C:00:00:05 */
+ /* Format: 00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (pwdinfo->p2p_state == P2P_STATE_NONE) {
+ RTW_INFO("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ }
+
+#ifdef CONFIG_INTEL_WIDI
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) ) {
+ RTW_INFO("[%s] WiFi is under survey!\n", __func__);
+ return ret;
+ }
+#endif /* CONFIG_INTEL_WIDI */
+
+ if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO)
+ return -1;
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ if (pnetwork->network.Configuration.DSConfig != 0)
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ else if (pwdinfo->nego_req_info.peer_ch != 0)
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig = pwdinfo->nego_req_info.peer_ch;
+ else {
+ /* Unexpected case */
+ uintPeerChannel = 0;
+ RTW_INFO("%s uintPeerChannel = 0\n", __func__);
+ }
+ break;
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (uintPeerChannel) {
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED))
+ _cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
+ memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+
+ pwdinfo->nego_req_info.peer_channel_num[0] = uintPeerChannel;
+ memcpy(pwdinfo->nego_req_info.peerDevAddr, pnetwork->network.MacAddress, ETH_ALEN);
+ pwdinfo->nego_req_info.benable = true;
+
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ if (rtw_p2p_state(pwdinfo) != P2P_STATE_GONEGO_OK) {
+ /* Restore to the listen state if the current p2p state is not nego OK */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+ }
+
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ u8 union_ch = rtw_mi_get_union_chan(padapter);
+ u8 union_bw = rtw_mi_get_union_bw(padapter);
+ u8 union_offset = rtw_mi_get_union_offset(padapter);
+ /* Have to enter the power saving with the AP */
+ set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
+
+ rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500);
+ }
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ RTW_INFO("[%s] Start PreTx Procedure!\n", __func__);
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED))
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_CONCURRENT_GO_NEGO_TIMEOUT);
+ else
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT);
+#else
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_GO_NEGO_TIMEOUT);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ } else {
+ RTW_INFO("[%s] Not Found in Scanning Queue~\n", __func__);
+#ifdef CONFIG_INTEL_WIDI
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+ rtw_free_network_queue(padapter, true);
+ /**
+ * For WiDi, if we can't find candidate device in scanning queue,
+ * driver will do scanning itself
+ */
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ rtw_sitesurvey_cmd(padapter, NULL, 0, NULL, 0);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+#endif /* CONFIG_INTEL_WIDI */
+ ret = -1;
+ }
+exit:
+ return ret;
+}
+
+static int rtw_p2p_invite_req(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ int jj, kk;
+ u8 peerMACStr[ETH_ALEN * 2] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+ u8 attr_content[50] = { 0x00 }, _status = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ unsigned long irqL;
+ struct tx_invite_req_info *pinvite_req_info = &pwdinfo->invitereq_info;
+
+ /* Commented by Albert 20120321 */
+ /* The input data contains two informations. */
+ /* 1. First information is the P2P device address which you want to send to. */
+ /* 2. Second information is the group id which combines with GO's mac address, space and GO's ssid. */
+ /* Command line sample: iwpriv wlan0 p2p_set invite="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" */
+ /* Format: 00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy */
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (wrqu->data.length <= 37) {
+ RTW_INFO("[%s] Wrong format!\n", __func__);
+ return ret;
+ }
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ RTW_INFO("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+ /* Reset the content of struct tx_invite_req_info */
+ pinvite_req_info->benable = false;
+ memset(pinvite_req_info->go_bssid, 0x00, ETH_ALEN);
+ memset(pinvite_req_info->go_ssid, 0x00, WLAN_SSID_MAXLEN);
+ pinvite_req_info->ssidlen = 0x00;
+ pinvite_req_info->operating_ch = pwdinfo->operating_channel;
+ memset(pinvite_req_info->peer_macaddr, 0x00, ETH_ALEN);
+ pinvite_req_info->token = 3;
+ }
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ pinvite_req_info->peer_macaddr[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_bss_ex_get_p2p_ie(&pnetwork->network, NULL, &p2pielen);
+ if (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ if (!memcmp(attr_content, pinvite_req_info->peer_macaddr, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ }
+
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+#ifdef CONFIG_WFD
+ if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST) && uintPeerChannel) {
+ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info;
+ u8 *wfd_ie;
+ uint wfd_ielen = 0;
+
+ wfd_ie = rtw_bss_ex_get_wfd_ie(&pnetwork->network, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ u8 *wfd_devinfo;
+ uint wfd_devlen;
+
+ RTW_INFO("[%s] Found WFD IE!\n", __func__);
+ wfd_devinfo = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, NULL, &wfd_devlen);
+ if (wfd_devinfo) {
+ u16 wfd_devinfo_field = 0;
+
+ /* Commented by Albert 20120319 */
+ /* The first two bytes are the WFD device information field of WFD device information subelement. */
+ /* In big endian format. */
+ wfd_devinfo_field = RTW_GET_BE16(wfd_devinfo);
+ if (wfd_devinfo_field & WFD_DEVINFO_SESSION_AVAIL)
+ pwfd_info->peer_session_avail = true;
+ else
+ pwfd_info->peer_session_avail = false;
+ }
+ }
+
+ if (false == pwfd_info->peer_session_avail) {
+ RTW_INFO("[%s] WFD Session not avaiable!\n", __func__);
+ goto exit;
+ }
+ }
+#endif /* CONFIG_WFD */
+
+ if (uintPeerChannel) {
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED))
+ _cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ /* Store the GO's bssid */
+ for (jj = 0, kk = 18; jj < ETH_ALEN; jj++, kk += 3)
+ pinvite_req_info->go_bssid[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ /* Store the GO's ssid */
+ pinvite_req_info->ssidlen = wrqu->data.length - 36;
+ memcpy(pinvite_req_info->go_ssid, &extra[36], (u32) pinvite_req_info->ssidlen);
+ pinvite_req_info->benable = true;
+ pinvite_req_info->peer_ch = uintPeerChannel;
+
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INVITE_REQ);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ u8 union_ch = rtw_mi_get_union_chan(padapter);
+ u8 union_bw = rtw_mi_get_union_bw(padapter);
+ u8 union_offset = rtw_mi_get_union_offset(padapter);
+ /* Have to enter the power saving with the AP */
+ set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
+
+ rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500);
+ } else
+ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+#else
+ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+#endif
+
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED))
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_CONCURRENT_INVITE_TIMEOUT);
+ else
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT);
+#else
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_INVITE_TIMEOUT);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+
+ } else
+ RTW_INFO("[%s] NOT Found in the Scanning Queue!\n", __func__);
+exit:
+
+ return ret;
+
+}
+
+static int rtw_p2p_set_persistent(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ int jj, kk;
+ u8 peerMACStr[ETH_ALEN * 2] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+ u8 attr_content[50] = { 0x00 }, _status = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ unsigned long irqL;
+ struct tx_invite_req_info *pinvite_req_info = &pwdinfo->invitereq_info;
+
+ /* Commented by Albert 20120328 */
+ /* The input data is 0 or 1 */
+ /* 0: disable persistent group functionality */
+ /* 1: enable persistent group founctionality */
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ RTW_INFO("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+ if (extra[0] == '0') /* Disable the persistent group function. */
+ pwdinfo->persistent_supported = false;
+ else if (extra[0] == '1') /* Enable the persistent group function. */
+ pwdinfo->persistent_supported = true;
+ else
+ pwdinfo->persistent_supported = false;
+ }
+ printk("[%s] persistent_supported = %d\n", __func__, pwdinfo->persistent_supported);
+
+exit:
+
+ return ret;
+
+}
+
+static int hexstr2bin(const char *hex, u8 *buf, size_t len)
+{
+ size_t i;
+ int a;
+ const char *ipos = hex;
+ u8 *opos = buf;
+
+ for (i = 0; i < len; i++) {
+ a = hex2byte_i(ipos);
+ if (a < 0)
+ return -1;
+ *opos++ = a;
+ ipos += 2;
+ }
+ return 0;
+}
+
+static int uuid_str2bin(const char *str, u8 *bin)
+{
+ const char *pos;
+ u8 *opos;
+
+ pos = str;
+ opos = bin;
+
+ if (hexstr2bin(pos, opos, 4))
+ return -1;
+ pos += 8;
+ opos += 4;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+ return -1;
+ pos += 4;
+ opos += 2;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+ return -1;
+ pos += 4;
+ opos += 2;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
+ return -1;
+ pos += 4;
+ opos += 2;
+
+ if (*pos++ != '-' || hexstr2bin(pos, opos, 6))
+ return -1;
+
+ return 0;
+}
+
+static int rtw_p2p_set_wps_uuid(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if ((36 == strlen(extra)) && (uuid_str2bin(extra, pwdinfo->uuid) == 0))
+ pwdinfo->external_uuid = 1;
+ else {
+ pwdinfo->external_uuid = 0;
+ ret = -EINVAL;
+ }
+
+ return ret;
+
+}
+#ifdef CONFIG_WFD
+static int rtw_p2p_set_pc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ int jj, kk;
+ u8 peerMACStr[ETH_ALEN * 2] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ u8 attr_content[50] = { 0x00 }, _status = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ unsigned long irqL;
+ uint uintPeerChannel = 0;
+
+ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info;
+
+ /* Commented by Albert 20120512 */
+ /* 1. Input information is the MAC address which wants to know the Preferred Connection bit (PC bit) */
+ /* Format: 00:E0:4C:00:00:05 */
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ RTW_INFO("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ }
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_bss_ex_get_p2p_ie(&pnetwork->network, NULL, &p2pielen);
+ if (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+ printk("[%s] Got P2P IE\n", __func__);
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ printk("[%s] P2P_ATTR_DEVICE_ID\n", __func__);
+ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ printk("[%s] P2P_ATTR_DEVICE_INFO\n", __func__);
+ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ }
+
+ }
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+ printk("[%s] channel = %d\n", __func__, uintPeerChannel);
+
+ if (uintPeerChannel) {
+ u8 *wfd_ie;
+ uint wfd_ielen = 0;
+
+ wfd_ie = rtw_bss_ex_get_wfd_ie(&pnetwork->network, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ u8 *wfd_devinfo;
+ uint wfd_devlen;
+
+ RTW_INFO("[%s] Found WFD IE!\n", __func__);
+ wfd_devinfo = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, NULL, &wfd_devlen);
+ if (wfd_devinfo) {
+ u16 wfd_devinfo_field = 0;
+
+ /* Commented by Albert 20120319 */
+ /* The first two bytes are the WFD device information field of WFD device information subelement. */
+ /* In big endian format. */
+ wfd_devinfo_field = RTW_GET_BE16(wfd_devinfo);
+ if (wfd_devinfo_field & WFD_DEVINFO_PC_TDLS)
+ pwfd_info->wfd_pc = true;
+ else
+ pwfd_info->wfd_pc = false;
+ }
+ }
+ } else
+ RTW_INFO("[%s] NOT Found in the Scanning Queue!\n", __func__);
+
+exit:
+
+ return ret;
+
+}
+
+static int rtw_p2p_set_wfd_device_type(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info;
+
+ /* Commented by Albert 20120328 */
+ /* The input data is 0 or 1 */
+ /* 0: specify to Miracast source device */
+ /* 1 or others: specify to Miracast sink device (display device) */
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (extra[0] == '0') /* Set to Miracast source device. */
+ pwfd_info->wfd_device_type = WFD_DEVINFO_SOURCE;
+ else /* Set to Miracast sink device. */
+ pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK;
+
+exit:
+
+ return ret;
+
+}
+
+static int rtw_p2p_set_wfd_enable(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* Commented by Kurt 20121206
+ * This function is used to set wfd enabled */
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ if (*extra == '0')
+ rtw_wfd_enable(padapter, 0);
+ else if (*extra == '1')
+ rtw_wfd_enable(padapter, 1);
+
+ RTW_INFO("[%s] wfd_enable = %d\n", __func__, pwdinfo->wfd_info->wfd_enable);
+
+ return ret;
+
+}
+
+static int rtw_p2p_set_driver_iface(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ /* Commented by Kurt 20121206
+ * This function is used to set driver iface is WEXT or CFG80211 */
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+ if (*extra == '1') {
+ pwdinfo->driver_interface = DRIVER_WEXT;
+ RTW_INFO("[%s] driver_interface = WEXT\n", __func__);
+ } else if (*extra == '2') {
+ pwdinfo->driver_interface = DRIVER_CFG80211;
+ RTW_INFO("[%s] driver_interface = CFG80211\n", __func__);
+ }
+
+ return ret;
+
+}
+
+/* To set the WFD session available to enable or disable */
+static int rtw_p2p_set_sa(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info;
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (0) {
+ RTW_INFO("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+ if (extra[0] == '0') /* Disable the session available. */
+ pwdinfo->session_available = false;
+ else if (extra[0] == '1') /* Enable the session available. */
+ pwdinfo->session_available = true;
+ else
+ pwdinfo->session_available = false;
+ }
+ printk("[%s] session available = %d\n", __func__, pwdinfo->session_available);
+
+exit:
+
+ return ret;
+
+}
+#endif /* CONFIG_WFD */
+
+static int rtw_p2p_prov_disc(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ u8 peerMAC[ETH_ALEN] = { 0x00 };
+ int jj, kk;
+ u8 peerMACStr[ETH_ALEN * 2] = { 0x00 };
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ _list *plist, *phead;
+ _queue *queue = &(pmlmepriv->scanned_queue);
+ struct wlan_network *pnetwork = NULL;
+ uint uintPeerChannel = 0;
+ u8 attr_content[100] = { 0x00 }, _status = 0;
+ u8 *p2pie;
+ uint p2pielen = 0, attr_contentlen = 0;
+ unsigned long irqL;
+
+ /* Commented by Albert 20110301 */
+ /* The input data contains two informations. */
+ /* 1. First information is the MAC address which wants to issue the provisioning discovery request frame. */
+ /* 2. Second information is the WPS configuration method which wants to discovery */
+ /* Format: 00:E0:4C:00:00:05_display */
+ /* Format: 00:E0:4C:00:00:05_keypad */
+ /* Format: 00:E0:4C:00:00:05_pbc */
+ /* Format: 00:E0:4C:00:00:05_label */
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+
+ if (pwdinfo->p2p_state == P2P_STATE_NONE) {
+ RTW_INFO("[%s] WiFi Direct is disable!\n", __func__);
+ return ret;
+ } else {
+#ifdef CONFIG_INTEL_WIDI
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) ) {
+ RTW_INFO("[%s] WiFi is under survey!\n", __func__);
+ return ret;
+ }
+#endif /* CONFIG_INTEL_WIDI */
+
+ /* Reset the content of struct tx_provdisc_req_info excluded the wps_config_method_request. */
+ memset(pwdinfo->tx_prov_disc_info.peerDevAddr, 0x00, ETH_ALEN);
+ memset(pwdinfo->tx_prov_disc_info.peerIFAddr, 0x00, ETH_ALEN);
+ memset(&pwdinfo->tx_prov_disc_info.ssid, 0x00, sizeof(NDIS_802_11_SSID));
+ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = 0;
+ pwdinfo->tx_prov_disc_info.peer_channel_num[1] = 0;
+ pwdinfo->tx_prov_disc_info.benable = false;
+ }
+
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ peerMAC[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ if (!memcmp(&extra[18], "display", 7))
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_DISPLYA;
+ else if (!memcmp(&extra[18], "keypad", 7))
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_KEYPAD;
+ else if (!memcmp(&extra[18], "pbc", 3))
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_PUSH_BUTTON;
+ else if (!memcmp(&extra[18], "label", 5))
+ pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_LABEL;
+ else {
+ RTW_INFO("[%s] Unknown WPS config methodn", __func__);
+ return ret ;
+ }
+
+ _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ phead = get_list_head(queue);
+ plist = get_next(phead);
+
+ while (1) {
+ if (rtw_end_of_queue_search(phead, plist) )
+ break;
+
+ if (uintPeerChannel != 0)
+ break;
+
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
+
+ /* Commented by Albert 2011/05/18 */
+ /* Match the device address located in the P2P IE */
+ /* This is for the case that the P2P device address is not the same as the P2P interface address. */
+
+ p2pie = rtw_bss_ex_get_p2p_ie(&pnetwork->network, NULL, &p2pielen);
+ if (p2pie) {
+ while (p2pie) {
+ /* The P2P Device ID attribute is included in the Beacon frame. */
+ /* The P2P Device Info attribute is included in the probe response frame. */
+
+ if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_ID, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device ID attribute of Beacon first */
+ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ } else if (rtw_get_p2p_attr_content(p2pie, p2pielen, P2P_ATTR_DEVICE_INFO, attr_content, &attr_contentlen)) {
+ /* Handle the P2P Device Info attribute of probe response */
+ if (!memcmp(attr_content, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ }
+
+ /* Get the next P2P IE */
+ p2pie = rtw_get_p2p_ie(p2pie + p2pielen, BSS_EX_TLV_IES_LEN(&pnetwork->network) - (p2pie + p2pielen - BSS_EX_TLV_IES(&pnetwork->network)), NULL, &p2pielen);
+ }
+
+ }
+
+#ifdef CONFIG_INTEL_WIDI
+ /* Some Intel WiDi source may not provide P2P IE, */
+ /* so we could only compare mac addr by 802.11 Source Address */
+ if (pmlmepriv->widi_state == INTEL_WIDI_STATE_WFD_CONNECTION
+ && uintPeerChannel == 0) {
+ if (!memcmp(pnetwork->network.MacAddress, peerMAC, ETH_ALEN)) {
+ uintPeerChannel = pnetwork->network.Configuration.DSConfig;
+ break;
+ }
+ }
+#endif /* CONFIG_INTEL_WIDI */
+
+ plist = get_next(plist);
+
+ }
+
+ _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
+
+ if (uintPeerChannel) {
+#ifdef CONFIG_WFD
+ if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
+ struct wifi_display_info *pwfd_info = pwdinfo->wfd_info;
+ u8 *wfd_ie;
+ uint wfd_ielen = 0;
+
+ wfd_ie = rtw_bss_ex_get_wfd_ie(&pnetwork->network, NULL, &wfd_ielen);
+ if (wfd_ie) {
+ u8 *wfd_devinfo;
+ uint wfd_devlen;
+
+ RTW_INFO("[%s] Found WFD IE!\n", __func__);
+ wfd_devinfo = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, NULL, &wfd_devlen);
+ if (wfd_devinfo) {
+ u16 wfd_devinfo_field = 0;
+
+ /* Commented by Albert 20120319 */
+ /* The first two bytes are the WFD device information field of WFD device information subelement. */
+ /* In big endian format. */
+ wfd_devinfo_field = RTW_GET_BE16(wfd_devinfo);
+ if (wfd_devinfo_field & WFD_DEVINFO_SESSION_AVAIL)
+ pwfd_info->peer_session_avail = true;
+ else
+ pwfd_info->peer_session_avail = false;
+ }
+ }
+
+ if (false == pwfd_info->peer_session_avail) {
+ RTW_INFO("[%s] WFD Session not avaiable!\n", __func__);
+ goto exit;
+ }
+ }
+#endif /* CONFIG_WFD */
+
+ RTW_INFO("[%s] peer channel: %d!\n", __func__, uintPeerChannel);
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED))
+ _cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
+#endif /* CONFIG_CONCURRENT_MODE */
+ memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, pnetwork->network.MacAddress, ETH_ALEN);
+ memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, peerMAC, ETH_ALEN);
+ pwdinfo->tx_prov_disc_info.peer_channel_num[0] = (u16) uintPeerChannel;
+ pwdinfo->tx_prov_disc_info.benable = true;
+ rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ);
+
+ if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT))
+ memcpy(&pwdinfo->tx_prov_disc_info.ssid, &pnetwork->network.Ssid, sizeof(NDIS_802_11_SSID));
+ else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+ memcpy(pwdinfo->tx_prov_disc_info.ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+ pwdinfo->tx_prov_disc_info.ssid.SsidLength = P2P_WILDCARD_SSID_LEN;
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ u8 union_ch = rtw_mi_get_union_chan(padapter);
+ u8 union_bw = rtw_mi_get_union_bw(padapter);
+ u8 union_offset = rtw_mi_get_union_offset(padapter);
+
+ /* Have to enter the power saving with the AP */
+ set_channel_bwmode(padapter, union_ch, union_offset, union_bw);
+
+ rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500);
+ } else
+ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+#else
+ set_channel_bwmode(padapter, uintPeerChannel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
+#endif
+
+ _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (rtw_mi_check_status(padapter, MI_LINKED))
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_CONCURRENT_PROVISION_TIMEOUT);
+ else
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+#else
+ _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ } else {
+ RTW_INFO("[%s] NOT Found in the Scanning Queue!\n", __func__);
+#ifdef CONFIG_INTEL_WIDI
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+ rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+ rtw_free_network_queue(padapter, true);
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ rtw_sitesurvey_cmd(padapter, NULL, 0, NULL, 0);
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+#endif /* CONFIG_INTEL_WIDI */
+ }
+exit:
+
+ return ret;
+
+}
+
+/* Added by Albert 20110328
+ * This function is used to inform the driver the user had specified the pin code value or pbc
+ * to application. */
+
+static int rtw_p2p_got_wpsinfo(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+
+
+ RTW_INFO("[%s] data = %s\n", __func__, extra);
+ /* Added by Albert 20110328 */
+ /* if the input data is P2P_NO_WPSINFO -> reset the wpsinfo */
+ /* if the input data is P2P_GOT_WPSINFO_PEER_DISPLAY_PIN -> the utility just input the PIN code got from the peer P2P device. */
+ /* if the input data is P2P_GOT_WPSINFO_SELF_DISPLAY_PIN -> the utility just got the PIN code from itself. */
+ /* if the input data is P2P_GOT_WPSINFO_PBC -> the utility just determine to use the PBC */
+
+ if (*extra == '0')
+ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+ else if (*extra == '1')
+ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PEER_DISPLAY_PIN;
+ else if (*extra == '2')
+ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_SELF_DISPLAY_PIN;
+ else if (*extra == '3')
+ pwdinfo->ui_got_wps_info = P2P_GOT_WPSINFO_PBC;
+ else
+ pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+
+ return ret;
+
+}
+
+#endif /* CONFIG_P2P */
+
+static int rtw_p2p_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+#ifdef CONFIG_P2P
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ RTW_INFO("[%s] extra = %s\n", __func__, extra);
+
+ if (!memcmp(extra, "enable=", 7))
+ rtw_wext_p2p_enable(dev, info, wrqu, &extra[7]);
+ else if (!memcmp(extra, "setDN=", 6)) {
+ wrqu->data.length -= 6;
+ rtw_p2p_setDN(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "profilefound=", 13)) {
+ wrqu->data.length -= 13;
+ rtw_p2p_profilefound(dev, info, wrqu, &extra[13]);
+ } else if (!memcmp(extra, "prov_disc=", 10)) {
+ wrqu->data.length -= 10;
+ rtw_p2p_prov_disc(dev, info, wrqu, &extra[10]);
+ } else if (!memcmp(extra, "nego=", 5)) {
+ wrqu->data.length -= 5;
+ rtw_p2p_connect(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "intent=", 7)) {
+ /* Commented by Albert 2011/03/23 */
+ /* The wrqu->data.length will include the null character */
+ /* So, we will decrease 7 + 1 */
+ wrqu->data.length -= 8;
+ rtw_p2p_set_intent(dev, info, wrqu, &extra[7]);
+ } else if (!memcmp(extra, "ssid=", 5)) {
+ wrqu->data.length -= 5;
+ rtw_p2p_set_go_nego_ssid(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "got_wpsinfo=", 12)) {
+ wrqu->data.length -= 12;
+ rtw_p2p_got_wpsinfo(dev, info, wrqu, &extra[12]);
+ } else if (!memcmp(extra, "listen_ch=", 10)) {
+ /* Commented by Albert 2011/05/24 */
+ /* The wrqu->data.length will include the null character */
+ /* So, we will decrease (10 + 1) */
+ wrqu->data.length -= 11;
+ rtw_p2p_set_listen_ch(dev, info, wrqu, &extra[10]);
+ } else if (!memcmp(extra, "op_ch=", 6)) {
+ /* Commented by Albert 2011/05/24 */
+ /* The wrqu->data.length will include the null character */
+ /* So, we will decrease (6 + 1) */
+ wrqu->data.length -= 7;
+ rtw_p2p_set_op_ch(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "invite=", 7)) {
+ wrqu->data.length -= 8;
+ rtw_p2p_invite_req(dev, info, wrqu, &extra[7]);
+ } else if (!memcmp(extra, "persistent=", 11)) {
+ wrqu->data.length -= 11;
+ rtw_p2p_set_persistent(dev, info, wrqu, &extra[11]);
+ } else if (!memcmp(extra, "uuid=", 5)) {
+ wrqu->data.length -= 5;
+ ret = rtw_p2p_set_wps_uuid(dev, info, wrqu, &extra[5]);
+ }
+
+#ifdef CONFIG_WFD
+ if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
+ if (!memcmp(extra, "sa=", 3)) {
+ /* sa: WFD Session Available information */
+ wrqu->data.length -= 3;
+ rtw_p2p_set_sa(dev, info, wrqu, &extra[3]);
+ } else if (!memcmp(extra, "pc=", 3)) {
+ /* pc: WFD Preferred Connection */
+ wrqu->data.length -= 3;
+ rtw_p2p_set_pc(dev, info, wrqu, &extra[3]);
+ } else if (!memcmp(extra, "wfd_type=", 9)) {
+ wrqu->data.length -= 9;
+ rtw_p2p_set_wfd_device_type(dev, info, wrqu, &extra[9]);
+ } else if (!memcmp(extra, "wfd_enable=", 11)) {
+ wrqu->data.length -= 11;
+ rtw_p2p_set_wfd_enable(dev, info, wrqu, &extra[11]);
+ } else if (!memcmp(extra, "driver_iface=", 13)) {
+ wrqu->data.length -= 13;
+ rtw_p2p_set_driver_iface(dev, info, wrqu, &extra[13]);
+ }
+ }
+#endif /* CONFIG_WFD */
+
+#endif /* CONFIG_P2P */
+
+ return ret;
+
+}
+
+static int rtw_p2p_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+#ifdef CONFIG_P2P
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct iw_point *pdata = &wrqu->data;
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+ if (padapter->bShowGetP2PState)
+ RTW_INFO("[%s] extra = %s\n", __func__, (char *)wrqu->data.pointer);
+
+ if (!memcmp((__force void *)wrqu->data.pointer, "status", 6))
+ rtw_p2p_get_status(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "role", 4))
+ rtw_p2p_get_role(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "peer_ifa", 8))
+ rtw_p2p_get_peer_ifaddr(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "req_cm", 6))
+ rtw_p2p_get_req_cm(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "peer_deva", 9)) {
+ /* Get the P2P device address when receiving the provision discovery request frame. */
+ rtw_p2p_get_peer_devaddr(dev, info, wrqu, extra);
+ } else if (!memcmp((__force void *)wrqu->data.pointer, "group_id", 8))
+ rtw_p2p_get_groupid(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "inv_peer_deva", 13)) {
+ /* Get the P2P device address when receiving the P2P Invitation request frame. */
+ rtw_p2p_get_peer_devaddr_by_invitation(dev, info, wrqu, extra);
+ } else if (!memcmp((__force void *)wrqu->data.pointer, "op_ch", 5))
+ rtw_p2p_get_op_ch(dev, info, wrqu, extra);
+
+#ifdef CONFIG_WFD
+ if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
+ if (!memcmp((__force void *)wrqu->data.pointer, "peer_port", 9))
+ rtw_p2p_get_peer_wfd_port(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "wfd_sa", 6))
+ rtw_p2p_get_peer_wfd_session_available(dev, info, wrqu, extra);
+ else if (!memcmp((__force void *)wrqu->data.pointer, "wfd_pc", 6))
+ rtw_p2p_get_peer_wfd_preferred_connection(dev, info, wrqu, extra);
+ }
+#endif /* CONFIG_WFD */
+
+#endif /* CONFIG_P2P */
+
+ return ret;
+
+}
+
+static int rtw_p2p_get2(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+
+#ifdef CONFIG_P2P
+
+ int length = wrqu->data.length;
+ char *buffer = (u8 *)rtw_malloc(length);
+
+ if (buffer == NULL) {
+ ret = -ENOMEM;
+ goto bad;
+ }
+
+ if (copy_from_user(buffer, wrqu->data.pointer, wrqu->data.length)) {
+ ret = -EFAULT;
+ goto bad;
+ }
+
+ RTW_INFO("[%s] buffer = %s\n", __func__, buffer);
+
+ if (!memcmp(buffer, "wpsCM=", 6))
+ ret = rtw_p2p_get_wps_configmethod(dev, info, wrqu, extra, &buffer[6]);
+ else if (!memcmp(buffer, "devN=", 5))
+ ret = rtw_p2p_get_device_name(dev, info, wrqu, extra, &buffer[5]);
+ else if (!memcmp(buffer, "dev_type=", 9))
+ ret = rtw_p2p_get_device_type(dev, info, wrqu, extra, &buffer[9]);
+ else if (!memcmp(buffer, "go_devadd=", 10))
+ ret = rtw_p2p_get_go_device_address(dev, info, wrqu, extra, &buffer[10]);
+ else if (!memcmp(buffer, "InvProc=", 8))
+ ret = rtw_p2p_get_invitation_procedure(dev, info, wrqu, extra, &buffer[8]);
+ else {
+ snprintf(extra, sizeof("Command not found."), "Command not found.");
+ wrqu->data.length = strlen(extra);
+ }
+
+bad:
+ if (buffer)
+ rtw_mfree(buffer, length);
+
+#endif /* CONFIG_P2P */
+
+ return ret;
+
+}
+
+static int rtw_cta_test_start(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ RTW_INFO("%s %s\n", __func__, extra);
+ if (!strcmp(extra, "1"))
+ padapter->in_cta_test = 1;
+ else
+ padapter->in_cta_test = 0;
+
+ if (padapter->in_cta_test) {
+ u32 v = rtw_read32(padapter, REG_RCR);
+ v &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN); /* | RCR_ADF */
+ rtw_write32(padapter, REG_RCR, v);
+ RTW_INFO("enable RCR_ADF\n");
+ } else {
+ u32 v = rtw_read32(padapter, REG_RCR);
+ v |= RCR_CBSSID_DATA | RCR_CBSSID_BCN ;/* | RCR_ADF */
+ rtw_write32(padapter, REG_RCR, v);
+ RTW_INFO("disable RCR_ADF\n");
+ }
+ return ret;
+}
+
+
+static int rtw_rereg_nd_name(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ _adapter *padapter = rtw_netdev_priv(dev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct rereg_nd_name_data *rereg_priv = &padapter->rereg_nd_name_priv;
+ char new_ifname[IFNAMSIZ];
+
+ if (rereg_priv->old_ifname[0] == 0) {
+ char *reg_ifname;
+#ifdef CONFIG_CONCURRENT_MODE
+ if (padapter->isprimary)
+ reg_ifname = padapter->registrypriv.ifname;
+ else
+#endif
+ reg_ifname = padapter->registrypriv.if2name;
+
+ strncpy(rereg_priv->old_ifname, reg_ifname, IFNAMSIZ);
+ rereg_priv->old_ifname[IFNAMSIZ - 1] = 0;
+ }
+
+ /* RTW_INFO("%s wrqu->data.length:%d\n", __func__, wrqu->data.length); */
+ if (wrqu->data.length > IFNAMSIZ)
+ return -EFAULT;
+
+ if (copy_from_user(new_ifname, wrqu->data.pointer, IFNAMSIZ))
+ return -EFAULT;
+
+ if (0 == strcmp(rereg_priv->old_ifname, new_ifname))
+ return ret;
+
+ RTW_INFO("%s new_ifname:%s\n", __func__, new_ifname);
+ rtw_set_rtnl_lock_holder(dvobj, current);
+ ret = rtw_change_ifname(padapter, new_ifname);
+ rtw_set_rtnl_lock_holder(dvobj, NULL);
+ if (0 != ret)
+ goto exit;
+
+ if (!memcmp(rereg_priv->old_ifname, "disable%d", 9) ) {
+ padapter->ledpriv.bRegUseLed = rereg_priv->old_bRegUseLed;
+ rtw_hal_sw_led_init(padapter);
+ /* rtw_ips_mode_req(&padapter->pwrctrlpriv, rereg_priv->old_ips_mode); */
+ }
+
+ strncpy(rereg_priv->old_ifname, new_ifname, IFNAMSIZ);
+ rereg_priv->old_ifname[IFNAMSIZ - 1] = 0;
+
+ if (!memcmp(new_ifname, "disable%d", 9) ) {
+
+ RTW_INFO("%s disable\n", __func__);
+ /* free network queue for Android's timming issue */
+ rtw_free_network_queue(padapter, true);
+
+ /* close led */
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+ rereg_priv->old_bRegUseLed = padapter->ledpriv.bRegUseLed;
+ padapter->ledpriv.bRegUseLed = false;
+ rtw_hal_sw_led_deinit(padapter);
+
+ /* the interface is being "disabled", we can do deeper IPS */
+ /* rereg_priv->old_ips_mode = rtw_get_ips_mode_req(&padapter->pwrctrlpriv); */
+ /* rtw_ips_mode_req(&padapter->pwrctrlpriv, IPS_NORMAL); */
+ }
+exit:
+ return ret;
+
+}
+
+#ifdef CONFIG_IOL
+#include <rtw_iol.h>
+#endif
+
+#ifdef DBG_CMD_QUEUE
+u8 dump_cmd_id = 0;
+#endif
+static int rtw_dbg_port(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ unsigned long irqL;
+ int ret = 0;
+ u8 major_cmd, minor_cmd;
+ u16 arg;
+ u32 extra_arg, *pdata, val32;
+ struct sta_info *psta;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ struct wlan_network *cur_network = &(pmlmepriv->cur_network);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+
+ pdata = (u32 *)&wrqu->data;
+
+ val32 = *pdata;
+ arg = (u16)(val32 & 0x0000ffff);
+ major_cmd = (u8)(val32 >> 24);
+ minor_cmd = (u8)((val32 >> 16) & 0x00ff);
+
+ extra_arg = *(pdata + 1);
+
+ switch (major_cmd) {
+ case 0x70: /* read_reg */
+ switch (minor_cmd) {
+ case 1:
+ RTW_INFO("rtw_read8(0x%x)=0x%02x\n", arg, rtw_read8(padapter, arg));
+ break;
+ case 2:
+ RTW_INFO("rtw_read16(0x%x)=0x%04x\n", arg, rtw_read16(padapter, arg));
+ break;
+ case 4:
+ RTW_INFO("rtw_read32(0x%x)=0x%08x\n", arg, rtw_read32(padapter, arg));
+ break;
+ }
+ break;
+ case 0x71: /* write_reg */
+ switch (minor_cmd) {
+ case 1:
+ rtw_write8(padapter, arg, extra_arg);
+ RTW_INFO("rtw_write8(0x%x)=0x%02x\n", arg, rtw_read8(padapter, arg));
+ break;
+ case 2:
+ rtw_write16(padapter, arg, extra_arg);
+ RTW_INFO("rtw_write16(0x%x)=0x%04x\n", arg, rtw_read16(padapter, arg));
+ break;
+ case 4:
+ rtw_write32(padapter, arg, extra_arg);
+ RTW_INFO("rtw_write32(0x%x)=0x%08x\n", arg, rtw_read32(padapter, arg));
+ break;
+ }
+ break;
+ case 0x72: /* read_bb */
+ RTW_INFO("read_bbreg(0x%x)=0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff));
+ break;
+ case 0x73: /* write_bb */
+ rtw_hal_write_bbreg(padapter, arg, 0xffffffff, extra_arg);
+ RTW_INFO("write_bbreg(0x%x)=0x%x\n", arg, rtw_hal_read_bbreg(padapter, arg, 0xffffffff));
+ break;
+ case 0x74: /* read_rf */
+ RTW_INFO("read RF_reg path(0x%02x),offset(0x%x),value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff));
+ break;
+ case 0x75: /* write_rf */
+ rtw_hal_write_rfreg(padapter, minor_cmd, arg, 0xffffffff, extra_arg);
+ RTW_INFO("write RF_reg path(0x%02x),offset(0x%x),value(0x%08x)\n", minor_cmd, arg, rtw_hal_read_rfreg(padapter, minor_cmd, arg, 0xffffffff));
+ break;
+
+ case 0x76:
+ switch (minor_cmd) {
+ case 0x00: /* normal mode, */
+ padapter->recvpriv.is_signal_dbg = 0;
+ break;
+ case 0x01: /* dbg mode */
+ padapter->recvpriv.is_signal_dbg = 1;
+ extra_arg = extra_arg > 100 ? 100 : extra_arg;
+ padapter->recvpriv.signal_strength_dbg = extra_arg;
+ break;
+ }
+ break;
+ case 0x78: /* IOL test */
+ switch (minor_cmd) {
+ #ifdef CONFIG_IOL
+ case 0x04: { /* LLT table initialization test */
+ u8 page_boundary = 0xf9;
+ {
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ rtw_IOL_append_LLT_cmd(xmit_frame, page_boundary);
+
+
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 500, 0))
+ ret = -EPERM;
+ }
+ }
+ break;
+ case 0x05: { /* blink LED test */
+ u16 reg = 0x4c;
+ u32 blink_num = 50;
+ u32 blink_delay_ms = 200;
+ int i;
+
+ {
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < blink_num; i++) {
+ #ifdef CONFIG_IOL_NEW_GENERATION
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x00, 0xff);
+ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x08, 0xff);
+ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+ #else
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x00);
+ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, 0x08);
+ rtw_IOL_append_DELAY_MS_cmd(xmit_frame, blink_delay_ms);
+ #endif
+ }
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, (blink_delay_ms * blink_num * 2) + 200, 0))
+ ret = -EPERM;
+ }
+ }
+ break;
+
+ case 0x06: { /* continuous wirte byte test */
+ u16 reg = arg;
+ u16 start_value = 0;
+ u32 write_num = extra_arg;
+ int i;
+ u8 final;
+
+ {
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < write_num; i++) {
+ #ifdef CONFIG_IOL_NEW_GENERATION
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, i + start_value, 0xFF);
+ #else
+ rtw_IOL_append_WB_cmd(xmit_frame, reg, i + start_value);
+ #endif
+ }
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+ ret = -EPERM;
+ }
+
+ final = rtw_read8(padapter, reg);
+ if (start_value + write_num - 1 == final)
+ RTW_INFO("continuous IOL_CMD_WB_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+ else
+ RTW_INFO("continuous IOL_CMD_WB_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+ }
+ break;
+
+ case 0x07: { /* continuous wirte word test */
+ u16 reg = arg;
+ u16 start_value = 200;
+ u32 write_num = extra_arg;
+
+ int i;
+ u16 final;
+
+ {
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < write_num; i++) {
+ #ifdef CONFIG_IOL_NEW_GENERATION
+ rtw_IOL_append_WW_cmd(xmit_frame, reg, i + start_value, 0xFFFF);
+ #else
+ rtw_IOL_append_WW_cmd(xmit_frame, reg, i + start_value);
+ #endif
+ }
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+ ret = -EPERM;
+ }
+
+ final = rtw_read16(padapter, reg);
+ if (start_value + write_num - 1 == final)
+ RTW_INFO("continuous IOL_CMD_WW_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+ else
+ RTW_INFO("continuous IOL_CMD_WW_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+ }
+ break;
+
+ case 0x08: { /* continuous wirte dword test */
+ u16 reg = arg;
+ u32 start_value = 0x110000c7;
+ u32 write_num = extra_arg;
+
+ int i;
+ u32 final;
+
+ {
+ struct xmit_frame *xmit_frame;
+
+ xmit_frame = rtw_IOL_accquire_xmit_frame(padapter);
+ if (xmit_frame == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < write_num; i++) {
+ #ifdef CONFIG_IOL_NEW_GENERATION
+ rtw_IOL_append_WD_cmd(xmit_frame, reg, i + start_value, 0xFFFFFFFF);
+ #else
+ rtw_IOL_append_WD_cmd(xmit_frame, reg, i + start_value);
+ #endif
+ }
+ if (_SUCCESS != rtw_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0))
+ ret = -EPERM;
+
+ }
+
+ final = rtw_read32(padapter, reg);
+ if (start_value + write_num - 1 == final)
+ RTW_INFO("continuous IOL_CMD_WD_REG to 0x%x %u times Success, start:%u, final:%u\n", reg, write_num, start_value, final);
+ else
+ RTW_INFO("continuous IOL_CMD_WD_REG to 0x%x %u times Fail, start:%u, final:%u\n", reg, write_num, start_value, final);
+ }
+ break;
+ #endif /* CONFIG_IOL */
+ }
+ break;
+ case 0x79: {
+ /*
+ * dbg 0x79000000 [value], set RESP_TXAGC to + value, value:0~15
+ * dbg 0x79010000 [value], set RESP_TXAGC to - value, value:0~15
+ */
+ u8 value = extra_arg & 0x0f;
+ u8 sign = minor_cmd;
+ u16 write_value = 0;
+
+ RTW_INFO("%s set RESP_TXAGC to %s %u\n", __func__, sign ? "minus" : "plus", value);
+
+ if (sign)
+ value = value | 0x10;
+
+ write_value = value | (value << 5);
+ rtw_write16(padapter, 0x6d9, write_value);
+ }
+ break;
+ case 0x7a:
+ receive_disconnect(padapter, pmlmeinfo->network.MacAddress
+ , WLAN_REASON_EXPIRATION_CHK, false);
+ break;
+ case 0x7F:
+ switch (minor_cmd) {
+ case 0x0:
+ RTW_INFO("fwstate=0x%x\n", get_fwstate(pmlmepriv));
+ break;
+ case 0x01:
+ RTW_INFO("auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n",
+ psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
+ psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
+ break;
+ case 0x02:
+ RTW_INFO("pmlmeinfo->state=0x%x\n", pmlmeinfo->state);
+ RTW_INFO("DrvBcnEarly=%d\n", pmlmeext->DrvBcnEarly);
+ RTW_INFO("DrvBcnTimeOut=%d\n", pmlmeext->DrvBcnTimeOut);
+ break;
+ case 0x03:
+ RTW_INFO("qos_option=%d\n", pmlmepriv->qospriv.qos_option);
+ RTW_INFO("ht_option=%d\n", pmlmepriv->htpriv.ht_option);
+ break;
+ case 0x04:
+ RTW_INFO("cur_ch=%d\n", pmlmeext->cur_channel);
+ RTW_INFO("cur_bw=%d\n", pmlmeext->cur_bwmode);
+ RTW_INFO("cur_ch_off=%d\n", pmlmeext->cur_ch_offset);
+
+ RTW_INFO("oper_ch=%d\n", rtw_get_oper_ch(padapter));
+ RTW_INFO("oper_bw=%d\n", rtw_get_oper_bw(padapter));
+ RTW_INFO("oper_ch_offet=%d\n", rtw_get_oper_choffset(padapter));
+
+ break;
+ case 0x05:
+ psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress);
+ if (psta) {
+ RTW_INFO("SSID=%s\n", cur_network->network.Ssid.Ssid);
+ RTW_INFO("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr));
+ RTW_INFO("cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset);
+ RTW_INFO("rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+ RTW_INFO("state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ RTW_INFO("qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ RTW_INFO("bwmode=%d, ch_offset=%d, sgi_20m=%d,sgi_40m=%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m);
+ RTW_INFO("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ RTW_INFO("agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+ sta_rx_reorder_ctl_dump(RTW_DBGDUMP, psta);
+ } else
+ RTW_INFO("can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress));
+ break;
+ case 0x06: {
+ }
+ break;
+ case 0x07:
+ RTW_INFO("bSurpriseRemoved=%s, bDriverStopped=%s\n"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False"
+ , rtw_is_drv_stopped(padapter) ? "True" : "False");
+ break;
+ case 0x08: {
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ RTW_INFO("free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d"
+ ", free_xmit_extbuf_cnt=%d, free_xframe_ext_cnt=%d"
+ ", free_recvframe_cnt=%d\n",
+ pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt,
+ pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt,
+ precvpriv->free_recvframe_cnt);
+ RTW_INFO("rx_urb_pending_cn=%d\n", ATOMIC_READ(&(precvpriv->rx_pending_cnt)));
+ }
+ break;
+ case 0x09: {
+ int i;
+ _list *plist, *phead;
+
+#ifdef CONFIG_AP_MODE
+ RTW_INFO("sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap);
+#endif
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ for (i = 0; i < NUM_STA; i++) {
+ phead = &(pstapriv->sta_hash[i]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ plist = get_next(plist);
+
+ if (extra_arg == psta->aid) {
+ RTW_INFO("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr));
+ RTW_INFO("rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self);
+ RTW_INFO("state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid);
+ RTW_INFO("qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate);
+ RTW_INFO("bwmode=%d, ch_offset=%d, sgi_20m=%d,sgi_40m=%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m,
+ psta->htpriv.sgi_40m);
+ RTW_INFO("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
+ RTW_INFO("agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
+
+#ifdef CONFIG_AP_MODE
+ RTW_INFO("capability=0x%x\n", psta->capability);
+ RTW_INFO("flags=0x%x\n", psta->flags);
+ RTW_INFO("wpa_psk=0x%x\n", psta->wpa_psk);
+ RTW_INFO("wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher);
+ RTW_INFO("wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher);
+ RTW_INFO("qos_info=0x%x\n", psta->qos_info);
+#endif
+ RTW_INFO("dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy);
+
+ sta_rx_reorder_ctl_dump(RTW_DBGDUMP, psta);
+ }
+
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ }
+ break;
+
+ case 0x0b: { /* Enable=1, Disable=0 driver control vrtl_carrier_sense. */
+ /* u8 driver_vcs_en; */ /* Enable=1, Disable=0 driver control vrtl_carrier_sense. */
+ /* u8 driver_vcs_type; */ /* force 0:disable VCS, 1:RTS-CTS, 2:CTS-to-self when vcs_en=1. */
+
+ if (arg == 0) {
+ RTW_INFO("disable driver ctrl vcs\n");
+ padapter->driver_vcs_en = 0;
+ } else if (arg == 1) {
+ RTW_INFO("enable driver ctrl vcs = %d\n", extra_arg);
+ padapter->driver_vcs_en = 1;
+
+ if (extra_arg > 2)
+ padapter->driver_vcs_type = 1;
+ else
+ padapter->driver_vcs_type = extra_arg;
+ }
+ }
+ break;
+ case 0x0c: { /* dump rx/tx packet */
+ if (arg == 0) {
+ RTW_INFO("dump rx packet (%d)\n", extra_arg);
+ /* pHalData->bDumpRxPkt =extra_arg; */
+ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_RXPKT, &(extra_arg));
+ } else if (arg == 1) {
+ RTW_INFO("dump tx packet (%d)\n", extra_arg);
+ rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(extra_arg));
+ }
+ }
+ break;
+ case 0x0e: {
+ if (arg == 0) {
+ RTW_INFO("disable driver ctrl rx_ampdu_factor\n");
+ padapter->driver_rx_ampdu_factor = 0xFF;
+ } else if (arg == 1) {
+
+ RTW_INFO("enable driver ctrl rx_ampdu_factor = %d\n", extra_arg);
+
+ if (extra_arg > 0x03)
+ padapter->driver_rx_ampdu_factor = 0xFF;
+ else
+ padapter->driver_rx_ampdu_factor = extra_arg;
+ }
+ }
+ break;
+ #ifdef DBG_CONFIG_ERROR_DETECT
+ case 0x0f: {
+ if (extra_arg == 0) {
+ RTW_INFO("###### silent reset test.......#####\n");
+ rtw_hal_sreset_reset(padapter);
+ } else {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+ psrtpriv->dbg_trigger_point = extra_arg;
+ }
+
+ }
+ break;
+ case 0x15: {
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ RTW_INFO("==>silent resete cnts:%d\n", pwrpriv->ips_enter_cnts);
+ }
+ break;
+
+ #endif
+
+ case 0x10: /* driver version display */
+ dump_drv_version(RTW_DBGDUMP);
+ break;
+ case 0x11: { /* dump linked status */
+ int pre_mode;
+ pre_mode = padapter->bLinkInfoDump;
+ /* linked_info_dump(padapter,extra_arg); */
+ if (extra_arg == 1 || (extra_arg == 0 && pre_mode == 1)) /* not consider pwr_saving 0: */
+ padapter->bLinkInfoDump = extra_arg;
+
+ else if ((extra_arg == 2) || (extra_arg == 0 && pre_mode == 2)) { /* consider power_saving */
+ /* RTW_INFO("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable") */
+ linked_info_dump(padapter, extra_arg);
+ }
+
+
+
+ }
+ break;
+ case 0x12: { /* set rx_stbc */
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ /* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, 0x3: enable both 2.4g and 5g */
+ /* default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
+ if (pregpriv && (extra_arg == 0 || extra_arg == 1 || extra_arg == 2 || extra_arg == 3)) {
+ pregpriv->rx_stbc = extra_arg;
+ RTW_INFO("set rx_stbc=%d\n", pregpriv->rx_stbc);
+ } else
+ RTW_INFO("get rx_stbc=%d\n", pregpriv->rx_stbc);
+
+ }
+ break;
+ case 0x13: { /* set ampdu_enable */
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ /* 0: disable, 0x1:enable */
+ if (pregpriv && extra_arg < 2) {
+ pregpriv->ampdu_enable = extra_arg;
+ RTW_INFO("set ampdu_enable=%d\n", pregpriv->ampdu_enable);
+ } else
+ RTW_INFO("get ampdu_enable=%d\n", pregpriv->ampdu_enable);
+
+ }
+ break;
+ case 0x14: { /* get wifi_spec */
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+ RTW_INFO("get wifi_spec=%d\n", pregpriv->wifi_spec);
+
+ }
+ break;
+
+#ifdef DBG_FIXED_CHAN
+ case 0x17: {
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ printk("===> Fixed channel to %d\n", extra_arg);
+ pmlmeext->fixed_chan = extra_arg;
+
+ }
+ break;
+#endif
+ case 0x19: {
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ /* extra_arg : */
+ /* BIT0: Enable VHT LDPC Rx, BIT1: Enable VHT LDPC Tx, */
+ /* BIT4: Enable HT LDPC Rx, BIT5: Enable HT LDPC Tx */
+ if (arg == 0) {
+ RTW_INFO("driver disable LDPC\n");
+ pregistrypriv->ldpc_cap = 0x00;
+ } else if (arg == 1) {
+ RTW_INFO("driver set LDPC cap = 0x%x\n", extra_arg);
+ pregistrypriv->ldpc_cap = (u8)(extra_arg & 0x33);
+ }
+ }
+ break;
+ case 0x1a: {
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ /* extra_arg : */
+ /* BIT0: Enable VHT STBC Rx, BIT1: Enable VHT STBC Tx, */
+ /* BIT4: Enable HT STBC Rx, BIT5: Enable HT STBC Tx */
+ if (arg == 0) {
+ RTW_INFO("driver disable STBC\n");
+ pregistrypriv->stbc_cap = 0x00;
+ } else if (arg == 1) {
+ RTW_INFO("driver set STBC cap = 0x%x\n", extra_arg);
+ pregistrypriv->stbc_cap = (u8)(extra_arg & 0x33);
+ }
+ }
+ break;
+ case 0x1b: {
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+
+ if (arg == 0) {
+ RTW_INFO("disable driver ctrl max_rx_rate, reset to default_rate_set\n");
+ init_mlme_default_rate_set(padapter);
+ pregistrypriv->ht_enable = (u8)rtw_ht_enable;
+ } else if (arg == 1) {
+
+ int i;
+ u8 max_rx_rate;
+
+ RTW_INFO("enable driver ctrl max_rx_rate = 0x%x\n", extra_arg);
+
+ max_rx_rate = (u8)extra_arg;
+
+ if (max_rx_rate < 0xc) { /* max_rx_rate < MSC0->B or G -> disable HT */
+ pregistrypriv->ht_enable = 0;
+ for (i = 0; i < NumRates; i++) {
+ if (pmlmeext->datarate[i] > max_rx_rate)
+ pmlmeext->datarate[i] = 0xff;
+ }
+
+ } else if (max_rx_rate < 0x1c) { /* mcs0~mcs15 */
+ u32 mcs_bitmap = 0x0;
+
+ for (i = 0; i < ((max_rx_rate + 1) - 0xc); i++)
+ mcs_bitmap |= BIT(i);
+
+ set_mcs_rate_by_mask(pmlmeext->default_supported_mcs_set, mcs_bitmap);
+ }
+ }
+ }
+ break;
+ case 0x1c: { /* enable/disable driver control AMPDU Density for peer sta's rx */
+ if (arg == 0) {
+ RTW_INFO("disable driver ctrl ampdu density\n");
+ padapter->driver_ampdu_spacing = 0xFF;
+ } else if (arg == 1) {
+
+ RTW_INFO("enable driver ctrl ampdu density = %d\n", extra_arg);
+
+ if (extra_arg > 0x07)
+ padapter->driver_ampdu_spacing = 0xFF;
+ else
+ padapter->driver_ampdu_spacing = extra_arg;
+ }
+ }
+ break;
+#ifdef CONFIG_BACKGROUND_NOISE_MONITOR
+ case 0x1e: {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv;
+ u8 chan = rtw_get_oper_ch(padapter);
+ RTW_INFO("===========================================\n");
+ odm_inband_noise_monitor(pDM_Odm, true, 0x1e, 100);
+ RTW_INFO("channel(%d),noise_a = %d, noise_b = %d , noise_all:%d\n",
+ chan, pDM_Odm->noise_level.noise[ODM_RF_PATH_A],
+ pDM_Odm->noise_level.noise[ODM_RF_PATH_B],
+ pDM_Odm->noise_level.noise_all);
+ RTW_INFO("===========================================\n");
+
+ }
+ break;
+#endif
+
+
+ case 0x20:
+ {
+ if (arg == 0xAA) {
+ u8 page_offset, page_num;
+ u32 page_size = 0;
+ u8 *buffer = NULL;
+ u32 buf_size = 0;
+
+ page_offset = (u8)(extra_arg >> 16);
+ page_num = (u8)(extra_arg & 0xFF);
+ rtw_dump_rsvd_page(RTW_DBGDUMP, padapter, page_offset, page_num);
+ }
+#ifdef CONFIG_SUPPORT_FIFO_DUMP
+ else {
+ u8 fifo_sel;
+ u32 addr, size;
+ u8 *buffer = NULL;
+
+ fifo_sel = (u8)(arg & 0x0F);
+ addr = (extra_arg >> 16) & 0xFFFF;
+ size = extra_arg & 0xFFFF;
+
+ RTW_INFO("fifo_sel:%d, start_addr:0x%04x, size:%d\n", fifo_sel, addr, size);
+ if (size) {
+ size = RND4(size);
+ buffer = rtw_zvmalloc(size);
+ if (NULL == buffer)
+ size = 0;
+ }
+ rtw_halmac_dump_fifo(adapter_to_dvobj(padapter), fifo_sel, addr, size, buffer);
+ if (buffer)
+ rtw_vmfree(buffer, size);
+ }
+#endif
+ }
+ break;
+
+ case 0x23: {
+ RTW_INFO("turn %s the bNotifyChannelChange Variable\n", (extra_arg == 1) ? "on" : "off");
+ padapter->bNotifyChannelChange = extra_arg;
+ break;
+ }
+ case 0x24: {
+#ifdef CONFIG_P2P
+ RTW_INFO("turn %s the bShowGetP2PState Variable\n", (extra_arg == 1) ? "on" : "off");
+ padapter->bShowGetP2PState = extra_arg;
+#endif /* CONFIG_P2P */
+ break;
+ }
+#ifdef CONFIG_GPIO_API
+ case 0x25: { /* Get GPIO register */
+ /*
+ * dbg 0x7f250000 [gpio_num], Get gpio value, gpio_num:0~7
+ */
+
+ u8 value;
+ RTW_INFO("Read GPIO Value extra_arg = %d\n", extra_arg);
+ value = rtw_hal_get_gpio(padapter, extra_arg);
+ RTW_INFO("Read GPIO Value = %d\n", value);
+ break;
+ }
+ case 0x26: { /* Set GPIO direction */
+
+ /* dbg 0x7f26000x [y], Set gpio direction,
+ * x: gpio_num,4~7 y: indicate direction, 0~1
+ */
+
+ int value;
+ RTW_INFO("Set GPIO Direction! arg = %d ,extra_arg=%d\n", arg , extra_arg);
+ value = rtw_hal_config_gpio(padapter, arg, extra_arg);
+ RTW_INFO("Set GPIO Direction %s\n", (value == -1) ? "Fail!!!" : "Success");
+ break;
+ }
+ case 0x27: { /* Set GPIO output direction value */
+ /*
+ * dbg 0x7f27000x [y], Set gpio output direction value,
+ * x: gpio_num,4~7 y: indicate direction, 0~1
+ */
+
+ int value;
+ RTW_INFO("Set GPIO Value! arg = %d ,extra_arg=%d\n", arg , extra_arg);
+ value = rtw_hal_set_gpio_output_value(padapter, arg, extra_arg);
+ RTW_INFO("Set GPIO Value %s\n", (value == -1) ? "Fail!!!" : "Success");
+ break;
+ }
+#endif
+#ifdef DBG_CMD_QUEUE
+ case 0x28: {
+ dump_cmd_id = extra_arg;
+ RTW_INFO("dump_cmd_id:%d\n", dump_cmd_id);
+ }
+ break;
+#endif /* DBG_CMD_QUEUE */
+ case 0xaa: {
+ if ((extra_arg & 0x7F) > 0x3F)
+ extra_arg = 0xFF;
+ RTW_INFO("chang data rate to :0x%02x\n", extra_arg);
+ padapter->fix_rate = extra_arg;
+ }
+ break;
+ case 0xdd: { /* registers dump , 0 for mac reg,1 for bb reg, 2 for rf reg */
+ if (extra_arg == 0)
+ mac_reg_dump(RTW_DBGDUMP, padapter);
+ else if (extra_arg == 1)
+ bb_reg_dump(RTW_DBGDUMP, padapter);
+ else if (extra_arg == 2)
+ rf_reg_dump(RTW_DBGDUMP, padapter);
+ else if (extra_arg == 11)
+ bb_reg_dump_ex(RTW_DBGDUMP, padapter);
+ }
+ break;
+
+ case 0xee: {
+ RTW_INFO(" === please control /proc to trun on/off PHYDM func ===\n");
+ }
+ break;
+
+ case 0xfd:
+ rtw_write8(padapter, 0xc50, arg);
+ RTW_INFO("wr(0xc50)=0x%x\n", rtw_read8(padapter, 0xc50));
+ rtw_write8(padapter, 0xc58, arg);
+ RTW_INFO("wr(0xc58)=0x%x\n", rtw_read8(padapter, 0xc58));
+ break;
+ case 0xfe:
+ RTW_INFO("rd(0xc50)=0x%x\n", rtw_read8(padapter, 0xc50));
+ RTW_INFO("rd(0xc58)=0x%x\n", rtw_read8(padapter, 0xc58));
+ break;
+ case 0xff: {
+ RTW_INFO("dbg(0x210)=0x%x\n", rtw_read32(padapter, 0x210));
+ RTW_INFO("dbg(0x608)=0x%x\n", rtw_read32(padapter, 0x608));
+ RTW_INFO("dbg(0x280)=0x%x\n", rtw_read32(padapter, 0x280));
+ RTW_INFO("dbg(0x284)=0x%x\n", rtw_read32(padapter, 0x284));
+ RTW_INFO("dbg(0x288)=0x%x\n", rtw_read32(padapter, 0x288));
+
+ RTW_INFO("dbg(0x664)=0x%x\n", rtw_read32(padapter, 0x664));
+
+
+ RTW_INFO("\n");
+
+ RTW_INFO("dbg(0x430)=0x%x\n", rtw_read32(padapter, 0x430));
+ RTW_INFO("dbg(0x438)=0x%x\n", rtw_read32(padapter, 0x438));
+
+ RTW_INFO("dbg(0x440)=0x%x\n", rtw_read32(padapter, 0x440));
+
+ RTW_INFO("dbg(0x458)=0x%x\n", rtw_read32(padapter, 0x458));
+
+ RTW_INFO("dbg(0x484)=0x%x\n", rtw_read32(padapter, 0x484));
+ RTW_INFO("dbg(0x488)=0x%x\n", rtw_read32(padapter, 0x488));
+
+ RTW_INFO("dbg(0x444)=0x%x\n", rtw_read32(padapter, 0x444));
+ RTW_INFO("dbg(0x448)=0x%x\n", rtw_read32(padapter, 0x448));
+ RTW_INFO("dbg(0x44c)=0x%x\n", rtw_read32(padapter, 0x44c));
+ RTW_INFO("dbg(0x450)=0x%x\n", rtw_read32(padapter, 0x450));
+ }
+ break;
+ }
+ break;
+ default:
+ RTW_INFO("error dbg cmd!\n");
+ break;
+ }
+
+
+ return ret;
+
+}
+
+static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
+{
+ uint ret = 0;
+ u32 flags;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ switch (name) {
+ case IEEE_PARAM_WPA_ENABLED:
+
+ padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; /* 802.1x */
+
+ /* ret = ieee80211_wpa_enable(ieee, value); */
+
+ switch ((value) & 0xff) {
+ case 1: /* WPA */
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
+ break;
+ case 2: /* WPA2 */
+ padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; /* WPA2_PSK */
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
+ break;
+ }
+
+
+ break;
+
+ case IEEE_PARAM_TKIP_COUNTERMEASURES:
+ /* ieee->tkip_countermeasures=value; */
+ break;
+
+ case IEEE_PARAM_DROP_UNENCRYPTED: {
+ /* HACK:
+ *
+ * wpa_supplicant calls set_wpa_enabled when the driver
+ * is loaded and unloaded, regardless of if WPA is being
+ * used. No other calls are made which can be used to
+ * determine if encryption will be used or not prior to
+ * association being expected. If encryption is not being
+ * used, drop_unencrypted is set to false, else true -- we
+ * can use this to determine if the CAP_PRIVACY_ON bit should
+ * be set.
+ */
+ break;
+ }
+ case IEEE_PARAM_PRIVACY_INVOKED:
+ break;
+ case IEEE_PARAM_AUTH_ALGS:
+ ret = wpa_set_auth_algs(dev, value);
+ break;
+ case IEEE_PARAM_IEEE_802_1X:
+ break;
+ case IEEE_PARAM_WPAX_SELECT:
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int wpa_mlme(struct net_device *dev, u32 command, u32 reason)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ switch (command) {
+ case IEEE_MLME_STA_DEAUTH:
+
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+
+ break;
+
+ case IEEE_MLME_STA_DISASSOC:
+
+ if (!rtw_set_802_11_disassociate(padapter))
+ ret = -1;
+
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+
+}
+
+static int wpa_supplicant_ioctl(struct net_device *dev, struct iw_point *p)
+{
+ struct ieee_param *param;
+ uint ret = 0;
+
+ /* down(&ieee->wx_sem); */
+
+ if (!p->pointer || p->length != sizeof(struct ieee_param))
+ return -EINVAL;
+
+ param = (struct ieee_param *)rtw_malloc(p->length);
+ if (param == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ rtw_mfree((u8 *)param, p->length);
+ return -EFAULT;
+ }
+
+ switch (param->cmd) {
+
+ case IEEE_CMD_SET_WPA_PARAM:
+ ret = wpa_set_param(dev, param->u.wpa_param.name, param->u.wpa_param.value);
+ break;
+
+ case IEEE_CMD_SET_WPA_IE:
+ /* ret = wpa_set_wpa_ie(dev, param, p->length); */
+ ret = rtw_set_wpa_ie((_adapter *)rtw_netdev_priv(dev), (char *)param->u.wpa_ie.data, (u16)param->u.wpa_ie.len);
+ break;
+
+ case IEEE_CMD_SET_ENCRYPTION:
+ ret = wpa_set_encryption(dev, param, p->length);
+ break;
+
+ case IEEE_CMD_MLME:
+ ret = wpa_mlme(dev, param->u.mlme.command, param->u.mlme.reason_code);
+ break;
+
+ default:
+ RTW_INFO("Unknown WPA supplicant request: %d\n", param->cmd);
+ ret = -EOPNOTSUPP;
+ break;
+
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+ rtw_mfree((u8 *)param, p->length);
+ return ret;
+}
+
+#ifdef CONFIG_AP_MODE
+static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
+{
+ int ret = 0;
+ u32 wep_key_idx, wep_key_len, wep_total_len;
+ NDIS_802_11_WEP *pwep = NULL;
+ struct sta_info *psta = NULL, *pbcmc_sta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ RTW_INFO("%s\n", __func__);
+
+ param->u.crypt.err = 0;
+ param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+ /* sizeof(struct ieee_param) = 64 bytes; */
+ /* if (param_len != (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) */
+ if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) {
+ if (param->u.crypt.idx >= WEP_KEYS
+#ifdef CONFIG_IEEE80211W
+ && param->u.crypt.idx > BIP_MAX_KEYID
+#endif /* CONFIG_IEEE80211W */
+ ) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else {
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (!psta) {
+ /* ret = -EINVAL; */
+ RTW_INFO("rtw_set_encryption(), sta has already been removed or never been added\n");
+ goto exit;
+ }
+ }
+
+ if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) {
+ /* todo:clear default encryption keys */
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+ psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+
+ RTW_INFO("clear default encryption keys, keyid=%d\n", param->u.crypt.idx);
+
+ goto exit;
+ }
+
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) {
+ RTW_INFO("r871x_set_encryption, crypt.alg = WEP\n");
+
+ wep_key_idx = param->u.crypt.idx;
+ wep_key_len = param->u.crypt.key_len;
+
+ RTW_INFO("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);
+
+ if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+
+ if (wep_key_len > 0) {
+ wep_key_len = wep_key_len <= 5 ? 5 : 13;
+ wep_total_len = wep_key_len + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial);
+ pwep = (NDIS_802_11_WEP *)rtw_malloc(wep_total_len);
+ if (pwep == NULL) {
+ RTW_INFO(" r871x_set_encryption: pwep allocate fail !!!\n");
+ goto exit;
+ }
+
+ memset(pwep, 0, wep_total_len);
+
+ pwep->KeyLength = wep_key_len;
+ pwep->Length = wep_total_len;
+
+ }
+
+ pwep->KeyIndex = wep_key_idx;
+
+ memcpy(pwep->KeyMaterial, param->u.crypt.key, pwep->KeyLength);
+
+ if (param->u.crypt.set_tx) {
+ RTW_INFO("wep, set_tx=1\n");
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+ if (pwep->KeyLength == 13) {
+ psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ }
+
+
+ psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+ rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 1);
+ } else {
+ RTW_INFO("wep, set_tx=0\n");
+
+ /* don't update "psecuritypriv->dot11PrivacyAlgrthm" and */
+ /* "psecuritypriv->dot11PrivacyKeyIndex=keyid", but can rtw_set_key to cam */
+
+ memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
+
+ psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
+
+ rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 0);
+ }
+
+ goto exit;
+
+ }
+
+
+ if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) /* */ { /* group key */
+ if (param->u.crypt.set_tx == 1) {
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RTW_INFO("%s, set group_key, WEP\n", __func__);
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ RTW_INFO("%s, set group_key, TKIP\n", __func__);
+
+ psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ /* DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); */
+ /* set mic key */
+ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ RTW_INFO("%s, set group_key, CCMP\n", __func__);
+
+ psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ }
+#ifdef CONFIG_IEEE80211W
+ else if (strcmp(param->u.crypt.alg, "BIP") == 0) {
+ int no;
+
+ RTW_INFO("BIP key_len=%d , index=%d\n", param->u.crypt.key_len, param->u.crypt.idx);
+ /* save the IGTK key, length 16 bytes */
+ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ /* RTW_INFO("IGTK key below:\n");
+ for(no=0;no<16;no++)
+ printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
+ RTW_INFO("\n"); */
+ padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx;
+ padapter->securitypriv.binstallBIPkey = true;
+ RTW_INFO(" ~~~~set sta key:IGKT\n");
+ goto exit;
+ }
+#endif /* CONFIG_IEEE80211W */
+ else {
+ RTW_INFO("%s, set group_key, none\n", __func__);
+
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ }
+
+ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+ psecuritypriv->binstallGrpkey = true;
+
+ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* !!! */
+
+ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta) {
+ pbcmc_sta->ieee8021x_blocked = false;
+ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; /* rx will use bmc_sta's dot118021XPrivacy */
+ }
+
+ }
+
+ goto exit;
+
+ }
+
+ if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ if (param->u.crypt.set_tx == 1) {
+ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ RTW_INFO("%s, set pairwise key, WEP\n", __func__);
+
+ psta->dot118021XPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psta->dot118021XPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ RTW_INFO("%s, set pairwise key, TKIP\n", __func__);
+
+ psta->dot118021XPrivacy = _TKIP_;
+
+ /* DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); */
+ /* set mic key */
+ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+
+ RTW_INFO("%s, set pairwise key, CCMP\n", __func__);
+
+ psta->dot118021XPrivacy = _AES_;
+ } else {
+ RTW_INFO("%s, set pairwise key, none\n", __func__);
+
+ psta->dot118021XPrivacy = _NO_PRIVACY_;
+ }
+
+ rtw_ap_set_pairwise_key(padapter, psta);
+
+ psta->ieee8021x_blocked = false;
+
+ psta->bpairwise_key_installed = true;
+
+ } else { /* group key??? */
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+ if (param->u.crypt.key_len == 13)
+ psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+
+ /* DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len); */
+ /* set mic key */
+ memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+ memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
+
+ psecuritypriv->busetkipkey = true;
+
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+ memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+ } else
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+
+ psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+ psecuritypriv->binstallGrpkey = true;
+
+ psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;/* !!! */
+
+ rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
+
+ pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
+ if (pbcmc_sta) {
+ pbcmc_sta->ieee8021x_blocked = false;
+ pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy; /* rx will use bmc_sta's dot118021XPrivacy */
+ }
+
+ }
+
+ }
+
+ }
+
+exit:
+
+ if (pwep)
+ rtw_mfree((u8 *)pwep, wep_total_len);
+
+ return ret;
+
+}
+
+static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ unsigned char *pbuf = param->u.bcn_ie.buf;
+
+
+ RTW_INFO("%s, len=%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2);
+
+ if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0))
+ pstapriv->max_num_sta = NUM_STA;
+
+
+ if (rtw_check_beacon_data(padapter, pbuf, (len - 12 - 2)) == _SUCCESS) /* 12 = param header, 2:no packed */
+ ret = 0;
+ else
+ ret = -EINVAL;
+
+
+ return ret;
+
+}
+
+static int rtw_hostapd_sta_flush(struct net_device *dev)
+{
+ /* unsigned long irqL; */
+ /* _list *phead, *plist; */
+ int ret = 0;
+ /* struct sta_info *psta = NULL; */
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ /* struct sta_priv *pstapriv = &padapter->stapriv; */
+
+ RTW_INFO("%s\n", __func__);
+
+ flush_all_cam_entry(padapter); /* clear CAM */
+
+ ret = rtw_sta_flush(padapter, true);
+
+ return ret;
+
+}
+
+static int rtw_add_sta(struct net_device *dev, struct ieee_param *param)
+{
+ unsigned long irqL;
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ RTW_INFO("rtw_add_sta(aid=%d)=" MAC_FMT "\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta) {
+ int flags = param->u.add_sta.flags;
+
+ /* RTW_INFO("rtw_add_sta(), init sta's variables, psta=%p\n", psta); */
+
+ psta->aid = param->u.add_sta.aid;/* aid=1~2007 */
+
+ memcpy(psta->bssrateset, param->u.add_sta.tx_supp_rates, 16);
+
+
+ /* check wmm cap. */
+ if (WLAN_STA_WME & flags)
+ psta->qos_option = 1;
+ else
+ psta->qos_option = 0;
+
+ if (pmlmepriv->qospriv.qos_option == 0)
+ psta->qos_option = 0;
+
+ /* chec 802.11n ht cap. */
+ if (WLAN_STA_HT & flags) {
+ psta->htpriv.ht_option = true;
+ psta->qos_option = 1;
+ memcpy((void *)&psta->htpriv.ht_cap, (void *)¶m->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+ } else
+ psta->htpriv.ht_option = false;
+
+ if (pmlmepriv->htpriv.ht_option == false)
+ psta->htpriv.ht_option = false;
+
+ update_sta_info_apmode(padapter, psta);
+
+
+ } else
+ ret = -ENOMEM;
+
+ return ret;
+
+}
+
+static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
+{
+ unsigned long irqL;
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ RTW_INFO("rtw_del_sta=" MAC_FMT "\n", MAC_ARG(param->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta) {
+ u8 updated = false;
+
+ /* RTW_INFO("free psta=%p, aid=%d\n", psta, psta->aid); */
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ if (list_empty(&psta->asoc_list) == false) {
+ list_del_init(&psta->asoc_list);
+ pstapriv->asoc_list_cnt--;
+ updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING, true);
+
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL);
+
+ psta = NULL;
+
+ } else {
+ RTW_INFO("rtw_del_sta(), sta has already been removed or never been added\n");
+
+ /* ret = -1; */
+ }
+
+
+ return ret;
+
+}
+
+static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param;
+ struct sta_data *psta_data = (struct sta_data *)param_ex->data;
+
+ RTW_INFO("rtw_ioctl_get_sta_info, sta_addr: " MAC_FMT "\n", MAC_ARG(param_ex->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param_ex->sta_addr[0] == 0xff && param_ex->sta_addr[1] == 0xff &&
+ param_ex->sta_addr[2] == 0xff && param_ex->sta_addr[3] == 0xff &&
+ param_ex->sta_addr[4] == 0xff && param_ex->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param_ex->sta_addr);
+ if (psta) {
+ psta_data->aid = (u16)psta->aid;
+ psta_data->capability = psta->capability;
+ psta_data->flags = psta->flags;
+
+ /*
+ nonerp_set : BIT(0)
+ no_short_slot_time_set : BIT(1)
+ no_short_preamble_set : BIT(2)
+ no_ht_gf_set : BIT(3)
+ no_ht_set : BIT(4)
+ ht_20mhz_set : BIT(5)
+ */
+
+ psta_data->sta_set = ((psta->nonerp_set) |
+ (psta->no_short_slot_time_set << 1) |
+ (psta->no_short_preamble_set << 2) |
+ (psta->no_ht_gf_set << 3) |
+ (psta->no_ht_set << 4) |
+ (psta->ht_20mhz_set << 5));
+
+ psta_data->tx_supp_rates_len = psta->bssratelen;
+ memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen);
+ memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct rtw_ieee80211_ht_cap));
+ psta_data->rx_pkts = psta->sta_stats.rx_data_pkts;
+ psta_data->rx_bytes = psta->sta_stats.rx_bytes;
+ psta_data->rx_drops = psta->sta_stats.rx_drops;
+
+ psta_data->tx_pkts = psta->sta_stats.tx_pkts;
+ psta_data->tx_bytes = psta->sta_stats.tx_bytes;
+ psta_data->tx_drops = psta->sta_stats.tx_drops;
+ } else
+ ret = -1;
+
+ return ret;
+
+}
+
+static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param)
+{
+ int ret = 0;
+ struct sta_info *psta = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ RTW_INFO("rtw_get_sta_wpaie, sta_addr: " MAC_FMT "\n", MAC_ARG(param->sta_addr));
+
+ if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ psta = rtw_get_stainfo(pstapriv, param->sta_addr);
+ if (psta) {
+ if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) {
+ int wpa_ie_len;
+ int copy_len;
+
+ wpa_ie_len = psta->wpa_ie[1];
+
+ copy_len = ((wpa_ie_len + 2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)) : (wpa_ie_len + 2);
+
+ param->u.wpa_ie.len = copy_len;
+
+ memcpy(param->u.wpa_ie.reserved, psta->wpa_ie, copy_len);
+ } else {
+ /* ret = -1; */
+ RTW_INFO("sta's wpa_ie is NONE\n");
+ }
+ } else
+ ret = -1;
+
+ return ret;
+
+}
+
+static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ int ie_len;
+
+ RTW_INFO("%s, len=%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ ie_len = len - 12 - 2; /* 12 = param header, 2:no packed */
+
+
+ if (pmlmepriv->wps_beacon_ie) {
+ rtw_mfree(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len);
+ pmlmepriv->wps_beacon_ie = NULL;
+ }
+
+ if (ie_len > 0) {
+ pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
+ pmlmepriv->wps_beacon_ie_len = ie_len;
+ if (pmlmepriv->wps_beacon_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ memcpy(pmlmepriv->wps_beacon_ie, param->u.bcn_ie.buf, ie_len);
+
+ update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, true);
+
+ pmlmeext->bstart_bss = true;
+
+ }
+
+
+ return ret;
+
+}
+
+static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int ie_len;
+
+ RTW_INFO("%s, len=%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ ie_len = len - 12 - 2; /* 12 = param header, 2:no packed */
+
+
+ if (pmlmepriv->wps_probe_resp_ie) {
+ rtw_mfree(pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len);
+ pmlmepriv->wps_probe_resp_ie = NULL;
+ }
+
+ if (ie_len > 0) {
+ pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
+ pmlmepriv->wps_probe_resp_ie_len = ie_len;
+ if (pmlmepriv->wps_probe_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ memcpy(pmlmepriv->wps_probe_resp_ie, param->u.bcn_ie.buf, ie_len);
+ }
+
+
+ return ret;
+
+}
+
+static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int ie_len;
+
+ RTW_INFO("%s, len=%d\n", __func__, len);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ ie_len = len - 12 - 2; /* 12 = param header, 2:no packed */
+
+
+ if (pmlmepriv->wps_assoc_resp_ie) {
+ rtw_mfree(pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len);
+ pmlmepriv->wps_assoc_resp_ie = NULL;
+ }
+
+ if (ie_len > 0) {
+ pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
+ pmlmepriv->wps_assoc_resp_ie_len = ie_len;
+ if (pmlmepriv->wps_assoc_resp_ie == NULL) {
+ RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ memcpy(pmlmepriv->wps_assoc_resp_ie, param->u.bcn_ie.buf, ie_len);
+ }
+
+
+ return ret;
+
+}
+
+static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *mlmepriv = &(adapter->mlmepriv);
+ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+ struct mlme_ext_info *mlmeinfo = &(mlmeext->mlmext_info);
+ int ie_len;
+ u8 *ssid_ie;
+ char ssid[NDIS_802_11_LENGTH_SSID + 1];
+ sint ssid_len = 0;
+ u8 ignore_broadcast_ssid;
+
+ if (check_fwstate(mlmepriv, WIFI_AP_STATE) != true)
+ return -EPERM;
+
+ if (param->u.bcn_ie.reserved[0] != 0xea)
+ return -EINVAL;
+
+ mlmeinfo->hidden_ssid_mode = ignore_broadcast_ssid = param->u.bcn_ie.reserved[1];
+
+ ie_len = len - 12 - 2; /* 12 = param header, 2:no packed */
+ ssid_ie = rtw_get_ie(param->u.bcn_ie.buf, WLAN_EID_SSID, &ssid_len, ie_len);
+
+ if (ssid_ie && ssid_len > 0 && ssid_len <= NDIS_802_11_LENGTH_SSID) {
+ WLAN_BSSID_EX *pbss_network = &mlmepriv->cur_network.network;
+ WLAN_BSSID_EX *pbss_network_ext = &mlmeinfo->network;
+
+ memcpy(ssid, ssid_ie + 2, ssid_len);
+ ssid[ssid_len] = 0x0;
+
+ if (0)
+ RTW_INFO(FUNC_ADPT_FMT" ssid:(%s,%d), from ie:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter),
+ ssid, ssid_len,
+ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength,
+ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength);
+
+ memcpy(pbss_network->Ssid.Ssid, (void *)ssid, ssid_len);
+ pbss_network->Ssid.SsidLength = ssid_len;
+ memcpy(pbss_network_ext->Ssid.Ssid, (void *)ssid, ssid_len);
+ pbss_network_ext->Ssid.SsidLength = ssid_len;
+
+ if (0)
+ RTW_INFO(FUNC_ADPT_FMT" after ssid:(%s,%d), (%s,%d)\n", FUNC_ADPT_ARG(adapter),
+ pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength,
+ pbss_network_ext->Ssid.Ssid, pbss_network_ext->Ssid.SsidLength);
+ }
+
+ RTW_INFO(FUNC_ADPT_FMT" ignore_broadcast_ssid:%d, %s,%d\n", FUNC_ADPT_ARG(adapter),
+ ignore_broadcast_ssid, ssid, ssid_len);
+
+ return ret;
+}
+
+#if CONFIG_RTW_MACADDR_ACL
+static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ ret = rtw_acl_remove_sta(padapter, param->sta_addr);
+
+ return ret;
+
+}
+
+static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
+ param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
+ param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff)
+ return -EINVAL;
+
+ ret = rtw_acl_add_sta(padapter, param->sta_addr);
+
+ return ret;
+
+}
+
+static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+ return -EINVAL;
+
+ rtw_set_macaddr_acl(padapter, param->u.mlme.command);
+
+ return ret;
+}
+#endif /* CONFIG_RTW_MACADDR_ACL */
+
+static int rtw_hostapd_ioctl(struct net_device *dev, struct iw_point *p)
+{
+ struct ieee_param *param;
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ /* RTW_INFO("%s\n", __func__); */
+
+ /*
+ * this function is expect to call in master mode, which allows no power saving
+ * so, we just check hw_init_completed
+ */
+
+ if (!rtw_is_hw_init_completed(padapter))
+ return -EPERM;
+
+ if (!p->pointer || p->length != sizeof(struct ieee_param))
+ return -EINVAL;
+
+ param = (struct ieee_param *)rtw_malloc(p->length);
+ if (param == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(param, p->pointer, p->length)) {
+ rtw_mfree((u8 *)param, p->length);
+ return -EFAULT;
+ }
+
+ switch (param->cmd) {
+ case RTL871X_HOSTAPD_FLUSH:
+
+ ret = rtw_hostapd_sta_flush(dev);
+
+ break;
+
+ case RTL871X_HOSTAPD_ADD_STA:
+
+ ret = rtw_add_sta(dev, param);
+
+ break;
+
+ case RTL871X_HOSTAPD_REMOVE_STA:
+
+ ret = rtw_del_sta(dev, param);
+
+ break;
+
+ case RTL871X_HOSTAPD_SET_BEACON:
+
+ ret = rtw_set_beacon(dev, param, p->length);
+
+ break;
+
+ case RTL871X_SET_ENCRYPTION:
+
+ ret = rtw_set_encryption(dev, param, p->length);
+
+ break;
+
+ case RTL871X_HOSTAPD_GET_WPAIE_STA:
+
+ ret = rtw_get_sta_wpaie(dev, param);
+
+ break;
+
+ case RTL871X_HOSTAPD_SET_WPS_BEACON:
+
+ ret = rtw_set_wps_beacon(dev, param, p->length);
+
+ break;
+
+ case RTL871X_HOSTAPD_SET_WPS_PROBE_RESP:
+
+ ret = rtw_set_wps_probe_resp(dev, param, p->length);
+
+ break;
+
+ case RTL871X_HOSTAPD_SET_WPS_ASSOC_RESP:
+
+ ret = rtw_set_wps_assoc_resp(dev, param, p->length);
+
+ break;
+
+ case RTL871X_HOSTAPD_SET_HIDDEN_SSID:
+
+ ret = rtw_set_hidden_ssid(dev, param, p->length);
+
+ break;
+
+ case RTL871X_HOSTAPD_GET_INFO_STA:
+
+ ret = rtw_ioctl_get_sta_data(dev, param, p->length);
+
+ break;
+
+#if CONFIG_RTW_MACADDR_ACL
+ case RTL871X_HOSTAPD_SET_MACADDR_ACL:
+ ret = rtw_ioctl_set_macaddr_acl(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_ACL_ADD_STA:
+ ret = rtw_ioctl_acl_add_sta(dev, param, p->length);
+ break;
+ case RTL871X_HOSTAPD_ACL_REMOVE_STA:
+ ret = rtw_ioctl_acl_remove_sta(dev, param, p->length);
+ break;
+#endif /* CONFIG_RTW_MACADDR_ACL */
+
+ default:
+ RTW_INFO("Unknown hostapd request: %d\n", param->cmd);
+ ret = -EOPNOTSUPP;
+ break;
+
+ }
+
+ if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+ ret = -EFAULT;
+
+
+ rtw_mfree((u8 *)param, p->length);
+
+ return ret;
+}
+#endif
+
+static int rtw_wx_set_priv(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *awrq,
+ char *extra)
+{
+
+#ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV
+ char *ext_dbg;
+#endif
+
+ int ret = 0;
+ int len = 0;
+ char *ext;
+ int i;
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_point *dwrq = (struct iw_point *)awrq;
+
+ if (dwrq->length == 0)
+ return -EFAULT;
+
+ len = dwrq->length;
+ ext = vmalloc(len);
+ if (!ext)
+ return -ENOMEM;
+
+ if (copy_from_user(ext, dwrq->pointer, len)) {
+ rtw_vmfree(ext, len);
+ return -EFAULT;
+ }
+
+
+
+#ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV
+ ext_dbg = vmalloc(len);
+ if (!ext_dbg) {
+ rtw_vmfree(ext, len);
+ return -ENOMEM;
+ }
+
+ memcpy(ext_dbg, ext, len);
+#endif
+
+ /* added for wps2.0 @20110524 */
+ if (dwrq->flags == 0x8766 && len > 8) {
+ u32 cp_sz;
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u8 *probereq_wpsie = ext;
+ int probereq_wpsie_len = len;
+ u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+ if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) &&
+ (!memcmp(&probereq_wpsie[2], wps_oui, 4) )) {
+ cp_sz = probereq_wpsie_len > MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN : probereq_wpsie_len;
+
+ if (pmlmepriv->wps_probe_req_ie) {
+ u32 free_len = pmlmepriv->wps_probe_req_ie_len;
+ pmlmepriv->wps_probe_req_ie_len = 0;
+ rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len);
+ pmlmepriv->wps_probe_req_ie = NULL;
+ }
+
+ pmlmepriv->wps_probe_req_ie = rtw_malloc(cp_sz);
+ if (pmlmepriv->wps_probe_req_ie == NULL) {
+ printk("%s()-%d: rtw_malloc() ERROR!\n", __func__, __LINE__);
+ ret = -EINVAL;
+ goto FREE_EXT;
+
+ }
+
+ memcpy(pmlmepriv->wps_probe_req_ie, probereq_wpsie, cp_sz);
+ pmlmepriv->wps_probe_req_ie_len = cp_sz;
+
+ }
+
+ goto FREE_EXT;
+
+ }
+
+ if (len >= WEXT_CSCAN_HEADER_SIZE
+ && !memcmp(ext, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)
+ ) {
+ ret = rtw_wx_set_scan(dev, info, awrq, ext);
+ goto FREE_EXT;
+ }
+
+#ifdef CONFIG_ANDROID
+ /* RTW_INFO("rtw_wx_set_priv: %s req=%s\n", dev->name, ext); */
+
+ i = rtw_android_cmdstr_to_num(ext);
+
+ switch (i) {
+ case ANDROID_WIFI_CMD_START:
+ indicate_wx_custom_event(padapter, "START");
+ break;
+ case ANDROID_WIFI_CMD_STOP:
+ indicate_wx_custom_event(padapter, "STOP");
+ break;
+ case ANDROID_WIFI_CMD_RSSI: {
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_network *pcur_network = &pmlmepriv->cur_network;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) )
+ sprintf(ext, "%s rssi %d", pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
+ else
+ sprintf(ext, "OK");
+ }
+ break;
+ case ANDROID_WIFI_CMD_LINKSPEED: {
+ u16 mbps = rtw_get_cur_max_rate(padapter) / 10;
+ sprintf(ext, "LINKSPEED %d", mbps);
+ }
+ break;
+ case ANDROID_WIFI_CMD_MACADDR:
+ sprintf(ext, "MACADDR = " MAC_FMT, MAC_ARG(dev->dev_addr));
+ break;
+ case ANDROID_WIFI_CMD_SCAN_ACTIVE: {
+ /* rtw_set_scan_mode(padapter, SCAN_ACTIVE); */
+ sprintf(ext, "OK");
+ }
+ break;
+ case ANDROID_WIFI_CMD_SCAN_PASSIVE: {
+ /* rtw_set_scan_mode(padapter, SCAN_PASSIVE); */
+ sprintf(ext, "OK");
+ }
+ break;
+
+ case ANDROID_WIFI_CMD_COUNTRY: {
+ char country_code[10];
+ sscanf(ext, "%*s %s", country_code);
+ rtw_set_country(padapter, country_code);
+ sprintf(ext, "OK");
+ }
+ break;
+ default:
+ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV
+ RTW_INFO("%s: %s unknowned req=%s\n", __func__,
+ dev->name, ext_dbg);
+ #endif
+
+ sprintf(ext, "OK");
+
+ }
+
+ if (copy_to_user(dwrq->pointer, ext, min(dwrq->length, (u16)(strlen(ext) + 1))))
+ ret = -EFAULT;
+
+#ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV
+ RTW_INFO("%s: %s req=%s rep=%s dwrq->length=%d, strlen(ext)+1=%d\n", __func__,
+ dev->name, ext_dbg , ext, dwrq->length, (u16)(strlen(ext) + 1));
+#endif
+#endif /* end of CONFIG_ANDROID */
+
+
+FREE_EXT:
+
+ rtw_vmfree(ext, len);
+ #ifdef CONFIG_DEBUG_RTW_WX_SET_PRIV
+ rtw_vmfree(ext_dbg, len);
+ #endif
+
+ /* RTW_INFO("rtw_wx_set_priv: (SIOCSIWPRIV) %s ret=%d\n", */
+ /* dev->name, ret); */
+
+ return ret;
+
+}
+#ifdef CONFIG_WOWLAN
+static int rtw_wowlan_ctrl(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wowlan_ioctl_param poidparam;
+ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sta_info *psta = NULL;
+ int ret = 0;
+ u32 start_time = jiffies;
+ poidparam.subcode = 0;
+
+ RTW_INFO("+rtw_wowlan_ctrl: %s\n", extra);
+
+ if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
+ check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+#ifdef CONFIG_PNO_SUPPORT
+ pwrctrlpriv->wowlan_pno_enable = true;
+#else
+ RTW_INFO("[%s] WARNING: Please Connect With AP First!!\n", __func__);
+ goto _rtw_wowlan_ctrl_exit_free;
+#endif /* CONFIG_PNO_SUPPORT */
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+ rtw_scan_abort(padapter);
+
+ if (!memcmp(extra, "enable", 6))
+
+
+ rtw_suspend_common(padapter);
+
+ else if (!memcmp(extra, "disable", 7)) {
+ RTW_ENABLE_FUNC(padapter, DF_RX_BIT);
+ RTW_ENABLE_FUNC(padapter, DF_TX_BIT);
+ rtw_resume_common(padapter);
+
+#ifdef CONFIG_PNO_SUPPORT
+ pwrctrlpriv->wowlan_pno_enable = false;
+#endif /* CONFIG_PNO_SUPPORT */
+
+ } else {
+ RTW_INFO("[%s] Invalid Parameter.\n", __func__);
+ goto _rtw_wowlan_ctrl_exit_free;
+ }
+ /* mutex_lock(&ioctl_mutex); */
+_rtw_wowlan_ctrl_exit_free:
+ RTW_INFO("-rtw_wowlan_ctrl( subcode = %d)\n", poidparam.subcode);
+ RTW_INFO("%s in %d ms\n", __func__,
+ rtw_get_passing_time_ms(start_time));
+_rtw_wowlan_ctrl_exit:
+ return ret;
+}
+
+/*
+ * IP filter This pattern if for a frame containing a ip packet:
+ * AA:AA:AA:AA:AA:AA:BB:BB:BB:BB:BB:BB:CC:CC:DD:-:-:-:-:-:-:-:-:EE:-:-:FF:FF:FF:FF:GG:GG:GG:GG:HH:HH:II:II
+ *
+ * A: Ethernet destination address
+ * B: Ethernet source address
+ * C: Ethernet protocol type
+ * D: IP header VER+Hlen, use: 0x45 (4 is for ver 4, 5 is for len 20)
+ * E: IP protocol
+ * F: IP source address ( 192.168.0.4: C0:A8:00:2C )
+ * G: IP destination address ( 192.168.0.4: C0:A8:00:2C )
+ * H: Source port (1024: 04:00)
+ * I: Destination port (1024: 04:00)
+ */
+
+static int rtw_wowlan_set_pattern(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct wowlan_ioctl_param poidparam;
+ int ret = 0, len = 0, i = 0;
+ u32 start_time = jiffies;
+ u8 input[wrqu->data.length];
+ u8 index = 0;
+
+ poidparam.subcode = 0;
+
+ if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
+ check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+ ret = -EFAULT;
+ RTW_INFO("Please Connect With AP First!!\n");
+ goto _rtw_wowlan_set_pattern_exit;
+ }
+
+ if (wrqu->data.length <= 0) {
+ ret = -EFAULT;
+ RTW_INFO("ERROR: parameter length <= 0\n");
+ goto _rtw_wowlan_set_pattern_exit;
+ } else {
+ /* set pattern */
+ if (copy_from_user(input,
+ wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+ /* leave PS first */
+ rtw_ps_deny(padapter, PS_DENY_IOCTL);
+ LeaveAllPowerSaveModeDirect(padapter);
+ if (strncmp(input, "pattern=", 8) == 0) {
+ if (pwrpriv->wowlan_pattern_idx >= MAX_WKFM_CAM_NUM) {
+ RTW_INFO("WARNING: priv-pattern is full(idx: %d)\n",
+ pwrpriv->wowlan_pattern_idx);
+ RTW_INFO("WARNING: please clean priv-pattern first\n");
+ ret = -EINVAL;
+ goto _rtw_wowlan_set_pattern_exit;
+ } else {
+ index = pwrpriv->wowlan_pattern_idx;
+ ret = rtw_wowlan_parser_pattern_cmd(input,
+ pwrpriv->patterns[index].content,
+ &pwrpriv->patterns[index].len,
+ pwrpriv->patterns[index].mask);
+
+ if (ret )
+ pwrpriv->wowlan_pattern_idx++;
+ }
+ } else if (strncmp(input, "clean", 5) == 0) {
+ poidparam.subcode = WOWLAN_PATTERN_CLEAN;
+ rtw_hal_set_hwreg(padapter,
+ HW_VAR_WOWLAN, (u8 *)&poidparam);
+ } else if (strncmp(input, "show", 4) == 0) {
+ rtw_wow_pattern_cam_dump(padapter);
+ rtw_wow_pattern_sw_dump(padapter);
+ } else {
+ RTW_INFO("ERROR: incorrect parameter!\n");
+ ret = -EINVAL;
+ }
+ rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL);
+ }
+_rtw_wowlan_set_pattern_exit:
+ return ret;
+}
+#endif /* CONFIG_WOWLAN */
+
+#ifdef CONFIG_AP_WOWLAN
+static int rtw_ap_wowlan_ctrl(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct wowlan_ioctl_param poidparam;
+ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sta_info *psta = NULL;
+ int ret = 0;
+ u32 start_time = jiffies;
+ poidparam.subcode = 0;
+
+ RTW_INFO("+rtw_ap_wowlan_ctrl: %s\n", extra);
+
+ if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ RTW_INFO("[%s] It is not AP mode!!\n", __func__);
+ goto _rtw_ap_wowlan_ctrl_exit_free;
+ }
+
+ if (!memcmp(extra, "enable", 6)) {
+
+ pwrctrlpriv->wowlan_ap_mode = true;
+
+ rtw_suspend_common(padapter);
+ } else if (!memcmp(extra, "disable", 7)) {
+ RTW_ENABLE_FUNC(padapter, DF_RX_BIT);
+ RTW_ENABLE_FUNC(padapter, DF_TX_BIT);
+ rtw_resume_common(padapter);
+ } else {
+ RTW_INFO("[%s] Invalid Parameter.\n", __func__);
+ goto _rtw_ap_wowlan_ctrl_exit_free;
+ }
+ /* mutex_lock(&ioctl_mutex); */
+_rtw_ap_wowlan_ctrl_exit_free:
+ RTW_INFO("-rtw_ap_wowlan_ctrl( subcode = %d)\n", poidparam.subcode);
+ RTW_INFO("%s in %d ms\n", __func__,
+ rtw_get_passing_time_ms(start_time));
+_rtw_ap_wowlan_ctrl_exit:
+ return ret;
+}
+#endif /* CONFIG_AP_WOWLAN */
+
+static int rtw_pm_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ unsigned mode = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_INFO("[%s] extra = %s\n", __func__, extra);
+
+ if (!memcmp(extra, "lps=", 4)) {
+ sscanf(extra + 4, "%u", &mode);
+ ret = rtw_pm_set_lps(padapter, mode);
+ } else if (!memcmp(extra, "ips=", 4)) {
+ sscanf(extra + 4, "%u", &mode);
+ ret = rtw_pm_set_ips(padapter, mode);
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE
+
+int rtw_vendor_ie_get_data(struct net_device *dev, int vendor_ie_num, char *extra)
+{
+ int j;
+ char *pstring;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u32 vendor_ie_mask = 0;
+ __u16 length = 0;
+
+ vendor_ie_mask = pmlmepriv->vendor_ie_mask[vendor_ie_num];
+ pstring = extra;
+ pstring += sprintf(pstring , "\nVendor IE num %d , Mask:%x " , vendor_ie_num , vendor_ie_mask);
+
+ if (vendor_ie_mask & WIFI_BEACON_VENDOR_IE_BIT)
+ pstring += sprintf(pstring , "[Beacon]");
+ if (vendor_ie_mask & WIFI_PROBEREQ_VENDOR_IE_BIT)
+ pstring += sprintf(pstring , "[Probe Req]");
+ if (vendor_ie_mask & WIFI_PROBERESP_VENDOR_IE_BIT)
+ pstring += sprintf(pstring , "[Probe Resp]");
+ if (vendor_ie_mask & WIFI_ASSOCREQ_VENDOR_IE_BIT)
+ pstring += sprintf(pstring , "[Assoc Req]");
+ if (vendor_ie_mask & WIFI_ASSOCRESP_VENDOR_IE_BIT)
+ pstring += sprintf(pstring , "[Assoc Resp]");
+
+ pstring += sprintf(pstring , "\nVendor IE:\n");
+ for (j = 0 ; j < pmlmepriv->vendor_ielen[vendor_ie_num] ; j++)
+ pstring += sprintf(pstring , "%02x" , pmlmepriv->vendor_ie[vendor_ie_num][j]);
+
+ length = pstring - extra;
+ return length;
+
+}
+
+int rtw_vendor_ie_get(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0, vendor_ie_num = 0, cmdlen;
+ struct iw_point *p;
+ u8 *ptmp;
+
+ p = &wrqu->data;
+ cmdlen = p->length;
+ if (0 == cmdlen)
+ return -EINVAL;
+
+ ptmp = (u8 *)rtw_malloc(cmdlen);
+ if (NULL == ptmp)
+ return -ENOMEM;
+
+ if (copy_from_user(ptmp, p->pointer, cmdlen)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ ret = sscanf(ptmp , "%d", &vendor_ie_num);
+ if (vendor_ie_num > WLAN_MAX_VENDOR_IE_NUM - 1) {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ wrqu->data.length = rtw_vendor_ie_get_data(dev, vendor_ie_num, extra);
+
+exit:
+ rtw_mfree(ptmp, cmdlen);
+
+ return 0;
+}
+
+int rtw_vendor_ie_set(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0, i , len = 0 , totoal_ie_len = 0 , total_ie_len_byte = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ u32 vendor_ie_mask = 0;
+ u32 vendor_ie_num = 0;
+ u32 id, elen;
+
+ ret = sscanf(extra, "%d,%x,%*s", &vendor_ie_num , &vendor_ie_mask);
+ if (strrchr(extra , ','))
+ extra = strrchr(extra , ',') + 1;
+ else
+ return -EINVAL;
+ totoal_ie_len = strlen(extra);
+ RTW_INFO("[%s] vendor_ie_num = %d , vendor_ie_mask = %x , vendor_ie = %s , len = %d\n", __func__ , vendor_ie_num , vendor_ie_mask , extra , totoal_ie_len);
+
+ if (vendor_ie_num > WLAN_MAX_VENDOR_IE_NUM - 1) {
+ RTW_INFO("[%s] only support %d vendor ie\n", __func__ , WLAN_MAX_VENDOR_IE_NUM);
+ return -EFAULT;
+ }
+
+ if (totoal_ie_len > WLAN_MAX_VENDOR_IE_LEN) {
+ RTW_INFO("[%s] Fail , not support ie length extend %d\n", __func__ , WLAN_MAX_VENDOR_IE_LEN);
+ return -EFAULT;
+ }
+
+ if (vendor_ie_mask == 0) {
+ RTW_INFO("[%s] Clear vendor_ie_num %d group\n", __func__ , vendor_ie_num);
+ goto _clear_path;
+ }
+
+ if (totoal_ie_len % 2 != 0) {
+ RTW_INFO("[%s] Fail , IE length = %zu is odd\n" , __func__ , strlen(extra));
+ return -EFAULT;
+ }
+
+ if (totoal_ie_len > 0) {
+ for (i = 0 ; i < strlen(extra) ; i += 2) {
+ pmlmepriv->vendor_ie[vendor_ie_num][len] = key_2char2num(extra[i] , extra[i + 1]);
+ if (len == 0) {
+ id = pmlmepriv->vendor_ie[vendor_ie_num][len];
+ if (id != WLAN_EID_VENDOR_SPECIFIC) {
+ RTW_INFO("[%s] Fail , VENDOR SPECIFIC IE ID \"%x\" was not correct\n", __func__ , id);
+ goto _clear_path;
+ }
+ } else if (len == 1) {
+ total_ie_len_byte = (totoal_ie_len / 2) - 2;
+ elen = pmlmepriv->vendor_ie[vendor_ie_num][len];
+ if (elen != total_ie_len_byte) {
+ RTW_INFO("[%s] Fail , Input IE length = \"%d\"(hex:%x) bytes , not match input total IE context length \"%d\" bytes\n", __func__ , elen , elen ,
+ total_ie_len_byte);
+ goto _clear_path;
+ }
+ }
+ len++;
+ }
+ pmlmepriv->vendor_ielen[vendor_ie_num] = len;
+ } else
+ pmlmepriv->vendor_ielen[vendor_ie_num] = 0;
+
+
+
+ if (vendor_ie_mask & WIFI_BEACON_VENDOR_IE_BIT)
+ RTW_INFO("[%s] Beacon append vendor ie\n", __func__);
+ if (vendor_ie_mask & WIFI_PROBEREQ_VENDOR_IE_BIT)
+ RTW_INFO("[%s] Probe Req append vendor ie\n", __func__);
+ if (vendor_ie_mask & WIFI_PROBERESP_VENDOR_IE_BIT)
+ RTW_INFO("[%s] Probe Resp append vendor ie\n", __func__);
+ if (vendor_ie_mask & WIFI_ASSOCREQ_VENDOR_IE_BIT)
+ RTW_INFO("[%s] Assoc Req append vendor ie\n", __func__);
+ if (vendor_ie_mask & WIFI_ASSOCRESP_VENDOR_IE_BIT)
+ RTW_INFO("[%s] Assoc Resp append vendor ie\n", __func__);
+
+ pmlmepriv->vendor_ie_mask[vendor_ie_num] = vendor_ie_mask;
+
+ return ret;
+
+_clear_path:
+ memset(pmlmepriv->vendor_ie[vendor_ie_num] , 0 , sizeof(u32) * WLAN_MAX_VENDOR_IE_LEN);
+ pmlmepriv->vendor_ielen[vendor_ie_num] = 0;
+ pmlmepriv->vendor_ie_mask[vendor_ie_num] = 0;
+ return -EFAULT;
+}
+#endif
+
+static int rtw_mp_efuse_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+
+ PEFUSE_HAL pEfuseHal;
+ struct iw_point *wrqu;
+
+ u8 *PROMContent = pHalData->efuse_eeprom_data;
+ u8 ips_mode = IPS_NUM; /* init invalid value */
+ u8 lps_mode = PS_MODE_NUM; /* init invalid value */
+ struct pwrctrl_priv *pwrctrlpriv ;
+ u8 *data = NULL;
+ u8 *rawdata = NULL;
+ char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL};
+ u16 i = 0, j = 0, mapLen = 0, addr = 0, cnts = 0;
+ u16 max_available_len = 0, raw_cursize = 0, raw_maxsize = 0;
+ u16 mask_len;
+ u8 mask_buf[64] = "";
+ int err;
+#ifdef CONFIG_IOL
+ u8 org_fw_iol = padapter->registrypriv.fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */
+#endif
+
+ wrqu = (struct iw_point *)wdata;
+ pwrctrlpriv = adapter_to_pwrctl(padapter);
+ pEfuseHal = &pHalData->EfuseHal;
+
+ err = 0;
+ data = rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
+ if (data == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ rawdata = rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
+ if (rawdata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length)) {
+ err = -EFAULT;
+ goto exit;
+ }
+#ifdef CONFIG_LPS
+ lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+#endif
+
+#ifdef CONFIG_IPS
+ ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
+ rtw_pm_set_ips(padapter, IPS_NONE);
+#endif
+
+ pch = extra;
+ RTW_INFO("%s: in=%s\n", __func__, extra);
+
+ i = 0;
+ /* mac 16 "00e04c871200" rmap,00,2 */
+ while ((token = strsep(&pch, ",")) != NULL) {
+ if (i > 2)
+ break;
+ tmp[i] = token;
+ i++;
+ }
+#ifdef CONFIG_IOL
+ padapter->registrypriv.fw_iol = 0;/* 0:Disable, 1:enable, 2:by usb speed */
+#endif
+
+ if (strcmp(tmp[0], "status") == 0) {
+ sprintf(extra, "Load File efuse=%s,Load File MAC=%s"
+ , pHalData->efuse_file_status == EFUSE_FILE_FAILED ? "FAIL" : "OK"
+ , pHalData->macaddr_file_status == MACADDR_FILE_FAILED ? "FAIL" : "OK"
+ );
+ goto exit;
+ } else if (strcmp(tmp[0], "drvmap") == 0) {
+ static u8 drvmaporder = 0;
+ u8 *efuse;
+ u32 shift, cnt;
+ u32 blksz = 0x200; /* The size of one time show, default 512 */
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false);
+
+ efuse = pHalData->efuse_eeprom_data;
+
+ shift = blksz * drvmaporder;
+ efuse += shift;
+ cnt = mapLen - shift;
+
+ if (cnt > blksz) {
+ cnt = blksz;
+ drvmaporder++;
+ } else
+ drvmaporder = 0;
+
+ sprintf(extra, "\n");
+ for (i = 0; i < cnt; i += 16) {
+ sprintf(extra + strlen(extra), "0x%02x\t", shift + i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra + strlen(extra), "%02X ", efuse[i + j]);
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++)
+ sprintf(extra + strlen(extra), "%02X ", efuse[i + j]);
+ sprintf(extra + strlen(extra), "\n");
+ }
+ if ((shift + cnt) < mapLen)
+ sprintf(extra + strlen(extra), "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);
+
+ } else if (strcmp(tmp[0], "realmap") == 0) {
+ static u8 order = 0;
+ u8 *efuse;
+ u32 shift, cnt;
+ u32 blksz = 0x200; /* The size of one time show, default 512 */
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&mapLen, false);
+ efuse = pEfuseHal->fakeEfuseInitMap;
+ if (rtw_efuse_mask_map_read(padapter, 0, mapLen, efuse) == _FAIL) {
+ RTW_INFO("%s: read realmap Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ shift = blksz * order;
+ efuse += shift;
+ cnt = mapLen - shift;
+ if (cnt > blksz) {
+ cnt = blksz;
+ order++;
+ } else
+ order = 0;
+
+ sprintf(extra, "\n");
+ for (i = 0; i < cnt; i += 16) {
+ sprintf(extra + strlen(extra), "0x%02x\t", shift + i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra + strlen(extra), "%02X ", efuse[i + j]);
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++)
+ sprintf(extra + strlen(extra), "%02X ", efuse[i + j]);
+ sprintf(extra + strlen(extra), "\n");
+ }
+ if ((shift + cnt) < mapLen)
+ sprintf(extra + strlen(extra), "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);
+ } else if (strcmp(tmp[0], "rmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ RTW_INFO("%s: rmap Fail!! Parameters error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* rmap addr cnts */
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ RTW_INFO("%s: addr=%x\n", __func__, addr);
+
+ cnts = simple_strtoul(tmp[2], &ptmp, 10);
+ if (cnts == 0) {
+ RTW_INFO("%s: rmap Fail!! cnts error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&max_available_len, false);
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (rtw_efuse_mask_map_read(padapter, addr, cnts, data) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_mask_map_read error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* RTW_INFO("%s: data={", __func__); */
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ /* RTW_INFO("0x%02x ", data[i]); */
+ sprintf(extra + strlen(extra), "0x%02X ", data[i]);
+ }
+ /* RTW_INFO("}\n"); */
+ } else if (strcmp(tmp[0], "realraw") == 0) {
+ static u8 raw_order = 0;
+ u32 shift, cnt;
+ u32 blksz = 0x200; /* The size of one time show, default 512 */
+
+ addr = 0;
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN , (void *)&mapLen, false);
+ RTW_INFO("Real content len = %d\n",mapLen );
+
+ if (rtw_efuse_access(padapter, false, addr, mapLen, rawdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ memset(extra, '\0', strlen(extra));
+
+ shift = blksz * raw_order;
+ rawdata += shift;
+ cnt = mapLen - shift;
+ if (cnt > blksz) {
+ cnt = blksz;
+ raw_order++;
+ } else
+ raw_order = 0;
+
+ sprintf(extra, "\n");
+ for (i = 0; i < cnt; i += 16) {
+ sprintf(extra + strlen(extra), "0x%02x\t", shift + i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra + strlen(extra), "%02X ", rawdata[i + j]);
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++)
+ sprintf(extra + strlen(extra), "%02X ", rawdata[i + j]);
+ sprintf(extra + strlen(extra), "\n");
+ }
+ if ((shift + cnt) < mapLen)
+ sprintf(extra + strlen(extra), "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);
+
+ } else if (strcmp(tmp[0], "btrealraw") == 0) {
+ static u8 bt_raw_order = 0;
+ u32 shift, cnt;
+ u32 blksz = 0x200; /* The size of one time show, default 512 */
+
+ addr = 0;
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&mapLen, false);
+ RTW_INFO("Real content len = %d\n", mapLen);
+#ifdef RTW_HALMAC
+ if (rtw_efuse_bt_access(padapter, false, 0, mapLen, rawdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+#else
+ rtw_write8(padapter, 0x35, 0x1);
+
+ if (rtw_efuse_access(padapter, false, addr, mapLen, rawdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+#endif
+ memset(extra, '\0', strlen(extra));
+
+ shift = blksz * bt_raw_order;
+ rawdata += shift;
+ cnt = mapLen - shift;
+ if (cnt > blksz) {
+ cnt = blksz;
+ bt_raw_order++;
+ } else
+ bt_raw_order = 0;
+
+ sprintf(extra, "\n");
+ for (i = 0; i < cnt; i += 16) {
+ sprintf(extra + strlen(extra), "0x%02x\t", shift + i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra + strlen(extra), "%02X ", rawdata[i + j]);
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++)
+ sprintf(extra + strlen(extra), "%02X ", rawdata[i + j]);
+ sprintf(extra + strlen(extra), "\n");
+ }
+ if ((shift + cnt) < mapLen)
+ sprintf(extra + strlen(extra), "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);
+
+ } else if (strcmp(tmp[0], "mac") == 0) {
+ if (hal_efuse_macaddr_offset(padapter) == -1) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ addr = hal_efuse_macaddr_offset(padapter);
+ cnts = 6;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_mask_map_read(padapter, addr, cnts, data) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_mask_map_read error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* RTW_INFO("%s: MAC address={", __func__); */
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ /* RTW_INFO("%02X", data[i]); */
+ sprintf(extra + strlen(extra), "%02X", data[i]);
+ if (i != (cnts - 1)) {
+ /* RTW_INFO(":"); */
+ sprintf(extra + strlen(extra), ":");
+ }
+ }
+ /* RTW_INFO("}\n"); */
+ } else if (strcmp(tmp[0], "vidpid") == 0) {
+ addr = EEPROM_VID_88EU;
+ cnts = 4;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%02x)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+ if (rtw_efuse_mask_map_read(padapter, addr, cnts, data) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* RTW_INFO("%s: {VID,PID}={", __func__); */
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ /* RTW_INFO("0x%02x", data[i]); */
+ sprintf(extra + strlen(extra), "0x%02X", data[i]);
+ if (i != (cnts - 1)) {
+ /* RTW_INFO(","); */
+ sprintf(extra + strlen(extra), ",");
+ }
+ }
+ /* RTW_INFO("}\n"); */
+ } else if (strcmp(tmp[0], "ableraw") == 0) {
+#ifdef RTW_HALMAC
+ raw_maxsize = efuse_GetavailableSize(padapter);
+#else
+ efuse_GetCurrentSize(padapter, &raw_cursize);
+ raw_maxsize = efuse_GetMaxSize(padapter);
+#endif
+ sprintf(extra, "[available raw size]= %d bytes\n", raw_maxsize - raw_cursize);
+ } else if (strcmp(tmp[0], "btableraw") == 0) {
+ efuse_bt_GetCurrentSize(padapter, &raw_cursize);
+ raw_maxsize = efuse_bt_GetMaxSize(padapter);
+ sprintf(extra, "[available raw size]= %d bytes\n", raw_maxsize - raw_cursize);
+ } else if (strcmp(tmp[0], "btfmap") == 0) {
+
+ BTEfuse_PowerSwitch(padapter, 1, true);
+
+ mapLen = EFUSE_BT_MAX_MAP_LEN;
+ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) {
+ RTW_INFO("%s: rtw_BT_efuse_map_read Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* RTW_INFO("OFFSET\tVALUE(hex)\n"); */
+ sprintf(extra, "\n");
+ for (i = 0; i < 512; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */
+ /* RTW_INFO("0x%03x\t", i); */
+ sprintf(extra + strlen(extra), "0x%03x\t", i);
+ for (j = 0; j < 8; j++) {
+ /* RTW_INFO("%02X ", pEfuseHal->BTEfuseInitMap[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]);
+ }
+ /* RTW_INFO("\t"); */
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++) {
+ /* RTW_INFO("%02X ", pEfuseHal->BTEfuseInitMap[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]);
+ }
+ /* RTW_INFO("\n"); */
+ sprintf(extra + strlen(extra), "\n");
+ }
+ /* RTW_INFO("\n"); */
+ } else if (strcmp(tmp[0], "btbmap") == 0) {
+ BTEfuse_PowerSwitch(padapter, 1, true);
+
+ mapLen = EFUSE_BT_MAX_MAP_LEN;
+ if (rtw_BT_efuse_map_read(padapter, 0, mapLen, pEfuseHal->BTEfuseInitMap) == _FAIL) {
+ RTW_INFO("%s: rtw_BT_efuse_map_read Fail!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ /* RTW_INFO("OFFSET\tVALUE(hex)\n"); */
+ sprintf(extra, "\n");
+ for (i = 512; i < 1024 ; i += 16) {
+ /* RTW_INFO("0x%03x\t", i); */
+ sprintf(extra + strlen(extra), "0x%03x\t", i);
+ for (j = 0; j < 8; j++) {
+ /* RTW_INFO("%02X ", data[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]);
+ }
+ /* RTW_INFO("\t"); */
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++) {
+ /* RTW_INFO("%02X ", data[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->BTEfuseInitMap[i + j]);
+ }
+ /* RTW_INFO("\n"); */
+ sprintf(extra + strlen(extra), "\n");
+ }
+ /* RTW_INFO("\n"); */
+ } else if (strcmp(tmp[0], "btrmap") == 0) {
+ u8 BTStatus;
+
+ rtw_write8(padapter, 0xa3, 0x05); /* For 8723AB ,8821S ? */
+ BTStatus = rtw_read8(padapter, 0xa0);
+
+ RTW_INFO("%s: Check 0xa0 BT Status =0x%x\n", __func__, BTStatus);
+ if (BTStatus != 0x04) {
+ sprintf(extra, "BT Status not Active ,can't to read BT eFuse\n");
+ goto exit;
+ }
+
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ BTEfuse_PowerSwitch(padapter, 1, true);
+
+ /* rmap addr cnts */
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+
+ cnts = simple_strtoul(tmp[2], &ptmp, 10);
+ if (cnts == 0) {
+ RTW_INFO("%s: btrmap Fail!! cnts error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+#ifndef RTW_HALMAC
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+#endif
+ if (rtw_BT_efuse_map_read(padapter, addr, cnts, data) == _FAIL) {
+ RTW_INFO("%s: rtw_BT_efuse_map_read error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ *extra = 0;
+ /* RTW_INFO("%s: bt efuse data={", __func__); */
+ for (i = 0; i < cnts; i++) {
+ /* RTW_INFO("0x%02x ", data[i]); */
+ sprintf(extra + strlen(extra), " 0x%02X ", data[i]);
+ }
+ /* RTW_INFO("}\n"); */
+ RTW_INFO(FUNC_ADPT_FMT ": BT MAC=[%s]\n", FUNC_ADPT_ARG(padapter), extra);
+ } else if (strcmp(tmp[0], "btffake") == 0) {
+ /* RTW_INFO("OFFSET\tVALUE(hex)\n"); */
+ sprintf(extra, "\n");
+ for (i = 0; i < 512; i += 16) {
+ /* RTW_INFO("0x%03x\t", i); */
+ sprintf(extra + strlen(extra), "0x%03x\t", i);
+ for (j = 0; j < 8; j++) {
+ /* RTW_INFO("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]);
+ }
+ /* RTW_INFO("\t"); */
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++) {
+ /* RTW_INFO("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]);
+ }
+ /* RTW_INFO("\n"); */
+ sprintf(extra + strlen(extra), "\n");
+ }
+ /* RTW_INFO("\n"); */
+ } else if (strcmp(tmp[0], "btbfake") == 0) {
+ /* RTW_INFO("OFFSET\tVALUE(hex)\n"); */
+ sprintf(extra, "\n");
+ for (i = 512; i < 1024; i += 16) {
+ /* RTW_INFO("0x%03x\t", i); */
+ sprintf(extra + strlen(extra), "0x%03x\t", i);
+ for (j = 0; j < 8; j++) {
+ /* RTW_INFO("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]);
+ }
+ /* RTW_INFO("\t"); */
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++) {
+ /* RTW_INFO("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i+j]); */
+ sprintf(extra + strlen(extra), "%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]);
+ }
+ /* RTW_INFO("\n"); */
+ sprintf(extra + strlen(extra), "\n");
+ }
+ /* RTW_INFO("\n"); */
+ } else if (strcmp(tmp[0], "wlrfkmap") == 0) {
+ static u8 fk_order = 0;
+ u8 *efuse;
+ u32 shift, cnt;
+ u32 blksz = 0x200; /* The size of one time show, default 512 */
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&mapLen, false);
+ efuse = pEfuseHal->fakeEfuseModifiedMap;
+
+ shift = blksz * fk_order;
+ efuse += shift;
+ cnt = mapLen - shift;
+ if (cnt > blksz) {
+ cnt = blksz;
+ fk_order++;
+ } else
+ fk_order = 0;
+
+ sprintf(extra, "\n");
+ for (i = 0; i < cnt; i += 16) {
+ sprintf(extra + strlen(extra), "0x%02x\t", shift + i);
+ for (j = 0; j < 8; j++)
+ sprintf(extra + strlen(extra), "%02X ", efuse[i + j]);
+ sprintf(extra + strlen(extra), "\t");
+ for (; j < 16; j++)
+ sprintf(extra + strlen(extra), "%02X ", efuse[i + j]);
+ sprintf(extra + strlen(extra), "\n");
+ }
+ if ((shift + cnt) < mapLen)
+ sprintf(extra + strlen(extra), "\t...more\n");
+
+ } else if (strcmp(tmp[0], "wlrfkrmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ RTW_INFO("%s: rmap Fail!! Parameters error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ /* rmap addr cnts */
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ RTW_INFO("%s: addr=%x\n", __func__, addr);
+
+ cnts = simple_strtoul(tmp[2], &ptmp, 10);
+ if (cnts == 0) {
+ RTW_INFO("%s: rmap Fail!! cnts error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+
+ /* RTW_INFO("%s: data={", __func__); */
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ RTW_INFO("wlrfkrmap = 0x%02x\n", pEfuseHal->fakeEfuseModifiedMap[addr + i]);
+ sprintf(extra + strlen(extra), "0x%02X ", pEfuseHal->fakeEfuseModifiedMap[addr + i]);
+ }
+ } else if (strcmp(tmp[0], "btrfkrmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ RTW_INFO("%s: rmap Fail!! Parameters error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ /* rmap addr cnts */
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ RTW_INFO("%s: addr=%x\n", __func__, addr);
+
+ cnts = simple_strtoul(tmp[2], &ptmp, 10);
+ if (cnts == 0) {
+ RTW_INFO("%s: rmap Fail!! cnts error!\n", __func__);
+ err = -EINVAL;
+ goto exit;
+ }
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+
+ /* RTW_INFO("%s: data={", __func__); */
+ *extra = 0;
+ for (i = 0; i < cnts; i++) {
+ RTW_INFO("wlrfkrmap = 0x%02x\n", pEfuseHal->fakeBTEfuseModifiedMap[addr + i]);
+ sprintf(extra + strlen(extra), "0x%02X ", pEfuseHal->fakeBTEfuseModifiedMap[addr + i]);
+ }
+ } else if (strcmp(tmp[0], "mask") == 0) {
+ *extra = 0;
+ mask_len = sizeof(u8) * rtw_get_efuse_mask_arraylen(padapter);
+ rtw_efuse_mask_array(padapter, mask_buf);
+
+ if (padapter->registrypriv.bFileMaskEfuse )
+ memcpy(mask_buf, maskfileBuffer, mask_len);
+
+ sprintf(extra, "\n");
+ for (i = 0; i < mask_len; i++)
+ sprintf(extra + strlen(extra), "0x%02X\n", mask_buf[i]);
+
+ } else
+ sprintf(extra, "Command not found!");
+
+exit:
+ if (data)
+ rtw_mfree(data, EFUSE_BT_MAX_MAP_LEN);
+ if (rawdata)
+ rtw_mfree(rawdata, EFUSE_BT_MAX_MAP_LEN);
+ if (!err)
+ wrqu->length = strlen(extra);
+
+ if (padapter->registrypriv.mp_mode == 0) {
+#ifdef CONFIG_IPS
+ rtw_pm_set_ips(padapter, ips_mode);
+#endif /* CONFIG_IPS */
+
+#ifdef CONFIG_LPS
+ rtw_pm_set_lps(padapter, lps_mode);
+#endif /* CONFIG_LPS */
+ }
+
+#ifdef CONFIG_IOL
+ padapter->registrypriv.fw_iol = org_fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */
+#endif
+ return err;
+}
+
+static int rtw_mp_efuse_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct iw_point *wrqu;
+ PADAPTER padapter;
+ struct pwrctrl_priv *pwrctrlpriv ;
+ PHAL_DATA_TYPE pHalData;
+ PEFUSE_HAL pEfuseHal;
+ struct hal_ops *pHalFunc;
+ struct mp_priv *pmp_priv;
+
+ u8 ips_mode = IPS_NUM; /* init invalid value */
+ u8 lps_mode = PS_MODE_NUM; /* init invalid value */
+ u32 i = 0, j = 0, jj, kk;
+ u8 *setdata = NULL;
+ u8 *ShadowMapBT = NULL;
+ u8 *ShadowMapWiFi = NULL;
+ u8 *setrawdata = NULL;
+ char *pch, *ptmp, *token, *tmp[3] = {NULL, NULL, NULL};
+ u16 addr = 0xFF, cnts = 0, BTStatus = 0 , max_available_len = 0;
+ u16 wifimaplen;
+ int err;
+
+ wrqu = (struct iw_point *)wdata;
+ padapter = rtw_netdev_priv(dev);
+ pwrctrlpriv = adapter_to_pwrctl(padapter);
+ pHalData = GET_HAL_DATA(padapter);
+ pEfuseHal = &pHalData->EfuseHal;
+ pHalFunc = &padapter->hal_func;
+ pmp_priv = &padapter->mppriv;
+
+ err = 0;
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&wifimaplen, false);
+
+ setdata = rtw_zmalloc(1024);
+ if (setdata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ ShadowMapBT = rtw_malloc(EFUSE_BT_MAX_MAP_LEN);
+ if (ShadowMapBT == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ ShadowMapWiFi = rtw_malloc(wifimaplen);
+ if (ShadowMapWiFi == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ setrawdata = rtw_malloc(EFUSE_MAX_SIZE);
+ if (setrawdata == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+#ifdef CONFIG_LPS
+ lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+#endif
+
+#ifdef CONFIG_IPS
+ ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
+ rtw_pm_set_ips(padapter, IPS_NONE);
+#endif
+
+ pch = extra;
+ RTW_INFO("%s: in=%s\n", __func__, extra);
+
+ i = 0;
+ while ((token = strsep(&pch, ",")) != NULL) {
+ if (i > 2)
+ break;
+ tmp[i] = token;
+ i++;
+ }
+
+ /* tmp[0],[1],[2] */
+ /* wmap,addr,00e04c871200 */
+ if (strcmp(tmp[0], "wmap") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+#ifndef RTW_HALMAC
+ /* unknown bug workaround, need to fix later */
+ addr = 0x1ff;
+ rtw_write8(padapter, EFUSE_CTRL + 1, (addr & 0xff));
+ rtw_msleep_os(10);
+ rtw_write8(padapter, EFUSE_CTRL + 2, ((addr >> 8) & 0x03));
+ rtw_msleep_os(10);
+ rtw_write8(padapter, EFUSE_CTRL + 3, 0x72);
+ rtw_msleep_os(10);
+ rtw_read8(padapter, EFUSE_CTRL);
+#endif /* RTW_HALMAC */
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: map data=%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ *extra = 0;
+ RTW_INFO("%s: after rtw_efuse_map_write to !memcmp\n", __func__);
+ if (rtw_efuse_mask_map_read(padapter, addr, cnts, ShadowMapWiFi) == _SUCCESS) {
+ if (!memcmp((void *)ShadowMapWiFi , (void *)setdata, cnts)) {
+ RTW_INFO("%s: WiFi write map afterf compare success\n", __func__);
+ sprintf(extra, "WiFi write map compare OK\n");
+ err = 0;
+ goto exit;
+ } else {
+ sprintf(extra, "WiFi write map compare FAIL\n");
+ RTW_INFO("%s: WiFi write map compare Fail\n", __func__);
+ err = 0;
+ goto exit;
+ }
+ }
+ } else if (strcmp(tmp[0], "wraw") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: raw data=%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setrawdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+
+ if (rtw_efuse_access(padapter, true, addr, cnts, setrawdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "btwraw") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: raw data=%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setrawdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+#ifdef RTW_HALMAC
+ if (rtw_efuse_bt_access(padapter, true, addr, cnts, setrawdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+#else
+ rtw_write8(padapter, 0x35, 1); /* switch bank 1 (BT)*/
+ if (rtw_efuse_access(padapter, true, addr, cnts, setrawdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_access error!!\n", __func__);
+ rtw_write8(padapter, 0x35, 0); /* switch bank 0 (WiFi)*/
+ err = -EFAULT;
+ goto exit;
+ }
+ rtw_write8(padapter, 0x35, 0); /* switch bank 0 (WiFi)*/
+#endif
+ } else if (strcmp(tmp[0], "mac") == 0) {
+ if (tmp[1] == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* mac,00e04c871200 */
+
+ if (hal_efuse_macaddr_offset(padapter) == -1) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ addr = hal_efuse_macaddr_offset(padapter);
+ cnts = strlen(tmp[1]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (cnts > 6) {
+ RTW_INFO("%s: error data for mac addr=\"%s\"\n", __func__, tmp[1]);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: MAC address=%s\n", __func__, tmp[1]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "vidpid") == 0) {
+ if (tmp[1] == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* pidvid,da0b7881 */
+ addr = EEPROM_VID_88EU;
+ cnts = strlen(tmp[1]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: VID/PID=%s\n", __func__, tmp[1]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ } else if (strcmp(tmp[0], "wldumpfake") == 0) {
+ if (wifimaplen > EFUSE_MAX_MAP_LEN)
+ cnts = EFUSE_MAX_MAP_LEN;
+ else
+ cnts = wifimaplen;
+ if (rtw_efuse_mask_map_read(padapter, 0, cnts, pEfuseHal->fakeEfuseModifiedMap) == _SUCCESS)
+ RTW_INFO("%s: WiFi hw efuse dump to Fake map success\n", __func__);
+ else {
+ RTW_INFO("%s: WiFi hw efuse dump to Fake map Fail\n", __func__);
+ err = -EFAULT;
+ }
+ } else if (strcmp(tmp[0], "btwmap") == 0) {
+ rtw_write8(padapter, 0xa3, 0x05); /* For 8723AB ,8821S ? */
+ BTStatus = rtw_read8(padapter, 0xa0);
+ RTW_INFO("%s: btwmap before read 0xa0 BT Status =0x%x\n", __func__, BTStatus);
+ if (BTStatus != 0x04) {
+ sprintf(extra, "BT Status not Active ,can't do Write\n");
+ goto exit;
+ }
+
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+#ifndef RTW_HALMAC
+ BTEfuse_PowerSwitch(padapter, 1, true);
+ addr = 0x1ff;
+ rtw_write8(padapter, EFUSE_CTRL + 1, (addr & 0xff));
+ rtw_msleep_os(10);
+ rtw_write8(padapter, EFUSE_CTRL + 2, ((addr >> 8) & 0x03));
+ rtw_msleep_os(10);
+ rtw_write8(padapter, EFUSE_CTRL + 3, 0x72);
+ rtw_msleep_os(10);
+ rtw_read8(padapter, EFUSE_CTRL);
+ BTEfuse_PowerSwitch(padapter, 1, false);
+#endif /* RTW_HALMAC */
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: BT data=%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+#ifndef RTW_HALMAC
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&max_available_len, false);
+ if ((addr + cnts) > max_available_len) {
+ RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __func__, addr, cnts);
+ err = -EFAULT;
+ goto exit;
+ }
+#endif
+ if (rtw_BT_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
+ RTW_INFO("%s: rtw_BT_efuse_map_write error!!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+ *extra = 0;
+ RTW_INFO("%s: after rtw_BT_efuse_map_write to !memcmp\n", __func__);
+ if ((rtw_BT_efuse_map_read(padapter, addr, cnts, ShadowMapBT) == _SUCCESS)) {
+ if (!memcmp((void *)ShadowMapBT , (void *)setdata, cnts)) {
+ RTW_INFO("%s: BT write map compare OK BTStatus=0x%x\n", __func__, BTStatus);
+ sprintf(extra, "BT write map compare OK");
+ err = 0;
+ goto exit;
+ } else {
+ sprintf(extra, "BT write map compare FAIL");
+ RTW_INFO("%s: BT write map compare FAIL BTStatus=0x%x\n", __func__, BTStatus);
+ err = 0;
+ goto exit;
+ }
+ }
+ } else if (strcmp(tmp[0], "btwfake") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: BT tmp data=%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ pEfuseHal->fakeBTEfuseModifiedMap[addr + jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+ } else if (strcmp(tmp[0], "btdumpfake") == 0) {
+ if (rtw_BT_efuse_map_read(padapter, 0, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _SUCCESS)
+ RTW_INFO("%s: BT read all map success\n", __func__);
+ else {
+ RTW_INFO("%s: BT read all map Fail!\n", __func__);
+ err = -EFAULT;
+ }
+ } else if (strcmp(tmp[0], "btfk2map") == 0) {
+ rtw_write8(padapter, 0xa3, 0x05);
+ BTStatus = rtw_read8(padapter, 0xa0);
+ RTW_INFO("%s: btwmap before read 0xa0 BT Status =0x%x\n", __func__, BTStatus);
+ if (BTStatus != 0x04) {
+ sprintf(extra, "BT Status not Active Write FAIL\n");
+ goto exit;
+ }
+#ifndef RTW_HALMAC
+ BTEfuse_PowerSwitch(padapter, 1, true);
+ addr = 0x1ff;
+ rtw_write8(padapter, EFUSE_CTRL + 1, (addr & 0xff));
+ rtw_msleep_os(10);
+ rtw_write8(padapter, EFUSE_CTRL + 2, ((addr >> 8) & 0x03));
+ rtw_msleep_os(10);
+ rtw_write8(padapter, EFUSE_CTRL + 3, 0x72);
+ rtw_msleep_os(10);
+ rtw_read8(padapter, EFUSE_CTRL);
+ BTEfuse_PowerSwitch(padapter, 1, false);
+#endif /* RTW_HALMAC */
+ memcpy(pEfuseHal->BTEfuseModifiedMap, pEfuseHal->fakeBTEfuseModifiedMap, EFUSE_BT_MAX_MAP_LEN);
+
+ if (rtw_BT_efuse_map_write(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _FAIL) {
+ RTW_INFO("%s: rtw_BT_efuse_map_write error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ RTW_INFO("pEfuseHal->fakeBTEfuseModifiedMap OFFSET\tVALUE(hex)\n");
+ for (i = 0; i < EFUSE_BT_MAX_MAP_LEN; i += 16) {
+ printk("0x%02x\t", i);
+ for (j = 0; j < 8; j++)
+ printk("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]);
+ printk("\t");
+
+ for (; j < 16; j++)
+ printk("%02X ", pEfuseHal->fakeBTEfuseModifiedMap[i + j]);
+ printk("\n");
+ }
+ printk("\n");
+ err = -EFAULT;
+ RTW_INFO("%s: rtw_BT_efuse_map_read !memcmp\n", __func__);
+ if ((rtw_BT_efuse_map_read(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseInitMap) == _SUCCESS)) {
+ if (!memcmp((void *)pEfuseHal->fakeBTEfuseModifiedMap, (void *)pEfuseHal->fakeBTEfuseInitMap, EFUSE_BT_MAX_MAP_LEN)) {
+ sprintf(extra, "BT write map compare OK");
+ RTW_INFO("%s: BT write map afterf compare success BTStatus=0x%x\n", __func__, BTStatus);
+ err = 0;
+ goto exit;
+ } else {
+ sprintf(extra, "BT write map compare FAIL");
+ if (rtw_BT_efuse_map_write(padapter, 0x00, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseModifiedMap) == _FAIL)
+ RTW_INFO("%s: rtw_BT_efuse_map_write compare error,retry = %d!\n", __func__, i);
+
+ if (rtw_BT_efuse_map_read(padapter, EFUSE_BT, EFUSE_BT_MAX_MAP_LEN, pEfuseHal->fakeBTEfuseInitMap) == _SUCCESS) {
+ RTW_INFO("pEfuseHal->fakeBTEfuseInitMap OFFSET\tVALUE(hex)\n");
+
+ for (i = 0; i < EFUSE_BT_MAX_MAP_LEN; i += 16) {
+ printk("0x%02x\t", i);
+ for (j = 0; j < 8; j++)
+ printk("%02X ", pEfuseHal->fakeBTEfuseInitMap[i + j]);
+ printk("\t");
+ for (; j < 16; j++)
+ printk("%02X ", pEfuseHal->fakeBTEfuseInitMap[i + j]);
+ printk("\n");
+ }
+ printk("\n");
+ }
+ RTW_INFO("%s: BT write map afterf compare not match to write efuse try write Map again , BTStatus=0x%x\n", __func__, BTStatus);
+ goto exit;
+ }
+ }
+ } else if (strcmp(tmp[0], "wlfk2map") == 0) {
+ *extra = 0;
+
+ if (padapter->registrypriv.bFileMaskEfuse != true && pmp_priv->bloadefusemap ) {
+ RTW_INFO("%s: File eFuse mask file not to be loaded\n", __func__);
+ sprintf(extra, "Not load eFuse mask file yet, Please use the efuse_mask CMD.\n");
+ err = 0;
+ goto exit;
+ }
+
+ if (wifimaplen > EFUSE_MAX_MAP_LEN)
+ cnts = EFUSE_MAX_MAP_LEN;
+ else
+ cnts = wifimaplen;
+ if (rtw_efuse_map_write(padapter, 0x00, cnts, pEfuseHal->fakeEfuseModifiedMap) == _FAIL) {
+ RTW_INFO("%s: rtw_efuse_map_write fakeEfuseModifiedMap error!\n", __func__);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (rtw_efuse_mask_map_read(padapter, 0x00, wifimaplen, ShadowMapWiFi) == _SUCCESS) {
+ if (!memcmp((void *)ShadowMapWiFi , (void *)pEfuseHal->fakeEfuseModifiedMap, cnts)) {
+ RTW_INFO("%s: WiFi write map afterf compare OK\n", __func__);
+ sprintf(extra, "WiFi write map compare OK\n");
+ err = 0;
+ goto exit;
+ } else {
+ sprintf(extra, "WiFi write map compare FAIL\n");
+ RTW_INFO("%s: WiFi write map compare Fail\n", __func__);
+ err = 0;
+ goto exit;
+ }
+ }
+ } else if (strcmp(tmp[0], "wlwfake") == 0) {
+ if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ addr = simple_strtoul(tmp[1], &ptmp, 16);
+ addr &= 0xFFF;
+
+ cnts = strlen(tmp[2]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: map tmp data=%s\n", __func__, tmp[2]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ pEfuseHal->fakeEfuseModifiedMap[addr + jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);
+ memset(extra, '\0', strlen(extra));
+ sprintf(extra, "wlwfake OK\n");
+
+ }
+ else if (strcmp(tmp[0], "wfakemac") == 0) {
+ if (tmp[1] == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
+ /* wfakemac,00e04c871200 */
+ if (hal_efuse_macaddr_offset(padapter) == -1) {
+ err = -EFAULT;
+ goto exit;
+ }
+
+ addr = hal_efuse_macaddr_offset(padapter);
+ cnts = strlen(tmp[1]);
+ if (cnts % 2) {
+ err = -EINVAL;
+ goto exit;
+ }
+ cnts /= 2;
+ if (cnts == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (cnts > 6) {
+ RTW_INFO("%s: error data for mac addr=\"%s\"\n", __func__, tmp[1]);
+ err = -EFAULT;
+ goto exit;
+ }
+
+ RTW_INFO("%s: addr=0x%X\n", __func__, addr);
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: MAC address=%s\n", __func__, tmp[1]);
+
+ for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
+ pEfuseHal->fakeEfuseModifiedMap[addr + jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+
+ memset(extra, '\0', strlen(extra));
+ sprintf(extra, "write mac addr to fake map OK\n");
+ } else if(strcmp(tmp[0], "update") == 0) {
+ RTW_INFO("To Use new eFuse map\n");
+ /*step read efuse/eeprom data and get mac_addr*/
+ rtw_hal_read_chip_info(padapter);
+ /* set mac addr*/
+ rtw_macaddr_cfg(adapter_mac_addr(padapter), get_hal_mac_addr(padapter));
+ memcpy(padapter->pnetdev->dev_addr, get_hal_mac_addr(padapter), ETH_ALEN); /* set mac addr to net_device */
+
+#ifdef CONFIG_P2P
+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter));
+#endif
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ rtw_hal_change_macaddr_mbid(padapter, adapter_mac_addr(padapter));
+#else
+ rtw_hal_set_hwreg(padapter, HW_VAR_MAC_ADDR, adapter_mac_addr(padapter)); /* set mac addr to mac register */
+#endif
+ /*pHalFunc->hal_deinit(padapter);*/
+ if (pHalFunc->hal_init(padapter) == _FAIL) {
+ err = -EINVAL;
+ goto exit;
+ }
+ memset(extra, '\0', strlen(extra));
+ sprintf(extra, "eFuse Update OK\n");
+ }
+
+exit:
+ if (setdata)
+ rtw_mfree(setdata, 1024);
+ if (ShadowMapBT)
+ rtw_mfree(ShadowMapBT, EFUSE_BT_MAX_MAP_LEN);
+ if (ShadowMapWiFi)
+ rtw_mfree(ShadowMapWiFi, wifimaplen);
+ if (setrawdata)
+ rtw_mfree(setrawdata, EFUSE_MAX_SIZE);
+
+ wrqu->length = strlen(extra);
+
+ if (padapter->registrypriv.mp_mode == 0) {
+#ifdef CONFIG_IPS
+ rtw_pm_set_ips(padapter, ips_mode);
+#endif /* CONFIG_IPS */
+
+#ifdef CONFIG_LPS
+ rtw_pm_set_lps(padapter, lps_mode);
+#endif /* CONFIG_LPS */
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_MP_INCLUDED
+
+#ifdef CONFIG_RTW_CUSTOMER_STR
+static int rtw_mp_customer_str(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ _adapter *adapter = rtw_netdev_priv(dev);
+ u32 len;
+ u8 *pbuf = NULL, *pch;
+ char *ptmp;
+ u8 param[RTW_CUSTOMER_STR_LEN];
+ u8 count = 0;
+ u8 tmp;
+ u8 i;
+ u32 pos;
+ u8 ret;
+ u8 read = 0;
+
+ if (adapter->registrypriv.mp_mode != 1
+ || !adapter->registrypriv.mp_customer_str)
+ return -EFAULT;
+
+ len = wrqu->data.length;
+
+ pbuf = (u8 *)rtw_zmalloc(len);
+ if (pbuf == NULL) {
+ RTW_WARN("%s: no memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(pbuf, wrqu->data.pointer, len)) {
+ rtw_mfree(pbuf, len);
+ RTW_WARN("%s: copy from user fail!\n", __func__);
+ return -EFAULT;
+ }
+ RTW_INFO("%s: string=\"%s\"\n", __func__, pbuf);
+
+ ptmp = (char *)pbuf;
+ pch = strsep(&ptmp, ",");
+ if ((pch == NULL) || (strlen(pch) == 0)) {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: parameter error(no cmd)!\n", __func__);
+ return -EFAULT;
+ }
+
+ memset(param, 0xFF, RTW_CUSTOMER_STR_LEN);
+
+ if (strcmp(pch, "read") == 0) {
+ read = 1;
+ ret = rtw_hal_customer_str_read(adapter, param);
+
+ } else if (strcmp(pch, "write") == 0) {
+ do {
+ pch = strsep(&ptmp, ":");
+ if ((pch == NULL) || (strlen(pch) == 0))
+ break;
+ if (strlen(pch) != 2
+ || IsHexDigit(*pch) == false
+ || IsHexDigit(*(pch + 1)) == false
+ || sscanf(pch, "%hhx", &tmp) != 1
+ ) {
+ RTW_WARN("%s: invalid 8-bit hex!\n", __func__);
+ rtw_mfree(pbuf, len);
+ return -EFAULT;
+ }
+
+ param[count++] = tmp;
+
+ } while (count < RTW_CUSTOMER_STR_LEN);
+
+ if (count == 0) {
+ rtw_mfree(pbuf, len);
+ RTW_WARN("%s: no input!\n", __func__);
+ return -EFAULT;
+ }
+ ret = rtw_hal_customer_str_write(adapter, param);
+ } else {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: parameter error(unknown cmd)!\n", __func__);
+ return -EFAULT;
+ }
+
+ pos = sprintf(extra, "%s: ", read ? "read" : "write");
+ if (read == 0 || ret == _SUCCESS) {
+ for (i = 0; i < RTW_CUSTOMER_STR_LEN; i++)
+ pos += sprintf(extra + pos, "%02x:", param[i]);
+ extra[pos] = 0;
+ pos--;
+ }
+ pos += sprintf(extra + pos, " %s", ret == _SUCCESS ? "OK" : "FAIL");
+
+ wrqu->data.length = strlen(extra) + 1;
+
+free_buf:
+ rtw_mfree(pbuf, len);
+ return 0;
+}
+#endif /* CONFIG_RTW_CUSTOMER_STR */
+
+static int rtw_priv_mp_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+
+ struct iw_point *wrqu = (struct iw_point *)wdata;
+ u32 subcmd = wrqu->flags;
+
+ switch (subcmd) {
+ case CTA_TEST:
+ RTW_INFO("set CTA_TEST\n");
+ rtw_cta_test_start(dev, info, wdata, extra);
+ break;
+ case MP_DISABLE_BT_COEXIST:
+ RTW_INFO("set case MP_DISABLE_BT_COEXIST\n");
+ rtw_mp_disable_bt_coexist(dev, info, wdata, extra);
+ break;
+ case MP_IQK:
+ RTW_INFO("set MP_IQK\n");
+ rtw_mp_iqk(dev, info, wrqu, extra);
+ break;
+ case MP_LCK:
+ RTW_INFO("set MP_LCK\n");
+ rtw_mp_lck(dev, info, wrqu, extra);
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int rtw_priv_mp_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+
+ struct iw_point *wrqu = (struct iw_point *)wdata;
+ u32 subcmd = wrqu->flags;
+
+ switch (subcmd) {
+ case MP_START:
+ RTW_INFO("set case mp_start\n");
+ rtw_mp_start(dev, info, wrqu, extra);
+ break;
+ case MP_STOP:
+ RTW_INFO("set case mp_stop\n");
+ rtw_mp_stop(dev, info, wrqu, extra);
+ break;
+ case MP_BANDWIDTH:
+ RTW_INFO("set case mp_bandwidth\n");
+ rtw_mp_bandwidth(dev, info, wrqu, extra);
+ break;
+ case MP_RESET_STATS:
+ RTW_INFO("set case MP_RESET_STATS\n");
+ rtw_mp_reset_stats(dev, info, wrqu, extra);
+ break;
+ case MP_SetRFPathSwh:
+ RTW_INFO("set MP_SetRFPathSwitch\n");
+ rtw_mp_SetRFPath(dev, info, wrqu, extra);
+ break;
+ case WRITE_REG:
+ rtw_mp_write_reg(dev, info, wrqu, extra);
+ break;
+ case WRITE_RF:
+ rtw_mp_write_rf(dev, info, wrqu, extra);
+ break;
+ case MP_PHYPARA:
+ RTW_INFO("mp_get MP_PHYPARA\n");
+ rtw_mp_phypara(dev, info, wrqu, extra);
+ break;
+ case MP_CHANNEL:
+ RTW_INFO("set case mp_channel\n");
+ rtw_mp_channel(dev , info, wrqu, extra);
+ break;
+ case READ_REG:
+ RTW_INFO("mp_get READ_REG\n");
+ rtw_mp_read_reg(dev, info, wrqu, extra);
+ break;
+ case READ_RF:
+ RTW_INFO("mp_get READ_RF\n");
+ rtw_mp_read_rf(dev, info, wrqu, extra);
+ break;
+ case MP_RATE:
+ RTW_INFO("set case mp_rate\n");
+ rtw_mp_rate(dev, info, wrqu, extra);
+ break;
+ case MP_TXPOWER:
+ RTW_INFO("set case MP_TXPOWER\n");
+ rtw_mp_txpower(dev, info, wrqu, extra);
+ break;
+ case MP_ANT_TX:
+ RTW_INFO("set case MP_ANT_TX\n");
+ rtw_mp_ant_tx(dev, info, wrqu, extra);
+ break;
+ case MP_ANT_RX:
+ RTW_INFO("set case MP_ANT_RX\n");
+ rtw_mp_ant_rx(dev, info, wrqu, extra);
+ break;
+ case MP_QUERY:
+ rtw_mp_trx_query(dev, info, wrqu, extra);
+ break;
+ case MP_CTX:
+ RTW_INFO("set case MP_CTX\n");
+ rtw_mp_ctx(dev, info, wrqu, extra);
+ break;
+ case MP_ARX:
+ RTW_INFO("set case MP_ARX\n");
+ rtw_mp_arx(dev, info, wrqu, extra);
+ break;
+ case MP_DUMP:
+ RTW_INFO("set case MP_DUMP\n");
+ rtw_mp_dump(dev, info, wrqu, extra);
+ break;
+ case MP_PSD:
+ RTW_INFO("set case MP_PSD\n");
+ rtw_mp_psd(dev, info, wrqu, extra);
+ break;
+ case MP_THER:
+ RTW_INFO("set case MP_THER\n");
+ rtw_mp_thermal(dev, info, wrqu, extra);
+ break;
+ case MP_PwrCtlDM:
+ RTW_INFO("set MP_PwrCtlDM\n");
+ rtw_mp_PwrCtlDM(dev, info, wrqu, extra);
+ break;
+ case MP_QueryDrvStats:
+ RTW_INFO("mp_get MP_QueryDrvStats\n");
+ rtw_mp_QueryDrv(dev, info, wdata, extra);
+ break;
+ case MP_PWRTRK:
+ RTW_INFO("set case MP_PWRTRK\n");
+ rtw_mp_pwrtrk(dev, info, wrqu, extra);
+ break;
+ case EFUSE_SET:
+ RTW_INFO("set case efuse set\n");
+ rtw_mp_efuse_set(dev, info, wdata, extra);
+ break;
+ case EFUSE_GET:
+ RTW_INFO("efuse get EFUSE_GET\n");
+ rtw_mp_efuse_get(dev, info, wdata, extra);
+ break;
+ case MP_GET_TXPOWER_INX:
+ RTW_INFO("mp_get MP_GET_TXPOWER_INX\n");
+ rtw_mp_txpower_index(dev, info, wrqu, extra);
+ break;
+ case MP_GETVER:
+ RTW_INFO("mp_get MP_GETVER\n");
+ rtw_mp_getver(dev, info, wdata, extra);
+ break;
+ case MP_MON:
+ RTW_INFO("mp_get MP_MON\n");
+ rtw_mp_mon(dev, info, wdata, extra);
+ break;
+ case EFUSE_MASK:
+ RTW_INFO("mp_get EFUSE_MASK\n");
+ rtw_efuse_mask_file(dev, info, wdata, extra);
+ break;
+ case EFUSE_FILE:
+ RTW_INFO("mp_get EFUSE_FILE\n");
+ rtw_efuse_file_map(dev, info, wdata, extra);
+ break;
+ case MP_TX:
+ RTW_INFO("mp_get MP_TX\n");
+ rtw_mp_tx(dev, info, wdata, extra);
+ break;
+ case MP_RX:
+ RTW_INFO("mp_get MP_RX\n");
+ rtw_mp_rx(dev, info, wdata, extra);
+ break;
+ case MP_HW_TX_MODE:
+ RTW_INFO("mp_get MP_HW_TX_MODE\n");
+ rtw_mp_hwtx(dev, info, wdata, extra);
+ break;
+#ifdef CONFIG_RTW_CUSTOMER_STR
+ case MP_CUSTOMER_STR:
+ RTW_INFO("customer str\n");
+ rtw_mp_customer_str(dev, info, wdata, extra);
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif /*#if defined(CONFIG_MP_INCLUDED)*/
+
+
+#ifdef CONFIG_SDIO_INDIRECT_ACCESS
+#define DBG_MP_SDIO_INDIRECT_ACCESS 1
+static int rtw_mp_sd_iread(struct net_device *dev
+ , struct iw_request_info *info
+ , struct iw_point *wrqu
+ , char *extra)
+{
+ char input[16];
+ u8 width;
+ unsigned long addr;
+ u32 ret = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ if (wrqu->length > 16) {
+ RTW_INFO(FUNC_ADPT_FMT" wrqu->length:%d\n", FUNC_ADPT_ARG(padapter), wrqu->length);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ RTW_INFO(FUNC_ADPT_FMT" copy_from_user fail\n", FUNC_ADPT_ARG(padapter));
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ memset(extra, 0, wrqu->length);
+
+ if (sscanf(input, "%hhu,%lx", &width, &addr) != 2) {
+ RTW_INFO(FUNC_ADPT_FMT" sscanf fail\n", FUNC_ADPT_ARG(padapter));
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (addr > 0x3FFF) {
+ RTW_INFO(FUNC_ADPT_FMT" addr:0x%lx\n", FUNC_ADPT_ARG(padapter), addr);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (DBG_MP_SDIO_INDIRECT_ACCESS)
+ RTW_INFO(FUNC_ADPT_FMT" width:%u, addr:0x%lx\n", FUNC_ADPT_ARG(padapter), width, addr);
+
+ switch (width) {
+ case 1:
+ sprintf(extra, "0x%02x", rtw_sd_iread8(padapter, addr));
+ wrqu->length = strlen(extra);
+ break;
+ case 2:
+ sprintf(extra, "0x%04x", rtw_sd_iread16(padapter, addr));
+ wrqu->length = strlen(extra);
+ break;
+ case 4:
+ sprintf(extra, "0x%08x", rtw_sd_iread32(padapter, addr));
+ wrqu->length = strlen(extra);
+ break;
+ default:
+ wrqu->length = 0;
+ ret = -EINVAL;
+ break;
+ }
+
+exit:
+ return ret;
+}
+
+static int rtw_mp_sd_iwrite(struct net_device *dev
+ , struct iw_request_info *info
+ , struct iw_point *wrqu
+ , char *extra)
+{
+ char width;
+ unsigned long addr, data;
+ int ret = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ char input[32];
+
+ if (wrqu->length > 32) {
+ RTW_INFO(FUNC_ADPT_FMT" wrqu->length:%d\n", FUNC_ADPT_ARG(padapter), wrqu->length);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (copy_from_user(input, wrqu->pointer, wrqu->length)) {
+ RTW_INFO(FUNC_ADPT_FMT" copy_from_user fail\n", FUNC_ADPT_ARG(padapter));
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ memset(extra, 0, wrqu->length);
+
+ if (sscanf(input, "%hhu,%lx,%lx", &width, &addr, &data) != 3) {
+ RTW_INFO(FUNC_ADPT_FMT" sscanf fail\n", FUNC_ADPT_ARG(padapter));
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (addr > 0x3FFF) {
+ RTW_INFO(FUNC_ADPT_FMT" addr:0x%lx\n", FUNC_ADPT_ARG(padapter), addr);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (DBG_MP_SDIO_INDIRECT_ACCESS)
+ RTW_INFO(FUNC_ADPT_FMT" width:%u, addr:0x%lx, data:0x%lx\n", FUNC_ADPT_ARG(padapter), width, addr, data);
+
+ switch (width) {
+ case 1:
+ if (data > 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ rtw_sd_iwrite8(padapter, addr, data);
+ break;
+ case 2:
+ if (data > 0xFFFF) {
+ ret = -EINVAL;
+ break;
+ }
+ rtw_sd_iwrite16(padapter, addr, data);
+ break;
+ case 4:
+ rtw_sd_iwrite32(padapter, addr, data);
+ break;
+ default:
+ wrqu->length = 0;
+ ret = -EINVAL;
+ break;
+ }
+
+exit:
+ return ret;
+}
+#endif /* CONFIG_SDIO_INDIRECT_ACCESS */
+
+static int rtw_priv_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct iw_point *wrqu = (struct iw_point *)wdata;
+ u32 subcmd = wrqu->flags;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ if (padapter == NULL)
+ return -ENETDOWN;
+
+ if (padapter->bup == false) {
+ RTW_INFO(" %s fail =>(padapter->bup == false )\n", __func__);
+ return -ENETDOWN;
+ }
+
+ if (RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("%s fail =>(bSurpriseRemoved ) || ( bDriverStopped == true)\n", __func__);
+ return -ENETDOWN;
+ }
+
+ if (extra == NULL) {
+ wrqu->length = 0;
+ return -EIO;
+ }
+
+ if (subcmd < MP_NULL) {
+#ifdef CONFIG_MP_INCLUDED
+ rtw_priv_mp_set(dev, info, wdata, extra);
+#endif
+ return 0;
+ }
+
+ switch (subcmd) {
+#ifdef CONFIG_WOWLAN
+ case MP_WOW_ENABLE:
+ RTW_INFO("set case MP_WOW_ENABLE: %s\n", extra);
+
+ rtw_wowlan_ctrl(dev, info, wdata, extra);
+ break;
+ case MP_WOW_SET_PATTERN:
+ RTW_INFO("set case MP_WOW_SET_PATTERN: %s\n", extra);
+ rtw_wowlan_set_pattern(dev, info, wdata, extra);
+ break;
+#endif
+#ifdef CONFIG_AP_WOWLAN
+ case MP_AP_WOW_ENABLE:
+ RTW_INFO("set case MP_AP_WOW_ENABLE: %s\n", extra);
+ rtw_ap_wowlan_ctrl(dev, info, wdata, extra);
+ break;
+#endif
+#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE
+ case VENDOR_IE_SET:
+ RTW_INFO("set case VENDOR_IE_SET\n");
+ rtw_vendor_ie_set(dev , info , wdata , extra);
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static int rtw_priv_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wdata, char *extra)
+{
+ struct iw_point *wrqu = (struct iw_point *)wdata;
+ u32 subcmd = wrqu->flags;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+
+ if (padapter == NULL)
+ return -ENETDOWN;
+
+ if (padapter->bup == false) {
+ RTW_INFO(" %s fail =>(padapter->bup == false )\n", __func__);
+ return -ENETDOWN;
+ }
+
+ if (RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("%s fail =>(padapter->bSurpriseRemoved ) || ( padapter->bDriverStopped == true)\n", __func__);
+ return -ENETDOWN;
+ }
+
+ if (extra == NULL) {
+ wrqu->length = 0;
+ return -EIO;
+ }
+
+ if (subcmd < MP_NULL) {
+#ifdef CONFIG_MP_INCLUDED
+ rtw_priv_mp_get(dev, info, wdata, extra);
+#endif
+ return 0;
+ }
+
+ switch (subcmd) {
+#ifdef CONFIG_SDIO_INDIRECT_ACCESS
+ case MP_SD_IREAD:
+ rtw_mp_sd_iread(dev, info, wrqu, extra);
+ break;
+ case MP_SD_IWRITE:
+ rtw_mp_sd_iwrite(dev, info, wrqu, extra);
+ break;
+#endif
+#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE
+ case VENDOR_IE_GET:
+ RTW_INFO("get case VENDOR_IE_GET\n");
+ rtw_vendor_ie_get(dev , info , wdata , extra);
+ break;
+#endif
+ default:
+ return -EIO;
+ }
+
+ rtw_msleep_os(10); /* delay 5ms for sending pkt before exit adb shell operation */
+ return 0;
+}
+
+
+
+static int rtw_wx_tdls_wfd_enable(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_WFD
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ if (extra[0] == '0')
+ rtw_tdls_wfd_enable(padapter, 0);
+ else
+ rtw_tdls_wfd_enable(padapter, 1);
+
+#endif /* CONFIG_WFD */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_weaksec(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ u8 i, j;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ if (extra[0] == '0')
+ padapter->wdinfo.wfd_tdls_weaksec = 0;
+ else
+ padapter->wdinfo.wfd_tdls_weaksec = 1;
+
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+
+static int rtw_tdls_enable(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+ unsigned long irqL;
+ _list *plist, *phead;
+ s32 index;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ u8 tdls_sta[NUM_STA][ETH_ALEN];
+ u8 empty_hwaddr[ETH_ALEN] = { 0x00 };
+ struct tdls_txmgmt txmgmt;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ memset(tdls_sta, 0x00, sizeof(tdls_sta));
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+
+ if (extra[0] == '0') {
+ ptdlsinfo->tdls_enable = 0;
+
+ if (pstapriv->asoc_sta_count == 1)
+ return ret;
+
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+ for (index = 0; index < NUM_STA; index++) {
+ phead = &(pstapriv->sta_hash[index]);
+ plist = get_next(phead);
+
+ while (rtw_end_of_queue_search(phead, plist) == false) {
+ psta = LIST_CONTAINOR(plist, struct sta_info , hash_list);
+
+ plist = get_next(plist);
+
+ if (psta->tdls_sta_state != TDLS_STATE_NONE)
+ memcpy(tdls_sta[index], psta->hwaddr, ETH_ALEN);
+ }
+ }
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ for (index = 0; index < NUM_STA; index++) {
+ if (memcmp(tdls_sta[index], empty_hwaddr, ETH_ALEN)) {
+ RTW_INFO("issue tear down to "MAC_FMT"\n", MAC_ARG(tdls_sta[index]));
+ txmgmt.status_code = _RSON_TDLS_TEAR_UN_RSN_;
+ memcpy(txmgmt.peer, tdls_sta[index], ETH_ALEN);
+ issue_tdls_teardown(padapter, &txmgmt, true);
+ }
+ }
+ rtw_tdls_cmd(padapter, NULL, TDLS_RS_RCR);
+ rtw_reset_tdls_info(padapter);
+ } else if (extra[0] == '1')
+ ptdlsinfo->tdls_enable = 1;
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_setup(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+#ifdef CONFIG_TDLS
+ u8 i, j;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_txmgmt txmgmt;
+#ifdef CONFIG_WFD
+ struct wifidirect_info *pwdinfo = &(padapter->wdinfo);
+#endif /* CONFIG_WFD */
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ if (wrqu->data.length - 1 != 17) {
+ RTW_INFO("[%s] length:%d != 17\n", __func__, (wrqu->data.length - 1));
+ return ret;
+ }
+
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+ for (i = 0, j = 0 ; i < ETH_ALEN; i++, j += 3)
+ txmgmt.peer[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+
+#ifdef CONFIG_WFD
+ if (_AES_ != padapter->securitypriv.dot11PrivacyAlgrthm) {
+ /* Weak Security situation with AP. */
+ if (0 == pwdinfo->wfd_tdls_weaksec) {
+ /* Can't send the tdls setup request out!! */
+ RTW_INFO("[%s] Current link is not AES, "
+ "SKIP sending the tdls setup request!!\n", __func__);
+ } else
+ issue_tdls_setup_req(padapter, &txmgmt, true);
+ } else
+#endif /* CONFIG_WFD */
+ {
+ issue_tdls_setup_req(padapter, &txmgmt, true);
+ }
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_teardown(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ u8 i, j;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct sta_info *ptdls_sta = NULL;
+ struct tdls_txmgmt txmgmt;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ if (wrqu->data.length - 1 != 17 && wrqu->data.length - 1 != 19) {
+ RTW_INFO("[%s] length:%d != 17 or 19\n",
+ __func__, (wrqu->data.length - 1));
+ return ret;
+ }
+
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+ for (i = 0, j = 0; i < ETH_ALEN; i++, j += 3)
+ txmgmt.peer[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+
+ ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), txmgmt.peer);
+
+ if (ptdls_sta != NULL) {
+ txmgmt.status_code = _RSON_TDLS_TEAR_UN_RSN_;
+ if (wrqu->data.length - 1 == 19)
+ issue_tdls_teardown(padapter, &txmgmt, false);
+ else
+ issue_tdls_teardown(padapter, &txmgmt, true);
+ } else
+ RTW_INFO("TDLS peer not found\n");
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_discovery(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_txmgmt txmgmt;
+ int i = 0, j = 0;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+ for (i = 0, j = 0 ; i < ETH_ALEN; i++, j += 3)
+ txmgmt.peer[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+
+ issue_tdls_dis_req(padapter, &txmgmt);
+
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_ch_switch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_TDLS_CH_SW
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info;
+ u8 i, j;
+ struct sta_info *ptdls_sta = NULL;
+ u8 take_care_iqk;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ if (rtw_tdls_is_chsw_allowed(padapter) == false) {
+ RTW_INFO("TDLS channel switch is not allowed\n");
+ return ret;
+ }
+
+ for (i = 0, j = 0 ; i < ETH_ALEN; i++, j += 3)
+ pchsw_info->addr[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+
+ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pchsw_info->addr);
+ if (ptdls_sta == NULL)
+ return ret;
+
+ pchsw_info->ch_sw_state |= TDLS_CH_SW_INITIATOR_STATE;
+
+ if (ptdls_sta != NULL) {
+ if (pchsw_info->off_ch_num == 0)
+ pchsw_info->off_ch_num = 11;
+ } else
+ RTW_INFO("TDLS peer not found\n");
+
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+ rtw_hal_get_hwreg(padapter, HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO, &take_care_iqk);
+ if (take_care_iqk ) {
+ u8 central_chnl;
+ u8 bw_mode;
+
+ bw_mode = (pchsw_info->ch_offset) ? CHANNEL_WIDTH_40 : CHANNEL_WIDTH_20;
+ central_chnl = rtw_get_center_ch(pchsw_info->off_ch_num, bw_mode, pchsw_info->ch_offset);
+ if (rtw_hal_ch_sw_iqk_info_search(padapter, central_chnl, bw_mode) >= 0)
+ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_START);
+ else
+ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_PREPARE);
+ } else
+ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_START);
+
+ /* issue_tdls_ch_switch_req(padapter, ptdls_sta); */
+ /* RTW_INFO("issue tdls ch switch req\n"); */
+
+#endif /* CONFIG_TDLS_CH_SW */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_ch_switch_off(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_TDLS_CH_SW
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info;
+ u8 i, j, mac_addr[ETH_ALEN];
+ struct sta_info *ptdls_sta = NULL;
+ struct tdls_txmgmt txmgmt;
+
+ memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt));
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ if (rtw_tdls_is_chsw_allowed(padapter) == false) {
+ RTW_INFO("TDLS channel switch is not allowed\n");
+ return ret;
+ }
+
+ if (wrqu->data.length >= 17) {
+ for (i = 0, j = 0 ; i < ETH_ALEN; i++, j += 3)
+ mac_addr[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr);
+ }
+
+ if (ptdls_sta == NULL)
+ return ret;
+
+ rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_END_TO_BASE_CHNL);
+
+ pchsw_info->ch_sw_state &= ~(TDLS_CH_SW_INITIATOR_STATE |
+ TDLS_CH_SWITCH_ON_STATE |
+ TDLS_PEER_AT_OFF_STATE);
+ memset(pchsw_info->addr, 0x00, ETH_ALEN);
+
+ ptdls_sta->ch_switch_time = 0;
+ ptdls_sta->ch_switch_timeout = 0;
+ _cancel_timer_ex(&ptdls_sta->ch_sw_timer);
+ _cancel_timer_ex(&ptdls_sta->delay_timer);
+ _cancel_timer_ex(&ptdls_sta->stay_on_base_chnl_timer);
+ _cancel_timer_ex(&ptdls_sta->ch_sw_monitor_timer);
+
+ rtw_pm_set_lps(padapter, PS_MODE_MAX);
+#endif /* CONFIG_TDLS_CH_SW */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_dump_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_TDLS_CH_SW
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+
+ RTW_INFO("[%s] dump_stack:%s\n", __func__, extra);
+
+ extra[wrqu->data.length] = 0x00;
+ ptdlsinfo->chsw_info.dump_stack = rtw_atoi(extra);
+
+ return ret;
+
+#endif
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_off_ch_num(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_TDLS_CH_SW
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+
+ RTW_INFO("[%s] off_ch_num:%s\n", __func__, extra);
+
+ extra[wrqu->data.length] = 0x00;
+ ptdlsinfo->chsw_info.off_ch_num = rtw_atoi(extra);
+
+ return ret;
+
+#endif
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_ch_offset(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_TDLS_CH_SW
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+
+ RTW_INFO("[%s] ch_offset:%s\n", __func__, extra);
+
+ extra[wrqu->data.length] = 0x00;
+ switch (rtw_atoi(extra)) {
+ case SCA:
+ ptdlsinfo->chsw_info.ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+ break;
+
+ case SCB:
+ ptdlsinfo->chsw_info.ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+ break;
+
+ default:
+ ptdlsinfo->chsw_info.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ break;
+ }
+
+ return ret;
+
+#endif
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_pson(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 i, j, mac_addr[ETH_ALEN];
+ struct sta_info *ptdls_sta = NULL;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ for (i = 0, j = 0; i < ETH_ALEN; i++, j += 3)
+ mac_addr[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+
+ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr);
+
+ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta->hwaddr, 1, 3, 500);
+
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_psoff(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 i, j, mac_addr[ETH_ALEN];
+ struct sta_info *ptdls_sta = NULL;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ for (i = 0, j = 0; i < ETH_ALEN; i++, j += 3)
+ mac_addr[i] = key_2char2num(*(extra + j), *(extra + j + 1));
+
+ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, mac_addr);
+
+ if (ptdls_sta)
+ issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta->hwaddr, 0, 3, 500);
+
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_setip(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_WFD
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info;
+ u8 i = 0, j = 0, k = 0, tag = 0;
+
+ RTW_INFO("[%s] %s %d\n", __func__, extra, wrqu->data.length - 1);
+
+ while (i < 4) {
+ for (j = 0; j < 4; j++) {
+ if (*(extra + j + tag) == '.' || *(extra + j + tag) == '\0') {
+ if (j == 1)
+ pwfd_info->ip_address[i] = convert_ip_addr('0', '0', *(extra + (j - 1) + tag));
+ if (j == 2)
+ pwfd_info->ip_address[i] = convert_ip_addr('0', *(extra + (j - 2) + tag), *(extra + (j - 1) + tag));
+ if (j == 3)
+ pwfd_info->ip_address[i] = convert_ip_addr(*(extra + (j - 3) + tag), *(extra + (j - 2) + tag), *(extra + (j - 1) + tag));
+
+ tag += j + 1;
+ break;
+ }
+ }
+ i++;
+ }
+
+ RTW_INFO("[%s] Set IP = %u.%u.%u.%u\n", __func__,
+ ptdlsinfo->wfd_info->ip_address[0],
+ ptdlsinfo->wfd_info->ip_address[1],
+ ptdlsinfo->wfd_info->ip_address[2],
+ ptdlsinfo->wfd_info->ip_address[3]);
+
+#endif /* CONFIG_WFD */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_getip(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_WFD
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info;
+
+ RTW_INFO("[%s]\n", __func__);
+
+ sprintf(extra, "\n\n%u.%u.%u.%u\n",
+ pwfd_info->peer_ip_address[0], pwfd_info->peer_ip_address[1],
+ pwfd_info->peer_ip_address[2], pwfd_info->peer_ip_address[3]);
+
+ RTW_INFO("[%s] IP=%u.%u.%u.%u\n", __func__,
+ pwfd_info->peer_ip_address[0], pwfd_info->peer_ip_address[1],
+ pwfd_info->peer_ip_address[2], pwfd_info->peer_ip_address[3]);
+
+ wrqu->data.length = strlen(extra);
+
+#endif /* CONFIG_WFD */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+static int rtw_tdls_getport(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_WFD
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+ struct wifi_display_info *pwfd_info = ptdlsinfo->wfd_info;
+
+ RTW_INFO("[%s]\n", __func__);
+
+ sprintf(extra, "\n\n%d\n", pwfd_info->peer_rtsp_ctrlport);
+ RTW_INFO("[%s] remote port = %d\n",
+ __func__, pwfd_info->peer_rtsp_ctrlport);
+
+ wrqu->data.length = strlen(extra);
+
+#endif /* CONFIG_WFD */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+
+}
+
+/* WFDTDLS, for sigma test */
+static int rtw_tdls_dis_result(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+#ifdef CONFIG_WFD
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+
+ RTW_INFO("[%s]\n", __func__);
+
+ if (ptdlsinfo->dev_discovered ) {
+ sprintf(extra, "\n\nDis=1\n");
+ ptdlsinfo->dev_discovered = false;
+ }
+
+ wrqu->data.length = strlen(extra);
+
+#endif /* CONFIG_WFD */
+#endif /* CONFIG_TDLS */
+
+ return ret;
+
+}
+
+/* WFDTDLS, for sigma test */
+static int rtw_wfd_tdls_status(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct tdls_info *ptdlsinfo = &padapter->tdlsinfo;
+
+ RTW_INFO("[%s]\n", __func__);
+
+ sprintf(extra, "\nlink_established:%d\n"
+ "sta_cnt:%d\n"
+ "sta_maximum:%d\n"
+ "cur_channel:%d\n"
+ "tdls_enable:%d"
+#ifdef CONFIG_TDLS_CH_SW
+ "ch_sw_state:%08x\n"
+ "chsw_on:%d\n"
+ "off_ch_num:%d\n"
+ "cur_time:%d\n"
+ "ch_offset:%d\n"
+ "delay_swtich_back:%d"
+#endif
+ ,
+ ptdlsinfo->link_established, ptdlsinfo->sta_cnt,
+ ptdlsinfo->sta_maximum, ptdlsinfo->cur_channel,
+ ptdlsinfo->tdls_enable
+#ifdef CONFIG_TDLS_CH_SW
+ ,
+ ptdlsinfo->chsw_info.ch_sw_state,
+ ATOMIC_READ(&padapter->tdlsinfo.chsw_info.chsw_on),
+ ptdlsinfo->chsw_info.off_ch_num,
+ ptdlsinfo->chsw_info.cur_time,
+ ptdlsinfo->chsw_info.ch_offset,
+ ptdlsinfo->chsw_info.delay_switch_back
+#endif
+ );
+
+ wrqu->data.length = strlen(extra);
+
+#endif /* CONFIG_TDLS */
+
+ return ret;
+
+}
+
+static int rtw_tdls_getsta(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+
+ int ret = 0;
+#ifdef CONFIG_TDLS
+ u8 i, j;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 addr[ETH_ALEN] = {0};
+ char charmac[17];
+ struct sta_info *ptdls_sta = NULL;
+
+ RTW_INFO("[%s] %s %d\n", __func__,
+ (char *)wrqu->data.pointer, wrqu->data.length - 1);
+
+ if (copy_from_user(charmac, wrqu->data.pointer + 9, 17)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ RTW_INFO("[%s] %d, charmac:%s\n", __func__, __LINE__, charmac);
+ for (i = 0, j = 0 ; i < ETH_ALEN; i++, j += 3)
+ addr[i] = key_2char2num(*(charmac + j), *(charmac + j + 1));
+
+ RTW_INFO("[%s] %d, charmac:%s, addr:"MAC_FMT"\n",
+ __func__, __LINE__, charmac, MAC_ARG(addr));
+ ptdls_sta = rtw_get_stainfo(&padapter->stapriv, addr);
+ if (ptdls_sta) {
+ sprintf(extra, "\n\ntdls_sta_state=0x%08x\n", ptdls_sta->tdls_sta_state);
+ RTW_INFO("\n\ntdls_sta_state=%d\n", ptdls_sta->tdls_sta_state);
+ } else {
+ sprintf(extra, "\n\nNot found this sta\n");
+ RTW_INFO("\n\nNot found this sta\n");
+ }
+ wrqu->data.length = strlen(extra);
+
+#endif /* CONFIG_TDLS */
+exit:
+ return ret;
+
+}
+
+static int rtw_tdls_get_best_ch(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+#ifdef CONFIG_FIND_BEST_CHANNEL
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0;
+
+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+ if (pmlmeext->channel_set[i].ChannelNum == 1)
+ index_24G = i;
+ if (pmlmeext->channel_set[i].ChannelNum == 36)
+ index_5G = i;
+ }
+
+ for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) {
+ /* 2.4G */
+ if (pmlmeext->channel_set[i].ChannelNum == 6 || pmlmeext->channel_set[i].ChannelNum == 11) {
+ if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) {
+ index_24G = i;
+ best_channel_24G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+
+ /* 5G */
+ if (pmlmeext->channel_set[i].ChannelNum >= 36
+ && pmlmeext->channel_set[i].ChannelNum < 140) {
+ /* Find primary channel */
+ if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0)
+ && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
+ index_5G = i;
+ best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+
+ if (pmlmeext->channel_set[i].ChannelNum >= 149
+ && pmlmeext->channel_set[i].ChannelNum < 165) {
+ /* Find primary channel */
+ if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0)
+ && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) {
+ index_5G = i;
+ best_channel_5G = pmlmeext->channel_set[i].ChannelNum;
+ }
+ }
+ RTW_INFO("The rx cnt of channel %3d = %d\n",
+ pmlmeext->channel_set[i].ChannelNum,
+ pmlmeext->channel_set[i].rx_count);
+ }
+
+ sprintf(extra, "\nbest_channel_24G = %d\n", best_channel_24G);
+ RTW_INFO("best_channel_24G = %d\n", best_channel_24G);
+
+ if (index_5G != 0) {
+ sprintf(extra, "best_channel_5G = %d\n", best_channel_5G);
+ RTW_INFO("best_channel_5G = %d\n", best_channel_5G);
+ }
+
+ wrqu->data.length = strlen(extra);
+
+#endif
+
+ return 0;
+
+}
+
+static int rtw_tdls(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_INFO("[%s] extra = %s\n", __func__, extra);
+
+ if (hal_chk_wl_func(padapter, WL_FUNC_TDLS) == false) {
+ RTW_INFO("Discard tdls oper since hal doesn't support tdls\n");
+ return 0;
+ }
+
+ if (padapter->tdlsinfo.tdls_enable == 0) {
+ RTW_INFO("tdls haven't enabled\n");
+ return 0;
+ }
+
+ /* WFD Sigma will use the tdls enable command to let the driver know we want to test the tdls now! */
+
+ if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
+ if (!memcmp(extra, "wfdenable=", 10)) {
+ wrqu->data.length -= 10;
+ rtw_wx_tdls_wfd_enable(dev, info, wrqu, &extra[10]);
+ return ret;
+ }
+ }
+
+ if (!memcmp(extra, "weaksec=", 8)) {
+ wrqu->data.length -= 8;
+ rtw_tdls_weaksec(dev, info, wrqu, &extra[8]);
+ return ret;
+ } else if (!memcmp(extra, "tdlsenable=", 11)) {
+ wrqu->data.length -= 11;
+ rtw_tdls_enable(dev, info, wrqu, &extra[11]);
+ return ret;
+ }
+
+ if (!memcmp(extra, "setup=", 6)) {
+ wrqu->data.length -= 6;
+ rtw_tdls_setup(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "tear=", 5)) {
+ wrqu->data.length -= 5;
+ rtw_tdls_teardown(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "dis=", 4)) {
+ wrqu->data.length -= 4;
+ rtw_tdls_discovery(dev, info, wrqu, &extra[4]);
+ } else if (!memcmp(extra, "swoff=", 6)) {
+ wrqu->data.length -= 6;
+ rtw_tdls_ch_switch_off(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "sw=", 3)) {
+ wrqu->data.length -= 3;
+ rtw_tdls_ch_switch(dev, info, wrqu, &extra[3]);
+ } else if (!memcmp(extra, "dumpstack=", 10)) {
+ wrqu->data.length -= 10;
+ rtw_tdls_dump_ch(dev, info, wrqu, &extra[10]);
+ } else if (!memcmp(extra, "offchnum=", 9)) {
+ wrqu->data.length -= 9;
+ rtw_tdls_off_ch_num(dev, info, wrqu, &extra[9]);
+ } else if (!memcmp(extra, "choffset=", 9)) {
+ wrqu->data.length -= 9;
+ rtw_tdls_ch_offset(dev, info, wrqu, &extra[9]);
+ } else if (!memcmp(extra, "pson=", 5)) {
+ wrqu->data.length -= 5;
+ rtw_tdls_pson(dev, info, wrqu, &extra[5]);
+ } else if (!memcmp(extra, "psoff=", 6)) {
+ wrqu->data.length -= 6;
+ rtw_tdls_psoff(dev, info, wrqu, &extra[6]);
+ }
+
+#ifdef CONFIG_WFD
+ if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
+ if (!memcmp(extra, "setip=", 6)) {
+ wrqu->data.length -= 6;
+ rtw_tdls_setip(dev, info, wrqu, &extra[6]);
+ } else if (!memcmp(extra, "tprobe=", 6))
+ issue_tunneled_probe_req((_adapter *)rtw_netdev_priv(dev));
+ }
+#endif /* CONFIG_WFD */
+
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+
+static int rtw_tdls_get(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+
+#ifdef CONFIG_TDLS
+
+ RTW_INFO("[%s] extra = %s\n", __func__, (char *) wrqu->data.pointer);
+
+ if (!memcmp(wrqu->data.pointer, "ip", 2))
+ rtw_tdls_getip(dev, info, wrqu, extra);
+ else if (!memcmp(wrqu->data.pointer, "port", 4))
+ rtw_tdls_getport(dev, info, wrqu, extra);
+ /* WFDTDLS, for sigma test */
+ else if (!memcmp(wrqu->data.pointer, "dis", 3))
+ rtw_tdls_dis_result(dev, info, wrqu, extra);
+ else if (!memcmp(wrqu->data.pointer, "status", 6))
+ rtw_wfd_tdls_status(dev, info, wrqu, extra);
+ else if (!memcmp(wrqu->data.pointer, "tdls_sta=", 9))
+ rtw_tdls_getsta(dev, info, wrqu, extra);
+ else if (!memcmp(wrqu->data.pointer, "best_ch", 7))
+ rtw_tdls_get_best_ch(dev, info, wrqu, extra);
+#endif /* CONFIG_TDLS */
+
+ return ret;
+}
+
+
+
+
+
+#ifdef CONFIG_INTEL_WIDI
+static int rtw_widi_set(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ process_intel_widi_cmd(padapter, extra);
+
+ return ret;
+}
+
+static int rtw_widi_set_probe_request(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ int ret = 0;
+ u8 *pbuf = NULL;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ pbuf = rtw_malloc(sizeof(l2_msg_t));
+ if (pbuf) {
+ if (copy_from_user(pbuf, wrqu->data.pointer, wrqu->data.length))
+ ret = -EFAULT;
+ /* memcpy(pbuf, wrqu->data.pointer, wrqu->data.length); */
+
+ if (wrqu->data.flags == 0)
+ intel_widi_wk_cmd(padapter, INTEL_WIDI_ISSUE_PROB_WK, pbuf, sizeof(l2_msg_t));
+ else if (wrqu->data.flags == 1)
+ rtw_set_wfd_rds_sink_info(padapter, (l2_msg_t *)pbuf);
+ }
+ return ret;
+}
+#endif /* CONFIG_INTEL_WIDI */
+
+#ifdef CONFIG_MAC_LOOPBACK_DRIVER
+
+#include <rtl8188e_hal.h>
+extern void rtl8188e_cal_txdesc_chksum(struct tx_desc *ptxdesc);
+#define cal_txdesc_chksum rtl8188e_cal_txdesc_chksum
+
+static s32 initLoopback(PADAPTER padapter)
+{
+ PLOOPBACKDATA ploopback;
+
+ if (padapter->ploopback == NULL) {
+ ploopback = (PLOOPBACKDATA)rtw_zmalloc(sizeof(LOOPBACKDATA));
+ if (ploopback == NULL)
+ return -ENOMEM;
+
+ sema_init(&ploopback->sema, 0);
+ ploopback->bstop = true;
+ ploopback->cnt = 0;
+ ploopback->size = 300;
+ memset(ploopback->msg, 0, sizeof(ploopback->msg));
+
+ padapter->ploopback = ploopback;
+ }
+
+ return 0;
+}
+
+static void freeLoopback(PADAPTER padapter)
+{
+ PLOOPBACKDATA ploopback;
+
+
+ ploopback = padapter->ploopback;
+ if (ploopback) {
+ rtw_mfree((u8 *)ploopback, sizeof(LOOPBACKDATA));
+ padapter->ploopback = NULL;
+ }
+}
+
+static s32 initpseudoadhoc(PADAPTER padapter)
+{
+ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
+ s32 err;
+
+ networkType = Ndis802_11IBSS;
+ err = rtw_set_802_11_infrastructure_mode(padapter, networkType);
+ if (err == false)
+ return _FAIL;
+
+ err = rtw_setopmode_cmd(padapter, networkType, true);
+ if (err == _FAIL)
+ return _FAIL;
+
+ return _SUCCESS;
+}
+
+static s32 createpseudoadhoc(PADAPTER padapter)
+{
+ NDIS_802_11_AUTHENTICATION_MODE authmode;
+ struct mlme_priv *pmlmepriv;
+ NDIS_802_11_SSID *passoc_ssid;
+ WLAN_BSSID_EX *pdev_network;
+ u8 *pibss;
+ u8 ssid[] = "pseduo_ad-hoc";
+ s32 err;
+ unsigned long irqL;
+
+
+ pmlmepriv = &padapter->mlmepriv;
+
+ authmode = Ndis802_11AuthModeOpen;
+ err = rtw_set_802_11_authentication_mode(padapter, authmode);
+ if (err == false)
+ return _FAIL;
+
+ passoc_ssid = &pmlmepriv->assoc_ssid;
+ memset(passoc_ssid, 0, sizeof(NDIS_802_11_SSID));
+ passoc_ssid->SsidLength = sizeof(ssid) - 1;
+ memcpy(passoc_ssid->Ssid, ssid, passoc_ssid->SsidLength);
+
+ pdev_network = &padapter->registrypriv.dev_network;
+ pibss = padapter->registrypriv.dev_network.MacAddress;
+ memcpy(&pdev_network->Ssid, passoc_ssid, sizeof(NDIS_802_11_SSID));
+
+ rtw_update_registrypriv_dev_network(padapter);
+ rtw_generate_random_ibss(pibss);
+
+ _enter_critical_bh(&pmlmepriv->lock, &irqL);
+ /*pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;*/
+ init_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+
+ _exit_critical_bh(&pmlmepriv->lock, &irqL);
+ {
+ struct wlan_network *pcur_network;
+ struct sta_info *psta;
+
+ /* 3 create a new psta */
+ pcur_network = &pmlmepriv->cur_network;
+
+ /* clear psta in the cur_network, if any */
+ psta = rtw_get_stainfo(&padapter->stapriv, pcur_network->network.MacAddress);
+ if (psta)
+ rtw_free_stainfo(padapter, psta);
+
+ psta = rtw_alloc_stainfo(&padapter->stapriv, pibss);
+ if (psta == NULL)
+ return _FAIL;
+
+ /* 3 join psudo AdHoc */
+ pcur_network->join_res = 1;
+ pcur_network->aid = psta->aid = 1;
+ memcpy(&pcur_network->network, pdev_network, get_WLAN_BSSID_EX_sz(pdev_network));
+
+ /* set msr to WIFI_FW_ADHOC_STATE */
+ padapter->hw_port = HW_PORT0;
+ Set_MSR(padapter, WIFI_FW_ADHOC_STATE);
+
+ }
+
+ return _SUCCESS;
+}
+
+static struct xmit_frame *createloopbackpkt(PADAPTER padapter, u32 size)
+{
+ struct xmit_priv *pxmitpriv;
+ struct xmit_frame *pframe;
+ struct xmit_buf *pxmitbuf;
+ struct pkt_attrib *pattrib;
+ struct tx_desc *desc;
+ u8 *pkt_start, *pkt_end, *ptr;
+ struct rtw_ieee80211_hdr *hdr;
+ s32 bmcast;
+ unsigned long irqL;
+
+
+ if ((TXDESC_SIZE + WLANHDR_OFFSET + size) > MAX_XMITBUF_SZ)
+ return NULL;
+
+ pxmitpriv = &padapter->xmitpriv;
+ pframe = NULL;
+
+ /* 2 1. allocate xmit frame */
+ pframe = rtw_alloc_xmitframe(pxmitpriv);
+ if (pframe == NULL)
+ return NULL;
+ pframe->padapter = padapter;
+
+ /* 2 2. allocate xmit buffer */
+ _enter_critical_bh(&pxmitpriv->lock, &irqL);
+ pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
+ _exit_critical_bh(&pxmitpriv->lock, &irqL);
+ if (pxmitbuf == NULL) {
+ rtw_free_xmitframe(pxmitpriv, pframe);
+ return NULL;
+ }
+
+ pframe->pxmitbuf = pxmitbuf;
+ pframe->buf_addr = pxmitbuf->pbuf;
+ pxmitbuf->priv_data = pframe;
+
+ /* 2 3. update_attrib() */
+ pattrib = &pframe->attrib;
+
+ /* init xmitframe attribute */
+ memset(pattrib, 0, sizeof(struct pkt_attrib));
+
+ pattrib->ether_type = 0x8723;
+ memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN);
+ memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+ memset(pattrib->dst, 0xFF, ETH_ALEN);
+ memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+
+ /* pattrib->dhcp_pkt = 0;
+ * pattrib->pktlen = 0; */
+ pattrib->ack_policy = 0;
+ /* pattrib->pkt_hdrlen = ETH_HLEN; */
+ pattrib->hdrlen = WLAN_HDR_A3_LEN;
+ pattrib->subtype = WIFI_DATA;
+ pattrib->priority = 0;
+ pattrib->qsel = pattrib->priority;
+ /* do_queue_select(padapter, pattrib); */
+ pattrib->nr_frags = 1;
+ pattrib->encrypt = 0;
+ pattrib->bswenc = false;
+ pattrib->qos_en = false;
+
+ bmcast = IS_MCAST(pattrib->ra);
+ if (bmcast) {
+ pattrib->mac_id = 1;
+ pattrib->psta = rtw_get_bcmc_stainfo(padapter);
+ } else {
+ pattrib->mac_id = 0;
+ pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv));
+ }
+
+ pattrib->pktlen = size;
+ pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen;
+
+ /* 2 4. fill TX descriptor */
+ desc = (struct tx_desc *)pframe->buf_addr;
+ memset(desc, 0, TXDESC_SIZE);
+
+ fill_default_txdesc(pframe, (u8 *)desc);
+
+ /* Hw set sequence number */
+ ((PTXDESC)desc)->hwseq_en = 0; /* HWSEQ_EN, 0:disable, 1:enable
+ * ((PTXDESC)desc)->hwseq_sel = 0; */ /* HWSEQ_SEL */
+
+ ((PTXDESC)desc)->disdatafb = 1;
+
+ /* convert to little endian */
+ desc->txdw0 = cpu_to_le32(desc->txdw0);
+ desc->txdw1 = cpu_to_le32(desc->txdw1);
+ desc->txdw2 = cpu_to_le32(desc->txdw2);
+ desc->txdw3 = cpu_to_le32(desc->txdw3);
+ desc->txdw4 = cpu_to_le32(desc->txdw4);
+ desc->txdw5 = cpu_to_le32(desc->txdw5);
+ desc->txdw6 = cpu_to_le32(desc->txdw6);
+ desc->txdw7 = cpu_to_le32(desc->txdw7);
+ cal_txdesc_chksum(desc);
+
+ /* 2 5. coalesce */
+ pkt_start = pframe->buf_addr + TXDESC_SIZE;
+ pkt_end = pkt_start + pattrib->last_txcmdsz;
+
+ /* 3 5.1. make wlan header, make_wlanhdr() */
+ hdr = (struct rtw_ieee80211_hdr *)pkt_start;
+ set_frame_sub_type(&hdr->frame_ctl, pattrib->subtype);
+ memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /* DA */
+ memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /* SA */
+ memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); /* RA, BSSID */
+
+ /* 3 5.2. make payload */
+ ptr = pkt_start + pattrib->hdrlen;
+ get_random_bytes(ptr, pkt_end - ptr);
+
+ pxmitbuf->len = TXDESC_SIZE + pattrib->last_txcmdsz;
+ pxmitbuf->ptail += pxmitbuf->len;
+
+ return pframe;
+}
+
+static void freeloopbackpkt(PADAPTER padapter, struct xmit_frame *pframe)
+{
+ struct xmit_priv *pxmitpriv;
+ struct xmit_buf *pxmitbuf;
+
+
+ pxmitpriv = &padapter->xmitpriv;
+ pxmitbuf = pframe->pxmitbuf;
+
+ rtw_free_xmitframe(pxmitpriv, pframe);
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+}
+
+static void printdata(u8 *pbuf, u32 len)
+{
+ u32 i, val;
+
+
+ for (i = 0; (i + 4) <= len; i += 4) {
+ printk("%08X", *(u32 *)(pbuf + i));
+ if ((i + 4) & 0x1F)
+ printk(" ");
+ else
+ printk("\n");
+ }
+
+ if (i < len) {
+#ifdef __BIG_ENDIAN
+ for (; i < len, i++)
+ printk("%02X", pbuf + i);
+#else /* __LITTLE_ENDIAN */
+ u8 str[9];
+ u8 n;
+ val = 0;
+ n = len - i;
+ memcpy(&val, pbuf + i, n);
+ sprintf(str, "%08X", val);
+ n = (4 - n) * 2;
+ printk("%8s", str + n);
+#endif /* __LITTLE_ENDIAN */
+ }
+ printk("\n");
+}
+
+static u8 pktcmp(PADAPTER padapter, u8 *txbuf, u32 txsz, u8 *rxbuf, u32 rxsz)
+{
+ PHAL_DATA_TYPE phal;
+ struct recv_stat *prxstat;
+ struct recv_stat report;
+ PRXREPORT prxreport;
+ u32 drvinfosize;
+ u32 rxpktsize;
+ u8 fcssize;
+ u8 ret = false;
+
+ prxstat = (struct recv_stat *)rxbuf;
+ report.rxdw0 = le32_to_cpu(prxstat->rxdw0);
+ report.rxdw1 = le32_to_cpu(prxstat->rxdw1);
+ report.rxdw2 = le32_to_cpu(prxstat->rxdw2);
+ report.rxdw3 = le32_to_cpu(prxstat->rxdw3);
+ report.rxdw4 = le32_to_cpu(prxstat->rxdw4);
+ report.rxdw5 = le32_to_cpu(prxstat->rxdw5);
+
+ prxreport = (PRXREPORT)&report;
+ drvinfosize = prxreport->drvinfosize << 3;
+ rxpktsize = prxreport->pktlen;
+
+ phal = GET_HAL_DATA(padapter);
+ if (phal->ReceiveConfig & RCR_APPFCS)
+ fcssize = IEEE80211_FCS_LEN;
+ else
+ fcssize = 0;
+
+ if ((txsz - TXDESC_SIZE) != (rxpktsize - fcssize)) {
+ RTW_INFO("%s: ERROR! size not match tx/rx=%d/%d !\n",
+ __func__, txsz - TXDESC_SIZE, rxpktsize - fcssize);
+ ret = false;
+ } else {
+ ret = !memcmp(txbuf + TXDESC_SIZE, \
+ rxbuf + RXDESC_SIZE + drvinfosize, \
+ txsz - TXDESC_SIZE);
+ if (ret == false)
+ RTW_INFO("%s: ERROR! pkt content mismatch!\n", __func__);
+ }
+
+ if (ret == false) {
+ RTW_INFO("\n%s: TX PKT total=%d, desc=%d, content=%d\n",
+ __func__, txsz, TXDESC_SIZE, txsz - TXDESC_SIZE);
+ RTW_INFO("%s: TX DESC size=%d\n", __func__, TXDESC_SIZE);
+ printdata(txbuf, TXDESC_SIZE);
+ RTW_INFO("%s: TX content size=%d\n", __func__, txsz - TXDESC_SIZE);
+ printdata(txbuf + TXDESC_SIZE, txsz - TXDESC_SIZE);
+
+ RTW_INFO("\n%s: RX PKT read=%d offset=%d(%d,%d) content=%d\n",
+ __func__, rxsz, RXDESC_SIZE + drvinfosize, RXDESC_SIZE, drvinfosize, rxpktsize);
+ if (rxpktsize != 0) {
+ RTW_INFO("%s: RX DESC size=%d\n", __func__, RXDESC_SIZE);
+ printdata(rxbuf, RXDESC_SIZE);
+ RTW_INFO("%s: RX drvinfo size=%d\n", __func__, drvinfosize);
+ printdata(rxbuf + RXDESC_SIZE, drvinfosize);
+ RTW_INFO("%s: RX content size=%d\n", __func__, rxpktsize);
+ printdata(rxbuf + RXDESC_SIZE + drvinfosize, rxpktsize);
+ } else {
+ RTW_INFO("%s: RX data size=%d\n", __func__, rxsz);
+ printdata(rxbuf, rxsz);
+ }
+ }
+
+ return ret;
+}
+
+thread_return lbk_thread(thread_context context)
+{
+ s32 err;
+ PADAPTER padapter;
+ PLOOPBACKDATA ploopback;
+ struct xmit_frame *pxmitframe;
+ u32 cnt, ok, fail, headerlen;
+ u32 pktsize;
+ u32 ff_hwaddr;
+
+
+ padapter = (PADAPTER)context;
+ ploopback = padapter->ploopback;
+ if (ploopback == NULL)
+ return -1;
+ cnt = 0;
+ ok = 0;
+ fail = 0;
+
+ daemonize("%s", "RTW_LBK_THREAD");
+ allow_signal(SIGTERM);
+
+ do {
+ if (ploopback->size == 0) {
+ get_random_bytes(&pktsize, 4);
+ pktsize = (pktsize % 1535) + 1; /* 1~1535 */
+ } else
+ pktsize = ploopback->size;
+
+ pxmitframe = createloopbackpkt(padapter, pktsize);
+ if (pxmitframe == NULL) {
+ sprintf(ploopback->msg, "loopback FAIL! 3. create Packet FAIL!");
+ break;
+ }
+
+ ploopback->txsize = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz;
+ memcpy(ploopback->txbuf, pxmitframe->buf_addr, ploopback->txsize);
+ ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
+ cnt++;
+ RTW_INFO("%s: wirte port cnt=%d size=%d\n", __func__, cnt, ploopback->txsize);
+ pxmitframe->pxmitbuf->pdata = ploopback->txbuf;
+ rtw_write_port(padapter, ff_hwaddr, ploopback->txsize, (u8 *)pxmitframe->pxmitbuf);
+
+ /* wait for rx pkt */
+ _rtw_down_sema(&ploopback->sema);
+
+ err = pktcmp(padapter, ploopback->txbuf, ploopback->txsize, ploopback->rxbuf, ploopback->rxsize);
+ if (err )
+ ok++;
+ else
+ fail++;
+
+ ploopback->txsize = 0;
+ memset(ploopback->txbuf, 0, 0x8000);
+ ploopback->rxsize = 0;
+ memset(ploopback->rxbuf, 0, 0x8000);
+
+ freeloopbackpkt(padapter, pxmitframe);
+ pxmitframe = NULL;
+
+ if (signal_pending(current))
+ flush_signals(current);
+
+ if ((ploopback->bstop ) ||
+ ((ploopback->cnt != 0) && (ploopback->cnt == cnt))) {
+ u32 ok_rate, fail_rate, all;
+ all = cnt;
+ ok_rate = (ok * 100) / all;
+ fail_rate = (fail * 100) / all;
+ sprintf(ploopback->msg, \
+ "loopback result: ok=%d%%(%d/%d),error=%d%%(%d/%d)", \
+ ok_rate, ok, all, fail_rate, fail, all);
+ break;
+ }
+ } while (1);
+
+ ploopback->bstop = true;
+
+ thread_exit();
+}
+
+static void loopbackTest(PADAPTER padapter, u32 cnt, u32 size, u8 *pmsg)
+{
+ PLOOPBACKDATA ploopback;
+ u32 len;
+ s32 err;
+
+
+ ploopback = padapter->ploopback;
+
+ if (ploopback) {
+ if (ploopback->bstop == false) {
+ ploopback->bstop = true;
+ up(&ploopback->sema);
+ }
+ len = 0;
+ do {
+ len = strlen(ploopback->msg);
+ if (len)
+ break;
+ rtw_msleep_os(1);
+ } while (1);
+ memcpy(pmsg, ploopback->msg, len + 1);
+ freeLoopback(padapter);
+
+ return;
+ }
+
+ /* disable dynamic algorithm */
+ rtw_phydm_ability_backup(padapter);
+ rtw_phydm_func_disable_all(padapter);
+
+ /* create pseudo ad-hoc connection */
+ err = initpseudoadhoc(padapter);
+ if (err == _FAIL) {
+ sprintf(pmsg, "loopback FAIL! 1.1 init ad-hoc FAIL!");
+ return;
+ }
+
+ err = createpseudoadhoc(padapter);
+ if (err == _FAIL) {
+ sprintf(pmsg, "loopback FAIL! 1.2 create ad-hoc master FAIL!");
+ return;
+ }
+
+ err = initLoopback(padapter);
+ if (err) {
+ sprintf(pmsg, "loopback FAIL! 2. init FAIL! error code=%d", err);
+ return;
+ }
+
+ ploopback = padapter->ploopback;
+
+ ploopback->bstop = false;
+ ploopback->cnt = cnt;
+ ploopback->size = size;
+ ploopback->lbkthread = kthread_run(lbk_thread, padapter, "RTW_LBK_THREAD");
+ if (IS_ERR(padapter->lbkthread)) {
+ freeLoopback(padapter);
+ sprintf(pmsg, "loopback start FAIL! cnt=%d", cnt);
+ return;
+ }
+
+ sprintf(pmsg, "loopback start! cnt=%d", cnt);
+}
+#endif /* CONFIG_MAC_LOOPBACK_DRIVER */
+
+static int rtw_test(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ u32 len;
+ u8 *pbuf, *pch;
+ char *ptmp;
+ u8 *delim = ",";
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+
+ RTW_INFO("+%s\n", __func__);
+ len = wrqu->data.length;
+
+ pbuf = (u8 *)rtw_zmalloc(len);
+ if (pbuf == NULL) {
+ RTW_INFO("%s: no memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(pbuf, wrqu->data.pointer, len)) {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: copy from user fail!\n", __func__);
+ return -EFAULT;
+ }
+ RTW_INFO("%s: string=\"%s\"\n", __func__, pbuf);
+
+ ptmp = (char *)pbuf;
+ pch = strsep(&ptmp, delim);
+ if ((pch == NULL) || (strlen(pch) == 0)) {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: parameter error(level 1)!\n", __func__);
+ return -EFAULT;
+ }
+
+#ifdef CONFIG_MAC_LOOPBACK_DRIVER
+ if (strcmp(pch, "loopback") == 0) {
+ s32 cnt = 0;
+ u32 size = 64;
+
+ pch = strsep(&ptmp, delim);
+ if ((pch == NULL) || (strlen(pch) == 0)) {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: parameter error(level 2)!\n", __func__);
+ return -EFAULT;
+ }
+
+ sscanf(pch, "%d", &cnt);
+ RTW_INFO("%s: loopback cnt=%d\n", __func__, cnt);
+
+ pch = strsep(&ptmp, delim);
+ if ((pch == NULL) || (strlen(pch) == 0)) {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: parameter error(level 2)!\n", __func__);
+ return -EFAULT;
+ }
+
+ sscanf(pch, "%d", &size);
+ RTW_INFO("%s: loopback size=%d\n", __func__, size);
+
+ loopbackTest(padapter, cnt, size, extra);
+ wrqu->data.length = strlen(extra) + 1;
+
+ goto free_buf;
+ }
+#endif
+
+
+#ifdef CONFIG_BT_COEXIST
+ if (strcmp(pch, "bton") == 0) {
+ rtw_btcoex_SetManualControl(padapter, false);
+ goto free_buf;
+ } else if (strcmp(pch, "btoff") == 0) {
+ rtw_btcoex_SetManualControl(padapter, true);
+ goto free_buf;
+ }
+#endif
+
+ if (strcmp(pch, "h2c") == 0) {
+ u8 param[8];
+ u8 count = 0;
+ u32 tmp;
+ u8 i;
+ u32 pos;
+ u8 ret;
+
+ do {
+ pch = strsep(&ptmp, delim);
+ if ((pch == NULL) || (strlen(pch) == 0))
+ break;
+
+ sscanf(pch, "%x", &tmp);
+ param[count++] = (u8)tmp;
+ } while (count < 8);
+
+ if (count == 0) {
+ rtw_mfree(pbuf, len);
+ RTW_INFO("%s: parameter error(level 2)!\n", __func__);
+ return -EFAULT;
+ }
+
+ ret = rtw_test_h2c_cmd(padapter, param, count);
+
+ pos = sprintf(extra, "H2C ID=0x%02x content=", param[0]);
+ for (i = 1; i < count; i++)
+ pos += sprintf(extra + pos, "%02x,", param[i]);
+ extra[pos] = 0;
+ pos--;
+ pos += sprintf(extra + pos, " %s", ret == _FAIL ? "FAIL" : "OK");
+
+ wrqu->data.length = strlen(extra) + 1;
+
+ goto free_buf;
+ }
+
+free_buf:
+ rtw_mfree(pbuf, len);
+ return 0;
+}
+
+static iw_handler rtw_handlers[] = {
+ NULL, /* SIOCSIWCOMMIT */
+ rtw_wx_get_name, /* SIOCGIWNAME */
+ dummy, /* SIOCSIWNWID */
+ dummy, /* SIOCGIWNWID */
+ rtw_wx_set_freq, /* SIOCSIWFREQ */
+ rtw_wx_get_freq, /* SIOCGIWFREQ */
+ rtw_wx_set_mode, /* SIOCSIWMODE */
+ rtw_wx_get_mode, /* SIOCGIWMODE */
+ dummy, /* SIOCSIWSENS */
+ rtw_wx_get_sens, /* SIOCGIWSENS */
+ NULL, /* SIOCSIWRANGE */
+ rtw_wx_get_range, /* SIOCGIWRANGE */
+ rtw_wx_set_priv, /* SIOCSIWPRIV */
+ NULL, /* SIOCGIWPRIV */
+ NULL, /* SIOCSIWSTATS */
+ NULL, /* SIOCGIWSTATS */
+ dummy, /* SIOCSIWSPY */
+ dummy, /* SIOCGIWSPY */
+ NULL, /* SIOCGIWTHRSPY */
+ NULL, /* SIOCWIWTHRSPY */
+ rtw_wx_set_wap, /* SIOCSIWAP */
+ rtw_wx_get_wap, /* SIOCGIWAP */
+ rtw_wx_set_mlme, /* request MLME operation; uses struct iw_mlme */
+ dummy, /* SIOCGIWAPLIST -- depricated */
+ rtw_wx_set_scan, /* SIOCSIWSCAN */
+ rtw_wx_get_scan, /* SIOCGIWSCAN */
+ rtw_wx_set_essid, /* SIOCSIWESSID */
+ rtw_wx_get_essid, /* SIOCGIWESSID */
+ dummy, /* SIOCSIWNICKN */
+ rtw_wx_get_nick, /* SIOCGIWNICKN */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ rtw_wx_set_rate, /* SIOCSIWRATE */
+ rtw_wx_get_rate, /* SIOCGIWRATE */
+ rtw_wx_set_rts, /* SIOCSIWRTS */
+ rtw_wx_get_rts, /* SIOCGIWRTS */
+ rtw_wx_set_frag, /* SIOCSIWFRAG */
+ rtw_wx_get_frag, /* SIOCGIWFRAG */
+ dummy, /* SIOCSIWTXPOW */
+ dummy, /* SIOCGIWTXPOW */
+ dummy, /* SIOCSIWRETRY */
+ rtw_wx_get_retry, /* SIOCGIWRETRY */
+ rtw_wx_set_enc, /* SIOCSIWENCODE */
+ rtw_wx_get_enc, /* SIOCGIWENCODE */
+ dummy, /* SIOCSIWPOWER */
+ rtw_wx_get_power, /* SIOCGIWPOWER */
+ NULL, /*---hole---*/
+ NULL, /*---hole---*/
+ rtw_wx_set_gen_ie, /* SIOCSIWGENIE */
+ NULL, /* SIOCGWGENIE */
+ rtw_wx_set_auth, /* SIOCSIWAUTH */
+ NULL, /* SIOCGIWAUTH */
+ rtw_wx_set_enc_ext, /* SIOCSIWENCODEEXT */
+ NULL, /* SIOCGIWENCODEEXT */
+ rtw_wx_set_pmkid, /* SIOCSIWPMKSA */
+ NULL, /*---hole---*/
+};
+
+
+static const struct iw_priv_args rtw_private_args[] = {
+ {
+ SIOCIWFIRSTPRIV + 0x0,
+ IW_PRIV_TYPE_CHAR | 0x7FF, 0, "write"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x1,
+ IW_PRIV_TYPE_CHAR | 0x7FF,
+ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "read"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x2, 0, 0, "driver_ext"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x3, 0, 0, "mp_ioctl"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x4,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "apinfo"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x5,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setpid"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x6,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_start"
+ },
+ /* for PLATFORM_MT53XX */
+ {
+ SIOCIWFIRSTPRIV + 0x7,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "get_sensitivity"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x8,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_prob_req_ie"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x9,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wps_assoc_req_ie"
+ },
+
+ /* for RTK_DMP_PLATFORM */
+ {
+ SIOCIWFIRSTPRIV + 0xA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "channel_plan"
+ },
+
+ {
+ SIOCIWFIRSTPRIV + 0xB,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "dbg"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0xC,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "rfw"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0xD,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "rfr"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x10,
+ IW_PRIV_TYPE_CHAR | 1024, 0, "p2p_set"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x11,
+ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "p2p_get"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x12, 0, 0, "NULL"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x13,
+ IW_PRIV_TYPE_CHAR | 64, IW_PRIV_TYPE_CHAR | 64 , "p2p_get2"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x14,
+ IW_PRIV_TYPE_CHAR | 64, 0, "tdls"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x15,
+ IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024 , "tdls_get"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x16,
+ IW_PRIV_TYPE_CHAR | 64, 0, "pm_set"
+ },
+
+ {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ , 0 , "rereg_nd_name"},
+#ifdef CONFIG_MP_INCLUDED
+ {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "NULL"},
+ {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "NULL"},
+#else
+ {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"},
+ {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"},
+#endif
+ {
+ SIOCIWFIRSTPRIV + 0x1D,
+ IW_PRIV_TYPE_CHAR | 40, IW_PRIV_TYPE_CHAR | 0x7FF, "test"
+ },
+
+#ifdef CONFIG_INTEL_WIDI
+ {
+ SIOCIWFIRSTPRIV + 0x1E,
+ IW_PRIV_TYPE_CHAR | 1024, 0, "widi_set"
+ },
+ {
+ SIOCIWFIRSTPRIV + 0x1F,
+ IW_PRIV_TYPE_CHAR | 128, 0, "widi_prob_req"
+ },
+#endif /* CONFIG_INTEL_WIDI */
+
+ { SIOCIWFIRSTPRIV + 0x0E, IW_PRIV_TYPE_CHAR | 1024, 0 , ""}, /* set */
+ { SIOCIWFIRSTPRIV + 0x0F, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , ""},/* get
+ * --- sub-ioctls definitions --- */
+
+#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE
+ { VENDOR_IE_SET, IW_PRIV_TYPE_CHAR | 1024 , 0 , "vendor_ie_set" },
+ { VENDOR_IE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "vendor_ie_get" },
+#endif
+#ifdef CONFIG_WOWLAN
+ { MP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "wow_mode" },
+ { MP_WOW_SET_PATTERN , IW_PRIV_TYPE_CHAR | 1024, 0, "wow_set_pattern" },
+#endif
+#ifdef CONFIG_AP_WOWLAN
+ { MP_AP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "ap_wow_mode" }, /* set */
+#endif
+#ifdef CONFIG_SDIO_INDIRECT_ACCESS
+ { MP_SD_IREAD, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "sd_iread" },
+ { MP_SD_IWRITE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "sd_iwrite" },
+#endif
+};
+
+
+static const struct iw_priv_args rtw_mp_private_args[] = {
+ /* --- sub-ioctls definitions --- */
+#ifdef CONFIG_MP_INCLUDED
+ { MP_START , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_start" },
+ { MP_PHYPARA, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_phypara" },
+ { MP_STOP , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_stop" },
+ { MP_CHANNEL , IW_PRIV_TYPE_CHAR | 1024 , IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_channel" },
+ { MP_BANDWIDTH , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_bandwidth"},
+ { MP_RATE , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate" },
+ { MP_RESET_STATS , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_reset_stats"},
+ { MP_QUERY , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "mp_query"},
+ { READ_REG , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_reg" },
+ { MP_RATE , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rate" },
+ { READ_RF , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "read_rf" },
+ { MP_PSD , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_psd"},
+ { MP_DUMP, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_dump" },
+ { MP_TXPOWER , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_txpower"},
+ { MP_ANT_TX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_tx"},
+ { MP_ANT_RX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ant_rx"},
+ { WRITE_REG , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_reg" },
+ { WRITE_RF , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "write_rf" },
+ { MP_CTX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ctx"},
+ { MP_ARX , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_arx"},
+ { MP_THER , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_ther"},
+ { EFUSE_SET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_set" },
+ { EFUSE_GET, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get" },
+ { MP_PWRTRK , IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_pwrtrk"},
+ { MP_QueryDrvStats, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_drvquery" },
+ { MP_IOCTL, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_ioctl"},
+ { MP_SetRFPathSwh, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_setrfpath" },
+ { MP_PwrCtlDM, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_pwrctldm" },
+ { MP_GET_TXPOWER_INX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_get_txpower" },
+ { MP_GETVER, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_priv_ver" },
+ { MP_MON, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_mon" },
+ { EFUSE_MASK, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_mask" },
+ { EFUSE_FILE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_file" },
+ { MP_TX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_tx" },
+ { MP_RX, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_rx" },
+ { MP_HW_TX_MODE, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "mp_hxtx" },
+ { CTA_TEST, IW_PRIV_TYPE_CHAR | 1024, 0, "cta_test"},
+ { MP_IQK, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_iqk"},
+ { MP_LCK, IW_PRIV_TYPE_CHAR | 1024, 0, "mp_lck"},
+#ifdef CONFIG_RTW_CUSTOMER_STR
+ { MP_CUSTOMER_STR, IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "customer_str" },
+#endif
+
+#endif /* CONFIG_MP_INCLUDED */
+};
+
+static iw_handler rtw_private_handler[] = {
+ rtw_wx_write32, /* 0x00 */
+ rtw_wx_read32, /* 0x01 */
+ rtw_drvext_hdl, /* 0x02 */
+#ifdef MP_IOCTL_HDL
+ rtw_mp_ioctl_hdl, /* 0x03 */
+#else
+ rtw_wx_priv_null,
+#endif
+ /* for MM DTV platform */
+ rtw_get_ap_info, /* 0x04 */
+
+ rtw_set_pid, /* 0x05 */
+ rtw_wps_start, /* 0x06 */
+
+ /* for PLATFORM_MT53XX */
+ rtw_wx_get_sensitivity, /* 0x07 */
+ rtw_wx_set_mtk_wps_probe_ie, /* 0x08 */
+ rtw_wx_set_mtk_wps_ie, /* 0x09 */
+
+ /* for RTK_DMP_PLATFORM
+ * Set Channel depend on the country code */
+ rtw_wx_set_channel_plan, /* 0x0A */
+
+ rtw_dbg_port, /* 0x0B */
+ rtw_wx_write_rf, /* 0x0C */
+ rtw_wx_read_rf, /* 0x0D */
+
+ rtw_priv_set, /*0x0E*/
+ rtw_priv_get, /*0x0F*/
+
+ rtw_p2p_set, /* 0x10 */
+ rtw_p2p_get, /* 0x11 */
+ NULL, /* 0x12 */
+ rtw_p2p_get2, /* 0x13 */
+
+ rtw_tdls, /* 0x14 */
+ rtw_tdls_get, /* 0x15 */
+
+ rtw_pm_set, /* 0x16 */
+ rtw_wx_priv_null, /* 0x17 */
+ rtw_rereg_nd_name, /* 0x18 */
+ rtw_wx_priv_null, /* 0x19 */
+#ifdef CONFIG_MP_INCLUDED
+ rtw_wx_priv_null, /* 0x1A */
+ rtw_wx_priv_null, /* 0x1B */
+#else
+ rtw_mp_efuse_set, /* 0x1A */
+ rtw_mp_efuse_get, /* 0x1B */
+#endif
+ NULL, /* 0x1C is reserved for hostapd */
+ rtw_test, /* 0x1D */
+#ifdef CONFIG_INTEL_WIDI
+ rtw_widi_set, /* 0x1E */
+ rtw_widi_set_probe_request, /* 0x1F */
+#endif /* CONFIG_INTEL_WIDI */
+};
+
+#if WIRELESS_EXT >= 17
+static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct iw_statistics *piwstats = &padapter->iwstats;
+ int tmp_level = 0;
+ int tmp_qual = 0;
+ int tmp_noise = 0;
+
+ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) != true) {
+ piwstats->qual.qual = 0;
+ piwstats->qual.level = 0;
+ piwstats->qual.noise = 0;
+ /* RTW_INFO("No link level:%d, qual:%d, noise:%d\n", tmp_level, tmp_qual, tmp_noise); */
+ } else {
+#ifdef CONFIG_SIGNAL_DISPLAY_DBM
+ tmp_level = translate_percentage_to_dbm(padapter->recvpriv.signal_strength);
+#else
+#ifdef CONFIG_SIGNAL_SCALE_MAPPING
+ tmp_level = padapter->recvpriv.signal_strength;
+#else
+ {
+ /* Do signal scale mapping when using percentage as the unit of signal strength, since the scale mapping is skipped in odm */
+
+ HAL_DATA_TYPE *pHal = GET_HAL_DATA(padapter);
+
+ tmp_level = (u8)odm_signal_scale_mapping(&pHal->odmpriv, padapter->recvpriv.signal_strength);
+ }
+#endif
+#endif
+
+ tmp_qual = padapter->recvpriv.signal_qual;
+ rtw_get_noise(padapter);
+ tmp_noise = padapter->recvpriv.noise;
+ /* RTW_INFO("level:%d, qual:%d, noise:%d, rssi (%d)\n", tmp_level, tmp_qual, tmp_noise,padapter->recvpriv.rssi); */
+
+ piwstats->qual.level = tmp_level;
+ piwstats->qual.qual = tmp_qual;
+ piwstats->qual.noise = tmp_noise;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14))
+ piwstats->qual.updated = IW_QUAL_ALL_UPDATED ;/* |IW_QUAL_DBM; */
+#else
+#ifdef RTK_DMP_PLATFORM
+ /* IW_QUAL_DBM= 0x8, if driver use this flag, wireless extension will show value of dbm. */
+ /* remove this flag for show percentage 0~100 */
+ piwstats->qual.updated = 0x07;
+#else
+ piwstats->qual.updated = 0x0f;
+#endif
+#endif
+
+#ifdef CONFIG_SIGNAL_DISPLAY_DBM
+ piwstats->qual.updated = piwstats->qual.updated | IW_QUAL_DBM;
+#endif
+
+ return &padapter->iwstats;
+}
+#endif
+
+#ifdef CONFIG_WIRELESS_EXT
+struct iw_handler_def rtw_handlers_def = {
+ .standard = rtw_handlers,
+ .num_standard = sizeof(rtw_handlers) / sizeof(iw_handler),
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) || defined(CONFIG_WEXT_PRIV)
+ .private = rtw_private_handler,
+ .private_args = (struct iw_priv_args *)rtw_private_args,
+ .num_private = sizeof(rtw_private_handler) / sizeof(iw_handler),
+ .num_private_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args),
+#endif
+#if WIRELESS_EXT >= 17
+ .get_wireless_stats = rtw_get_wireless_stats,
+#endif
+};
+#endif
+
+/* copy from net/wireless/wext.c start
+ * ----------------------------------------------------------------
+ *
+ * Calculate size of private arguments
+ */
+static const char iw_priv_type_size[] = {
+ 0, /* IW_PRIV_TYPE_NONE */
+ 1, /* IW_PRIV_TYPE_BYTE */
+ 1, /* IW_PRIV_TYPE_CHAR */
+ 0, /* Not defined */
+ sizeof(__u32), /* IW_PRIV_TYPE_INT */
+ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
+ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
+ 0, /* Not defined */
+};
+
+static int get_priv_size(__u16 args)
+{
+ int num = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ return num * iw_priv_type_size[type];
+}
+/* copy from net/wireless/wext.c end */
+
+
+static int _rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_data)
+{
+ int err = 0;
+ u8 *input = NULL;
+ u32 input_len = 0;
+ const char delim[] = " ";
+ u8 *output = NULL;
+ u32 output_len = 0;
+ u32 count = 0;
+ u8 *buffer = NULL;
+ u32 buffer_len = 0;
+ char *ptr = NULL;
+ u8 cmdname[17] = {0}; /* IFNAMSIZ+1 */
+ u32 cmdlen;
+ s32 len;
+ u8 *extra = NULL;
+ u32 extra_size = 0;
+
+ s32 k;
+ const iw_handler *priv; /* Private ioctl */
+ const struct iw_priv_args *priv_args; /* Private ioctl description */
+ const struct iw_priv_args *mp_priv_args; /*MP Private ioctl description */
+ const struct iw_priv_args *sel_priv_args; /*Selected Private ioctl description */
+ u32 num_priv; /* Number of ioctl */
+ u32 num_priv_args; /* Number of descriptions */
+ u32 num_mp_priv_args; /*Number of MP descriptions */
+ u32 num_sel_priv_args; /*Number of Selected descriptions */
+ iw_handler handler;
+ int temp;
+ int subcmd = 0; /* sub-ioctl index */
+ int offset = 0; /* Space for sub-ioctl index */
+
+ union iwreq_data wdata;
+
+ memcpy(&wdata, wrq_data, sizeof(wdata));
+
+ input_len = wdata.data.length;
+ if (!input_len)
+ return -EINVAL;
+ input = rtw_zmalloc(input_len);
+ if (NULL == input)
+ return -ENOMEM;
+ if (copy_from_user(input, wdata.data.pointer, input_len)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ input[input_len - 1] = '\0';
+ ptr = input;
+ len = input_len;
+
+ if (ptr == NULL) {
+ err = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ sscanf(ptr, "%16s", cmdname);
+ cmdlen = strlen(cmdname);
+ RTW_INFO("%s: cmd=%s\n", __func__, cmdname);
+
+ /* skip command string */
+ if (cmdlen > 0)
+ cmdlen += 1; /* skip one space */
+ ptr += cmdlen;
+ len -= cmdlen;
+ RTW_INFO("%s: parameters=%s\n", __func__, ptr);
+
+ priv = rtw_private_handler;
+ priv_args = rtw_private_args;
+ mp_priv_args = rtw_mp_private_args;
+ num_priv = sizeof(rtw_private_handler) / sizeof(iw_handler);
+ num_priv_args = sizeof(rtw_private_args) / sizeof(struct iw_priv_args);
+ num_mp_priv_args = sizeof(rtw_mp_private_args) / sizeof(struct iw_priv_args);
+
+ if (num_priv_args == 0) {
+ err = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ /* Search the correct ioctl */
+ k = -1;
+ sel_priv_args = priv_args;
+ num_sel_priv_args = num_priv_args;
+ while
+ ((++k < num_sel_priv_args) && strcmp(sel_priv_args[k].name, cmdname))
+ ;
+
+ /* If not found... */
+ if (k == num_sel_priv_args) {
+ k = -1;
+ sel_priv_args = mp_priv_args;
+ num_sel_priv_args = num_mp_priv_args;
+ while
+ ((++k < num_sel_priv_args) && strcmp(sel_priv_args[k].name, cmdname))
+ ;
+
+ if (k == num_sel_priv_args) {
+ err = -EOPNOTSUPP;
+ goto exit;
+ }
+ }
+
+ /* Watch out for sub-ioctls ! */
+ if (sel_priv_args[k].cmd < SIOCDEVPRIVATE) {
+ int j = -1;
+
+ /* Find the matching *real* ioctl */
+ while ((++j < num_priv_args) && ((priv_args[j].name[0] != '\0') ||
+ (priv_args[j].set_args != sel_priv_args[k].set_args) ||
+ (priv_args[j].get_args != sel_priv_args[k].get_args)))
+ ;
+
+ /* If not found... */
+ if (j == num_priv_args) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* Save sub-ioctl number */
+ subcmd = sel_priv_args[k].cmd;
+ /* Reserve one int (simplify alignment issues) */
+ offset = sizeof(__u32);
+ /* Use real ioctl definition from now on */
+ k = j;
+ }
+
+ buffer = rtw_zmalloc(4096);
+ if (NULL == buffer) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* If we have to set some data */
+ if ((priv_args[k].set_args & IW_PRIV_TYPE_MASK) &&
+ (priv_args[k].set_args & IW_PRIV_SIZE_MASK)) {
+ u8 *str;
+
+ switch (priv_args[k].set_args & IW_PRIV_TYPE_MASK) {
+ case IW_PRIV_TYPE_BYTE:
+ /* Fetch args */
+ count = 0;
+ do {
+ str = strsep(&ptr, delim);
+ if (NULL == str)
+ break;
+ sscanf(str, "%i", &temp);
+ buffer[count++] = (u8)temp;
+ } while (1);
+ buffer_len = count;
+
+ /* Number of args to fetch */
+ wdata.data.length = count;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+
+ break;
+
+ case IW_PRIV_TYPE_INT:
+ /* Fetch args */
+ count = 0;
+ do {
+ str = strsep(&ptr, delim);
+ if (NULL == str)
+ break;
+ sscanf(str, "%i", &temp);
+ ((s32 *)buffer)[count++] = (s32)temp;
+ } while (1);
+ buffer_len = count * sizeof(s32);
+
+ /* Number of args to fetch */
+ wdata.data.length = count;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+
+ break;
+
+ case IW_PRIV_TYPE_CHAR:
+ if (len > 0) {
+ /* Size of the string to fetch */
+ wdata.data.length = len;
+ if (wdata.data.length > (priv_args[k].set_args & IW_PRIV_SIZE_MASK))
+ wdata.data.length = priv_args[k].set_args & IW_PRIV_SIZE_MASK;
+
+ /* Fetch string */
+ memcpy(buffer, ptr, wdata.data.length);
+ } else {
+ wdata.data.length = 1;
+ buffer[0] = '\0';
+ }
+ buffer_len = wdata.data.length;
+ break;
+
+ default:
+ RTW_INFO("%s: Not yet implemented...\n", __func__);
+ err = -1;
+ goto exit;
+ }
+
+ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ (wdata.data.length != (priv_args[k].set_args & IW_PRIV_SIZE_MASK))) {
+ RTW_INFO("%s: The command %s needs exactly %d argument(s)...\n",
+ __func__, cmdname, priv_args[k].set_args & IW_PRIV_SIZE_MASK);
+ err = -EINVAL;
+ goto exit;
+ }
+ } /* if args to set */
+ else
+ wdata.data.length = 0L;
+
+ /* Those two tests are important. They define how the driver
+ * will have to handle the data */
+ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ ((get_priv_size(priv_args[k].set_args) + offset) <= IFNAMSIZ)) {
+ /* First case : all SET args fit within wrq */
+ if (offset)
+ wdata.mode = subcmd;
+ memcpy(wdata.name + offset, buffer, IFNAMSIZ - offset);
+ } else {
+ if ((priv_args[k].set_args == 0) &&
+ (priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ)) {
+ /* Second case : no SET args, GET args fit within wrq */
+ if (offset)
+ wdata.mode = subcmd;
+ } else {
+ /* Third case : args won't fit in wrq, or variable number of args */
+ if (copy_to_user(wdata.data.pointer, buffer, buffer_len)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ wdata.data.flags = subcmd;
+ }
+ }
+
+ rtw_mfree(input, input_len);
+ input = NULL;
+
+ extra_size = 0;
+ if (IW_IS_SET(priv_args[k].cmd)) {
+ /* Size of set arguments */
+ extra_size = get_priv_size(priv_args[k].set_args);
+
+ /* Does it fits in iwr ? */
+ if ((priv_args[k].set_args & IW_PRIV_SIZE_FIXED) &&
+ ((extra_size + offset) <= IFNAMSIZ))
+ extra_size = 0;
+ } else {
+ /* Size of get arguments */
+ extra_size = get_priv_size(priv_args[k].get_args);
+
+ /* Does it fits in iwr ? */
+ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (extra_size <= IFNAMSIZ))
+ extra_size = 0;
+ }
+
+ if (extra_size == 0) {
+ extra = (u8 *)&wdata;
+ rtw_mfree(buffer, 4096);
+ buffer = NULL;
+ } else
+ extra = buffer;
+
+ handler = priv[priv_args[k].cmd - SIOCIWFIRSTPRIV];
+ err = handler(dev, NULL, &wdata, extra);
+
+ /* If we have to get some data */
+ if ((priv_args[k].get_args & IW_PRIV_TYPE_MASK) &&
+ (priv_args[k].get_args & IW_PRIV_SIZE_MASK)) {
+ int j;
+ int n = 0; /* number of args */
+ u8 str[20] = {0};
+
+ /* Check where is the returned data */
+ if ((priv_args[k].get_args & IW_PRIV_SIZE_FIXED) &&
+ (get_priv_size(priv_args[k].get_args) <= IFNAMSIZ))
+ n = priv_args[k].get_args & IW_PRIV_SIZE_MASK;
+ else
+ n = wdata.data.length;
+
+ output = rtw_zmalloc(4096);
+ if (NULL == output) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ switch (priv_args[k].get_args & IW_PRIV_TYPE_MASK) {
+ case IW_PRIV_TYPE_BYTE:
+ /* Display args */
+ for (j = 0; j < n; j++) {
+ sprintf(str, "%d ", extra[j]);
+ len = strlen(str);
+ output_len = strlen(output);
+ if ((output_len + len + 1) > 4096) {
+ err = -E2BIG;
+ goto exit;
+ }
+ memcpy(output + output_len, str, len);
+ }
+ break;
+
+ case IW_PRIV_TYPE_INT:
+ /* Display args */
+ for (j = 0; j < n; j++) {
+ sprintf(str, "%d ", ((__s32 *)extra)[j]);
+ len = strlen(str);
+ output_len = strlen(output);
+ if ((output_len + len + 1) > 4096) {
+ err = -E2BIG;
+ goto exit;
+ }
+ memcpy(output + output_len, str, len);
+ }
+ break;
+
+ case IW_PRIV_TYPE_CHAR:
+ /* Display args */
+ memcpy(output, extra, n);
+ break;
+
+ default:
+ RTW_INFO("%s: Not yet implemented...\n", __func__);
+ err = -1;
+ goto exit;
+ }
+
+ output_len = strlen(output) + 1;
+ wrq_data->data.length = output_len;
+ if (copy_to_user(wrq_data->data.pointer, output, output_len)) {
+ err = -EFAULT;
+ goto exit;
+ }
+ } /* if args to set */
+ else
+ wrq_data->data.length = 0;
+
+exit:
+ if (input)
+ rtw_mfree(input, input_len);
+ if (buffer)
+ rtw_mfree(buffer, 4096);
+ if (output)
+ rtw_mfree(output, 4096);
+
+ return err;
+}
+
+#ifdef CONFIG_COMPAT
+static int rtw_ioctl_compat_wext_private(struct net_device *dev, struct ifreq *rq)
+{
+ struct compat_iw_point iwp_compat;
+ union iwreq_data wrq_data;
+ int err = 0;
+ RTW_INFO("%s:...\n", __func__);
+ if (copy_from_user(&iwp_compat, rq->ifr_ifru.ifru_data, sizeof(struct compat_iw_point)))
+ return -EFAULT;
+
+ wrq_data.data.pointer = compat_ptr(iwp_compat.pointer);
+ wrq_data.data.length = iwp_compat.length;
+ wrq_data.data.flags = iwp_compat.flags;
+
+ err = _rtw_ioctl_wext_private(dev, &wrq_data);
+
+ iwp_compat.pointer = ptr_to_compat(wrq_data.data.pointer);
+ iwp_compat.length = wrq_data.data.length;
+ iwp_compat.flags = wrq_data.data.flags;
+ if (copy_to_user(rq->ifr_ifru.ifru_data, &iwp_compat, sizeof(struct compat_iw_point)))
+ return -EFAULT;
+
+ return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int rtw_ioctl_standard_wext_private(struct net_device *dev, struct ifreq *rq)
+{
+ struct iw_point *iwp;
+ struct ifreq ifrq;
+ union iwreq_data wrq_data;
+ int err = 0;
+ iwp = &wrq_data.data;
+ RTW_INFO("%s:...\n", __func__);
+ if (copy_from_user(iwp, rq->ifr_ifru.ifru_data, sizeof(struct iw_point)))
+ return -EFAULT;
+
+ err = _rtw_ioctl_wext_private(dev, &wrq_data);
+
+ if (copy_to_user(rq->ifr_ifru.ifru_data, iwp, sizeof(struct iw_point)))
+ return -EFAULT;
+
+ return err;
+}
+
+static int rtw_ioctl_wext_private(struct net_device *dev, struct ifreq *rq)
+{
+#ifdef CONFIG_COMPAT
+#if (KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE)
+ if (is_compat_task())
+#else
+ if (in_compat_syscall())
+#endif
+ return rtw_ioctl_compat_wext_private(dev, rq);
+ else
+#endif /* CONFIG_COMPAT */
+ return rtw_ioctl_standard_wext_private(dev, rq);
+}
+
+int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct iwreq *wrq = (struct iwreq *)rq;
+ int ret = 0;
+
+ switch (cmd) {
+ case RTL_IOCTL_WPA_SUPPLICANT:
+ ret = wpa_supplicant_ioctl(dev, &wrq->u.data);
+ break;
+#ifdef CONFIG_AP_MODE
+ case RTL_IOCTL_HOSTAPD:
+ ret = rtw_hostapd_ioctl(dev, &wrq->u.data);
+ break;
+#ifdef CONFIG_WIRELESS_EXT
+ case SIOCSIWMODE:
+ ret = rtw_wx_set_mode(dev, NULL, &wrq->u, NULL);
+ break;
+#endif
+#endif /* CONFIG_AP_MODE */
+ case SIOCDEVPRIVATE:
+ ret = rtw_ioctl_wext_private(dev, rq);
+ break;
+ case (SIOCDEVPRIVATE+1):
+ ret = rtw_android_priv_cmd(dev, rq, cmd);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_mp.c b/drivers/staging/rtl8188eu/os_dep/ioctl_mp.c
new file mode 100644
index 000000000000..d08bb3bffdfb
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/ioctl_mp.c
@@ -0,0 +1,2028 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#if defined(CONFIG_MP_INCLUDED)
+
+#include <drv_types.h>
+#include <rtw_mp.h>
+#include <rtw_mp_ioctl.h>
+#include "../../hal/phydm_precomp.h"
+
+/*
+ * Input Format: %s,%d,%d
+ * %s is width, could be
+ * "b" for 1 byte
+ * "w" for WORD (2 bytes)
+ * "dw" for DWORD (4 bytes)
+ * 1st %d is address(offset)
+ * 2st %d is data to write
+ */
+int rtw_mp_write_reg(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ char *pch, *pnext, *ptmp;
+ char *width_str;
+ char width, buf[5];
+ u32 addr, data;
+ int ret;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ char input[128];
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ memset(extra, 0, wrqu->length);
+
+ pch = input;
+
+ pnext = strpbrk(pch, " ,.-");
+ if (pnext == NULL)
+ return -EINVAL;
+ *pnext = 0;
+ width_str = pch;
+
+ pch = pnext + 1;
+ pnext = strpbrk(pch, " ,.-");
+ if (pnext == NULL)
+ return -EINVAL;
+ *pnext = 0;
+ /*addr = simple_strtoul(pch, &ptmp, 16);
+ memset(buf, '\0', sizeof(buf));
+ memcpy(buf, pch, pnext-pch);
+ ret = kstrtoul(buf, 16, &addr);*/
+ ret = sscanf(pch, "%x", &addr);
+ if (addr > 0x3FFF)
+ return -EINVAL;
+
+ pch = pnext + 1;
+ pnext = strpbrk(pch, " ,.-");
+ if ((pch - input) >= wrqu->length)
+ return -EINVAL;
+ /*data = simple_strtoul(pch, &ptmp, 16);*/
+ ret = sscanf(pch, "%x", &data);
+ RTW_INFO("data=%x,addr=%x\n", (u32)data, (u32)addr);
+ ret = 0;
+ width = width_str[0];
+ switch (width) {
+ case 'b':
+ /* 1 byte*/
+ if (data > 0xFF) {
+ ret = -EINVAL;
+ break;
+ }
+ rtw_write8(padapter, addr, data);
+ break;
+ case 'w':
+ /* 2 bytes*/
+ if (data > 0xFFFF) {
+ ret = -EINVAL;
+ break;
+ }
+ rtw_write16(padapter, addr, data);
+ break;
+ case 'd':
+ /* 4 bytes*/
+ rtw_write32(padapter, addr, data);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ * Input Format: %s,%d
+ * %s is width, could be
+ * "b" for 1 byte
+ * "w" for WORD (2 bytes)
+ * "dw" for DWORD (4 bytes)
+ * %d is address(offset)
+ *
+ * Return:
+ * %d for data readed
+ */
+int rtw_mp_read_reg(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ char input[128];
+ char *pch, *pnext, *ptmp;
+ char *width_str;
+ char width;
+ char data[20], tmp[20], buf[3];
+ u32 addr = 0, strtout = 0;
+ u32 i = 0, j = 0, ret = 0, data32 = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ memset(extra, 0, wrqu->length);
+ memset(data, '\0', sizeof(data));
+ memset(tmp, '\0', sizeof(tmp));
+ pch = input;
+ pnext = strpbrk(pch, " ,.-");
+ if (pnext == NULL)
+ return -EINVAL;
+ *pnext = 0;
+ width_str = pch;
+
+ pch = pnext + 1;
+
+ ret = sscanf(pch, "%x", &addr);
+ if (addr > 0x3FFF)
+ return -EINVAL;
+
+ ret = 0;
+ width = width_str[0];
+
+ switch (width) {
+ case 'b':
+ data32 = rtw_read8(padapter, addr);
+ RTW_INFO("%x\n", data32);
+ sprintf(extra, "%d", data32);
+ wrqu->length = strlen(extra);
+ break;
+ case 'w':
+ /* 2 bytes*/
+ sprintf(data, "%04x\n", rtw_read16(padapter, addr));
+
+ for (i = 0 ; i <= strlen(data) ; i++) {
+ if (i % 2 == 0) {
+ tmp[j] = ' ';
+ j++;
+ }
+ if (data[i] != '\0')
+ tmp[j] = data[i];
+
+ j++;
+ }
+ pch = tmp;
+ RTW_INFO("pch=%s", pch);
+
+ while (*pch != '\0') {
+ pnext = strpbrk(pch, " ");
+ if (!pnext || ((pnext - tmp) > 4))
+ break;
+
+ pnext++;
+ if (*pnext != '\0') {
+ /*strtout = simple_strtoul(pnext , &ptmp, 16);*/
+ ret = sscanf(pnext, "%x", &strtout);
+ sprintf(extra + strlen(extra), " %d", strtout);
+ } else
+ break;
+ pch = pnext;
+ }
+ wrqu->length = strlen(extra);
+ break;
+ case 'd':
+ /* 4 bytes */
+ sprintf(data, "%08x", rtw_read32(padapter, addr));
+ /*add read data format blank*/
+ for (i = 0 ; i <= strlen(data) ; i++) {
+ if (i % 2 == 0) {
+ tmp[j] = ' ';
+ j++;
+ }
+ if (data[i] != '\0')
+ tmp[j] = data[i];
+
+ j++;
+ }
+ pch = tmp;
+ RTW_INFO("pch=%s", pch);
+
+ while (*pch != '\0') {
+ pnext = strpbrk(pch, " ");
+ if (!pnext)
+ break;
+
+ pnext++;
+ if (*pnext != '\0') {
+ ret = sscanf(pnext, "%x", &strtout);
+ sprintf(extra + strlen(extra), " %d", strtout);
+ } else
+ break;
+ pch = pnext;
+ }
+ wrqu->length = strlen(extra);
+ break;
+
+ default:
+ wrqu->length = 0;
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+
+/*
+ * Input Format: %d,%x,%x
+ * %d is RF path, should be smaller than MAX_RF_PATH_NUMS
+ * 1st %x is address(offset)
+ * 2st %x is data to write
+ */
+int rtw_mp_write_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+
+ u32 path, addr, data;
+ int ret;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ char input[128];
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ memset(input, 0, wrqu->length);
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+
+ ret = sscanf(input, "%d,%x,%x", &path, &addr, &data);
+ if (ret < 3)
+ return -EINVAL;
+
+ if (path >= GET_HAL_RFPATH_NUM(padapter))
+ return -EINVAL;
+ if (addr > 0xFF)
+ return -EINVAL;
+ if (data > 0xFFFFF)
+ return -EINVAL;
+
+ memset(extra, 0, wrqu->length);
+
+ write_rfreg(padapter, path, addr, data);
+
+ sprintf(extra, "write_rf completed\n");
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+/*
+ * Input Format: %d,%x
+ * %d is RF path, should be smaller than MAX_RF_PATH_NUMS
+ * %x is address(offset)
+ *
+ * Return:
+ * %d for data readed
+ */
+int rtw_mp_read_rf(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ char input[128];
+ char *pch, *pnext, *ptmp;
+ char data[20], tmp[20], buf[3];
+ u32 path, addr, strtou;
+ u32 ret, i = 0 , j = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ memset(input, 0, wrqu->length);
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ ret = sscanf(input, "%d,%x", &path, &addr);
+ if (ret < 2)
+ return -EINVAL;
+
+ if (path >= GET_HAL_RFPATH_NUM(padapter))
+ return -EINVAL;
+ if (addr > 0xFF)
+ return -EINVAL;
+
+ memset(extra, 0, wrqu->length);
+
+ sprintf(data, "%08x", read_rfreg(padapter, path, addr));
+ /*add read data format blank*/
+ for (i = 0 ; i <= strlen(data) ; i++) {
+ if (i % 2 == 0) {
+ tmp[j] = ' ';
+ j++;
+ }
+ tmp[j] = data[i];
+ j++;
+ }
+ pch = tmp;
+ RTW_INFO("pch=%s", pch);
+
+ while (*pch != '\0') {
+ pnext = strpbrk(pch, " ");
+ if (!pnext)
+ break;
+ pnext++;
+ if (*pnext != '\0') {
+ /*strtou =simple_strtoul(pnext , &ptmp, 16);*/
+ ret = sscanf(pnext, "%x", &strtou);
+ sprintf(extra + strlen(extra), " %d", strtou);
+ } else
+ break;
+ pch = pnext;
+ }
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+int rtw_mp_start(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ int ret = 0;
+ u8 val8;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct hal_ops *pHalFunc = &padapter->hal_func;
+
+ rtw_pm_set_ips(padapter, IPS_NONE);
+ LeaveAllPowerSaveMode(padapter);
+
+ if (rtw_mi_check_fwstate(padapter, _FW_UNDER_SURVEY))
+ rtw_mi_scan_abort(padapter, false);
+
+ if (rtw_mp_cmd(padapter, MP_START, RTW_CMDF_WAIT_ACK) != _SUCCESS)
+ ret = -EPERM;
+
+ memset(extra, 0, wrqu->length);
+ sprintf(extra, "mp_start %s\n", ret == 0 ? "ok" : "fail");
+ wrqu->length = strlen(extra);
+
+ return ret;
+}
+
+
+
+int rtw_mp_stop(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ int ret = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ struct hal_ops *pHalFunc = &padapter->hal_func;
+
+ if (rtw_mp_cmd(padapter, MP_STOP, RTW_CMDF_WAIT_ACK) != _SUCCESS)
+ ret = -EPERM;
+
+ memset(extra, 0, wrqu->length);
+ sprintf(extra, "mp_stop %s\n", ret == 0 ? "ok" : "fail");
+ wrqu->length = strlen(extra);
+
+ return ret;
+}
+
+
+int rtw_mp_rate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 rate = MPT_RATE_1M;
+ u8 input[128];
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ rate = rtw_mpRateParseFunc(padapter, input);
+ padapter->mppriv.rateidx = rate;
+
+ if (rate == 0 && strcmp(input, "1M") != 0) {
+ rate = rtw_atoi(input);
+ padapter->mppriv.rateidx = MRateToHwRate(rate);
+ /*if (rate <= 0x7f)
+ rate = wifirate2_ratetbl_inx((u8)rate);
+ else if (rate < 0xC8)
+ rate = (rate - 0x79 + MPT_RATE_MCS0);
+ HT rate 0x80(MCS0) ~ 0x8F(MCS15) ~ 0x9F(MCS31) 128~159
+ VHT1SS~2SS rate 0xA0 (VHT1SS_MCS0 44) ~ 0xB3 (VHT2SS_MCS9 #63) 160~179
+ VHT rate 0xB4 (VHT3SS_MCS0 64) ~ 0xC7 (VHT2SS_MCS9 #83) 180~199
+ else
+ VHT rate 0x90(VHT1SS_MCS0) ~ 0x99(VHT1SS_MCS9) 144~153
+ rate =(rate - MPT_RATE_VHT1SS_MCS0);
+ */
+ }
+ memset(extra, 0, wrqu->length);
+
+ sprintf(extra, "Set data rate to %s index %d" , input, padapter->mppriv.rateidx);
+ RTW_INFO("%s: %s rate index=%d\n", __func__, input, padapter->mppriv.rateidx);
+
+ if (padapter->mppriv.rateidx >= DESC_RATEVHTSS4MCS9)
+ return -EINVAL;
+
+ pMptCtx->mpt_rate_index = HwRateToMPTRate(padapter->mppriv.rateidx);
+ SetDataRate(padapter);
+
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_mp_channel(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ u8 input[128];
+ u32 channel = 1;
+ int cur_ch_offset;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ channel = rtw_atoi(input);
+ /*RTW_INFO("%s: channel=%d\n", __func__, channel);*/
+ memset(extra, 0, wrqu->length);
+ sprintf(extra, "Change channel %d to channel %d", padapter->mppriv.channel , channel);
+ padapter->mppriv.channel = channel;
+ SetChannel(padapter);
+ pHalData->current_channel = channel;
+
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_mp_bandwidth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 bandwidth = 0, sg = 0;
+ int cur_ch_offset;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ u8 input[128];
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ if (sscanf(input, "40M=%d,shortGI=%d", &bandwidth, &sg) > 0)
+ RTW_INFO("%s: bw=%d sg=%d\n", __func__, bandwidth , sg);
+
+ if (bandwidth == 1)
+ bandwidth = CHANNEL_WIDTH_40;
+ else if (bandwidth == 2)
+ bandwidth = CHANNEL_WIDTH_80;
+
+ padapter->mppriv.bandwidth = (u8)bandwidth;
+ padapter->mppriv.preamble = sg;
+ memset(extra, 0, wrqu->length);
+ sprintf(extra, "Change BW %d to BW %d\n", pHalData->current_channel_bw , bandwidth);
+
+ SetBandwidth(padapter);
+ pHalData->current_channel_bw = bandwidth;
+ /*cur_ch_offset = rtw_get_offset_by_ch(padapter->mppriv.channel);*/
+ /*set_channel_bwmode(padapter, padapter->mppriv.channel, cur_ch_offset, bandwidth);*/
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+int rtw_mp_txpower_index(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ char input[128];
+ u32 rfpath;
+ u32 txpower_inx;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ rfpath = rtw_atoi(input);
+ txpower_inx = mpt_ProQueryCalTxPower(padapter, rfpath);
+ sprintf(extra, " %d", txpower_inx);
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+int rtw_mp_txpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 idx_a = 0, idx_b = 0, idx_c = 0, idx_d = 0, status = 0;
+ int MsetPower = 1;
+ u8 input[128];
+
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ MsetPower = strncmp(input, "off", 3);
+ if (MsetPower == 0) {
+ padapter->mppriv.bSetTxPower = 0;
+ sprintf(extra, "MP Set power off");
+ } else {
+ if (sscanf(input, "patha=%d,pathb=%d,pathc=%d,pathd=%d", &idx_a, &idx_b, &idx_c, &idx_d) < 3)
+ RTW_INFO("Invalid format on line %s ,patha=%d,pathb=%d,pathc=%d,pathd=%d\n", input , idx_a , idx_b , idx_c , idx_d);
+
+ sprintf(extra, "Set power level path_A:%d path_B:%d path_C:%d path_D:%d", idx_a , idx_b , idx_c , idx_d);
+ padapter->mppriv.txpoweridx = (u8)idx_a;
+
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_A] = (u8)idx_a;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_B] = (u8)idx_b;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_C] = (u8)idx_c;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_D] = (u8)idx_d;
+ padapter->mppriv.bSetTxPower = 1;
+
+ SetTxPower(padapter);
+ }
+
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_mp_ant_tx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 i;
+ u8 input[128];
+ u16 antenna = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ sprintf(extra, "switch Tx antenna to %s", input);
+
+ for (i = 0; i < strlen(input); i++) {
+ switch (input[i]) {
+ case 'a':
+ antenna |= ANTENNA_A;
+ break;
+ case 'b':
+ antenna |= ANTENNA_B;
+ break;
+ case 'c':
+ antenna |= ANTENNA_C;
+ break;
+ case 'd':
+ antenna |= ANTENNA_D;
+ break;
+ }
+ }
+ /*antenna |= BIT(extra[i]-'a');*/
+ RTW_INFO("%s: antenna=0x%x\n", __func__, antenna);
+ padapter->mppriv.antenna_tx = antenna;
+ padapter->mppriv.antenna_rx = antenna;
+ /*RTW_INFO("%s:mppriv.antenna_rx=%d\n", __func__, padapter->mppriv.antenna_tx);*/
+ pHalData->antenna_tx_path = antenna;
+
+ SetAntenna(padapter);
+
+ wrqu->length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_mp_ant_rx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 i;
+ u16 antenna = 0;
+ u8 input[128];
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+ /*RTW_INFO("%s: input=%s\n", __func__, input);*/
+ memset(extra, 0, wrqu->length);
+
+ sprintf(extra, "switch Rx antenna to %s", input);
+
+ for (i = 0; i < strlen(input); i++) {
+ switch (input[i]) {
+ case 'a':
+ antenna |= ANTENNA_A;
+ break;
+ case 'b':
+ antenna |= ANTENNA_B;
+ break;
+ case 'c':
+ antenna |= ANTENNA_C;
+ break;
+ case 'd':
+ antenna |= ANTENNA_D;
+ break;
+ }
+ }
+
+ RTW_INFO("%s: antenna=0x%x\n", __func__, antenna);
+ padapter->mppriv.antenna_tx = antenna;
+ padapter->mppriv.antenna_rx = antenna;
+ pHalData->AntennaRxPath = antenna;
+ /*RTW_INFO("%s:mppriv.antenna_rx=%d\n", __func__, padapter->mppriv.antenna_rx);*/
+ SetAntenna(padapter);
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+int rtw_set_ctx_destAddr(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ int jj, kk = 0;
+
+ struct pkt_attrib *pattrib;
+ struct mp_priv *pmp_priv;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ pmp_priv = &padapter->mppriv;
+ pattrib = &pmp_priv->tx.attrib;
+
+ if (strlen(extra) < 5)
+ return _FAIL;
+
+ RTW_INFO("%s: in=%s\n", __func__, extra);
+ for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3)
+ pattrib->dst[jj] = key_2char2num(extra[kk], extra[kk + 1]);
+
+ RTW_INFO("pattrib->dst:%x %x %x %x %x %x\n", pattrib->dst[0], pattrib->dst[1], pattrib->dst[2], pattrib->dst[3], pattrib->dst[4], pattrib->dst[5]);
+ return 0;
+}
+
+
+
+int rtw_mp_ctx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 pkTx = 1;
+ int countPkTx = 1, cotuTx = 1, CarrSprTx = 1, scTx = 1, sgleTx = 1, stop = 1;
+ u32 bStartTest = 1;
+ u32 count = 0, pktinterval = 0, pktlen = 0;
+ u8 status;
+ struct mp_priv *pmp_priv;
+ struct pkt_attrib *pattrib;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+
+ pmp_priv = &padapter->mppriv;
+ pattrib = &pmp_priv->tx.attrib;
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ RTW_INFO("%s: in=%s\n", __func__, extra);
+#ifdef CONFIG_CONCURRENT_MODE
+ if (!is_primary_adapter(padapter)) {
+ sprintf(extra, "Error: MP mode can't support Virtual Adapter, Please to use main Adapter.\n");
+ wrqu->length = strlen(extra);
+ return 0;
+ }
+#endif
+ countPkTx = strncmp(extra, "count=", 5); /* strncmp true is 0*/
+ cotuTx = strncmp(extra, "background", 20);
+ CarrSprTx = strncmp(extra, "background,cs", 20);
+ scTx = strncmp(extra, "background,sc", 20);
+ sgleTx = strncmp(extra, "background,stone", 20);
+ pkTx = strncmp(extra, "background,pkt", 20);
+ stop = strncmp(extra, "stop", 4);
+ if (sscanf(extra, "count=%d,pkt", &count) > 0)
+ RTW_INFO("count= %d\n", count);
+ if (sscanf(extra, "pktinterval=%d", &pktinterval) > 0)
+ RTW_INFO("pktinterval= %d\n", pktinterval);
+
+ if (sscanf(extra, "pktlen=%d", &pktlen) > 0)
+ RTW_INFO("pktlen= %d\n", pktlen);
+
+ if (!memcmp(extra, "destmac=", 8)) {
+ wrqu->length -= 8;
+ rtw_set_ctx_destAddr(dev, info, wrqu, &extra[8]);
+ sprintf(extra, "Set dest mac OK !\n");
+ return 0;
+ }
+
+ /*RTW_INFO("%s: count=%d countPkTx=%d cotuTx=%d CarrSprTx=%d scTx=%d sgleTx=%d pkTx=%d stop=%d\n", __func__, count, countPkTx, cotuTx, CarrSprTx, pkTx, sgleTx, scTx, stop);*/
+ memset(extra, '\0', strlen(extra));
+
+ if (pktinterval != 0) {
+ sprintf(extra, "Pkt Interval = %d", pktinterval);
+ padapter->mppriv.pktInterval = pktinterval;
+ wrqu->length = strlen(extra);
+ return 0;
+ }
+ if (pktlen != 0) {
+ sprintf(extra, "Pkt len = %d", pktlen);
+ pattrib->pktlen = pktlen;
+ wrqu->length = strlen(extra);
+ return 0;
+ }
+ if (stop == 0) {
+ bStartTest = 0; /* To set Stop*/
+ pmp_priv->tx.stop = 1;
+ sprintf(extra, "Stop continuous Tx");
+ odm_write_dig(&pHalData->odmpriv, 0x20);
+ } else {
+ bStartTest = 1;
+ odm_write_dig(&pHalData->odmpriv, 0x7f);
+ if (pmp_priv->mode != MP_ON) {
+ if (pmp_priv->tx.stop != 1) {
+ RTW_INFO("%s: MP_MODE != ON %d\n", __func__, pmp_priv->mode);
+ return -EFAULT;
+ }
+ }
+ }
+
+ pmp_priv->tx.count = count;
+
+ if (pkTx == 0 || countPkTx == 0)
+ pmp_priv->mode = MP_PACKET_TX;
+ if (sgleTx == 0)
+ pmp_priv->mode = MP_SINGLE_TONE_TX;
+ if (cotuTx == 0)
+ pmp_priv->mode = MP_CONTINUOUS_TX;
+ if (CarrSprTx == 0)
+ pmp_priv->mode = MP_CARRIER_SUPPRISSION_TX;
+ if (scTx == 0)
+ pmp_priv->mode = MP_SINGLE_CARRIER_TX;
+
+ status = rtw_mp_pretx_proc(padapter, bStartTest, extra);
+
+ wrqu->length = strlen(extra);
+ return status;
+}
+
+
+
+int rtw_mp_disable_bt_coexist(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = (PADAPTER)rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct hal_ops *pHalFunc = &padapter->hal_func;
+
+ u8 input[128];
+ u32 bt_coexist;
+
+ if (wrqu->data.length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+
+ bt_coexist = rtw_atoi(input);
+
+ if (bt_coexist == 0) {
+ RTW_INFO("Set OID_RT_SET_DISABLE_BT_COEXIST: disable BT_COEXIST\n");
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_HaltNotify(padapter);
+ rtw_btcoex_SetManualControl(padapter, true);
+ /* Force to switch Antenna to WiFi*/
+ rtw_write16(padapter, 0x870, 0x300);
+ rtw_write16(padapter, 0x860, 0x110);
+#endif
+ /* CONFIG_BT_COEXIST */
+ } else {
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SetManualControl(padapter, false);
+#endif
+ }
+
+ return 0;
+}
+
+
+int rtw_mp_arx(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ int bStartRx = 0, bStopRx = 0, bQueryPhy = 0, bQueryMac = 0, bSetBssid = 0;
+ int bmac_filter = 0, bfilter_init = 0, bmon = 0, bSmpCfg = 0, bloopbk = 0;
+ u8 input[128];
+ char *pch, *ptmp, *token, *tmp[2] = {NULL, NULL};
+ u32 i = 0, ii = 0, jj = 0, kk = 0, cnts = 0, ret;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ struct mp_priv *pmppriv = &padapter->mppriv;
+ struct dbg_rx_counter rx_counter;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ RTW_INFO("%s: %s\n", __func__, input);
+#ifdef CONFIG_CONCURRENT_MODE
+ if (!is_primary_adapter(padapter)) {
+ sprintf(extra, "Error: MP mode can't support Virtual Adapter, Please to use main Adapter.\n");
+ wrqu->length = strlen(extra);
+ return 0;
+ }
+#endif
+ bStartRx = (strncmp(input, "start", 5) == 0) ? 1 : 0; /* strncmp true is 0*/
+ bStopRx = (strncmp(input, "stop", 5) == 0) ? 1 : 0; /* strncmp true is 0*/
+ bQueryPhy = (strncmp(input, "phy", 3) == 0) ? 1 : 0; /* strncmp true is 0*/
+ bQueryMac = (strncmp(input, "mac", 3) == 0) ? 1 : 0; /* strncmp true is 0*/
+ bSetBssid = (strncmp(input, "setbssid=", 8) == 0) ? 1 : 0; /* strncmp true is 0*/
+ /*bfilter_init = (strncmp(input, "filter_init",11)==0)?1:0;*/
+ bmac_filter = (strncmp(input, "accept_mac", 10) == 0) ? 1 : 0;
+ bmon = (strncmp(input, "mon=", 4) == 0) ? 1 : 0;
+ bSmpCfg = (strncmp(input , "smpcfg=" , 7) == 0) ? 1 : 0;
+ pmppriv->bloopback = (strncmp(input, "loopbk", 6) == 0) ? 1 : 0; /* strncmp true is 0*/
+
+ if (bSetBssid == 1) {
+ pch = input;
+ while ((token = strsep(&pch, "=")) != NULL) {
+ if (i > 1)
+ break;
+ tmp[i] = token;
+ i++;
+ }
+ if ((tmp[0] != NULL) && (tmp[1] != NULL)) {
+ cnts = strlen(tmp[1]) / 2;
+ if (cnts < 1)
+ return -EFAULT;
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: data=%s\n", __func__, tmp[1]);
+ for (jj = 0, kk = 0; jj < cnts ; jj++, kk += 2) {
+ pmppriv->network_macaddr[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+ RTW_INFO("network_macaddr[%d]=%x\n", jj, pmppriv->network_macaddr[jj]);
+ }
+ } else
+ return -EFAULT;
+
+ pmppriv->bSetRxBssid = true;
+ }
+
+ if (bmac_filter) {
+ pmppriv->bmac_filter = bmac_filter;
+ pch = input;
+ while ((token = strsep(&pch, "=")) != NULL) {
+ if (i > 1)
+ break;
+ tmp[i] = token;
+ i++;
+ }
+ if ((tmp[0] != NULL) && (tmp[1] != NULL)) {
+ cnts = strlen(tmp[1]) / 2;
+ if (cnts < 1)
+ return -EFAULT;
+ RTW_INFO("%s: cnts=%d\n", __func__, cnts);
+ RTW_INFO("%s: data=%s\n", __func__, tmp[1]);
+ for (jj = 0, kk = 0; jj < cnts ; jj++, kk += 2) {
+ pmppriv->mac_filter[jj] = key_2char2num(tmp[1][kk], tmp[1][kk + 1]);
+ RTW_INFO("%s mac_filter[%d]=%x\n", __func__, jj, pmppriv->mac_filter[jj]);
+ }
+ } else
+ return -EFAULT;
+
+ }
+
+ if (bStartRx) {
+ sprintf(extra, "start");
+ SetPacketRx(padapter, bStartRx, false);
+ } else if (bStopRx) {
+ SetPacketRx(padapter, bStartRx, false);
+ pmppriv->bmac_filter = false;
+ pmppriv->bSetRxBssid = false;
+ sprintf(extra, "Received packet OK:%d CRC error:%d ,Filter out:%d", padapter->mppriv.rx_pktcount, padapter->mppriv.rx_crcerrpktcount, padapter->mppriv.rx_pktcount_filter_out);
+ } else if (bQueryPhy) {
+ memset(&rx_counter, 0, sizeof(struct dbg_rx_counter));
+ rtw_dump_phy_rx_counters(padapter, &rx_counter);
+
+ RTW_INFO("%s: OFDM_FA =%d\n", __func__, rx_counter.rx_ofdm_fa);
+ RTW_INFO("%s: CCK_FA =%d\n", __func__, rx_counter.rx_cck_fa);
+ sprintf(extra, "Phy Received packet OK:%d CRC error:%d FA Counter: %d", rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, rx_counter.rx_cck_fa + rx_counter.rx_ofdm_fa);
+
+
+ } else if (bQueryMac) {
+ memset(&rx_counter, 0, sizeof(struct dbg_rx_counter));
+ rtw_dump_mac_rx_counters(padapter, &rx_counter);
+ sprintf(extra, "Mac Received packet OK: %d , CRC error: %d , Drop Packets: %d\n",
+ rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, rx_counter.rx_pkt_drop);
+
+ }
+
+ if (bmon == 1) {
+ ret = sscanf(input, "mon=%d", &bmon);
+
+ if (bmon == 1) {
+ pmppriv->rx_bindicatePkt = true;
+ sprintf(extra, "Indicating Receive Packet to network start\n");
+ } else {
+ pmppriv->rx_bindicatePkt = false;
+ sprintf(extra, "Indicating Receive Packet to network Stop\n");
+ }
+ }
+ if (bSmpCfg == 1) {
+ ret = sscanf(input, "smpcfg=%d", &bSmpCfg);
+
+ if (bSmpCfg == 1) {
+ pmppriv->bRTWSmbCfg = true;
+ sprintf(extra , "Indicate By Simple Config Format\n");
+ SetPacketRx(padapter, true, true);
+ } else {
+ pmppriv->bRTWSmbCfg = false;
+ sprintf(extra , "Indicate By Normal Format\n");
+ SetPacketRx(padapter, true, false);
+ }
+ }
+
+ if (pmppriv->bloopback == true) {
+ sprintf(extra , "Enter MAC LoopBack mode\n");
+ _rtw_write32(padapter, 0x100, 0xB0106FF);
+ RTW_INFO("0x100 :0x%x" , _rtw_read32(padapter, 0x100));
+ _rtw_write16(padapter, 0x608, 0x30c);
+ RTW_INFO("0x100 :0x%x" , _rtw_read32(padapter, 0x608));
+ }
+
+ wrqu->length = strlen(extra) + 1;
+
+ return 0;
+}
+
+
+int rtw_mp_trx_query(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u32 txok, txfail, rxok, rxfail, rxfilterout;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+ RT_PMAC_TX_INFO PMacTxInfo = pMptCtx->PMacTxInfo;
+
+ if (PMacTxInfo.bEnPMacTx == true)
+ txok = hal_mpt_query_phytxok(padapter);
+ else
+ txok = padapter->mppriv.tx.sended;
+
+ txfail = 0;
+ rxok = padapter->mppriv.rx_pktcount;
+ rxfail = padapter->mppriv.rx_crcerrpktcount;
+ rxfilterout = padapter->mppriv.rx_pktcount_filter_out;
+
+ memset(extra, '\0', 128);
+
+ sprintf(extra, "Tx OK:%d, Tx Fail:%d, Rx OK:%d, CRC error:%d ,Rx Filter out:%d\n", txok, txfail, rxok, rxfail, rxfilterout);
+
+ wrqu->length = strlen(extra) + 1;
+
+ return 0;
+}
+
+
+int rtw_mp_pwrtrk(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 enable;
+ u32 thermal;
+ s32 ret;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ u8 input[128];
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ memset(extra, 0, wrqu->length);
+
+ enable = 1;
+ if (wrqu->length > 1) {
+ /* not empty string*/
+ if (strncmp(input, "stop", 4) == 0) {
+ enable = 0;
+ sprintf(extra, "mp tx power tracking stop");
+ } else if (sscanf(input, "ther=%d", &thermal) == 1) {
+ ret = SetThermalMeter(padapter, (u8)thermal);
+ if (ret == _FAIL)
+ return -EPERM;
+ sprintf(extra, "mp tx power tracking start,target value=%d ok", thermal);
+ } else
+ return -EINVAL;
+ }
+
+ ret = SetPowerTracking(padapter, enable);
+ if (ret == _FAIL)
+ return -EPERM;
+
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+
+int rtw_mp_psd(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ u8 input[128];
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ strcpy(extra, input);
+
+ wrqu->length = mp_query_psd(padapter, extra);
+
+ return 0;
+}
+
+
+int rtw_mp_thermal(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ u8 val;
+ int bwrite = 1;
+ u16 addr = EEPROM_THERMAL_METER_88E;
+ u16 cnt = 1;
+ u16 max_available_size = 0;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ if (copy_from_user(extra, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ bwrite = strncmp(extra, "write", 6);/* strncmp true is 0*/
+
+ GetThermalMeter(padapter, &val);
+
+ if (bwrite == 0) {
+ /*RTW_INFO("to write val:%d",val);*/
+ EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false);
+ if (2 > max_available_size) {
+ RTW_INFO("no available efuse!\n");
+ return -EFAULT;
+ }
+ if (rtw_efuse_map_write(padapter, addr, cnt, &val) == _FAIL) {
+ RTW_INFO("rtw_efuse_map_write error\n");
+ return -EFAULT;
+ }
+ sprintf(extra, " efuse write ok :%d", val);
+ } else
+ sprintf(extra, "%d", val);
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+
+int rtw_mp_reset_stats(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct mp_priv *pmp_priv;
+ struct pkt_attrib *pattrib;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ pmp_priv = &padapter->mppriv;
+
+ pmp_priv->tx.sended = 0;
+ pmp_priv->tx_pktcount = 0;
+ pmp_priv->rx_pktcount = 0;
+ pmp_priv->rx_pktcount_filter_out = 0;
+ pmp_priv->rx_crcerrpktcount = 0;
+
+ rtw_reset_phy_rx_counters(padapter);
+ rtw_reset_mac_rx_counters(padapter);
+
+ memset(extra, 0, wrqu->length);
+ sprintf(extra, "mp_reset_stats ok\n");
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+int rtw_mp_dump(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ struct mp_priv *pmp_priv;
+ struct pkt_attrib *pattrib;
+ u32 value;
+ u8 input[128];
+ u8 rf_type, path_nums = 0;
+ u32 i, j = 1, path;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ pmp_priv = &padapter->mppriv;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ if (strncmp(input, "all", 4) == 0) {
+ mac_reg_dump(RTW_DBGDUMP, padapter);
+ bb_reg_dump(RTW_DBGDUMP, padapter);
+ rf_reg_dump(RTW_DBGDUMP, padapter);
+ }
+ return 0;
+}
+
+
+int rtw_mp_phypara(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ char input[128];
+ u32 valxcap, ret;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ RTW_INFO("%s:iwpriv in=%s\n", __func__, input);
+
+ ret = sscanf(input, "xcap=%d", &valxcap);
+
+ pHalData->crystal_cap = (u8)valxcap;
+ hal_set_crystal_cap(padapter , valxcap);
+
+ sprintf(extra, "Set xcap=%d", valxcap);
+ wrqu->length = strlen(extra) + 1;
+
+ return 0;
+
+}
+
+
+int rtw_mp_SetRFPath(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ char input[128];
+ int bMain = 1, bTurnoff = 1;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ RTW_INFO("%s:iwpriv in=%s\n", __func__, input);
+
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ bMain = strncmp(input, "1", 2); /* strncmp true is 0*/
+ bTurnoff = strncmp(input, "0", 3); /* strncmp true is 0*/
+
+ memset(extra, 0, wrqu->length);
+
+ if (bMain == 0) {
+ MP_PHY_SetRFPathSwitch(padapter, true);
+ RTW_INFO("%s:PHY_SetRFPathSwitch=true\n", __func__);
+ sprintf(extra, "mp_setrfpath Main\n");
+
+ } else if (bTurnoff == 0) {
+ MP_PHY_SetRFPathSwitch(padapter, false);
+ RTW_INFO("%s:PHY_SetRFPathSwitch=false\n", __func__);
+ sprintf(extra, "mp_setrfpath Aux\n");
+ } else {
+ bMain = MP_PHY_QueryRFPathSwitch(padapter);
+ RTW_INFO("%s:PHY_SetRFPathSwitch = %s\n", __func__, (bMain ? "Main":"Aux"));
+ sprintf(extra, "mp_setrfpath %s\n" , (bMain ? "Main":"Aux"));
+ }
+
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+
+int rtw_mp_QueryDrv(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ char input[128];
+ int qAutoLoad = 1;
+ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
+
+ if (wrqu->data.length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+ RTW_INFO("%s:iwpriv in=%s\n", __func__, input);
+
+ qAutoLoad = strncmp(input, "autoload", 8); /* strncmp true is 0*/
+
+ if (qAutoLoad == 0) {
+ RTW_INFO("%s:qAutoLoad\n", __func__);
+
+ if (pHalData->bautoload_fail_flag)
+ sprintf(extra, "fail");
+ else
+ sprintf(extra, "ok");
+ }
+ wrqu->data.length = strlen(extra) + 1;
+ return 0;
+}
+
+
+int rtw_mp_PwrCtlDM(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ u8 input[128];
+ int bstart = 1;
+
+ if (wrqu->length > 128)
+ return -EFAULT;
+ if (copy_from_user(input, wrqu->pointer, wrqu->length))
+ return -EFAULT;
+
+ bstart = strncmp(input, "start", 5); /* strncmp true is 0*/
+ if (bstart == 0) {
+ sprintf(extra, "PwrCtlDM start\n");
+ MPT_PwrCtlDM(padapter, 1);
+ } else {
+ sprintf(extra, "PwrCtlDM stop\n");
+ MPT_PwrCtlDM(padapter, 0);
+ }
+ wrqu->length = strlen(extra);
+
+ return 0;
+}
+
+int rtw_mp_iqk(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ rtw_mp_trigger_iqk(padapter);
+
+ return 0;
+}
+
+int rtw_mp_lck(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ rtw_mp_trigger_lck(padapter);
+
+ return 0;
+}
+
+int rtw_mp_getver(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ struct mp_priv *pmp_priv;
+
+ pmp_priv = &padapter->mppriv;
+
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+
+ sprintf(extra, "rtwpriv=%d\n", RTWPRIV_VER_INFO);
+ wrqu->data.length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_mp_mon(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct hal_ops *pHalFunc = &padapter->hal_func;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
+ int bstart = 1, bstop = 1;
+
+ networkType = Ndis802_11Infrastructure;
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+
+ rtw_pm_set_ips(padapter, IPS_NONE);
+ LeaveAllPowerSaveMode(padapter);
+
+#ifdef CONFIG_MP_INCLUDED
+ if (init_mp_priv(padapter) == _FAIL)
+ RTW_INFO("%s: initialize MP private data Fail!\n", __func__);
+ padapter->mppriv.channel = 6;
+
+ bstart = strncmp(extra, "start", 5); /* strncmp true is 0*/
+ bstop = strncmp(extra, "stop", 4); /* strncmp true is 0*/
+ if (bstart == 0) {
+ mp_join(padapter, WIFI_FW_ADHOC_STATE);
+ SetPacketRx(padapter, true, false);
+ SetChannel(padapter);
+ pmp_priv->rx_bindicatePkt = true;
+ pmp_priv->bRTWSmbCfg = true;
+ sprintf(extra, "monitor mode start\n");
+ } else if (bstop == 0) {
+ SetPacketRx(padapter, false, false);
+ pmp_priv->rx_bindicatePkt = false;
+ pmp_priv->bRTWSmbCfg = false;
+ padapter->registrypriv.mp_mode = 1;
+ pHalFunc->hal_deinit(padapter);
+ padapter->registrypriv.mp_mode = 0;
+ pHalFunc->hal_init(padapter);
+ /*rtw_disassoc_cmd(padapter, 0, true);*/
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ rtw_disassoc_cmd(padapter, 500, true);
+ rtw_indicate_disconnect(padapter, 0, false);
+ /*rtw_free_assoc_resources(padapter, 1);*/
+ }
+ rtw_pm_set_ips(padapter, IPS_NORMAL);
+ sprintf(extra, "monitor mode Stop\n");
+ }
+#endif
+ wrqu->data.length = strlen(extra);
+ return 0;
+}
+
+int rtw_mp_pretx_proc(PADAPTER padapter, u8 bStartTest, char *extra)
+{
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+
+ switch (pmp_priv->mode) {
+
+ case MP_PACKET_TX:
+ if (bStartTest == 0) {
+ pmp_priv->tx.stop = 1;
+ pmp_priv->mode = MP_ON;
+ sprintf(extra, "Stop continuous Tx");
+ } else if (pmp_priv->tx.stop == 1) {
+ sprintf(extra + strlen(extra), "\nStart continuous DA=ffffffffffff len=1500 count=%u\n", pmp_priv->tx.count);
+ pmp_priv->tx.stop = 0;
+ SetPacketTx(padapter);
+ } else
+ return -EFAULT;
+ return 0;
+ case MP_SINGLE_TONE_TX:
+ if (bStartTest != 0)
+ sprintf(extra + strlen(extra), "\nStart continuous DA=ffffffffffff len=1500\n infinite=yes.");
+ SetSingleToneTx(padapter, (u8)bStartTest);
+ break;
+ case MP_CONTINUOUS_TX:
+ if (bStartTest != 0)
+ sprintf(extra + strlen(extra), "\nStart continuous DA=ffffffffffff len=1500\n infinite=yes.");
+ SetContinuousTx(padapter, (u8)bStartTest);
+ break;
+ case MP_CARRIER_SUPPRISSION_TX:
+ if (bStartTest != 0) {
+ if (HwRateToMPTRate(pmp_priv->rateidx) <= MPT_RATE_11M)
+ sprintf(extra + strlen(extra), "\nStart continuous DA=ffffffffffff len=1500\n infinite=yes.");
+ else
+ sprintf(extra + strlen(extra), "\nSpecify carrier suppression but not CCK rate");
+ }
+ SetCarrierSuppressionTx(padapter, (u8)bStartTest);
+ break;
+ case MP_SINGLE_CARRIER_TX:
+ if (bStartTest != 0)
+ sprintf(extra + strlen(extra), "\nStart continuous DA=ffffffffffff len=1500\n infinite=yes.");
+ SetSingleCarrierTx(padapter, (u8)bStartTest);
+ break;
+
+ default:
+ sprintf(extra, "Error! Continuous-Tx is not on-going.");
+ return -EFAULT;
+ }
+
+ if (bStartTest == 1 && pmp_priv->mode != MP_ON) {
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+
+ if (pmp_priv->tx.stop == 0) {
+ pmp_priv->tx.stop = 1;
+ rtw_msleep_os(5);
+ }
+ pmp_priv->tx.attrib.ht_en = 1;
+ pmp_priv->tx.stop = 0;
+ pmp_priv->tx.count = 1;
+ SetPacketTx(padapter);
+ } else
+ pmp_priv->mode = MP_ON;
+
+ return 0;
+}
+
+int rtw_mp_tx(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+
+ u32 bandwidth = 0, sg = 0, channel = 6, txpower = 40, rate = 108, ant = 0, txmode = 1, count = 0;
+ u8 i = 0, j = 0, bStartTest = 1, status = 0, Idx = 0, tmpU1B = 0;
+ u16 antenna = 0;
+
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+ RTW_INFO("extra = %s\n", extra);
+#ifdef CONFIG_CONCURRENT_MODE
+ if (!is_primary_adapter(padapter)) {
+ sprintf(extra, "Error: MP mode can't support Virtual Adapter, Please to use main Adapter.\n");
+ wrqu->data.length = strlen(extra);
+ return 0;
+ }
+#endif
+
+ if (strncmp(extra, "stop", 3) == 0) {
+ bStartTest = 0; /* To set Stop*/
+ pmp_priv->tx.stop = 1;
+ sprintf(extra, "Stop continuous Tx");
+ status = rtw_mp_pretx_proc(padapter, bStartTest, extra);
+ wrqu->data.length = strlen(extra);
+ return status;
+ } else if (strncmp(extra, "count", 5) == 0) {
+ if (sscanf(extra, "count=%d", &count) < 1)
+ RTW_INFO("Got Count=%d]\n", count);
+ pmp_priv->tx.count = count;
+ return 0;
+ } else if (strncmp(extra, "setting", 7) == 0) {
+ memset(extra, 0, wrqu->data.length);
+ sprintf(extra, "Current Setting :\n Channel:%d", pmp_priv->channel);
+ sprintf(extra + strlen(extra), "\n Bandwidth:%d", pmp_priv->bandwidth);
+ sprintf(extra + strlen(extra), "\n Rate index:%d", pmp_priv->rateidx);
+ sprintf(extra + strlen(extra), "\n TxPower index:%d", pmp_priv->txpoweridx);
+ sprintf(extra + strlen(extra), "\n Antenna TxPath:%d", pmp_priv->antenna_tx);
+ sprintf(extra + strlen(extra), "\n Antenna RxPath:%d", pmp_priv->antenna_rx);
+ sprintf(extra + strlen(extra), "\n MP Mode:%d", pmp_priv->mode);
+ wrqu->data.length = strlen(extra);
+ return 0;
+#ifdef CONFIG_MP_VHT_HW_TX_MODE
+ } else if (strncmp(extra, "pmact", 5) == 0) {
+ if (strncmp(extra, "pmact=", 6) == 0) {
+ memset(&pMptCtx->PMacTxInfo, 0, sizeof(pMptCtx->PMacTxInfo));
+ if (strncmp(extra, "pmact=start", 11) == 0) {
+ pMptCtx->PMacTxInfo.bEnPMacTx = true;
+ sprintf(extra, "Set PMac Tx Mode start\n");
+ } else {
+ pMptCtx->PMacTxInfo.bEnPMacTx = false;
+ sprintf(extra, "Set PMac Tx Mode Stop\n");
+ }
+ if (pMptCtx->bldpc == true)
+ pMptCtx->PMacTxInfo.bLDPC = true;
+
+ if (pMptCtx->bstbc == true)
+ pMptCtx->PMacTxInfo.bSTBC = true;
+
+ pMptCtx->PMacTxInfo.bSPreamble = pmp_priv->preamble;
+ pMptCtx->PMacTxInfo.bSGI = pmp_priv->preamble;
+ pMptCtx->PMacTxInfo.BandWidth = pmp_priv->bandwidth;
+ pMptCtx->PMacTxInfo.TX_RATE = HwRateToMPTRate(pmp_priv->rateidx);
+
+ pMptCtx->PMacTxInfo.Mode = pMptCtx->HWTxmode;
+
+ pMptCtx->PMacTxInfo.NDP_sound = false;/*(Adapter.PacketType == NDP_PKT)?true:false;*/
+
+ if (padapter->mppriv.pktInterval == 0)
+ pMptCtx->PMacTxInfo.PacketPeriod = 100;
+ else
+ pMptCtx->PMacTxInfo.PacketPeriod = padapter->mppriv.pktInterval;
+
+ if (padapter->mppriv.pktLength < 1000)
+ pMptCtx->PMacTxInfo.PacketLength = 1000;
+ else
+ pMptCtx->PMacTxInfo.PacketLength = padapter->mppriv.pktLength;
+
+ pMptCtx->PMacTxInfo.PacketPattern = rtw_random32() % 0xFF;
+
+ if (padapter->mppriv.tx_pktcount != 0)
+ pMptCtx->PMacTxInfo.PacketCount = padapter->mppriv.tx_pktcount;
+
+ pMptCtx->PMacTxInfo.Ntx = 0;
+ for (Idx = 16; Idx < 20; Idx++) {
+ tmpU1B = (padapter->mppriv.antenna_tx >> Idx) & 1;
+ if (tmpU1B)
+ pMptCtx->PMacTxInfo.Ntx++;
+ }
+
+ memset(pMptCtx->PMacTxInfo.MacAddress, 0xFF, ETH_ALEN);
+
+ PMAC_Get_Pkt_Param(&pMptCtx->PMacTxInfo, &pMptCtx->PMacPktInfo);
+
+ if (MPT_IS_CCK_RATE(pMptCtx->PMacTxInfo.TX_RATE))
+
+ CCK_generator(&pMptCtx->PMacTxInfo, &pMptCtx->PMacPktInfo);
+ else {
+ PMAC_Nsym_generator(&pMptCtx->PMacTxInfo, &pMptCtx->PMacPktInfo);
+ /* 24 BIT*/
+ L_SIG_generator(pMptCtx->PMacPktInfo.N_sym, &pMptCtx->PMacTxInfo, &pMptCtx->PMacPktInfo);
+ }
+ /* 48BIT*/
+ if (MPT_IS_HT_RATE(pMptCtx->PMacTxInfo.TX_RATE))
+ HT_SIG_generator(&pMptCtx->PMacTxInfo, &pMptCtx->PMacPktInfo);
+ else if (MPT_IS_VHT_RATE(pMptCtx->PMacTxInfo.TX_RATE)) {
+ /* 48BIT*/
+ VHT_SIG_A_generator(&pMptCtx->PMacTxInfo, &pMptCtx->PMacPktInfo);
+
+ /* 26/27/29 BIT & CRC 8 BIT*/
+ VHT_SIG_B_generator(&pMptCtx->PMacTxInfo);
+
+ /* 32 BIT*/
+ VHT_Delimiter_generator(&pMptCtx->PMacTxInfo);
+ }
+
+ mpt_ProSetPMacTx(padapter);
+
+ } else if (strncmp(extra, "pmact,mode=", 11) == 0) {
+ int txmode = 0;
+
+ if (sscanf(extra, "pmact,mode=%d", &txmode) > 0) {
+ if (txmode == 1) {
+ pMptCtx->HWTxmode = CONTINUOUS_TX;
+ sprintf(extra, "\t Config HW Tx mode = CONTINUOUS_TX\n");
+ } else if (txmode == 2) {
+ pMptCtx->HWTxmode = OFDM_Single_Tone_TX;
+ sprintf(extra, "\t Config HW Tx mode = OFDM_Single_Tone_TX\n");
+ } else {
+ pMptCtx->HWTxmode = PACKETS_TX;
+ sprintf(extra, "\t Config HW Tx mode = PACKETS_TX\n");
+ }
+ } else {
+ pMptCtx->HWTxmode = PACKETS_TX;
+ sprintf(extra, "\t Config HW Tx mode=\n 0 = PACKETS_TX\n 1 = CONTINUOUS_TX\n 2 = OFDM_Single_Tone_TX");
+ }
+ } else if (strncmp(extra, "pmact,", 6) == 0) {
+ int PacketPeriod = 0, PacketLength = 0, PacketCout = 0;
+ int bldpc = 0, bstbc = 0;
+
+ if (sscanf(extra, "pmact,period=%d", &PacketPeriod) > 0) {
+ padapter->mppriv.pktInterval = PacketPeriod;
+ RTW_INFO("PacketPeriod=%d\n", padapter->mppriv.pktInterval);
+ sprintf(extra, "PacketPeriod [1~255]= %d\n", padapter->mppriv.pktInterval);
+
+ } else if (sscanf(extra, "pmact,length=%d", &PacketLength) > 0) {
+ padapter->mppriv.pktLength = PacketLength;
+ RTW_INFO("PacketPeriod=%d\n", padapter->mppriv.pktLength);
+ sprintf(extra, "PacketLength[~65535]=%d\n", padapter->mppriv.pktLength);
+
+ } else if (sscanf(extra, "pmact,count=%d", &PacketCout) > 0) {
+ padapter->mppriv.tx_pktcount = PacketCout;
+ RTW_INFO("Packet Cout =%d\n", padapter->mppriv.tx_pktcount);
+ sprintf(extra, "Packet Cout =%d\n", padapter->mppriv.tx_pktcount);
+
+ } else if (sscanf(extra, "pmact,ldpc=%d", &bldpc) > 0) {
+ pMptCtx->bldpc = bldpc;
+ RTW_INFO("Set LDPC =%d\n", pMptCtx->bldpc);
+ sprintf(extra, "Set LDPC =%d\n", pMptCtx->bldpc);
+
+ } else if (sscanf(extra, "pmact,stbc=%d", &bstbc) > 0) {
+ pMptCtx->bstbc = bstbc;
+ RTW_INFO("Set STBC =%d\n", pMptCtx->bstbc);
+ sprintf(extra, "Set STBC =%d\n", pMptCtx->bstbc);
+ } else
+ sprintf(extra, "\n period={1~255}\n length={1000~65535}\n count={0~}\n ldpc={0/1}\n stbc={0/1}");
+
+ }
+
+ wrqu->data.length = strlen(extra);
+ return 0;
+#endif
+ } else {
+
+ if (sscanf(extra, "ch=%d,bw=%d,rate=%d,pwr=%d,ant=%d,tx=%d", &channel, &bandwidth, &rate, &txpower, &ant, &txmode) < 6) {
+ RTW_INFO("Invalid format [ch=%d,bw=%d,rate=%d,pwr=%d,ant=%d,tx=%d]\n", channel, bandwidth, rate, txpower, ant, txmode);
+ memset(extra, 0, wrqu->data.length);
+ sprintf(extra, "\n Please input correct format as bleow:\n");
+ sprintf(extra + strlen(extra), "\t ch=%d,bw=%d,rate=%d,pwr=%d,ant=%d,tx=%d\n", channel, bandwidth, rate, txpower, ant, txmode);
+ sprintf(extra + strlen(extra), "\n [ ch : BGN = <1~14> , A or AC = <36~165> ]");
+ sprintf(extra + strlen(extra), "\n [ bw : Bandwidth: 0 = 20M, 1 = 40M, 2 = 80M ]");
+ sprintf(extra + strlen(extra), "\n [ rate : CCK: 1 2 5.5 11M X 2 = < 2 4 11 22 >]");
+ sprintf(extra + strlen(extra), "\n [ OFDM: 6 9 12 18 24 36 48 54M X 2 = < 12 18 24 36 48 72 96 108>");
+ sprintf(extra + strlen(extra), "\n [ HT 1S2SS MCS0 ~ MCS15 : < [MCS0]=128 ~ [MCS7]=135 ~ [MCS15]=143 >");
+ sprintf(extra + strlen(extra), "\n [ HT 3SS MCS16 ~ MCS32 : < [MCS16]=144 ~ [MCS23]=151 ~ [MCS32]=159 >");
+ sprintf(extra + strlen(extra), "\n [ VHT 1SS MCS0 ~ MCS9 : < [MCS0]=160 ~ [MCS9]=169 >");
+ sprintf(extra + strlen(extra), "\n [ txpower : 1~63 power index");
+ sprintf(extra + strlen(extra), "\n [ ant : <A = 1, B = 2, C = 4, D = 8> ,2T ex: AB=3 BC=6 CD=12");
+ sprintf(extra + strlen(extra), "\n [ txmode : < 0 = CONTINUOUS_TX, 1 = PACKET_TX, 2 = SINGLE_TONE_TX, 3 = CARRIER_SUPPRISSION_TX, 4 = SINGLE_CARRIER_TX>\n");
+ wrqu->data.length = strlen(extra);
+ return status;
+
+ } else {
+ RTW_INFO("Got format [ch=%d,bw=%d,rate=%d,pwr=%d,ant=%d,tx=%d]\n", channel, bandwidth, rate, txpower, ant, txmode);
+ memset(extra, 0, wrqu->data.length);
+ sprintf(extra, "Change Current channel %d to channel %d", padapter->mppriv.channel , channel);
+ padapter->mppriv.channel = channel;
+ SetChannel(padapter);
+ pHalData->current_channel = channel;
+
+ if (bandwidth == 1)
+ bandwidth = CHANNEL_WIDTH_40;
+ else if (bandwidth == 2)
+ bandwidth = CHANNEL_WIDTH_80;
+ sprintf(extra + strlen(extra), "\nChange Current Bandwidth %d to Bandwidth %d", padapter->mppriv.bandwidth , bandwidth);
+ padapter->mppriv.bandwidth = (u8)bandwidth;
+ padapter->mppriv.preamble = sg;
+ SetBandwidth(padapter);
+ pHalData->current_channel_bw = bandwidth;
+
+ sprintf(extra + strlen(extra), "\nSet power level :%d", txpower);
+ padapter->mppriv.txpoweridx = (u8)txpower;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_A] = (u8)txpower;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_B] = (u8)txpower;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_C] = (u8)txpower;
+ pMptCtx->TxPwrLevel[ODM_RF_PATH_D] = (u8)txpower;
+
+ RTW_INFO("%s: bw=%d sg=%d\n", __func__, bandwidth, sg);
+
+ if (rate <= 0x7f)
+ rate = wifirate2_ratetbl_inx((u8)rate);
+ else if (rate < 0xC8)
+ rate = (rate - 0x80 + MPT_RATE_MCS0);
+ /*HT rate 0x80(MCS0) ~ 0x8F(MCS15) ~ 0x9F(MCS31) 128~159
+ VHT1SS~2SS rate 0xA0 (VHT1SS_MCS0 44) ~ 0xB3 (VHT2SS_MCS9 #63) 160~179
+ VHT rate 0xB4 (VHT3SS_MCS0 64) ~ 0xC7 (VHT2SS_MCS9 #83) 180~199
+ else
+ VHT rate 0x90(VHT1SS_MCS0) ~ 0x99(VHT1SS_MCS9) 144~153
+ rate =(rate - MPT_RATE_VHT1SS_MCS0);
+ */
+ RTW_INFO("%s: rate index=%d\n", __func__, rate);
+ if (rate >= MPT_RATE_LAST)
+ return -EINVAL;
+ sprintf(extra + strlen(extra), "\nSet data rate to %d index %d", padapter->mppriv.rateidx, rate);
+
+ padapter->mppriv.rateidx = rate;
+ pMptCtx->mpt_rate_index = rate;
+ SetDataRate(padapter);
+
+ sprintf(extra + strlen(extra), "\nSet Antenna Path :%d", ant);
+ switch (ant) {
+ case 1:
+ antenna = ANTENNA_A;
+ break;
+ case 2:
+ antenna = ANTENNA_B;
+ break;
+ case 4:
+ antenna = ANTENNA_C;
+ break;
+ case 8:
+ antenna = ANTENNA_D;
+ break;
+ case 3:
+ antenna = ANTENNA_AB;
+ break;
+ case 5:
+ antenna = ANTENNA_AC;
+ break;
+ case 9:
+ antenna = ANTENNA_AD;
+ break;
+ case 6:
+ antenna = ANTENNA_BC;
+ break;
+ case 10:
+ antenna = ANTENNA_BD;
+ break;
+ case 12:
+ antenna = ANTENNA_CD;
+ break;
+ case 7:
+ antenna = ANTENNA_ABC;
+ break;
+ case 14:
+ antenna = ANTENNA_BCD;
+ break;
+ case 11:
+ antenna = ANTENNA_ABD;
+ break;
+ case 15:
+ antenna = ANTENNA_ABCD;
+ break;
+ }
+ RTW_INFO("%s: antenna=0x%x\n", __func__, antenna);
+ padapter->mppriv.antenna_tx = antenna;
+ padapter->mppriv.antenna_rx = antenna;
+ pHalData->antenna_tx_path = antenna;
+ SetAntenna(padapter);
+
+ if (txmode == 0)
+ pmp_priv->mode = MP_CONTINUOUS_TX;
+ else if (txmode == 1) {
+ pmp_priv->mode = MP_PACKET_TX;
+ pmp_priv->tx.count = count;
+ } else if (txmode == 2)
+ pmp_priv->mode = MP_SINGLE_TONE_TX;
+ else if (txmode == 3)
+ pmp_priv->mode = MP_CARRIER_SUPPRISSION_TX;
+ else if (txmode == 4)
+ pmp_priv->mode = MP_SINGLE_CARRIER_TX;
+
+ status = rtw_mp_pretx_proc(padapter, bStartTest, extra);
+ }
+
+ }
+
+ wrqu->data.length = strlen(extra);
+ return status;
+}
+
+
+int rtw_mp_rx(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+
+ u32 bandwidth = 0, sg = 0, channel = 6, ant = 0;
+ u16 antenna = 0;
+ u8 bStartRx = 0;
+
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (!is_primary_adapter(padapter)) {
+ sprintf(extra, "Error: MP mode can't support Virtual Adapter, Please to use main Adapter.\n");
+ wrqu->data.length = strlen(extra);
+ return 0;
+ }
+#endif
+
+ if (strncmp(extra, "stop", 4) == 0) {
+ memset(extra, 0, wrqu->data.length);
+ SetPacketRx(padapter, bStartRx, false);
+ pmp_priv->bmac_filter = false;
+ sprintf(extra, "Received packet OK:%d CRC error:%d ,Filter out:%d", padapter->mppriv.rx_pktcount, padapter->mppriv.rx_crcerrpktcount, padapter->mppriv.rx_pktcount_filter_out);
+ wrqu->data.length = strlen(extra);
+ return 0;
+
+ } else if (sscanf(extra, "ch=%d,bw=%d,ant=%d", &channel, &bandwidth, &ant) < 3) {
+ RTW_INFO("Invalid format [ch=%d,bw=%d,ant=%d]\n", channel, bandwidth, ant);
+ memset(extra, 0, wrqu->data.length);
+ sprintf(extra, "\n Please input correct format as bleow:\n");
+ sprintf(extra + strlen(extra), "\t ch=%d,bw=%d,ant=%d\n", channel, bandwidth, ant);
+ sprintf(extra + strlen(extra), "\n [ ch : BGN = <1~14> , A or AC = <36~165> ]");
+ sprintf(extra + strlen(extra), "\n [ bw : Bandwidth: 0 = 20M, 1 = 40M, 2 = 80M ]");
+ sprintf(extra + strlen(extra), "\n [ ant : <A = 1, B = 2, C = 4, D = 8> ,2T ex: AB=3 BC=6 CD=12");
+ wrqu->data.length = strlen(extra);
+ return 0;
+
+ } else {
+ bStartRx = 1;
+ RTW_INFO("Got format [ch=%d,bw=%d,ant=%d]\n", channel, bandwidth, ant);
+ memset(extra, 0, wrqu->data.length);
+ sprintf(extra, "Change Current channel %d to channel %d", padapter->mppriv.channel , channel);
+ padapter->mppriv.channel = channel;
+ SetChannel(padapter);
+ pHalData->current_channel = channel;
+
+ if (bandwidth == 1)
+ bandwidth = CHANNEL_WIDTH_40;
+ else if (bandwidth == 2)
+ bandwidth = CHANNEL_WIDTH_80;
+ sprintf(extra + strlen(extra), "\nChange Current Bandwidth %d to Bandwidth %d", padapter->mppriv.bandwidth , bandwidth);
+ padapter->mppriv.bandwidth = (u8)bandwidth;
+ padapter->mppriv.preamble = sg;
+ SetBandwidth(padapter);
+ pHalData->current_channel_bw = bandwidth;
+
+ sprintf(extra + strlen(extra), "\nSet Antenna Path :%d", ant);
+ switch (ant) {
+ case 1:
+ antenna = ANTENNA_A;
+ break;
+ case 2:
+ antenna = ANTENNA_B;
+ break;
+ case 4:
+ antenna = ANTENNA_C;
+ break;
+ case 8:
+ antenna = ANTENNA_D;
+ break;
+ case 3:
+ antenna = ANTENNA_AB;
+ break;
+ case 5:
+ antenna = ANTENNA_AC;
+ break;
+ case 9:
+ antenna = ANTENNA_AD;
+ break;
+ case 6:
+ antenna = ANTENNA_BC;
+ break;
+ case 10:
+ antenna = ANTENNA_BD;
+ break;
+ case 12:
+ antenna = ANTENNA_CD;
+ break;
+ case 7:
+ antenna = ANTENNA_ABC;
+ break;
+ case 14:
+ antenna = ANTENNA_BCD;
+ break;
+ case 11:
+ antenna = ANTENNA_ABD;
+ break;
+ case 15:
+ antenna = ANTENNA_ABCD;
+ break;
+ }
+ RTW_INFO("%s: antenna=0x%x\n", __func__, antenna);
+ padapter->mppriv.antenna_tx = antenna;
+ padapter->mppriv.antenna_rx = antenna;
+ pHalData->antenna_tx_path = antenna;
+ SetAntenna(padapter);
+
+ sprintf(extra + strlen(extra), "\nstart Rx");
+ SetPacketRx(padapter, bStartRx, false);
+ }
+ wrqu->data.length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_mp_hwtx(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+ PMPT_CONTEXT pMptCtx = &(padapter->mppriv.mpt_ctx);
+
+ return 0;
+}
+
+int rtw_efuse_mask_file(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ char *rtw_efuse_mask_file_path;
+ u8 Status;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+
+ memset(maskfileBuffer, 0x00, sizeof(maskfileBuffer));
+
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+
+ if (strncmp(extra, "off", 3) == 0 && strlen(extra) < 4) {
+ padapter->registrypriv.boffefusemask = 1;
+ sprintf(extra, "Turn off Efuse Mask\n");
+ wrqu->data.length = strlen(extra);
+ return 0;
+ }
+ if (strncmp(extra, "on", 2) == 0 && strlen(extra) < 3) {
+ padapter->registrypriv.boffefusemask = 0;
+ sprintf(extra, "Turn on Efuse Mask\n");
+ wrqu->data.length = strlen(extra);
+ return 0;
+ }
+ if (strncmp(extra, "data,", 5) == 0) {
+ u8 *pch, *pdata;
+ char *ptmp, tmp;
+ u8 count = 0;
+ u8 i = 0;
+ u32 datalen = 0;
+
+ ptmp = extra;
+ pch = strsep(&ptmp, ",");
+
+ if ((pch == NULL) || (strlen(pch) == 0)) {
+ RTW_INFO("%s: parameter error(no cmd)!\n", __func__);
+ return -EFAULT;
+ }
+
+ do {
+ pch = strsep(&ptmp, ":");
+ if ((pch == NULL) || (strlen(pch) == 0))
+ break;
+ if (strlen(pch) != 2
+ || IsHexDigit(*pch) == false
+ || IsHexDigit(*(pch + 1)) == false
+ || sscanf(pch, "%hhx", &tmp) != 1
+ ) {
+ RTW_INFO("%s: invalid 8-bit hex! input format: data,01:23:45:67:89:ab:cd:ef...\n", __func__);
+ return -EFAULT;
+ }
+ maskfileBuffer[count++] = tmp;
+
+ } while (count < 64);
+
+ for (i = 0; i < count; i++)
+ sprintf(extra + strlen(extra), ":%02x", maskfileBuffer[i]);
+
+ padapter->registrypriv.bFileMaskEfuse = true;
+
+ sprintf(extra + strlen(extra), "\nLoad Efuse Mask data %d hex ok\n", count);
+ wrqu->data.length = strlen(extra);
+ return 0;
+ }
+ rtw_efuse_mask_file_path = extra;
+
+ if (rtw_is_file_readable(rtw_efuse_mask_file_path) == true) {
+ RTW_INFO("%s do rtw_efuse_mask_file_read = %s! ,sizeof maskfileBuffer %zu\n", __func__, rtw_efuse_mask_file_path, sizeof(maskfileBuffer));
+ Status = rtw_efuse_file_read(padapter, rtw_efuse_mask_file_path, maskfileBuffer, sizeof(maskfileBuffer));
+ if (Status == true)
+ padapter->registrypriv.bFileMaskEfuse = true;
+ sprintf(extra, "efuse mask file read OK\n");
+ } else {
+ padapter->registrypriv.bFileMaskEfuse = false;
+ sprintf(extra, "efuse mask file readable FAIL\n");
+ RTW_INFO("%s rtw_is_file_readable fail!\n", __func__);
+ }
+ wrqu->data.length = strlen(extra);
+ return 0;
+}
+
+
+int rtw_efuse_file_map(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ char *rtw_efuse_file_map_path;
+ u8 Status;
+ PEFUSE_HAL pEfuseHal;
+ PADAPTER padapter = rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ struct mp_priv *pmp_priv = &padapter->mppriv;
+
+ pEfuseHal = &pHalData->EfuseHal;
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length))
+ return -EFAULT;
+
+ rtw_efuse_file_map_path = extra;
+
+ memset(pEfuseHal->fakeEfuseModifiedMap, 0xFF, EFUSE_MAX_MAP_LEN);
+
+ if (rtw_is_file_readable(rtw_efuse_file_map_path) == true) {
+ RTW_INFO("%s do rtw_efuse_mask_file_read = %s!\n", __func__, rtw_efuse_file_map_path);
+ Status = rtw_efuse_file_read(padapter, rtw_efuse_file_map_path, pEfuseHal->fakeEfuseModifiedMap, sizeof(pEfuseHal->fakeEfuseModifiedMap));
+ if (Status == true) {
+ pmp_priv->bloadefusemap = true;
+ sprintf(extra, "efuse file file_read OK\n");
+ } else {
+ pmp_priv->bloadefusemap = false;
+ sprintf(extra, "efuse file file_read FAIL\n");
+ }
+ } else {
+ sprintf(extra, "efuse file readable FAIL\n");
+ RTW_INFO("%s rtw_is_file_readable fail!\n", __func__);
+ }
+ wrqu->data.length = strlen(extra);
+ return 0;
+}
+
+#endif
diff --git a/drivers/staging/rtl8188eu/os_dep/mlme_linux.c b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
new file mode 100644
index 000000000000..12fe36975d92
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/mlme_linux.c
@@ -0,0 +1,726 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+
+
+#define _MLME_OSDEP_C_
+
+#include <drv_types.h>
+#include <rtw_mlme.h>
+
+#ifdef RTK_DMP_PLATFORM
+void Linkup_workitem_callback(struct work_struct *work)
+{
+ struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkup_workitem);
+ _adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);
+
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12))
+ kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKUP);
+#else
+ kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKUP);
+#endif
+
+}
+
+void Linkdown_workitem_callback(struct work_struct *work)
+{
+ struct mlme_priv *pmlmepriv = container_of(work, struct mlme_priv, Linkdown_workitem);
+ _adapter *padapter = container_of(pmlmepriv, _adapter, mlmepriv);
+
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 12))
+ kobject_uevent(&padapter->pnetdev->dev.kobj, KOBJ_LINKDOWN);
+#else
+ kobject_hotplug(&padapter->pnetdev->class_dev.kobj, KOBJ_LINKDOWN);
+#endif
+
+}
+#endif
+
+
+/*
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void sitesurvey_ctrl_handler(void *FunctionContext)
+#else
+void sitesurvey_ctrl_handler(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *adapter = (_adapter *)FunctionContext;
+#else
+ _adapter *adapter = from_timer(adapter, t, sitesurveyctrl.sitesurvey_ctrl_timer);
+#endif
+
+ _sitesurvey_ctrl_handler(adapter);
+
+ _set_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, 3000);
+}
+*/
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void rtw_join_timeout_handler(void *FunctionContext)
+#else
+void rtw_join_timeout_handler(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *adapter = (_adapter *)FunctionContext;
+#else
+ _adapter *adapter = from_timer(adapter, t, mlmepriv.assoc_timer);
+#endif
+
+ _rtw_join_timeout_handler(adapter);
+}
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _rtw_scan_timeout_handler(void *FunctionContext)
+#else
+void _rtw_scan_timeout_handler(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *adapter = (_adapter *)FunctionContext;
+#else
+ _adapter *adapter = from_timer(adapter, t, mlmepriv.scan_to_timer);
+#endif
+
+ rtw_scan_timeout_handler(adapter);
+}
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _dynamic_check_timer_handler (void *FunctionContext)
+#else
+void _dynamic_check_timer_handler(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ struct dvobj_priv *pdvobj = (struct dvobj_priv *)FunctionContext;
+#else
+ struct dvobj_priv *pdvobj = from_timer(pdvobj, t, dynamic_chk_timer);
+#endif
+ _adapter *adapter = dvobj_get_primary_adapter(pdvobj);
+
+#if (MP_DRIVER == 1)
+ if (adapter->registrypriv.mp_mode == 1 && adapter->mppriv.mp_dm == 0) { /* for MP ODM dynamic Tx power tracking */
+ /* RTW_INFO("_dynamic_check_timer_handler mp_dm =0 return\n"); */
+ _set_timer(&pdvobj->dynamic_chk_timer, 2000);
+ return;
+ }
+#endif
+
+ rtw_dynamic_check_timer_handler(adapter);
+
+ _set_timer(&pdvobj->dynamic_chk_timer, 2000);
+}
+
+#ifdef CONFIG_SET_SCAN_DENY_TIMER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+static void _rtw_set_scan_deny_timer_hdl(void *FunctionContext)
+#else
+static void _rtw_set_scan_deny_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *adapter = (_adapter *)FunctionContext;
+#else
+ _adapter *adapter = from_timer(adapter, t, mlmepriv.set_scan_deny_timer);
+#endif
+
+ rtw_set_scan_deny_timer_hdl(adapter);
+}
+#endif
+
+void rtw_init_mlme_timer(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&pmlmepriv->assoc_timer, padapter->pnetdev, rtw_join_timeout_handler, padapter);
+ /* _init_timer(&pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer, padapter->pnetdev, sitesurvey_ctrl_handler, padapter); */
+ _init_timer(&pmlmepriv->scan_to_timer, padapter->pnetdev, _rtw_scan_timeout_handler, padapter);
+
+#ifdef CONFIG_DFS_MASTER
+ _init_timer(&pmlmepriv->dfs_master_timer, padapter->pnetdev, rtw_dfs_master_timer_hdl, padapter);
+#endif
+
+#ifdef CONFIG_SET_SCAN_DENY_TIMER
+ _init_timer(&pmlmepriv->set_scan_deny_timer, padapter->pnetdev, _rtw_set_scan_deny_timer_hdl, padapter);
+#endif
+#else
+ timer_setup(&pmlmepriv->assoc_timer, rtw_join_timeout_handler, 0);
+ /* timer_setup(&pmlmepriv->sitesurveyctrl.sitesurvey_ctrl_timer, sitesurvey_ctrl_handler, 0); */
+ timer_setup(&pmlmepriv->scan_to_timer, _rtw_scan_timeout_handler, 0);
+
+#ifdef CONFIG_DFS_MASTER
+ timer_setup(&pmlmepriv->dfs_master_timer, rtw_dfs_master_timer_hdl, 0);
+#endif
+
+#ifdef CONFIG_SET_SCAN_DENY_TIMER
+ timer_setup(&pmlmepriv->set_scan_deny_timer, _rtw_set_scan_deny_timer_hdl, 0);
+#endif
+#endif
+#ifdef RTK_DMP_PLATFORM
+ _init_workitem(&(pmlmepriv->Linkup_workitem), Linkup_workitem_callback, padapter);
+ _init_workitem(&(pmlmepriv->Linkdown_workitem), Linkdown_workitem_callback, padapter);
+#endif
+
+}
+
+void rtw_os_indicate_connect(_adapter *adapter)
+{
+ struct mlme_priv *pmlmepriv = &(adapter->mlmepriv);
+
+#ifdef CONFIG_IOCTL_CFG80211
+ if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+ (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+ rtw_cfg80211_ibss_indicate_connect(adapter);
+ else
+ rtw_cfg80211_indicate_connect(adapter);
+#endif /* CONFIG_IOCTL_CFG80211 */
+
+ rtw_indicate_wx_assoc_event(adapter);
+ netif_carrier_on(adapter->pnetdev);
+
+ if (adapter->pid[2] != 0)
+ rtw_signal_process(adapter->pid[2], SIGALRM);
+
+#ifdef RTK_DMP_PLATFORM
+ _set_workitem(&adapter->mlmepriv.Linkup_workitem);
+#endif
+
+
+}
+
+extern void indicate_wx_scan_complete_event(_adapter *padapter);
+void rtw_os_indicate_scan_done(_adapter *padapter, bool aborted)
+{
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_cfg80211_indicate_scan_done(padapter, aborted);
+#endif
+ indicate_wx_scan_complete_event(padapter);
+}
+
+static RT_PMKID_LIST backupPMKIDList[NUM_PMKID_CACHE];
+void rtw_reset_securitypriv(_adapter *adapter)
+{
+ u8 backupPMKIDIndex = 0;
+ u8 backupTKIPCountermeasure = 0x00;
+ u32 backupTKIPcountermeasure_time = 0;
+ /* add for CONFIG_IEEE80211W, none 11w also can use */
+ unsigned long irqL;
+ struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+
+ _enter_critical_bh(&adapter->security_key_mutex, &irqL);
+
+ if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802.1x */
+ /* Added by Albert 2009/02/18 */
+ /* We have to backup the PMK information for WiFi PMK Caching test item. */
+ /* */
+ /* Backup the btkip_countermeasure information. */
+ /* When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */
+
+ memset(&backupPMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+
+ memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+ backupPMKIDIndex = adapter->securitypriv.PMKIDIndex;
+ backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure;
+ backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time;
+#ifdef CONFIG_IEEE80211W
+ /* reset RX BIP packet number */
+ pmlmeext->mgnt_80211w_IPN_rx = 0;
+#endif /* CONFIG_IEEE80211W */
+ memset((unsigned char *)&adapter->securitypriv, 0, sizeof(struct security_priv));
+ /* _init_timer(&(adapter->securitypriv.tkip_timer),adapter->pnetdev, rtw_use_tkipkey_handler, adapter); */
+
+ /* Added by Albert 2009/02/18 */
+ /* Restore the PMK information to securitypriv structure for the following connection. */
+ memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+ adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
+ adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure;
+ adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time;
+
+ adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+ adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+ } else { /* reset values in securitypriv */
+ /* if(adapter->mlmepriv.fw_state & WIFI_STATION_STATE) */
+ /* { */
+ struct security_priv *psec_priv = &adapter->securitypriv;
+
+ psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+ psec_priv->dot11PrivacyKeyIndex = 0;
+
+ psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ psec_priv->dot118021XGrpKeyid = 1;
+
+ psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
+ psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
+ /* } */
+ }
+ /* add for CONFIG_IEEE80211W, none 11w also can use */
+ _exit_critical_bh(&adapter->security_key_mutex, &irqL);
+
+ RTW_INFO(FUNC_ADPT_FMT" - End to Disconnect\n", FUNC_ADPT_ARG(adapter));
+}
+
+void rtw_os_indicate_disconnect(_adapter *adapter, u16 reason, u8 locally_generated)
+{
+ /* RT_PMKID_LIST backupPMKIDList[NUM_PMKID_CACHE]; */
+
+
+ netif_carrier_off(adapter->pnetdev); /* Do it first for tx broadcast pkt after disconnection issue! */
+
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_cfg80211_indicate_disconnect(adapter, reason, locally_generated);
+#endif /* CONFIG_IOCTL_CFG80211 */
+
+ rtw_indicate_wx_disassoc_event(adapter);
+
+#ifdef RTK_DMP_PLATFORM
+ _set_workitem(&adapter->mlmepriv.Linkdown_workitem);
+#endif
+ /* modify for CONFIG_IEEE80211W, none 11w also can use the same command */
+ rtw_reset_securitypriv_cmd(adapter);
+
+
+}
+
+void rtw_report_sec_ie(_adapter *adapter, u8 authmode, u8 *sec_ie)
+{
+ uint len;
+ u8 *buff, *p, i;
+ union iwreq_data wrqu;
+
+
+
+ buff = NULL;
+ if (authmode == _WPA_IE_ID_) {
+
+ buff = rtw_zmalloc(IW_CUSTOM_MAX);
+ if (NULL == buff) {
+ RTW_INFO(FUNC_ADPT_FMT ": alloc memory FAIL!!\n",
+ FUNC_ADPT_ARG(adapter));
+ return;
+ }
+ p = buff;
+
+ p += sprintf(p, "ASSOCINFO(ReqIEs=");
+
+ len = sec_ie[1] + 2;
+ len = (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX;
+
+ for (i = 0; i < len; i++)
+ p += sprintf(p, "%02x", sec_ie[i]);
+
+ p += sprintf(p, ")");
+
+ memset(&wrqu, 0, sizeof(wrqu));
+
+ wrqu.data.length = p - buff;
+
+ wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ? wrqu.data.length : IW_CUSTOM_MAX;
+
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(adapter->pnetdev, IWEVCUSTOM, &wrqu, buff);
+#endif
+
+ rtw_mfree(buff, IW_CUSTOM_MAX);
+ }
+
+
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+static void _survey_timer_hdl(void *FunctionContext)
+#else
+static void _survey_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *padapter = (_adapter *)FunctionContext;
+#else
+ _adapter *padapter = from_timer(padapter, t, mlmeextpriv.survey_timer);
+#endif
+
+ survey_timer_hdl(padapter);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+static void _link_timer_hdl(void *FunctionContext)
+#else
+static void _link_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *padapter = (_adapter *)FunctionContext;
+#else
+ _adapter *padapter = from_timer(padapter, t, mlmeextpriv.link_timer);
+#endif
+
+ link_timer_hdl(padapter);
+}
+
+#ifdef CONFIG_RTW_80211R
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _ft_link_timer_hdl(void *FunctionContext)
+#else
+void _ft_link_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *padapter = (_adapter *)FunctionContext;
+#else
+ _adapter *padapter = from_timer(ipadapter, t, ft_link_timer);
+#endif
+
+ ft_link_timer_hdl(padapter);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _ft_roam_timer_hdl(void *FunctionContext)
+#else
+void _ft_roam_timer_hdl(struct timer_list *t);
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *padapter = (_adapter *)FunctionContext;
+#else
+ _adapter *padapter = from_timer(adapter, t, ft_roam_timer);
+#endif
+
+ ft_roam_timer_hdl(padapter);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+static void _addba_timer_hdl(void *FunctionContext)
+#else
+static void _addba_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ struct sta_info *psta = (struct sta_info *)FunctionContext;
+#else
+ struct sta_info *psta = from_timer(psta, t, addba_retry_timer);
+#endif
+
+ addba_timer_hdl(psta);
+}
+
+#ifdef CONFIG_IEEE80211W
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _sa_query_timer_hdl(void *FunctionContext)
+#else
+void _sa_query_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ struct sta_info *psta = (struct sta_info *)FunctionContext;
+#else
+ struct sta_info *psta = from_timer(psta, t, dot11w_expire_timer);
+#endif
+
+ sa_query_timer_hdl(psta);
+}
+
+void init_dot11w_expire_timer(_adapter *padapter, struct sta_info *psta)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&psta->dot11w_expire_timer, padapter->pnetdev, _sa_query_timer_hdl, psta);
+#else
+ timer_setip(&psta->dot11w_expire_timer, _sa_query_timer_hdl, 0);
+#endif
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+void init_addba_retry_timer(_adapter *padapter, struct sta_info *psta)
+{
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&psta->addba_retry_timer, padapter->pnetdev, _addba_timer_hdl, psta);
+#else
+ timer_setup(&psta->addba_retry_timer, _addba_timer_hdl, 0);
+#endif
+}
+
+/*
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _reauth_timer_hdl(void *FunctionContext)
+#else
+void _reauth_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *padapter = (_adapter *)FunctionContext;
+#else
+ _adapter *padapter = from_timer(adapter, t, reauth_timer);
+#endif
+
+ reauth_timer_hdl(padapter);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _reassoc_timer_hdl(void *FunctionContext)
+#else
+void _reassoc_timer_hdl(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _adapter *padapter = (_adapter *)FunctionContext;
+#else
+ _adapter *padapter = from_timer(adapter, t, reassoc_timer);
+#endif
+
+` reassoc_timer_hdl(padapter);
+}
+*/
+
+void init_mlme_ext_timer(_adapter *padapter)
+{
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&pmlmeext->survey_timer, padapter->pnetdev, _survey_timer_hdl, padapter);
+ _init_timer(&pmlmeext->link_timer, padapter->pnetdev, _link_timer_hdl, padapter);
+#ifdef CONFIG_RTW_80211R
+ _init_timer(&pmlmeext->ft_link_timer, padapter->pnetdev, _ft_link_timer_hdl, padapter);
+ _init_timer(&pmlmeext->ft_roam_timer, padapter->pnetdev, _ft_roam_timer_hdl, padapter);
+#endif
+
+ /* _init_timer(&pmlmeext->ADDBA_timer, padapter->pnetdev, _addba_timer_hdl, padapter); */
+
+ /* _init_timer(&pmlmeext->reauth_timer, padapter->pnetdev, _reauth_timer_hdl, padapter); */
+ /* _init_timer(&pmlmeext->reassoc_timer, padapter->pnetdev, _reassoc_timer_hdl, padapter); */
+#else
+ timer_setup(&pmlmeext->survey_timer, _survey_timer_hdl, 0);
+ timer_setup(&pmlmeext->link_timer, _link_timer_hdl, 0);
+#ifdef CONFIG_RTW_80211R
+ timer_setup(&pmlmeext->ft_link_timer, _ft_link_timer_hdl, 0);
+ timer_setup(&pmlmeext->ft_roam_timer, _ft_roam_timer_hdl, 0);
+#endif
+
+ /* timer_setup(&pmlmeext->ADDBA_timer, _addba_timer_hdl, 0); */
+
+ /* timer_setup(&pmlmeext->reauth_timer, _reauth_timer_hdl, 0); */
+ /* timer_setup(&pmlmeext->reassoc_timer, _reassoc_timer_hdl, 0); */
+#endif
+}
+
+#ifdef CONFIG_AP_MODE
+
+void rtw_indicate_sta_assoc_event(_adapter *padapter, struct sta_info *psta)
+{
+ union iwreq_data wrqu;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (psta == NULL)
+ return;
+
+ if (psta->aid > NUM_STA)
+ return;
+
+ if (pstapriv->sta_aid[psta->aid - 1] != psta)
+ return;
+
+
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+ RTW_INFO("+rtw_indicate_sta_assoc_event\n");
+
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, IWEVREGISTERED, &wrqu, NULL);
+#endif
+
+}
+
+void rtw_indicate_sta_disassoc_event(_adapter *padapter, struct sta_info *psta)
+{
+ union iwreq_data wrqu;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+
+ if (psta == NULL)
+ return;
+
+ if (psta->aid > NUM_STA)
+ return;
+
+ if (pstapriv->sta_aid[psta->aid - 1] != psta)
+ return;
+
+
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+ RTW_INFO("+rtw_indicate_sta_disassoc_event\n");
+
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, IWEVEXPIRED, &wrqu, NULL);
+#endif
+
+}
+
+
+#ifdef CONFIG_HOSTAPD_MLME
+
+static int mgnt_xmit_entry(struct sk_buff *skb, struct net_device *pnetdev)
+{
+ struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
+ _adapter *padapter = (_adapter *)phostapdpriv->padapter;
+
+ /* RTW_INFO("%s\n", __func__); */
+
+ return rtw_hal_hostap_mgnt_xmit_entry(padapter, skb);
+}
+
+static int mgnt_netdev_open(struct net_device *pnetdev)
+{
+ struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
+
+ RTW_INFO("mgnt_netdev_open: MAC Address:" MAC_FMT "\n", MAC_ARG(pnetdev->dev_addr));
+
+
+ init_usb_anchor(&phostapdpriv->anchored);
+
+ rtw_netif_wake_queue(pnetdev);
+
+ netif_carrier_on(pnetdev);
+
+ /* rtw_write16(phostapdpriv->padapter, 0x0116, 0x0100); */ /* only excluding beacon */
+
+ return 0;
+}
+static int mgnt_netdev_close(struct net_device *pnetdev)
+{
+ struct hostapd_priv *phostapdpriv = rtw_netdev_priv(pnetdev);
+
+ RTW_INFO("%s\n", __func__);
+
+ usb_kill_anchored_urbs(&phostapdpriv->anchored);
+
+ netif_carrier_off(pnetdev);
+
+ rtw_netif_stop_queue(pnetdev);
+
+ /* rtw_write16(phostapdpriv->padapter, 0x0116, 0x3f3f); */
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+static const struct net_device_ops rtl871x_mgnt_netdev_ops = {
+ .ndo_open = mgnt_netdev_open,
+ .ndo_stop = mgnt_netdev_close,
+ .ndo_start_xmit = mgnt_xmit_entry,
+};
+#endif
+
+int hostapd_mode_init(_adapter *padapter)
+{
+ unsigned char mac[ETH_ALEN];
+ struct hostapd_priv *phostapdpriv;
+ struct net_device *pnetdev;
+
+ pnetdev = rtw_alloc_etherdev(sizeof(struct hostapd_priv));
+ if (!pnetdev)
+ return -ENOMEM;
+
+ /* SET_MODULE_OWNER(pnetdev); */
+ ether_setup(pnetdev);
+
+ /* pnetdev->type = ARPHRD_IEEE80211; */
+
+ phostapdpriv = rtw_netdev_priv(pnetdev);
+ phostapdpriv->pmgnt_netdev = pnetdev;
+ phostapdpriv->padapter = padapter;
+ padapter->phostapdpriv = phostapdpriv;
+
+ /* pnetdev->init = NULL; */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+
+ RTW_INFO("register rtl871x_mgnt_netdev_ops to netdev_ops\n");
+
+ pnetdev->netdev_ops = &rtl871x_mgnt_netdev_ops;
+
+#else
+
+ pnetdev->open = mgnt_netdev_open;
+
+ pnetdev->stop = mgnt_netdev_close;
+
+ pnetdev->hard_start_xmit = mgnt_xmit_entry;
+
+ /* pnetdev->set_mac_address = r871x_net_set_mac_address; */
+
+ /* pnetdev->get_stats = r871x_net_get_stats; */
+
+ /* pnetdev->do_ioctl = r871x_mp_ioctl; */
+
+#endif
+
+ pnetdev->watchdog_timeo = HZ; /* 1 second timeout */
+
+ /* pnetdev->wireless_handlers = NULL; */
+
+#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
+ pnetdev->features |= NETIF_F_IP_CSUM;
+#endif
+
+
+
+ if (dev_alloc_name(pnetdev, "mgnt.wlan%d") < 0)
+ RTW_INFO("hostapd_mode_init(): dev_alloc_name, fail!\n");
+
+
+ /* SET_NETDEV_DEV(pnetdev, pintfpriv->udev); */
+
+
+ mac[0] = 0x00;
+ mac[1] = 0xe0;
+ mac[2] = 0x4c;
+ mac[3] = 0x87;
+ mac[4] = 0x11;
+ mac[5] = 0x12;
+
+ memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
+
+
+ netif_carrier_off(pnetdev);
+
+
+ /* Tell the network stack we exist */
+ if (register_netdev(pnetdev) != 0) {
+ RTW_INFO("hostapd_mode_init(): register_netdev fail!\n");
+
+ if (pnetdev)
+ rtw_free_netdev(pnetdev);
+ }
+
+ return 0;
+
+}
+
+void hostapd_mode_unload(_adapter *padapter)
+{
+ struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
+ struct net_device *pnetdev = phostapdpriv->pmgnt_netdev;
+
+ unregister_netdev(pnetdev);
+ rtw_free_netdev(pnetdev);
+
+}
+
+#endif
+#endif
diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
new file mode 100644
index 000000000000..38f6aae673d6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c
@@ -0,0 +1,4311 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _OS_INTFS_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+#include <rtw_debug.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
+MODULE_AUTHOR("Realtek Semiconductor Corp.");
+MODULE_VERSION(DRIVERVERSION);
+
+/* module param defaults */
+static int rtw_chip_version = 0x00;
+static int rtw_rfintfs = HWPI;
+static int rtw_lbkmode = 0;/* RTL8712_AIR_TRX; */
+static int rtw_network_mode = Ndis802_11IBSS;/* Ndis802_11Infrastructure; */ /* infra, ad-hoc, auto */
+/* NDIS_802_11_SSID ssid; */
+static int rtw_channel = 1;/* ad-hoc support requirement */
+static int rtw_wireless_mode = WIRELESS_MODE_MAX;
+static int rtw_vrtl_carrier_sense = AUTO_VCS;
+static int rtw_vcs_type = RTS_CTS;
+static int rtw_rts_thresh = 2347;
+static int rtw_frag_thresh = 2346;
+static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */
+static int rtw_scan_mode = 1;/* active, passive */
+static int rtw_adhoc_tx_pwr = 1;
+static int rtw_soft_ap = 0;
+/* int smart_ps = 1; */
+#ifdef CONFIG_POWER_SAVING
+ static int rtw_power_mgnt = PS_MODE_MAX;
+ #ifdef CONFIG_IPS_LEVEL_2
+ static int rtw_ips_mode = IPS_LEVEL_2;
+ #else
+ static int rtw_ips_mode = IPS_NORMAL;
+ #endif
+#else
+ static int rtw_power_mgnt = PS_MODE_ACTIVE;
+ static int rtw_ips_mode = IPS_NONE;
+#endif
+module_param(rtw_ips_mode, int, 0644);
+MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode");
+
+static int rtw_smart_ps = 2;
+
+static int rtw_check_fw_ps = 1;
+
+#ifdef CONFIG_TX_EARLY_MODE
+static int rtw_early_mode = 1;
+#endif
+
+static int rtw_usb_rxagg_mode = 2;/* RX_AGG_DMA=1, RX_AGG_USB=2 */
+module_param(rtw_usb_rxagg_mode, int, 0644);
+
+/* set log level when inserting driver module, default log level is _DRV_INFO_ = 4,
+* please refer to "How_to_set_driver_debug_log_level.doc" to set the available level.
+*/
+#ifdef RTW_LOG_LEVEL
+ uint rtw_drv_log_level = (uint)RTW_LOG_LEVEL; /* from Makefile */
+#else
+ uint rtw_drv_log_level = _DRV_INFO_;
+#endif
+module_param(rtw_drv_log_level, uint, 0644);
+MODULE_PARM_DESC(rtw_drv_log_level, "set log level when insert driver module, default log level is _DRV_INFO_ = 4");
+
+static int rtw_radio_enable = 1;
+static int rtw_long_retry_lmt = 7;
+static int rtw_short_retry_lmt = 7;
+static int rtw_busy_thresh = 40;
+/* int qos_enable = 0; */ /* * */
+static int rtw_ack_policy = NORMAL_ACK;
+
+static int rtw_mp_mode = 0;
+
+#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_RTW_CUSTOMER_STR)
+static uint rtw_mp_customer_str = 0;
+module_param(rtw_mp_customer_str, uint, 0644);
+MODULE_PARM_DESC(rtw_mp_customer_str, "Whether or not to enable customer str support on MP mode");
+#endif
+
+static int rtw_software_encrypt = 0;
+static int rtw_software_decrypt = 0;
+
+static int rtw_acm_method = 0;/* 0:By SW 1:By HW. */
+
+static int rtw_wmm_enable = 1;/* default is set to enable the wmm. */
+static int rtw_uapsd_enable = 0;
+static int rtw_uapsd_max_sp = NO_LIMIT;
+static int rtw_uapsd_acbk_en = 0;
+static int rtw_uapsd_acbe_en = 0;
+static int rtw_uapsd_acvi_en = 0;
+static int rtw_uapsd_acvo_en = 0;
+static int rtw_pwrtrim_enable = 0; /* Default Enalbe power trim by efuse config */
+
+static uint rtw_tx_bw_mode = 0x21;
+module_param(rtw_tx_bw_mode, uint, 0644);
+MODULE_PARM_DESC(rtw_tx_bw_mode, "The max tx bw for 2.4G and 5G. format is the same as rtw_bw_mode");
+
+static int rtw_led_enable = 1;
+
+int rtw_ht_enable = 1;
+/* 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160MHz, 4: 80+80MHz
+* 2.4G use bit 0 ~ 3, 5G use bit 4 ~ 7
+* 0x21 means enable 2.4G 40MHz & 5G 80MHz */
+int rtw_bw_mode = 0x21;
+int rtw_ampdu_enable = 1;/* for enable tx_ampdu , */ /* 0: disable, 0x1:enable */
+static int rtw_rx_stbc = 1;/* 0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable 2.4GHZ for IOT issue with bufflao's AP at 5GHZ */
+static int rtw_ampdu_amsdu = 0;/* 0: disabled, 1:enabled, 2:auto . There is an IOT issu with DLINK DIR-629 when the flag turn on */
+/* Short GI support Bit Map
+* BIT0 - 20MHz, 0: non-support, 1: support
+* BIT1 - 40MHz, 0: non-support, 1: support
+* BIT2 - 80MHz, 0: non-support, 1: support
+* BIT3 - 160MHz, 0: non-support, 1: support */
+static int rtw_short_gi = 0xf;
+/* BIT0: Enable VHT LDPC Rx, BIT1: Enable VHT LDPC Tx, BIT4: Enable HT LDPC Rx, BIT5: Enable HT LDPC Tx */
+static int rtw_ldpc_cap = 0x33;
+/* BIT0: Enable VHT STBC Rx, BIT1: Enable VHT STBC Tx, BIT4: Enable HT STBC Rx, BIT5: Enable HT STBC Tx */
+static int rtw_stbc_cap = 0x13;
+/*
+* BIT0: Enable VHT SU Beamformer
+* BIT1: Enable VHT SU Beamformee
+* BIT2: Enable VHT MU Beamformer, depend on VHT SU Beamformer
+* BIT3: Enable VHT MU Beamformee, depend on VHT SU Beamformee
+* BIT4: Enable HT Beamformer
+* BIT5: Enable HT Beamformee
+*/
+static int rtw_beamform_cap = BIT(1) | BIT(3);
+static int rtw_bfer_rf_number = 0; /*BeamformerCapRfNum Rf path number, 0 for auto, others for manual*/
+static int rtw_bfee_rf_number = 0; /*BeamformeeCapRfNum Rf path number, 0 for auto, others for manual*/
+
+static int rtw_lowrate_two_xmit = 1;/* Use 2 path Tx to transmit MCS0~7 and legacy mode */
+
+static int rtw_rf_config = RF_TYPE_AUTO;
+module_param(rtw_rf_config, int, 0644);
+
+/* 0: not check in watch dog, 1: check in watch dog */
+static int rtw_check_hw_status = 0;
+
+static int rtw_low_power = 0;
+#ifdef CONFIG_WIFI_TEST
+ static int rtw_wifi_spec = 1;/* for wifi test */
+#else
+ static int rtw_wifi_spec = 0;
+#endif
+
+#ifdef CONFIG_DEFAULT_PATTERNS_EN
+ static bool rtw_support_default_patterns = true;
+#else
+ static bool rtw_support_default_patterns = false;
+#endif
+
+static int rtw_special_rf_path = 0; /* 0: 2T2R ,1: only turn on path A 1T1R */
+
+static char rtw_country_unspecified[] = {0xFF, 0xFF, 0x00};
+static char *rtw_country_code = rtw_country_unspecified;
+module_param(rtw_country_code, charp, 0644);
+MODULE_PARM_DESC(rtw_country_code, "The default country code (in alpha2)");
+
+static int rtw_channel_plan = RTW_CHPLAN_MAX;
+module_param(rtw_channel_plan, int, 0644);
+MODULE_PARM_DESC(rtw_channel_plan, "The default chplan ID when rtw_alpha2 is not specified or valid");
+
+static uint rtw_excl_chs[MAX_CHANNEL_NUM] = CONFIG_RTW_EXCL_CHS;
+static int rtw_excl_chs_num = 0;
+module_param_array(rtw_excl_chs, uint, &rtw_excl_chs_num, 0644);
+MODULE_PARM_DESC(rtw_excl_chs, "exclusive channel array");
+
+/*if concurrent softap + p2p(GO) is needed, this param lets p2p response full channel list.
+But Softap must be SHUT DOWN once P2P decide to set up connection and become a GO.*/
+#ifdef CONFIG_FULL_CH_IN_P2P_HANDSHAKE
+ static int rtw_full_ch_in_p2p_handshake = 1; /* reply full channel list*/
+#else
+ static int rtw_full_ch_in_p2p_handshake = 0; /* reply only softap channel*/
+#endif
+
+#ifdef CONFIG_BT_COEXIST
+static int rtw_btcoex_enable = 2;
+module_param(rtw_btcoex_enable, int, 0644);
+MODULE_PARM_DESC(rtw_btcoex_enable, "BT co-existence on/off, 0:off, 1:on, 2:by efuse");
+
+static int rtw_ant_num = 0;
+module_param(rtw_ant_num, int, 0644);
+MODULE_PARM_DESC(rtw_ant_num, "Antenna number setting, 0:by efuse");
+
+static int rtw_bt_iso = 2;/* 0:Low, 1:High, 2:From Efuse */
+static int rtw_bt_sco = 3;/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */
+static int rtw_bt_ampdu = 1 ; /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+#endif /* CONFIG_BT_COEXIST */
+
+static int rtw_AcceptAddbaReq = true;/* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */
+
+static int rtw_antdiv_cfg = 2; /* 0:OFF , 1:ON, 2:decide by Efuse config */
+static int rtw_antdiv_type = 0
+ ; /* 0:decide by efuse 1: for 88EE, 1Tx and 1RxCG are diversity.(2 Ant with SPDT), 2: for 88EE, 1Tx and 2Rx are diversity.( 2 Ant, Tx and RxCG are both on aux port, RxCS is on main port ), 3: for 88EE, 1Tx and 1RxCG are fixed.(1Ant, Tx and RxCG are both on aux port) */
+
+static int rtw_drv_ant_band_switch = 1; /* 0:OFF , 1:ON, Driver control antenna band switch*/
+
+/* 0: doesn't switch, 1: switch from usb2.0 to usb 3.0 2: switch from usb3.0 to usb 2.0 */
+static int rtw_switch_usb_mode = 0;
+
+#ifdef CONFIG_USB_AUTOSUSPEND
+static int rtw_enusbss = 1;/* 0:disable,1:enable */
+#else
+static int rtw_enusbss = 0;/* 0:disable,1:enable */
+#endif
+
+static int rtw_hwpdn_mode = 2; /* 0:disable,1:enable,2: by EFUSE config */
+
+#ifdef CONFIG_HW_PWRP_DETECTION
+static int rtw_hwpwrp_detect = 1;
+#else
+static int rtw_hwpwrp_detect = 0; /* HW power ping detect 0:disable , 1:enable */
+#endif
+
+static int rtw_hw_wps_pbc = 1;
+
+#ifdef CONFIG_TX_MCAST2UNI
+int rtw_mc2u_disable = 0;
+#endif /* CONFIG_TX_MCAST2UNI */
+
+#ifdef CONFIG_80211D
+static int rtw_80211d = 0;
+#endif
+
+#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV
+static int rtw_force_ant = 2;/* 0 :normal, 1:Main ant, 2:Aux ant */
+static int rtw_force_igi = 0; /* 0 :normal */
+module_param(rtw_force_ant, int, 0644);
+module_param(rtw_force_igi, int, 0644);
+#endif
+
+static int rtw_force_igi_lb = CONFIG_RTW_FORCE_IGI_LB;
+module_param(rtw_force_igi_lb, int, 0644);
+MODULE_PARM_DESC(rtw_force_igi_lb, "force IGI low-bound, 0:no specified");
+
+#ifdef CONFIG_QOS_OPTIMIZATION
+static int rtw_qos_opt_enable = 1; /* 0: disable,1:enable */
+#else
+static int rtw_qos_opt_enable = 0; /* 0: disable,1:enable */
+#endif
+module_param(rtw_qos_opt_enable, int, 0644);
+
+#ifdef CONFIG_AUTO_CHNL_SEL_NHM
+static int rtw_acs_mode = 1; /*0:disable, 1:enable*/
+module_param(rtw_acs_mode, int, 0644);
+
+static int rtw_acs_auto_scan = 0; /*0:disable, 1:enable*/
+module_param(rtw_acs_auto_scan, int, 0644);
+
+#endif
+
+static char *ifname = "wlan%d";
+module_param(ifname, charp, 0644);
+MODULE_PARM_DESC(ifname, "The default name to allocate for first interface");
+
+static char *if2name = "wlan%d";
+module_param(if2name, charp, 0644);
+MODULE_PARM_DESC(if2name, "The default name to allocate for second interface");
+
+char *rtw_initmac = NULL; /* temp mac address if users want to use instead of the mac address in Efuse */
+
+#ifdef CONFIG_CONCURRENT_MODE
+
+ #if (CONFIG_IFACE_NUMBER > 2)
+ int rtw_virtual_iface_num = CONFIG_IFACE_NUMBER - 1;
+ module_param(rtw_virtual_iface_num, int, 0644);
+ #else
+ int rtw_virtual_iface_num = 1;
+ #endif
+
+#endif
+
+module_param(rtw_pwrtrim_enable, int, 0644);
+module_param(rtw_initmac, charp, 0644);
+module_param(rtw_special_rf_path, int, 0644);
+module_param(rtw_chip_version, int, 0644);
+module_param(rtw_rfintfs, int, 0644);
+module_param(rtw_lbkmode, int, 0644);
+module_param(rtw_network_mode, int, 0644);
+module_param(rtw_channel, int, 0644);
+module_param(rtw_mp_mode, int, 0644);
+module_param(rtw_wmm_enable, int, 0644);
+module_param(rtw_vrtl_carrier_sense, int, 0644);
+module_param(rtw_vcs_type, int, 0644);
+module_param(rtw_busy_thresh, int, 0644);
+module_param(rtw_led_enable, int, 0644);
+module_param(rtw_ht_enable, int, 0644);
+module_param(rtw_bw_mode, int, 0644);
+module_param(rtw_ampdu_enable, int, 0644);
+module_param(rtw_rx_stbc, int, 0644);
+module_param(rtw_ampdu_amsdu, int, 0644);
+
+#ifdef CONFIG_BEAMFORMING
+module_param(rtw_beamform_cap, int, 0644);
+#endif
+module_param(rtw_lowrate_two_xmit, int, 0644);
+
+module_param(rtw_power_mgnt, int, 0644);
+module_param(rtw_smart_ps, int, 0644);
+module_param(rtw_low_power, int, 0644);
+module_param(rtw_wifi_spec, int, 0644);
+
+module_param(rtw_full_ch_in_p2p_handshake, int, 0644);
+module_param(rtw_antdiv_cfg, int, 0644);
+module_param(rtw_antdiv_type, int, 0644);
+
+module_param(rtw_drv_ant_band_switch, int, 0644);
+
+module_param(rtw_switch_usb_mode, int, 0644);
+
+module_param(rtw_enusbss, int, 0644);
+module_param(rtw_hwpdn_mode, int, 0644);
+module_param(rtw_hwpwrp_detect, int, 0644);
+
+module_param(rtw_hw_wps_pbc, int, 0644);
+module_param(rtw_check_hw_status, int, 0644);
+
+#ifdef CONFIG_TX_EARLY_MODE
+module_param(rtw_early_mode, int, 0644);
+#endif
+#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+static char *rtw_adaptor_info_caching_file_path = "/data/misc/wifi/rtw_cache";
+module_param(rtw_adaptor_info_caching_file_path, charp, 0644);
+MODULE_PARM_DESC(rtw_adaptor_info_caching_file_path, "The path of adapter info cache file");
+#endif /* CONFIG_ADAPTOR_INFO_CACHING_FILE */
+
+#ifdef CONFIG_LAYER2_ROAMING
+static uint rtw_max_roaming_times = 2;
+module_param(rtw_max_roaming_times, uint, 0644);
+MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try");
+#endif /* CONFIG_LAYER2_ROAMING */
+
+#ifdef CONFIG_IOL
+static int rtw_fw_iol = 1;
+module_param(rtw_fw_iol, int, 0644);
+MODULE_PARM_DESC(rtw_fw_iol, "FW IOL. 0:Disable, 1:enable, 2:by usb speed");
+#endif /* CONFIG_IOL */
+
+#ifdef CONFIG_FILE_FWIMG
+static char *rtw_fw_file_path = "/system/etc/firmware/rtlwifi/FW_NIC.BIN";
+module_param(rtw_fw_file_path, charp, 0644);
+MODULE_PARM_DESC(rtw_fw_file_path, "The path of fw image");
+
+static char *rtw_fw_wow_file_path = "/system/etc/firmware/rtlwifi/FW_WoWLAN.BIN";
+module_param(rtw_fw_wow_file_path, charp, 0644);
+MODULE_PARM_DESC(rtw_fw_wow_file_path, "The path of fw for Wake on Wireless image");
+
+#ifdef CONFIG_MP_INCLUDED
+static char *rtw_fw_mp_bt_file_path = "";
+module_param(rtw_fw_mp_bt_file_path, charp, 0644);
+MODULE_PARM_DESC(rtw_fw_mp_bt_file_path, "The path of fw for MP-BT image");
+#endif /* CONFIG_MP_INCLUDED */
+#endif /* CONFIG_FILE_FWIMG */
+
+#ifdef CONFIG_TX_MCAST2UNI
+module_param(rtw_mc2u_disable, int, 0644);
+#endif /* CONFIG_TX_MCAST2UNI */
+
+#ifdef CONFIG_80211D
+module_param(rtw_80211d, int, 0644);
+MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism");
+#endif
+
+static uint rtw_notch_filter = RTW_NOTCH_FILTER;
+module_param(rtw_notch_filter, uint, 0644);
+MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P");
+
+static uint rtw_hiq_filter = CONFIG_RTW_HIQ_FILTER;
+module_param(rtw_hiq_filter, uint, 0644);
+MODULE_PARM_DESC(rtw_hiq_filter, "0:allow all, 1:allow special, 2:deny all");
+
+static uint rtw_adaptivity_en = CONFIG_RTW_ADAPTIVITY_EN;
+module_param(rtw_adaptivity_en, uint, 0644);
+MODULE_PARM_DESC(rtw_adaptivity_en, "0:disable, 1:enable");
+
+static uint rtw_adaptivity_mode = CONFIG_RTW_ADAPTIVITY_MODE;
+module_param(rtw_adaptivity_mode, uint, 0644);
+MODULE_PARM_DESC(rtw_adaptivity_mode, "0:normal, 1:carrier sense");
+
+static uint rtw_adaptivity_dml = CONFIG_RTW_ADAPTIVITY_DML;
+module_param(rtw_adaptivity_dml, uint, 0644);
+MODULE_PARM_DESC(rtw_adaptivity_dml, "0:disable, 1:enable");
+
+static uint rtw_adaptivity_dc_backoff = CONFIG_RTW_ADAPTIVITY_DC_BACKOFF;
+module_param(rtw_adaptivity_dc_backoff, uint, 0644);
+MODULE_PARM_DESC(rtw_adaptivity_dc_backoff, "DC backoff for Adaptivity");
+
+static int rtw_adaptivity_th_l2h_ini = CONFIG_RTW_ADAPTIVITY_TH_L2H_INI;
+module_param(rtw_adaptivity_th_l2h_ini, int, 0644);
+MODULE_PARM_DESC(rtw_adaptivity_th_l2h_ini, "th_l2h_ini for Adaptivity");
+
+static int rtw_adaptivity_th_edcca_hl_diff = CONFIG_RTW_ADAPTIVITY_TH_EDCCA_HL_DIFF;
+module_param(rtw_adaptivity_th_edcca_hl_diff, int, 0644);
+MODULE_PARM_DESC(rtw_adaptivity_th_edcca_hl_diff, "th_edcca_hl_diff for Adaptivity");
+
+#ifdef CONFIG_DFS_MASTER
+static uint rtw_dfs_region_domain = CONFIG_RTW_DFS_REGION_DOMAIN;
+module_param(rtw_dfs_region_domain, uint, 0644);
+MODULE_PARM_DESC(rtw_dfs_region_domain, "0:UNKNOWN, 1:FCC, 2:MKK, 3:ETSI");
+#endif
+
+static uint rtw_amplifier_type_2g = CONFIG_RTW_AMPLIFIER_TYPE_2G;
+module_param(rtw_amplifier_type_2g, uint, 0644);
+MODULE_PARM_DESC(rtw_amplifier_type_2g, "BIT3:2G ext-PA, BIT4:2G ext-LNA");
+
+static uint rtw_amplifier_type_5g = CONFIG_RTW_AMPLIFIER_TYPE_5G;
+module_param(rtw_amplifier_type_5g, uint, 0644);
+MODULE_PARM_DESC(rtw_amplifier_type_5g, "BIT6:5G ext-PA, BIT7:5G ext-LNA");
+
+static uint rtw_RFE_type = CONFIG_RTW_RFE_TYPE;
+module_param(rtw_RFE_type, uint, 0644);
+MODULE_PARM_DESC(rtw_RFE_type, "default init value:64");
+
+static uint rtw_powertracking_type = 64;
+module_param(rtw_powertracking_type, uint, 0644);
+MODULE_PARM_DESC(rtw_powertracking_type, "default init value:64");
+
+static uint rtw_GLNA_type = CONFIG_RTW_GLNA_TYPE;
+module_param(rtw_GLNA_type, uint, 0644);
+MODULE_PARM_DESC(rtw_GLNA_type, "default init value:0");
+
+static uint rtw_TxBBSwing_2G = 0xFF;
+module_param(rtw_TxBBSwing_2G, uint, 0644);
+MODULE_PARM_DESC(rtw_TxBBSwing_2G, "default init value:0xFF");
+
+static uint rtw_TxBBSwing_5G = 0xFF;
+module_param(rtw_TxBBSwing_5G, uint, 0644);
+MODULE_PARM_DESC(rtw_TxBBSwing_5G, "default init value:0xFF");
+
+static uint rtw_OffEfuseMask = 0;
+module_param(rtw_OffEfuseMask, uint, 0644);
+MODULE_PARM_DESC(rtw_OffEfuseMask, "default open Efuse Mask value:0");
+
+static uint rtw_FileMaskEfuse = 0;
+module_param(rtw_FileMaskEfuse, uint, 0644);
+MODULE_PARM_DESC(rtw_FileMaskEfuse, "default drv Mask Efuse value:0");
+
+static uint rtw_rxgain_offset_2g = 0;
+module_param(rtw_rxgain_offset_2g, uint, 0644);
+MODULE_PARM_DESC(rtw_rxgain_offset_2g, "default RF Gain 2G Offset value:0");
+
+static uint rtw_rxgain_offset_5gl = 0;
+module_param(rtw_rxgain_offset_5gl, uint, 0644);
+MODULE_PARM_DESC(rtw_rxgain_offset_5gl, "default RF Gain 5GL Offset value:0");
+
+static uint rtw_rxgain_offset_5gm = 0;
+module_param(rtw_rxgain_offset_5gm, uint, 0644);
+MODULE_PARM_DESC(rtw_rxgain_offset_5gm, "default RF Gain 5GM Offset value:0");
+
+static uint rtw_rxgain_offset_5gh = 0;
+module_param(rtw_rxgain_offset_5gh, uint, 0644);
+MODULE_PARM_DESC(rtw_rxgain_offset_5gm, "default RF Gain 5GL Offset value:0");
+
+static uint rtw_pll_ref_clk_sel = CONFIG_RTW_PLL_REF_CLK_SEL;
+module_param(rtw_pll_ref_clk_sel, uint, 0644);
+MODULE_PARM_DESC(rtw_pll_ref_clk_sel, "force pll_ref_clk_sel, 0xF:use autoload value");
+
+static int rtw_tx_pwr_by_rate = CONFIG_TXPWR_BY_RATE_EN;
+module_param(rtw_tx_pwr_by_rate, int, 0644);
+MODULE_PARM_DESC(rtw_tx_pwr_by_rate, "0:Disable, 1:Enable, 2: Depend on efuse");
+
+static int rtw_tx_pwr_lmt_enable = CONFIG_TXPWR_LIMIT_EN;
+module_param(rtw_tx_pwr_lmt_enable, int, 0644);
+MODULE_PARM_DESC(rtw_tx_pwr_lmt_enable, "0:Disable, 1:Enable, 2: Depend on efuse");
+
+static int rtw_target_tx_pwr_2g_a[RATE_SECTION_NUM] = CONFIG_RTW_TARGET_TX_PWR_2G_A;
+static int rtw_target_tx_pwr_2g_a_num = 0;
+module_param_array(rtw_target_tx_pwr_2g_a, int, &rtw_target_tx_pwr_2g_a_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_2g_a, "2.4G target tx power (unit:dBm) of RF path A for each rate section, should match the real calibrate power, -1: undefined");
+
+static int rtw_target_tx_pwr_2g_b[RATE_SECTION_NUM] = CONFIG_RTW_TARGET_TX_PWR_2G_B;
+static int rtw_target_tx_pwr_2g_b_num = 0;
+module_param_array(rtw_target_tx_pwr_2g_b, int, &rtw_target_tx_pwr_2g_b_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_2g_b, "2.4G target tx power (unit:dBm) of RF path B for each rate section, should match the real calibrate power, -1: undefined");
+
+static int rtw_target_tx_pwr_2g_c[RATE_SECTION_NUM] = CONFIG_RTW_TARGET_TX_PWR_2G_C;
+static int rtw_target_tx_pwr_2g_c_num = 0;
+module_param_array(rtw_target_tx_pwr_2g_c, int, &rtw_target_tx_pwr_2g_c_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_2g_c, "2.4G target tx power (unit:dBm) of RF path C for each rate section, should match the real calibrate power, -1: undefined");
+
+static int rtw_target_tx_pwr_2g_d[RATE_SECTION_NUM] = CONFIG_RTW_TARGET_TX_PWR_2G_D;
+static int rtw_target_tx_pwr_2g_d_num = 0;
+module_param_array(rtw_target_tx_pwr_2g_d, int, &rtw_target_tx_pwr_2g_d_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_2g_d, "2.4G target tx power (unit:dBm) of RF path D for each rate section, should match the real calibrate power, -1: undefined");
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+static int rtw_target_tx_pwr_5g_a[RATE_SECTION_NUM - 1] = CONFIG_RTW_TARGET_TX_PWR_5G_A;
+static int rtw_target_tx_pwr_5g_a_num = 0;
+module_param_array(rtw_target_tx_pwr_5g_a, int, &rtw_target_tx_pwr_5g_a_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_5g_a, "5G target tx power (unit:dBm) of RF path A for each rate section, should match the real calibrate power, -1: undefined");
+
+static int rtw_target_tx_pwr_5g_b[RATE_SECTION_NUM - 1] = CONFIG_RTW_TARGET_TX_PWR_5G_B;
+static int rtw_target_tx_pwr_5g_b_num = 0;
+module_param_array(rtw_target_tx_pwr_5g_b, int, &rtw_target_tx_pwr_5g_b_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_5g_b, "5G target tx power (unit:dBm) of RF path B for each rate section, should match the real calibrate power, -1: undefined");
+
+static int rtw_target_tx_pwr_5g_c[RATE_SECTION_NUM - 1] = CONFIG_RTW_TARGET_TX_PWR_5G_C;
+static int rtw_target_tx_pwr_5g_c_num = 0;
+module_param_array(rtw_target_tx_pwr_5g_c, int, &rtw_target_tx_pwr_5g_c_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_5g_c, "5G target tx power (unit:dBm) of RF path C for each rate section, should match the real calibrate power, -1: undefined");
+
+static int rtw_target_tx_pwr_5g_d[RATE_SECTION_NUM - 1] = CONFIG_RTW_TARGET_TX_PWR_5G_D;
+static int rtw_target_tx_pwr_5g_d_num = 0;
+module_param_array(rtw_target_tx_pwr_5g_d, int, &rtw_target_tx_pwr_5g_d_num, 0644);
+MODULE_PARM_DESC(rtw_target_tx_pwr_5g_d, "5G target tx power (unit:dBm) of RF path D for each rate section, should match the real calibrate power, -1: undefined");
+#endif /* CONFIG_IEEE80211_BAND_5GHZ */
+
+#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
+char *rtw_phy_file_path = REALTEK_CONFIG_PATH;
+module_param(rtw_phy_file_path, charp, 0644);
+MODULE_PARM_DESC(rtw_phy_file_path, "The path of phy parameter");
+/* PHY FILE Bit Map
+* BIT0 - MAC, 0: non-support, 1: support
+* BIT1 - BB, 0: non-support, 1: support
+* BIT2 - BB_PG, 0: non-support, 1: support
+* BIT3 - BB_MP, 0: non-support, 1: support
+* BIT4 - RF, 0: non-support, 1: support
+* BIT5 - RF_TXPWR_TRACK, 0: non-support, 1: support
+* BIT6 - RF_TXPWR_LMT, 0: non-support, 1: support */
+static int rtw_load_phy_file = (BIT2 | BIT6);
+module_param(rtw_load_phy_file, int, 0644);
+MODULE_PARM_DESC(rtw_load_phy_file, "PHY File Bit Map");
+static int rtw_decrypt_phy_file = 0;
+module_param(rtw_decrypt_phy_file, int, 0644);
+MODULE_PARM_DESC(rtw_decrypt_phy_file, "Enable Decrypt PHY File");
+#endif
+
+#ifdef CONFIG_SUPPORT_TRX_SHARED
+#ifdef DFT_TRX_SHARE_MODE
+int rtw_trx_share_mode = DFT_TRX_SHARE_MODE;
+#else
+int rtw_trx_share_mode = 0;
+#endif
+module_param(rtw_trx_share_mode, int, 0644);
+MODULE_PARM_DESC(rtw_trx_share_mode, "TRx FIFO Shared");
+#endif
+
+int _netdev_open(struct net_device *pnetdev);
+int netdev_open(struct net_device *pnetdev);
+static int netdev_close(struct net_device *pnetdev);
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+extern int rtw_sdio_set_power(int on);
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+
+#ifdef CONFIG_MCC_MODE
+/* enable MCC mode or not */
+static int rtw_en_mcc = 1;
+/* can referece following value before insmod driver */
+static int rtw_mcc_ap_bw20_target_tx_tp = MCC_AP_BW20_TARGET_TX_TP;
+static int rtw_mcc_ap_bw40_target_tx_tp = MCC_AP_BW40_TARGET_TX_TP;
+static int rtw_mcc_ap_bw80_target_tx_tp = MCC_AP_BW80_TARGET_TX_TP;
+static int rtw_mcc_sta_bw20_target_tx_tp = MCC_STA_BW20_TARGET_TX_TP;
+static int rtw_mcc_sta_bw40_target_tx_tp = MCC_STA_BW40_TARGET_TX_TP;
+static int rtw_mcc_sta_bw80_target_tx_tp = MCC_STA_BW80_TARGET_TX_TP;
+static int rtw_mcc_single_tx_cri = MCC_SINGLE_TX_CRITERIA;
+static int rtw_mcc_policy_table_idx = 0;
+static int rtw_mcc_duration = 0;
+static int rtw_mcc_tsf_sync_offset = 0;
+static int rtw_mcc_start_time_offset = 0;
+static int rtw_mcc_interval = 0;
+static int rtw_mcc_guard_offset0 = -1;
+static int rtw_mcc_guard_offset1 = -1;
+module_param(rtw_en_mcc, int, 0644);
+module_param(rtw_mcc_single_tx_cri, int, 0644);
+module_param(rtw_mcc_ap_bw20_target_tx_tp, int, 0644);
+module_param(rtw_mcc_ap_bw40_target_tx_tp, int, 0644);
+module_param(rtw_mcc_ap_bw80_target_tx_tp, int, 0644);
+module_param(rtw_mcc_sta_bw20_target_tx_tp, int, 0644);
+module_param(rtw_mcc_sta_bw40_target_tx_tp, int, 0644);
+module_param(rtw_mcc_sta_bw80_target_tx_tp, int, 0644);
+module_param(rtw_mcc_policy_table_idx, int, 0644);
+module_param(rtw_mcc_duration, int, 0644);
+module_param(rtw_mcc_tsf_sync_offset, int, 0644);
+module_param(rtw_mcc_start_time_offset, int, 0644);
+module_param(rtw_mcc_interval, int, 0644);
+module_param(rtw_mcc_guard_offset0, int, 0644);
+module_param(rtw_mcc_guard_offset1, int, 0644);
+#endif /*CONFIG_MCC_MODE */
+
+#ifdef CONFIG_RTW_NAPI
+/*following setting should define NAPI in Makefile
+enable napi only = 1, disable napi = 0*/
+static int rtw_en_napi = 1;
+module_param(rtw_en_napi, int, 0644);
+#ifdef CONFIG_RTW_GRO
+/*following setting should define GRO in Makefile
+enable gro = 1, disable gro = 0*/
+static int rtw_en_gro = 1;
+module_param(rtw_en_gro, int, 0644);
+#endif /* CONFIG_RTW_GRO */
+#endif /* CONFIG_RTW_NAPI */
+
+static void rtw_regsty_load_target_tx_power(struct registry_priv *regsty)
+{
+ int path, rs;
+ int *target_tx_pwr;
+
+ for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {
+ if (path == RF_PATH_A)
+ target_tx_pwr = rtw_target_tx_pwr_2g_a;
+ else if (path == RF_PATH_B)
+ target_tx_pwr = rtw_target_tx_pwr_2g_b;
+ else if (path == RF_PATH_C)
+ target_tx_pwr = rtw_target_tx_pwr_2g_c;
+ else if (path == RF_PATH_D)
+ target_tx_pwr = rtw_target_tx_pwr_2g_d;
+
+ for (rs = CCK; rs < RATE_SECTION_NUM; rs++)
+ regsty->target_tx_pwr_2g[path][rs] = target_tx_pwr[rs];
+ }
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+ for (path = RF_PATH_A; path < RF_PATH_MAX; path++) {
+ if (path == RF_PATH_A)
+ target_tx_pwr = rtw_target_tx_pwr_5g_a;
+ else if (path == RF_PATH_B)
+ target_tx_pwr = rtw_target_tx_pwr_5g_b;
+ else if (path == RF_PATH_C)
+ target_tx_pwr = rtw_target_tx_pwr_5g_c;
+ else if (path == RF_PATH_D)
+ target_tx_pwr = rtw_target_tx_pwr_5g_d;
+
+ for (rs = OFDM; rs < RATE_SECTION_NUM; rs++)
+ regsty->target_tx_pwr_5g[path][rs - 1] = target_tx_pwr[rs - 1];
+ }
+#endif /* CONFIG_IEEE80211_BAND_5GHZ */
+}
+
+inline void rtw_regsty_load_excl_chs(struct registry_priv *regsty)
+{
+ int i;
+ int ch_num = 0;
+
+ for (i = 0; i < MAX_CHANNEL_NUM; i++)
+ if (((u8)rtw_excl_chs[i]) != 0)
+ regsty->excl_chs[ch_num++] = (u8)rtw_excl_chs[i];
+
+ if (ch_num < MAX_CHANNEL_NUM)
+ regsty->excl_chs[ch_num] = 0;
+}
+
+uint loadparam(_adapter *padapter)
+{
+ uint status = _SUCCESS;
+ struct registry_priv *registry_par = &padapter->registrypriv;
+
+
+#ifdef CONFIG_RTW_DEBUG
+ if (rtw_drv_log_level >= _DRV_MAX_)
+ rtw_drv_log_level = _DRV_DEBUG_;
+#endif
+
+ registry_par->chip_version = (u8)rtw_chip_version;
+ registry_par->rfintfs = (u8)rtw_rfintfs;
+ registry_par->lbkmode = (u8)rtw_lbkmode;
+ /* registry_par->hci = (u8)hci; */
+ registry_par->network_mode = (u8)rtw_network_mode;
+
+ memcpy(registry_par->ssid.Ssid, "ANY", 3);
+ registry_par->ssid.SsidLength = 3;
+
+ registry_par->channel = (u8)rtw_channel;
+ registry_par->wireless_mode = (u8)rtw_wireless_mode;
+
+ if (IsSupported24G(registry_par->wireless_mode) && (!is_supported_5g(registry_par->wireless_mode))
+ && (registry_par->channel > 14))
+ registry_par->channel = 1;
+ else if (is_supported_5g(registry_par->wireless_mode) && (!IsSupported24G(registry_par->wireless_mode))
+ && (registry_par->channel <= 14))
+ registry_par->channel = 36;
+
+ registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ;
+ registry_par->vcs_type = (u8)rtw_vcs_type;
+ registry_par->rts_thresh = (u16)rtw_rts_thresh;
+ registry_par->frag_thresh = (u16)rtw_frag_thresh;
+ registry_par->preamble = (u8)rtw_preamble;
+ registry_par->scan_mode = (u8)rtw_scan_mode;
+ registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr;
+ registry_par->soft_ap = (u8)rtw_soft_ap;
+ registry_par->smart_ps = (u8)rtw_smart_ps;
+ registry_par->check_fw_ps = (u8)rtw_check_fw_ps;
+ registry_par->power_mgnt = (u8)rtw_power_mgnt;
+ registry_par->ips_mode = (u8)rtw_ips_mode;
+ registry_par->radio_enable = (u8)rtw_radio_enable;
+ registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt;
+ registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt;
+ registry_par->busy_thresh = (u16)rtw_busy_thresh;
+ /* registry_par->qos_enable = (u8)rtw_qos_enable; */
+ registry_par->ack_policy = (u8)rtw_ack_policy;
+ registry_par->mp_mode = (u8)rtw_mp_mode;
+#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_RTW_CUSTOMER_STR)
+ registry_par->mp_customer_str = (u8)rtw_mp_customer_str;
+#endif
+ registry_par->software_encrypt = (u8)rtw_software_encrypt;
+ registry_par->software_decrypt = (u8)rtw_software_decrypt;
+
+ registry_par->acm_method = (u8)rtw_acm_method;
+ registry_par->usb_rxagg_mode = (u8)rtw_usb_rxagg_mode;
+
+ /* UAPSD */
+ registry_par->wmm_enable = (u8)rtw_wmm_enable;
+ registry_par->uapsd_enable = (u8)rtw_uapsd_enable;
+ registry_par->uapsd_max_sp = (u8)rtw_uapsd_max_sp;
+ registry_par->uapsd_acbk_en = (u8)rtw_uapsd_acbk_en;
+ registry_par->uapsd_acbe_en = (u8)rtw_uapsd_acbe_en;
+ registry_par->uapsd_acvi_en = (u8)rtw_uapsd_acvi_en;
+ registry_par->uapsd_acvo_en = (u8)rtw_uapsd_acvo_en;
+
+ registry_par->RegPwrTrimEnable = (u8)rtw_pwrtrim_enable;
+ registry_par->led_enable = (u8)rtw_led_enable;
+ registry_par->tx_bw_mode = (u8)rtw_tx_bw_mode;
+
+ registry_par->ht_enable = (u8)rtw_ht_enable;
+ registry_par->bw_mode = (u8)rtw_bw_mode;
+ registry_par->ampdu_enable = (u8)rtw_ampdu_enable;
+ registry_par->rx_stbc = (u8)rtw_rx_stbc;
+ registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu;
+ registry_par->short_gi = (u8)rtw_short_gi;
+ registry_par->ldpc_cap = (u8)rtw_ldpc_cap;
+ registry_par->stbc_cap = (u8)rtw_stbc_cap;
+ registry_par->beamform_cap = (u8)rtw_beamform_cap;
+ registry_par->beamformer_rf_num = (u8)rtw_bfer_rf_number;
+ registry_par->beamformee_rf_num = (u8)rtw_bfee_rf_number;
+
+#ifdef CONFIG_TX_EARLY_MODE
+ registry_par->early_mode = (u8)rtw_early_mode;
+#endif
+ registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit;
+ registry_par->rf_config = (u8)rtw_rf_config;
+ registry_par->low_power = (u8)rtw_low_power;
+
+ registry_par->check_hw_status = (u8)rtw_check_hw_status;
+
+ registry_par->wifi_spec = (u8)rtw_wifi_spec;
+
+ if (strlen(rtw_country_code) != 2
+ || is_alpha(rtw_country_code[0]) == false
+ || is_alpha(rtw_country_code[1]) == false
+ ) {
+ if (rtw_country_code != rtw_country_unspecified)
+ RTW_ERR("%s discard rtw_country_code not in alpha2\n", __func__);
+ memset(registry_par->alpha2, 0xFF, 2);
+ } else
+ memcpy(registry_par->alpha2, rtw_country_code, 2);
+
+ registry_par->channel_plan = (u8)rtw_channel_plan;
+ rtw_regsty_load_excl_chs(registry_par);
+
+ registry_par->special_rf_path = (u8)rtw_special_rf_path;
+
+ registry_par->full_ch_in_p2p_handshake = (u8)rtw_full_ch_in_p2p_handshake;
+#ifdef CONFIG_BT_COEXIST
+ registry_par->btcoex = (u8)rtw_btcoex_enable;
+ registry_par->bt_iso = (u8)rtw_bt_iso;
+ registry_par->bt_sco = (u8)rtw_bt_sco;
+ registry_par->bt_ampdu = (u8)rtw_bt_ampdu;
+ registry_par->ant_num = (u8)rtw_ant_num;
+#endif
+
+ registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq;
+
+ registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg;
+ registry_par->antdiv_type = (u8)rtw_antdiv_type;
+
+ registry_par->drv_ant_band_switch = (u8) rtw_drv_ant_band_switch;
+
+ registry_par->switch_usb_mode = (u8)rtw_switch_usb_mode;
+
+#ifdef CONFIG_AUTOSUSPEND
+ registry_par->usbss_enable = (u8)rtw_enusbss;/* 0:disable,1:enable */
+#endif
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode;/* 0:disable,1:enable,2:by EFUSE config */
+ registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect;/* 0:disable,1:enable */
+#endif
+
+ registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc;
+
+#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE
+ snprintf(registry_par->adaptor_info_caching_file_path, PATH_LENGTH_MAX, "%s", rtw_adaptor_info_caching_file_path);
+ registry_par->adaptor_info_caching_file_path[PATH_LENGTH_MAX - 1] = 0;
+#endif
+
+#ifdef CONFIG_LAYER2_ROAMING
+ registry_par->max_roaming_times = (u8)rtw_max_roaming_times;
+#ifdef CONFIG_INTEL_WIDI
+ registry_par->max_roaming_times = (u8)rtw_max_roaming_times + 2;
+#endif /* CONFIG_INTEL_WIDI */
+#endif
+
+#ifdef CONFIG_IOL
+ registry_par->fw_iol = rtw_fw_iol;
+#endif
+
+#ifdef CONFIG_80211D
+ registry_par->enable80211d = (u8)rtw_80211d;
+#endif
+
+ snprintf(registry_par->ifname, 16, "%s", ifname);
+ snprintf(registry_par->if2name, 16, "%s", if2name);
+
+ registry_par->notch_filter = (u8)rtw_notch_filter;
+
+#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV
+ registry_par->force_ant = (u8)rtw_force_ant;
+ registry_par->force_igi = (u8)rtw_force_igi;
+#endif
+
+#ifdef CONFIG_CONCURRENT_MODE
+ registry_par->virtual_iface_num = (u8)rtw_virtual_iface_num;
+#endif
+
+ registry_par->force_igi_lb = (u8)rtw_force_igi_lb;
+
+ registry_par->pll_ref_clk_sel = (u8)rtw_pll_ref_clk_sel;
+
+ registry_par->RegEnableTxPowerLimit = (u8)rtw_tx_pwr_lmt_enable;
+ registry_par->RegEnableTxPowerByRate = (u8)rtw_tx_pwr_by_rate;
+
+ rtw_regsty_load_target_tx_power(registry_par);
+
+ registry_par->RegPowerBase = 14;
+ registry_par->TxBBSwing_2G = (s8)rtw_TxBBSwing_2G;
+ registry_par->TxBBSwing_5G = (s8)rtw_TxBBSwing_5G;
+ registry_par->bEn_RFE = 1;
+ registry_par->RFE_Type = (u8)rtw_RFE_type;
+ registry_par->PowerTracking_Type = (u8)rtw_powertracking_type;
+ registry_par->AmplifierType_2G = (u8)rtw_amplifier_type_2g;
+ registry_par->AmplifierType_5G = (u8)rtw_amplifier_type_5g;
+ registry_par->GLNA_Type = (u8)rtw_GLNA_type;
+#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
+ registry_par->load_phy_file = (u8)rtw_load_phy_file;
+ registry_par->RegDecryptCustomFile = (u8)rtw_decrypt_phy_file;
+#endif
+ registry_par->qos_opt_enable = (u8)rtw_qos_opt_enable;
+
+ registry_par->hiq_filter = (u8)rtw_hiq_filter;
+
+ registry_par->adaptivity_en = (u8)rtw_adaptivity_en;
+ registry_par->adaptivity_mode = (u8)rtw_adaptivity_mode;
+ registry_par->adaptivity_dml = (u8)rtw_adaptivity_dml;
+ registry_par->adaptivity_dc_backoff = (u8)rtw_adaptivity_dc_backoff;
+ registry_par->adaptivity_th_l2h_ini = (s8)rtw_adaptivity_th_l2h_ini;
+ registry_par->adaptivity_th_edcca_hl_diff = (s8)rtw_adaptivity_th_edcca_hl_diff;
+
+ registry_par->boffefusemask = (u8)rtw_OffEfuseMask;
+ registry_par->bFileMaskEfuse = (u8)rtw_FileMaskEfuse;
+#ifdef CONFIG_AUTO_CHNL_SEL_NHM
+ registry_par->acs_mode = (u8)rtw_acs_mode;
+ registry_par->acs_auto_scan = (u8)rtw_acs_auto_scan;
+#endif
+ registry_par->reg_rxgain_offset_2g = (u32) rtw_rxgain_offset_2g;
+ registry_par->reg_rxgain_offset_5gl = (u32) rtw_rxgain_offset_5gl;
+ registry_par->reg_rxgain_offset_5gm = (u32) rtw_rxgain_offset_5gm;
+ registry_par->reg_rxgain_offset_5gh = (u32) rtw_rxgain_offset_5gh;
+
+#ifdef CONFIG_DFS_MASTER
+ registry_par->dfs_region_domain = (u8)rtw_dfs_region_domain;
+#endif
+
+#ifdef CONFIG_MCC_MODE
+ registry_par->en_mcc = (u8)rtw_en_mcc;
+ registry_par->rtw_mcc_ap_bw20_target_tx_tp = (u32)rtw_mcc_ap_bw20_target_tx_tp;
+ registry_par->rtw_mcc_ap_bw40_target_tx_tp = (u32)rtw_mcc_ap_bw40_target_tx_tp;
+ registry_par->rtw_mcc_ap_bw80_target_tx_tp = (u32)rtw_mcc_ap_bw80_target_tx_tp;
+ registry_par->rtw_mcc_sta_bw20_target_tx_tp = (u32)rtw_mcc_sta_bw20_target_tx_tp;
+ registry_par->rtw_mcc_sta_bw40_target_tx_tp = (u32)rtw_mcc_sta_bw40_target_tx_tp;
+ registry_par->rtw_mcc_sta_bw80_target_tx_tp = (u32)rtw_mcc_sta_bw80_target_tx_tp;
+ registry_par->rtw_mcc_single_tx_cri = (u32)rtw_mcc_single_tx_cri;
+ registry_par->rtw_mcc_policy_table_idx = rtw_mcc_policy_table_idx;
+ registry_par->rtw_mcc_duration = (u8)rtw_mcc_duration;
+ registry_par->rtw_mcc_tsf_sync_offset = (u8)rtw_mcc_tsf_sync_offset;
+ registry_par->rtw_mcc_start_time_offset = (u8)rtw_mcc_start_time_offset;
+ registry_par->rtw_mcc_interval = (u8)rtw_mcc_interval;
+ registry_par->rtw_mcc_guard_offset0 = rtw_mcc_guard_offset0;
+ registry_par->rtw_mcc_guard_offset1 = rtw_mcc_guard_offset1;
+#endif /*CONFIG_MCC_MODE */
+#ifdef CONFIG_DEFAULT_PATTERNS_EN
+ registry_par->default_patterns_en = rtw_support_default_patterns;
+#endif
+
+#ifdef CONFIG_SUPPORT_TRX_SHARED
+ registry_par->trx_share_mode = rtw_trx_share_mode;
+#endif
+
+#ifdef CONFIG_RTW_NAPI
+ registry_par->en_napi = (u8)rtw_en_napi;
+#ifdef CONFIG_RTW_GRO
+ registry_par->en_gro = (u8)rtw_en_gro;
+ if (!registry_par->en_napi && registry_par->en_gro) {
+ registry_par->en_gro = 0;
+ RTW_WARN("Disable GRO because NAPI is not enabled\n");
+ }
+#endif /* CONFIG_RTW_GRO */
+#endif /* CONFIG_RTW_NAPI */
+
+ return status;
+}
+
+/**
+ * rtw_net_set_mac_address
+ * This callback function is used for the Media Access Control address
+ * of each net_device needs to be changed.
+ *
+ * Arguments:
+ * @pnetdev: net_device pointer.
+ * @addr: new MAC address.
+ *
+ * Return:
+ * ret = 0: Permit to change net_device's MAC address.
+ * ret = -1 (Default): Operation not permitted.
+ *
+ * Auther: Arvin Liu
+ * Date: 2015/05/29
+ */
+static int rtw_net_set_mac_address(struct net_device *pnetdev, void *addr)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sockaddr *sa = (struct sockaddr *)addr;
+ int ret = -1;
+
+ /* only the net_device is in down state to permit modifying mac addr */
+ if ((pnetdev->flags & IFF_UP) == true) {
+ RTW_INFO(FUNC_ADPT_FMT": The net_device's is not in down state\n"
+ , FUNC_ADPT_ARG(padapter));
+
+ return ret;
+ }
+
+ /* if the net_device is linked, it's not permit to modify mac addr */
+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) ||
+ check_fwstate(pmlmepriv, _FW_LINKED) ||
+ check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+ RTW_INFO(FUNC_ADPT_FMT": The net_device's is not idle currently\n"
+ , FUNC_ADPT_ARG(padapter));
+
+ return ret;
+ }
+
+ /* check whether the input mac address is valid to permit modifying mac addr */
+ if (rtw_check_invalid_mac_address(sa->sa_data, false) == true) {
+ RTW_INFO(FUNC_ADPT_FMT": Invalid Mac Addr for "MAC_FMT"\n"
+ , FUNC_ADPT_ARG(padapter), MAC_ARG(sa->sa_data));
+
+ return ret;
+ }
+
+ memcpy(adapter_mac_addr(padapter), sa->sa_data, ETH_ALEN); /* set mac addr to adapter */
+ memcpy(pnetdev->dev_addr, sa->sa_data, ETH_ALEN); /* set mac addr to net_device */
+
+ rtw_ps_deny(padapter, PS_DENY_IOCTL);
+ LeaveAllPowerSaveModeDirect(padapter); /* leave PS mode for guaranteeing to access hw register successfully */
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ rtw_hal_change_macaddr_mbid(padapter, sa->sa_data);
+#else
+ rtw_hal_set_hwreg(padapter, HW_VAR_MAC_ADDR, sa->sa_data); /* set mac addr to mac register */
+#endif
+ rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL);
+
+ RTW_INFO(FUNC_ADPT_FMT": Set Mac Addr to "MAC_FMT" Successfully\n"
+ , FUNC_ADPT_ARG(padapter), MAC_ARG(sa->sa_data));
+
+ ret = 0;
+
+ return ret;
+}
+
+static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ struct recv_priv *precvpriv = &(padapter->recvpriv);
+
+ padapter->stats.tx_packets = pxmitpriv->tx_pkts;/* pxmitpriv->tx_pkts++; */
+ padapter->stats.rx_packets = precvpriv->rx_pkts;/* precvpriv->rx_pkts++; */
+ padapter->stats.tx_dropped = pxmitpriv->tx_drop;
+ padapter->stats.rx_dropped = precvpriv->rx_drop;
+ padapter->stats.tx_bytes = pxmitpriv->tx_bytes;
+ padapter->stats.rx_bytes = precvpriv->rx_bytes;
+
+ return &padapter->stats;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+/*
+ * AC to queue mapping
+ *
+ * AC_VO -> queue 0
+ * AC_VI -> queue 1
+ * AC_BE -> queue 2
+ * AC_BK -> queue 3
+ */
+static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
+
+/* Given a data frame determine the 802.1p/1d tag to use. */
+static unsigned int rtw_classify8021d(struct sk_buff *skb)
+{
+ unsigned int dscp;
+
+ /* skb->priority values from 256->263 are magic values to
+ * directly indicate a specific 802.1d priority. This is used
+ * to allow 802.1d priority to be passed directly in from VLAN
+ * tags, etc.
+ */
+ if (skb->priority >= 256 && skb->priority <= 263)
+ return skb->priority - 256;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ dscp = ip_hdr(skb)->tos & 0xfc;
+ break;
+ default:
+ return 0;
+ }
+
+ return dscp >> 5;
+}
+
+
+static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0))
+ ,struct net_device *sb_dev
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
+ ,struct net_device *sb_dev
+ ,select_queue_fallback_t fallback
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ ,void *unused
+ ,select_queue_fallback_t fallback
+#endif
+)
+{
+ _adapter *padapter = rtw_netdev_priv(dev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ skb->priority = rtw_classify8021d(skb);
+
+ if (pmlmepriv->acm_mask != 0)
+ skb->priority = qos_acm(pmlmepriv->acm_mask, skb->priority);
+
+ return rtw_1d_to_queue[skb->priority];
+}
+
+u16 rtw_recv_select_queue(struct sk_buff *skb)
+{
+ struct iphdr *piphdr;
+ unsigned int dscp;
+ __be16 eth_type;
+ u32 priority;
+ u8 *pdata = skb->data;
+
+ memcpy(ð_type, pdata + (ETH_ALEN << 1), 2);
+
+ switch (eth_type) {
+ case htons(ETH_P_IP):
+ piphdr = (struct iphdr *)(pdata + ETH_HLEN);
+ dscp = piphdr->tos & 0xfc;
+ priority = dscp >> 5;
+ break;
+ default:
+ priority = 0;
+ }
+
+ return rtw_1d_to_queue[priority];
+}
+
+#endif
+static int rtw_ndev_notifier_call(struct notifier_block *nb, unsigned long state, void *ptr)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+#else
+ struct net_device *dev = ptr;
+#endif
+
+ if (dev == NULL)
+ return NOTIFY_DONE;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+ if (dev->netdev_ops == NULL)
+ return NOTIFY_DONE;
+
+ if (dev->netdev_ops->ndo_do_ioctl == NULL)
+ return NOTIFY_DONE;
+
+ if (dev->netdev_ops->ndo_do_ioctl != rtw_ioctl)
+#else
+ if (dev->do_ioctl == NULL)
+ return NOTIFY_DONE;
+
+ if (dev->do_ioctl != rtw_ioctl)
+#endif
+ return NOTIFY_DONE;
+
+ RTW_INFO(FUNC_NDEV_FMT" state:%lu\n", FUNC_NDEV_ARG(dev), state);
+
+ switch (state) {
+ case NETDEV_CHANGENAME:
+ rtw_adapter_proc_replace(dev);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rtw_ndev_notifier = {
+ .notifier_call = rtw_ndev_notifier_call,
+};
+
+int rtw_ndev_notifier_register(void)
+{
+ return register_netdevice_notifier(&rtw_ndev_notifier);
+}
+
+void rtw_ndev_notifier_unregister(void)
+{
+ unregister_netdevice_notifier(&rtw_ndev_notifier);
+}
+
+static int rtw_ndev_init(struct net_device *dev)
+{
+ _adapter *adapter = rtw_netdev_priv(dev);
+
+ RTW_INFO(FUNC_ADPT_FMT" if%d mac_addr="MAC_FMT"\n"
+ , FUNC_ADPT_ARG(adapter), (adapter->iface_id + 1), MAC_ARG(dev->dev_addr));
+ strncpy(adapter->old_ifname, dev->name, IFNAMSIZ);
+ adapter->old_ifname[IFNAMSIZ - 1] = '\0';
+ rtw_adapter_proc_init(dev);
+
+ return 0;
+}
+
+static void rtw_ndev_uninit(struct net_device *dev)
+{
+ _adapter *adapter = rtw_netdev_priv(dev);
+
+ RTW_INFO(FUNC_ADPT_FMT" if%d\n"
+ , FUNC_ADPT_ARG(adapter), (adapter->iface_id + 1));
+ rtw_adapter_proc_deinit(dev);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+static const struct net_device_ops rtw_netdev_ops = {
+ .ndo_init = rtw_ndev_init,
+ .ndo_uninit = rtw_ndev_uninit,
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = rtw_xmit_entry,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ .ndo_select_queue = rtw_select_queue,
+#endif
+ .ndo_set_mac_address = rtw_net_set_mac_address,
+ .ndo_get_stats = rtw_net_get_stats,
+ .ndo_do_ioctl = rtw_ioctl,
+};
+#endif
+
+int rtw_init_netdev_name(struct net_device *pnetdev, const char *ifname)
+{
+ _adapter *padapter = rtw_netdev_priv(pnetdev);
+
+#ifdef CONFIG_EASY_REPLACEMENT
+ struct net_device *TargetNetdev = NULL;
+ _adapter *TargetAdapter = NULL;
+ struct net *devnet = NULL;
+
+ if (padapter->bDongle == 1) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
+ TargetNetdev = dev_get_by_name("wlan0");
+#else
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+ devnet = pnetdev->nd_net;
+#else
+ devnet = dev_net(pnetdev);
+#endif
+ TargetNetdev = dev_get_by_name(devnet, "wlan0");
+#endif
+ if (TargetNetdev) {
+ RTW_INFO("Force onboard module driver disappear !!!\n");
+ TargetAdapter = rtw_netdev_priv(TargetNetdev);
+ TargetAdapter->DriverState = DRIVER_DISAPPEAR;
+
+ padapter->pid[0] = TargetAdapter->pid[0];
+ padapter->pid[1] = TargetAdapter->pid[1];
+ padapter->pid[2] = TargetAdapter->pid[2];
+
+ dev_put(TargetNetdev);
+ unregister_netdev(TargetNetdev);
+
+ padapter->DriverState = DRIVER_REPLACE_DONGLE;
+ }
+ }
+#endif /* CONFIG_EASY_REPLACEMENT */
+
+ if (dev_alloc_name(pnetdev, ifname) < 0)
+ RTW_ERR("dev_alloc_name, fail!\n");
+
+ netif_carrier_off(pnetdev);
+ /* rtw_netif_stop_queue(pnetdev); */
+
+ return 0;
+}
+
+static void rtw_hook_if_ops(struct net_device *ndev)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+ ndev->netdev_ops = &rtw_netdev_ops;
+#else
+ ndev->init = rtw_ndev_init;
+ ndev->uninit = rtw_ndev_uninit;
+ ndev->open = netdev_open;
+ ndev->stop = netdev_close;
+ ndev->hard_start_xmit = rtw_xmit_entry;
+ ndev->set_mac_address = rtw_net_set_mac_address;
+ ndev->get_stats = rtw_net_get_stats;
+ ndev->do_ioctl = rtw_ioctl;
+#endif
+}
+
+#ifdef CONFIG_CONCURRENT_MODE
+static void rtw_hook_vir_if_ops(struct net_device *ndev);
+#endif
+struct net_device *rtw_init_netdev(_adapter *old_padapter)
+{
+ _adapter *padapter;
+ struct net_device *pnetdev;
+
+ if (old_padapter != NULL) {
+ rtw_os_ndev_free(old_padapter);
+ pnetdev = rtw_alloc_etherdev_with_old_priv(sizeof(_adapter), (void *)old_padapter);
+ } else
+ pnetdev = rtw_alloc_etherdev(sizeof(_adapter));
+
+ if (!pnetdev)
+ return NULL;
+
+ padapter = rtw_netdev_priv(pnetdev);
+ padapter->pnetdev = pnetdev;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+ SET_MODULE_OWNER(pnetdev);
+#endif
+
+ rtw_hook_if_ops(pnetdev);
+#ifdef CONFIG_CONCURRENT_MODE
+ if (!is_primary_adapter(padapter))
+ rtw_hook_vir_if_ops(pnetdev);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
+ pnetdev->features |= NETIF_F_IP_CSUM;
+#endif
+
+ /* pnetdev->tx_timeout = NULL; */
+ pnetdev->watchdog_timeo = HZ * 3; /* 3 second timeout */
+
+#ifdef CONFIG_WIRELESS_EXT
+ pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def;
+#endif
+
+#ifdef WIRELESS_SPY
+ /* priv->wireless_data.spy_data = &priv->spy_data; */
+ /* pnetdev->wireless_data = &priv->wireless_data; */
+#endif
+
+ return pnetdev;
+}
+
+static int rtw_os_ndev_alloc(_adapter *adapter)
+{
+ int ret = _FAIL;
+ struct net_device *ndev = NULL;
+
+ ndev = rtw_init_netdev(adapter);
+ if (ndev == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)
+ SET_NETDEV_DEV(ndev, dvobj_to_dev(adapter_to_dvobj(adapter)));
+#endif
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (rtw_cfg80211_ndev_res_alloc(adapter) != _SUCCESS) {
+ rtw_warn_on(1);
+ goto free_ndev;
+ }
+#endif
+
+ ret = _SUCCESS;
+
+free_ndev:
+ if (ret != _SUCCESS && ndev)
+ rtw_free_netdev(ndev);
+exit:
+ return ret;
+}
+
+void rtw_os_ndev_free(_adapter *adapter)
+{
+#if defined(CONFIG_IOCTL_CFG80211)
+ rtw_cfg80211_ndev_res_free(adapter);
+#endif
+
+ if (adapter->pnetdev) {
+ rtw_free_netdev(adapter->pnetdev);
+ adapter->pnetdev = NULL;
+ }
+}
+
+static int rtw_os_ndev_register(_adapter *adapter, const char *name)
+{
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ int ret = _SUCCESS;
+ struct net_device *ndev = adapter->pnetdev;
+ u8 rtnl_lock_needed = rtw_rtnl_lock_needed(dvobj);
+
+#ifdef CONFIG_RTW_NAPI
+ netif_napi_add(ndev, &adapter->napi, rtw_recv_napi_poll, RTL_NAPI_WEIGHT);
+#endif /* CONFIG_RTW_NAPI */
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (rtw_cfg80211_ndev_res_register(adapter) != _SUCCESS) {
+ rtw_warn_on(1);
+ ret = _FAIL;
+ goto exit;
+ }
+#endif
+
+ /* alloc netdev name */
+ rtw_init_netdev_name(ndev, name);
+
+ memcpy(ndev->dev_addr, adapter_mac_addr(adapter), ETH_ALEN);
+
+ /* Tell the network stack we exist */
+
+ if (rtnl_lock_needed)
+ ret = (register_netdev(ndev) == 0) ? _SUCCESS : _FAIL;
+ else
+ ret = (register_netdevice(ndev) == 0) ? _SUCCESS : _FAIL;
+
+ if (ret == _SUCCESS)
+ adapter->registered = 1;
+ else
+ RTW_INFO(FUNC_NDEV_FMT" if%d Failed!\n", FUNC_NDEV_ARG(ndev), (adapter->iface_id + 1));
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (ret != _SUCCESS) {
+ rtw_cfg80211_ndev_res_unregister(adapter);
+ #if !defined(RTW_SINGLE_WIPHY)
+ rtw_wiphy_unregister(adapter_to_wiphy(adapter));
+ #endif
+ }
+#endif
+
+exit:
+#ifdef CONFIG_RTW_NAPI
+ if (ret != _SUCCESS)
+ netif_napi_del(&adapter->napi);
+#endif /* CONFIG_RTW_NAPI */
+
+ return ret;
+}
+
+void rtw_os_ndev_unregister(_adapter *adapter)
+{
+ struct net_device *netdev = NULL;
+
+ if (adapter == NULL || adapter->registered == 0)
+ return;
+
+ adapter->ndev_unregistering = 1;
+
+ netdev = adapter->pnetdev;
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ rtw_cfg80211_ndev_res_unregister(adapter);
+#endif
+
+ if ((adapter->DriverState != DRIVER_DISAPPEAR) && netdev) {
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ u8 rtnl_lock_needed = rtw_rtnl_lock_needed(dvobj);
+
+ if (rtnl_lock_needed)
+ unregister_netdev(netdev);
+ else
+ unregister_netdevice(netdev);
+ }
+
+#if defined(CONFIG_IOCTL_CFG80211) && !defined(RTW_SINGLE_WIPHY)
+#ifdef CONFIG_RFKILL_POLL
+ rtw_cfg80211_deinit_rfkill(adapter_to_wiphy(adapter));
+#endif
+ rtw_wiphy_unregister(adapter_to_wiphy(adapter));
+#endif
+
+#ifdef CONFIG_RTW_NAPI
+ if (adapter->napi_state == NAPI_ENABLE) {
+ napi_disable(&adapter->napi);
+ adapter->napi_state = NAPI_DISABLE;
+ }
+ netif_napi_del(&adapter->napi);
+#endif /* CONFIG_RTW_NAPI */
+
+ adapter->registered = 0;
+ adapter->ndev_unregistering = 0;
+}
+
+/**
+ * rtw_os_ndev_init - Allocate and register OS layer net device and relating structures for @adapter
+ * @adapter: the adapter on which this function applies
+ * @name: the requesting net device name
+ *
+ * Returns:
+ * _SUCCESS or _FAIL
+ */
+int rtw_os_ndev_init(_adapter *adapter, const char *name)
+{
+ int ret = _FAIL;
+
+ if (rtw_os_ndev_alloc(adapter) != _SUCCESS)
+ goto exit;
+
+ if (rtw_os_ndev_register(adapter, name) != _SUCCESS)
+ goto os_ndev_free;
+
+ ret = _SUCCESS;
+
+os_ndev_free:
+ if (ret != _SUCCESS)
+ rtw_os_ndev_free(adapter);
+exit:
+ return ret;
+}
+
+/**
+ * rtw_os_ndev_deinit - Unregister and free OS layer net device and relating structures for @adapter
+ * @adapter: the adapter on which this function applies
+ */
+void rtw_os_ndev_deinit(_adapter *adapter)
+{
+ rtw_os_ndev_unregister(adapter);
+ rtw_os_ndev_free(adapter);
+}
+
+static int rtw_os_ndevs_alloc(struct dvobj_priv *dvobj)
+{
+ int i, status = _SUCCESS;
+ _adapter *adapter;
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (rtw_cfg80211_dev_res_alloc(dvobj) != _SUCCESS) {
+ rtw_warn_on(1);
+ status = _FAIL;
+ goto exit;
+ }
+#endif
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+
+ if (i >= CONFIG_IFACE_NUMBER) {
+ RTW_ERR("%s %d >= CONFIG_IFACE_NUMBER(%d)\n", __func__, i, CONFIG_IFACE_NUMBER);
+ rtw_warn_on(1);
+ continue;
+ }
+
+ adapter = dvobj->padapters[i];
+ if (adapter && !adapter->pnetdev) {
+
+ #ifdef CONFIG_RTW_DYNAMIC_NDEV
+ if (!is_primary_adapter(adapter))
+ continue;
+ #endif
+
+ status = rtw_os_ndev_alloc(adapter);
+ if (status != _SUCCESS) {
+ rtw_warn_on(1);
+ break;
+ }
+ }
+ }
+
+ if (status != _SUCCESS) {
+ for (; i >= 0; i--) {
+ adapter = dvobj->padapters[i];
+ if (adapter && adapter->pnetdev)
+ rtw_os_ndev_free(adapter);
+ }
+ }
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (status != _SUCCESS)
+ rtw_cfg80211_dev_res_free(dvobj);
+#endif
+exit:
+ return status;
+}
+
+static void rtw_os_ndevs_free(struct dvobj_priv *dvobj)
+{
+ int i;
+ _adapter *adapter = NULL;
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+
+ if (i >= CONFIG_IFACE_NUMBER) {
+ RTW_ERR("%s %d >= CONFIG_IFACE_NUMBER(%d)\n", __func__, i, CONFIG_IFACE_NUMBER);
+ rtw_warn_on(1);
+ continue;
+ }
+
+ adapter = dvobj->padapters[i];
+
+ if (adapter == NULL)
+ continue;
+
+ rtw_os_ndev_free(adapter);
+ }
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ rtw_cfg80211_dev_res_free(dvobj);
+#endif
+}
+
+u32 rtw_start_drv_threads(_adapter *padapter)
+{
+ u32 _status = _SUCCESS;
+
+
+#ifdef CONFIG_XMIT_THREAD_MODE
+ padapter->xmitThread = kthread_run(rtw_xmit_thread, padapter, "RTW_XMIT_THREAD");
+ if (IS_ERR(padapter->xmitThread))
+ _status = _FAIL;
+#endif /* #ifdef CONFIG_XMIT_THREAD_MODE */
+
+#ifdef CONFIG_RECV_THREAD_MODE
+ if (is_primary_adapter(padapter)) {
+ padapter->recvThread = kthread_run(rtw_recv_thread, padapter, "RTW_RECV_THREAD");
+ if (IS_ERR(padapter->recvThread))
+ _status = _FAIL;
+ }
+#endif
+
+ if (is_primary_adapter(padapter)) {
+ padapter->cmdThread = kthread_run(rtw_cmd_thread, padapter, "RTW_CMD_THREAD");
+ if (IS_ERR(padapter->cmdThread))
+ _status = _FAIL;
+ else
+ _rtw_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema); /* wait for cmd_thread to run */
+ }
+
+
+#ifdef CONFIG_EVENT_THREAD_MODE
+ padapter->evtThread = kthread_run(event_thread, padapter, "RTW_EVENT_THREAD");
+ if (IS_ERR(padapter->evtThread))
+ _status = _FAIL;
+#endif
+
+ rtw_hal_start_thread(padapter);
+ return _status;
+
+}
+
+void rtw_stop_drv_threads(_adapter *padapter)
+{
+
+ if (is_primary_adapter(padapter))
+ rtw_stop_cmd_thread(padapter);
+
+#ifdef CONFIG_EVENT_THREAD_MODE
+ up(&padapter->evtpriv.evt_notify);
+ if (padapter->evtThread)
+ _rtw_down_sema(&padapter->evtpriv.terminate_evtthread_sema);
+#endif
+
+#ifdef CONFIG_XMIT_THREAD_MODE
+ /* Below is to termindate tx_thread... */
+ up(&padapter->xmitpriv.xmit_sema);
+ _rtw_down_sema(&padapter->xmitpriv.terminate_xmitthread_sema);
+#endif
+
+#ifdef CONFIG_RECV_THREAD_MODE
+ if (is_primary_adapter(padapter)) {
+ /* Below is to termindate rx_thread... */
+ up(&padapter->recvpriv.recv_sema);
+ _rtw_down_sema(&padapter->recvpriv.terminate_recvthread_sema);
+ }
+#endif
+
+ rtw_hal_stop_thread(padapter);
+}
+
+u8 rtw_init_default_value(_adapter *padapter);
+u8 rtw_init_default_value(_adapter *padapter)
+{
+ u8 ret = _SUCCESS;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+ /* xmit_priv */
+ pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense;
+ pxmitpriv->vcs = pregistrypriv->vcs_type;
+ pxmitpriv->vcs_type = pregistrypriv->vcs_type;
+ /* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */
+ pxmitpriv->frag_len = pregistrypriv->frag_thresh;
+
+ /* security_priv */
+ /* rtw_get_encrypt_decrypt_from_registrypriv(padapter); */
+ psecuritypriv->binstallGrpkey = _FAIL;
+#ifdef CONFIG_GTK_OL
+ psecuritypriv->binstallKCK_KEK = _FAIL;
+#endif /* CONFIG_GTK_OL */
+ psecuritypriv->sw_encrypt = pregistrypriv->software_encrypt;
+ psecuritypriv->sw_decrypt = pregistrypriv->software_decrypt;
+
+ psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
+ psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+
+ psecuritypriv->dot11PrivacyKeyIndex = 0;
+
+ psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+ psecuritypriv->dot118021XGrpKeyid = 1;
+
+ psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+ psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled;
+#ifdef CONFIG_CONCURRENT_MODE
+ psecuritypriv->dot118021x_bmc_cam_id = INVALID_SEC_MAC_CAM_ID;
+#endif
+
+
+ /* pwrctrl_priv */
+
+
+ /* registry_priv */
+ rtw_init_registrypriv_dev_network(padapter);
+ rtw_update_registrypriv_dev_network(padapter);
+
+
+ /* hal_priv */
+ rtw_hal_def_value_init(padapter);
+
+ /* misc. */
+ RTW_ENABLE_FUNC(padapter, DF_RX_BIT);
+ RTW_ENABLE_FUNC(padapter, DF_TX_BIT);
+ padapter->bLinkInfoDump = 0;
+ padapter->bNotifyChannelChange = false;
+#ifdef CONFIG_P2P
+ padapter->bShowGetP2PState = 1;
+#endif
+
+ /* for debug purpose */
+ padapter->fix_rate = 0xFF;
+ padapter->data_fb = 0;
+ padapter->fix_bw = 0xFF;
+ padapter->power_offset = 0;
+ padapter->rsvd_page_offset = 0;
+ padapter->rsvd_page_num = 0;
+
+ padapter->driver_tx_bw_mode = pregistrypriv->tx_bw_mode;
+
+ padapter->driver_ampdu_spacing = 0xFF;
+ padapter->driver_rx_ampdu_factor = 0xFF;
+ padapter->driver_rx_ampdu_spacing = 0xFF;
+ padapter->fix_rx_ampdu_accept = RX_AMPDU_ACCEPT_INVALID;
+ padapter->fix_rx_ampdu_size = RX_AMPDU_SIZE_INVALID;
+#ifdef CONFIG_TX_AMSDU
+ padapter->tx_amsdu = 2;
+ padapter->tx_amsdu_rate = 400;
+#endif
+#ifdef DBG_RX_COUNTER_DUMP
+ padapter->dump_rx_cnt_mode = 0;
+ padapter->drv_rx_cnt_ok = 0;
+ padapter->drv_rx_cnt_crcerror = 0;
+ padapter->drv_rx_cnt_drop = 0;
+#endif
+#ifdef CONFIG_RTW_NAPI
+ padapter->napi_state = NAPI_DISABLE;
+#endif
+ padapter->tsf.sync_port = MAX_HW_PORT;
+ padapter->tsf.offset = 0;
+
+ return ret;
+}
+
+#ifdef CONFIG_SWTIMER_BASED_TXBCN
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+void _tx_beacon_timer_handler(void *FunctionContext)
+#else
+void _tx_beacon_timer_handler(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ struct dvobj_priv *pdvobj = (struct dvobj_priv *)FunctionContext;
+#else
+ struct dvobj_priv *pdvobj = from_timer(pdvobj, t, txbcn_timer);
+#endif
+
+ tx_beacon_timer_handler(pdvobj);
+}
+#endif
+
+struct dvobj_priv *devobj_init(void)
+{
+ struct dvobj_priv *pdvobj = NULL;
+ _adapter *adapter;
+
+ pdvobj = (struct dvobj_priv *)rtw_zmalloc(sizeof(*pdvobj));
+ if (pdvobj == NULL)
+ return NULL;
+
+ _rtw_mutex_init(&pdvobj->hw_init_mutex);
+ _rtw_mutex_init(&pdvobj->h2c_fwcmd_mutex);
+ _rtw_mutex_init(&pdvobj->setch_mutex);
+ _rtw_mutex_init(&pdvobj->setbw_mutex);
+ _rtw_mutex_init(&pdvobj->rf_read_reg_mutex);
+#ifdef CONFIG_SDIO_INDIRECT_ACCESS
+ _rtw_mutex_init(&pdvobj->sd_indirect_access_mutex);
+#endif
+
+#ifdef CONFIG_RTW_CUSTOMER_STR
+ _rtw_mutex_init(&pdvobj->customer_str_mutex);
+ memset(pdvobj->customer_str, 0xFF, RTW_CUSTOMER_STR_LEN);
+#endif
+
+ pdvobj->processing_dev_remove = false;
+
+ ATOMIC_SET(&pdvobj->disable_func, 0);
+
+ rtw_macid_ctl_init(&pdvobj->macid_ctl);
+ spin_lock_init(&pdvobj->cam_ctl.lock);
+ _rtw_mutex_init(&pdvobj->cam_ctl.sec_cam_access_mutex);
+#ifdef CONFIG_MBSSID_CAM
+ rtw_mbid_cam_init(pdvobj);
+#endif
+
+#ifdef CONFIG_AP_MODE
+ pdvobj->nr_ap_if = 0;
+ pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL; /* default value is equal to the default beacon_interval (100ms) */
+ _rtw_init_queue(&pdvobj->ap_if_q);
+#ifdef CONFIG_SWTIMER_BASED_TXBCN
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&pdvobj->txbcn_timer, NULL, _tx_beacon_timer_handler, pdvobj);
+#else
+ timer_setup(&pdvobj->txbcn_timer, _tx_beacon_timer_handler, 0);
+#endif
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&pdvobj->dynamic_chk_timer, NULL, _dynamic_check_timer_handler, pdvobj);
+#else
+ timer_setup(&pdvobj->dynamic_chk_timer, _dynamic_check_timer_handler, 0);
+#endif
+
+#ifdef CONFIG_MCC_MODE
+ _rtw_mutex_init(&(pdvobj->mcc_objpriv.mcc_mutex));
+ spin_lock_init(&pdvobj->mcc_objpriv.mcc_lock);
+#endif /* CONFIG_MCC_MODE */
+
+ return pdvobj;
+
+}
+
+void devobj_deinit(struct dvobj_priv *pdvobj)
+{
+ if (!pdvobj)
+ return;
+
+ /* TODO: use rtw_os_ndevs_deinit instead at the first stage of driver's dev deinit function */
+#if defined(CONFIG_IOCTL_CFG80211)
+ rtw_cfg80211_dev_res_free(pdvobj);
+#endif
+
+#ifdef CONFIG_MCC_MODE
+ _rtw_mutex_free(&(pdvobj->mcc_objpriv.mcc_mutex));
+#endif /* CONFIG_MCC_MODE */
+
+ _rtw_mutex_free(&pdvobj->hw_init_mutex);
+ _rtw_mutex_free(&pdvobj->h2c_fwcmd_mutex);
+
+#ifdef CONFIG_RTW_CUSTOMER_STR
+ _rtw_mutex_free(&pdvobj->customer_str_mutex);
+#endif
+
+ _rtw_mutex_free(&pdvobj->setch_mutex);
+ _rtw_mutex_free(&pdvobj->setbw_mutex);
+ _rtw_mutex_free(&pdvobj->rf_read_reg_mutex);
+#ifdef CONFIG_SDIO_INDIRECT_ACCESS
+ _rtw_mutex_free(&pdvobj->sd_indirect_access_mutex);
+#endif
+
+ rtw_macid_ctl_deinit(&pdvobj->macid_ctl);
+ _rtw_mutex_free(&pdvobj->cam_ctl.sec_cam_access_mutex);
+
+#ifdef CONFIG_MBSSID_CAM
+ rtw_mbid_cam_deinit(pdvobj);
+#endif
+
+ rtw_mfree((u8 *)pdvobj, sizeof(*pdvobj));
+}
+
+inline u8 rtw_rtnl_lock_needed(struct dvobj_priv *dvobj)
+{
+ if (dvobj->rtnl_lock_holder && dvobj->rtnl_lock_holder == current)
+ return 0;
+ return 1;
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+static inline int rtnl_is_locked(void)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17))
+ if (unlikely(rtnl_trylock())) {
+ rtnl_unlock();
+#else
+ if (unlikely(down_trylock(&rtnl_sem) == 0)) {
+ up(&rtnl_sem);
+#endif
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+inline void rtw_set_rtnl_lock_holder(struct dvobj_priv *dvobj, _thread_hdl_ thd_hdl)
+{
+ rtw_warn_on(!rtnl_is_locked());
+
+ if (!thd_hdl || rtnl_is_locked())
+ dvobj->rtnl_lock_holder = thd_hdl;
+
+ if (dvobj->rtnl_lock_holder && 0)
+ RTW_INFO("rtnl_lock_holder: %s:%d\n", current->comm, current->pid);
+}
+
+u8 rtw_reset_drv_sw(_adapter *padapter)
+{
+ u8 ret8 = _SUCCESS;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
+
+ /* hal_priv */
+ if (is_primary_adapter(padapter))
+ rtw_hal_def_value_init(padapter);
+
+ RTW_ENABLE_FUNC(padapter, DF_RX_BIT);
+ RTW_ENABLE_FUNC(padapter, DF_TX_BIT);
+
+ padapter->tsf.sync_port = MAX_HW_PORT;
+ padapter->tsf.offset = 0;
+
+ padapter->bLinkInfoDump = 0;
+
+ padapter->xmitpriv.tx_pkts = 0;
+ padapter->recvpriv.rx_pkts = 0;
+
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+
+ /* pmlmepriv->LinkDetectInfo.TrafficBusyState = false; */
+ pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0;
+ pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0;
+
+ _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING);
+
+#ifdef CONFIG_AUTOSUSPEND
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34))
+ adapter_to_dvobj(padapter)->pusbdev->autosuspend_disabled = 1;/* autosuspend disabled by the user */
+#endif
+#endif
+
+#ifdef DBG_CONFIG_ERROR_DETECT
+ if (is_primary_adapter(padapter))
+ rtw_hal_sreset_reset_value(padapter);
+#endif
+ pwrctrlpriv->pwr_state_check_cnts = 0;
+
+ /* mlmeextpriv */
+ mlmeext_set_scan_state(&padapter->mlmeextpriv, SCAN_DISABLE);
+
+#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
+ rtw_set_signal_stat_timer(&padapter->recvpriv);
+#endif
+
+ return ret8;
+}
+
+
+u8 rtw_init_drv_sw(_adapter *padapter)
+{
+ u8 ret8 = _SUCCESS;
+
+ INIT_LIST_HEAD(&padapter->list);
+ ret8 = rtw_init_default_value(padapter);
+
+ if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL) {
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ padapter->cmdpriv.padapter = padapter;
+
+ if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL) {
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ rtw_rfctl_init(padapter);
+
+ if (rtw_init_mlme_priv(padapter) == _FAIL) {
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+#ifdef CONFIG_P2P
+ rtw_init_wifidirect_timers(padapter);
+ init_wifidirect_info(padapter, P2P_ROLE_DISABLE);
+ reset_global_wifidirect_info(padapter);
+ #ifdef CONFIG_IOCTL_CFG80211
+ rtw_init_cfg80211_wifidirect_info(padapter);
+ #endif
+#ifdef CONFIG_WFD
+ if (rtw_init_wifi_display_info(padapter) == _FAIL)
+ RTW_ERR("Can't init init_wifi_display_info\n");
+#endif
+#endif /* CONFIG_P2P */
+
+ if (init_mlme_ext_priv(padapter) == _FAIL) {
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+#ifdef CONFIG_TDLS
+ if (rtw_init_tdls_info(padapter) == _FAIL) {
+ RTW_INFO("Can't rtw_init_tdls_info\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+#endif /* CONFIG_TDLS */
+
+ if (_rtw_init_xmit_priv(&padapter->xmitpriv, padapter) == _FAIL) {
+ RTW_INFO("Can't _rtw_init_xmit_priv\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ if (_rtw_init_recv_priv(&padapter->recvpriv, padapter) == _FAIL) {
+ RTW_INFO("Can't _rtw_init_recv_priv\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+ /* add for CONFIG_IEEE80211W, none 11w also can use */
+ spin_lock_init(&padapter->security_key_mutex);
+
+ /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+ /* memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv)); */
+
+ /* _init_timer(&(padapter->securitypriv.tkip_timer), padapter->pifp, rtw_use_tkipkey_handler, padapter); */
+
+ if (_rtw_init_sta_priv(&padapter->stapriv) == _FAIL) {
+ RTW_INFO("Can't _rtw_init_sta_priv\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+
+ padapter->stapriv.padapter = padapter;
+ padapter->setband = WIFI_FREQUENCY_BAND_AUTO;
+ padapter->fix_rate = 0xFF;
+ padapter->power_offset = 0;
+ padapter->rsvd_page_offset = 0;
+ padapter->rsvd_page_num = 0;
+
+ padapter->data_fb = 0;
+ padapter->fix_rx_ampdu_accept = RX_AMPDU_ACCEPT_INVALID;
+ padapter->fix_rx_ampdu_size = RX_AMPDU_SIZE_INVALID;
+#ifdef DBG_RX_COUNTER_DUMP
+ padapter->dump_rx_cnt_mode = 0;
+ padapter->drv_rx_cnt_ok = 0;
+ padapter->drv_rx_cnt_crcerror = 0;
+ padapter->drv_rx_cnt_drop = 0;
+#endif
+ rtw_init_bcmc_stainfo(padapter);
+
+ rtw_init_pwrctrl_priv(padapter);
+
+ /* memset((u8 *)&padapter->qospriv, 0, sizeof (struct qos_priv)); */ /* move to mlme_priv */
+
+#ifdef CONFIG_MP_INCLUDED
+ if (init_mp_priv(padapter) == _FAIL)
+ RTW_INFO("%s: initialize MP private data Fail!\n", __func__);
+#endif
+
+ rtw_hal_dm_init(padapter);
+#ifdef CONFIG_SW_LED
+ rtw_hal_sw_led_init(padapter);
+#endif
+#ifdef DBG_CONFIG_ERROR_DETECT
+ rtw_hal_sreset_init(padapter);
+#endif
+
+#ifdef CONFIG_INTEL_WIDI
+ if (rtw_init_intel_widi(padapter) == _FAIL) {
+ RTW_INFO("Can't rtw_init_intel_widi\n");
+ ret8 = _FAIL;
+ goto exit;
+ }
+#endif /* CONFIG_INTEL_WIDI */
+
+#ifdef CONFIG_WAPI_SUPPORT
+ padapter->WapiSupport = true; /* set true temp, will revise according to Efuse or Registry value later. */
+ rtw_wapi_init(padapter);
+#endif
+
+#ifdef CONFIG_BR_EXT
+ spin_lock_init(&padapter->br_ext_lock);
+#endif /* CONFIG_BR_EXT */
+
+#ifdef CONFIG_BEAMFORMING
+#ifdef RTW_BEAMFORMING_VERSION_2
+ rtw_bf_init(padapter);
+#endif /* RTW_BEAMFORMING_VERSION_2 */
+#endif /* CONFIG_BEAMFORMING */
+
+exit:
+
+
+
+ return ret8;
+
+}
+
+#ifdef CONFIG_WOWLAN
+void rtw_cancel_dynamic_chk_timer(_adapter *padapter)
+{
+ _cancel_timer_ex(&adapter_to_dvobj(padapter)->dynamic_chk_timer);
+}
+#endif
+
+void rtw_cancel_all_timer(_adapter *padapter)
+{
+
+ _cancel_timer_ex(&padapter->mlmepriv.assoc_timer);
+
+ _cancel_timer_ex(&padapter->mlmepriv.scan_to_timer);
+
+#ifdef CONFIG_DFS_MASTER
+ _cancel_timer_ex(&padapter->mlmepriv.dfs_master_timer);
+#endif
+
+ _cancel_timer_ex(&adapter_to_dvobj(padapter)->dynamic_chk_timer);
+
+ /* cancel sw led timer */
+ rtw_hal_sw_led_deinit(padapter);
+
+ _cancel_timer_ex(&(adapter_to_pwrctl(padapter)->pwr_state_check_timer));
+
+#ifdef CONFIG_TX_AMSDU
+ _cancel_timer_ex(&padapter->xmitpriv.amsdu_bk_timer);
+ _cancel_timer_ex(&padapter->xmitpriv.amsdu_be_timer);
+ _cancel_timer_ex(&padapter->xmitpriv.amsdu_vo_timer);
+ _cancel_timer_ex(&padapter->xmitpriv.amsdu_vi_timer);
+#endif
+
+#ifdef CONFIG_IOCTL_CFG80211
+#ifdef CONFIG_P2P
+ _cancel_timer_ex(&padapter->cfg80211_wdinfo.remain_on_ch_timer);
+#endif /* CONFIG_P2P */
+#endif /* CONFIG_IOCTL_CFG80211 */
+
+#ifdef CONFIG_SET_SCAN_DENY_TIMER
+ _cancel_timer_ex(&padapter->mlmepriv.set_scan_deny_timer);
+ rtw_clear_scan_deny(padapter);
+#endif
+
+#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS
+ _cancel_timer_ex(&padapter->recvpriv.signal_stat_timer);
+#endif
+
+#ifdef CONFIG_LPS_RPWM_TIMER
+ _cancel_timer_ex(&(adapter_to_pwrctl(padapter)->pwr_rpwm_timer));
+#endif /* CONFIG_LPS_RPWM_TIMER */
+
+ /* cancel dm timer */
+ rtw_hal_dm_deinit(padapter);
+
+#ifdef CONFIG_PLATFORM_FS_MX61
+ msleep(50);
+#endif
+}
+
+u8 rtw_free_drv_sw(_adapter *padapter)
+{
+
+#ifdef CONFIG_WAPI_SUPPORT
+ rtw_wapi_free(padapter);
+#endif
+
+ /* we can call rtw_p2p_enable here, but: */
+ /* 1. rtw_p2p_enable may have IO operation */
+ /* 2. rtw_p2p_enable is bundled with wext interface */
+ #ifdef CONFIG_P2P
+ {
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+ if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+ _cancel_timer_ex(&pwdinfo->find_phase_timer);
+ _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer);
+ _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer);
+ #ifdef CONFIG_CONCURRENT_MODE
+ _cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer);
+ #endif /* CONFIG_CONCURRENT_MODE */
+ rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+ }
+ }
+ #endif
+
+#ifdef CONFIG_INTEL_WIDI
+ rtw_free_intel_widi(padapter);
+#endif /* CONFIG_INTEL_WIDI */
+
+ free_mlme_ext_priv(&padapter->mlmeextpriv);
+
+#ifdef CONFIG_TDLS
+ /* rtw_free_tdls_info(&padapter->tdlsinfo); */
+#endif /* CONFIG_TDLS */
+
+ rtw_free_cmd_priv(&padapter->cmdpriv);
+
+ rtw_free_evt_priv(&padapter->evtpriv);
+
+ rtw_free_mlme_priv(&padapter->mlmepriv);
+
+ /* free_io_queue(padapter); */
+
+ _rtw_free_xmit_priv(&padapter->xmitpriv);
+
+ _rtw_free_sta_priv(&padapter->stapriv); /* will free bcmc_stainfo here */
+
+ _rtw_free_recv_priv(&padapter->recvpriv);
+
+ rtw_free_pwrctrl_priv(padapter);
+
+ /* rtw_mfree((void *)padapter, sizeof (padapter)); */
+
+#ifdef CONFIG_DRVEXT_MODULE
+ free_drvext(&padapter->drvextpriv);
+#endif
+
+ rtw_hal_free_data(padapter);
+
+
+ /* free the old_pnetdev */
+ if (padapter->rereg_nd_name_priv.old_pnetdev) {
+ free_netdev(padapter->rereg_nd_name_priv.old_pnetdev);
+ padapter->rereg_nd_name_priv.old_pnetdev = NULL;
+ }
+
+ return _SUCCESS;
+
+}
+void rtw_intf_start(_adapter *adapter)
+{
+ if (adapter->intf_start)
+ adapter->intf_start(adapter);
+}
+void rtw_intf_stop(_adapter *adapter)
+{
+ if (adapter->intf_stop)
+ adapter->intf_stop(adapter);
+}
+
+#ifdef CONFIG_CONCURRENT_MODE
+int _netdev_vir_if_open(struct net_device *pnetdev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ _adapter *primary_padapter = GET_PRIMARY_ADAPTER(padapter);
+
+ RTW_INFO(FUNC_NDEV_FMT" , bup=%d\n", FUNC_NDEV_ARG(pnetdev), padapter->bup);
+
+ if (!primary_padapter)
+ goto _netdev_virtual_iface_open_error;
+
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+ if (padapter->bup == false) {
+ u8 mac[ETH_ALEN];
+
+ /* get mac address from primary_padapter */
+ if (primary_padapter->bup == false)
+ rtw_macaddr_cfg(adapter_mac_addr(primary_padapter), get_hal_mac_addr(primary_padapter));
+
+ memcpy(mac, adapter_mac_addr(primary_padapter), ETH_ALEN);
+
+ /*
+ * If the BIT1 is 0, the address is universally administered.
+ * If it is 1, the address is locally administered
+ */
+ mac[0] |= BIT(1);
+
+ memcpy(adapter_mac_addr(padapter), mac, ETH_ALEN);
+
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ rtw_mbid_camid_alloc(padapter, adapter_mac_addr(padapter));
+#endif
+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter));
+ memcpy(pnetdev->dev_addr, adapter_mac_addr(padapter), ETH_ALEN);
+ }
+#endif /*CONFIG_PLATFORM_INTEL_BYT*/
+
+ if (primary_padapter->bup == false || !rtw_is_hw_init_completed(primary_padapter))
+ _netdev_open(primary_padapter->pnetdev);
+
+ if (padapter->bup == false && primary_padapter->bup == true &&
+ rtw_is_hw_init_completed(primary_padapter)) {
+ padapter->bFWReady = primary_padapter->bFWReady;
+ }
+
+ if (padapter->bup == false) {
+ if (rtw_start_drv_threads(padapter) == _FAIL)
+ goto _netdev_virtual_iface_open_error;
+ }
+
+#ifdef CONFIG_RTW_NAPI
+ if (padapter->napi_state == NAPI_DISABLE) {
+ napi_enable(&padapter->napi);
+ padapter->napi_state = NAPI_ENABLE;
+ }
+#endif
+
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_cfg80211_init_wiphy(padapter);
+ rtw_cfg80211_init_wdev_data(padapter);
+#endif
+
+ padapter->bup = true;
+
+ padapter->net_closed = false;
+
+ rtw_netif_wake_queue(pnetdev);
+
+ RTW_INFO(FUNC_NDEV_FMT" (bup=%d) exit\n", FUNC_NDEV_ARG(pnetdev), padapter->bup);
+
+ return 0;
+
+_netdev_virtual_iface_open_error:
+
+ padapter->bup = false;
+
+#ifdef CONFIG_RTW_NAPI
+ if(padapter->napi_state == NAPI_ENABLE) {
+ napi_disable(&padapter->napi);
+ padapter->napi_state = NAPI_DISABLE;
+ }
+#endif
+
+ netif_carrier_off(pnetdev);
+ rtw_netif_stop_queue(pnetdev);
+
+ return -1;
+
+}
+
+int netdev_vir_if_open(struct net_device *pnetdev)
+{
+ int ret;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+
+ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL);
+ ret = _netdev_vir_if_open(pnetdev);
+ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL);
+
+#ifdef CONFIG_AUTO_AP_MODE
+ /* if(padapter->iface_id == 2) */
+ /* rtw_start_auto_ap(padapter); */
+#endif
+
+ return ret;
+}
+
+static int netdev_vir_if_close(struct net_device *pnetdev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ RTW_INFO(FUNC_NDEV_FMT" , bup=%d\n", FUNC_NDEV_ARG(pnetdev), padapter->bup);
+ padapter->net_closed = true;
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+
+ if (pnetdev)
+ rtw_netif_stop_queue(pnetdev);
+
+#ifdef CONFIG_P2P
+ if (!rtw_p2p_chk_role(&padapter->wdinfo, P2P_ROLE_DISABLE))
+ rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
+#endif
+
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_scan_abort(padapter);
+ rtw_cfg80211_wait_scan_req_empty(padapter, 200);
+ adapter_wdev_data(padapter)->bandroid_scan = false;
+#endif
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+static const struct net_device_ops rtw_netdev_vir_if_ops = {
+ .ndo_init = rtw_ndev_init,
+ .ndo_uninit = rtw_ndev_uninit,
+ .ndo_open = netdev_vir_if_open,
+ .ndo_stop = netdev_vir_if_close,
+ .ndo_start_xmit = rtw_xmit_entry,
+ .ndo_set_mac_address = rtw_net_set_mac_address,
+ .ndo_get_stats = rtw_net_get_stats,
+ .ndo_do_ioctl = rtw_ioctl,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ .ndo_select_queue = rtw_select_queue,
+#endif
+};
+#endif
+
+static void rtw_hook_vir_if_ops(struct net_device *ndev)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
+ ndev->netdev_ops = &rtw_netdev_vir_if_ops;
+#else
+ ndev->init = rtw_ndev_init;
+ ndev->uninit = rtw_ndev_uninit;
+ ndev->open = netdev_vir_if_open;
+ ndev->stop = netdev_vir_if_close;
+ ndev->set_mac_address = rtw_net_set_mac_address;
+#endif
+}
+_adapter *rtw_drv_add_vir_if(_adapter *primary_padapter,
+ void (*set_intf_ops)(_adapter *primary_padapter, struct _io_ops *pops))
+{
+ int res = _FAIL;
+ _adapter *padapter = NULL;
+ struct dvobj_priv *pdvobjpriv;
+ u8 mac[ETH_ALEN];
+
+ /****** init adapter ******/
+ padapter = (_adapter *)rtw_zvmalloc(sizeof(*padapter));
+ if (padapter == NULL)
+ goto exit;
+
+ if (loadparam(padapter) != _SUCCESS)
+ goto free_adapter;
+
+ memcpy(padapter, primary_padapter, sizeof(_adapter));
+
+ /* */
+ padapter->bup = false;
+ padapter->net_closed = true;
+ padapter->dir_dev = NULL;
+ padapter->dir_odm = NULL;
+
+ /*set adapter_type/iface type*/
+ padapter->isprimary = false;
+ padapter->adapter_type = VIRTUAL_ADAPTER;
+
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ padapter->hw_port = HW_PORT0;
+#else
+ padapter->hw_port = HW_PORT1;
+#endif
+
+
+ /****** hook vir if into dvobj ******/
+ pdvobjpriv = adapter_to_dvobj(padapter);
+ padapter->iface_id = pdvobjpriv->iface_nums;
+ pdvobjpriv->padapters[pdvobjpriv->iface_nums++] = padapter;
+
+ padapter->intf_start = primary_padapter->intf_start;
+ padapter->intf_stop = primary_padapter->intf_stop;
+
+ /* step init_io_priv */
+ if ((rtw_init_io_priv(padapter, set_intf_ops)) == _FAIL) {
+ goto free_adapter;
+ }
+
+ /*init drv data*/
+ if (rtw_init_drv_sw(padapter) != _SUCCESS)
+ goto free_drv_sw;
+
+
+ /*get mac address from primary_padapter*/
+ memcpy(mac, adapter_mac_addr(primary_padapter), ETH_ALEN);
+
+ /*
+ * If the BIT1 is 0, the address is universally administered.
+ * If it is 1, the address is locally administered
+ */
+ mac[0] |= BIT(1);
+ if (padapter->iface_id > IFACE_ID1)
+ mac[4] ^= BIT(padapter->iface_id);
+
+ memcpy(adapter_mac_addr(padapter), mac, ETH_ALEN);
+ /* update mac-address to mbsid-cam cache*/
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ rtw_mbid_camid_alloc(padapter, adapter_mac_addr(padapter));
+#endif
+ RTW_INFO("%s if%d mac_addr : "MAC_FMT"\n", __func__, padapter->iface_id + 1, MAC_ARG(adapter_mac_addr(padapter)));
+#ifdef CONFIG_P2P
+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter));
+#endif
+ res = _SUCCESS;
+
+free_drv_sw:
+ if (res != _SUCCESS && padapter)
+ rtw_free_drv_sw(padapter);
+free_adapter:
+ if (res != _SUCCESS && padapter) {
+ rtw_vmfree((u8 *)padapter, sizeof(*padapter));
+ padapter = NULL;
+ }
+exit:
+ return padapter;
+}
+
+void rtw_drv_stop_vir_if(_adapter *padapter)
+{
+ struct net_device *pnetdev = NULL;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ if (padapter == NULL)
+ return;
+
+ pnetdev = padapter->pnetdev;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
+ rtw_disassoc_cmd(padapter, 0, false);
+
+#ifdef CONFIG_AP_MODE
+ if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) {
+ free_mlme_ap_info(padapter);
+ #ifdef CONFIG_HOSTAPD_MLME
+ hostapd_mode_unload(padapter);
+ #endif
+ }
+#endif
+
+ if (padapter->bup == true) {
+ #ifdef CONFIG_XMIT_ACK
+ if (padapter->xmitpriv.ack_tx)
+ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP);
+ #endif
+
+ rtw_intf_stop(padapter);
+
+ rtw_stop_drv_threads(padapter);
+
+ padapter->bup = false;
+ }
+ /* cancel timer after thread stop */
+ rtw_cancel_all_timer(padapter);
+}
+
+void rtw_drv_free_vir_if(_adapter *padapter)
+{
+ if (padapter == NULL)
+ return;
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+ rtw_free_drv_sw(padapter);
+
+ /* TODO: use rtw_os_ndevs_deinit instead at the first stage of driver's dev deinit function */
+ rtw_os_ndev_free(padapter);
+
+ rtw_vmfree((u8 *)padapter, sizeof(_adapter));
+}
+
+
+void rtw_drv_stop_vir_ifaces(struct dvobj_priv *dvobj)
+{
+ int i;
+
+ for (i = VIF_START_ID; i < dvobj->iface_nums; i++)
+ rtw_drv_stop_vir_if(dvobj->padapters[i]);
+}
+
+void rtw_drv_free_vir_ifaces(struct dvobj_priv *dvobj)
+{
+ int i;
+
+ for (i = VIF_START_ID; i < dvobj->iface_nums; i++)
+ rtw_drv_free_vir_if(dvobj->padapters[i]);
+}
+
+void rtw_drv_del_vir_if(_adapter *padapter)
+{
+ rtw_drv_stop_vir_if(padapter);
+ rtw_drv_free_vir_if(padapter);
+}
+
+void rtw_drv_del_vir_ifaces(_adapter *primary_padapter)
+{
+ int i;
+ struct dvobj_priv *dvobj = primary_padapter->dvobj;
+
+ for (i = VIF_START_ID; i < dvobj->iface_nums; i++)
+ rtw_drv_del_vir_if(dvobj->padapters[i]);
+
+}
+
+#endif /*end of CONFIG_CONCURRENT_MODE*/
+
+static int rtw_os_ndevs_register(struct dvobj_priv *dvobj)
+{
+ int i, status = _SUCCESS;
+ struct registry_priv *regsty = dvobj_to_regsty(dvobj);
+ _adapter *adapter;
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (rtw_cfg80211_dev_res_register(dvobj) != _SUCCESS) {
+ rtw_warn_on(1);
+ status = _FAIL;
+ goto exit;
+ }
+#endif
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+
+ if (i >= CONFIG_IFACE_NUMBER) {
+ RTW_ERR("%s %d >= CONFIG_IFACE_NUMBER(%d)\n", __func__, i, CONFIG_IFACE_NUMBER);
+ rtw_warn_on(1);
+ continue;
+ }
+
+ adapter = dvobj->padapters[i];
+ if (adapter) {
+ char *name;
+
+ #ifdef CONFIG_RTW_DYNAMIC_NDEV
+ if (!is_primary_adapter(adapter))
+ continue;
+ #endif
+
+ if (adapter->iface_id == IFACE_ID0)
+ name = regsty->ifname;
+ else if (adapter->iface_id == IFACE_ID1)
+ name = regsty->if2name;
+ else
+ name = "wlan%d";
+
+ status = rtw_os_ndev_register(adapter, name);
+
+ if (status != _SUCCESS) {
+ rtw_warn_on(1);
+ break;
+ }
+ }
+ }
+
+ if (status != _SUCCESS) {
+ for (; i >= 0; i--) {
+ adapter = dvobj->padapters[i];
+ if (adapter)
+ rtw_os_ndev_unregister(adapter);
+ }
+ }
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ if (status != _SUCCESS)
+ rtw_cfg80211_dev_res_unregister(dvobj);
+#endif
+exit:
+ return status;
+}
+
+void rtw_os_ndevs_unregister(struct dvobj_priv *dvobj)
+{
+ int i;
+ _adapter *adapter = NULL;
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ adapter = dvobj->padapters[i];
+
+ if (adapter == NULL)
+ continue;
+
+ rtw_os_ndev_unregister(adapter);
+ }
+
+#if defined(CONFIG_IOCTL_CFG80211)
+ rtw_cfg80211_dev_res_unregister(dvobj);
+#endif
+}
+
+/**
+ * rtw_os_ndevs_init - Allocate and register OS layer net devices and relating structures for @dvobj
+ * @dvobj: the dvobj on which this function applies
+ *
+ * Returns:
+ * _SUCCESS or _FAIL
+ */
+int rtw_os_ndevs_init(struct dvobj_priv *dvobj)
+{
+ int ret = _FAIL;
+
+ if (rtw_os_ndevs_alloc(dvobj) != _SUCCESS)
+ goto exit;
+
+ if (rtw_os_ndevs_register(dvobj) != _SUCCESS)
+ goto os_ndevs_free;
+
+ ret = _SUCCESS;
+
+os_ndevs_free:
+ if (ret != _SUCCESS)
+ rtw_os_ndevs_free(dvobj);
+exit:
+ return ret;
+}
+
+/**
+ * rtw_os_ndevs_deinit - Unregister and free OS layer net devices and relating structures for @dvobj
+ * @dvobj: the dvobj on which this function applies
+ */
+void rtw_os_ndevs_deinit(struct dvobj_priv *dvobj)
+{
+ rtw_os_ndevs_unregister(dvobj);
+ rtw_os_ndevs_free(dvobj);
+}
+
+#ifdef CONFIG_BR_EXT
+void netdev_br_init(struct net_device *netdev)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
+ rcu_read_lock();
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) */
+
+ /* if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == true) */
+ {
+ /* struct net_bridge *br = netdev->br_port->br; */ /* ->dev->dev_addr; */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
+ if (netdev->br_port)
+#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */
+ if (rcu_dereference(adapter->pnetdev->rx_handler_data))
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */
+ {
+ struct net_device *br_netdev;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
+ br_netdev = dev_get_by_name(CONFIG_BR_EXT_BRNAME);
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) */
+ struct net *devnet = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+ devnet = netdev->nd_net;
+#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) */
+ devnet = dev_net(netdev);
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)) */
+
+ br_netdev = dev_get_by_name(devnet, CONFIG_BR_EXT_BRNAME);
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) */
+
+ if (br_netdev) {
+ memcpy(adapter->br_mac, br_netdev->dev_addr, ETH_ALEN);
+ dev_put(br_netdev);
+ } else
+ printk("%s()-%d: dev_get_by_name(%s) failed!", __func__, __LINE__, CONFIG_BR_EXT_BRNAME);
+ }
+
+ adapter->ethBrExtInfo.addPPPoETag = 1;
+ }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
+ rcu_read_unlock();
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) */
+}
+#endif /* CONFIG_BR_EXT */
+
+int _netdev_open(struct net_device *pnetdev)
+{
+ uint status;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */
+
+
+ RTW_INFO(FUNC_NDEV_FMT" , bup=%d\n", FUNC_NDEV_ARG(pnetdev), padapter->bup);
+
+ padapter->netif_up = true;
+
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+ rtw_sdio_set_power(1);
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+
+ if (pwrctrlpriv->ps_flag == true) {
+ padapter->net_closed = false;
+ goto netdev_open_normal_process;
+ }
+
+ if (padapter->bup == false) {
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+ rtw_macaddr_cfg(adapter_mac_addr(padapter), get_hal_mac_addr(padapter));
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ rtw_mbid_camid_alloc(padapter, adapter_mac_addr(padapter));
+#endif
+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter));
+ memcpy(pnetdev->dev_addr, adapter_mac_addr(padapter), ETH_ALEN);
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+
+ rtw_clr_surprise_removed(padapter);
+ rtw_clr_drv_stopped(padapter);
+
+ status = rtw_hal_init(padapter);
+ if (status == _FAIL) {
+ goto netdev_open_error;
+ }
+ RTW_INFO("MAC Address = "MAC_FMT"\n", MAC_ARG(pnetdev->dev_addr));
+
+ status = rtw_start_drv_threads(padapter);
+ if (status == _FAIL) {
+ RTW_INFO("Initialize driver software resource Failed!\n");
+ goto netdev_open_error;
+ }
+
+#ifdef CONFIG_RTW_NAPI
+ if(padapter->napi_state == NAPI_DISABLE) {
+ napi_enable(&padapter->napi);
+ padapter->napi_state = NAPI_ENABLE;
+ }
+#endif
+
+#ifdef CONFIG_DRVEXT_MODULE
+ init_drvext(padapter);
+#endif
+ rtw_intf_start(padapter);
+
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_cfg80211_init_wiphy(padapter);
+ rtw_cfg80211_init_wdev_data(padapter);
+#endif
+
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+ padapter->bup = true;
+ pwrctrlpriv->bips_processing = false;
+
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_IpsNotify(padapter, IPS_NONE);
+#endif /* CONFIG_BT_COEXIST */
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+ }
+ padapter->net_closed = false;
+
+ _set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 2000);
+
+#ifndef CONFIG_IPS_CHECK_IN_WD
+ rtw_set_pwr_state_check_timer(pwrctrlpriv);
+#endif
+
+ /* netif_carrier_on(pnetdev); */ /* call this func when rtw_joinbss_event_callback return success */
+ rtw_netif_wake_queue(pnetdev);
+
+#ifdef CONFIG_BR_EXT
+ netdev_br_init(pnetdev);
+#endif /* CONFIG_BR_EXT */
+
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+ if (is_primary_adapter(padapter) && (pHalData->EEPROMBluetoothCoexist)) {
+ rtw_btcoex_init_socket(padapter);
+ padapter->coex_info.BtMgnt.ExtConfig.HCIExtensionVer = 0x04;
+ rtw_btcoex_SetHciVersion(padapter, 0x04);
+ } else
+ RTW_INFO("CONFIG_BT_COEXIST: VIRTUAL_ADAPTER\n");
+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */
+
+
+netdev_open_normal_process:
+
+#ifdef CONFIG_CONCURRENT_MODE
+ {
+ _adapter *sec_adapter = adapter_to_dvobj(padapter)->padapters[IFACE_ID1];
+
+ #ifndef CONFIG_RTW_DYNAMIC_NDEV
+ if (sec_adapter && (sec_adapter->bup == false))
+ _netdev_vir_if_open(sec_adapter->pnetdev);
+ #endif
+ }
+#endif
+
+ RTW_INFO("-871x_drv - drv_open, bup=%d\n", padapter->bup);
+
+ return 0;
+
+netdev_open_error:
+
+ padapter->bup = false;
+
+#ifdef CONFIG_RTW_NAPI
+ if(padapter->napi_state == NAPI_ENABLE) {
+ napi_disable(&padapter->napi);
+ padapter->napi_state = NAPI_DISABLE;
+ }
+#endif
+
+ netif_carrier_off(pnetdev);
+ rtw_netif_stop_queue(pnetdev);
+
+ RTW_INFO("-871x_drv - drv_open fail, bup=%d\n", padapter->bup);
+
+ return -1;
+
+}
+
+int netdev_open(struct net_device *pnetdev)
+{
+ int ret = false;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter);
+
+ if (pwrctrlpriv->bInSuspend == true) {
+ RTW_INFO(" [WARN] "ADPT_FMT" %s failed, bInSuspend=%d\n", ADPT_ARG(padapter), __func__, pwrctrlpriv->bInSuspend);
+ return 0;
+ }
+
+ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL);
+ if (is_primary_adapter(padapter))
+ ret = _netdev_open(pnetdev);
+#ifdef CONFIG_CONCURRENT_MODE
+ else
+ ret = _netdev_vir_if_open(pnetdev);
+#endif
+ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL);
+
+
+#ifdef CONFIG_AUTO_AP_MODE
+ if (padapter->iface_id == IFACE_ID2)
+ rtw_start_auto_ap(padapter);
+#endif
+
+ return ret;
+}
+
+#ifdef CONFIG_IPS
+static int ips_netdrv_open(_adapter *padapter)
+{
+ int status = _SUCCESS;
+ /* struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); */
+
+ padapter->net_closed = false;
+
+ RTW_INFO("===> %s.........\n", __func__);
+
+
+ rtw_clr_drv_stopped(padapter);
+ /* padapter->bup = true; */
+
+ status = rtw_hal_init(padapter);
+ if (status == _FAIL) {
+ goto netdev_open_error;
+ }
+ rtw_intf_start(padapter);
+
+#ifndef CONFIG_IPS_CHECK_IN_WD
+ rtw_set_pwr_state_check_timer(adapter_to_pwrctl(padapter));
+#endif
+ _set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 2000);
+
+ return _SUCCESS;
+
+netdev_open_error:
+ /* padapter->bup = false; */
+ RTW_INFO("-ips_netdrv_open - drv_open failure, bup=%d\n", padapter->bup);
+
+ return _FAIL;
+}
+
+
+int rtw_ips_pwr_up(_adapter *padapter)
+{
+ int result;
+ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
+#ifdef DBG_CONFIG_ERROR_DETECT
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+#endif/* #ifdef DBG_CONFIG_ERROR_DETECT */
+ u32 start_time = jiffies;
+ RTW_INFO("===> rtw_ips_pwr_up..............\n");
+
+#if defined(CONFIG_SWLPS_IN_IPS) || defined(CONFIG_FWLPS_IN_IPS)
+#ifdef DBG_CONFIG_ERROR_DETECT
+ if (psrtpriv->silent_reset_inprogress == true)
+#endif/* #ifdef DBG_CONFIG_ERROR_DETECT */
+#endif /* defined(CONFIG_SWLPS_IN_IPS) || defined(CONFIG_FWLPS_IN_IPS) */
+ rtw_reset_drv_sw(padapter);
+
+ result = ips_netdrv_open(padapter);
+
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+ RTW_INFO("<=== rtw_ips_pwr_up.............. in %dms\n", rtw_get_passing_time_ms(start_time));
+ return result;
+
+}
+
+void rtw_ips_pwr_down(_adapter *padapter)
+{
+ u32 start_time = jiffies;
+ RTW_INFO("===> rtw_ips_pwr_down...................\n");
+
+ padapter->net_closed = true;
+
+ rtw_ips_dev_unload(padapter);
+ RTW_INFO("<=== rtw_ips_pwr_down..................... in %dms\n", rtw_get_passing_time_ms(start_time));
+}
+#endif
+void rtw_ips_dev_unload(_adapter *padapter)
+{
+ struct net_device *pnetdev = (struct net_device *)padapter->pnetdev;
+ struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
+ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter);
+#ifdef DBG_CONFIG_ERROR_DETECT
+ struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+#endif/* #ifdef DBG_CONFIG_ERROR_DETECT */
+ RTW_INFO("====> %s...\n", __func__);
+
+
+#if defined(CONFIG_SWLPS_IN_IPS) || defined(CONFIG_FWLPS_IN_IPS)
+#ifdef DBG_CONFIG_ERROR_DETECT
+ if (psrtpriv->silent_reset_inprogress == true)
+#endif /* #ifdef DBG_CONFIG_ERROR_DETECT */
+#endif /* defined(CONFIG_SWLPS_IN_IPS) || defined(CONFIG_FWLPS_IN_IPS) */
+ {
+ rtw_hal_set_hwreg(padapter, HW_VAR_FIFO_CLEARN_UP, NULL);
+ rtw_intf_stop(padapter);
+ }
+ if (!rtw_is_surprise_removed(padapter))
+ rtw_hal_deinit(padapter);
+}
+
+int pm_netdev_open(struct net_device *pnetdev, u8 bnormal)
+{
+ int status = 0;
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+
+ if (bnormal) {
+ _enter_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL);
+ status = _netdev_open(pnetdev);
+ _exit_critical_mutex(&(adapter_to_dvobj(padapter)->hw_init_mutex), NULL);
+ }
+#ifdef CONFIG_IPS
+ else
+ status = (_SUCCESS == ips_netdrv_open(padapter)) ? (0) : (-1);
+#endif
+
+ return status;
+}
+
+static int netdev_close(struct net_device *pnetdev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */
+
+ RTW_INFO(FUNC_NDEV_FMT" , bup=%d\n", FUNC_NDEV_ARG(pnetdev), padapter->bup);
+#ifndef CONFIG_PLATFORM_INTEL_BYT
+ if (pwrctl->bInternalAutoSuspend == true) {
+ /* rtw_pwr_wakeup(padapter); */
+ if (pwrctl->rf_pwrstate == rf_off)
+ pwrctl->ps_flag = true;
+ }
+ padapter->net_closed = true;
+ padapter->netif_up = false;
+ pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+
+ /* if (!rtw_is_hw_init_completed(padapter)) {
+ RTW_INFO("(1)871x_drv - drv_close, bup=%d, hw_init_completed=%s\n", padapter->bup, rtw_is_hw_init_completed(padapter)?"true":"false");
+
+ rtw_set_drv_stopped(padapter);
+
+ rtw_dev_unload(padapter);
+ }
+ else*/
+ if (pwrctl->rf_pwrstate == rf_on) {
+ RTW_INFO("(2)871x_drv - drv_close, bup=%d, hw_init_completed=%s\n", padapter->bup, rtw_is_hw_init_completed(padapter) ? "true" : "false");
+
+ /* s1. */
+ if (pnetdev)
+ rtw_netif_stop_queue(pnetdev);
+
+#ifndef CONFIG_ANDROID
+ /* s2. */
+ LeaveAllPowerSaveMode(padapter);
+ rtw_disassoc_cmd(padapter, 500, false);
+ /* s2-2. indicate disconnect to os */
+ rtw_indicate_disconnect(padapter, 0, false);
+ /* s2-3. */
+ rtw_free_assoc_resources(padapter, 1);
+ /* s2-4. */
+ rtw_free_network_queue(padapter, true);
+#endif
+ /* Close LED */
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+ }
+
+#ifdef CONFIG_BR_EXT
+ /* if (OPMODE & (WIFI_STATION_STATE | WIFI_ADHOC_STATE)) */
+ {
+ /* void nat25_db_cleanup(_adapter *priv); */
+ nat25_db_cleanup(padapter);
+ }
+#endif /* CONFIG_BR_EXT */
+
+#ifdef CONFIG_P2P
+ if (!rtw_p2p_chk_role(&padapter->wdinfo, P2P_ROLE_DISABLE))
+ rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_scan_abort(padapter);
+ rtw_cfg80211_wait_scan_req_empty(padapter, 200);
+ adapter_wdev_data(padapter)->bandroid_scan = false;
+ /* padapter->rtw_wdev->iftype = NL80211_IFTYPE_MONITOR; */ /* set this at the end */
+#endif /* CONFIG_IOCTL_CFG80211 */
+
+#ifdef CONFIG_WAPI_SUPPORT
+ rtw_wapi_disable_tx(padapter);
+#endif
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+ if (is_primary_adapter(padapter) && (pHalData->EEPROMBluetoothCoexist))
+ rtw_btcoex_close_socket(padapter);
+ else
+ RTW_INFO("CONFIG_BT_COEXIST: VIRTUAL_ADAPTER\n");
+#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */
+#else /* !CONFIG_PLATFORM_INTEL_BYT */
+
+ if (pwrctl->bInSuspend == true) {
+ RTW_INFO("+871x_drv - drv_close, bInSuspend=%d\n", pwrctl->bInSuspend);
+ return 0;
+ }
+
+ rtw_scan_abort(padapter); /* stop scanning process before wifi is going to down */
+#ifdef CONFIG_IOCTL_CFG80211
+ rtw_cfg80211_wait_scan_req_empty(padapter, 200);
+#endif
+
+ RTW_INFO("netdev_close, bips_processing=%d\n", pwrctl->bips_processing);
+ while (pwrctl->bips_processing == true) /* waiting for ips_processing done before call rtw_dev_unload() */
+ rtw_msleep_os(1);
+
+ rtw_dev_unload(padapter);
+ rtw_sdio_set_power(0);
+
+#endif /* !CONFIG_PLATFORM_INTEL_BYT */
+
+ RTW_INFO("-871x_drv - drv_close, bup=%d\n", padapter->bup);
+
+ return 0;
+}
+
+static int pm_netdev_close(struct net_device *pnetdev, u8 bnormal)
+{
+ int status = 0;
+
+ status = netdev_close(pnetdev);
+
+ return status;
+}
+
+void rtw_ndev_destructor(struct net_device *ndev)
+{
+ RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+
+#ifdef CONFIG_IOCTL_CFG80211
+ if (ndev->ieee80211_ptr)
+ rtw_mfree((u8 *)ndev->ieee80211_ptr, sizeof(struct wireless_dev));
+#endif
+ free_netdev(ndev);
+}
+
+#ifdef CONFIG_ARP_KEEP_ALIVE
+struct route_info {
+ struct in_addr dst_addr;
+ struct in_addr src_addr;
+ struct in_addr gateway;
+ unsigned int dev_index;
+};
+
+static void parse_routes(struct nlmsghdr *nl_hdr, struct route_info *rt_info)
+{
+ struct rtmsg *rt_msg;
+ struct rtattr *rt_attr;
+ int rt_len;
+
+ rt_msg = (struct rtmsg *) NLMSG_DATA(nl_hdr);
+ if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN))
+ return;
+
+ rt_attr = (struct rtattr *) RTM_RTA(rt_msg);
+ rt_len = RTM_PAYLOAD(nl_hdr);
+
+ for (; RTA_OK(rt_attr, rt_len); rt_attr = RTA_NEXT(rt_attr, rt_len)) {
+ switch (rt_attr->rta_type) {
+ case RTA_OIF:
+ rt_info->dev_index = *(int *) RTA_DATA(rt_attr);
+ break;
+ case RTA_GATEWAY:
+ rt_info->gateway.s_addr = *(u_int *) RTA_DATA(rt_attr);
+ break;
+ case RTA_PREFSRC:
+ rt_info->src_addr.s_addr = *(u_int *) RTA_DATA(rt_attr);
+ break;
+ case RTA_DST:
+ rt_info->dst_addr.s_addr = *(u_int *) RTA_DATA(rt_attr);
+ break;
+ }
+ }
+}
+
+static int route_dump(u32 *gw_addr , int *gw_index)
+{
+ int err = 0;
+ struct socket *sock;
+ struct {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
+ } req;
+ struct msghdr msg;
+ struct iovec iov;
+ struct sockaddr_nl nladdr;
+ mm_segment_t oldfs;
+ char *pg;
+ int size = 0;
+
+ err = sock_create(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, &sock);
+ if (err) {
+ printk(": Could not create a datagram socket, error = %d\n", -ENXIO);
+ return err;
+ }
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = RTM_GETROUTE;
+ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.g.rtgen_family = AF_INET;
+
+ iov.iov_base = &req;
+ iov.iov_len = sizeof(req);
+
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+ /* referece:sock_xmit in kernel code
+ * WRITE for sock_sendmsg, READ for sock_recvmsg
+ * third parameter for msg_iovlen
+ * last parameter for iov_len
+ */
+ iov_iter_init(&msg.msg_iter, WRITE, &iov, 1, sizeof(req));
+#else
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+#endif
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_DONTWAIT;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ err = sock_sendmsg(sock, &msg);
+#else
+ err = sock_sendmsg(sock, &msg, sizeof(req));
+#endif
+ set_fs(oldfs);
+
+ if (err < 0)
+ goto out_sock;
+
+ pg = (char *) __get_free_page(GFP_KERNEL);
+ if (pg == NULL) {
+ err = -ENOMEM;
+ goto out_sock;
+ }
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+restart:
+#endif
+
+ for (;;) {
+ struct nlmsghdr *h;
+
+ iov.iov_base = pg;
+ iov.iov_len = PAGE_SIZE;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+ iov_iter_init(&msg.msg_iter, READ, &iov, 1, PAGE_SIZE);
+#endif
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ err = sock_recvmsg(sock, &msg, PAGE_SIZE, MSG_DONTWAIT);
+ set_fs(oldfs);
+
+ if (err < 0)
+ goto out_sock_pg;
+
+ if (msg.msg_flags & MSG_TRUNC) {
+ err = -ENOBUFS;
+ goto out_sock_pg;
+ }
+
+ h = (struct nlmsghdr *) pg;
+
+ while (NLMSG_OK(h, err)) {
+ struct route_info rt_info;
+ if (h->nlmsg_type == NLMSG_DONE) {
+ err = 0;
+ goto done;
+ }
+
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *errm = (struct nlmsgerr *) NLMSG_DATA(h);
+ err = errm->error;
+ printk("NLMSG error: %d\n", errm->error);
+ goto done;
+ }
+
+ if (h->nlmsg_type == RTM_GETROUTE)
+ printk("RTM_GETROUTE: NLMSG: %d\n", h->nlmsg_type);
+ if (h->nlmsg_type != RTM_NEWROUTE) {
+ printk("NLMSG: %d\n", h->nlmsg_type);
+ err = -EINVAL;
+ goto done;
+ }
+
+ memset(&rt_info, 0, sizeof(struct route_info));
+ parse_routes(h, &rt_info);
+ if (!rt_info.dst_addr.s_addr && rt_info.gateway.s_addr && rt_info.dev_index) {
+ *gw_addr = rt_info.gateway.s_addr;
+ *gw_index = rt_info.dev_index;
+
+ }
+ h = NLMSG_NEXT(h, err);
+ }
+
+ if (err) {
+ printk("!!!Remnant of size %d %d %d\n", err, h->nlmsg_len, h->nlmsg_type);
+ err = -EINVAL;
+ break;
+ }
+ }
+
+done:
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ if (!err && req.g.rtgen_family == AF_INET) {
+ req.g.rtgen_family = AF_INET6;
+
+ iov.iov_base = &req;
+ iov.iov_len = sizeof(req);
+
+ msg.msg_name = &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+ iov_iter_init(&msg.msg_iter, WRITE, &iov, 1, sizeof(req));
+#else
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+#endif
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = MSG_DONTWAIT;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ err = sock_sendmsg(sock, &msg);
+#else
+ err = sock_sendmsg(sock, &msg, sizeof(req));
+#endif
+ set_fs(oldfs);
+
+ if (err > 0)
+ goto restart;
+ }
+#endif
+
+out_sock_pg:
+ free_page((unsigned long) pg);
+
+out_sock:
+ sock_release(sock);
+ return err;
+}
+
+static int arp_query(unsigned char *haddr, u32 paddr,
+ struct net_device *dev)
+{
+ struct neighbour *neighbor_entry;
+ int ret = 0;
+
+ neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev);
+
+ if (neighbor_entry != NULL) {
+ neighbor_entry->used = jiffies;
+ if (neighbor_entry->nud_state & NUD_VALID) {
+ memcpy(haddr, neighbor_entry->ha, dev->addr_len);
+ ret = 1;
+ }
+ neigh_release(neighbor_entry);
+ }
+ return ret;
+}
+
+static int get_defaultgw(u32 *ip_addr , char mac[])
+{
+ int gw_index = 0; /* oif device index */
+ struct net_device *gw_dev = NULL; /* oif device */
+
+ route_dump(ip_addr, &gw_index);
+
+ if (!(*ip_addr) || !gw_index) {
+ /* RTW_INFO("No default GW\n"); */
+ return -1;
+ }
+
+ gw_dev = dev_get_by_index(&init_net, gw_index);
+
+ if (gw_dev == NULL) {
+ /* RTW_INFO("get Oif Device Fail\n"); */
+ return -1;
+ }
+
+ if (!arp_query(mac, *ip_addr, gw_dev)) {
+ /* RTW_INFO( "arp query failed\n"); */
+ dev_put(gw_dev);
+ return -1;
+
+ }
+ dev_put(gw_dev);
+
+ return 0;
+}
+
+int rtw_gw_addr_query(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
+ u32 gw_addr = 0; /* default gw address */
+ unsigned char gw_mac[32] = {0}; /* default gw mac */
+ int i;
+ int res;
+
+ res = get_defaultgw(&gw_addr, gw_mac);
+ if (!res) {
+ pmlmepriv->gw_ip[0] = gw_addr & 0xff;
+ pmlmepriv->gw_ip[1] = (gw_addr & 0xff00) >> 8;
+ pmlmepriv->gw_ip[2] = (gw_addr & 0xff0000) >> 16;
+ pmlmepriv->gw_ip[3] = (gw_addr & 0xff000000) >> 24;
+ memcpy(pmlmepriv->gw_mac_addr, gw_mac, 6);
+ RTW_INFO("%s Gateway Mac:\t" MAC_FMT "\n", __func__, MAC_ARG(pmlmepriv->gw_mac_addr));
+ RTW_INFO("%s Gateway IP:\t" IP_FMT "\n", __func__, IP_ARG(pmlmepriv->gw_ip));
+ } else
+ RTW_INFO("Get Gateway IP/MAC fail!\n");
+
+ return res;
+}
+#endif
+
+void rtw_dev_unload(_adapter *padapter)
+{
+ struct net_device *pnetdev = (struct net_device *)padapter->pnetdev;
+ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
+ struct dvobj_priv *pobjpriv = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &pobjpriv->drv_dbg;
+ struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+ u8 cnt = 0;
+
+
+ if (padapter->bup == true) {
+ RTW_INFO("==> "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+ rtw_set_drv_stopped(padapter);
+#ifdef CONFIG_XMIT_ACK
+ if (padapter->xmitpriv.ack_tx)
+ rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP);
+#endif
+
+ rtw_intf_stop(padapter);
+
+
+ if (!pwrctl->bInternalAutoSuspend)
+ rtw_stop_drv_threads(padapter);
+
+ while (ATOMIC_READ(&(pcmdpriv->cmdthd_running)) == true) {
+ if (cnt > 5) {
+ RTW_INFO("stop cmdthd timeout\n");
+ break;
+ } else {
+ cnt++;
+ RTW_INFO("cmdthd is running(%d)\n", cnt);
+ rtw_msleep_os(10);
+ }
+ }
+
+
+ /* check the status of IPS */
+ if (rtw_hal_check_ips_status(padapter) == true || pwrctl->rf_pwrstate == rf_off) { /* check HW status and SW state */
+ RTW_INFO("%s: driver in IPS-FWLPS\n", __func__);
+ pdbgpriv->dbg_dev_unload_inIPS_cnt++;
+ } else
+ RTW_INFO("%s: driver not in IPS\n", __func__);
+
+ if (!rtw_is_surprise_removed(padapter)) {
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_IpsNotify(padapter, pwrctl->ips_mode_req);
+#endif
+#ifdef CONFIG_WOWLAN
+ if (pwrctl->bSupportRemoteWakeup == true &&
+ pwrctl->wowlan_mode == true)
+ RTW_INFO("%s bSupportRemoteWakeup==true do not run rtw_hal_deinit()\n", __func__);
+ else
+#endif
+ {
+ /* amy modify 20120221 for power seq is different between driver open and ips */
+ rtw_hal_deinit(padapter);
+ }
+ rtw_set_surprise_removed(padapter);
+ }
+
+ padapter->bup = false;
+
+ RTW_INFO("<== "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+ } else {
+ RTW_INFO("%s: bup==false\n", __func__);
+ }
+ rtw_cancel_all_timer(padapter);
+}
+
+int rtw_suspend_free_assoc_resource(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct net_device *pnetdev = padapter->pnetdev;
+#ifdef CONFIG_P2P
+ struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_P2P */
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+
+ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) {
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
+ && check_fwstate(pmlmepriv, _FW_LINKED)
+ #ifdef CONFIG_P2P
+ && (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
+ #if defined(CONFIG_IOCTL_CFG80211) && RTW_P2P_GROUP_INTERFACE
+ || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)
+ #endif
+ )
+ #endif /* CONFIG_P2P */
+ ) {
+ RTW_INFO("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n", __func__,
+ pmlmepriv->cur_network.network.Ssid.Ssid,
+ MAC_ARG(pmlmepriv->cur_network.network.MacAddress),
+ pmlmepriv->cur_network.network.Ssid.SsidLength,
+ pmlmepriv->assoc_ssid.SsidLength);
+ rtw_set_to_roam(padapter, 1);
+ }
+ }
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) {
+ rtw_disassoc_cmd(padapter, 0, false);
+ /* s2-2. indicate disconnect to os */
+ rtw_indicate_disconnect(padapter, 0, false);
+ }
+#ifdef CONFIG_AP_MODE
+ else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+ rtw_sta_flush(padapter, true);
+#endif
+
+ /* s2-3. */
+ rtw_free_assoc_resources(padapter, 1);
+
+ /* s2-4. */
+#ifdef CONFIG_AUTOSUSPEND
+ if (is_primary_adapter(padapter) && (!adapter_to_pwrctl(padapter)->bInternalAutoSuspend))
+#endif
+ rtw_free_network_queue(padapter, true);
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+ RTW_INFO("%s: fw_under_survey\n", __func__);
+ rtw_indicate_scan_done(padapter, 1);
+ clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+ }
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) {
+ RTW_INFO("%s: fw_under_linking\n", __func__);
+ rtw_indicate_disconnect(padapter, 0, false);
+ }
+
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+ return _SUCCESS;
+}
+
+#ifdef CONFIG_WOWLAN
+int rtw_suspend_wow(_adapter *padapter)
+{
+ u8 ch, bw, offset;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct net_device *pnetdev = padapter->pnetdev;
+ struct dvobj_priv *psdpriv = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct wowlan_ioctl_param poidparam;
+ int i;
+ _adapter *iface = NULL;
+ u8 ps_mode;
+ int ret = _SUCCESS;
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+
+
+ RTW_INFO("wowlan_mode: %d\n", pwrpriv->wowlan_mode);
+ RTW_INFO("wowlan_pno_enable: %d\n", pwrpriv->wowlan_pno_enable);
+#ifdef CONFIG_P2P_WOWLAN
+ RTW_INFO("wowlan_p2p_enable: %d\n", pwrpriv->wowlan_p2p_enable);
+#endif
+
+ if (pwrpriv->wowlan_mode == true) {
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SuspendNotify(padapter, BTCOEX_SUSPEND_STATE_SUSPEND_KEEP_ANT);
+#endif
+
+ if (pnetdev)
+ rtw_netif_stop_queue(pnetdev);
+ rtw_mi_buddy_netif_stop_queue(padapter, true);
+
+ /* 0. Power off LED */
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+ /* 1. stop thread */
+ rtw_set_drv_stopped(padapter); /*for stop thread*/
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if ((iface) && (iface->bup == true))
+ rtw_stop_drv_threads(iface);
+ }
+ rtw_clr_drv_stopped(padapter); /*for 32k command*/
+
+ /* #ifdef CONFIG_LPS */
+ /* rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "WOWLAN"); */
+ /* #endif */
+
+ /* 2.2 free irq */
+ /* sdio_free_irq(adapter_to_dvobj(padapter)); */
+#if !(CONFIG_RTW_SDIO_KEEP_IRQ)
+ if (padapter->intf_free_irq)
+ padapter->intf_free_irq(adapter_to_dvobj(padapter));
+#endif
+
+#ifdef CONFIG_RUNTIME_PORT_SWITCH
+ if (rtw_port_switch_chk(padapter)) {
+ RTW_INFO(" ### PORT SWITCH ###\n");
+ rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL);
+ }
+#endif
+
+ poidparam.subcode = WOWLAN_ENABLE;
+ rtw_hal_set_hwreg(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam);
+ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) {
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)
+ && check_fwstate(pmlmepriv, _FW_LINKED)) {
+ RTW_INFO("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n", __func__,
+ pmlmepriv->cur_network.network.Ssid.Ssid,
+ MAC_ARG(pmlmepriv->cur_network.network.MacAddress),
+ pmlmepriv->cur_network.network.Ssid.SsidLength,
+ pmlmepriv->assoc_ssid.SsidLength);
+
+ rtw_set_to_roam(padapter, 0);
+ }
+ }
+
+ RTW_INFO("%s: wowmode suspending\n", __func__);
+
+ if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+ RTW_INFO("%s: fw_under_survey\n", __func__);
+ rtw_indicate_scan_done(padapter, 1);
+ clr_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+ }
+
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ ch = rtw_mi_get_union_chan(padapter);
+ bw = rtw_mi_get_union_bw(padapter);
+ offset = rtw_mi_get_union_offset(padapter);
+ RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n",
+ FUNC_ADPT_ARG(padapter), ch, bw, offset);
+ set_channel_bwmode(padapter, ch, offset, bw);
+ }
+
+#ifdef CONFIG_CONCURRENT_MODE
+ rtw_mi_buddy_suspend_free_assoc_resource(padapter);
+#endif
+
+ if (pwrpriv->wowlan_pno_enable) {
+ RTW_INFO("%s: pno: %d\n", __func__,
+ pwrpriv->wowlan_pno_enable);
+#ifdef CONFIG_FWLPS_IN_IPS
+ rtw_set_fw_in_ips_mode(padapter, true);
+#endif
+ }
+#ifdef CONFIG_LPS
+ else
+ rtw_set_ps_mode(padapter, PS_MODE_MAX, 0, 0, "WOWLAN");
+#endif /* #ifdef CONFIG_LPS */
+
+ } else
+ RTW_INFO("%s: ### ERROR ### wowlan_mode=%d\n", __func__, pwrpriv->wowlan_mode);
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+ return ret;
+}
+#endif /* #ifdef CONFIG_WOWLAN */
+
+#ifdef CONFIG_AP_WOWLAN
+int rtw_suspend_ap_wow(_adapter *padapter)
+{
+ u8 ch, bw, offset;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct dvobj_priv *psdpriv = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct wowlan_ioctl_param poidparam;
+ int i;
+ _adapter *iface = NULL;
+ u8 ps_mode;
+ int ret = _SUCCESS;
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+
+ pwrpriv->wowlan_ap_mode = true;
+
+ RTW_INFO("wowlan_ap_mode: %d\n", pwrpriv->wowlan_ap_mode);
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SuspendNotify(padapter, BTCOEX_SUSPEND_STATE_SUSPEND_KEEP_ANT);
+#endif
+
+ rtw_mi_netif_stop_queue(padapter, false);
+
+ /* 0. Power off LED */
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+ /* 1. stop thread */
+ rtw_set_drv_stopped(padapter); /*for stop thread*/
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if ((iface) && (iface->bup == true))
+ rtw_stop_drv_threads(iface);
+ }
+ rtw_clr_drv_stopped(padapter); /*for 32k command*/
+
+ /* 2.2 free irq */
+ if (padapter->intf_free_irq)
+ padapter->intf_free_irq(adapter_to_dvobj(padapter));
+
+#ifdef CONFIG_RUNTIME_PORT_SWITCH
+ if (rtw_port_switch_chk(padapter)) {
+ RTW_INFO(" ### PORT SWITCH ###\n");
+ rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL);
+ }
+#endif
+
+ poidparam.subcode = WOWLAN_AP_ENABLE;
+ rtw_hal_set_hwreg(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam);
+
+ RTW_INFO("%s: wowmode suspending\n", __func__);
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ ch = rtw_mi_get_union_chan(padapter);
+ bw = rtw_mi_get_union_bw(padapter);
+ offset = rtw_mi_get_union_offset(padapter);
+ RTW_INFO("back to linked/linking union - ch:%u, bw:%u, offset:%u\n", ch, bw, offset);
+ set_channel_bwmode(padapter, ch, offset, bw);
+ }
+ /*FOR ONE AP - TODO :Multi-AP*/
+ {
+ int i;
+ _adapter *iface;
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if ((iface) && rtw_is_adapter_up(iface)) {
+ if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE | _FW_LINKED))
+ rtw_mi_buddy_suspend_free_assoc_resource(iface);
+ }
+ }
+
+ }
+
+#ifdef CONFIG_LPS
+ rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, 0, "AP-WOWLAN");
+#endif
+
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+ return ret;
+}
+#endif /* #ifdef CONFIG_AP_WOWLAN */
+
+
+static int rtw_suspend_normal(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ int ret = _SUCCESS;
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SuspendNotify(padapter, BTCOEX_SUSPEND_STATE_SUSPEND);
+#endif
+
+ rtw_mi_netif_stop_queue(padapter, true);
+
+ rtw_mi_suspend_free_assoc_resource(padapter);
+
+ rtw_led_control(padapter, LED_CTL_POWER_OFF);
+
+ if ((rtw_hal_check_ips_status(padapter) == true)
+ || (adapter_to_pwrctl(padapter)->rf_pwrstate == rf_off))
+ RTW_INFO("%s: ### ERROR #### driver in IPS ####ERROR###!!!\n", __func__);
+
+
+#ifdef CONFIG_CONCURRENT_MODE
+ rtw_mi_buddy_dev_unload(padapter);
+#endif
+ rtw_dev_unload(padapter);
+
+ /* sdio_deinit(adapter_to_dvobj(padapter)); */
+ if (padapter->intf_deinit)
+ padapter->intf_deinit(adapter_to_dvobj(padapter));
+
+#if !(CONFIG_RTW_SDIO_KEEP_IRQ)
+ if(padapter->intf_free_irq)
+ padapter->intf_free_irq(adapter_to_dvobj(padapter));
+#endif
+
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+ return ret;
+}
+
+int rtw_suspend_common(_adapter *padapter)
+{
+ struct dvobj_priv *psdpriv = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ int ret = 0;
+ u32 start_time = jiffies;
+
+ RTW_INFO(" suspend start\n");
+ RTW_INFO("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+ pdbgpriv->dbg_suspend_cnt++;
+
+ pwrpriv->bInSuspend = true;
+
+ while (pwrpriv->bips_processing == true)
+ rtw_msleep_os(1);
+
+#ifdef CONFIG_IOL_READ_EFUSE_MAP
+ if (!padapter->bup) {
+ u8 bMacPwrCtrlOn = false;
+ rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn);
+ if (bMacPwrCtrlOn)
+ rtw_hal_power_off(padapter);
+ }
+#endif
+
+ if ((!padapter->bup) || RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("%s bup=%d bDriverStopped=%s bSurpriseRemoved = %s\n", __func__
+ , padapter->bup
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+ pdbgpriv->dbg_suspend_error_cnt++;
+ goto exit;
+ }
+ rtw_ps_deny(padapter, PS_DENY_SUSPEND);
+
+ rtw_mi_cancel_all_timer(padapter);
+ LeaveAllPowerSaveModeDirect(padapter);
+ rtw_stop_cmd_thread(padapter);
+
+ rtw_ps_deny_cancel(padapter, PS_DENY_SUSPEND);
+
+ if (rtw_mi_check_status(padapter, MI_AP_MODE) == false) {
+#ifdef CONFIG_WOWLAN
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
+ pwrpriv->wowlan_mode = true;
+ else if (pwrpriv->wowlan_pno_enable == true)
+ pwrpriv->wowlan_mode |= pwrpriv->wowlan_pno_enable;
+
+#ifdef CONFIG_P2P_WOWLAN
+ if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE) || P2P_ROLE_DISABLE != padapter->wdinfo.role)
+ pwrpriv->wowlan_p2p_mode = true;
+ if (pwrpriv->wowlan_p2p_mode)
+ pwrpriv->wowlan_mode |= pwrpriv->wowlan_p2p_mode;
+#endif /* CONFIG_P2P_WOWLAN */
+
+ if (pwrpriv->wowlan_mode == true)
+ rtw_suspend_wow(padapter);
+ else
+#endif /* CONFIG_WOWLAN */
+ rtw_suspend_normal(padapter);
+ } else if (rtw_mi_check_status(padapter, MI_AP_MODE)) {
+#ifdef CONFIG_AP_WOWLAN
+ rtw_suspend_ap_wow(padapter);
+#else
+ rtw_suspend_normal(padapter);
+#endif /*CONFIG_AP_WOWLAN*/
+ }
+
+
+ RTW_INFO("rtw suspend success in %d ms\n",
+ rtw_get_passing_time_ms(start_time));
+
+exit:
+ RTW_INFO("<=== %s return %d.............. in %dms\n", __func__
+ , ret, rtw_get_passing_time_ms(start_time));
+
+ return ret;
+}
+
+#ifdef CONFIG_WOWLAN
+int rtw_resume_process_wow(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct net_device *pnetdev = padapter->pnetdev;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct dvobj_priv *psdpriv = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+ struct wowlan_ioctl_param poidparam;
+ struct sta_info *psta = NULL;
+ int ret = _SUCCESS;
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+
+ if (padapter) {
+ pnetdev = padapter->pnetdev;
+ pwrpriv = adapter_to_pwrctl(padapter);
+ } else {
+ pdbgpriv->dbg_resume_error_cnt++;
+ ret = -1;
+ goto exit;
+ }
+
+ if (RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("%s pdapter %p bDriverStopped %s bSurpriseRemoved %s\n"
+ , __func__, padapter
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+ goto exit;
+ }
+
+ pwrpriv->wowlan_in_resume = true;
+#ifdef CONFIG_PNO_SUPPORT
+#ifdef CONFIG_FWLPS_IN_IPS
+ if (pwrpriv->wowlan_pno_enable)
+ rtw_set_fw_in_ips_mode(padapter, false);
+#endif /* CONFIG_FWLPS_IN_IPS */
+#endif/* CONFIG_PNO_SUPPORT */
+
+ if (pwrpriv->wowlan_mode == true) {
+#ifdef CONFIG_LPS
+ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "WOWLAN");
+#endif /* CONFIG_LPS */
+
+ pwrpriv->bFwCurrentInPSMode = false;
+
+#if !(CONFIG_RTW_SDIO_KEEP_IRQ)
+ /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { */
+ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) {
+ ret = -1;
+ goto exit;
+ }
+#endif
+
+ /* Disable WOW, set H2C command */
+ poidparam.subcode = WOWLAN_DISABLE;
+ rtw_hal_set_hwreg(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ rtw_mi_buddy_reset_drv_sw(padapter);
+#endif
+
+ psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv));
+ if (psta)
+ set_sta_rate(padapter, psta);
+
+
+ rtw_clr_drv_stopped(padapter);
+ RTW_INFO("%s: wowmode resuming, DriverStopped:%s\n", __func__, rtw_is_drv_stopped(padapter) ? "True" : "False");
+
+ rtw_mi_start_drv_threads(padapter);
+
+ rtw_mi_intf_start(padapter);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ rtw_mi_buddy_netif_carrier_on(padapter);
+#endif
+
+ /* start netif queue */
+ if (pnetdev)
+ rtw_netif_wake_queue(pnetdev);
+ } else
+
+ RTW_INFO("%s: ### ERROR ### wowlan_mode=%d\n", __func__, pwrpriv->wowlan_mode);
+
+ if (padapter->pid[1] != 0) {
+ RTW_INFO("pid[1]:%d\n", padapter->pid[1]);
+ rtw_signal_process(padapter->pid[1], SIGUSR2);
+ }
+
+ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) {
+ if (pwrpriv->wowlan_wake_reason == FW_DECISION_DISCONNECT ||
+ pwrpriv->wowlan_wake_reason == RX_DISASSOC||
+ pwrpriv->wowlan_wake_reason == RX_DEAUTH) {
+
+ RTW_INFO("%s: disconnect reason: %02x\n", __func__,
+ pwrpriv->wowlan_wake_reason);
+ rtw_indicate_disconnect(padapter, 0, false);
+
+ rtw_sta_media_status_rpt(padapter,
+ rtw_get_stainfo(&padapter->stapriv,
+ get_bssid(&padapter->mlmepriv)), 0);
+
+ rtw_free_assoc_resources(padapter, 1);
+ pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+ } else {
+ RTW_INFO("%s: do roaming\n", __func__);
+ rtw_roaming(padapter, NULL);
+ }
+ }
+
+ if (pwrpriv->wowlan_wake_reason == FW_DECISION_DISCONNECT)
+ rtw_lock_ext_suspend_timeout(2000);
+
+ if (pwrpriv->wowlan_wake_reason == RX_GTK ||
+ pwrpriv->wowlan_wake_reason == RX_DISASSOC||
+ pwrpriv->wowlan_wake_reason == RX_DEAUTH)
+ rtw_lock_ext_suspend_timeout(8000);
+
+ if (pwrpriv->wowlan_wake_reason == RX_PNO) {
+#ifdef CONFIG_IOCTL_CFG80211
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+ u8 locally_generated = 1;
+
+ cfg80211_disconnected(padapter->pnetdev, 0, NULL, 0, locally_generated, GFP_ATOMIC);
+#else
+ cfg80211_disconnected(padapter->pnetdev, 0, NULL, 0, GFP_ATOMIC);
+#endif
+#endif /* CONFIG_IOCTL_CFG80211 */
+ rtw_lock_ext_suspend_timeout(10000);
+ }
+
+ if (pwrpriv->wowlan_mode == true) {
+ pwrpriv->bips_processing = false;
+ _set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 2000);
+#ifndef CONFIG_IPS_CHECK_IN_WD
+ rtw_set_pwr_state_check_timer(pwrpriv);
+#endif
+ } else
+ RTW_INFO("do not reset timer\n");
+
+ pwrpriv->wowlan_mode = false;
+
+ /* Power On LED */
+#ifdef CONFIG_SW_LED
+
+ if (pwrpriv->wowlan_wake_reason == RX_DISASSOC||
+ pwrpriv->wowlan_wake_reason == RX_DEAUTH||
+ pwrpriv->wowlan_wake_reason == FW_DECISION_DISCONNECT)
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+ else
+ rtw_led_control(padapter, LED_CTL_LINK);
+#endif
+ /* clean driver side wake up reason. */
+ pwrpriv->wowlan_last_wake_reason = pwrpriv->wowlan_wake_reason;
+ pwrpriv->wowlan_wake_reason = 0;
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SuspendNotify(padapter, BTCOEX_SUSPEND_STATE_RESUME);
+#endif /* CONFIG_BT_COEXIST */
+
+exit:
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+ return ret;
+}
+#endif /* #ifdef CONFIG_WOWLAN */
+
+#ifdef CONFIG_AP_WOWLAN
+int rtw_resume_process_ap_wow(_adapter *padapter)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct net_device *pnetdev = padapter->pnetdev;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct dvobj_priv *psdpriv = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
+ struct wowlan_ioctl_param poidparam;
+ struct sta_info *psta = NULL;
+ int ret = _SUCCESS;
+ u8 ch, bw, offset;
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+
+ if (padapter) {
+ pnetdev = padapter->pnetdev;
+ pwrpriv = adapter_to_pwrctl(padapter);
+ } else {
+ pdbgpriv->dbg_resume_error_cnt++;
+ ret = -1;
+ goto exit;
+ }
+
+
+#ifdef CONFIG_LPS
+ rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "AP-WOWLAN");
+#endif /* CONFIG_LPS */
+
+ pwrpriv->bFwCurrentInPSMode = false;
+
+ rtw_hal_disable_interrupt(padapter);
+
+ rtw_hal_clear_interrupt(padapter);
+
+ /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) { */
+ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) {
+ ret = -1;
+ goto exit;
+ }
+
+ /* Disable WOW, set H2C command */
+ poidparam.subcode = WOWLAN_AP_DISABLE;
+ rtw_hal_set_hwreg(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam);
+ pwrpriv->wowlan_ap_mode = false;
+
+ rtw_clr_drv_stopped(padapter);
+ RTW_INFO("%s: wowmode resuming, DriverStopped:%s\n", __func__, rtw_is_drv_stopped(padapter) ? "True" : "False");
+
+ rtw_mi_start_drv_threads(padapter);
+
+ if (rtw_mi_check_status(padapter, MI_LINKED)) {
+ ch = rtw_mi_get_union_chan(padapter);
+ bw = rtw_mi_get_union_bw(padapter);
+ offset = rtw_mi_get_union_offset(padapter);
+ RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n", FUNC_ADPT_ARG(padapter), ch, bw, offset);
+ set_channel_bwmode(padapter, ch, offset, bw);
+ }
+
+ /*FOR ONE AP - TODO :Multi-AP*/
+ {
+ int i;
+ _adapter *iface;
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if ((iface) && rtw_is_adapter_up(iface)) {
+ if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE | _FW_LINKED))
+ rtw_mi_buddy_reset_drv_sw(iface);
+ }
+ }
+
+ }
+ rtw_mi_intf_start(padapter);
+ rtw_mi_netif_wake_queue(padapter);
+
+ if (padapter->pid[1] != 0) {
+ RTW_INFO("pid[1]:%d\n", padapter->pid[1]);
+ rtw_signal_process(padapter->pid[1], SIGUSR2);
+ }
+
+#ifdef CONFIG_RESUME_IN_WORKQUEUE
+ /* rtw_unlock_suspend(); */
+#endif /* CONFIG_RESUME_IN_WORKQUEUE */
+
+ if (pwrpriv->wowlan_wake_reason == AP_OFFLOAD_WAKEUP)
+ rtw_lock_ext_suspend_timeout(8000);
+
+ pwrpriv->bips_processing = false;
+ _set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 2000);
+#ifndef CONFIG_IPS_CHECK_IN_WD
+ rtw_set_pwr_state_check_timer(pwrpriv);
+#endif
+ /* clean driver side wake up reason. */
+ pwrpriv->wowlan_wake_reason = 0;
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SuspendNotify(padapter, BTCOEX_SUSPEND_STATE_RESUME);
+#endif /* CONFIG_BT_COEXIST */
+
+ /* Power On LED */
+#ifdef CONFIG_SW_LED
+
+ rtw_led_control(padapter, LED_CTL_LINK);
+#endif
+exit:
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+ return ret;
+}
+#endif /* #ifdef CONFIG_APWOWLAN */
+
+static void rtw_mi_resume_process_normal(_adapter *padapter)
+{
+ int i;
+ _adapter *iface;
+ struct mlme_priv *pmlmepriv;
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+
+ for (i = 0; i < dvobj->iface_nums; i++) {
+ iface = dvobj->padapters[i];
+ if ((iface) && rtw_is_adapter_up(iface)) {
+ pmlmepriv = &iface->mlmepriv;
+
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+ RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv));
+
+ if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME))
+ rtw_roaming(padapter, NULL);
+
+ } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv));
+ rtw_ap_restore_network(padapter);
+ } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
+ RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv));
+ else
+ RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv));
+ }
+ }
+}
+
+static int rtw_resume_process_normal(_adapter *padapter)
+{
+ struct net_device *pnetdev;
+ struct pwrctrl_priv *pwrpriv;
+ struct dvobj_priv *psdpriv;
+ struct debug_priv *pdbgpriv;
+ int ret = _SUCCESS;
+
+ if (!padapter) {
+ ret = -1;
+ goto exit;
+ }
+
+ pnetdev = padapter->pnetdev;
+ pwrpriv = adapter_to_pwrctl(padapter);
+ psdpriv = padapter->dvobj;
+ pdbgpriv = &psdpriv->drv_dbg;
+
+ RTW_INFO("==> "FUNC_ADPT_FMT" entry....\n", FUNC_ADPT_ARG(padapter));
+ /* interface init */
+ /* if (sdio_init(adapter_to_dvobj(padapter)) != _SUCCESS) */
+ if ((padapter->intf_init) && (padapter->intf_init(adapter_to_dvobj(padapter)) != _SUCCESS)) {
+ ret = -1;
+ goto exit;
+ }
+ rtw_hal_disable_interrupt(padapter);
+#if !(CONFIG_RTW_SDIO_KEEP_IRQ)
+ /* if (sdio_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS) */
+ if ((padapter->intf_alloc_irq) && (padapter->intf_alloc_irq(adapter_to_dvobj(padapter)) != _SUCCESS)) {
+ ret = -1;
+ goto exit;
+ }
+#endif
+
+ rtw_mi_reset_drv_sw(padapter);
+
+ pwrpriv->bkeepfwalive = false;
+
+ RTW_INFO("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive);
+ if (pm_netdev_open(pnetdev, true) != 0) {
+ ret = -1;
+ pdbgpriv->dbg_resume_error_cnt++;
+ goto exit;
+ }
+
+ rtw_mi_netif_carrier_on(padapter);
+
+ if (padapter->pid[1] != 0) {
+ RTW_INFO("pid[1]:%d\n", padapter->pid[1]);
+ rtw_signal_process(padapter->pid[1], SIGUSR2);
+ }
+
+#ifdef CONFIG_BT_COEXIST
+ rtw_btcoex_SuspendNotify(padapter, BTCOEX_SUSPEND_STATE_RESUME);
+#endif /* CONFIG_BT_COEXIST */
+
+ rtw_mi_resume_process_normal(padapter);
+
+#ifdef CONFIG_RESUME_IN_WORKQUEUE
+ /* rtw_unlock_suspend(); */
+#endif /* CONFIG_RESUME_IN_WORKQUEUE */
+ RTW_INFO("<== "FUNC_ADPT_FMT" exit....\n", FUNC_ADPT_ARG(padapter));
+
+exit:
+ return ret;
+}
+
+int rtw_resume_common(_adapter *padapter)
+{
+ int ret = 0;
+ u32 start_time = jiffies;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+
+ if (pwrpriv->bInSuspend == false)
+ return 0;
+
+ RTW_INFO("resume start\n");
+ RTW_INFO("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+ if (rtw_mi_check_status(padapter, WIFI_AP_STATE) == false) {
+#ifdef CONFIG_WOWLAN
+ if (pwrpriv->wowlan_mode == true)
+ rtw_resume_process_wow(padapter);
+ else
+#endif
+ rtw_resume_process_normal(padapter);
+
+ } else if (rtw_mi_check_status(padapter, WIFI_AP_STATE)) {
+#ifdef CONFIG_AP_WOWLAN
+ rtw_resume_process_ap_wow(padapter);
+#else
+ rtw_resume_process_normal(padapter);
+#endif /* CONFIG_AP_WOWLAN */
+ }
+
+ if (pwrpriv) {
+ pwrpriv->bInSuspend = false;
+#ifdef CONFIG_WOWLAN
+ pwrpriv->wowlan_in_resume = false;
+#endif
+ }
+ RTW_INFO("%s:%d in %d ms\n", __func__ , ret,
+ rtw_get_passing_time_ms(start_time));
+
+
+ return ret;
+}
+
+#ifdef CONFIG_GPIO_API
+u8 rtw_get_gpio(struct net_device *netdev, u8 gpio_num)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev);
+ return rtw_hal_get_gpio(adapter, gpio_num);
+}
+EXPORT_SYMBOL(rtw_get_gpio);
+
+int rtw_set_gpio_output_value(struct net_device *netdev, u8 gpio_num, bool isHigh)
+{
+ u8 direction = 0;
+ u8 res = -1;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev);
+ return rtw_hal_set_gpio_output_value(adapter, gpio_num, isHigh);
+}
+EXPORT_SYMBOL(rtw_set_gpio_output_value);
+
+int rtw_config_gpio(struct net_device *netdev, u8 gpio_num, bool isOutput)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev);
+ return rtw_hal_config_gpio(adapter, gpio_num, isOutput);
+}
+EXPORT_SYMBOL(rtw_config_gpio);
+int rtw_register_gpio_interrupt(struct net_device *netdev, int gpio_num, void(*callback)(u8 level))
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev);
+ return rtw_hal_register_gpio_interrupt(adapter, gpio_num, callback);
+}
+EXPORT_SYMBOL(rtw_register_gpio_interrupt);
+
+int rtw_disable_gpio_interrupt(struct net_device *netdev, int gpio_num)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(netdev);
+ return rtw_hal_disable_gpio_interrupt(adapter, gpio_num);
+}
+EXPORT_SYMBOL(rtw_disable_gpio_interrupt);
+
+#endif /* #ifdef CONFIG_GPIO_API */
+
+#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE
+
+int rtw_vendor_ie_get_api(struct net_device *dev, int ie_num, char *extra, __u16 *length)
+{
+ *length = rtw_vendor_ie_get_data(dev, ie_num, extra);
+ return 0;
+}
+EXPORT_SYMBOL(rtw_vendor_ie_get_api);
+
+int rtw_vendor_ie_set_api(struct net_device *dev, char *extra)
+{
+ return rtw_vendor_ie_set(dev, NULL, NULL, extra);
+}
+EXPORT_SYMBOL(rtw_vendor_ie_set_api);
+
+#endif
diff --git a/drivers/staging/rtl8188eu/os_dep/osdep_service.c b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
new file mode 100644
index 000000000000..9132038bd135
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/osdep_service.c
@@ -0,0 +1,1731 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+
+
+#define _OSDEP_SERVICE_C_
+
+#include <drv_types.h>
+
+#define RT_TAG '1178'
+
+/*
+* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE
+* @return: one of RTW_STATUS_CODE
+*/
+inline int RTW_STATUS_CODE(int error_code)
+{
+ if (error_code >= 0)
+ return _SUCCESS;
+
+ switch (error_code) {
+ /* case -ETIMEDOUT: */
+ /* return RTW_STATUS_TIMEDOUT; */
+ default:
+ return _FAIL;
+ }
+}
+
+u32 rtw_atoi(u8 *s)
+{
+ int num = 0, flag = 0;
+ int i;
+ for (i = 0; i <= strlen(s); i++) {
+ if (s[i] >= '0' && s[i] <= '9')
+ num = num * 10 + s[i] - '0';
+ else if (s[0] == '-' && i == 0)
+ flag = 1;
+ else
+ break;
+ }
+
+ if (flag == 1)
+ num = num * -1;
+
+ return num;
+
+}
+
+inline u8 *_rtw_zvmalloc(u32 sz)
+{
+ u8 *pbuf;
+ pbuf = vmalloc(sz);
+ if (pbuf != NULL)
+ memset(pbuf, 0, sz);
+ return pbuf;
+}
+
+inline void _rtw_vmfree(u8 *pbuf, u32 sz)
+{
+ vfree(pbuf);
+}
+
+u8 *_rtw_malloc(u32 sz)
+{
+ u8 *pbuf = NULL;
+
+#ifdef RTK_DMP_PLATFORM
+ if (sz > 0x4000)
+ pbuf = (u8 *)dvr_malloc(sz);
+ else
+#endif
+ pbuf = kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+
+ return pbuf;
+}
+
+u8 *_rtw_zmalloc(u32 sz)
+{
+ u8 *pbuf = _rtw_malloc(sz);
+
+ if (pbuf != NULL)
+ memset(pbuf, 0, sz);
+ return pbuf;
+}
+
+void _rtw_mfree(u8 *pbuf, u32 sz)
+{
+#ifdef RTK_DMP_PLATFORM
+ if (sz > 0x4000)
+ dvr_free(pbuf);
+ else
+#endif
+ kfree(pbuf);
+}
+
+inline struct sk_buff *_rtw_skb_alloc(u32 sz)
+{
+ return __dev_alloc_skb(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+}
+
+inline void _rtw_skb_free(struct sk_buff *skb)
+{
+ dev_kfree_skb_any(skb);
+}
+
+inline struct sk_buff *_rtw_skb_copy(const struct sk_buff *skb)
+{
+ return skb_copy(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+}
+
+inline struct sk_buff *_rtw_skb_clone(struct sk_buff *skb)
+{
+ return skb_clone(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+}
+inline struct sk_buff *_rtw_pskb_copy(struct sk_buff *skb)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
+ return pskb_copy(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+#else
+ return skb_clone(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+#endif
+}
+
+inline int _rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb)
+{
+ skb->dev = ndev;
+ return netif_rx(skb);
+}
+
+#ifdef CONFIG_RTW_NAPI
+inline int _rtw_netif_receive_skb(_nic_hdl ndev, struct sk_buff *skb)
+{
+ skb->dev = ndev;
+ return netif_receive_skb(skb);
+}
+
+#ifdef CONFIG_RTW_GRO
+inline gro_result_t _rtw_napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+{
+ return napi_gro_receive(napi, skb);
+}
+#endif /* CONFIG_RTW_GRO */
+#endif /* CONFIG_RTW_NAPI */
+
+void _rtw_skb_queue_purge(struct sk_buff_head *list)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(list)) != NULL)
+ _rtw_skb_free(skb);
+}
+
+inline void *_rtw_usb_buffer_alloc(struct usb_device *dev, size_t size, dma_addr_t *dma)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ return usb_alloc_coherent(dev, size, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), dma);
+#else
+ return usb_buffer_alloc(dev, size, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), dma);
+#endif
+}
+
+inline void _rtw_usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ usb_free_coherent(dev, size, addr, dma);
+#else
+ usb_buffer_free(dev, size, addr, dma);
+#endif
+}
+
+#if defined(DBG_MEM_ALLOC)
+
+struct rtw_mem_stat {
+ ATOMIC_T alloc; /* the memory bytes we allocate currently */
+ ATOMIC_T peak; /* the peak memory bytes we allocate */
+ ATOMIC_T alloc_cnt; /* the alloc count for alloc currently */
+ ATOMIC_T alloc_err_cnt; /* the error times we fail to allocate memory */
+};
+
+struct rtw_mem_stat rtw_mem_type_stat[mstat_tf_idx(MSTAT_TYPE_MAX)];
+#ifdef RTW_MEM_FUNC_STAT
+struct rtw_mem_stat rtw_mem_func_stat[mstat_ff_idx(MSTAT_FUNC_MAX)];
+#endif
+
+char *MSTAT_TYPE_str[] = {
+ "VIR",
+ "PHY",
+ "SKB",
+ "USB",
+};
+
+#ifdef RTW_MEM_FUNC_STAT
+char *MSTAT_FUNC_str[] = {
+ "UNSP",
+ "IO",
+ "TXIO",
+ "RXIO",
+ "TX",
+ "RX",
+};
+#endif
+
+void rtw_mstat_dump(void *sel)
+{
+ int i;
+ int value_t[4][mstat_tf_idx(MSTAT_TYPE_MAX)];
+#ifdef RTW_MEM_FUNC_STAT
+ int value_f[4][mstat_ff_idx(MSTAT_FUNC_MAX)];
+#endif
+
+ int vir_alloc, vir_peak, vir_alloc_err, phy_alloc, phy_peak, phy_alloc_err;
+ int tx_alloc, tx_peak, tx_alloc_err, rx_alloc, rx_peak, rx_alloc_err;
+
+ for (i = 0; i < mstat_tf_idx(MSTAT_TYPE_MAX); i++) {
+ value_t[0][i] = ATOMIC_READ(&(rtw_mem_type_stat[i].alloc));
+ value_t[1][i] = ATOMIC_READ(&(rtw_mem_type_stat[i].peak));
+ value_t[2][i] = ATOMIC_READ(&(rtw_mem_type_stat[i].alloc_cnt));
+ value_t[3][i] = ATOMIC_READ(&(rtw_mem_type_stat[i].alloc_err_cnt));
+ }
+
+#ifdef RTW_MEM_FUNC_STAT
+ for (i = 0; i < mstat_ff_idx(MSTAT_FUNC_MAX); i++) {
+ value_f[0][i] = ATOMIC_READ(&(rtw_mem_func_stat[i].alloc));
+ value_f[1][i] = ATOMIC_READ(&(rtw_mem_func_stat[i].peak));
+ value_f[2][i] = ATOMIC_READ(&(rtw_mem_func_stat[i].alloc_cnt));
+ value_f[3][i] = ATOMIC_READ(&(rtw_mem_func_stat[i].alloc_err_cnt));
+ }
+#endif
+
+ RTW_PRINT_SEL(sel, "===================== MSTAT =====================\n");
+ RTW_PRINT_SEL(sel, "%4s %10s %10s %10s %10s\n", "TAG", "alloc", "peak", "aloc_cnt", "err_cnt");
+ RTW_PRINT_SEL(sel, "-------------------------------------------------\n");
+ for (i = 0; i < mstat_tf_idx(MSTAT_TYPE_MAX); i++)
+ RTW_PRINT_SEL(sel, "%4s %10d %10d %10d %10d\n", MSTAT_TYPE_str[i], value_t[0][i], value_t[1][i], value_t[2][i], value_t[3][i]);
+#ifdef RTW_MEM_FUNC_STAT
+ RTW_PRINT_SEL(sel, "-------------------------------------------------\n");
+ for (i = 0; i < mstat_ff_idx(MSTAT_FUNC_MAX); i++)
+ RTW_PRINT_SEL(sel, "%4s %10d %10d %10d %10d\n", MSTAT_FUNC_str[i], value_f[0][i], value_f[1][i], value_f[2][i], value_f[3][i]);
+#endif
+}
+
+void rtw_mstat_update(const enum mstat_f flags, const MSTAT_STATUS status, u32 sz)
+{
+ static u32 update_time = 0;
+ int peak, alloc;
+ int i;
+
+ /* initialization */
+ if (!update_time) {
+ for (i = 0; i < mstat_tf_idx(MSTAT_TYPE_MAX); i++) {
+ ATOMIC_SET(&(rtw_mem_type_stat[i].alloc), 0);
+ ATOMIC_SET(&(rtw_mem_type_stat[i].peak), 0);
+ ATOMIC_SET(&(rtw_mem_type_stat[i].alloc_cnt), 0);
+ ATOMIC_SET(&(rtw_mem_type_stat[i].alloc_err_cnt), 0);
+ }
+ #ifdef RTW_MEM_FUNC_STAT
+ for (i = 0; i < mstat_ff_idx(MSTAT_FUNC_MAX); i++) {
+ ATOMIC_SET(&(rtw_mem_func_stat[i].alloc), 0);
+ ATOMIC_SET(&(rtw_mem_func_stat[i].peak), 0);
+ ATOMIC_SET(&(rtw_mem_func_stat[i].alloc_cnt), 0);
+ ATOMIC_SET(&(rtw_mem_func_stat[i].alloc_err_cnt), 0);
+ }
+ #endif
+ }
+
+ switch (status) {
+ case MSTAT_ALLOC_SUCCESS:
+ ATOMIC_INC(&(rtw_mem_type_stat[mstat_tf_idx(flags)].alloc_cnt));
+ alloc = ATOMIC_ADD_RETURN(&(rtw_mem_type_stat[mstat_tf_idx(flags)].alloc), sz);
+ peak = ATOMIC_READ(&(rtw_mem_type_stat[mstat_tf_idx(flags)].peak));
+ if (peak < alloc)
+ ATOMIC_SET(&(rtw_mem_type_stat[mstat_tf_idx(flags)].peak), alloc);
+
+ #ifdef RTW_MEM_FUNC_STAT
+ ATOMIC_INC(&(rtw_mem_func_stat[mstat_ff_idx(flags)].alloc_cnt));
+ alloc = ATOMIC_ADD_RETURN(&(rtw_mem_func_stat[mstat_ff_idx(flags)].alloc), sz);
+ peak = ATOMIC_READ(&(rtw_mem_func_stat[mstat_ff_idx(flags)].peak));
+ if (peak < alloc)
+ ATOMIC_SET(&(rtw_mem_func_stat[mstat_ff_idx(flags)].peak), alloc);
+ #endif
+ break;
+
+ case MSTAT_ALLOC_FAIL:
+ ATOMIC_INC(&(rtw_mem_type_stat[mstat_tf_idx(flags)].alloc_err_cnt));
+ #ifdef RTW_MEM_FUNC_STAT
+ ATOMIC_INC(&(rtw_mem_func_stat[mstat_ff_idx(flags)].alloc_err_cnt));
+ #endif
+ break;
+
+ case MSTAT_FREE:
+ ATOMIC_DEC(&(rtw_mem_type_stat[mstat_tf_idx(flags)].alloc_cnt));
+ ATOMIC_SUB(&(rtw_mem_type_stat[mstat_tf_idx(flags)].alloc), sz);
+ #ifdef RTW_MEM_FUNC_STAT
+ ATOMIC_DEC(&(rtw_mem_func_stat[mstat_ff_idx(flags)].alloc_cnt));
+ ATOMIC_SUB(&(rtw_mem_func_stat[mstat_ff_idx(flags)].alloc), sz);
+ #endif
+ break;
+ };
+
+ /* if (rtw_get_passing_time_ms(update_time) > 5000) { */
+ /* rtw_mstat_dump(RTW_DBGDUMP); */
+ update_time = jiffies;
+ /* } */
+}
+
+#ifndef SIZE_MAX
+ #define SIZE_MAX (~(size_t)0)
+#endif
+
+struct mstat_sniff_rule {
+ enum mstat_f flags;
+ size_t lb;
+ size_t hb;
+};
+
+struct mstat_sniff_rule mstat_sniff_rules[] = {
+ {MSTAT_TYPE_PHY, 4097, SIZE_MAX},
+};
+
+int mstat_sniff_rule_num = sizeof(mstat_sniff_rules) / sizeof(struct mstat_sniff_rule);
+
+bool match_mstat_sniff_rules(const enum mstat_f flags, const size_t size)
+{
+ int i;
+ for (i = 0; i < mstat_sniff_rule_num; i++) {
+ if (mstat_sniff_rules[i].flags == flags
+ && mstat_sniff_rules[i].lb <= size
+ && mstat_sniff_rules[i].hb >= size)
+ return true;
+ }
+
+ return false;
+}
+
+inline u8 *dbg_rtw_vmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line)
+{
+ u8 *p;
+
+ if (match_mstat_sniff_rules(flags, sz))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __func__, (sz));
+
+ p = vmalloc((sz));
+
+ rtw_mstat_update(
+ flags
+ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , sz
+ );
+
+ return p;
+}
+
+inline u8 *dbg_rtw_zvmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line)
+{
+ u8 *p;
+
+ if (match_mstat_sniff_rules(flags, sz))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __func__, (sz));
+
+ p = _rtw_zvmalloc((sz));
+
+ rtw_mstat_update(
+ flags
+ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , sz
+ );
+
+ return p;
+}
+
+inline void dbg_rtw_vmfree(u8 *pbuf, u32 sz, const enum mstat_f flags, const char *func, const int line)
+{
+
+ if (match_mstat_sniff_rules(flags, sz))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __func__, (sz));
+
+ _rtw_vmfree((pbuf), (sz));
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , sz
+ );
+}
+
+inline u8 *dbg_rtw_malloc(u32 sz, const enum mstat_f flags, const char *func, const int line)
+{
+ u8 *p;
+
+ if (match_mstat_sniff_rules(flags, sz))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __func__, (sz));
+
+ p = _rtw_malloc((sz));
+
+ rtw_mstat_update(
+ flags
+ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , sz
+ );
+
+ return p;
+}
+
+inline u8 *dbg_rtw_zmalloc(u32 sz, const enum mstat_f flags, const char *func, const int line)
+{
+ u8 *p;
+
+ if (match_mstat_sniff_rules(flags, sz))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __func__, (sz));
+
+ p = _rtw_zmalloc((sz));
+
+ rtw_mstat_update(
+ flags
+ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , sz
+ );
+
+ return p;
+}
+
+inline void dbg_rtw_mfree(u8 *pbuf, u32 sz, const enum mstat_f flags, const char *func, const int line)
+{
+ if (match_mstat_sniff_rules(flags, sz))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d)\n", func, line, __func__, (sz));
+
+ _rtw_mfree((pbuf), (sz));
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , sz
+ );
+}
+
+inline struct sk_buff *dbg_rtw_skb_alloc(unsigned int size, const enum mstat_f flags, const char *func, int line)
+{
+ struct sk_buff *skb;
+ unsigned int truesize = 0;
+
+ skb = _rtw_skb_alloc(size);
+
+ if (skb)
+ truesize = skb->truesize;
+
+ if (!skb || truesize < size || match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d), skb:%p, truesize=%u\n", func, line, __func__, size, skb, truesize);
+
+ rtw_mstat_update(
+ flags
+ , skb ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , truesize
+ );
+
+ return skb;
+}
+
+inline void dbg_rtw_skb_free(struct sk_buff *skb, const enum mstat_f flags, const char *func, int line)
+{
+ unsigned int truesize = skb->truesize;
+
+ if (match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __func__, truesize);
+
+ _rtw_skb_free(skb);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , truesize
+ );
+}
+
+inline struct sk_buff *dbg_rtw_skb_copy(const struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line)
+{
+ struct sk_buff *skb_cp;
+ unsigned int truesize = skb->truesize;
+ unsigned int cp_truesize = 0;
+
+ skb_cp = _rtw_skb_copy(skb);
+ if (skb_cp)
+ cp_truesize = skb_cp->truesize;
+
+ if (!skb_cp || cp_truesize < truesize || match_mstat_sniff_rules(flags, cp_truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%u), skb_cp:%p, cp_truesize=%u\n", func, line, __func__, truesize, skb_cp, cp_truesize);
+
+ rtw_mstat_update(
+ flags
+ , skb_cp ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , truesize
+ );
+
+ return skb_cp;
+}
+
+inline struct sk_buff *dbg_rtw_skb_clone(struct sk_buff *skb, const enum mstat_f flags, const char *func, const int line)
+{
+ struct sk_buff *skb_cl;
+ unsigned int truesize = skb->truesize;
+ unsigned int cl_truesize = 0;
+
+ skb_cl = _rtw_skb_clone(skb);
+ if (skb_cl)
+ cl_truesize = skb_cl->truesize;
+
+ if (!skb_cl || cl_truesize < truesize || match_mstat_sniff_rules(flags, cl_truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%u), skb_cl:%p, cl_truesize=%u\n", func, line, __func__, truesize, skb_cl, cl_truesize);
+
+ rtw_mstat_update(
+ flags
+ , skb_cl ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , truesize
+ );
+
+ return skb_cl;
+}
+
+inline int dbg_rtw_netif_rx(_nic_hdl ndev, struct sk_buff *skb, const enum mstat_f flags, const char *func, int line)
+{
+ int ret;
+ unsigned int truesize = skb->truesize;
+
+ if (match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __func__, truesize);
+
+ ret = _rtw_netif_rx(ndev, skb);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , truesize
+ );
+
+ return ret;
+}
+
+#ifdef CONFIG_RTW_NAPI
+inline int dbg_rtw_netif_receive_skb(_nic_hdl ndev, struct sk_buff *skb, const enum mstat_f flags, const char *func, int line)
+{
+ int ret;
+ unsigned int truesize = skb->truesize;
+
+ if (match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __func__, truesize);
+
+ ret = _rtw_netif_receive_skb(ndev, skb);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , truesize
+ );
+
+ return ret;
+}
+
+#ifdef CONFIG_RTW_GRO
+inline gro_result_t dbg_rtw_napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb, const enum mstat_f flags, const char *func, int line)
+{
+ int ret;
+ unsigned int truesize = skb->truesize;
+
+ if (match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __func__, truesize);
+
+ ret = _rtw_napi_gro_receive(napi, skb);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , truesize
+ );
+
+ return ret;
+}
+#endif /* CONFIG_RTW_GRO */
+#endif /* CONFIG_RTW_NAPI */
+
+inline void dbg_rtw_skb_queue_purge(struct sk_buff_head *list, enum mstat_f flags, const char *func, int line)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(list)) != NULL)
+ dbg_rtw_skb_free(skb, flags, func, line);
+}
+
+inline void *dbg_rtw_usb_buffer_alloc(struct usb_device *dev, size_t size, dma_addr_t *dma, const enum mstat_f flags, const char *func, int line)
+{
+ void *p;
+
+ if (match_mstat_sniff_rules(flags, size))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%zu)\n", func, line, __func__, size);
+
+ p = _rtw_usb_buffer_alloc(dev, size, dma);
+
+ rtw_mstat_update(
+ flags
+ , p ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , size
+ );
+
+ return p;
+}
+
+inline void dbg_rtw_usb_buffer_free(struct usb_device *dev, size_t size, void *addr, dma_addr_t dma, const enum mstat_f flags, const char *func, int line)
+{
+
+ if (match_mstat_sniff_rules(flags, size))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%zu)\n", func, line, __func__, size);
+
+ _rtw_usb_buffer_free(dev, size, addr, dma);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , size
+ );
+}
+
+#endif /* defined(DBG_MEM_ALLOC) */
+
+void *rtw_malloc2d(int h, int w, size_t size)
+{
+ int j;
+
+ void **a = (void **) rtw_zmalloc(h * sizeof(void *) + h * w * size);
+ if (a == NULL) {
+ RTW_INFO("%s: alloc memory fail!\n", __func__);
+ return NULL;
+ }
+
+ for (j = 0; j < h; j++)
+ a[j] = ((char *)(a + h)) + j * w * size;
+
+ return a;
+}
+
+void rtw_mfree2d(void *pbuf, int h, int w, int size)
+{
+ rtw_mfree((u8 *)pbuf, h * sizeof(void *) + w * h * size);
+}
+
+u32 _rtw_down_sema(_sema *sema)
+{
+ if (down_interruptible(sema))
+ return _FAIL;
+ return _SUCCESS;
+}
+
+void _rtw_mutex_init(_mutex *pmutex)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+ mutex_init(pmutex);
+#else
+ init_MUTEX(pmutex);
+#endif
+}
+
+void _rtw_mutex_free(_mutex *pmutex)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+ mutex_destroy(pmutex);
+#endif
+}
+
+void _rtw_init_queue(_queue *pqueue)
+{
+ INIT_LIST_HEAD(&(pqueue->queue));
+ spin_lock_init(&(pqueue->lock));
+}
+
+u32 _rtw_queue_empty(_queue *pqueue)
+{
+ return list_empty(&(pqueue->queue));
+}
+
+
+u32 rtw_end_of_queue_search(_list *head, _list *plist)
+{
+ if (head == plist)
+ return true;
+ else
+ return false;
+}
+
+inline u32 rtw_systime_to_ms(u32 systime)
+{
+ return systime * 1000 / HZ;
+}
+
+inline u32 rtw_ms_to_systime(u32 ms)
+{
+ return ms * HZ / 1000;
+}
+
+/* the input parameter start use the same unit as returned by rtw_get_current_time */
+inline s32 rtw_get_passing_time_ms(u32 start)
+{
+ return rtw_systime_to_ms(jiffies - start);
+}
+
+inline s32 rtw_get_time_interval_ms(u32 start, u32 end)
+{
+ return rtw_systime_to_ms(end - start);
+}
+
+void rtw_sleep_schedulable(int ms)
+{
+ u32 delta;
+
+ delta = (ms * HZ) / 1000; /* (ms) */
+ if (delta == 0) {
+ delta = 1;/* 1 ms */
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (schedule_timeout(delta) != 0)
+ return ;
+ return;
+}
+
+void rtw_msleep_os(int ms)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
+ if (ms < 20) {
+ unsigned long us = ms * 1000UL;
+ usleep_range(us, us + 1000UL);
+ } else
+#endif
+ msleep((unsigned int)ms);
+}
+void rtw_usleep_os(int us)
+{
+ /* msleep((unsigned int)us); */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
+ usleep_range(us, us + 1);
+#else
+ if (1 < (us / 1000))
+ msleep(1);
+ else
+ msleep((us / 1000) + 1);
+#endif
+}
+
+#ifdef DBG_DELAY_OS
+void _rtw_mdelay_os(int ms, const char *func, const int line)
+{
+ RTW_INFO("%s:%d %s(%d)\n", func, line, __func__, ms);
+ mdelay((unsigned long)ms);
+}
+
+void _rtw_udelay_os(int us, const char *func, const int line)
+{
+ RTW_INFO("%s:%d %s(%d)\n", func, line, __func__, us);
+
+ udelay((unsigned long)us);
+}
+#else
+void rtw_mdelay_os(int ms)
+{
+ mdelay((unsigned long)ms);
+}
+
+void rtw_udelay_os(int us)
+{
+ udelay((unsigned long)us);
+}
+#endif
+
+void rtw_yield_os(void)
+{
+ yield();
+}
+
+#define RTW_SUSPEND_LOCK_NAME "rtw_wifi"
+#define RTW_SUSPEND_EXT_LOCK_NAME "rtw_wifi_ext"
+#define RTW_SUSPEND_RX_LOCK_NAME "rtw_wifi_rx"
+#define RTW_SUSPEND_TRAFFIC_LOCK_NAME "rtw_wifi_traffic"
+#define RTW_SUSPEND_RESUME_LOCK_NAME "rtw_wifi_resume"
+#define RTW_RESUME_SCAN_LOCK_NAME "rtw_wifi_scan"
+#ifdef CONFIG_WAKELOCK
+static struct wake_lock rtw_suspend_lock;
+static struct wake_lock rtw_suspend_ext_lock;
+static struct wake_lock rtw_suspend_rx_lock;
+static struct wake_lock rtw_suspend_traffic_lock;
+static struct wake_lock rtw_suspend_resume_lock;
+static struct wake_lock rtw_resume_scan_lock;
+#elif defined(CONFIG_ANDROID_POWER)
+static android_suspend_lock_t rtw_suspend_lock = {
+ .name = RTW_SUSPEND_LOCK_NAME
+};
+static android_suspend_lock_t rtw_suspend_ext_lock = {
+ .name = RTW_SUSPEND_EXT_LOCK_NAME
+};
+static android_suspend_lock_t rtw_suspend_rx_lock = {
+ .name = RTW_SUSPEND_RX_LOCK_NAME
+};
+static android_suspend_lock_t rtw_suspend_traffic_lock = {
+ .name = RTW_SUSPEND_TRAFFIC_LOCK_NAME
+};
+static android_suspend_lock_t rtw_suspend_resume_lock = {
+ .name = RTW_SUSPEND_RESUME_LOCK_NAME
+};
+static android_suspend_lock_t rtw_resume_scan_lock = {
+ .name = RTW_RESUME_SCAN_LOCK_NAME
+};
+#endif
+
+inline void rtw_suspend_lock_init(void)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_init(&rtw_suspend_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_LOCK_NAME);
+ wake_lock_init(&rtw_suspend_ext_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_EXT_LOCK_NAME);
+ wake_lock_init(&rtw_suspend_rx_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_RX_LOCK_NAME);
+ wake_lock_init(&rtw_suspend_traffic_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_TRAFFIC_LOCK_NAME);
+ wake_lock_init(&rtw_suspend_resume_lock, WAKE_LOCK_SUSPEND, RTW_SUSPEND_RESUME_LOCK_NAME);
+ wake_lock_init(&rtw_resume_scan_lock, WAKE_LOCK_SUSPEND, RTW_RESUME_SCAN_LOCK_NAME);
+#elif defined(CONFIG_ANDROID_POWER)
+ android_init_suspend_lock(&rtw_suspend_lock);
+ android_init_suspend_lock(&rtw_suspend_ext_lock);
+ android_init_suspend_lock(&rtw_suspend_rx_lock);
+ android_init_suspend_lock(&rtw_suspend_traffic_lock);
+ android_init_suspend_lock(&rtw_suspend_resume_lock);
+ android_init_suspend_lock(&rtw_resume_scan_lock);
+#endif
+}
+
+inline void rtw_suspend_lock_uninit(void)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_destroy(&rtw_suspend_lock);
+ wake_lock_destroy(&rtw_suspend_ext_lock);
+ wake_lock_destroy(&rtw_suspend_rx_lock);
+ wake_lock_destroy(&rtw_suspend_traffic_lock);
+ wake_lock_destroy(&rtw_suspend_resume_lock);
+ wake_lock_destroy(&rtw_resume_scan_lock);
+#elif defined(CONFIG_ANDROID_POWER)
+ android_uninit_suspend_lock(&rtw_suspend_lock);
+ android_uninit_suspend_lock(&rtw_suspend_ext_lock);
+ android_uninit_suspend_lock(&rtw_suspend_rx_lock);
+ android_uninit_suspend_lock(&rtw_suspend_traffic_lock);
+ android_uninit_suspend_lock(&rtw_suspend_resume_lock);
+ android_uninit_suspend_lock(&rtw_resume_scan_lock);
+#endif
+}
+
+inline void rtw_lock_suspend(void)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock(&rtw_suspend_lock);
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend(&rtw_suspend_lock);
+#endif
+
+#if defined(CONFIG_WAKELOCK) || defined(CONFIG_ANDROID_POWER)
+ /* RTW_INFO("####%s: suspend_lock_count:%d####\n", __func__, rtw_suspend_lock.stat.count); */
+#endif
+}
+
+inline void rtw_unlock_suspend(void)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_unlock(&rtw_suspend_lock);
+#elif defined(CONFIG_ANDROID_POWER)
+ android_unlock_suspend(&rtw_suspend_lock);
+#endif
+
+#if defined(CONFIG_WAKELOCK) || defined(CONFIG_ANDROID_POWER)
+ /* RTW_INFO("####%s: suspend_lock_count:%d####\n", __func__, rtw_suspend_lock.stat.count); */
+#endif
+}
+
+inline void rtw_resume_lock_suspend(void)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock(&rtw_suspend_resume_lock);
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend(&rtw_suspend_resume_lock);
+#endif
+
+#if defined(CONFIG_WAKELOCK) || defined(CONFIG_ANDROID_POWER)
+ /* RTW_INFO("####%s: suspend_lock_count:%d####\n", __func__, rtw_suspend_lock.stat.count); */
+#endif
+}
+
+inline void rtw_resume_unlock_suspend(void)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_unlock(&rtw_suspend_resume_lock);
+#elif defined(CONFIG_ANDROID_POWER)
+ android_unlock_suspend(&rtw_suspend_resume_lock);
+#endif
+
+#if defined(CONFIG_WAKELOCK) || defined(CONFIG_ANDROID_POWER)
+ /* RTW_INFO("####%s: suspend_lock_count:%d####\n", __func__, rtw_suspend_lock.stat.count); */
+#endif
+}
+
+inline void rtw_lock_suspend_timeout(u32 timeout_ms)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_timeout(&rtw_suspend_lock, rtw_ms_to_systime(timeout_ms));
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend_auto_expire(&rtw_suspend_lock, rtw_ms_to_systime(timeout_ms));
+#endif
+}
+
+inline void rtw_lock_ext_suspend_timeout(u32 timeout_ms)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_timeout(&rtw_suspend_ext_lock, rtw_ms_to_systime(timeout_ms));
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend_auto_expire(&rtw_suspend_ext_lock, rtw_ms_to_systime(timeout_ms));
+#endif
+ /* RTW_INFO("EXT lock timeout:%d\n", timeout_ms); */
+}
+
+inline void rtw_lock_rx_suspend_timeout(u32 timeout_ms)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_timeout(&rtw_suspend_rx_lock, rtw_ms_to_systime(timeout_ms));
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend_auto_expire(&rtw_suspend_rx_lock, rtw_ms_to_systime(timeout_ms));
+#endif
+ /* RTW_INFO("RX lock timeout:%d\n", timeout_ms); */
+}
+
+
+inline void rtw_lock_traffic_suspend_timeout(u32 timeout_ms)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_timeout(&rtw_suspend_traffic_lock, rtw_ms_to_systime(timeout_ms));
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend_auto_expire(&rtw_suspend_traffic_lock, rtw_ms_to_systime(timeout_ms));
+#endif
+ /* RTW_INFO("traffic lock timeout:%d\n", timeout_ms); */
+}
+
+inline void rtw_lock_resume_scan_timeout(u32 timeout_ms)
+{
+#ifdef CONFIG_WAKELOCK
+ wake_lock_timeout(&rtw_resume_scan_lock, rtw_ms_to_systime(timeout_ms));
+#elif defined(CONFIG_ANDROID_POWER)
+ android_lock_suspend_auto_expire(&rtw_resume_scan_lock, rtw_ms_to_systime(timeout_ms));
+#endif
+ /* RTW_INFO("resume scan lock:%d\n", timeout_ms); */
+}
+
+inline void ATOMIC_SET(ATOMIC_T *v, int i)
+{
+ atomic_set(v, i);
+}
+
+inline int ATOMIC_READ(ATOMIC_T *v)
+{
+ return atomic_read(v);
+}
+
+inline void ATOMIC_ADD(ATOMIC_T *v, int i)
+{
+ atomic_add(i, v);
+}
+inline void ATOMIC_SUB(ATOMIC_T *v, int i)
+{
+ atomic_sub(i, v);
+}
+
+inline void ATOMIC_INC(ATOMIC_T *v)
+{
+ atomic_inc(v);
+}
+
+inline void ATOMIC_DEC(ATOMIC_T *v)
+{
+ atomic_dec(v);
+}
+
+inline int ATOMIC_ADD_RETURN(ATOMIC_T *v, int i)
+{
+ return atomic_add_return(i, v);
+}
+
+inline int ATOMIC_SUB_RETURN(ATOMIC_T *v, int i)
+{
+ return atomic_sub_return(i, v);
+}
+
+inline int ATOMIC_INC_RETURN(ATOMIC_T *v)
+{
+ return atomic_inc_return(v);
+}
+
+inline int ATOMIC_DEC_RETURN(ATOMIC_T *v)
+{
+ return atomic_dec_return(v);
+}
+
+/*
+* Open a file with the specific @param path, @param flag, @param mode
+* @param fpp the pointer of struct file pointer to get struct file pointer while file opening is success
+* @param path the path of the file to open
+* @param flag file operation flags, please refer to linux document
+* @param mode please refer to linux document
+* @return Linux specific error code
+*/
+static int openFile(struct file **fpp, const char *path, int flag, int mode)
+{
+ struct file *fp;
+
+ fp = filp_open(path, flag, mode);
+ if (IS_ERR(fp)) {
+ *fpp = NULL;
+ return PTR_ERR(fp);
+ } else {
+ *fpp = fp;
+ return 0;
+ }
+}
+
+/*
+* Close the file with the specific @param fp
+* @param fp the pointer of struct file to close
+* @return always 0
+*/
+static int closeFile(struct file *fp)
+{
+ filp_close(fp, NULL);
+ return 0;
+}
+
+static int readFile(struct file *fp, char *buf, int len)
+{
+ int rlen = 0, sum = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ if (!(fp->f_mode & FMODE_CAN_READ))
+#else
+ if (!fp->f_op || !fp->f_op->read)
+#endif
+ return -EPERM;
+
+ while (sum < len) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
+ rlen = kernel_read(fp, buf + sum, len - sum, &fp->f_pos);
+#else
+ rlen = __vfs_read(fp, buf + sum, len - sum, &fp->f_pos);
+#endif
+#else
+ rlen = fp->f_op->read(fp, buf + sum, len - sum, &fp->f_pos);
+#endif
+ if (rlen > 0)
+ sum += rlen;
+ else if (0 != rlen)
+ return rlen;
+ else
+ break;
+ }
+
+ return sum;
+
+}
+
+static int writeFile(struct file *fp, char *buf, int len)
+{
+ int wlen = 0, sum = 0;
+
+ if (!fp->f_op || !fp->f_op->write)
+ return -EPERM;
+
+ while (sum < len) {
+ wlen = fp->f_op->write(fp, (char __user *)buf + sum, len - sum, &fp->f_pos);
+ if (wlen > 0)
+ sum += wlen;
+ else if (0 != wlen)
+ return wlen;
+ else
+ break;
+ }
+
+ return sum;
+
+}
+
+/*
+* Test if the specifi @param path is a file and readable
+* If readable, @param sz is got
+* @param path the path of the file to test
+* @return Linux specific error code
+*/
+static int isFileReadable(const char *path, u32 *sz)
+{
+ struct file *fp;
+ int ret = 0;
+#ifdef set_fs
+ mm_segment_t oldfs;
+#endif
+ char buf;
+
+ fp = filp_open(path, O_RDONLY, 0);
+ if (IS_ERR(fp))
+ ret = PTR_ERR(fp);
+ else {
+#ifdef set_fs
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+#endif
+
+ if (1 != readFile(fp, &buf, 1))
+ ret = PTR_ERR(fp);
+
+ if (ret == 0 && sz) {
+ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+ *sz = i_size_read(fp->f_path.dentry->d_inode);
+ #else
+ *sz = i_size_read(fp->f_dentry->d_inode);
+ #endif
+ }
+
+#ifdef set_fs
+ set_fs(oldfs);
+#endif
+ filp_close(fp, NULL);
+ }
+ return ret;
+}
+
+/*
+* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most
+* @param path the path of the file to open and read
+* @param buf the starting address of the buffer to store file content
+* @param sz how many bytes to read at most
+* @return the byte we've read, or Linux specific error code
+*/
+static int retriveFromFile(const char *path, u8 *buf, u32 sz)
+{
+ int ret = -1;
+#ifdef set_fs
+ mm_segment_t oldfs;
+#endif
+ struct file *fp;
+
+ if (path && buf) {
+ ret = openFile(&fp, path, O_RDONLY, 0);
+ if (0 == ret) {
+ RTW_INFO("%s openFile path:%s fp=%p\n", __func__, path , fp);
+
+#ifdef set_fs
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+#endif
+ ret = readFile(fp, buf, sz);
+#ifdef set_fs
+ set_fs(oldfs);
+#endif
+ closeFile(fp);
+
+ RTW_INFO("%s readFile, ret:%d\n", __func__, ret);
+
+ } else
+ RTW_INFO("%s openFile path:%s Fail, ret:%d\n", __func__, path, ret);
+ } else {
+ RTW_INFO("%s NULL pointer\n", __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/*
+* Open the file with @param path and wirte @param sz byte of data starting from @param buf into the file
+* @param path the path of the file to open and write
+* @param buf the starting address of the data to write into file
+* @param sz how many bytes to write at most
+* @return the byte we've written, or Linux specific error code
+*/
+static int storeToFile(const char *path, u8 *buf, u32 sz)
+{
+ int ret = 0;
+#ifdef set_fs
+ mm_segment_t oldfs;
+#endif
+ struct file *fp;
+
+ if (path && buf) {
+ ret = openFile(&fp, path, O_CREAT | O_WRONLY, 0666);
+ if (0 == ret) {
+ RTW_INFO("%s openFile path:%s fp=%p\n", __func__, path , fp);
+
+#ifdef set_fs
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+#endif
+ ret = writeFile(fp, buf, sz);
+#ifdef set_fs
+ set_fs(oldfs);
+#endif
+ closeFile(fp);
+
+ RTW_INFO("%s writeFile, ret:%d\n", __func__, ret);
+
+ } else
+ RTW_INFO("%s openFile path:%s Fail, ret:%d\n", __func__, path, ret);
+ } else {
+ RTW_INFO("%s NULL pointer\n", __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/*
+* Test if the specifi @param path is a file and readable
+* @param path the path of the file to test
+* @return true or false
+*/
+int rtw_is_file_readable(const char *path)
+{
+ if (isFileReadable(path, NULL) == 0)
+ return true;
+ else
+ return false;
+}
+
+/*
+* Test if the specifi @param path is a file and readable.
+* If readable, @param sz is got
+* @param path the path of the file to test
+* @return true or false
+*/
+int rtw_is_file_readable_with_size(const char *path, u32 *sz)
+{
+ if (isFileReadable(path, sz) == 0)
+ return true;
+ else
+ return false;
+}
+
+/*
+* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most
+* @param path the path of the file to open and read
+* @param buf the starting address of the buffer to store file content
+* @param sz how many bytes to read at most
+* @return the byte we've read
+*/
+int rtw_retrieve_from_file(const char *path, u8 *buf, u32 sz)
+{
+ int ret = retriveFromFile(path, buf, sz);
+
+ return ret >= 0 ? ret : 0;
+}
+
+/*
+* Open the file with @param path and wirte @param sz byte of data starting from @param buf into the file
+* @param path the path of the file to open and write
+* @param buf the starting address of the data to write into file
+* @param sz how many bytes to write at most
+* @return the byte we've written
+*/
+int rtw_store_to_file(const char *path, u8 *buf, u32 sz)
+{
+ int ret = storeToFile(path, buf, sz);
+ return ret >= 0 ? ret : 0;
+}
+
+struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv)
+{
+ struct net_device *pnetdev;
+ struct rtw_netdev_priv_indicator *pnpi;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+#else
+ pnetdev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator));
+#endif
+ if (!pnetdev)
+ goto RETURN;
+
+ pnpi = netdev_priv(pnetdev);
+ pnpi->priv = old_priv;
+ pnpi->sizeof_priv = sizeof_priv;
+
+RETURN:
+ return pnetdev;
+}
+
+struct net_device *rtw_alloc_etherdev(int sizeof_priv)
+{
+ struct net_device *pnetdev;
+ struct rtw_netdev_priv_indicator *pnpi;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+#else
+ pnetdev = alloc_etherdev(sizeof(struct rtw_netdev_priv_indicator));
+#endif
+ if (!pnetdev)
+ goto RETURN;
+
+ pnpi = netdev_priv(pnetdev);
+
+ pnpi->priv = rtw_zvmalloc(sizeof_priv);
+ if (!pnpi->priv) {
+ free_netdev(pnetdev);
+ pnetdev = NULL;
+ goto RETURN;
+ }
+
+ pnpi->sizeof_priv = sizeof_priv;
+RETURN:
+ return pnetdev;
+}
+
+void rtw_free_netdev(struct net_device *netdev)
+{
+ struct rtw_netdev_priv_indicator *pnpi;
+
+ if (!netdev)
+ goto RETURN;
+
+ pnpi = netdev_priv(netdev);
+
+ if (!pnpi->priv)
+ goto RETURN;
+
+ free_netdev(netdev);
+
+RETURN:
+ return;
+}
+
+int rtw_change_ifname(_adapter *padapter, const char *ifname)
+{
+ struct dvobj_priv *dvobj;
+ struct net_device *pnetdev;
+ struct net_device *cur_pnetdev;
+ struct rereg_nd_name_data *rereg_priv;
+ int ret;
+ u8 rtnl_lock_needed;
+
+ if (!padapter)
+ goto error;
+
+ dvobj = adapter_to_dvobj(padapter);
+ cur_pnetdev = padapter->pnetdev;
+ rereg_priv = &padapter->rereg_nd_name_priv;
+
+ /* free the old_pnetdev */
+ if (rereg_priv->old_pnetdev) {
+ free_netdev(rereg_priv->old_pnetdev);
+ rereg_priv->old_pnetdev = NULL;
+ }
+
+ rtnl_lock_needed = rtw_rtnl_lock_needed(dvobj);
+
+ if (rtnl_lock_needed)
+ unregister_netdev(cur_pnetdev);
+ else
+ unregister_netdevice(cur_pnetdev);
+
+ rereg_priv->old_pnetdev = cur_pnetdev;
+
+ pnetdev = rtw_init_netdev(padapter);
+ if (!pnetdev) {
+ ret = -1;
+ goto error;
+ }
+
+ SET_NETDEV_DEV(pnetdev, dvobj_to_dev(adapter_to_dvobj(padapter)));
+
+ rtw_init_netdev_name(pnetdev, ifname);
+
+ memcpy(pnetdev->dev_addr, adapter_mac_addr(padapter), ETH_ALEN);
+
+ if (rtnl_lock_needed)
+ ret = register_netdev(pnetdev);
+ else
+ ret = register_netdevice(pnetdev);
+
+ if (ret != 0) {
+ goto error;
+ }
+
+ return 0;
+
+error:
+
+ return -1;
+
+}
+
+#ifdef CONFIG_PLATFORM_SPRD
+ #ifdef do_div
+ #undef do_div
+ #endif
+ #include <asm-generic/div64.h>
+#endif
+
+u64 rtw_modular64(u64 x, u64 y)
+{
+ return do_div(x, y);
+}
+
+u64 rtw_division64(u64 x, u64 y)
+{
+ do_div(x, y);
+ return x;
+}
+
+inline u32 rtw_random32(void)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ return prandom_u32();
+#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18))
+ u32 random_int;
+ get_random_bytes(&random_int , 4);
+ return random_int;
+#else
+ return random32();
+#endif
+}
+
+void rtw_buf_free(u8 **buf, u32 *buf_len)
+{
+ u32 ori_len;
+
+ if (!buf || !buf_len)
+ return;
+
+ ori_len = *buf_len;
+
+ if (*buf) {
+ u32 tmp_buf_len = *buf_len;
+ *buf_len = 0;
+ rtw_mfree(*buf, tmp_buf_len);
+ *buf = NULL;
+ }
+}
+
+void rtw_buf_update(u8 **buf, u32 *buf_len, u8 *src, u32 src_len)
+{
+ u32 ori_len = 0, dup_len = 0;
+ u8 *ori = NULL;
+ u8 *dup = NULL;
+
+ if (!buf || !buf_len)
+ return;
+
+ if (!src || !src_len)
+ goto keep_ori;
+
+ /* duplicate src */
+ dup = rtw_malloc(src_len);
+ if (dup) {
+ dup_len = src_len;
+ memcpy(dup, src, dup_len);
+ }
+
+keep_ori:
+ ori = *buf;
+ ori_len = *buf_len;
+
+ /* replace buf with dup */
+ *buf_len = 0;
+ *buf = dup;
+ *buf_len = dup_len;
+
+ /* free ori */
+ if (ori && ori_len > 0)
+ rtw_mfree(ori, ori_len);
+}
+
+
+/**
+ * rtw_cbuf_full - test if cbuf is full
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is full
+ */
+inline bool rtw_cbuf_full(struct rtw_cbuf *cbuf)
+{
+ return (cbuf->write == cbuf->read - 1) ? true : false;
+}
+
+/**
+ * rtw_cbuf_empty - test if cbuf is empty
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is empty
+ */
+inline bool rtw_cbuf_empty(struct rtw_cbuf *cbuf)
+{
+ return (cbuf->write == cbuf->read) ? true : false;
+}
+
+/**
+ * rtw_cbuf_push - push a pointer into cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ * @buf: pointer to push in
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: true push success
+ */
+bool rtw_cbuf_push(struct rtw_cbuf *cbuf, void *buf)
+{
+ if (rtw_cbuf_full(cbuf))
+ return _FAIL;
+
+ if (0)
+ RTW_INFO("%s on %u\n", __func__, cbuf->write);
+ cbuf->bufs[cbuf->write] = buf;
+ cbuf->write = (cbuf->write + 1) % cbuf->size;
+
+ return _SUCCESS;
+}
+
+/**
+ * rtw_cbuf_pop - pop a pointer from cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: pointer popped out
+ */
+void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
+{
+ void *buf;
+ if (rtw_cbuf_empty(cbuf))
+ return NULL;
+
+ if (0)
+ RTW_INFO("%s on %u\n", __func__, cbuf->read);
+ buf = cbuf->bufs[cbuf->read];
+ cbuf->read = (cbuf->read + 1) % cbuf->size;
+
+ return buf;
+}
+
+/**
+ * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization
+ * @size: size of pointer
+ *
+ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure
+ */
+struct rtw_cbuf *rtw_cbuf_alloc(u32 size)
+{
+ struct rtw_cbuf *cbuf;
+
+ cbuf = (struct rtw_cbuf *)rtw_malloc(sizeof(*cbuf) + sizeof(void *) * size);
+
+ if (cbuf) {
+ cbuf->write = cbuf->read = 0;
+ cbuf->size = size;
+ }
+
+ return cbuf;
+}
+
+/**
+ * rtw_cbuf_free - free the given rtw_cbuf
+ * @cbuf: pointer of struct rtw_cbuf to free
+ */
+void rtw_cbuf_free(struct rtw_cbuf *cbuf)
+{
+ rtw_mfree((u8 *)cbuf, sizeof(*cbuf) + sizeof(void *) * cbuf->size);
+}
+
+/**
+ * map_readN - read a range of map data
+ * @map: map to read
+ * @offset: start address to read
+ * @len: length to read
+ * @buf: pointer of buffer to store data read
+ *
+ * Returns: _SUCCESS or _FAIL
+ */
+int map_readN(const struct map_t *map, u16 offset, u16 len, u8 *buf)
+{
+ const struct map_seg_t *seg;
+ int ret = _FAIL;
+ int i;
+
+ if (len == 0) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ if (offset + len > map->len) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ memset(buf, map->init_value, len);
+
+ for (i = 0; i < map->seg_num; i++) {
+ u8 *c_dst, *c_src;
+ u16 c_len;
+
+ seg = map->segs + i;
+ if (seg->sa + seg->len <= offset || seg->sa >= offset + len)
+ continue;
+
+ if (seg->sa >= offset) {
+ c_dst = buf + (seg->sa - offset);
+ c_src = seg->c;
+ if (seg->sa + seg->len <= offset + len)
+ c_len = seg->len;
+ else
+ c_len = offset + len - seg->sa;
+ } else {
+ c_dst = buf;
+ c_src = seg->c + (offset - seg->sa);
+ if (seg->sa + seg->len >= offset + len)
+ c_len = len;
+ else
+ c_len = seg->sa + seg->len - offset;
+ }
+
+ memcpy(c_dst, c_src, c_len);
+ }
+
+exit:
+ return ret;
+}
+
+/**
+ * map_read8 - read 1 byte of map data
+ * @map: map to read
+ * @offset: address to read
+ *
+ * Returns: value of data of specified offset. map.init_value if offset is out of range
+ */
+u8 map_read8(const struct map_t *map, u16 offset)
+{
+ const struct map_seg_t *seg;
+ u8 val = map->init_value;
+ int i;
+
+ if (offset + 1 > map->len) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ for (i = 0; i < map->seg_num; i++) {
+ seg = map->segs + i;
+ if (seg->sa + seg->len <= offset || seg->sa >= offset + 1)
+ continue;
+
+ val = *(seg->c + offset - seg->sa);
+ break;
+ }
+
+exit:
+ return val;
+}
+
+/**
+* is_null -
+*
+* Return true if c is null character
+* false otherwise.
+*/
+inline bool is_null(char c)
+{
+ if (c == '\0')
+ return true;
+ else
+ return false;
+}
+
+/**
+* is_eol -
+*
+* Return true if c is represent for EOL (end of line)
+* false otherwise.
+*/
+inline bool is_eol(char c)
+{
+ if (c == '\r' || c == '\n')
+ return true;
+ else
+ return false;
+}
+
+/**
+* is_space -
+*
+* Return true if c is represent for space
+* false otherwise.
+*/
+inline bool is_space(char c)
+{
+ if (c == ' ' || c == '\t')
+ return true;
+ else
+ return false;
+}
+
+/**
+* IsHexDigit -
+*
+* Return true if chTmp is represent for hex digit
+* false otherwise.
+*/
+inline bool IsHexDigit(char chTmp)
+{
+ if ((chTmp >= '0' && chTmp <= '9') ||
+ (chTmp >= 'a' && chTmp <= 'f') ||
+ (chTmp >= 'A' && chTmp <= 'F'))
+ return true;
+ else
+ return false;
+}
+
+/**
+* is_alpha -
+*
+* Return true if chTmp is represent for alphabet
+* false otherwise.
+*/
+inline bool is_alpha(char chTmp)
+{
+ if ((chTmp >= 'a' && chTmp <= 'z') ||
+ (chTmp >= 'A' && chTmp <= 'Z'))
+ return true;
+ else
+ return false;
+}
+
+inline char alpha_to_upper(char c)
+{
+ if ((c >= 'a' && c <= 'z'))
+ c = 'A' + (c - 'a');
+ return c;
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
new file mode 100644
index 000000000000..bb5833a0bf41
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c
@@ -0,0 +1,790 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _RECV_OSDEP_C_
+
+#include <drv_types.h>
+#include <usb_osintf.h>
+
+int rtw_os_recvframe_duplicate_skb(_adapter *padapter, union recv_frame *pcloneframe, _pkt *pskb)
+{
+ int res = _SUCCESS;
+ _pkt *pkt_copy = NULL;
+ struct rx_pkt_attrib *pattrib = &pcloneframe->u.hdr.attrib;
+
+ if (pskb == NULL) {
+ RTW_INFO("%s [WARN] skb == NULL, drop frag frame\n", __func__);
+ return _FAIL;
+ }
+ pkt_copy = rtw_skb_copy(pskb);
+
+ if (pkt_copy == NULL) {
+ RTW_INFO("%s [WARN] rtw_skb_copy fail , drop frag frame\n", __func__);
+ return _FAIL;
+ }
+ pkt_copy->dev = padapter->pnetdev;
+
+ pcloneframe->u.hdr.pkt = pkt_copy;
+ pcloneframe->u.hdr.rx_head = pkt_copy->head;
+ pcloneframe->u.hdr.rx_data = pkt_copy->data;
+ pcloneframe->u.hdr.rx_end = skb_end_pointer(pkt_copy);
+ pcloneframe->u.hdr.rx_tail = skb_tail_pointer(pkt_copy);
+ pcloneframe->u.hdr.len = pkt_copy->len;
+
+ return res;
+}
+
+int rtw_os_alloc_recvframe(_adapter *padapter, union recv_frame *precvframe, u8 *pdata, _pkt *pskb)
+{
+ int res = _SUCCESS;
+ u8 shift_sz = 0;
+ u32 skb_len, alloc_sz;
+ _pkt *pkt_copy = NULL;
+ struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib;
+
+
+ if (pdata == NULL) {
+ precvframe->u.hdr.pkt = NULL;
+ res = _FAIL;
+ return res;
+ }
+
+
+ /* Modified by Albert 20101213 */
+ /* For 8 bytes IP header alignment. */
+ shift_sz = pattrib->qos ? 6 : 0; /* Qos data, wireless lan header length is 26 */
+
+ skb_len = le16_to_cpu(pattrib->pkt_len);
+
+ /* for first fragment packet, driver need allocate 1536+drvinfo_sz+RXDESC_SIZE to defrag packet. */
+ /* modify alloc_sz for recvive crc error packet by thomas 2011-06-02 */
+ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+ /* alloc_sz = 1664; */ /* 1664 is 128 alignment. */
+ alloc_sz = (skb_len <= 1650) ? 1664 : (skb_len + 14);
+ } else {
+ alloc_sz = skb_len;
+ /* 6 is for IP header 8 bytes alignment in QoS packet case. */
+ /* 8 is for skb->data 4 bytes alignment. */
+ alloc_sz += 14;
+ }
+
+ pkt_copy = rtw_skb_alloc(alloc_sz);
+
+ if (pkt_copy) {
+ pkt_copy->dev = padapter->pnetdev;
+ pkt_copy->len = skb_len;
+ precvframe->u.hdr.pkt = pkt_copy;
+ precvframe->u.hdr.rx_head = pkt_copy->head;
+ precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz;
+ skb_reserve(pkt_copy, 8 - ((SIZE_PTR)(pkt_copy->data) & 7)); /* force pkt_copy->data at 8-byte alignment address */
+ skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
+ memcpy(pkt_copy->data, pdata, skb_len);
+ precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_copy->data;
+ } else {
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
+ RTW_INFO("%s:can not allocate memory for skb copy\n", __func__);
+
+ precvframe->u.hdr.pkt = NULL;
+
+ /* rtw_free_recvframe(precvframe, pfree_recv_queue); */
+ /*exit_rtw_os_recv_resource_alloc;*/
+
+ res = _FAIL;
+#else
+ if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+ RTW_INFO("%s: alloc_skb fail , drop frag frame\n", __func__);
+ /* rtw_free_recvframe(precvframe, pfree_recv_queue); */
+ res = _FAIL;
+ goto exit_rtw_os_recv_resource_alloc;
+ }
+
+ if (pskb == NULL) {
+ res = _FAIL;
+ goto exit_rtw_os_recv_resource_alloc;
+ }
+
+ precvframe->u.hdr.pkt = rtw_skb_clone(pskb);
+ if (precvframe->u.hdr.pkt) {
+ precvframe->u.hdr.pkt->dev = padapter->pnetdev;
+ precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pdata;
+ precvframe->u.hdr.rx_end = pdata + alloc_sz;
+ } else {
+ RTW_INFO("%s: rtw_skb_clone fail\n", __func__);
+ /* rtw_free_recvframe(precvframe, pfree_recv_queue); */
+ /*exit_rtw_os_recv_resource_alloc;*/
+ res = _FAIL;
+ }
+#endif
+ }
+
+exit_rtw_os_recv_resource_alloc:
+
+ return res;
+
+}
+
+void rtw_os_free_recvframe(union recv_frame *precvframe)
+{
+ if (precvframe->u.hdr.pkt) {
+ rtw_skb_free(precvframe->u.hdr.pkt);/* free skb by driver */
+
+ precvframe->u.hdr.pkt = NULL;
+ }
+}
+
+/* init os related resource in struct recv_priv */
+int rtw_os_recv_resource_init(struct recv_priv *precvpriv, _adapter *padapter)
+{
+ int res = _SUCCESS;
+
+
+#ifdef CONFIG_RTW_NAPI
+ skb_queue_head_init(&precvpriv->rx_napi_skb_queue);
+#endif /* CONFIG_RTW_NAPI */
+
+ return res;
+}
+
+/* alloc os related resource in union recv_frame */
+int rtw_os_recv_resource_alloc(_adapter *padapter, union recv_frame *precvframe)
+{
+ int res = _SUCCESS;
+
+ precvframe->u.hdr.pkt_newalloc = precvframe->u.hdr.pkt = NULL;
+
+ return res;
+}
+
+/* free os related resource in union recv_frame */
+void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
+{
+ sint i;
+ union recv_frame *precvframe;
+
+ precvframe = (union recv_frame *) precvpriv->precv_frame_buf;
+
+#ifdef CONFIG_RTW_NAPI
+ if (skb_queue_len(&precvpriv->rx_napi_skb_queue))
+ RTW_WARN("rx_napi_skb_queue not empty\n");
+ rtw_skb_queue_purge(&precvpriv->rx_napi_skb_queue);
+#endif /* CONFIG_RTW_NAPI */
+
+ for (i = 0; i < NR_RECVFRAME; i++) {
+ if (precvframe->u.hdr.pkt) {
+ rtw_skb_free(precvframe->u.hdr.pkt);/* free skb by driver */
+ precvframe->u.hdr.pkt = NULL;
+ }
+ precvframe++;
+ }
+}
+
+/* alloc os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_alloc(_adapter *padapter, struct recv_buf *precvbuf)
+{
+ int res = _SUCCESS;
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+ struct usb_device *pusbd = pdvobjpriv->pusbdev;
+
+ precvbuf->irp_pending = false;
+ precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
+ if (precvbuf->purb == NULL)
+ res = _FAIL;
+
+ precvbuf->pskb = NULL;
+
+ precvbuf->pallocated_buf = precvbuf->pbuf = NULL;
+
+ precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pend = NULL;
+
+ precvbuf->transfer_len = 0;
+
+ precvbuf->len = 0;
+
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
+ precvbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)precvbuf->alloc_sz, &precvbuf->dma_transfer_addr);
+ precvbuf->pbuf = precvbuf->pallocated_buf;
+ if (precvbuf->pallocated_buf == NULL)
+ return _FAIL;
+#endif /* CONFIG_USE_USB_BUFFER_ALLOC_RX */
+
+ return res;
+}
+
+/* free os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_free(_adapter *padapter, struct recv_buf *precvbuf)
+{
+ int ret = _SUCCESS;
+
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
+
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+ struct usb_device *pusbd = pdvobjpriv->pusbdev;
+
+ rtw_usb_buffer_free(pusbd, (size_t)precvbuf->alloc_sz, precvbuf->pallocated_buf, precvbuf->dma_transfer_addr);
+ precvbuf->pallocated_buf = NULL;
+ precvbuf->dma_transfer_addr = 0;
+
+#endif /* CONFIG_USE_USB_BUFFER_ALLOC_RX */
+
+ if (precvbuf->purb) {
+ /* usb_kill_urb(precvbuf->purb); */
+ usb_free_urb(precvbuf->purb);
+ }
+
+ if (precvbuf->pskb) {
+#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
+ if (rtw_free_skb_premem(precvbuf->pskb) != 0)
+#endif
+ rtw_skb_free(precvbuf->pskb);
+ }
+ return ret;
+
+}
+
+_pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 *pdata)
+{
+ u16 eth_type;
+ u8 *data_ptr;
+ _pkt *sub_skb;
+ struct rx_pkt_attrib *pattrib;
+
+ pattrib = &prframe->u.hdr.attrib;
+
+#ifdef CONFIG_SKB_COPY
+ sub_skb = rtw_skb_alloc(nSubframe_Length + 12);
+ if (sub_skb) {
+ skb_reserve(sub_skb, 12);
+ data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length);
+ memcpy(data_ptr, (pdata + ETH_HLEN), nSubframe_Length);
+ } else
+#endif /* CONFIG_SKB_COPY */
+ {
+ sub_skb = rtw_skb_clone(prframe->u.hdr.pkt);
+ if (sub_skb) {
+ sub_skb->data = pdata + ETH_HLEN;
+ sub_skb->len = nSubframe_Length;
+ skb_set_tail_pointer(sub_skb, nSubframe_Length);
+ } else {
+ RTW_INFO("%s(): rtw_skb_clone() Fail!!!\n", __func__);
+ return NULL;
+ }
+ }
+
+ eth_type = RTW_GET_BE16(&sub_skb->data[6]);
+
+ if (sub_skb->len >= 8 &&
+ ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) &&
+ eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
+ !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
+ skb_pull(sub_skb, SNAP_SIZE);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
+ } else {
+ __be16 len;
+ /* Leave Ethernet header part of hdr and full payload */
+ len = htons(sub_skb->len);
+ memcpy(skb_push(sub_skb, 2), &len, 2);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
+ memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
+ }
+
+ return sub_skb;
+}
+
+#ifdef CONFIG_RTW_NAPI
+static int napi_recv(_adapter *padapter, int budget)
+{
+ _pkt *pskb;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ int work_done = 0;
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+ u8 rx_ok;
+
+ while ((work_done < budget) &&
+ (!skb_queue_empty(&precvpriv->rx_napi_skb_queue))) {
+ pskb = skb_dequeue(&precvpriv->rx_napi_skb_queue);
+ if (!pskb)
+ break;
+
+ rx_ok = false;
+
+#ifdef CONFIG_RTW_GRO
+ if (pregistrypriv->en_gro) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)
+ if (rtw_napi_gro_receive(&padapter->napi, pskb) != GRO_DROP)
+ rx_ok = true;
+#else
+ rx_ok = true;
+#endif
+ goto next;
+ }
+#endif /* CONFIG_RTW_GRO */
+
+ if (rtw_netif_receive_skb(padapter->pnetdev, pskb) == NET_RX_SUCCESS)
+ rx_ok = true;
+
+#ifdef CONFIG_RTW_GRO
+next:
+#endif /* CONFIG_RTW_GRO */
+ if (rx_ok) {
+ work_done++;
+ DBG_COUNTER(padapter->rx_logs.os_netif_ok);
+ } else {
+ DBG_COUNTER(padapter->rx_logs.os_netif_err);
+ }
+ }
+ return work_done;
+}
+
+int rtw_recv_napi_poll(struct napi_struct *napi, int budget)
+{
+ _adapter *padapter = container_of(napi, _adapter, napi);
+ int work_done = 0;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ work_done = napi_recv(padapter, budget);
+ if (work_done < budget) {
+ napi_complete(napi);
+ if (!skb_queue_empty(&precvpriv->rx_napi_skb_queue))
+ napi_schedule(napi);
+ }
+ return work_done;
+}
+#endif /* CONFIG_RTW_NAPI */
+
+#ifdef DBG_UDP_PKT_LOSE_11AC
+ #define PAYLOAD_LEN_LOC_OF_IP_HDR 0x10 /*ethernet payload length location of ip header (DA + SA+eth_type+(version&hdr_len)) */
+#endif
+
+void rtw_os_recv_indicate_pkt(_adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib)
+{
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct recv_priv *precvpriv = &(padapter->recvpriv);
+ struct registry_priv *pregistrypriv = &padapter->registrypriv;
+#ifdef CONFIG_BR_EXT
+ void *br_port = NULL;
+#endif
+ int ret;
+
+ /* Indicate the packets to upper layer */
+ if (pkt) {
+ if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+ _pkt *pskb2 = NULL;
+ struct sta_info *psta = NULL;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int bmcast = IS_MCAST(pattrib->dst);
+
+ if (!memcmp(pattrib->dst, adapter_mac_addr(padapter), ETH_ALEN) == false) {
+ if (bmcast) {
+ psta = rtw_get_bcmc_stainfo(padapter);
+ pskb2 = rtw_skb_clone(pkt);
+ } else
+ psta = rtw_get_stainfo(pstapriv, pattrib->dst);
+
+ if (psta) {
+ struct net_device *pnetdev = (struct net_device *)padapter->pnetdev;
+
+ pkt->dev = pnetdev;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ skb_set_queue_mapping(pkt, rtw_recv_select_queue(pkt));
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) */
+
+ _rtw_xmit_entry(pkt, pnetdev);
+
+ if (bmcast && (pskb2 != NULL)) {
+ pkt = pskb2;
+ DBG_COUNTER(padapter->rx_logs.os_indicate_ap_mcast);
+ } else {
+ DBG_COUNTER(padapter->rx_logs.os_indicate_ap_forward);
+ return;
+ }
+ }
+ } else { /* to APself */
+ DBG_COUNTER(padapter->rx_logs.os_indicate_ap_self);
+ }
+ }
+
+#ifdef CONFIG_BR_EXT
+ /* Insert NAT2.5 RX here! */
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35))
+ br_port = padapter->pnetdev->br_port;
+#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */
+ rcu_read_lock();
+ br_port = rcu_dereference(padapter->pnetdev->rx_handler_data);
+ rcu_read_unlock();
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */
+
+#endif /* CONFIG_BR_EXT */
+ if (precvpriv->sink_udpport > 0)
+ rtw_sink_rtp_seq_dbg(padapter, pkt);
+#ifdef DBG_UDP_PKT_LOSE_11AC
+ /* After eth_type_trans process , pkt->data pointer will move from ethrnet header to ip header ,
+ * we have to check ethernet type , so this debug must be print before eth_type_trans
+ */
+ if (*((unsigned short *)(pkt->data + ETH_ALEN * 2)) == htons(ETH_P_ARP)) {
+ /* ARP Payload length will be 42bytes or 42+18(tailer)=60bytes*/
+ if (pkt->len != 42 && pkt->len != 60)
+ RTW_INFO("Error !!%s,ARP Payload length %u not correct\n",
+ __func__, pkt->len);
+ } else if (*((unsigned short *)(pkt->data + ETH_ALEN * 2)) == htons(ETH_P_IP)) {
+ if (be16_to_cpu(*((u16 *)(pkt->data + PAYLOAD_LEN_LOC_OF_IP_HDR))) !=
+ (pkt->len) - ETH_HLEN) {
+ RTW_INFO("Error !!%s,Payload length not correct\n", __func__);
+ RTW_INFO("%s, IP header describe Total length=%u\n",
+ __func__, be16_to_cpu(*((u16 *)(pkt->data +
+ PAYLOAD_LEN_LOC_OF_IP_HDR))));
+ RTW_INFO("%s, Pkt real length=%u\n", __func__,
+ (pkt->len) - ETH_HLEN);
+ }
+ }
+#endif
+ /* After eth_type_trans process , pkt->data pointer will move from ethrnet header to ip header */
+ pkt->protocol = eth_type_trans(pkt, padapter->pnetdev);
+ pkt->dev = padapter->pnetdev;
+
+#ifdef CONFIG_TCP_CSUM_OFFLOAD_RX
+ if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1))
+ pkt->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ pkt->ip_summed = CHECKSUM_NONE;
+#else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */
+ pkt->ip_summed = CHECKSUM_NONE;
+#endif /* CONFIG_TCP_CSUM_OFFLOAD_RX */
+
+#ifdef CONFIG_RTW_NAPI
+ if (pregistrypriv->en_napi) {
+ skb_queue_tail(&precvpriv->rx_napi_skb_queue, pkt);
+ napi_schedule(&padapter->napi);
+ return;
+ }
+#endif /* CONFIG_RTW_NAPI */
+
+ ret = rtw_netif_rx(padapter->pnetdev, pkt);
+ if (ret == NET_RX_SUCCESS)
+ DBG_COUNTER(padapter->rx_logs.os_netif_ok);
+ else
+ DBG_COUNTER(padapter->rx_logs.os_netif_err);
+ }
+}
+
+void rtw_handle_tkip_mic_err(_adapter *padapter, struct sta_info *sta, u8 bgroup)
+{
+#ifdef CONFIG_IOCTL_CFG80211
+ enum nl80211_key_type key_type = 0;
+#endif
+ union iwreq_data wrqu;
+ struct iw_michaelmicfailure ev;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
+ u32 cur_time = 0;
+
+ if (psecuritypriv->last_mic_err_time == 0) {
+ psecuritypriv->last_mic_err_time = jiffies;
+ } else {
+ cur_time = jiffies;
+
+ if (cur_time - psecuritypriv->last_mic_err_time < 60 * HZ) {
+ psecuritypriv->btkip_countermeasure = true;
+ psecuritypriv->last_mic_err_time = 0;
+ psecuritypriv->btkip_countermeasure_time = cur_time;
+ } else {
+ psecuritypriv->last_mic_err_time = jiffies;
+ }
+ }
+
+#ifdef CONFIG_IOCTL_CFG80211
+ if (bgroup)
+ key_type |= NL80211_KEYTYPE_GROUP;
+ else
+ key_type |= NL80211_KEYTYPE_PAIRWISE;
+
+ cfg80211_michael_mic_failure(padapter->pnetdev, sta->hwaddr, key_type, -1, NULL, GFP_ATOMIC);
+#endif
+
+ memset(&ev, 0x00, sizeof(ev));
+ if (bgroup)
+ ev.flags |= IW_MICFAILURE_GROUP;
+ else
+ ev.flags |= IW_MICFAILURE_PAIRWISE;
+
+ ev.src_addr.sa_family = ARPHRD_ETHER;
+ memcpy(ev.src_addr.sa_data, sta->hwaddr, ETH_ALEN);
+
+ memset(&wrqu, 0x00, sizeof(wrqu));
+ wrqu.data.length = sizeof(ev);
+
+#ifndef CONFIG_IOCTL_CFG80211
+ wireless_send_event(padapter->pnetdev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev);
+#endif
+}
+
+void rtw_hostapd_mlme_rx(_adapter *padapter, union recv_frame *precv_frame)
+{
+#ifdef CONFIG_HOSTAPD_MLME
+ _pkt *skb;
+ struct hostapd_priv *phostapdpriv = padapter->phostapdpriv;
+ struct net_device *pmgnt_netdev = phostapdpriv->pmgnt_netdev;
+
+ skb = precv_frame->u.hdr.pkt;
+
+ if (!skb)
+ return;
+
+ skb->data = precv_frame->u.hdr.rx_data;
+ skb->tail = precv_frame->u.hdr.rx_tail;
+ skb->len = precv_frame->u.hdr.len;
+
+ skb->dev = pmgnt_netdev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(0x0003); /*ETH_P_80211_RAW*/
+
+ skb_reset_mac_header(skb);
+
+ memset(skb->cb, 0, sizeof(skb->cb));
+
+ rtw_netif_rx(pmgnt_netdev, skb);
+
+ precv_frame->u.hdr.pkt = NULL; /* set pointer to NULL before rtw_free_recvframe() if call rtw_netif_rx() */
+#endif
+}
+
+#ifdef CONFIG_AUTO_AP_MODE
+static void rtw_os_ksocket_send(_adapter *padapter, union recv_frame *precv_frame)
+{
+ _pkt *skb = precv_frame->u.hdr.pkt;
+ struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib;
+ struct sta_info *psta = precv_frame->u.hdr.psta;
+
+ RTW_INFO("eth rx: got eth_type=0x%x\n", pattrib->eth_type);
+
+ if (psta && psta->isrc && psta->pid > 0) {
+ u16 rx_pid;
+
+ rx_pid = *(u16 *)(skb->data + ETH_HLEN);
+
+ RTW_INFO("eth rx(pid=0x%x): sta("MAC_FMT") pid=0x%x\n",
+ rx_pid, MAC_ARG(psta->hwaddr), psta->pid);
+
+ if (rx_pid == psta->pid) {
+ int i;
+ u16 len = *(u16 *)(skb->data + ETH_HLEN + 2);
+
+ RTW_INFO("eth, RC: len=0x%x\n", len);
+
+ for (i = 0; i < len; i++)
+ RTW_INFO("0x%x\n", *(skb->data + ETH_HLEN + 4 + i));
+
+ RTW_INFO("eth, RC-end\n");
+
+ }
+
+ }
+
+}
+#endif /* CONFIG_AUTO_AP_MODE */
+
+int rtw_recv_monitor(_adapter *padapter, union recv_frame *precv_frame)
+{
+ int ret = _FAIL;
+ struct recv_priv *precvpriv;
+ _queue *pfree_recv_queue;
+ _pkt *skb;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct rx_pkt_attrib *pattrib;
+
+ if (!precv_frame)
+ goto _recv_drop;
+
+ pattrib = &precv_frame->u.hdr.attrib;
+ precvpriv = &(padapter->recvpriv);
+ pfree_recv_queue = &(precvpriv->free_recv_queue);
+
+ skb = precv_frame->u.hdr.pkt;
+ if (!skb) {
+ RTW_INFO("%s :skb==NULL something wrong!!!!\n", __func__);
+ goto _recv_drop;
+ }
+
+ skb->data = precv_frame->u.hdr.rx_data;
+ skb_set_tail_pointer(skb, precv_frame->u.hdr.len);
+ skb->len = precv_frame->u.hdr.len;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(0x0019); /* ETH_P_80211_RAW */
+
+ rtw_netif_rx(padapter->pnetdev, skb);
+
+ /* pointers to NULL before rtw_free_recvframe() */
+ precv_frame->u.hdr.pkt = NULL;
+
+ ret = _SUCCESS;
+
+_recv_drop:
+
+ /* enqueue back to free_recv_queue */
+ if (precv_frame)
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+ return ret;
+}
+
+static inline void check_reg_rule(struct sta_info *sta, u8 *ip, _adapter *padapter)
+{
+ u8 *tcp = ip + GET_IPV4_IHL(ip) * 4;
+
+ if (rtw_st_ctl_chk_reg_rule(&sta->st_ctl, padapter, IPV4_DST(ip),
+ TCP_DST(tcp), IPV4_SRC(ip), TCP_SRC(tcp))) {
+ if (GET_TCP_SYN(tcp) && GET_TCP_ACK(tcp)) {
+ session_tracker_add_cmd(padapter, sta, IPV4_DST(ip),
+ TCP_DST(tcp), IPV4_SRC(ip),
+ TCP_SRC(tcp));
+ if (DBG_SESSION_TRACKER)
+ RTW_INFO(FUNC_ADPT_FMT" local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT" SYN-ACK\n",
+ FUNC_ADPT_ARG(padapter),
+ IP_ARG(IPV4_DST(ip)), PORT_ARG(TCP_DST(tcp)),
+ IP_ARG(IPV4_SRC(ip)), PORT_ARG(TCP_SRC(tcp)));
+ }
+ if (GET_TCP_FIN(tcp)) {
+ session_tracker_del_cmd(padapter, sta,
+ IPV4_DST(ip), TCP_DST(tcp),
+ IPV4_SRC(ip), TCP_SRC(tcp));
+ if (DBG_SESSION_TRACKER)
+ RTW_INFO(FUNC_ADPT_FMT" local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT" FIN\n",
+ FUNC_ADPT_ARG(padapter),
+ IP_ARG(IPV4_DST(ip)), PORT_ARG(TCP_DST(tcp)),
+ IP_ARG(IPV4_SRC(ip)), PORT_ARG(TCP_SRC(tcp)));
+ }
+ }
+}
+
+int rtw_recv_indicatepkt(_adapter *padapter, union recv_frame *precv_frame)
+{
+ struct recv_priv *precvpriv;
+ _queue *pfree_recv_queue;
+ _pkt *skb;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct rx_pkt_attrib *pattrib;
+
+ if (!precv_frame)
+ goto _recv_indicatepkt_drop;
+
+ DBG_COUNTER(padapter->rx_logs.os_indicate);
+ pattrib = &precv_frame->u.hdr.attrib;
+ precvpriv = &(padapter->recvpriv);
+ pfree_recv_queue = &(precvpriv->free_recv_queue);
+
+#ifdef CONFIG_DRVEXT_MODULE
+ if (drvext_rx_handler(padapter, precv_frame->u.hdr.rx_data, precv_frame->u.hdr.len) == _SUCCESS)
+ goto _recv_indicatepkt_drop;
+#endif
+
+#ifdef CONFIG_WAPI_SUPPORT
+ if (rtw_wapi_check_for_drop(padapter, precv_frame)) {
+ WAPI_TRACE(WAPI_ERR, "%s(): Rx Reorder Drop case!!\n", __func__);
+ goto _recv_indicatepkt_drop;
+ }
+#endif
+
+ skb = precv_frame->u.hdr.pkt;
+ if (!skb)
+ goto _recv_indicatepkt_drop;
+
+ skb->data = precv_frame->u.hdr.rx_data;
+
+ skb_set_tail_pointer(skb, precv_frame->u.hdr.len);
+
+ skb->len = precv_frame->u.hdr.len;
+
+
+ if (pattrib->eth_type == cpu_to_le16(0x888e))
+ RTW_INFO("recv eapol packet\n");
+
+#ifdef CONFIG_AUTO_AP_MODE
+ if (pattrib->eth_type == 0x8899) {
+ rtw_os_ksocket_send(padapter, precv_frame);
+
+ /* goto _recv_indicatepkt_drop; */
+ }
+#endif /* CONFIG_AUTO_AP_MODE */
+
+ /* TODO: move to core */
+ {
+ _pkt *pkt = skb;
+ struct ethhdr *etherhdr = (struct ethhdr *)pkt->data;
+ struct sta_info *sta = precv_frame->u.hdr.psta;
+
+ if (!sta)
+ goto bypass_session_tracker;
+
+ if (ntohs(etherhdr->h_proto) == ETH_P_IP) {
+ u8 *ip = pkt->data + 14;
+
+ if (GET_IPV4_PROTOCOL(ip) == 0x06 /* TCP */
+ && rtw_st_ctl_chk_reg_s_proto(&sta->st_ctl, 0x06))
+ check_reg_rule(sta, ip, padapter);
+ }
+bypass_session_tracker:
+ ;
+ }
+
+ rtw_os_recv_indicate_pkt(padapter, skb, pattrib);
+
+ precv_frame->u.hdr.pkt = NULL; /* pointers to NULL before rtw_free_recvframe() */
+
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+ return _SUCCESS;
+
+_recv_indicatepkt_drop:
+
+ /* enqueue back to free_recv_queue */
+ if (precv_frame)
+ rtw_free_recvframe(precv_frame, pfree_recv_queue);
+
+ DBG_COUNTER(padapter->rx_logs.os_indicate_err);
+
+ return _FAIL;
+}
+
+void rtw_os_read_port(_adapter *padapter, struct recv_buf *precvbuf)
+{
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ precvbuf->ref_cnt--;
+
+ /* free skb in recv_buf */
+ rtw_skb_free(precvbuf->pskb);
+
+ precvbuf->pskb = NULL;
+
+ if (precvbuf->irp_pending == false)
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+static void _rtw_reordering_ctrl_timeout_handler(void *FunctionContext)
+#else
+static void _rtw_reordering_ctrl_timeout_handler(struct timer_list *t)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)FunctionContext;
+#else
+ struct recv_reorder_ctrl *preorder_ctrl = from_timer(preorder_ctrl, t, reordering_ctrl_timer);
+#endif
+
+ rtw_reordering_ctrl_timeout_handler(preorder_ctrl);
+}
+
+void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
+{
+ _adapter *padapter = preorder_ctrl->padapter;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
+ _init_timer(&preorder_ctrl->reordering_ctrl_timer, padapter->pnetdev, _rtw_reordering_ctrl_timeout_handler, preorder_ctrl);
+#else
+ timer_setup(&preorder_ctrl->reordering_ctrl_timer, _rtw_reordering_ctrl_timeout_handler, 0);
+#endif
+
+}
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_android.c b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
new file mode 100644
index 000000000000..5c55717c1b5a
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_android.c
@@ -0,0 +1,1250 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+
+#ifdef CONFIG_GPIO_WAKEUP
+#include <linux/gpio.h>
+#endif
+
+#include <drv_types.h>
+
+#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
+#include <linux/platform_device.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ #include <linux/wlan_plat.h>
+#else
+ #include <linux/wifi_tiwlan.h>
+#endif
+#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#define strnicmp strncasecmp
+#endif /* Linux kernel >= 4.0.0 */
+
+#ifdef CONFIG_GPIO_WAKEUP
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#endif
+
+#include "rtw_version.h"
+
+extern void macstr2num(u8 *dst, u8 *src);
+
+static const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
+ "START",
+ "STOP",
+ "SCAN-ACTIVE",
+ "SCAN-PASSIVE",
+ "RSSI",
+ "LINKSPEED",
+ "RXFILTER-START",
+ "RXFILTER-STOP",
+ "RXFILTER-ADD",
+ "RXFILTER-REMOVE",
+ "BTCOEXSCAN-START",
+ "BTCOEXSCAN-STOP",
+ "BTCOEXMODE",
+ "SETSUSPENDOPT",
+ "P2P_DEV_ADDR",
+ "SETFWPATH",
+ "SETBAND",
+ "GETBAND",
+ "COUNTRY",
+ "P2P_SET_NOA",
+ "P2P_GET_NOA",
+ "P2P_SET_PS",
+ "SET_AP_WPS_P2P_IE",
+
+ "MIRACAST",
+
+#ifdef CONFIG_PNO_SUPPORT
+ "PNOSSIDCLR",
+ "PNOSETUP",
+ "PNOFORCE",
+ "PNODEBUG",
+#endif
+
+ "MACADDR",
+
+ "BLOCK_SCAN",
+ "BLOCK",
+ "WFD-ENABLE",
+ "WFD-DISABLE",
+ "WFD-SET-TCPPORT",
+ "WFD-SET-MAXTPUT",
+ "WFD-SET-DEVTYPE",
+ "SET_DTIM",
+ "HOSTAPD_SET_MACADDR_ACL",
+ "HOSTAPD_ACL_ADD_STA",
+ "HOSTAPD_ACL_REMOVE_STA",
+#if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0))
+ "GTK_REKEY_OFFLOAD",
+#endif /* CONFIG_GTK_OL */
+/* Private command for P2P disable*/
+ "P2P_DISABLE",
+ "DRIVER_VERSION"
+};
+
+#ifdef CONFIG_PNO_SUPPORT
+#define PNO_TLV_PREFIX 'S'
+#define PNO_TLV_VERSION '1'
+#define PNO_TLV_SUBVERSION '2'
+#define PNO_TLV_RESERVED '0'
+#define PNO_TLV_TYPE_SSID_IE 'S'
+#define PNO_TLV_TYPE_TIME 'T'
+#define PNO_TLV_FREQ_REPEAT 'R'
+#define PNO_TLV_FREQ_EXPO_MAX 'M'
+
+typedef struct cmd_tlv {
+ char prefix;
+ char version;
+ char subver;
+ char reserved;
+} cmd_tlv_t;
+
+#ifdef CONFIG_PNO_SET_DEBUG
+char pno_in_example[] = {
+ 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
+ 'S', '1', '2', '0',
+ 'S', /* 1 */
+ 0x05,
+ 'd', 'l', 'i', 'n', 'k',
+ 'S', /* 2 */
+ 0x06,
+ 'B', 'U', 'F', 'B', 'U', 'F',
+ 'S', /* 3 */
+ 0x20,
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '!', '@', '#', '$', '%', '^',
+ 'S', /* 4 */
+ 0x0a,
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ 'T',
+ '0', '5',
+ 'R',
+ '2',
+ 'M',
+ '2',
+ 0x00
+};
+#endif /* CONFIG_PNO_SET_DEBUG */
+#endif /* PNO_SUPPORT */
+
+typedef struct android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+#ifdef CONFIG_COMPAT
+typedef struct compat_android_wifi_priv_cmd {
+ compat_uptr_t buf;
+ int used_len;
+ int total_len;
+} compat_android_wifi_priv_cmd;
+#endif /* CONFIG_COMPAT */
+
+/**
+ * Local (static) functions and variables
+ */
+
+/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
+ * time (only) in dhd_open, subsequential wifi on will be handled by
+ * wl_android_wifi_on
+ */
+static int g_wifi_on = true;
+
+static unsigned int oob_irq = 0;
+static unsigned int oob_gpio = 0;
+
+#ifdef CONFIG_PNO_SUPPORT
+/*
+ * rtw_android_pno_setup
+ * Description:
+ * This is used for private command.
+ *
+ * Parameter:
+ * net: net_device
+ * command: parameters from private command
+ * total_len: the length of the command.
+ *
+ * */
+static int rtw_android_pno_setup(struct net_device *net, char *command, int total_len)
+{
+ pno_ssid_t pno_ssids_local[MAX_PNO_LIST_COUNT];
+ int res = -1;
+ int nssid = 0;
+ cmd_tlv_t *cmd_tlv_temp;
+ char *str_ptr;
+ int tlv_size_left;
+ int pno_time = 0;
+ int pno_repeat = 0;
+ int pno_freq_expo_max = 0;
+ int cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOSETUP_SET]) + 1;
+
+#ifdef CONFIG_PNO_SET_DEBUG
+ int i;
+ char *p;
+ p = pno_in_example;
+
+ total_len = sizeof(pno_in_example);
+ str_ptr = p + cmdlen;
+#else
+ str_ptr = command + cmdlen;
+#endif
+
+ if (total_len < (cmdlen + sizeof(cmd_tlv_t))) {
+ RTW_INFO("%s argument=%d less min size\n", __func__, total_len);
+ goto exit_proc;
+ }
+
+ tlv_size_left = total_len - cmdlen;
+
+ cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
+ memset(pno_ssids_local, 0, sizeof(pno_ssids_local));
+
+ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
+ (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
+ (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
+
+ str_ptr += sizeof(cmd_tlv_t);
+ tlv_size_left -= sizeof(cmd_tlv_t);
+
+ nssid = rtw_parse_ssid_list_tlv(&str_ptr, pno_ssids_local,
+ MAX_PNO_LIST_COUNT, &tlv_size_left);
+ if (nssid <= 0) {
+ RTW_INFO("SSID is not presented or corrupted ret=%d\n", nssid);
+ goto exit_proc;
+ } else {
+ if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
+ RTW_INFO("%s scan duration corrupted field size %d\n",
+ __func__, tlv_size_left);
+ goto exit_proc;
+ }
+ str_ptr++;
+ pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
+ RTW_INFO("%s: pno_time=%d\n", __func__, pno_time);
+
+ if (str_ptr[0] != 0) {
+ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
+ RTW_INFO("%s pno repeat : corrupted field\n",
+ __func__);
+ goto exit_proc;
+ }
+ str_ptr++;
+ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
+ RTW_INFO("%s :got pno_repeat=%d\n", __func__, pno_repeat);
+ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
+ RTW_INFO("%s FREQ_EXPO_MAX corrupted field size\n",
+ __func__);
+ goto exit_proc;
+ }
+ str_ptr++;
+ pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
+ RTW_INFO("%s: pno_freq_expo_max=%d\n",
+ __func__, pno_freq_expo_max);
+ }
+ }
+ } else {
+ RTW_INFO("%s get wrong TLV command\n", __func__);
+ goto exit_proc;
+ }
+
+ res = rtw_dev_pno_set(net, pno_ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
+
+#ifdef CONFIG_PNO_SET_DEBUG
+ rtw_dev_pno_debug(net);
+#endif
+
+exit_proc:
+ return res;
+}
+
+/*
+ * rtw_android_cfg80211_pno_setup
+ * Description:
+ * This is used for cfg80211 sched_scan.
+ *
+ * Parameter:
+ * net: net_device
+ * request: cfg80211_request
+ * */
+
+int rtw_android_cfg80211_pno_setup(struct net_device *net,
+ struct cfg80211_ssid *ssids, int n_ssids, int interval)
+{
+ int res = -1;
+ int nssid = 0;
+ int pno_time = 0;
+ int pno_repeat = 0;
+ int pno_freq_expo_max = 0;
+ int index = 0;
+ pno_ssid_t pno_ssids_local[MAX_PNO_LIST_COUNT];
+
+ if (n_ssids > MAX_PNO_LIST_COUNT || n_ssids < 0) {
+ RTW_INFO("%s: nssids(%d) is invalid.\n", __func__, n_ssids);
+ return -EINVAL;
+ }
+
+ memset(pno_ssids_local, 0, sizeof(pno_ssids_local));
+
+ nssid = n_ssids;
+
+ for (index = 0 ; index < nssid ; index++) {
+ pno_ssids_local[index].SSID_len = ssids[index].ssid_len;
+ memcpy(pno_ssids_local[index].SSID, ssids[index].ssid,
+ ssids[index].ssid_len);
+ }
+
+ pno_time = (interval / 1000);
+
+ RTW_INFO("%s: nssids: %d, pno_time=%d\n", __func__, nssid, pno_time);
+
+ res = rtw_dev_pno_set(net, pno_ssids_local, nssid, pno_time,
+ pno_repeat, pno_freq_expo_max);
+
+#ifdef CONFIG_PNO_SET_DEBUG
+ rtw_dev_pno_debug(net);
+#endif
+exit_proc:
+ return res;
+}
+
+int rtw_android_pno_enable(struct net_device *net, int pno_enable)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
+ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
+
+ if (pwrctl) {
+ pwrctl->wowlan_pno_enable = pno_enable;
+ RTW_INFO("%s: wowlan_pno_enable: %d\n", __func__, pwrctl->wowlan_pno_enable);
+ if (pwrctl->wowlan_pno_enable == 0) {
+ if (pwrctl->pnlo_info != NULL) {
+ rtw_mfree((u8 *)pwrctl->pnlo_info, sizeof(pno_nlo_info_t));
+ pwrctl->pnlo_info = NULL;
+ }
+ if (pwrctl->pno_ssid_list != NULL) {
+ rtw_mfree((u8 *)pwrctl->pno_ssid_list, sizeof(pno_ssid_list_t));
+ pwrctl->pno_ssid_list = NULL;
+ }
+ if (pwrctl->pscan_info != NULL) {
+ rtw_mfree((u8 *)pwrctl->pscan_info, sizeof(pno_scan_info_t));
+ pwrctl->pscan_info = NULL;
+ }
+ }
+ return 0;
+ } else
+ return -1;
+}
+#endif /* CONFIG_PNO_SUPPORT */
+
+int rtw_android_cmdstr_to_num(char *cmdstr)
+{
+ int cmd_num;
+ for (cmd_num = 0 ; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
+ if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])))
+ break;
+
+ return cmd_num;
+}
+
+static int rtw_android_get_rssi(struct net_device *net, char *command, int total_len)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_network *pcur_network = &pmlmepriv->cur_network;
+ int bytes_written = 0;
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+ bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d",
+ pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
+ }
+
+ return bytes_written;
+}
+
+static int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct wlan_network *pcur_network = &pmlmepriv->cur_network;
+ int bytes_written = 0;
+ u16 link_speed = 0;
+
+ link_speed = rtw_get_cur_max_rate(padapter) / 10;
+ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
+
+ return bytes_written;
+}
+
+static int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ int bytes_written = 0;
+
+ bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr));
+ return bytes_written;
+}
+
+static int rtw_android_set_country(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
+ int ret = _FAIL;
+
+ ret = rtw_set_country(adapter, country_code);
+
+ return (ret == _SUCCESS) ? 0 : -1;
+}
+
+static int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len)
+{
+ int bytes_written = 0;
+
+ /* We use the same address as our HW MAC address */
+ memcpy(command, net->dev_addr, ETH_ALEN);
+
+ bytes_written = ETH_ALEN;
+ return bytes_written;
+}
+
+static int rtw_android_set_block_scan(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK_SCAN]) + 1;
+
+#ifdef CONFIG_IOCTL_CFG80211
+ adapter_wdev_data(adapter)->block_scan = (*block_value == '0') ? false : true;
+#endif
+
+ return 0;
+}
+
+static int rtw_android_set_block(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1;
+
+#ifdef CONFIG_IOCTL_CFG80211
+ adapter_wdev_data(adapter)->block = (*block_value == '0') ? false : true;
+#endif
+
+ return 0;
+}
+
+static int rtw_android_setband(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ char *arg = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SETBAND]) + 1;
+ u32 band = WIFI_FREQUENCY_BAND_AUTO;
+ int ret = _FAIL;
+
+ if (sscanf(arg, "%u", &band) >= 1)
+ ret = rtw_set_band(adapter, band);
+
+ return (ret == _SUCCESS) ? 0 : -1;
+}
+
+static int rtw_android_getband(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ int bytes_written = 0;
+
+ bytes_written = snprintf(command, total_len, "%u", adapter->setband);
+
+ return bytes_written;
+}
+
+#ifdef CONFIG_WFD
+static int rtw_android_set_miracast_mode(struct net_device *net, char *command, int total_len)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
+ struct wifi_display_info *wfd_info = &adapter->wfd_info;
+ char *arg = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_MIRACAST]) + 1;
+ u8 mode;
+ int num;
+ int ret = _FAIL;
+
+ num = sscanf(arg, "%hhu", &mode);
+
+ if (num < 1)
+ goto exit;
+
+ switch (mode) {
+ case 1: /* soruce */
+ mode = MIRACAST_SOURCE;
+ break;
+ case 2: /* sink */
+ mode = MIRACAST_SINK;
+ break;
+ case 0: /* disabled */
+ default:
+ mode = MIRACAST_DISABLED;
+ break;
+ }
+ wfd_info->stack_wfd_mode = mode;
+ RTW_INFO("stack miracast mode: %s\n", get_miracast_mode_str(wfd_info->stack_wfd_mode));
+
+ ret = _SUCCESS;
+
+exit:
+ return (ret == _SUCCESS) ? 0 : -1;
+}
+#endif /* CONFIG_WFD */
+
+static int get_int_from_command(char *pcmd)
+{
+ int i = 0;
+
+ for (i = 0; i < strlen(pcmd); i++) {
+ if (pcmd[i] == '=') {
+ /* Skip the '=' and space characters. */
+ i += 2;
+ break;
+ }
+ }
+ return rtw_atoi(pcmd + i) ;
+}
+
+#if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0))
+int rtw_gtk_offload(struct net_device *net, u8 *cmd_ptr)
+{
+ int i;
+ /* u8 *cmd_ptr = priv_cmd.buf; */
+ struct sta_info *psta;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
+
+
+ if (psta == NULL)
+ RTW_INFO("%s, : Obtain Sta_info fail\n", __func__);
+ else {
+ /* string command length of "GTK_REKEY_OFFLOAD" */
+ cmd_ptr += 18;
+
+ memcpy(psta->kek, cmd_ptr, RTW_KEK_LEN);
+ cmd_ptr += RTW_KEK_LEN;
+ /*
+ printk("supplicant KEK: ");
+ for(i=0;i<RTW_KEK_LEN; i++)
+ printk(" %02x ", psta->kek[i]);
+ printk("\n supplicant KCK: ");
+ */
+ memcpy(psta->kck, cmd_ptr, RTW_KCK_LEN);
+ cmd_ptr += RTW_KCK_LEN;
+ /*
+ for(i=0;i<RTW_KEK_LEN; i++)
+ printk(" %02x ", psta->kck[i]);
+ */
+ memcpy(psta->replay_ctr, cmd_ptr, RTW_REPLAY_CTR_LEN);
+ psecuritypriv->binstallKCK_KEK = true;
+
+ /* printk("\nREPLAY_CTR: "); */
+ /* for(i=0;i<RTW_REPLAY_CTR_LEN; i++) */
+ /* printk(" %02x ", psta->replay_ctr[i]); */
+ }
+
+ return _SUCCESS;
+}
+#endif /* CONFIG_GTK_OL */
+
+int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+ int ret = 0;
+ char *command = NULL;
+ int cmd_num;
+ int bytes_written = 0;
+#ifdef CONFIG_PNO_SUPPORT
+ uint cmdlen = 0;
+ uint pno_enable = 0;
+#endif
+ android_wifi_priv_cmd priv_cmd;
+ _adapter *padapter = (_adapter *) rtw_netdev_priv(net);
+#ifdef CONFIG_WFD
+ struct wifi_display_info *pwfd_info;
+#endif
+
+ rtw_lock_suspend();
+
+ if (!ifr->ifr_data) {
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (padapter->registrypriv.mp_mode == 1) {
+ ret = -EINVAL;
+ goto exit;
+ }
+#ifdef CONFIG_COMPAT
+#if (KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE)
+ if (is_compat_task()) {
+#else
+ if (in_compat_syscall()) {
+#endif
+ /* User space is 32-bit, use compat ioctl */
+ compat_android_wifi_priv_cmd compat_priv_cmd;
+
+ if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, sizeof(compat_android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
+ priv_cmd.used_len = compat_priv_cmd.used_len;
+ priv_cmd.total_len = compat_priv_cmd.total_len;
+ } else
+#endif /* CONFIG_COMPAT */
+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ if (padapter->registrypriv.mp_mode == 1) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ /*RTW_INFO("%s priv_cmd.buf=%p priv_cmd.total_len=%d priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);*/
+ command = rtw_zmalloc(priv_cmd.total_len);
+ if (!command) {
+ RTW_INFO("%s: failed to allocate memory\n", __func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
+ if (!access_ok(priv_cmd.buf, priv_cmd.total_len)) {
+#else
+ if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)) {
+#endif
+ RTW_DBG("%s: failed to access memory\n", __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+ if (copy_from_user(command, (void __user *)priv_cmd.buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ RTW_INFO("%s: Android private cmd \"%s\" on %s\n"
+ , __func__, command, ifr->ifr_name);
+
+ cmd_num = rtw_android_cmdstr_to_num(command);
+
+ switch (cmd_num) {
+ case ANDROID_WIFI_CMD_START:
+ /* bytes_written = wl_android_wifi_on(net); */
+ goto response;
+ case ANDROID_WIFI_CMD_SETFWPATH:
+ goto response;
+ }
+
+ if (!g_wifi_on) {
+ RTW_INFO("%s: Ignore private cmd \"%s\" - iface %s is down\n"
+ , __func__, command, ifr->ifr_name);
+ ret = 0;
+ goto exit;
+ }
+
+ if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
+ switch (cmd_num) {
+ case ANDROID_WIFI_CMD_WFD_ENABLE:
+ case ANDROID_WIFI_CMD_WFD_DISABLE:
+ case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
+ case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
+ case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
+ goto response;
+ }
+ }
+
+ switch (cmd_num) {
+
+ case ANDROID_WIFI_CMD_STOP:
+ /* bytes_written = wl_android_wifi_off(net); */
+ break;
+
+ case ANDROID_WIFI_CMD_SCAN_ACTIVE:
+ /* rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE); */
+#ifdef CONFIG_PLATFORM_MSTAR
+#ifdef CONFIG_IOCTL_CFG80211
+ adapter_wdev_data((_adapter *)rtw_netdev_priv(net))->bandroid_scan = true;
+#endif /* CONFIG_IOCTL_CFG80211 */
+#endif /* CONFIG_PLATFORM_MSTAR */
+ break;
+ case ANDROID_WIFI_CMD_SCAN_PASSIVE:
+ /* rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE); */
+ break;
+
+ case ANDROID_WIFI_CMD_RSSI:
+ bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_LINKSPEED:
+ bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_MACADDR:
+ bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_BLOCK_SCAN:
+ bytes_written = rtw_android_set_block_scan(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_BLOCK:
+ bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_RXFILTER_START:
+ /* bytes_written = net_os_set_packet_filter(net, 1); */
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_STOP:
+ /* bytes_written = net_os_set_packet_filter(net, 0); */
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_ADD:
+ /* int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; */
+ /* bytes_written = net_os_rxfilter_add_remove(net, true, filter_num); */
+ break;
+ case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
+ /* int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; */
+ /* bytes_written = net_os_rxfilter_add_remove(net, false, filter_num); */
+ break;
+
+ case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
+ /* TBD: BTCOEXSCAN-START */
+ break;
+ case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
+ /* TBD: BTCOEXSCAN-STOP */
+ break;
+ case ANDROID_WIFI_CMD_BTCOEXMODE:
+ break;
+ case ANDROID_WIFI_CMD_SETSUSPENDOPT:
+ /* bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); */
+ break;
+
+ case ANDROID_WIFI_CMD_SETBAND:
+ bytes_written = rtw_android_setband(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_GETBAND:
+ bytes_written = rtw_android_getband(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_COUNTRY:
+ bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
+ break;
+
+#ifdef CONFIG_PNO_SUPPORT
+ case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
+ /* bytes_written = dhd_dev_pno_reset(net); */
+ break;
+ case ANDROID_WIFI_CMD_PNOSETUP_SET:
+ bytes_written = rtw_android_pno_setup(net, command, priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_PNOENABLE_SET:
+ cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOENABLE_SET]);
+ pno_enable = *(command + cmdlen + 1) - '0';
+ bytes_written = rtw_android_pno_enable(net, pno_enable);
+ break;
+#endif
+
+ case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
+ bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
+ break;
+ case ANDROID_WIFI_CMD_P2P_SET_NOA:
+ /* int skip = strlen(CMD_P2P_SET_NOA) + 1; */
+ /* bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); */
+ break;
+ case ANDROID_WIFI_CMD_P2P_GET_NOA:
+ /* bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); */
+ break;
+ case ANDROID_WIFI_CMD_P2P_SET_PS:
+ /* int skip = strlen(CMD_P2P_SET_PS) + 1; */
+ /* bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip); */
+ break;
+
+#ifdef CONFIG_IOCTL_CFG80211
+ case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE: {
+ int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
+ bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
+ break;
+ }
+#endif /* CONFIG_IOCTL_CFG80211 */
+
+#ifdef CONFIG_WFD
+
+ case ANDROID_WIFI_CMD_MIRACAST:
+ bytes_written = rtw_android_set_miracast_mode(net, command, priv_cmd.total_len);
+ break;
+
+ case ANDROID_WIFI_CMD_WFD_ENABLE: {
+ /* Commented by Albert 2012/07/24 */
+ /* We can enable the WFD function by using the following command: */
+ /* wpa_cli driver wfd-enable */
+
+ if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
+ rtw_wfd_enable(padapter, 1);
+ break;
+ }
+
+ case ANDROID_WIFI_CMD_WFD_DISABLE: {
+ /* Commented by Albert 2012/07/24 */
+ /* We can disable the WFD function by using the following command: */
+ /* wpa_cli driver wfd-disable */
+
+ if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
+ rtw_wfd_enable(padapter, 0);
+ break;
+ }
+ case ANDROID_WIFI_CMD_WFD_SET_TCPPORT: {
+ /* Commented by Albert 2012/07/24 */
+ /* We can set the tcp port number by using the following command: */
+ /* wpa_cli driver wfd-set-tcpport = 554 */
+
+ if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
+ rtw_wfd_set_ctrl_port(padapter, (u16)get_int_from_command(priv_cmd.buf));
+ break;
+ }
+ case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT: {
+ break;
+ }
+ case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE: {
+ /* Commented by Albert 2012/08/28 */
+ /* Specify the WFD device type ( WFD source/primary sink ) */
+
+ pwfd_info = &padapter->wfd_info;
+ if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) {
+ pwfd_info->wfd_device_type = (u8) get_int_from_command(priv_cmd.buf);
+ pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
+ }
+ break;
+ }
+#endif
+ case ANDROID_WIFI_CMD_CHANGE_DTIM: {
+#ifdef CONFIG_LPS
+ u8 dtim;
+ u8 *ptr = (u8 *) &priv_cmd.buf;
+
+ ptr += 9;/* string command length of "SET_DTIM"; */
+
+ dtim = rtw_atoi(ptr);
+
+ RTW_INFO("DTIM=%d\n", dtim);
+
+ rtw_lps_change_dtim_cmd(padapter, dtim);
+#endif
+ }
+ break;
+
+#if CONFIG_RTW_MACADDR_ACL
+ case ANDROID_WIFI_CMD_HOSTAPD_SET_MACADDR_ACL: {
+ rtw_set_macaddr_acl(padapter, get_int_from_command(command));
+ break;
+ }
+ case ANDROID_WIFI_CMD_HOSTAPD_ACL_ADD_STA: {
+ u8 addr[ETH_ALEN] = {0x00};
+ macstr2num(addr, command + strlen("HOSTAPD_ACL_ADD_STA") + 3); /* 3 is space bar + "=" + space bar these 3 chars */
+ rtw_acl_add_sta(padapter, addr);
+ break;
+ }
+ case ANDROID_WIFI_CMD_HOSTAPD_ACL_REMOVE_STA: {
+ u8 addr[ETH_ALEN] = {0x00};
+ macstr2num(addr, command + strlen("HOSTAPD_ACL_REMOVE_STA") + 3); /* 3 is space bar + "=" + space bar these 3 chars */
+ rtw_acl_remove_sta(padapter, addr);
+ break;
+ }
+#endif /* CONFIG_RTW_MACADDR_ACL */
+#if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0))
+ case ANDROID_WIFI_CMD_GTK_REKEY_OFFLOAD:
+ rtw_gtk_offload(net, (u8 *)command);
+ break;
+#endif /* CONFIG_GTK_OL */
+ case ANDROID_WIFI_CMD_P2P_DISABLE: {
+#ifdef CONFIG_P2P
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ u8 channel, ch_offset;
+ u16 bwmode;
+
+ rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
+#endif /* CONFIG_P2P */
+ break;
+ }
+ case ANDROID_WIFI_CMD_DRIVERVERSION: {
+ bytes_written = strlen(DRIVERVERSION);
+ snprintf(command, bytes_written + 1, DRIVERVERSION);
+ break;
+ }
+ default:
+ RTW_INFO("Unknown PRIVATE command %s - ignored\n", command);
+ snprintf(command, 3, "OK");
+ bytes_written = strlen("OK");
+ }
+
+response:
+ if (bytes_written >= 0) {
+ if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+ command[0] = '\0';
+ if (bytes_written >= priv_cmd.total_len) {
+ RTW_INFO("%s: bytes_written = %d\n", __func__, bytes_written);
+ bytes_written = priv_cmd.total_len;
+ } else
+ bytes_written++;
+ priv_cmd.used_len = bytes_written;
+ if (copy_to_user((void __user *)priv_cmd.buf, command, bytes_written)) {
+ RTW_INFO("%s: failed to copy data to user buffer\n", __func__);
+ ret = -EFAULT;
+ }
+ } else
+ ret = bytes_written;
+
+exit:
+ rtw_unlock_suspend();
+ if (command)
+ rtw_mfree(command, priv_cmd.total_len);
+
+ return ret;
+}
+
+
+/**
+ * Functions for Android WiFi card detection
+ */
+#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
+
+static int g_wifidev_registered = 0;
+static struct semaphore wifi_control_sem;
+static struct wifi_platform_data *wifi_control_data = NULL;
+static struct resource *wifi_irqres = NULL;
+
+static int wifi_add_dev(void);
+static void wifi_del_dev(void);
+
+int rtw_android_wifictrl_func_add(void)
+{
+ int ret = 0;
+ sema_init(&wifi_control_sem, 0);
+
+ ret = wifi_add_dev();
+ if (ret) {
+ RTW_INFO("%s: platform_driver_register failed\n", __func__);
+ return ret;
+ }
+ g_wifidev_registered = 1;
+
+ /* Waiting callback after platform_driver_register is done or exit with error */
+ if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) {
+ ret = -EINVAL;
+ RTW_INFO("%s: platform_driver_register timeout\n", __func__);
+ }
+
+ return ret;
+}
+
+void rtw_android_wifictrl_func_del(void)
+{
+ if (g_wifidev_registered) {
+ wifi_del_dev();
+ g_wifidev_registered = 0;
+ }
+}
+
+void *wl_android_prealloc(int section, unsigned long size)
+{
+ void *alloc_ptr = NULL;
+ if (wifi_control_data && wifi_control_data->mem_prealloc) {
+ alloc_ptr = wifi_control_data->mem_prealloc(section, size);
+ if (alloc_ptr) {
+ RTW_INFO("success alloc section %d\n", section);
+ if (size != 0L)
+ memset(alloc_ptr, 0, size);
+ return alloc_ptr;
+ }
+ }
+
+ RTW_INFO("can't alloc section %d\n", section);
+ return NULL;
+}
+
+int wifi_get_irq_number(unsigned long *irq_flags_ptr)
+{
+ if (wifi_irqres) {
+ *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
+ return (int)wifi_irqres->start;
+ }
+#ifdef CUSTOM_OOB_GPIO_NUM
+ return CUSTOM_OOB_GPIO_NUM;
+#else
+ return -1;
+#endif
+}
+
+int wifi_set_power(int on, unsigned long msec)
+{
+ RTW_INFO("%s = %d\n", __func__, on);
+ if (wifi_control_data && wifi_control_data->set_power)
+ wifi_control_data->set_power(on);
+ if (msec)
+ msleep(msec);
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+int wifi_get_mac_addr(unsigned char *buf)
+{
+ RTW_INFO("%s\n", __func__);
+ if (!buf)
+ return -EINVAL;
+ if (wifi_control_data && wifi_control_data->get_mac_addr)
+ return wifi_control_data->get_mac_addr(buf);
+ return -EOPNOTSUPP;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE)
+void *wifi_get_country_code(char *ccode)
+{
+ RTW_INFO("%s\n", __func__);
+ if (!ccode)
+ return NULL;
+ if (wifi_control_data && wifi_control_data->get_country_code)
+ return wifi_control_data->get_country_code(ccode);
+ return NULL;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
+
+static int wifi_set_carddetect(int on)
+{
+ RTW_INFO("%s = %d\n", __func__, on);
+ if (wifi_control_data && wifi_control_data->set_carddetect)
+ wifi_control_data->set_carddetect(on);
+ return 0;
+}
+
+static int wifi_probe(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
+ int wifi_wake_gpio = 0;
+
+ RTW_INFO("## %s\n", __func__);
+ wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
+
+ if (wifi_irqres == NULL)
+ wifi_irqres = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "bcm4329_wlan_irq");
+ else
+ wifi_wake_gpio = wifi_irqres->start;
+
+#ifdef CONFIG_GPIO_WAKEUP
+ printk("%s: gpio:%d wifi_wake_gpio:%d\n", __func__,
+ wifi_irqres->start, wifi_wake_gpio);
+
+ if (wifi_wake_gpio > 0) {
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+ wifi_configure_gpio();
+#else /* CONFIG_PLATFORM_INTEL_BYT */
+ gpio_request(wifi_wake_gpio, "oob_irq");
+ gpio_direction_input(wifi_wake_gpio);
+ oob_irq = gpio_to_irq(wifi_wake_gpio);
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+ printk("%s oob_irq:%d\n", __func__, oob_irq);
+ } else if (wifi_irqres) {
+ oob_irq = wifi_irqres->start;
+ printk("%s oob_irq:%d\n", __func__, oob_irq);
+ }
+#endif
+ wifi_control_data = wifi_ctrl;
+
+ wifi_set_power(1, 0); /* Power On */
+ wifi_set_carddetect(1); /* CardDetect (0->1) */
+
+ up(&wifi_control_sem);
+ return 0;
+}
+
+#ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
+extern PADAPTER g_test_adapter;
+
+static void shutdown_card(void)
+{
+ u32 addr;
+ u8 tmp8, cnt = 0;
+
+ if (NULL == g_test_adapter) {
+ RTW_INFO("%s: padapter==NULL\n", __func__);
+ return;
+ }
+
+#ifdef CONFIG_FWLPS_IN_IPS
+ LeaveAllPowerSaveMode(g_test_adapter);
+#endif /* CONFIG_FWLPS_IN_IPS */
+
+ /* Leave SDIO HCI Suspend */
+ addr = 0x10250086;
+ rtw_write8(g_test_adapter, addr, 0);
+ do {
+ tmp8 = rtw_read8(g_test_adapter, addr);
+ cnt++;
+ RTW_INFO(FUNC_ADPT_FMT ": polling SDIO_HSUS_CTRL(0x%x)=0x%x, cnt=%d\n",
+ FUNC_ADPT_ARG(g_test_adapter), addr, tmp8, cnt);
+
+ if (tmp8 & BIT(1))
+ break;
+
+ if (cnt >= 100) {
+ RTW_INFO(FUNC_ADPT_FMT ": polling 0x%x[1]==1 FAIL!!\n",
+ FUNC_ADPT_ARG(g_test_adapter), addr);
+ break;
+ }
+
+ rtw_mdelay_os(10);
+ } while (1);
+
+ /* unlock register I/O */
+ rtw_write8(g_test_adapter, 0x1C, 0);
+
+ /* enable power down function */
+ /* 0x04[4] = 1 */
+ /* 0x05[7] = 1 */
+ addr = 0x04;
+ tmp8 = rtw_read8(g_test_adapter, addr);
+ tmp8 |= BIT(4);
+ rtw_write8(g_test_adapter, addr, tmp8);
+ RTW_INFO(FUNC_ADPT_FMT ": read after write 0x%x=0x%x\n",
+ FUNC_ADPT_ARG(g_test_adapter), addr, rtw_read8(g_test_adapter, addr));
+
+ addr = 0x05;
+ tmp8 = rtw_read8(g_test_adapter, addr);
+ tmp8 |= BIT(7);
+ rtw_write8(g_test_adapter, addr, tmp8);
+ RTW_INFO(FUNC_ADPT_FMT ": read after write 0x%x=0x%x\n",
+ FUNC_ADPT_ARG(g_test_adapter), addr, rtw_read8(g_test_adapter, addr));
+
+ /* lock register page0 0x0~0xB read/write */
+ rtw_write8(g_test_adapter, 0x1C, 0x0E);
+
+ rtw_set_surprise_removed(g_test_adapter);
+ RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s\n",
+ FUNC_ADPT_ARG(g_test_adapter), rtw_is_surprise_removed(g_test_adapter) ? "True" : "False");
+}
+#endif /* RTW_SUPPORT_PLATFORM_SHUTDOWN */
+
+static int wifi_remove(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+ RTW_INFO("## %s\n", __func__);
+ wifi_control_data = wifi_ctrl;
+
+ wifi_set_power(0, 0); /* Power Off */
+ wifi_set_carddetect(0); /* CardDetect (1->0) */
+
+ up(&wifi_control_sem);
+ return 0;
+}
+
+#ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
+static void wifi_shutdown(struct platform_device *pdev)
+{
+ struct wifi_platform_data *wifi_ctrl =
+ (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+
+ RTW_INFO("## %s\n", __func__);
+
+ wifi_control_data = wifi_ctrl;
+
+ shutdown_card();
+ wifi_set_power(0, 0); /* Power Off */
+ wifi_set_carddetect(0); /* CardDetect (1->0) */
+}
+#endif /* RTW_SUPPORT_PLATFORM_SHUTDOWN */
+
+static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ RTW_INFO("##> %s\n", __func__);
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+ bcmsdh_oob_intr_set(0);
+#endif
+ return 0;
+}
+
+static int wifi_resume(struct platform_device *pdev)
+{
+ RTW_INFO("##> %s\n", __func__);
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+ if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
+ bcmsdh_oob_intr_set(1);
+#endif
+ return 0;
+}
+
+/* temporarily use these two */
+static struct platform_driver wifi_device = {
+ .probe = wifi_probe,
+ .remove = wifi_remove,
+ .suspend = wifi_suspend,
+ .resume = wifi_resume,
+#ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
+ .shutdown = wifi_shutdown,
+#endif /* RTW_SUPPORT_PLATFORM_SHUTDOWN */
+ .driver = {
+ .name = "bcmdhd_wlan",
+ }
+};
+
+static struct platform_driver wifi_device_legacy = {
+ .probe = wifi_probe,
+ .remove = wifi_remove,
+ .suspend = wifi_suspend,
+ .resume = wifi_resume,
+ .driver = {
+ .name = "bcm4329_wlan",
+ }
+};
+
+static int wifi_add_dev(void)
+{
+ RTW_INFO("## Calling platform_driver_register\n");
+ platform_driver_register(&wifi_device);
+ platform_driver_register(&wifi_device_legacy);
+ return 0;
+}
+
+static void wifi_del_dev(void)
+{
+ RTW_INFO("## Unregister platform_driver_register\n");
+ platform_driver_unregister(&wifi_device);
+ platform_driver_unregister(&wifi_device_legacy);
+}
+#endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
+
+#ifdef CONFIG_GPIO_WAKEUP
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+int wifi_configure_gpio(void)
+{
+ if (gpio_request(oob_gpio, "oob_irq")) {
+ RTW_INFO("## %s Cannot request GPIO\n", __func__);
+ return -1;
+ }
+ gpio_export(oob_gpio, 0);
+ if (gpio_direction_input(oob_gpio)) {
+ RTW_INFO("## %s Cannot set GPIO direction input\n", __func__);
+ return -1;
+ }
+ oob_irq = gpio_to_irq(oob_gpio);
+ if (oob_irq < 0) {
+ RTW_INFO("## %s Cannot convert GPIO to IRQ\n", __func__);
+ return -1;
+ }
+
+ RTW_INFO("## %s OOB_IRQ=%d\n", __func__, oob_irq);
+
+ return 0;
+}
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+void wifi_free_gpio(unsigned int gpio)
+{
+#ifdef CONFIG_PLATFORM_INTEL_BYT
+ if (gpio)
+ gpio_free(gpio);
+#endif /* CONFIG_PLATFORM_INTEL_BYT */
+}
+#endif /* CONFIG_GPIO_WAKEUP */
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.c b/drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.c
new file mode 100644
index 000000000000..8d18373c728c
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.c
@@ -0,0 +1,1330 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+
+#include <drv_types.h>
+
+#ifdef CONFIG_IOCTL_CFG80211
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT)
+
+/*
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/wait.h>
+#include <net/cfg80211.h>
+*/
+
+#include <net/rtnetlink.h>
+
+#ifdef DBG_MEM_ALLOC
+extern bool match_mstat_sniff_rules(const enum mstat_f flags, const size_t size);
+struct sk_buff *dbg_rtw_cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev, int len, int event_id, gfp_t gfp
+ , const enum mstat_f flags, const char *func, const int line)
+{
+ struct sk_buff *skb;
+ unsigned int truesize = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
+ skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, wdev, len, event_id, gfp);
+#endif
+
+ if (skb)
+ truesize = skb->truesize;
+
+ if (!skb || truesize < len || match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d), skb:%p, truesize=%u\n", func, line, __func__, len, skb, truesize);
+
+ rtw_mstat_update(
+ flags
+ , skb ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , truesize
+ );
+
+ return skb;
+}
+
+void dbg_rtw_cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp
+ , const enum mstat_f flags, const char *func, const int line)
+{
+ unsigned int truesize = skb->truesize;
+
+ if (match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __func__, truesize);
+
+ cfg80211_vendor_event(skb, gfp);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , truesize
+ );
+}
+
+struct sk_buff *dbg_rtw_cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int len
+ , const enum mstat_f flags, const char *func, const int line)
+{
+ struct sk_buff *skb;
+ unsigned int truesize = 0;
+
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+
+ if (skb)
+ truesize = skb->truesize;
+
+ if (!skb || truesize < len || match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s(%d), skb:%p, truesize=%u\n", func, line, __func__, len, skb, truesize);
+
+ rtw_mstat_update(
+ flags
+ , skb ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
+ , truesize
+ );
+
+ return skb;
+}
+
+int dbg_rtw_cfg80211_vendor_cmd_reply(struct sk_buff *skb
+ , const enum mstat_f flags, const char *func, const int line)
+{
+ unsigned int truesize = skb->truesize;
+ int ret;
+
+ if (match_mstat_sniff_rules(flags, truesize))
+ RTW_INFO("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __func__, truesize);
+
+ ret = cfg80211_vendor_cmd_reply(skb);
+
+ rtw_mstat_update(
+ flags
+ , MSTAT_FREE
+ , truesize
+ );
+
+ return ret;
+}
+
+#define rtw_cfg80211_vendor_event_alloc(wiphy, wdev, len, event_id, gfp) \
+ dbg_rtw_cfg80211_vendor_event_alloc(wiphy, wdev, len, event_id, gfp, MSTAT_FUNC_CFG_VENDOR | MSTAT_TYPE_SKB, __func__, __LINE__)
+
+#define rtw_cfg80211_vendor_event(skb, gfp) \
+ dbg_rtw_cfg80211_vendor_event(skb, gfp, MSTAT_FUNC_CFG_VENDOR | MSTAT_TYPE_SKB, __func__, __LINE__)
+
+#define rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len) \
+ dbg_rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len, MSTAT_FUNC_CFG_VENDOR | MSTAT_TYPE_SKB, __func__, __LINE__)
+
+#define rtw_cfg80211_vendor_cmd_reply(skb) \
+ dbg_rtw_cfg80211_vendor_cmd_reply(skb, MSTAT_FUNC_CFG_VENDOR | MSTAT_TYPE_SKB, __func__, __LINE__)
+#else
+
+static struct sk_buff *rtw_cfg80211_vendor_event_alloc(
+ struct wiphy *wiphy, struct wireless_dev *wdev, int len, int event_id, gfp_t gfp)
+{
+ struct sk_buff *skb;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0))
+ skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, wdev, len, event_id, gfp);
+#endif
+ return skb;
+}
+
+#define rtw_cfg80211_vendor_event(skb, gfp) \
+ cfg80211_vendor_event(skb, gfp)
+
+#define rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len) \
+ cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len)
+
+#define rtw_cfg80211_vendor_cmd_reply(skb) \
+ cfg80211_vendor_cmd_reply(skb)
+#endif /* DBG_MEM_ALLOC */
+
+/*
+ * This API is to be used for asynchronous vendor events. This
+ * shouldn't be used in response to a vendor command from its
+ * do_it handler context (instead rtw_cfgvendor_send_cmd_reply should
+ * be used).
+ */
+int rtw_cfgvendor_send_async_event(struct wiphy *wiphy,
+ struct net_device *dev, int event_id, const void *data, int len)
+{
+ gfp_t kflags;
+ struct sk_buff *skb;
+
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), len, event_id, kflags);
+ if (!skb) {
+ RTW_ERR(FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(dev));
+ return -ENOMEM;
+ }
+
+ /* Push the data to the skb */
+ nla_put_nohdr(skb, len, data);
+
+ rtw_cfg80211_vendor_event(skb, kflags);
+
+ return 0;
+}
+
+static int rtw_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
+ struct net_device *dev, const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+ if (unlikely(!skb)) {
+ RTW_ERR(FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(dev));
+ return -ENOMEM;
+ }
+
+ /* Push the data to the skb */
+ nla_put_nohdr(skb, len, data);
+
+ return rtw_cfg80211_vendor_cmd_reply(skb);
+}
+
+#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */
+#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */
+#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */
+#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */
+#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */
+#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */
+#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */
+#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */
+#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */
+#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */
+#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */
+#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */
+#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */
+#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */
+#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */
+#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */
+
+#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3
+
+#include <hal_data.h>
+static int rtw_dev_get_feature_set(struct net_device *dev)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *HalData = GET_HAL_DATA(adapter);
+ HAL_VERSION *hal_ver = &HalData->version_id;
+
+ int feature_set = 0;
+
+ feature_set |= WIFI_FEATURE_INFRA;
+
+ if (IS_8814A_SERIES(*hal_ver) || IS_8812_SERIES(*hal_ver) ||
+ IS_8821_SERIES(*hal_ver))
+ feature_set |= WIFI_FEATURE_INFRA_5G;
+
+ feature_set |= WIFI_FEATURE_P2P;
+ feature_set |= WIFI_FEATURE_SOFT_AP;
+
+ feature_set |= WIFI_FEATURE_ADDITIONAL_STA;
+
+ return feature_set;
+}
+
+static int *rtw_dev_get_feature_set_matrix(struct net_device *dev, int *num)
+{
+ int feature_set_full, mem_needed;
+ int *ret;
+
+ *num = 0;
+ mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS;
+ ret = (int *)rtw_malloc(mem_needed);
+
+ if (!ret) {
+ RTW_ERR(FUNC_NDEV_FMT" failed to allocate %d bytes\n"
+ , FUNC_NDEV_ARG(dev), mem_needed);
+ return ret;
+ }
+
+ feature_set_full = rtw_dev_get_feature_set(dev);
+
+ ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) |
+ (feature_set_full & WIFI_FEATURE_INFRA_5G) |
+ (feature_set_full & WIFI_FEATURE_NAN) |
+ (feature_set_full & WIFI_FEATURE_D2D_RTT) |
+ (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
+ (feature_set_full & WIFI_FEATURE_PNO) |
+ (feature_set_full & WIFI_FEATURE_BATCH_SCAN) |
+ (feature_set_full & WIFI_FEATURE_GSCAN) |
+ (feature_set_full & WIFI_FEATURE_HOTSPOT) |
+ (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) |
+ (feature_set_full & WIFI_FEATURE_EPR);
+
+ ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) |
+ (feature_set_full & WIFI_FEATURE_INFRA_5G) |
+ /* Not yet verified NAN with P2P */
+ /* (feature_set_full & WIFI_FEATURE_NAN) | */
+ (feature_set_full & WIFI_FEATURE_P2P) |
+ (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
+ (feature_set_full & WIFI_FEATURE_D2D_RTT) |
+ (feature_set_full & WIFI_FEATURE_EPR);
+
+ ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) |
+ (feature_set_full & WIFI_FEATURE_INFRA_5G) |
+ (feature_set_full & WIFI_FEATURE_NAN) |
+ (feature_set_full & WIFI_FEATURE_D2D_RTT) |
+ (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
+ (feature_set_full & WIFI_FEATURE_TDLS) |
+ (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) |
+ (feature_set_full & WIFI_FEATURE_EPR);
+ *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS;
+
+ return ret;
+}
+
+static int rtw_cfgvendor_get_feature_set(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ int reply;
+
+ reply = rtw_dev_get_feature_set(wdev_to_ndev(wdev));
+
+ err = rtw_cfgvendor_send_cmd_reply(wiphy, wdev_to_ndev(wdev), &reply, sizeof(int));
+
+ if (unlikely(err))
+ RTW_ERR(FUNC_NDEV_FMT" Vendor Command reply failed ret:%d\n"
+ , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
+
+ return err;
+}
+
+static int rtw_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct sk_buff *skb;
+ int *reply;
+ int num, mem_needed, i;
+
+ reply = rtw_dev_get_feature_set_matrix(wdev_to_ndev(wdev), &num);
+
+ if (!reply) {
+ RTW_ERR(FUNC_NDEV_FMT" Could not get feature list matrix\n"
+ , FUNC_NDEV_ARG(wdev_to_ndev(wdev)));
+ err = -EINVAL;
+ return err;
+ }
+
+ mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) +
+ ATTRIBUTE_U32_LEN;
+
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ RTW_ERR(FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(wdev_to_ndev(wdev)));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num);
+ for (i = 0; i < num; i++)
+ nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]);
+
+ err = rtw_cfg80211_vendor_cmd_reply(skb);
+
+ if (unlikely(err))
+ RTW_ERR(FUNC_NDEV_FMT" Vendor Command reply failed ret:%d\n"
+ , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
+exit:
+ rtw_mfree((u8 *)reply, sizeof(int) * num);
+ return err;
+}
+
+#if defined(GSCAN_SUPPORT) && 0
+int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
+ struct net_device *dev, void *data, int len, wl_vendor_event_t event)
+{
+ u16 kflags;
+ const void *ptr;
+ struct sk_buff *skb;
+ int malloc_len, total, iter_cnt_to_send, cnt;
+ gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
+
+ total = len / sizeof(wifi_gscan_result_t);
+ while (total > 0) {
+ malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
+ if (malloc_len > NLMSG_DEFAULT_SIZE)
+ malloc_len = NLMSG_DEFAULT_SIZE;
+ iter_cnt_to_send =
+ (malloc_len - VENDOR_DATA_OVERHEAD) / sizeof(wifi_gscan_result_t);
+ total = total - iter_cnt_to_send;
+
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), malloc_len, event, kflags);
+ if (!skb) {
+ WL_ERR(("skb alloc failed"));
+ return -ENOMEM;
+ }
+
+ while (cache && iter_cnt_to_send) {
+ ptr = (const void *) &cache->results[cache->tot_consumed];
+
+ if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed))
+ cnt = iter_cnt_to_send;
+ else
+ cnt = (cache->tot_count - cache->tot_consumed);
+
+ iter_cnt_to_send -= cnt;
+ cache->tot_consumed += cnt;
+ /* Push the data to the skb */
+ nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
+ if (cache->tot_consumed == cache->tot_count)
+ cache = cache->next;
+
+ }
+
+ rtw_cfg80211_vendor_event(skb, kflags);
+ }
+
+ return 0;
+}
+
+
+static int wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pno_gscan_capabilities_t *reply = NULL;
+ uint32 reply_len = 0;
+
+
+ reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
+ if (!reply) {
+ WL_ERR(("Could not get capabilities\n"));
+ err = -EINVAL;
+ return err;
+ }
+
+ err = rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ reply, reply_len);
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d\n", err));
+
+ kfree(reply);
+ return err;
+}
+
+static int wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0, type, band;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ uint16 *reply = NULL;
+ uint32 reply_len = 0, num_channels, mem_needed;
+ struct sk_buff *skb;
+
+ type = nla_type(data);
+
+ if (type == GSCAN_ATTRIBUTE_BAND)
+ band = nla_get_u32(data);
+ else
+ return -1;
+
+ reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
+
+ if (!reply) {
+ WL_ERR(("Could not get channel list\n"));
+ err = -EINVAL;
+ return err;
+ }
+ num_channels = reply_len / sizeof(uint32);
+ mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
+
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
+ nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
+
+ err = rtw_cfg80211_vendor_cmd_reply(skb);
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d\n", err));
+exit:
+ kfree(reply);
+ return err;
+}
+
+static int wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_results_cache_t *results, *iter;
+ uint32 reply_len, complete = 0, num_results_iter;
+ int32 mem_needed;
+ wifi_gscan_result_t *ptr;
+ uint16 num_scan_ids, num_results;
+ struct sk_buff *skb;
+ struct nlattr *scan_hdr;
+
+ dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
+ dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+ results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
+
+ if (!results) {
+ WL_ERR(("No results to send %d\n", err));
+ err = rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ results, 0);
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d\n", err));
+ dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+ return err;
+ }
+ num_scan_ids = reply_len & 0xFFFF;
+ num_results = (reply_len & 0xFFFF0000) >> 16;
+ mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
+ (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
+ VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
+
+ if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
+ mem_needed = (int32)NLMSG_DEFAULT_SIZE;
+ complete = 0;
+ } else
+ complete = 1;
+
+ WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed,
+ (int)NLMSG_DEFAULT_SIZE));
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+ return -ENOMEM;
+ }
+ iter = results;
+
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, complete);
+
+ mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
+
+ while (iter && ((mem_needed - GSCAN_BATCH_RESULT_HDR_LEN) > 0)) {
+ scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
+ nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
+ num_results_iter =
+ (mem_needed - GSCAN_BATCH_RESULT_HDR_LEN) / sizeof(wifi_gscan_result_t);
+
+ if ((iter->tot_count - iter->tot_consumed) < num_results_iter)
+ num_results_iter = iter->tot_count - iter->tot_consumed;
+
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
+ if (num_results_iter) {
+ ptr = &iter->results[iter->tot_consumed];
+ iter->tot_consumed += num_results_iter;
+ nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
+ num_results_iter * sizeof(wifi_gscan_result_t), ptr);
+ }
+ nla_nest_end(skb, scan_hdr);
+ mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
+ (num_results_iter * sizeof(wifi_gscan_result_t));
+ iter = iter->next;
+ }
+
+ dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
+ dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+
+ return rtw_cfg80211_vendor_cmd_reply(skb);
+}
+
+static int wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int type, tmp = len;
+ int run = 0xFF;
+ int flush = 0;
+ const struct nlattr *iter;
+
+ nla_for_each_attr(iter, data, len, tmp) {
+ type = nla_type(iter);
+ if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
+ run = nla_get_u32(iter);
+ else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
+ flush = nla_get_u32(iter);
+ }
+
+ if (run != 0xFF) {
+ err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
+
+ if (unlikely(err))
+ WL_ERR(("Could not run gscan:%d\n", err));
+ return err;
+ } else
+ return -1;
+
+
+}
+
+static int wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int type;
+ bool real_time = false;
+
+ type = nla_type(data);
+
+ if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
+ real_time = nla_get_u32(data);
+
+ err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
+
+ if (unlikely(err))
+ WL_ERR(("Could not run gscan:%d\n", err));
+
+ } else
+ err = -1;
+
+ return err;
+}
+
+static int wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_scan_params_t *scan_param;
+ int j = 0;
+ int type, tmp, tmp1, tmp2, k = 0;
+ const struct nlattr *iter, *iter1, *iter2;
+ struct dhd_pno_gscan_channel_bucket *ch_bucket;
+
+ scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL);
+ if (!scan_param) {
+ WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
+ err = -EINVAL;
+ return err;
+
+ }
+
+ scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
+ nla_for_each_attr(iter, data, len, tmp) {
+ type = nla_type(iter);
+
+ if (j >= GSCAN_MAX_CH_BUCKETS)
+ break;
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BASE_PERIOD:
+ scan_param->scan_fr = nla_get_u32(iter) / 1000;
+ break;
+ case GSCAN_ATTRIBUTE_NUM_BUCKETS:
+ scan_param->nchannel_buckets = nla_get_u32(iter);
+ break;
+ case GSCAN_ATTRIBUTE_CH_BUCKET_1:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_2:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_3:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_4:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_5:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_6:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_7:
+ nla_for_each_nested(iter1, iter, tmp1) {
+ type = nla_type(iter1);
+ ch_bucket =
+ scan_param->channel_bucket;
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BUCKET_ID:
+ break;
+ case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
+ ch_bucket[j].bucket_freq_multiple =
+ nla_get_u32(iter1) / 1000;
+ break;
+ case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
+ ch_bucket[j].num_channels =
+ nla_get_u32(iter1);
+ break;
+ case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
+ nla_for_each_nested(iter2, iter1, tmp2) {
+ if (k >= PFN_SWC_RSSI_WINDOW_MAX)
+ break;
+ ch_bucket[j].chan_list[k] =
+ nla_get_u32(iter2);
+ k++;
+ }
+ k = 0;
+ break;
+ case GSCAN_ATTRIBUTE_BUCKETS_BAND:
+ ch_bucket[j].band = (uint16)
+ nla_get_u32(iter1);
+ break;
+ case GSCAN_ATTRIBUTE_REPORT_EVENTS:
+ ch_bucket[j].report_flag = (uint8)
+ nla_get_u32(iter1);
+ break;
+ }
+ }
+ j++;
+ break;
+ }
+ }
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_SCAN_CFG_ID, scan_param, 0) < 0) {
+ WL_ERR(("Could not set GSCAN scan cfg\n"));
+ err = -EINVAL;
+ }
+
+ kfree(scan_param);
+ return err;
+
+}
+
+static int wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_hotlist_scan_params_t *hotlist_params;
+ int tmp, tmp1, tmp2, type, j = 0, dummy;
+ const struct nlattr *outer, *inner, *iter;
+ uint8 flush = 0;
+ struct bssid_t *pbssid;
+
+ hotlist_params = (gscan_hotlist_scan_params_t *)kzalloc(len, GFP_KERNEL);
+ if (!hotlist_params) {
+ WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes\n", len));
+ return -1;
+ }
+
+ hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
+
+ nla_for_each_attr(iter, data, len, tmp2) {
+ type = nla_type(iter);
+ switch (type) {
+ case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
+ pbssid = hotlist_params->bssid;
+ nla_for_each_nested(outer, iter, tmp) {
+ nla_for_each_nested(inner, outer, tmp1) {
+ type = nla_type(inner);
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BSSID:
+ memcpy(&(pbssid[j].macaddr),
+ nla_data(inner), ETHER_ADDR_LEN);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_LOW:
+ pbssid[j].rssi_reporting_threshold =
+ (int8) nla_get_u8(inner);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_HIGH:
+ dummy = (int8) nla_get_u8(inner);
+ break;
+ }
+ }
+ j++;
+ }
+ hotlist_params->nbssid = j;
+ break;
+ case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
+ flush = nla_get_u8(iter);
+ break;
+ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
+ hotlist_params->lost_ap_window = nla_get_u32(iter);
+ break;
+ }
+
+ }
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
+ WL_ERR(("Could not set GSCAN HOTLIST cfg\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+exit:
+ kfree(hotlist_params);
+ return err;
+}
+static int wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0, tmp, type;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_batch_params_t batch_param;
+ const struct nlattr *iter;
+
+ batch_param.mscan = batch_param.bestn = 0;
+ batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
+
+ nla_for_each_attr(iter, data, len, tmp) {
+ type = nla_type(iter);
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
+ batch_param.bestn = nla_get_u32(iter);
+ break;
+ case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
+ batch_param.mscan = nla_get_u32(iter);
+ break;
+ case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
+ batch_param.buffer_threshold = nla_get_u32(iter);
+ break;
+ }
+ }
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, 0) < 0) {
+ WL_ERR(("Could not set batch cfg\n"));
+ err = -EINVAL;
+ return err;
+ }
+
+ return err;
+}
+
+static int wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_swc_params_t *significant_params;
+ int tmp, tmp1, tmp2, type, j = 0;
+ const struct nlattr *outer, *inner, *iter;
+ uint8 flush = 0;
+ wl_pfn_significant_bssid_t *pbssid;
+
+ significant_params = (gscan_swc_params_t *) kzalloc(len, GFP_KERNEL);
+ if (!significant_params) {
+ WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes\n", len));
+ return -1;
+ }
+
+
+ nla_for_each_attr(iter, data, len, tmp2) {
+ type = nla_type(iter);
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH:
+ flush = nla_get_u8(iter);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE:
+ significant_params->rssi_window = nla_get_u16(iter);
+ break;
+ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
+ significant_params->lost_ap_window = nla_get_u16(iter);
+ break;
+ case GSCAN_ATTRIBUTE_MIN_BREACHING:
+ significant_params->swc_threshold = nla_get_u16(iter);
+ break;
+ case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS:
+ pbssid = significant_params->bssid_elem_list;
+ nla_for_each_nested(outer, iter, tmp) {
+ nla_for_each_nested(inner, outer, tmp1) {
+ switch (nla_type(inner)) {
+ case GSCAN_ATTRIBUTE_BSSID:
+ memcpy(&(pbssid[j].macaddr),
+ nla_data(inner),
+ ETHER_ADDR_LEN);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_HIGH:
+ pbssid[j].rssi_high_threshold =
+ (int8) nla_get_u8(inner);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_LOW:
+ pbssid[j].rssi_low_threshold =
+ (int8) nla_get_u8(inner);
+ break;
+ }
+ }
+ j++;
+ }
+ break;
+ }
+ }
+ significant_params->nbssid = j;
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, significant_params, flush) < 0) {
+ WL_ERR(("Could not set GSCAN significant cfg\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+exit:
+ kfree(significant_params);
+ return err;
+}
+#endif /* GSCAN_SUPPORT */
+
+#if defined(RTT_SUPPORT) && 0
+void wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
+{
+ struct wireless_dev *wdev = (struct wireless_dev *)ctx;
+ struct wiphy *wiphy;
+ struct sk_buff *skb;
+ uint32 tot_len = NLMSG_DEFAULT_SIZE, entry_len = 0;
+ gfp_t kflags;
+ rtt_report_t *rtt_report = NULL;
+ rtt_result_t *rtt_result = NULL;
+ struct list_head *rtt_list;
+ wiphy = wdev->wiphy;
+
+ WL_DBG(("In\n"));
+ /* Push the data to the skb */
+ if (!rtt_data) {
+ WL_ERR(("rtt_data is NULL\n"));
+ goto exit;
+ }
+ rtt_list = (struct list_head *)rtt_data;
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+ /* Alloc the SKB for vendor_event */
+ skb = rtw_cfg80211_vendor_event_alloc(wiphy, wdev, tot_len, GOOGLE_RTT_COMPLETE_EVENT, kflags);
+ if (!skb) {
+ WL_ERR(("skb alloc failed"));
+ goto exit;
+ }
+ /* fill in the rtt results on each entry */
+ list_for_each_entry(rtt_result, rtt_list, list) {
+ entry_len = 0;
+ if (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) {
+ entry_len = sizeof(rtt_report_t);
+ rtt_report = kzalloc(entry_len, kflags);
+ if (!rtt_report) {
+ WL_ERR(("rtt_report alloc failed"));
+ goto exit;
+ }
+ rtt_report->addr = rtt_result->peer_mac;
+ rtt_report->num_measurement = 1; /* ONE SHOT */
+ rtt_report->status = rtt_result->err_code;
+ rtt_report->type = (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) ? RTT_ONE_WAY : RTT_TWO_WAY;
+ rtt_report->peer = rtt_result->target_info->peer;
+ rtt_report->channel = rtt_result->target_info->channel;
+ rtt_report->rssi = rtt_result->avg_rssi;
+ /* tx_rate */
+ rtt_report->tx_rate = rtt_result->tx_rate;
+ /* RTT */
+ rtt_report->rtt = rtt_result->meanrtt;
+ rtt_report->rtt_sd = rtt_result->sdrtt;
+ /* convert to centi meter */
+ if (rtt_result->distance != 0xffffffff)
+ rtt_report->distance = (rtt_result->distance >> 2) * 25;
+ else /* invalid distance */
+ rtt_report->distance = -1;
+
+ rtt_report->ts = rtt_result->ts;
+ nla_append(skb, entry_len, rtt_report);
+ kfree(rtt_report);
+ }
+ }
+ rtw_cfg80211_vendor_event(skb, kflags);
+exit:
+ return;
+}
+
+static int wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int err = 0, rem, rem1, rem2, type;
+ rtt_config_params_t rtt_param;
+ rtt_target_info_t *rtt_target = NULL;
+ const struct nlattr *iter, *iter1, *iter2;
+ int8 eabuf[ETHER_ADDR_STR_LEN];
+ int8 chanbuf[CHANSPEC_STR_LEN];
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ WL_DBG(("In\n"));
+ err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
+ if (err < 0) {
+ WL_ERR(("failed to register rtt_noti_callback\n"));
+ goto exit;
+ }
+ memset(&rtt_param, 0, sizeof(rtt_param));
+ nla_for_each_attr(iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case RTT_ATTRIBUTE_TARGET_CNT:
+ rtt_param.rtt_target_cnt = nla_get_u8(iter);
+ if (rtt_param.rtt_target_cnt > RTT_MAX_TARGET_CNT) {
+ WL_ERR(("exceed max target count : %d\n",
+ rtt_param.rtt_target_cnt));
+ err = BCME_RANGE;
+ }
+ break;
+ case RTT_ATTRIBUTE_TARGET_INFO:
+ rtt_target = rtt_param.target_info;
+ nla_for_each_nested(iter1, iter, rem1) {
+ nla_for_each_nested(iter2, iter1, rem2) {
+ type = nla_type(iter2);
+ switch (type) {
+ case RTT_ATTRIBUTE_TARGET_MAC:
+ memcpy(&rtt_target->addr, nla_data(iter2), ETHER_ADDR_LEN);
+ break;
+ case RTT_ATTRIBUTE_TARGET_TYPE:
+ rtt_target->type = nla_get_u8(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_PEER:
+ rtt_target->peer = nla_get_u8(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_CHAN:
+ memcpy(&rtt_target->channel, nla_data(iter2),
+ sizeof(rtt_target->channel));
+ break;
+ case RTT_ATTRIBUTE_TARGET_MODE:
+ rtt_target->continuous = nla_get_u8(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_INTERVAL:
+ rtt_target->interval = nla_get_u32(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT:
+ rtt_target->measure_cnt = nla_get_u32(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_NUM_PKT:
+ rtt_target->ftm_cnt = nla_get_u32(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_NUM_RETRY:
+ rtt_target->retry_cnt = nla_get_u32(iter2);
+ }
+ }
+ /* convert to chanspec value */
+ rtt_target->chanspec = dhd_rtt_convert_to_chspec(rtt_target->channel);
+ if (rtt_target->chanspec == 0) {
+ WL_ERR(("Channel is not valid\n"));
+ goto exit;
+ }
+ WL_INFORM(("Target addr %s, Channel : %s for RTT\n",
+ bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, eabuf),
+ wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
+ rtt_target++;
+ }
+ break;
+ }
+ }
+ WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
+ if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
+ WL_ERR(("Could not set RTT configuration\n"));
+ err = -EINVAL;
+ }
+exit:
+ return err;
+}
+
+static int wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int err = 0, rem, type, target_cnt = 0;
+ const struct nlattr *iter;
+ struct ether_addr *mac_list = NULL, *mac_addr = NULL;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ nla_for_each_attr(iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case RTT_ATTRIBUTE_TARGET_CNT:
+ target_cnt = nla_get_u8(iter);
+ mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN , GFP_KERNEL);
+ if (mac_list == NULL) {
+ WL_ERR(("failed to allocate mem for mac list\n"));
+ goto exit;
+ }
+ mac_addr = &mac_list[0];
+ break;
+ case RTT_ATTRIBUTE_TARGET_MAC:
+ if (mac_addr)
+ memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN);
+ else {
+ WL_ERR(("mac_list is NULL\n"));
+ goto exit;
+ }
+ break;
+ }
+ if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
+ WL_ERR(("Could not cancel RTT configuration\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+exit:
+ if (mac_list)
+ kfree(mac_list);
+ return err;
+}
+static int wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ rtt_capabilities_t capability;
+
+ err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
+ if (unlikely(err)) {
+ WL_ERR(("Vendor Command reply failed ret:%d\n", err));
+ goto exit;
+ }
+ err = rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ &capability, sizeof(capability));
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d\n", err));
+exit:
+ return err;
+}
+
+#endif /* RTT_SUPPORT */
+static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ u8 resp[1] = {'\0'};
+
+ RTW_INFO(FUNC_NDEV_FMT" %s\n", FUNC_NDEV_ARG(wdev_to_ndev(wdev)), (char *)data);
+ err = rtw_cfgvendor_send_cmd_reply(wiphy, wdev_to_ndev(wdev), resp, 1);
+ if (unlikely(err))
+ RTW_ERR(FUNC_NDEV_FMT"Vendor Command reply failed ret:%d\n"
+ , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
+
+ return err;
+}
+
+static const struct wiphy_vendor_command rtw_vendor_cmds[] = {
+ {
+ {
+ .vendor_id = OUI_BRCM,
+ .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_priv_string_handler
+ },
+#if defined(GSCAN_SUPPORT) && 0
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_gscan_get_capabilities
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_set_scan_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_set_batch_scan_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_initiate_gscan
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_enable_full_scan_result
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_HOTLIST
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_hotlist_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_significant_change_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_gscan_get_batch_results
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_gscan_get_channel_list
+ },
+#endif /* GSCAN_SUPPORT */
+#if defined(RTT_SUPPORT) && 0
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = RTT_SUBCMD_SET_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_rtt_set_config
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = RTT_SUBCMD_CANCEL_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_rtt_cancel_config
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = RTT_SUBCMD_GETCAPABILITY
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = wl_cfgvendor_rtt_get_capability
+ },
+#endif /* RTT_SUPPORT */
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = rtw_cfgvendor_get_feature_set
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
+ .policy = VENDOR_CMD_RAW_DATA,
+#endif
+ .doit = rtw_cfgvendor_get_feature_set_matrix
+ }
+};
+
+static const struct nl80211_vendor_cmd_info rtw_vendor_events[] = {
+ { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
+ { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
+#if defined(GSCAN_SUPPORT) && 0
+ { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
+ { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
+ { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
+ { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
+#endif /* GSCAN_SUPPORT */
+#if defined(RTT_SUPPORT) && 0
+ { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
+#endif /* RTT_SUPPORT */
+#if defined(GSCAN_SUPPORT) && 0
+ { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
+ { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }
+#endif /* GSCAN_SUPPORT */
+};
+
+int rtw_cfgvendor_attach(struct wiphy *wiphy)
+{
+
+ RTW_INFO("Register RTW cfg80211 vendor cmd(0x%x) interface\n", NL80211_CMD_VENDOR);
+
+ wiphy->vendor_commands = rtw_vendor_cmds;
+ wiphy->n_vendor_commands = ARRAY_SIZE(rtw_vendor_cmds);
+ wiphy->vendor_events = rtw_vendor_events;
+ wiphy->n_vendor_events = ARRAY_SIZE(rtw_vendor_events);
+
+ return 0;
+}
+
+int rtw_cfgvendor_detach(struct wiphy *wiphy)
+{
+ RTW_INFO("Vendor: Unregister RTW cfg80211 vendor interface\n");
+
+ wiphy->vendor_commands = NULL;
+ wiphy->vendor_events = NULL;
+ wiphy->n_vendor_commands = 0;
+ wiphy->n_vendor_events = 0;
+
+ return 0;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT) */
+
+#endif /* CONFIG_IOCTL_CFG80211 */
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.h b/drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.h
new file mode 100644
index 000000000000..8caacca8bee0
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_cfgvendor.h
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+
+#ifndef _RTW_CFGVENDOR_H_
+#define _RTW_CFGVENDOR_H_
+
+#define OUI_BRCM 0x001018
+#define OUI_GOOGLE 0x001A11
+#define BRCM_VENDOR_SUBCMD_PRIV_STR 1
+#define ATTRIBUTE_U32_LEN (NLA_HDRLEN + 4)
+#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN
+#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN
+#define VENDOR_DATA_OVERHEAD (NLA_HDRLEN)
+
+#define SCAN_RESULTS_COMPLETE_FLAG_LEN ATTRIBUTE_U32_LEN
+#define SCAN_INDEX_HDR_LEN (NLA_HDRLEN)
+#define SCAN_ID_HDR_LEN ATTRIBUTE_U32_LEN
+#define SCAN_FLAGS_HDR_LEN ATTRIBUTE_U32_LEN
+#define GSCAN_NUM_RESULTS_HDR_LEN ATTRIBUTE_U32_LEN
+#define GSCAN_RESULTS_HDR_LEN (NLA_HDRLEN)
+#define GSCAN_BATCH_RESULT_HDR_LEN (SCAN_INDEX_HDR_LEN + SCAN_ID_HDR_LEN + \
+ SCAN_FLAGS_HDR_LEN + \
+ GSCAN_NUM_RESULTS_HDR_LEN + \
+ GSCAN_RESULTS_HDR_LEN)
+
+#define VENDOR_REPLY_OVERHEAD (VENDOR_ID_OVERHEAD + \
+ VENDOR_SUBCMD_OVERHEAD + \
+ VENDOR_DATA_OVERHEAD)
+typedef enum {
+ /* don't use 0 as a valid subcommand */
+ VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+ /* define all vendor startup commands between 0x0 and 0x0FFF */
+ VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+ VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
+
+ /* define all GScan related commands between 0x1000 and 0x10FF */
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
+
+ /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
+
+ /* define all RTT related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
+
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
+
+ ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300,
+ ANDROID_NL80211_SUBCMD_TDLS_RANGE_END = 0x13FF,
+ /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+enum wl_vendor_subcmd {
+ BRCM_VENDOR_SCMD_UNSPEC,
+ BRCM_VENDOR_SCMD_PRIV_STR,
+ GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+ GSCAN_SUBCMD_SET_CONFIG,
+ GSCAN_SUBCMD_SET_SCAN_CONFIG,
+ GSCAN_SUBCMD_ENABLE_GSCAN,
+ GSCAN_SUBCMD_GET_SCAN_RESULTS,
+ GSCAN_SUBCMD_SCAN_RESULTS,
+ GSCAN_SUBCMD_SET_HOTLIST,
+ GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,
+ GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,
+ GSCAN_SUBCMD_GET_CHANNEL_LIST,
+ ANDR_WIFI_SUBCMD_GET_FEATURE_SET,
+ ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX,
+ RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+ RTT_SUBCMD_CANCEL_CONFIG,
+ RTT_SUBCMD_GETCAPABILITY,
+ /* Add more sub commands here */
+ VENDOR_SUBCMD_MAX
+};
+
+enum gscan_attributes {
+ GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
+ GSCAN_ATTRIBUTE_BASE_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKETS_BAND,
+ GSCAN_ATTRIBUTE_BUCKET_ID,
+ GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+ GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+ GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+ GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+ GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+ GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
+ GSCAN_ATTRIBUTE_FLUSH_FEATURE,
+ GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS,
+ GSCAN_ATTRIBUTE_REPORT_EVENTS,
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
+ GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
+ GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */
+ GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */
+ GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */
+ GSCAN_ATTRIBUTE_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_CHANNEL_LIST,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_SSID = 40,
+ GSCAN_ATTRIBUTE_BSSID,
+ GSCAN_ATTRIBUTE_CHANNEL,
+ GSCAN_ATTRIBUTE_RSSI,
+ GSCAN_ATTRIBUTE_TIMESTAMP,
+ GSCAN_ATTRIBUTE_RTT,
+ GSCAN_ATTRIBUTE_RTTSD,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
+ GSCAN_ATTRIBUTE_RSSI_LOW,
+ GSCAN_ATTRIBUTE_RSSI_HIGH,
+ GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM,
+ GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
+
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
+ GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+ GSCAN_ATTRIBUTE_MIN_BREACHING,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
+ GSCAN_ATTRIBUTE_MAX
+};
+
+enum gscan_bucket_attributes {
+ GSCAN_ATTRIBUTE_CH_BUCKET_1,
+ GSCAN_ATTRIBUTE_CH_BUCKET_2,
+ GSCAN_ATTRIBUTE_CH_BUCKET_3,
+ GSCAN_ATTRIBUTE_CH_BUCKET_4,
+ GSCAN_ATTRIBUTE_CH_BUCKET_5,
+ GSCAN_ATTRIBUTE_CH_BUCKET_6,
+ GSCAN_ATTRIBUTE_CH_BUCKET_7
+};
+
+enum gscan_ch_attributes {
+ GSCAN_ATTRIBUTE_CH_ID_1,
+ GSCAN_ATTRIBUTE_CH_ID_2,
+ GSCAN_ATTRIBUTE_CH_ID_3,
+ GSCAN_ATTRIBUTE_CH_ID_4,
+ GSCAN_ATTRIBUTE_CH_ID_5,
+ GSCAN_ATTRIBUTE_CH_ID_6,
+ GSCAN_ATTRIBUTE_CH_ID_7
+};
+
+enum rtt_attributes {
+ RTT_ATTRIBUTE_TARGET_CNT,
+ RTT_ATTRIBUTE_TARGET_INFO,
+ RTT_ATTRIBUTE_TARGET_MAC,
+ RTT_ATTRIBUTE_TARGET_TYPE,
+ RTT_ATTRIBUTE_TARGET_PEER,
+ RTT_ATTRIBUTE_TARGET_CHAN,
+ RTT_ATTRIBUTE_TARGET_MODE,
+ RTT_ATTRIBUTE_TARGET_INTERVAL,
+ RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT,
+ RTT_ATTRIBUTE_TARGET_NUM_PKT,
+ RTT_ATTRIBUTE_TARGET_NUM_RETRY
+};
+
+typedef enum wl_vendor_event {
+ BRCM_VENDOR_EVENT_UNSPEC,
+ BRCM_VENDOR_EVENT_PRIV_STR,
+ GOOGLE_GSCAN_SIGNIFICANT_EVENT,
+ GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT,
+ GOOGLE_GSCAN_BATCH_SCAN_EVENT,
+ GOOGLE_SCAN_FULL_RESULTS_EVENT,
+ GOOGLE_RTT_COMPLETE_EVENT,
+ GOOGLE_SCAN_COMPLETE_EVENT,
+ GOOGLE_GSCAN_GEOFENCE_LOST_EVENT
+} wl_vendor_event_t;
+
+enum andr_wifi_feature_set_attr {
+ ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
+ ANDR_WIFI_ATTRIBUTE_FEATURE_SET
+};
+
+typedef enum wl_vendor_gscan_attribute {
+ ATTR_START_GSCAN,
+ ATTR_STOP_GSCAN,
+ ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */
+ ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */
+ ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */
+ ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */
+ ATTR_GET_GSCAN_CAPABILITIES_ID,
+ /* Add more sub commands here */
+ ATTR_GSCAN_MAX
+} wl_vendor_gscan_attribute_t;
+
+typedef enum gscan_batch_attribute {
+ ATTR_GSCAN_BATCH_BESTN,
+ ATTR_GSCAN_BATCH_MSCAN,
+ ATTR_GSCAN_BATCH_BUFFER_THRESHOLD
+} gscan_batch_attribute_t;
+
+typedef enum gscan_geofence_attribute {
+ ATTR_GSCAN_NUM_HOTLIST_BSSID,
+ ATTR_GSCAN_HOTLIST_BSSID
+} gscan_geofence_attribute_t;
+
+typedef enum gscan_complete_event {
+ WIFI_SCAN_BUFFER_FULL,
+ WIFI_SCAN_COMPLETE
+} gscan_complete_event_t;
+
+/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */
+#define BRCM_VENDOR_SCMD_CAPA "cap"
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT)
+extern int rtw_cfgvendor_attach(struct wiphy *wiphy);
+extern int rtw_cfgvendor_detach(struct wiphy *wiphy);
+extern int rtw_cfgvendor_send_async_event(struct wiphy *wiphy,
+ struct net_device *dev, int event_id, const void *data, int len);
+#if defined(GSCAN_SUPPORT) && 0
+extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
+ struct net_device *dev, void *data, int len, wl_vendor_event_t event);
+#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT) */
+
+#endif /* _RTW_CFGVENDOR_H_ */
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_proc.c b/drivers/staging/rtl8188eu/os_dep/rtw_proc.c
new file mode 100644
index 000000000000..cdf24a2859d1
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_proc.c
@@ -0,0 +1,3216 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+
+#include <linux/ctype.h> /* tolower() */
+#include <drv_types.h>
+#include <hal_data.h>
+#include "rtw_proc.h"
+#ifdef CONFIG_BT_COEXIST
+#include <rtw_btcoex.h>
+#endif
+
+#ifdef CONFIG_PROC_DEBUG
+
+static struct proc_dir_entry *rtw_proc = NULL;
+
+inline struct proc_dir_entry *get_rtw_drv_proc(void)
+{
+ return rtw_proc;
+}
+
+#define RTW_PROC_NAME DRV_NAME
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+#define file_inode(file) ((file)->f_dentry->d_inode)
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0))
+#define PDE_DATA(inode) PDE((inode))->data
+#define proc_get_parent_data(inode) PDE((inode))->parent->data
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
+#define get_proc_net proc_net
+#else
+#define get_proc_net init_net.proc_net
+#endif
+
+inline struct proc_dir_entry *rtw_proc_create_dir(const char *name, struct proc_dir_entry *parent, void *data)
+{
+ struct proc_dir_entry *entry;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
+ entry = proc_mkdir_data(name, S_IRUGO | S_IXUGO, parent, data);
+#else
+ /* entry = proc_mkdir_mode(name, S_IRUGO|S_IXUGO, parent); */
+ entry = proc_mkdir(name, parent);
+ if (entry)
+ entry->data = data;
+#endif
+
+ return entry;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent,
+ const struct proc_ops *fops, void * data)
+#else
+inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent,
+ const struct file_operations *fops, void * data)
+#endif
+{
+ struct proc_dir_entry *entry;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+ entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUGO, parent, fops, data);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26))
+ entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUGO, parent, fops, data);
+#else
+ entry = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUGO, parent);
+ if (entry) {
+ entry->data = data;
+ entry->proc_fops = fops;
+ }
+#endif
+
+ return entry;
+}
+
+static int proc_get_dummy(struct seq_file *m, void *v)
+{
+ return 0;
+}
+
+static int proc_get_drv_version(struct seq_file *m, void *v)
+{
+ dump_drv_version(m);
+ return 0;
+}
+
+static int proc_get_log_level(struct seq_file *m, void *v)
+{
+ dump_log_level(m);
+ return 0;
+}
+
+static int proc_get_drv_cfg(struct seq_file *m, void *v)
+{
+ dump_drv_cfg(m);
+ return 0;
+}
+
+static ssize_t proc_set_log_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ char tmp[32];
+ int log_level;
+
+ if (count < 1)
+ return -EINVAL;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+#ifdef CONFIG_RTW_DEBUG
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%d ", &log_level);
+
+ if (log_level >= _DRV_NONE_ && log_level <= _DRV_MAX_) {
+ rtw_drv_log_level = log_level;
+ printk("rtw_drv_log_level:%d\n", rtw_drv_log_level);
+ }
+ } else
+ return -EFAULT;
+#else
+ printk("CONFIG_RTW_DEBUG is disabled\n");
+#endif
+
+ return count;
+}
+
+#ifdef DBG_MEM_ALLOC
+static int proc_get_mstat(struct seq_file *m, void *v)
+{
+ rtw_mstat_dump(m);
+ return 0;
+}
+#endif /* DBG_MEM_ALLOC */
+
+static int proc_get_country_chplan_map(struct seq_file *m, void *v)
+{
+ dump_country_chplan_map(m);
+ return 0;
+}
+
+static int proc_get_chplan_id_list(struct seq_file *m, void *v)
+{
+ dump_chplan_id_list(m);
+ return 0;
+}
+
+static int proc_get_chplan_test(struct seq_file *m, void *v)
+{
+ dump_chplan_test(m);
+ return 0;
+}
+
+/*
+* rtw_drv_proc:
+* init/deinit when register/unregister driver
+*/
+static const struct rtw_proc_hdl drv_proc_hdls[] = {
+ RTW_PROC_HDL_SSEQ("ver_info", proc_get_drv_version, NULL),
+ RTW_PROC_HDL_SSEQ("log_level", proc_get_log_level, proc_set_log_level),
+ RTW_PROC_HDL_SSEQ("drv_cfg", proc_get_drv_cfg, NULL),
+#ifdef DBG_MEM_ALLOC
+ RTW_PROC_HDL_SSEQ("mstat", proc_get_mstat, NULL),
+#endif /* DBG_MEM_ALLOC */
+ RTW_PROC_HDL_SSEQ("country_chplan_map", proc_get_country_chplan_map, NULL),
+ RTW_PROC_HDL_SSEQ("chplan_id_list", proc_get_chplan_id_list, NULL),
+ RTW_PROC_HDL_SSEQ("chplan_test", proc_get_chplan_test, NULL),
+};
+
+static const int drv_proc_hdls_num = sizeof(drv_proc_hdls) / sizeof(struct rtw_proc_hdl);
+
+static int rtw_drv_proc_open(struct inode *inode, struct file *file)
+{
+ /* struct net_device *dev = proc_get_parent_data(inode); */
+ ssize_t index = (ssize_t)PDE_DATA(inode);
+ const struct rtw_proc_hdl *hdl = drv_proc_hdls + index;
+ void *private = NULL;
+
+ if (hdl->type == RTW_PROC_HDL_TYPE_SEQ) {
+ int res = seq_open(file, hdl->u.seq_op);
+
+ if (res == 0)
+ ((struct seq_file *)file->private_data)->private = private;
+
+ return res;
+ } else if (hdl->type == RTW_PROC_HDL_TYPE_SSEQ) {
+ int (*show)(struct seq_file *, void *) = hdl->u.show ? hdl->u.show : proc_get_dummy;
+
+ return single_open(file, show, private);
+ } else {
+ return -EROFS;
+ }
+}
+
+static ssize_t rtw_drv_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
+{
+ ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
+ const struct rtw_proc_hdl *hdl = drv_proc_hdls + index;
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
+
+ if (write)
+ return write(file, buffer, count, pos, NULL);
+
+ return -EROFS;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+static const struct proc_ops rtw_drv_proc_seq_fops = {
+ .proc_open = rtw_drv_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = seq_release,
+ .proc_write = rtw_drv_proc_write,
+};
+#else
+static const struct file_operations rtw_drv_proc_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_drv_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = rtw_drv_proc_write,
+};
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+static const struct proc_ops rtw_drv_proc_sseq_fops = {
+ .proc_open = rtw_drv_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = rtw_drv_proc_write,
+};
+#else
+static const struct file_operations rtw_drv_proc_sseq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_drv_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = rtw_drv_proc_write,
+};
+#endif
+
+int rtw_drv_proc_init(void)
+{
+ int ret = _FAIL;
+ ssize_t i;
+ struct proc_dir_entry *entry = NULL;
+
+ if (rtw_proc != NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ rtw_proc = rtw_proc_create_dir(RTW_PROC_NAME, get_proc_net, NULL);
+
+ if (rtw_proc == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ for (i = 0; i < drv_proc_hdls_num; i++) {
+ if (drv_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ)
+ entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_seq_fops, (void *)i);
+ else if (drv_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ)
+ entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_sseq_fops, (void *)i);
+ else
+ entry = NULL;
+
+ if (!entry) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+ }
+
+ ret = _SUCCESS;
+
+exit:
+ return ret;
+}
+
+void rtw_drv_proc_deinit(void)
+{
+ int i;
+
+ if (rtw_proc == NULL)
+ return;
+
+ for (i = 0; i < drv_proc_hdls_num; i++)
+ remove_proc_entry(drv_proc_hdls[i].name, rtw_proc);
+
+ remove_proc_entry(RTW_PROC_NAME, get_proc_net);
+ rtw_proc = NULL;
+}
+
+#ifndef RTW_SEQ_FILE_TEST
+#define RTW_SEQ_FILE_TEST 0
+#endif
+
+#if RTW_SEQ_FILE_TEST
+#define RTW_SEQ_FILE_TEST_SHOW_LIMIT 300
+static void *proc_start_seq_file_test(struct seq_file *m, loff_t *pos)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
+ if (*pos >= RTW_SEQ_FILE_TEST_SHOW_LIMIT) {
+ RTW_INFO(FUNC_ADPT_FMT" pos:%llu, out of range return\n", FUNC_ADPT_ARG(adapter), *pos);
+ return NULL;
+ }
+
+ RTW_INFO(FUNC_ADPT_FMT" return pos:%lld\n", FUNC_ADPT_ARG(adapter), *pos);
+ return pos;
+}
+void proc_stop_seq_file_test(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
+}
+
+void *proc_next_seq_file_test(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ (*pos)++;
+ if (*pos >= RTW_SEQ_FILE_TEST_SHOW_LIMIT) {
+ RTW_INFO(FUNC_ADPT_FMT" pos:%lld, out of range return\n", FUNC_ADPT_ARG(adapter), *pos);
+ return NULL;
+ }
+
+ RTW_INFO(FUNC_ADPT_FMT" return pos:%lld\n", FUNC_ADPT_ARG(adapter), *pos);
+ return pos;
+}
+
+static int proc_get_seq_file_test(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ u32 pos = *((loff_t *)(v));
+ RTW_INFO(FUNC_ADPT_FMT" pos:%d\n", FUNC_ADPT_ARG(adapter), pos);
+ RTW_PRINT_SEL(m, FUNC_ADPT_FMT" pos:%d\n", FUNC_ADPT_ARG(adapter), pos);
+ return 0;
+}
+
+struct seq_operations seq_file_test = {
+ .start = proc_start_seq_file_test,
+ .stop = proc_stop_seq_file_test,
+ .next = proc_next_seq_file_test,
+ .show = proc_get_seq_file_test,
+};
+#endif /* RTW_SEQ_FILE_TEST */
+
+#ifdef CONFIG_SDIO_HCI
+static int proc_get_sd_f0_reg_dump(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ sd_f0_reg_dump(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_sdio_local_reg_dump(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ sdio_local_reg_dump(m, adapter);
+
+ return 0;
+}
+#endif /* CONFIG_SDIO_HCI */
+
+#ifdef RTW_HALMAC
+#include "../../hal/hal_halmac.h"
+static int proc_get_halmac_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_dump_halmac_info(m);
+ return 0;
+}
+#endif
+static int proc_get_fw_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_dump_fw_info(m, adapter);
+ return 0;
+}
+static int proc_get_mac_reg_dump(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ mac_reg_dump(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_bb_reg_dump(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ bb_reg_dump(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_bb_reg_dump_ex(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ bb_reg_dump_ex(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_rf_reg_dump(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rf_reg_dump(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_dump_tx_rate_bmp(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_tx_rate_bmp(m, adapter_to_dvobj(adapter));
+
+ return 0;
+}
+
+static int proc_get_dump_adapters_status(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_adapters_status(m, adapter_to_dvobj(adapter));
+
+ return 0;
+}
+
+#ifdef CONFIG_RTW_CUSTOMER_STR
+static int proc_get_customer_str(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 cstr[RTW_CUSTOMER_STR_LEN];
+
+ if (rtw_hal_customer_str_read(adapter, cstr) != _SUCCESS)
+ goto exit;
+
+ RTW_PRINT_SEL(m, RTW_CUSTOMER_STR_FMT"\n", RTW_CUSTOMER_STR_ARG(cstr));
+
+exit:
+ return 0;
+}
+#endif /* CONFIG_RTW_CUSTOMER_STR */
+
+/* gpio setting */
+#ifdef CONFIG_GPIO_API
+static ssize_t proc_set_config_gpio(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32] = {0};
+ int num = 0, gpio_pin = 0, gpio_mode = 0; /* gpio_mode:0 input 1:output; */
+
+ if (count < 2)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ num = sscanf(tmp, "%d %d", &gpio_pin, &gpio_mode);
+ RTW_INFO("num=%d gpio_pin=%d mode=%d\n", num, gpio_pin, gpio_mode);
+ padapter->pre_gpio_pin = gpio_pin;
+
+ if (gpio_mode == 0 || gpio_mode == 1)
+ rtw_hal_config_gpio(padapter, gpio_pin, gpio_mode);
+ }
+ return count;
+
+}
+static ssize_t proc_set_gpio_output_value(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32] = {0};
+ int num = 0, gpio_pin = 0, pin_mode = 0; /* pin_mode: 1 high 0:low */
+
+ if (count < 2)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ num = sscanf(tmp, "%d %d", &gpio_pin, &pin_mode);
+ RTW_INFO("num=%d gpio_pin=%d pin_high=%d\n", num, gpio_pin, pin_mode);
+ padapter->pre_gpio_pin = gpio_pin;
+
+ if (pin_mode == 0 || pin_mode == 1)
+ rtw_hal_set_gpio_output_value(padapter, gpio_pin, pin_mode);
+ }
+ return count;
+}
+static int proc_get_gpio(struct seq_file *m, void *v)
+{
+ u8 gpioreturnvalue = 0;
+ struct net_device *dev = m->private;
+
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ if (!padapter)
+ return -EFAULT;
+ gpioreturnvalue = rtw_hal_get_gpio(padapter, padapter->pre_gpio_pin);
+ RTW_PRINT_SEL(m, "get_gpio %d:%d\n", padapter->pre_gpio_pin, gpioreturnvalue);
+
+ return 0;
+
+}
+static ssize_t proc_set_gpio(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32] = {0};
+ int num = 0, gpio_pin = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ num = sscanf(tmp, "%d", &gpio_pin);
+ RTW_INFO("num=%d gpio_pin=%d\n", num, gpio_pin);
+ padapter->pre_gpio_pin = gpio_pin;
+
+ }
+ return count;
+}
+#endif
+static ssize_t proc_set_rx_info_msg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct recv_priv *precvpriv = &(padapter->recvpriv);
+ char tmp[32] = {0};
+ int phy_info_flag = 0;
+
+ if (!padapter)
+ return -EFAULT;
+
+ if (count < 1) {
+ RTW_INFO("argument size is less than 1\n");
+ return -EFAULT;
+ }
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ int num = sscanf(tmp, "%d", &phy_info_flag);
+
+ precvpriv->store_law_data_flag = (bool) phy_info_flag;
+
+ /*RTW_INFO("precvpriv->store_law_data_flag = %d\n",( bool )(precvpriv->store_law_data_flag));*/
+ }
+ return count;
+}
+static int proc_get_rx_info_msg(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_hal_set_odm_var(padapter, HAL_ODM_RX_Dframe_INFO, m, false);
+ return 0;
+}
+static int proc_get_tx_info_msg(struct seq_file *m, void *v)
+{
+ unsigned long irqL;
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+ struct sta_info *psta;
+ u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ int i;
+ _list *plist, *phead;
+ u8 current_rate_id = 0, current_sgi = 0;
+
+ char *BW, *status;
+
+ _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE))
+ status = "station mode";
+ else if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE))
+ status = "AP mode";
+ else
+ status = " ";
+ _RTW_PRINT_SEL(m, "status=%s\n", status);
+ for (i = 0; i < NUM_STA; i++) {
+ phead = &(pstapriv->sta_hash[i]);
+ plist = get_next(phead);
+
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+
+ psta = LIST_CONTAINOR(plist, struct sta_info, hash_list);
+
+ plist = get_next(plist);
+
+ if ((memcmp(psta->hwaddr, bc_addr, 6))
+ && (memcmp(psta->hwaddr, null_addr, 6))
+ && (memcmp(psta->hwaddr, adapter_mac_addr(padapter), 6))) {
+
+ switch (psta->bw_mode) {
+
+ case CHANNEL_WIDTH_20:
+ BW = "20M";
+ break;
+
+ case CHANNEL_WIDTH_40:
+ BW = "40M";
+ break;
+
+ case CHANNEL_WIDTH_80:
+ BW = "80M";
+ break;
+
+ case CHANNEL_WIDTH_160:
+ BW = "160M";
+ break;
+
+ default:
+ BW = "";
+ break;
+ }
+ current_rate_id = rtw_get_current_tx_rate(adapter, psta->mac_id);
+ current_sgi = rtw_get_current_tx_sgi(adapter, psta->mac_id);
+
+ RTW_PRINT_SEL(m, "==============================\n");
+ _RTW_PRINT_SEL(m, "macaddr=" MAC_FMT"\n", MAC_ARG(psta->hwaddr));
+ _RTW_PRINT_SEL(m, "Tx_Data_Rate=%s\n", HDATA_RATE(current_rate_id));
+ _RTW_PRINT_SEL(m, "BW=%s,sgi=%u\n", BW, current_sgi);
+
+ }
+ }
+ }
+
+ _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL);
+
+ return 0;
+
+}
+
+
+static int proc_get_linked_info_dump(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ if (padapter)
+ RTW_PRINT_SEL(m, "linked_info_dump :%s\n", (padapter->bLinkInfoDump) ? "enable" : "disable");
+
+ return 0;
+}
+
+
+static ssize_t proc_set_linked_info_dump(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ char tmp[32] = {0};
+ int mode = 0, pre_mode = 0;
+ int num = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ pre_mode = padapter->bLinkInfoDump;
+ RTW_INFO("pre_mode=%d\n", pre_mode);
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ num = sscanf(tmp, "%d ", &mode);
+ RTW_INFO("num=%d mode=%d\n", num, mode);
+
+ if (num != 1) {
+ RTW_INFO("argument number is wrong\n");
+ return -EFAULT;
+ }
+
+ if (mode == 1 || (mode == 0 && pre_mode == 1)) /* not consider pwr_saving 0: */
+ padapter->bLinkInfoDump = mode;
+
+ else if ((mode == 2) || (mode == 0 && pre_mode == 2)) { /* consider power_saving */
+ /* RTW_INFO("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable") */
+ linked_info_dump(padapter, mode);
+ }
+ }
+ return count;
+}
+
+static int proc_get_mac_qinfo(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_hal_get_hwreg(adapter, HW_VAR_DUMP_MAC_QUEUE_INFO, (u8 *)m);
+
+ return 0;
+}
+
+int proc_get_wifi_spec(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregpriv = &padapter->registrypriv;
+
+ RTW_PRINT_SEL(m, "wifi_spec=%d\n", pregpriv->wifi_spec);
+ return 0;
+}
+
+static int proc_get_chan_plan(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_cur_chset(m, adapter);
+
+ return 0;
+}
+
+static ssize_t proc_set_chan_plan(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u8 chan_plan = RTW_CHPLAN_MAX;
+
+ if (!padapter)
+ return -EFAULT;
+
+ if (count < 1) {
+ RTW_INFO("argument size is less than 1\n");
+ return -EFAULT;
+ }
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ int num = sscanf(tmp, "%hhx", &chan_plan);
+ if (num != 1)
+ return count;
+ }
+
+ rtw_set_channel_plan(padapter, chan_plan);
+
+ return count;
+}
+
+static int proc_get_country_code(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ if (adapter->mlmepriv.country_ent)
+ dump_country_chplan(m, adapter->mlmepriv.country_ent);
+ else
+ RTW_PRINT_SEL(m, "unspecified\n");
+
+ return 0;
+}
+
+static ssize_t proc_set_country_code(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ char alpha2[2];
+ int num;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (!buffer || copy_from_user(tmp, buffer, count))
+ goto exit;
+
+ num = sscanf(tmp, "%c%c", &alpha2[0], &alpha2[1]);
+ if (num != 2)
+ return count;
+
+ rtw_set_country(padapter, alpha2);
+
+exit:
+ return count;
+}
+
+#if CONFIG_RTW_MACADDR_ACL
+static int proc_get_macaddr_acl(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_macaddr_acl(m, adapter);
+ return 0;
+}
+
+static ssize_t proc_set_macaddr_acl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *mlme = &adapter->mlmepriv;
+ struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+ char tmp[17 * NUM_ACL + 32] = {0};
+ u8 mode;
+ u8 addr[ETH_ALEN];
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ /* mode [<macaddr>] */
+ char *c, *next;
+
+ next = tmp;
+ c = strsep(&next, " \t");
+
+ if (sscanf(c, "%hhu", &mode) != 1)
+ return count;
+
+ if (mode >= RTW_ACL_MODE_MAX)
+ mode = RTW_ACL_MODE_DISABLED;
+
+ rtw_set_macaddr_acl(adapter, RTW_ACL_MODE_DISABLED); /* deinit first */
+ if (mode == RTW_ACL_MODE_DISABLED)
+ return count;
+
+ rtw_set_macaddr_acl(adapter, mode);
+
+ /* macaddr list */
+ c = strsep(&next, " \t");
+ while (c != NULL) {
+ if (sscanf(c, MAC_SFMT, MAC_SARG(addr)) != 6)
+ break;
+
+ if (rtw_check_invalid_mac_address(addr, 0) == false)
+ rtw_acl_add_sta(adapter, addr);
+
+ c = strsep(&next, " \t");
+ }
+
+ }
+
+exit:
+ return count;
+}
+#endif /* CONFIG_RTW_MACADDR_ACL */
+
+#if CONFIG_RTW_PRE_LINK_STA
+static int proc_get_pre_link_sta(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_pre_link_sta_ctl(m, &adapter->stapriv);
+ return 0;
+}
+
+ssize_t proc_set_pre_link_sta(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *mlme = &adapter->mlmepriv;
+ struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+ char tmp[17 * RTW_PRE_LINK_STA_NUM + 32] = {0};
+ char arg0[16] = {0};
+ u8 addr[ETH_ALEN];
+
+#define PRE_LINK_STA_CMD_RESET 0
+#define PRE_LINK_STA_CMD_ADD 1
+#define PRE_LINK_STA_CMD_DEL 2
+#define PRE_LINK_STA_CMD_NUM 3
+
+ static const char * const pre_link_sta_cmd_str[] = {
+ "reset",
+ "add",
+ "del"
+ };
+ u8 cmd_id = PRE_LINK_STA_CMD_NUM;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ /* cmd [<macaddr>] */
+ char *c, *next;
+ int i;
+
+ next = tmp;
+ c = strsep(&next, " \t");
+
+ if (sscanf(c, "%s", arg0) != 1)
+ goto exit;
+
+ for (i = 0; i < PRE_LINK_STA_CMD_NUM; i++)
+ if (strcmp(pre_link_sta_cmd_str[i], arg0) == 0)
+ cmd_id = i;
+
+ switch (cmd_id) {
+ case PRE_LINK_STA_CMD_RESET:
+ rtw_pre_link_sta_ctl_reset(&adapter->stapriv);
+ goto exit;
+ case PRE_LINK_STA_CMD_ADD:
+ case PRE_LINK_STA_CMD_DEL:
+ break;
+ default:
+ goto exit;
+ }
+
+ /* macaddr list */
+ c = strsep(&next, " \t");
+ while (c != NULL) {
+ if (sscanf(c, MAC_SFMT, MAC_SARG(addr)) != 6)
+ break;
+
+ if (rtw_check_invalid_mac_address(addr, 0) == false) {
+ if (cmd_id == PRE_LINK_STA_CMD_ADD)
+ rtw_pre_link_sta_add(&adapter->stapriv, addr);
+ else
+ rtw_pre_link_sta_del(&adapter->stapriv, addr);
+ }
+
+ c = strsep(&next, " \t");
+ }
+ }
+
+exit:
+ return count;
+}
+#endif /* CONFIG_RTW_PRE_LINK_STA */
+
+#ifdef CONFIG_DFS_MASTER
+ssize_t proc_set_update_non_ocp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *mlme = &adapter->mlmepriv;
+ struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+ char tmp[32];
+ u8 ch, bw = CHANNEL_WIDTH_20, offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+ int ms = -1;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhu %hhu %hhu %d", &ch, &bw, &offset, &ms);
+
+ if (num < 1 || (bw != CHANNEL_WIDTH_20 && num < 3))
+ goto exit;
+
+ if (bw == CHANNEL_WIDTH_20)
+ rtw_chset_update_non_ocp_ms(mlmeext->channel_set
+ , ch, bw, HAL_PRIME_CHNL_OFFSET_DONT_CARE, ms);
+ else
+ rtw_chset_update_non_ocp_ms(mlmeext->channel_set
+ , ch, bw, offset, ms);
+ }
+
+exit:
+ return count;
+}
+
+ssize_t proc_set_radar_detect(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+ char tmp[32];
+ u8 fake_radar_detect_cnt = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhu", &fake_radar_detect_cnt);
+
+ if (num < 1)
+ goto exit;
+
+ rfctl->dbg_dfs_master_fake_radar_detect_cnt = fake_radar_detect_cnt;
+ }
+
+exit:
+ return count;
+}
+
+static int proc_get_dfs_ch_sel_d_flags(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+
+ RTW_PRINT_SEL(m, "0x%02x\n", rfctl->dfs_ch_sel_d_flags);
+
+ return 0;
+}
+
+static ssize_t proc_set_dfs_ch_sel_d_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter);
+ char tmp[32];
+ u8 d_flags;
+ int num;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (!buffer || copy_from_user(tmp, buffer, count))
+ goto exit;
+
+ num = sscanf(tmp, "%hhx", &d_flags);
+ if (num != 1)
+ goto exit;
+
+ rfctl->dfs_ch_sel_d_flags = d_flags;
+
+exit:
+ return count;
+}
+#endif /* CONFIG_DFS_MASTER */
+
+static int proc_get_udpport(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct recv_priv *precvpriv = &(padapter->recvpriv);
+
+ RTW_PRINT_SEL(m, "%d\n", precvpriv->sink_udpport);
+ return 0;
+}
+static ssize_t proc_set_udpport(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct recv_priv *precvpriv = &(padapter->recvpriv);
+ int sink_udpport = 0;
+ char tmp[32];
+
+
+ if (!padapter)
+ return -EFAULT;
+
+ if (count < 1) {
+ RTW_INFO("argument size is less than 1\n");
+ return -EFAULT;
+ }
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%d", &sink_udpport);
+
+ if (num != 1) {
+ RTW_INFO("invalid input parameter number!\n");
+ return count;
+ }
+
+ }
+ precvpriv->sink_udpport = sink_udpport;
+
+ return count;
+
+}
+
+static int proc_get_mi_ap_bc_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+ u8 i;
+
+ for (i = 0; i < dvobj->iface_nums; i++)
+ RTW_PRINT_SEL(m, "iface_id:%d, mac_id && sec_cam_id = %d\n", i, macid_ctl->iface_bmc[i]);
+
+ return 0;
+}
+static int proc_get_macid_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj);
+ u8 chip_type = rtw_get_chip_type(adapter);
+ u8 i;
+ u8 null_addr[ETH_ALEN] = {0};
+ u8 *macaddr;
+
+ RTW_PRINT_SEL(m, "max_num:%u\n", macid_ctl->num);
+ RTW_PRINT_SEL(m, "\n");
+
+ RTW_PRINT_SEL(m, "used:\n");
+ dump_macid_map(m, &macid_ctl->used, macid_ctl->num);
+ RTW_PRINT_SEL(m, "\n");
+
+ RTW_PRINT_SEL(m, "%-3s %-3s %-4s %-4s %-17s %-6s %-3s"
+ , "id", "bmc", "if_g", "ch_g", "macaddr", "bw", "vht");
+
+ if (chip_type == RTL8814A)
+ _RTW_PRINT_SEL(m, " %-10s", "rate_bmp1");
+
+ _RTW_PRINT_SEL(m, " %-10s %s\n", "rate_bmp0", "status");
+
+ for (i = 0; i < macid_ctl->num; i++) {
+ if (rtw_macid_is_used(macid_ctl, i)
+ || macid_ctl->h2c_msr[i]
+ ) {
+ if (macid_ctl->sta[i])
+ macaddr = macid_ctl->sta[i]->hwaddr;
+ else
+ macaddr = null_addr;
+
+ RTW_PRINT_SEL(m, "%3u %3u %4d %4d "MAC_FMT" %6s %3u"
+ , i
+ , rtw_macid_is_bmc(macid_ctl, i)
+ , rtw_macid_get_if_g(macid_ctl, i)
+ , rtw_macid_get_ch_g(macid_ctl, i)
+ , MAC_ARG(macaddr)
+ , ch_width_str(macid_ctl->bw[i])
+ , macid_ctl->vht_en[i]
+ );
+
+ if (chip_type == RTL8814A)
+ _RTW_PRINT_SEL(m, " 0x%08X", macid_ctl->rate_bmp1[i]);
+
+ _RTW_PRINT_SEL(m, " 0x%08X "H2C_MSR_FMT" %s\n"
+ , macid_ctl->rate_bmp0[i]
+ , H2C_MSR_ARG(&macid_ctl->h2c_msr[i])
+ , rtw_macid_is_used(macid_ctl, i) ? "" : "[unused]"
+ );
+ }
+ }
+
+ return 0;
+}
+
+static int proc_get_sec_cam(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl;
+
+ RTW_PRINT_SEL(m, "sec_cap:0x%02x\n", cam_ctl->sec_cap);
+ RTW_PRINT_SEL(m, "flags:0x%08x\n", cam_ctl->flags);
+ RTW_PRINT_SEL(m, "\n");
+
+ RTW_PRINT_SEL(m, "max_num:%u\n", cam_ctl->num);
+ RTW_PRINT_SEL(m, "used:\n");
+ dump_sec_cam_map(m, &cam_ctl->used, cam_ctl->num);
+ RTW_PRINT_SEL(m, "\n");
+
+ RTW_PRINT_SEL(m, "reg_scr:0x%04x\n", rtw_read16(adapter, 0x680));
+ RTW_PRINT_SEL(m, "\n");
+
+ dump_sec_cam(m, adapter);
+
+ return 0;
+}
+
+static ssize_t proc_set_sec_cam(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
+ struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl;
+ char tmp[32] = {0};
+ char cmd[4];
+ u8 id_1 = 0, id_2 = 0;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ /* c <id_1>: clear specific cam entry */
+ /* wfc <id_1>: write specific cam entry from cam cache */
+ /* sw <id_1> <id_2>: sec_cam 1/2 swap */
+
+ int num = sscanf(tmp, "%s %hhu %hhu", cmd, &id_1, &id_2);
+
+ if (num < 2)
+ return count;
+
+ if ((id_1 >= cam_ctl->num) || (id_2 >= cam_ctl->num)) {
+ RTW_ERR(FUNC_ADPT_FMT" invalid id_1:%u id_2:%u\n", FUNC_ADPT_ARG(adapter), id_1, id_2);
+ return count;
+ }
+
+ if (strcmp("c", cmd) == 0) {
+ _clear_cam_entry(adapter, id_1);
+ adapter->securitypriv.hw_decrypted = false; /* temporarily set this for TX path to use SW enc */
+ } else if (strcmp("wfc", cmd) == 0)
+ write_cam_from_cache(adapter, id_1);
+ else if (strcmp("sw", cmd) == 0)
+ rtw_sec_cam_swap(adapter, id_1, id_2);
+ else if (strcmp("cdk", cmd) == 0)
+ rtw_clean_dk_section(adapter);
+#ifdef DBG_SEC_CAM_MOVE
+ else if (strcmp("sgd", cmd) == 0)
+ rtw_hal_move_sta_gk_to_dk(adapter);
+ else if (strcmp("rsd", cmd) == 0)
+ rtw_hal_read_sta_dk_key(adapter, id_1);
+#endif
+ }
+
+ return count;
+}
+
+static int proc_get_sec_cam_cache(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_sec_cam_cache(m, adapter);
+ return 0;
+}
+
+static ssize_t proc_set_change_bss_chbw(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct mlme_priv *mlme = &(adapter->mlmepriv);
+ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+ char tmp[32];
+ s16 ch;
+ s8 bw = -1, offset = -1;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hd %hhd %hhd", &ch, &bw, &offset);
+
+ if (num < 1 || (bw != CHANNEL_WIDTH_20 && num < 3))
+ goto exit;
+
+ if (check_fwstate(mlme, WIFI_AP_STATE) && check_fwstate(mlme, WIFI_ASOC_STATE))
+ rtw_change_bss_chbw_cmd(adapter, RTW_CMDF_WAIT_ACK, ch, bw, offset);
+ }
+
+exit:
+ return count;
+}
+
+static int proc_get_tx_bw_mode(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_PRINT_SEL(m, "0x%02x\n", adapter->driver_tx_bw_mode);
+ RTW_PRINT_SEL(m, "2.4G:%s\n", ch_width_str(ADAPTER_TX_BW_2G(adapter)));
+ RTW_PRINT_SEL(m, "5G:%s\n", ch_width_str(ADAPTER_TX_BW_5G(adapter)));
+
+ return 0;
+}
+
+static ssize_t proc_set_tx_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl;
+ struct mlme_priv *mlme = &(adapter->mlmepriv);
+ struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
+ char tmp[32];
+ u8 bw_mode;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ u8 update = false;
+ int num = sscanf(tmp, "%hhx", &bw_mode);
+
+ if (num < 1 || bw_mode == adapter->driver_tx_bw_mode)
+ goto exit;
+
+ if ((MLME_STATE(adapter) & WIFI_ASOC_STATE)
+ && ((mlmeext->cur_channel <= 14 && BW_MODE_2G(bw_mode) != ADAPTER_TX_BW_2G(adapter))
+ || (mlmeext->cur_channel >= 36 && BW_MODE_5G(bw_mode) != ADAPTER_TX_BW_5G(adapter)))
+ ) {
+ /* RA mask update needed */
+ update = true;
+ }
+ adapter->driver_tx_bw_mode = bw_mode;
+
+ if (update == true) {
+ struct sta_info *sta;
+ int i;
+
+ for (i = 0; i < MACID_NUM_SW_LIMIT; i++) {
+ sta = macid_ctl->sta[i];
+ if (sta && !is_broadcast_mac_addr(sta->hwaddr))
+ rtw_dm_ra_mask_wk_cmd(adapter, (u8 *)sta);
+ }
+ }
+ }
+
+exit:
+ return count;
+}
+
+static int proc_get_hal_txpwr_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter);
+
+ if (hal_is_band_support(adapter, BAND_ON_2_4G))
+ dump_hal_txpwr_info_2g(m, adapter, hal_spec->rfpath_num_2g, hal_spec->max_tx_cnt);
+
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+ if (hal_is_band_support(adapter, BAND_ON_5G))
+ dump_hal_txpwr_info_5g(m, adapter, hal_spec->rfpath_num_5g, hal_spec->max_tx_cnt);
+#endif
+
+ return 0;
+}
+
+static int proc_get_target_tx_power(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_target_tx_power(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_tx_power_by_rate(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_tx_power_by_rate(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_tx_power_limit(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_tx_power_limit(m, adapter);
+
+ return 0;
+}
+
+static int proc_get_tx_power_ext_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_tx_power_ext_info(m, adapter);
+
+ return 0;
+}
+
+static ssize_t proc_set_tx_power_ext_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ char tmp[32] = {0};
+ char cmd[16] = {0};
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%s", cmd);
+
+ if (num < 1)
+ return count;
+
+ #ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE
+ phy_free_filebuf_mask(adapter, LOAD_BB_PG_PARA_FILE | LOAD_RF_TXPWR_LMT_PARA_FILE);
+ #endif
+
+ rtw_ps_deny(adapter, PS_DENY_IOCTL);
+ LeaveAllPowerSaveModeDirect(adapter);
+
+ if (strcmp("default", cmd) == 0)
+ rtw_run_in_thread_cmd(adapter, ((void *)(phy_reload_default_tx_power_ext_info)), adapter);
+ else
+ rtw_run_in_thread_cmd(adapter, ((void *)(phy_reload_tx_power_ext_info)), adapter);
+
+ rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL);
+ }
+
+ return count;
+}
+
+static void *proc_start_tx_power_idx(struct seq_file *m, loff_t *pos)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 path = ((*pos) & 0xFF00) >> 8;
+ u8 rs = *pos & 0xFF;
+
+ if (path >= RF_PATH_MAX)
+ return NULL;
+
+ return pos;
+}
+static void proc_stop_tx_power_idx(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+}
+
+static void *proc_next_tx_power_idx(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 path = ((*pos) & 0xFF00) >> 8;
+ u8 rs = *pos & 0xFF;
+
+ rs++;
+ if (rs >= RATE_SECTION_NUM) {
+ rs = 0;
+ path++;
+ }
+
+ if (path >= RF_PATH_MAX)
+ return NULL;
+
+ *pos = (path << 8) | rs;
+
+ return pos;
+}
+
+static int proc_get_tx_power_idx(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ u32 pos = *((loff_t *)(v));
+ u8 path = (pos & 0xFF00) >> 8;
+ u8 rs = pos & 0xFF;
+
+ if (0)
+ RTW_INFO("%s path=%u, rs=%u\n", __func__, path, rs);
+
+ if (path == RF_PATH_A && rs == CCK)
+ dump_tx_power_idx_title(m, adapter);
+ dump_tx_power_idx_by_path_rs(m, adapter, path, rs);
+
+ return 0;
+}
+
+static struct seq_operations seq_ops_tx_power_idx = {
+ .start = proc_start_tx_power_idx,
+ .stop = proc_stop_tx_power_idx,
+ .next = proc_next_tx_power_idx,
+ .show = proc_get_tx_power_idx,
+};
+
+#ifdef CONFIG_RF_POWER_TRIM
+static int proc_get_kfree_flag(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct kfree_data_t *kfree_data = GET_KFREE_DATA(adapter);
+
+ RTW_PRINT_SEL(m, "0x%02x\n", kfree_data->flag);
+
+ return 0;
+}
+
+static ssize_t proc_set_kfree_flag(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct kfree_data_t *kfree_data = GET_KFREE_DATA(adapter);
+ char tmp[32] = {0};
+ u8 flag;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhx", &flag);
+
+ if (num < 1)
+ return count;
+
+ kfree_data->flag = flag;
+ }
+
+ return count;
+}
+
+static int proc_get_kfree_bb_gain(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+ struct kfree_data_t *kfree_data = GET_KFREE_DATA(adapter);
+ u8 i, j;
+
+ for (i = 0; i < BB_GAIN_NUM; i++) {
+ if (i == 0)
+ _RTW_PRINT_SEL(m, "2G: ");
+ else if (i == 1)
+ _RTW_PRINT_SEL(m, "5GLB1: ");
+ else if (i == 2)
+ _RTW_PRINT_SEL(m, "5GLB2: ");
+ else if (i == 3)
+ _RTW_PRINT_SEL(m, "5GMB1: ");
+ else if (i == 4)
+ _RTW_PRINT_SEL(m, "5GMB2: ");
+ else if (i == 5)
+ _RTW_PRINT_SEL(m, "5GHB: ");
+
+ for (j = 0; j < hal_data->NumTotalRFPath; j++)
+ _RTW_PRINT_SEL(m, "%d ", kfree_data->bb_gain[i][j]);
+ _RTW_PRINT_SEL(m, "\n");
+ }
+
+ return 0;
+}
+
+static ssize_t proc_set_kfree_bb_gain(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter);
+ struct kfree_data_t *kfree_data = GET_KFREE_DATA(adapter);
+ char tmp[BB_GAIN_NUM * RF_PATH_MAX] = {0};
+ u8 path, chidx;
+ s8 bb_gain[BB_GAIN_NUM];
+ char ch_band_Group[6];
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ char *c, *next;
+ int i = 0;
+
+ next = tmp;
+ c = strsep(&next, " \t");
+
+ if (sscanf(c, "%s", ch_band_Group) != 1) {
+ RTW_INFO("Error Head Format, channel Group select\n,Please input:\t 2G , 5GLB1 , 5GLB2 , 5GMB1 , 5GMB2 , 5GHB\n");
+ return count;
+ }
+ if (strcmp("2G", ch_band_Group) == 0)
+ chidx = BB_GAIN_2G;
+#ifdef CONFIG_IEEE80211_BAND_5GHZ
+ else if (strcmp("5GLB1", ch_band_Group) == 0)
+ chidx = BB_GAIN_5GLB1;
+ else if (strcmp("5GLB2", ch_band_Group) == 0)
+ chidx = BB_GAIN_5GLB2;
+ else if (strcmp("5GMB1", ch_band_Group) == 0)
+ chidx = BB_GAIN_5GMB1;
+ else if (strcmp("5GMB2", ch_band_Group) == 0)
+ chidx = BB_GAIN_5GMB2;
+ else if (strcmp("5GHB", ch_band_Group) == 0)
+ chidx = BB_GAIN_5GHB;
+#endif /*CONFIG_IEEE80211_BAND_5GHZ*/
+ else {
+ RTW_INFO("Error Head Format, channel Group select\n,Please input:\t 2G , 5GLB1 , 5GLB2 , 5GMB1 , 5GMB2 , 5GHB\n");
+ return count;
+ }
+ c = strsep(&next, " \t");
+
+ while (c != NULL) {
+ if (sscanf(c, "%hhx", &bb_gain[i]) != 1)
+ break;
+
+ kfree_data->bb_gain[chidx][i] = bb_gain[i];
+ RTW_INFO("%s,kfree_data->bb_gain[%d][%d]=%x\n", __func__, chidx, i, kfree_data->bb_gain[chidx][i]);
+
+ c = strsep(&next, " \t");
+ i++;
+ }
+
+ }
+
+ return count;
+
+}
+
+static int proc_get_kfree_thermal(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct kfree_data_t *kfree_data = GET_KFREE_DATA(adapter);
+
+ _RTW_PRINT_SEL(m, "%d\n", kfree_data->thermal);
+
+ return 0;
+}
+
+static ssize_t proc_set_kfree_thermal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct kfree_data_t *kfree_data = GET_KFREE_DATA(adapter);
+ char tmp[32] = {0};
+ s8 thermal;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhd", &thermal);
+
+ if (num < 1)
+ return count;
+
+ kfree_data->thermal = thermal;
+ }
+
+ return count;
+}
+
+static ssize_t proc_set_tx_gain_offset(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *adapter;
+ char tmp[32] = {0};
+ u8 rf_path;
+ s8 offset;
+
+ adapter = (_adapter *)rtw_netdev_priv(dev);
+ if (!adapter)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ u8 write_value;
+ int num = sscanf(tmp, "%hhu %hhd", &rf_path, &offset);
+
+ if (num < 2)
+ return count;
+
+ RTW_INFO("write rf_path:%u tx gain offset:%d\n", rf_path, offset);
+ rtw_rf_set_tx_gain_offset(adapter, rf_path, offset);
+ }
+
+ return count;
+}
+#endif /* CONFIG_RF_POWER_TRIM */
+
+#ifdef CONFIG_BT_COEXIST
+ssize_t proc_set_btinfo_evt(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u8 btinfo[8];
+
+ if (count < 6)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ int num = 0;
+
+ memset(btinfo, 0, 8);
+
+ num = sscanf(tmp, "%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx"
+ , &btinfo[0], &btinfo[1], &btinfo[2], &btinfo[3]
+ , &btinfo[4], &btinfo[5], &btinfo[6], &btinfo[7]);
+
+ if (num < 6)
+ return -EINVAL;
+
+ btinfo[1] = num - 2;
+
+ rtw_btinfo_cmd(padapter, btinfo, btinfo[1] + 2);
+ }
+
+ return count;
+}
+
+static u8 btreg_read_type = 0;
+static u16 btreg_read_addr = 0;
+static int btreg_read_error = 0;
+static u8 btreg_write_type = 0;
+static u16 btreg_write_addr = 0;
+static int btreg_write_error = 0;
+
+static u8 *btreg_type[] = {
+ "rf",
+ "modem",
+ "bluewize",
+ "vendor",
+ "le"
+};
+
+static int btreg_parse_str(char const *input, u8 *type, u16 *addr, u16 *val)
+{
+ u32 num;
+ u8 str[80] = {0};
+ u8 t = 0;
+ u32 a, v;
+ u8 i, n;
+ u8 *p;
+
+
+ num = sscanf(input, "%s %x %x", str, &a, &v);
+ if (num < 2) {
+ RTW_INFO("%s: INVALID input!(%s)\n", __func__, input);
+ return -EINVAL;
+ }
+ if ((num < 3) && val) {
+ RTW_INFO("%s: INVALID input!(%s)\n", __func__, input);
+ return -EINVAL;
+ }
+
+ /* convert to lower case for following type compare */
+ p = str;
+ for (; *p; ++p)
+ *p = tolower(*p);
+ n = sizeof(btreg_type) / sizeof(btreg_type[0]);
+ for (i = 0; i < n; i++) {
+ if (!strcmp(str, btreg_type[i])) {
+ t = i;
+ break;
+ }
+ }
+ if (i == n) {
+ RTW_INFO("%s: unknown type(%s)!\n", __func__, str);
+ return -EINVAL;
+ }
+
+ switch (t) {
+ case 0:
+ /* RF */
+ if (a & 0xFFFFFF80) {
+ RTW_INFO("%s: INVALID address(0x%X) for type %s(%d)!\n",
+ __func__, a, btreg_type[t], t);
+ return -EINVAL;
+ }
+ break;
+ case 1:
+ /* Modem */
+ if (a & 0xFFFFFE00) {
+ RTW_INFO("%s: INVALID address(0x%X) for type %s(%d)!\n",
+ __func__, a, btreg_type[t], t);
+ return -EINVAL;
+ }
+ break;
+ default:
+ /* Others(Bluewize, Vendor, LE) */
+ if (a & 0xFFFFF000) {
+ RTW_INFO("%s: INVALID address(0x%X) for type %s(%d)!\n",
+ __func__, a, btreg_type[t], t);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ if (val) {
+ if (v & 0xFFFF0000) {
+ RTW_INFO("%s: INVALID value(0x%x)!\n", __func__, v);
+ return -EINVAL;
+ }
+ *val = (u16)v;
+ }
+
+ *type = (u8)t;
+ *addr = (u16)a;
+
+ return 0;
+}
+
+int proc_get_btreg_read(struct seq_file *m, void *v)
+{
+ struct net_device *dev;
+ PADAPTER padapter;
+ u16 ret;
+ u32 data;
+
+
+ if (btreg_read_error)
+ return btreg_read_error;
+
+ dev = m->private;
+ padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+ ret = rtw_btcoex_btreg_read(padapter, btreg_read_type, btreg_read_addr, &data);
+ if (CHECK_STATUS_CODE_FROM_BT_MP_OPER_RET(ret, BT_STATUS_BT_OP_SUCCESS))
+ RTW_PRINT_SEL(m, "BTREG read: (%s)0x%04X = 0x%08x\n", btreg_type[btreg_read_type], btreg_read_addr, data);
+ else
+ RTW_PRINT_SEL(m, "BTREG read: (%s)0x%04X read fail. error code = 0x%04x.\n", btreg_type[btreg_read_type], btreg_read_addr, ret);
+
+ return 0;
+}
+
+ssize_t proc_set_btreg_read(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ PADAPTER padapter;
+ u8 tmp[80] = {0};
+ u32 num;
+ int err;
+
+
+ padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+ if (NULL == buffer) {
+ RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n",
+ FUNC_ADPT_ARG(padapter));
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (count < 1) {
+ RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n",
+ FUNC_ADPT_ARG(padapter));
+ err = -EFAULT;
+ goto exit;
+ }
+
+ num = count;
+ if (num > (sizeof(tmp) - 1))
+ num = (sizeof(tmp) - 1);
+
+ if (copy_from_user(tmp, buffer, num)) {
+ RTW_INFO(FUNC_ADPT_FMT ": copy buffer from user space FAIL!\n",
+ FUNC_ADPT_ARG(padapter));
+ err = -EFAULT;
+ goto exit;
+ }
+ /* [Coverity] sure tmp end with '\0'(string terminal) */
+ tmp[sizeof(tmp) - 1] = 0;
+
+ err = btreg_parse_str(tmp, &btreg_read_type, &btreg_read_addr, NULL);
+ if (err)
+ goto exit;
+
+ RTW_INFO(FUNC_ADPT_FMT ": addr=(%s)0x%X\n",
+ FUNC_ADPT_ARG(padapter), btreg_type[btreg_read_type], btreg_read_addr);
+
+exit:
+ btreg_read_error = err;
+
+ return count;
+}
+
+int proc_get_btreg_write(struct seq_file *m, void *v)
+{
+ struct net_device *dev;
+ PADAPTER padapter;
+ u16 ret;
+ u32 data;
+
+
+ if (btreg_write_error < 0)
+ return btreg_write_error;
+ else if (btreg_write_error > 0) {
+ RTW_PRINT_SEL(m, "BTREG write: (%s)0x%04X write fail. error code = 0x%04x.\n", btreg_type[btreg_write_type], btreg_write_addr, btreg_write_error);
+ return 0;
+ }
+
+ dev = m->private;
+ padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+ ret = rtw_btcoex_btreg_read(padapter, btreg_write_type, btreg_write_addr, &data);
+ if (CHECK_STATUS_CODE_FROM_BT_MP_OPER_RET(ret, BT_STATUS_BT_OP_SUCCESS))
+ RTW_PRINT_SEL(m, "BTREG read: (%s)0x%04X = 0x%08x\n", btreg_type[btreg_write_type], btreg_write_addr, data);
+ else
+ RTW_PRINT_SEL(m, "BTREG read: (%s)0x%04X read fail. error code = 0x%04x.\n", btreg_type[btreg_write_type], btreg_write_addr, ret);
+
+ return 0;
+}
+
+ssize_t proc_set_btreg_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ PADAPTER padapter;
+ u8 tmp[80] = {0};
+ u32 num;
+ u16 val;
+ u16 ret;
+ int err;
+
+
+ padapter = (PADAPTER)rtw_netdev_priv(dev);
+
+ if (NULL == buffer) {
+ RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n",
+ FUNC_ADPT_ARG(padapter));
+ err = -EFAULT;
+ goto exit;
+ }
+
+ if (count < 1) {
+ RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n",
+ FUNC_ADPT_ARG(padapter));
+ err = -EFAULT;
+ goto exit;
+ }
+
+ num = count;
+ if (num > (sizeof(tmp) - 1))
+ num = (sizeof(tmp) - 1);
+
+ if (copy_from_user(tmp, buffer, num)) {
+ RTW_INFO(FUNC_ADPT_FMT ": copy buffer from user space FAIL!\n",
+ FUNC_ADPT_ARG(padapter));
+ err = -EFAULT;
+ goto exit;
+ }
+
+ err = btreg_parse_str(tmp, &btreg_write_type, &btreg_write_addr, &val);
+ if (err)
+ goto exit;
+
+ RTW_INFO(FUNC_ADPT_FMT ": Set (%s)0x%X = 0x%x\n",
+ FUNC_ADPT_ARG(padapter), btreg_type[btreg_write_type], btreg_write_addr, val);
+
+ ret = rtw_btcoex_btreg_write(padapter, btreg_write_type, btreg_write_addr, val);
+ if (!CHECK_STATUS_CODE_FROM_BT_MP_OPER_RET(ret, BT_STATUS_BT_OP_SUCCESS))
+ err = ret;
+
+exit:
+ btreg_write_error = err;
+
+ return count;
+}
+#endif /* CONFIG_BT_COEXIST */
+
+#ifdef CONFIG_MBSSID_CAM
+int proc_get_mbid_cam_cache(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_mbid_cam_cache_dump(m, __func__, adapter);
+ rtw_mbid_cam_dump(m, __func__, adapter);
+ return 0;
+}
+#endif /* CONFIG_MBSSID_CAM */
+
+static int proc_get_mac_addr(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_hal_dump_macaddr(m, adapter);
+ return 0;
+}
+
+static int proc_get_skip_band(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ int bandskip;
+
+ bandskip = RTW_GET_SCAN_BAND_SKIP(adapter);
+ RTW_PRINT_SEL(m, "bandskip:0x%02x\n", bandskip);
+ return 0;
+}
+
+static ssize_t proc_set_skip_band(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[6];
+ u8 skip_band;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhu", &skip_band);
+
+ if (num < 1)
+ return -EINVAL;
+
+ if (1 == skip_band)
+ RTW_SET_SCAN_BAND_SKIP(padapter, BAND_24G);
+ else if (2 == skip_band)
+ RTW_SET_SCAN_BAND_SKIP(padapter, BAND_5G);
+ else if (3 == skip_band)
+ RTW_CLR_SCAN_BAND_SKIP(padapter, BAND_24G);
+ else if (4 == skip_band)
+ RTW_CLR_SCAN_BAND_SKIP(padapter, BAND_5G);
+ }
+ return count;
+
+}
+
+#ifdef CONFIG_AUTO_CHNL_SEL_NHM
+static int proc_get_best_chan(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ u8 best_24g_ch = 0, best_5g_ch = 0;
+
+ rtw_hal_get_odm_var(adapter, HAL_ODM_AUTO_CHNL_SEL, &(best_24g_ch), &(best_5g_ch));
+
+ RTW_PRINT_SEL(m, "Best 2.4G CH:%u\n", best_24g_ch);
+ RTW_PRINT_SEL(m, "Best 5G CH:%u\n", best_5g_ch);
+ return 0;
+}
+
+static ssize_t proc_set_acs(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u8 acs_satae = 0;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhu", &acs_satae);
+
+ if (num < 1)
+ return -EINVAL;
+
+ if (1 == acs_satae)
+ rtw_acs_start(padapter, true);
+ else
+ rtw_acs_start(padapter, false);
+
+ }
+ return count;
+}
+#endif
+
+static int proc_get_hal_spec(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_hal_spec(m, adapter);
+ return 0;
+}
+
+static int proc_get_phy_cap(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_dump_phy_cap(m, adapter);
+ rtw_dump_drv_phy_cap(m, adapter);
+ rtw_get_dft_phy_cap(m, adapter);
+ return 0;
+}
+
+#ifdef CONFIG_SUPPORT_TRX_SHARED
+#include "../../hal/hal_halmac.h"
+static int proc_get_trx_share_mode(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ dump_trx_share_mode(m, adapter);
+ return 0;
+}
+#endif
+
+static int proc_dump_rsvd_page(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_dump_rsvd_page(m, adapter, adapter->rsvd_page_offset, adapter->rsvd_page_num);
+ return 0;
+}
+static ssize_t proc_set_rsvd_page_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u8 page_offset, page_num;
+
+ if (count < 2)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhu %hhu", &page_offset, &page_num);
+
+ if (num < 2)
+ return -EINVAL;
+ padapter->rsvd_page_offset = page_offset;
+ padapter->rsvd_page_num = page_num;
+ }
+ return count;
+}
+
+#ifdef CONFIG_WOW_PATTERN_HW_CAM
+int proc_dump_pattern_cam(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ int i;
+ struct rtl_wow_pattern context;
+
+ for (i = 0 ; i < pwrpriv->wowlan_pattern_idx; i++) {
+ rtw_wow_pattern_read_cam_ent(padapter, i, &context);
+ rtw_dump_wow_pattern(m, &context, i);
+ }
+
+ return 0;
+}
+#endif
+
+static int proc_get_napi_info(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
+ struct registry_priv *pregistrypriv = &adapter->registrypriv;
+ u8 napi = 0, gro = 0;
+ u32 weight = 0;
+
+
+#ifdef CONFIG_RTW_NAPI
+ if (pregistrypriv->en_napi) {
+ napi = 1;
+ weight = RTL_NAPI_WEIGHT;
+ }
+
+#ifdef CONFIG_RTW_GRO
+ if (pregistrypriv->en_gro)
+ gro = 1;
+#endif /* CONFIG_RTW_GRO */
+#endif /* CONFIG_RTW_NAPI */
+
+ if (napi)
+ RTW_PRINT_SEL(m, "NAPI enable, weight=%d\n", weight);
+ else
+ RTW_PRINT_SEL(m, "NAPI disable\n");
+ RTW_PRINT_SEL(m, "GRO %s\n", gro?"enable":"disable");
+
+ return 0;
+}
+
+/*
+* rtw_adapter_proc:
+* init/deinit when register/unregister net_device
+*/
+static const struct rtw_proc_hdl adapter_proc_hdls[] = {
+#if RTW_SEQ_FILE_TEST
+ RTW_PROC_HDL_SEQ("seq_file_test", &seq_file_test, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("write_reg", NULL, proc_set_write_reg),
+ RTW_PROC_HDL_SSEQ("read_reg", proc_get_read_reg, proc_set_read_reg),
+ RTW_PROC_HDL_SSEQ("tx_rate_bmp", proc_get_dump_tx_rate_bmp, NULL),
+ RTW_PROC_HDL_SSEQ("adapters_status", proc_get_dump_adapters_status, NULL),
+#ifdef CONFIG_RTW_CUSTOMER_STR
+ RTW_PROC_HDL_SSEQ("customer_str", proc_get_customer_str, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("fwstate", proc_get_fwstate, NULL),
+ RTW_PROC_HDL_SSEQ("sec_info", proc_get_sec_info, NULL),
+ RTW_PROC_HDL_SSEQ("mlmext_state", proc_get_mlmext_state, NULL),
+ RTW_PROC_HDL_SSEQ("qos_option", proc_get_qos_option, NULL),
+ RTW_PROC_HDL_SSEQ("ht_option", proc_get_ht_option, NULL),
+ RTW_PROC_HDL_SSEQ("rf_info", proc_get_rf_info, NULL),
+ RTW_PROC_HDL_SSEQ("scan_param", proc_get_scan_param, proc_set_scan_param),
+ RTW_PROC_HDL_SSEQ("scan_abort", proc_get_scan_abort, NULL),
+#ifdef CONFIG_SCAN_BACKOP
+ RTW_PROC_HDL_SSEQ("backop_flags_sta", proc_get_backop_flags_sta, proc_set_backop_flags_sta),
+ RTW_PROC_HDL_SSEQ("backop_flags_ap", proc_get_backop_flags_ap, proc_set_backop_flags_ap),
+#endif
+ RTW_PROC_HDL_SSEQ("survey_info", proc_get_survey_info, proc_set_survey_info),
+ RTW_PROC_HDL_SSEQ("ap_info", proc_get_ap_info, NULL),
+ RTW_PROC_HDL_SSEQ("trx_info", proc_get_trx_info, proc_reset_trx_info),
+ RTW_PROC_HDL_SSEQ("tx_power_offset", proc_get_tx_power_offset, proc_set_tx_power_offset),
+ RTW_PROC_HDL_SSEQ("rate_ctl", proc_get_rate_ctl, proc_set_rate_ctl),
+ RTW_PROC_HDL_SSEQ("bw_ctl", proc_get_bw_ctl, proc_set_bw_ctl),
+ RTW_PROC_HDL_SSEQ("dis_pwt_ctl", proc_get_dis_pwt, proc_set_dis_pwt),
+ RTW_PROC_HDL_SSEQ("mac_qinfo", proc_get_mac_qinfo, NULL),
+ RTW_PROC_HDL_SSEQ("macid_info", proc_get_macid_info, NULL),
+ RTW_PROC_HDL_SSEQ("bcmc_info", proc_get_mi_ap_bc_info, NULL),
+ RTW_PROC_HDL_SSEQ("sec_cam", proc_get_sec_cam, proc_set_sec_cam),
+ RTW_PROC_HDL_SSEQ("sec_cam_cache", proc_get_sec_cam_cache, NULL),
+ RTW_PROC_HDL_SSEQ("suspend_info", proc_get_suspend_resume_info, NULL),
+ RTW_PROC_HDL_SSEQ("wifi_spec", proc_get_wifi_spec, NULL),
+#ifdef CONFIG_LAYER2_ROAMING
+ RTW_PROC_HDL_SSEQ("roam_flags", proc_get_roam_flags, proc_set_roam_flags),
+ RTW_PROC_HDL_SSEQ("roam_param", proc_get_roam_param, proc_set_roam_param),
+ RTW_PROC_HDL_SSEQ("roam_tgt_addr", NULL, proc_set_roam_tgt_addr),
+#endif /* CONFIG_LAYER2_ROAMING */
+
+#ifdef CONFIG_RTW_80211R
+ RTW_PROC_HDL_SSEQ("ft_flags", proc_get_ft_flags, proc_set_ft_flags),
+#endif
+
+#ifdef CONFIG_SDIO_HCI
+ RTW_PROC_HDL_SSEQ("sd_f0_reg_dump", proc_get_sd_f0_reg_dump, NULL),
+ RTW_PROC_HDL_SSEQ("sdio_local_reg_dump", proc_get_sdio_local_reg_dump, NULL),
+#endif /* CONFIG_SDIO_HCI */
+
+ RTW_PROC_HDL_SSEQ("fwdl_test_case", NULL, proc_set_fwdl_test_case),
+ RTW_PROC_HDL_SSEQ("del_rx_ampdu_test_case", NULL, proc_set_del_rx_ampdu_test_case),
+ RTW_PROC_HDL_SSEQ("wait_hiq_empty", NULL, proc_set_wait_hiq_empty),
+
+ RTW_PROC_HDL_SSEQ("mac_reg_dump", proc_get_mac_reg_dump, NULL),
+ RTW_PROC_HDL_SSEQ("bb_reg_dump", proc_get_bb_reg_dump, NULL),
+ RTW_PROC_HDL_SSEQ("bb_reg_dump_ex", proc_get_bb_reg_dump_ex, NULL),
+ RTW_PROC_HDL_SSEQ("rf_reg_dump", proc_get_rf_reg_dump, NULL),
+
+#ifdef CONFIG_AP_MODE
+ RTW_PROC_HDL_SSEQ("all_sta_info", proc_get_all_sta_info, NULL),
+#endif /* CONFIG_AP_MODE */
+
+#ifdef CONFIG_FIND_BEST_CHANNEL
+ RTW_PROC_HDL_SSEQ("best_channel", proc_get_best_channel, proc_set_best_channel),
+#endif
+
+ RTW_PROC_HDL_SSEQ("rx_signal", proc_get_rx_signal, proc_set_rx_signal),
+ RTW_PROC_HDL_SSEQ("hw_info", proc_get_hw_status, proc_set_hw_status),
+
+ RTW_PROC_HDL_SSEQ("ht_enable", proc_get_ht_enable, proc_set_ht_enable),
+ RTW_PROC_HDL_SSEQ("bw_mode", proc_get_bw_mode, proc_set_bw_mode),
+ RTW_PROC_HDL_SSEQ("ampdu_enable", proc_get_ampdu_enable, proc_set_ampdu_enable),
+ RTW_PROC_HDL_SSEQ("rx_ampdu", proc_get_rx_ampdu, proc_set_rx_ampdu),
+ RTW_PROC_HDL_SSEQ("rx_ampdu_factor", proc_get_rx_ampdu_factor, proc_set_rx_ampdu_factor),
+ RTW_PROC_HDL_SSEQ("rx_ampdu_density", proc_get_rx_ampdu_density, proc_set_rx_ampdu_density),
+ RTW_PROC_HDL_SSEQ("tx_ampdu_density", proc_get_tx_ampdu_density, proc_set_tx_ampdu_density),
+#ifdef CONFIG_TX_AMSDU
+ RTW_PROC_HDL_SSEQ("tx_amsdu", proc_get_tx_amsdu, proc_set_tx_amsdu),
+ RTW_PROC_HDL_SSEQ("tx_amsdu_rate", proc_get_tx_amsdu_rate, proc_set_tx_amsdu_rate),
+#endif
+
+ RTW_PROC_HDL_SSEQ("en_fwps", proc_get_en_fwps, proc_set_en_fwps),
+ RTW_PROC_HDL_SSEQ("mac_rptbuf", proc_get_mac_rptbuf, NULL),
+
+ /* RTW_PROC_HDL_SSEQ("path_rssi", proc_get_two_path_rssi, NULL),
+ * RTW_PROC_HDL_SSEQ("rssi_disp",proc_get_rssi_disp, proc_set_rssi_disp), */
+
+#ifdef CONFIG_BT_COEXIST
+ RTW_PROC_HDL_SSEQ("btcoex_dbg", proc_get_btcoex_dbg, proc_set_btcoex_dbg),
+ RTW_PROC_HDL_SSEQ("btcoex", proc_get_btcoex_info, NULL),
+ RTW_PROC_HDL_SSEQ("btinfo_evt", NULL, proc_set_btinfo_evt),
+ RTW_PROC_HDL_SSEQ("btreg_read", proc_get_btreg_read, proc_set_btreg_read),
+ RTW_PROC_HDL_SSEQ("btreg_write", proc_get_btreg_write, proc_set_btreg_write),
+#endif /* CONFIG_BT_COEXIST */
+
+#if defined(DBG_CONFIG_ERROR_DETECT)
+ RTW_PROC_HDL_SSEQ("sreset", proc_get_sreset, proc_set_sreset),
+#endif /* DBG_CONFIG_ERROR_DETECT */
+ RTW_PROC_HDL_SSEQ("trx_info_debug", proc_get_trx_info_debug, NULL),
+ RTW_PROC_HDL_SSEQ("linked_info_dump", proc_get_linked_info_dump, proc_set_linked_info_dump),
+ RTW_PROC_HDL_SSEQ("tx_info_msg", proc_get_tx_info_msg, NULL),
+ RTW_PROC_HDL_SSEQ("rx_info_msg", proc_get_rx_info_msg, proc_set_rx_info_msg),
+#ifdef CONFIG_GPIO_API
+ RTW_PROC_HDL_SSEQ("gpio_info", proc_get_gpio, proc_set_gpio),
+ RTW_PROC_HDL_SSEQ("gpio_set_output_value", NULL, proc_set_gpio_output_value),
+ RTW_PROC_HDL_SSEQ("gpio_set_direction", NULL, proc_set_config_gpio),
+#endif
+
+#ifdef CONFIG_DBG_COUNTER
+ RTW_PROC_HDL_SSEQ("rx_logs", proc_get_rx_logs, NULL),
+ RTW_PROC_HDL_SSEQ("tx_logs", proc_get_tx_logs, NULL),
+ RTW_PROC_HDL_SSEQ("int_logs", proc_get_int_logs, NULL),
+#endif
+
+#ifdef CONFIG_PCI_HCI
+ RTW_PROC_HDL_SSEQ("rx_ring", proc_get_rx_ring, NULL),
+ RTW_PROC_HDL_SSEQ("tx_ring", proc_get_tx_ring, NULL),
+#endif
+
+#ifdef CONFIG_WOWLAN
+ RTW_PROC_HDL_SSEQ("wow_pattern_info", proc_get_pattern_info, proc_set_pattern_info),
+ RTW_PROC_HDL_SSEQ("wowlan_last_wake_reason", proc_get_wakeup_reason, NULL),
+#ifdef CONFIG_WOW_PATTERN_HW_CAM
+ RTW_PROC_HDL_SSEQ("wow_pattern_cam", proc_dump_pattern_cam, NULL),
+#endif
+#endif
+
+#ifdef CONFIG_GPIO_WAKEUP
+ RTW_PROC_HDL_SSEQ("wowlan_gpio_info", proc_get_wowlan_gpio_info, proc_set_wowlan_gpio_info),
+#endif
+#ifdef CONFIG_P2P_WOWLAN
+ RTW_PROC_HDL_SSEQ("p2p_wowlan_info", proc_get_p2p_wowlan_info, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("country_code", proc_get_country_code, proc_set_country_code),
+ RTW_PROC_HDL_SSEQ("chan_plan", proc_get_chan_plan, proc_set_chan_plan),
+#if CONFIG_RTW_MACADDR_ACL
+ RTW_PROC_HDL_SSEQ("macaddr_acl", proc_get_macaddr_acl, proc_set_macaddr_acl),
+#endif
+#if CONFIG_RTW_PRE_LINK_STA
+ RTW_PROC_HDL_SSEQ("pre_link_sta", proc_get_pre_link_sta, proc_set_pre_link_sta),
+#endif
+#ifdef CONFIG_DFS_MASTER
+ RTW_PROC_HDL_SSEQ("dfs_master_test_case", proc_get_dfs_master_test_case, proc_set_dfs_master_test_case),
+ RTW_PROC_HDL_SSEQ("update_non_ocp", NULL, proc_set_update_non_ocp),
+ RTW_PROC_HDL_SSEQ("radar_detect", NULL, proc_set_radar_detect),
+ RTW_PROC_HDL_SSEQ("dfs_ch_sel_d_flags", proc_get_dfs_ch_sel_d_flags, proc_set_dfs_ch_sel_d_flags),
+#endif
+ RTW_PROC_HDL_SSEQ("new_bcn_max", proc_get_new_bcn_max, proc_set_new_bcn_max),
+ RTW_PROC_HDL_SSEQ("sink_udpport", proc_get_udpport, proc_set_udpport),
+#ifdef DBG_RX_COUNTER_DUMP
+ RTW_PROC_HDL_SSEQ("dump_rx_cnt_mode", proc_get_rx_cnt_dump, proc_set_rx_cnt_dump),
+#endif
+ RTW_PROC_HDL_SSEQ("change_bss_chbw", NULL, proc_set_change_bss_chbw),
+ RTW_PROC_HDL_SSEQ("tx_bw_mode", proc_get_tx_bw_mode, proc_set_tx_bw_mode),
+ RTW_PROC_HDL_SSEQ("hal_txpwr_info", proc_get_hal_txpwr_info, NULL),
+ RTW_PROC_HDL_SSEQ("target_tx_power", proc_get_target_tx_power, NULL),
+ RTW_PROC_HDL_SSEQ("tx_power_by_rate", proc_get_tx_power_by_rate, NULL),
+ RTW_PROC_HDL_SSEQ("tx_power_limit", proc_get_tx_power_limit, NULL),
+ RTW_PROC_HDL_SSEQ("tx_power_ext_info", proc_get_tx_power_ext_info, proc_set_tx_power_ext_info),
+ RTW_PROC_HDL_SEQ("tx_power_idx", &seq_ops_tx_power_idx, NULL),
+#ifdef CONFIG_RF_POWER_TRIM
+ RTW_PROC_HDL_SSEQ("tx_gain_offset", NULL, proc_set_tx_gain_offset),
+ RTW_PROC_HDL_SSEQ("kfree_flag", proc_get_kfree_flag, proc_set_kfree_flag),
+ RTW_PROC_HDL_SSEQ("kfree_bb_gain", proc_get_kfree_bb_gain, proc_set_kfree_bb_gain),
+ RTW_PROC_HDL_SSEQ("kfree_thermal", proc_get_kfree_thermal, proc_set_kfree_thermal),
+#endif
+#ifdef CONFIG_POWER_SAVING
+ RTW_PROC_HDL_SSEQ("ps_info", proc_get_ps_info, NULL),
+#endif
+#ifdef CONFIG_TDLS
+ RTW_PROC_HDL_SSEQ("tdls_info", proc_get_tdls_info, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("monitor", proc_get_monitor, proc_set_monitor),
+
+#ifdef CONFIG_AUTO_CHNL_SEL_NHM
+ RTW_PROC_HDL_SSEQ("acs", proc_get_best_chan, proc_set_acs),
+#endif
+#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
+ RTW_PROC_HDL_SSEQ("rtkm_info", proc_get_rtkm_info, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("efuse_map", proc_get_efuse_map, NULL),
+#ifdef CONFIG_IEEE80211W
+ RTW_PROC_HDL_SSEQ("11w_tx_sa_query", proc_get_tx_sa_query, proc_set_tx_sa_query),
+ RTW_PROC_HDL_SSEQ("11w_tx_deauth", proc_get_tx_deauth, proc_set_tx_deauth),
+ RTW_PROC_HDL_SSEQ("11w_tx_auth", proc_get_tx_auth, proc_set_tx_auth),
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_MBSSID_CAM
+ RTW_PROC_HDL_SSEQ("mbid_cam", proc_get_mbid_cam_cache, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("mac_addr", proc_get_mac_addr, NULL),
+ RTW_PROC_HDL_SSEQ("skip_band", proc_get_skip_band, proc_set_skip_band),
+ RTW_PROC_HDL_SSEQ("hal_spec", proc_get_hal_spec, NULL),
+
+ RTW_PROC_HDL_SSEQ("rx_stat", proc_get_rx_stat, NULL),
+
+ RTW_PROC_HDL_SSEQ("tx_stat", proc_get_tx_stat, NULL),
+ /**** PHY Capability ****/
+ RTW_PROC_HDL_SSEQ("phy_cap", proc_get_phy_cap, NULL),
+
+ RTW_PROC_HDL_SSEQ("rx_stbc", proc_get_rx_stbc, proc_set_rx_stbc),
+ RTW_PROC_HDL_SSEQ("stbc_cap", proc_get_stbc_cap, proc_set_stbc_cap),
+ RTW_PROC_HDL_SSEQ("ldpc_cap", proc_get_ldpc_cap, proc_set_ldpc_cap),
+#ifdef CONFIG_BEAMFORMING
+ RTW_PROC_HDL_SSEQ("txbf_cap", proc_get_txbf_cap, proc_set_txbf_cap),
+#endif
+
+#ifdef CONFIG_SUPPORT_TRX_SHARED
+ RTW_PROC_HDL_SSEQ("trx_share_mode", proc_get_trx_share_mode, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("napi_info", proc_get_napi_info, NULL),
+ RTW_PROC_HDL_SSEQ("rsvd_page", proc_dump_rsvd_page, proc_set_rsvd_page_info),
+
+ RTW_PROC_HDL_SSEQ("fw_info", proc_get_fw_info, NULL),
+#ifdef RTW_HALMAC
+ RTW_PROC_HDL_SSEQ("halmac_info", proc_get_halmac_info, NULL),
+#endif
+ RTW_PROC_HDL_SSEQ("ack_timeout", proc_get_ack_timeout, proc_set_ack_timeout),
+};
+
+static const int adapter_proc_hdls_num = sizeof(adapter_proc_hdls) / sizeof(struct rtw_proc_hdl);
+
+static int rtw_adapter_proc_open(struct inode *inode, struct file *file)
+{
+ ssize_t index = (ssize_t)PDE_DATA(inode);
+ const struct rtw_proc_hdl *hdl = adapter_proc_hdls + index;
+ void *private = proc_get_parent_data(inode);
+
+ if (hdl->type == RTW_PROC_HDL_TYPE_SEQ) {
+ int res = seq_open(file, hdl->u.seq_op);
+
+ if (res == 0)
+ ((struct seq_file *)file->private_data)->private = private;
+
+ return res;
+ } else if (hdl->type == RTW_PROC_HDL_TYPE_SSEQ) {
+ int (*show)(struct seq_file *, void *) = hdl->u.show ? hdl->u.show : proc_get_dummy;
+
+ return single_open(file, show, private);
+ } else {
+ return -EROFS;
+ }
+}
+
+static ssize_t rtw_adapter_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
+{
+ ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
+ const struct rtw_proc_hdl *hdl = adapter_proc_hdls + index;
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
+
+ if (write)
+ return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
+
+ return -EROFS;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+static const struct proc_ops rtw_adapter_proc_seq_fops = {
+ .proc_open = rtw_adapter_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = seq_release,
+ .proc_write = rtw_adapter_proc_write,
+};
+#else
+static const struct file_operations rtw_adapter_proc_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_adapter_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = rtw_adapter_proc_write,
+};
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+static const struct proc_ops rtw_adapter_proc_sseq_fops = {
+ .proc_open = rtw_adapter_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = rtw_adapter_proc_write,
+};
+#else
+static const struct file_operations rtw_adapter_proc_sseq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_adapter_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = rtw_adapter_proc_write,
+};
+#endif
+
+static int proc_get_odm_force_igi_lb(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ RTW_PRINT_SEL(m, "force_igi_lb:0x%02x\n", rtw_odm_get_force_igi_lb(padapter));
+
+ return 0;
+}
+
+static ssize_t proc_set_odm_force_igi_lb(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u8 force_igi_lb;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%hhx", &force_igi_lb);
+
+ if (num != 1)
+ return count;
+
+ rtw_odm_set_force_igi_lb(padapter, force_igi_lb);
+ }
+
+ return count;
+}
+
+int proc_get_odm_adaptivity(struct seq_file *m, void *v)
+{
+ struct net_device *dev = m->private;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+
+ rtw_odm_adaptivity_parm_msg(m, padapter);
+
+ return 0;
+}
+
+ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *dev = data;
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
+ char tmp[32];
+ u32 th_l2h_ini;
+ u32 th_l2h_ini_mode2;
+ s8 th_edcca_hl_diff;
+ s8 th_edcca_hl_diff_mode2;
+ u8 edcca_enable;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp)) {
+ rtw_warn_on(1);
+ return -EFAULT;
+ }
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+
+ int num = sscanf(tmp, "%x %hhd %x %hhd %hhu", &th_l2h_ini, &th_edcca_hl_diff, &th_l2h_ini_mode2, &th_edcca_hl_diff_mode2, &edcca_enable);
+
+ if (num != 5)
+ return count;
+
+ rtw_odm_adaptivity_parm_set(padapter, (s8)th_l2h_ini, th_edcca_hl_diff, (s8)th_l2h_ini_mode2, th_edcca_hl_diff_mode2, edcca_enable);
+ }
+
+ return count;
+}
+
+static char *phydm_msg = NULL;
+#define PHYDM_MSG_LEN 80*24
+
+static int proc_get_phydm_cmd(struct seq_file *m, void *v)
+{
+ struct net_device *netdev;
+ PADAPTER padapter;
+ PHAL_DATA_TYPE pHalData;
+ struct PHY_DM_STRUCT *phydm;
+
+
+ netdev = m->private;
+ padapter = (PADAPTER)rtw_netdev_priv(netdev);
+ pHalData = GET_HAL_DATA(padapter);
+ phydm = &pHalData->odmpriv;
+
+ if (NULL == phydm_msg) {
+ phydm_msg = rtw_zmalloc(PHYDM_MSG_LEN);
+ if (NULL == phydm_msg)
+ return -ENOMEM;
+
+ phydm_cmd(phydm, NULL, 0, 0, phydm_msg, PHYDM_MSG_LEN);
+ }
+
+ _RTW_PRINT_SEL(m, "%s\n", phydm_msg);
+
+ rtw_mfree(phydm_msg, PHYDM_MSG_LEN);
+ phydm_msg = NULL;
+
+ return 0;
+}
+
+static ssize_t proc_set_phydm_cmd(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
+{
+ struct net_device *netdev;
+ PADAPTER padapter;
+ PHAL_DATA_TYPE pHalData;
+ struct PHY_DM_STRUCT *phydm;
+ char tmp[64] = {0};
+
+
+ netdev = (struct net_device *)data;
+ padapter = (PADAPTER)rtw_netdev_priv(netdev);
+ pHalData = GET_HAL_DATA(padapter);
+ phydm = &pHalData->odmpriv;
+
+ if (count < 1)
+ return -EFAULT;
+
+ if (count > sizeof(tmp))
+ return -EFAULT;
+
+ if (buffer && !copy_from_user(tmp, buffer, count)) {
+ if (NULL == phydm_msg) {
+ phydm_msg = rtw_zmalloc(PHYDM_MSG_LEN);
+ if (NULL == phydm_msg)
+ return -ENOMEM;
+ } else
+ memset(phydm_msg, 0, PHYDM_MSG_LEN);
+
+ phydm_cmd(phydm, tmp, count, 1, phydm_msg, PHYDM_MSG_LEN);
+
+ if (strlen(phydm_msg) == 0) {
+ rtw_mfree(phydm_msg, PHYDM_MSG_LEN);
+ phydm_msg = NULL;
+ }
+ }
+
+ return count;
+}
+
+#ifdef CONFIG_LAMODE
+static void *proc_start_lamode_dump(struct seq_file *m, loff_t *pos)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(m->private);
+ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter);
+ struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv;
+ PRT_ADCSMP AdcSmp = &(pDM_Odm->adcsmp);
+ static unsigned long index;
+ static unsigned long max;
+
+
+ if (*pos == 0) {
+ rtw_pm_set_ips(adapter, IPS_NONE);
+ rtw_pm_set_lps(adapter, PS_MODE_ACTIVE);
+ ADCSmp_Start(pDM_Odm, AdcSmp);
+ index = 0;
+ *pos = max = ADCSmp_Get_SampleCounts(pDM_Odm);
+ if (max == 0)
+ return NULL;
+ } else if (index >= max) {
+ return NULL;
+ }
+
+ return &index;
+}
+
+static void proc_stop_lamode_dump(struct seq_file *m, void *v)
+{
+ /* v is a NULL in kernel 3.19.0-25 */
+}
+
+static void *proc_next_lamode_dump(struct seq_file *m, void *v, loff_t *pos)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(m->private);
+ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter);
+ struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv;
+ unsigned long *index = v;
+
+
+ *index += 2;
+ if (*index >= *pos) {
+ ADCSmp_DeInit(pDM_Odm);
+ if (phydm_msg) {
+ _RTW_PRINT_SEL(m, "%s", phydm_msg);
+ rtw_mfree(phydm_msg, PHYDM_MSG_LEN);
+ phydm_msg = NULL;
+ }
+ return NULL;
+ }
+ return index;
+}
+
+static int proc_show_lamode_data(struct seq_file *m, void *v)
+{
+ _adapter *adapter = (_adapter *)rtw_netdev_priv(m->private);
+ PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter);
+ struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv;
+ unsigned long *index = v;
+ char line[32];
+ int rtn;
+
+
+ memset(line, 0, sizeof(line));
+ rtn = ADCSmp_Query_SingleData(pDM_Odm, line, sizeof(line), *index);
+ _RTW_PRINT_SEL(m, "%s", line);
+
+ if (rtn<0)
+ return -1;
+
+ return 0;
+}
+
+static struct seq_operations seq_ops_lamode = {
+ .start = proc_start_lamode_dump,
+ .stop = proc_stop_lamode_dump,
+ .next = proc_next_lamode_dump,
+ .show = proc_show_lamode_data,
+};
+#endif /* CONFIG_LAMODE */
+
+/*
+* rtw_odm_proc:
+* init/deinit when register/unregister net_device, along with rtw_adapter_proc
+*/
+static const struct rtw_proc_hdl odm_proc_hdls[] = {
+ RTW_PROC_HDL_SSEQ("adaptivity", proc_get_odm_adaptivity, proc_set_odm_adaptivity),
+ RTW_PROC_HDL_SSEQ("force_igi_lb", proc_get_odm_force_igi_lb, proc_set_odm_force_igi_lb),
+ RTW_PROC_HDL_SSEQ("cmd", proc_get_phydm_cmd, proc_set_phydm_cmd),
+#ifdef CONFIG_LAMODE
+ RTW_PROC_HDL_SEQ("lamode", &seq_ops_lamode, proc_set_phydm_cmd)
+#endif /* CONFIG_LAMODE */
+};
+
+static const int odm_proc_hdls_num = sizeof(odm_proc_hdls) / sizeof(struct rtw_proc_hdl);
+
+static int rtw_odm_proc_open(struct inode *inode, struct file *file)
+{
+ ssize_t index = (ssize_t)PDE_DATA(inode);
+ const struct rtw_proc_hdl *hdl = odm_proc_hdls + index;
+ void *private = proc_get_parent_data(inode);
+
+ if (hdl->type == RTW_PROC_HDL_TYPE_SEQ) {
+ int res = seq_open(file, hdl->u.seq_op);
+
+ if (res == 0)
+ ((struct seq_file *)file->private_data)->private = private;
+
+ return res;
+ } else if (hdl->type == RTW_PROC_HDL_TYPE_SSEQ) {
+ int (*show)(struct seq_file *, void *) = hdl->u.show ? hdl->u.show : proc_get_dummy;
+
+ return single_open(file, show, private);
+ } else {
+ return -EROFS;
+ }
+}
+
+static ssize_t rtw_odm_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
+{
+ ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
+ const struct rtw_proc_hdl *hdl = odm_proc_hdls + index;
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
+
+ if (write)
+ return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
+
+ return -EROFS;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+static const struct proc_ops rtw_odm_proc_seq_fops = {
+ .proc_open = rtw_odm_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = seq_release,
+ .proc_write = rtw_odm_proc_write,
+};
+#else
+static const struct file_operations rtw_odm_proc_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_odm_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = rtw_odm_proc_write,
+};
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0))
+static const struct proc_ops rtw_odm_proc_sseq_fops = {
+ .proc_open = rtw_odm_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+ .proc_write = rtw_odm_proc_write,
+};
+#else
+static const struct file_operations rtw_odm_proc_sseq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_odm_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = rtw_odm_proc_write,
+};
+#endif
+
+static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev)
+{
+ struct proc_dir_entry *dir_odm = NULL;
+ struct proc_dir_entry *entry = NULL;
+ _adapter *adapter = rtw_netdev_priv(dev);
+ ssize_t i;
+
+ if (adapter->dir_dev == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ if (adapter->dir_odm != NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ dir_odm = rtw_proc_create_dir("odm", adapter->dir_dev, dev);
+ if (dir_odm == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ adapter->dir_odm = dir_odm;
+
+ for (i = 0; i < odm_proc_hdls_num; i++) {
+ if (odm_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ)
+ entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_seq_fops, (void *)i);
+ else if (odm_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ)
+ entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_sseq_fops, (void *)i);
+ else
+ entry = NULL;
+
+ if (!entry) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+ }
+
+exit:
+ return dir_odm;
+}
+
+static void rtw_odm_proc_deinit(_adapter *adapter)
+{
+ struct proc_dir_entry *dir_odm = NULL;
+ int i;
+
+ dir_odm = adapter->dir_odm;
+
+ if (dir_odm == NULL) {
+ rtw_warn_on(1);
+ return;
+ }
+
+ for (i = 0; i < odm_proc_hdls_num; i++)
+ remove_proc_entry(odm_proc_hdls[i].name, dir_odm);
+
+ remove_proc_entry("odm", adapter->dir_dev);
+
+ adapter->dir_odm = NULL;
+
+ if (phydm_msg) {
+ rtw_mfree(phydm_msg, PHYDM_MSG_LEN);
+ phydm_msg = NULL;
+ }
+}
+
+#ifdef CONFIG_MCC_MODE
+/*
+* rtw_mcc_proc:
+* init/deinit when register/unregister net_device, along with rtw_adapter_proc
+*/
+const struct rtw_proc_hdl mcc_proc_hdls[] = {
+ RTW_PROC_HDL_SSEQ("mcc_info", proc_get_mcc_info, NULL),
+ RTW_PROC_HDL_SSEQ("mcc_enable", proc_get_mcc_info, proc_set_mcc_enable),
+ RTW_PROC_HDL_SSEQ("mcc_single_tx_criteria", proc_get_mcc_info, proc_set_mcc_single_tx_criteria),
+ RTW_PROC_HDL_SSEQ("mcc_ap_bw20_target_tp", proc_get_mcc_info, proc_set_mcc_ap_bw20_target_tp),
+ RTW_PROC_HDL_SSEQ("mcc_ap_bw40_target_tp", proc_get_mcc_info, proc_set_mcc_ap_bw40_target_tp),
+ RTW_PROC_HDL_SSEQ("mcc_ap_bw80_target_tp", proc_get_mcc_info, proc_set_mcc_ap_bw80_target_tp),
+ RTW_PROC_HDL_SSEQ("mcc_sta_bw20_target_tp", proc_get_mcc_info, proc_set_mcc_sta_bw20_target_tp),
+ RTW_PROC_HDL_SSEQ("mcc_sta_bw40_target_tp", proc_get_mcc_info, proc_set_mcc_sta_bw40_target_tp),
+ RTW_PROC_HDL_SSEQ("mcc_sta_bw80_target_tp", proc_get_mcc_info, proc_set_mcc_sta_bw80_target_tp),
+ RTW_PROC_HDL_SSEQ("mcc_policy_table", proc_get_mcc_policy_table, proc_set_mcc_policy_table),
+};
+
+const int mcc_proc_hdls_num = sizeof(mcc_proc_hdls) / sizeof(struct rtw_proc_hdl);
+
+static int rtw_mcc_proc_open(struct inode *inode, struct file *file)
+{
+ ssize_t index = (ssize_t)PDE_DATA(inode);
+ const struct rtw_proc_hdl *hdl = mcc_proc_hdls + index;
+ void *private = proc_get_parent_data(inode);
+
+ if (hdl->type == RTW_PROC_HDL_TYPE_SEQ) {
+ int res = seq_open(file, hdl->u.seq_op);
+
+ if (res == 0)
+ ((struct seq_file *)file->private_data)->private = private;
+
+ return res;
+ } else if (hdl->type == RTW_PROC_HDL_TYPE_SSEQ) {
+ int (*show)(struct seq_file *, void *) = hdl->u.show ? hdl->u.show : proc_get_dummy;
+
+ return single_open(file, show, private);
+ } else {
+ return -EROFS;
+ }
+}
+
+static ssize_t rtw_mcc_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
+{
+ ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
+ const struct rtw_proc_hdl *hdl = mcc_proc_hdls + index;
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
+
+ if (write)
+ return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
+
+ return -EROFS;
+}
+
+static const struct file_operations rtw_mcc_proc_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_mcc_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = rtw_mcc_proc_write,
+};
+
+static const struct file_operations rtw_mcc_proc_sseq_fops = {
+ .owner = THIS_MODULE,
+ .open = rtw_mcc_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = rtw_mcc_proc_write,
+};
+
+struct proc_dir_entry *rtw_mcc_proc_init(struct net_device *dev)
+{
+ struct proc_dir_entry *dir_mcc = NULL;
+ struct proc_dir_entry *entry = NULL;
+ _adapter *adapter = rtw_netdev_priv(dev);
+ ssize_t i;
+
+ if (adapter->dir_dev == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ if (adapter->dir_mcc != NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ dir_mcc = rtw_proc_create_dir("mcc", adapter->dir_dev, dev);
+ if (dir_mcc == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ adapter->dir_mcc = dir_mcc;
+
+ for (i = 0; i < mcc_proc_hdls_num; i++) {
+ if (mcc_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ)
+ entry = rtw_proc_create_entry(mcc_proc_hdls[i].name, dir_mcc, &rtw_mcc_proc_seq_fops, (void *)i);
+ else if (mcc_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ)
+ entry = rtw_proc_create_entry(mcc_proc_hdls[i].name, dir_mcc, &rtw_mcc_proc_sseq_fops, (void *)i);
+ else
+ entry = NULL;
+
+ if (!entry) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+ }
+
+exit:
+ return dir_mcc;
+}
+
+void rtw_mcc_proc_deinit(_adapter *adapter)
+{
+ struct proc_dir_entry *dir_mcc = NULL;
+ int i;
+
+ dir_mcc = adapter->dir_mcc;
+
+ if (dir_mcc == NULL) {
+ rtw_warn_on(1);
+ return;
+ }
+
+ for (i = 0; i < mcc_proc_hdls_num; i++)
+ remove_proc_entry(mcc_proc_hdls[i].name, dir_mcc);
+
+ remove_proc_entry("mcc", adapter->dir_dev);
+
+ adapter->dir_mcc = NULL;
+}
+#endif /* CONFIG_MCC_MODE */
+
+struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev)
+{
+ struct proc_dir_entry *drv_proc = get_rtw_drv_proc();
+ struct proc_dir_entry *dir_dev = NULL;
+ struct proc_dir_entry *entry = NULL;
+ _adapter *adapter = rtw_netdev_priv(dev);
+ u8 rf_type;
+ ssize_t i;
+
+ if (drv_proc == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ if (adapter->dir_dev != NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ dir_dev = rtw_proc_create_dir(dev->name, drv_proc, dev);
+ if (dir_dev == NULL) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+
+ adapter->dir_dev = dir_dev;
+
+ for (i = 0; i < adapter_proc_hdls_num; i++) {
+ if (adapter_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SEQ)
+ entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_seq_fops, (void *)i);
+ else if (adapter_proc_hdls[i].type == RTW_PROC_HDL_TYPE_SSEQ)
+ entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_sseq_fops, (void *)i);
+ else
+ entry = NULL;
+
+ if (!entry) {
+ rtw_warn_on(1);
+ goto exit;
+ }
+ }
+
+ rtw_odm_proc_init(dev);
+
+#ifdef CONFIG_MCC_MODE
+ rtw_mcc_proc_init(dev);
+#endif /* CONFIG_MCC_MODE */
+
+exit:
+ return dir_dev;
+}
+
+void rtw_adapter_proc_deinit(struct net_device *dev)
+{
+ struct proc_dir_entry *drv_proc = get_rtw_drv_proc();
+ struct proc_dir_entry *dir_dev = NULL;
+ _adapter *adapter = rtw_netdev_priv(dev);
+ int i;
+
+ dir_dev = adapter->dir_dev;
+
+ if (dir_dev == NULL) {
+ rtw_warn_on(1);
+ return;
+ }
+
+ for (i = 0; i < adapter_proc_hdls_num; i++)
+ remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
+
+ rtw_odm_proc_deinit(adapter);
+
+#ifdef CONFIG_MCC_MODE
+ rtw_mcc_proc_deinit(adapter);
+#endif /* CONFIG_MCC_MODE */
+
+ remove_proc_entry(dev->name, drv_proc);
+
+ adapter->dir_dev = NULL;
+}
+
+void rtw_adapter_proc_replace(struct net_device *dev)
+{
+ struct proc_dir_entry *drv_proc = get_rtw_drv_proc();
+ struct proc_dir_entry *dir_dev = NULL;
+ _adapter *adapter = rtw_netdev_priv(dev);
+ int i;
+
+ dir_dev = adapter->dir_dev;
+
+ if (dir_dev == NULL) {
+ rtw_warn_on(1);
+ return;
+ }
+
+ for (i = 0; i < adapter_proc_hdls_num; i++)
+ remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
+
+ rtw_odm_proc_deinit(adapter);
+
+#ifdef CONFIG_MCC_MODE
+ rtw_mcc_proc_deinit(adapter);
+#endif /* CONIG_MCC_MODE */
+
+ remove_proc_entry(adapter->old_ifname, drv_proc);
+
+ adapter->dir_dev = NULL;
+
+ rtw_adapter_proc_init(dev);
+
+}
+
+#endif /* CONFIG_PROC_DEBUG */
diff --git a/drivers/staging/rtl8188eu/os_dep/rtw_proc.h b/drivers/staging/rtl8188eu/os_dep/rtw_proc.h
new file mode 100644
index 000000000000..daba6f283b2f
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/rtw_proc.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#ifndef __RTW_PROC_H__
+#define __RTW_PROC_H__
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#define RTW_PROC_HDL_TYPE_SEQ 0
+#define RTW_PROC_HDL_TYPE_SSEQ 1
+
+struct rtw_proc_hdl {
+ char *name;
+ u8 type;
+ union {
+ int (*show)(struct seq_file *, void *);
+ struct seq_operations *seq_op;
+ } u;
+ ssize_t (*write)(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data);
+};
+
+#define RTW_PROC_HDL_SEQ(_name, _seq_op, _write) \
+ { .name = _name, .type = RTW_PROC_HDL_TYPE_SEQ, .u.seq_op = _seq_op, .write = _write}
+
+#define RTW_PROC_HDL_SSEQ(_name, _show, _write) \
+ { .name = _name, .type = RTW_PROC_HDL_TYPE_SSEQ, .u.show = _show, .write = _write}
+
+#ifdef CONFIG_PROC_DEBUG
+
+struct proc_dir_entry *get_rtw_drv_proc(void);
+int rtw_drv_proc_init(void);
+void rtw_drv_proc_deinit(void);
+struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev);
+void rtw_adapter_proc_deinit(struct net_device *dev);
+void rtw_adapter_proc_replace(struct net_device *dev);
+
+#else /* !CONFIG_PROC_DEBUG */
+
+#define get_rtw_drv_proc() NULL
+#define rtw_drv_proc_init() 0
+#define rtw_drv_proc_deinit() do {} while (0)
+#define rtw_adapter_proc_init(dev) NULL
+#define rtw_adapter_proc_deinit(dev) do {} while (0)
+#define rtw_adapter_proc_replace(dev) do {} while (0)
+
+#endif /* !CONFIG_PROC_DEBUG */
+
+#endif /* __RTW_PROC_H__ */
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
new file mode 100644
index 000000000000..f3ea5a3332e9
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c
@@ -0,0 +1,1345 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _HCI_INTF_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#ifdef CONFIG_GLOBAL_UI_PID
+int ui_pid[3] = {0, 0, 0};
+#endif
+
+static int rtw_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtw_resume(struct usb_interface *intf);
+
+
+static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid);
+static void rtw_dev_remove(struct usb_interface *pusb_intf);
+
+static void rtw_dev_shutdown(struct device *dev)
+{
+ struct usb_interface *usb_intf = container_of(dev, struct usb_interface, dev);
+ struct dvobj_priv *dvobj = NULL;
+ _adapter *adapter = NULL;
+ int i;
+
+ RTW_INFO("%s\n", __func__);
+
+ if (usb_intf) {
+ dvobj = usb_get_intfdata(usb_intf);
+ if (dvobj) {
+ adapter = dvobj_get_primary_adapter(dvobj);
+ if (adapter) {
+ if (!rtw_is_surprise_removed(adapter)) {
+ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter);
+ #ifdef CONFIG_WOWLAN
+ if (pwrctl->wowlan_mode == true)
+ RTW_INFO("%s wowlan_mode ==true do not run rtw_hal_deinit()\n", __func__);
+ else
+ #endif
+ {
+ rtw_hal_deinit(adapter);
+ rtw_set_surprise_removed(adapter);
+ }
+ }
+ }
+ ATOMIC_SET(&dvobj->continual_io_error, MAX_CONTINUAL_IO_ERR + 1);
+ }
+ }
+}
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23))
+/* Some useful macros to use to create struct usb_device_id */
+#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
+#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
+#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
+#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
+#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
+#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
+#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
+#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
+#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
+#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
+#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400
+
+
+#define USB_DEVICE_ID_MATCH_INT_INFO \
+ (USB_DEVICE_ID_MATCH_INT_CLASS | \
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS | \
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL)
+
+
+#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+ | USB_DEVICE_ID_MATCH_DEVICE, \
+ .idVendor = (vend), \
+ .idProduct = (prod), \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr)
+
+/**
+ * USB_VENDOR_AND_INTERFACE_INFO - describe a specific usb vendor with a class of usb interfaces
+ * @vend: the 16 bit USB Vendor ID
+ * @cl: bInterfaceClass value
+ * @sc: bInterfaceSubClass value
+ * @pr: bInterfaceProtocol value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific vendor with a specific class of interfaces.
+ *
+ * This is especially useful when explicitly matching devices that have
+ * vendor specific bDeviceClass values, but standards-compliant interfaces.
+ */
+#define USB_VENDOR_AND_INTERFACE_INFO(vend, cl, sc, pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+ | USB_DEVICE_ID_MATCH_VENDOR, \
+ .idVendor = (vend), \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), \
+ .bInterfaceProtocol = (pr)
+
+/* ----------------------------------------------------------------------- */
+#endif
+
+
+#define USB_VENDER_ID_REALTEK 0x0BDA
+
+
+/* DID_USB_v916_20130116 */
+static struct usb_device_id rtw_usb_id_tbl[] = {
+ /*=== Realtek demoboard ===*/
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8179), .driver_info = RTL8188E}, /* 8188EUS */
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179), .driver_info = RTL8188E}, /* 8188ETV */
+ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xf179), .driver_info = RTL8188F}, /* 8188FU */
+ /*=== Customer ID ===*/
+ /****** 8188EUS ********/
+ {USB_DEVICE(0x07B8, 0x8179), .driver_info = RTL8188E}, /* Abocom - Abocom */
+ {USB_DEVICE(0x0DF6, 0x0076), .driver_info = RTL8188E}, /* Sitecom N150 v2 */
+ {USB_DEVICE(0x2001, 0x330F), .driver_info = RTL8188E}, /* DLink DWA-125 REV D1 */
+ {USB_DEVICE(0x2001, 0x3310), .driver_info = RTL8188E}, /* Dlink DWA-123 REV D1 */
+ {USB_DEVICE(0x2001, 0x3311), .driver_info = RTL8188E}, /* DLink GO-USB-N150 REV B1 */
+ {USB_DEVICE(0x2001, 0x331B), .driver_info = RTL8188E}, /* D-Link DWA-121 rev B1 */
+ {USB_DEVICE(0x056E, 0x4008), .driver_info = RTL8188E}, /* Elecom WDC-150SU2M */
+ {USB_DEVICE(0x2357, 0x010c), .driver_info = RTL8188E}, /* TP-Link TL-WN722N v2 */
+ {USB_DEVICE(0x2357, 0x0111), .driver_info = RTL8188E}, /* TP-Link TL-WN727N v5.21 */
+ {USB_DEVICE(0x2C4E, 0x0102), .driver_info = RTL8188E}, /* MERCUSYS MW150US v2 */
+ {USB_DEVICE(0x0B05, 0x18F0), .driver_info = RTL8188E}, /* ASUS USB-N10 Nano B1 */
+ {USB_DEVICE(0x7392, 0xb811), .driver_info = RTL8188E}, /* Edimax EW-7811Un V2 */
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl);
+
+static int const rtw_usb_id_len = sizeof(rtw_usb_id_tbl) / sizeof(struct usb_device_id);
+
+static struct specific_device_id specific_device_id_tbl[] = {
+ {.idVendor = USB_VENDER_ID_REALTEK, .idProduct = 0x8177, .flags = SPEC_DEV_ID_DISABLE_HT}, /* 8188cu 1*1 dongole, (b/g mode only) */
+ {.idVendor = USB_VENDER_ID_REALTEK, .idProduct = 0x817E, .flags = SPEC_DEV_ID_DISABLE_HT}, /* 8188CE-VAU USB minCard (b/g mode only) */
+ {.idVendor = 0x0b05, .idProduct = 0x1791, .flags = SPEC_DEV_ID_DISABLE_HT},
+ {.idVendor = 0x13D3, .idProduct = 0x3311, .flags = SPEC_DEV_ID_DISABLE_HT},
+ {.idVendor = 0x13D3, .idProduct = 0x3359, .flags = SPEC_DEV_ID_DISABLE_HT}, /* Russian customer -Azwave (8188CE-VAU g mode) */
+#ifdef RTK_DMP_PLATFORM
+ {.idVendor = USB_VENDER_ID_REALTEK, .idProduct = 0x8111, .flags = SPEC_DEV_ID_ASSIGN_IFNAME}, /* Realtek 5G dongle for WiFi Display */
+ {.idVendor = 0x2019, .idProduct = 0xAB2D, .flags = SPEC_DEV_ID_ASSIGN_IFNAME}, /* PCI-Abocom 5G dongle for WiFi Display */
+#endif /* RTK_DMP_PLATFORM */
+ {}
+};
+
+struct rtw_usb_drv {
+ struct usb_driver usbdrv;
+ int drv_registered;
+ u8 hw_type;
+};
+
+static struct rtw_usb_drv usb_drv = {
+ .usbdrv.name = (char *)DRV_NAME,
+ .usbdrv.probe = rtw_drv_init,
+ .usbdrv.disconnect = rtw_dev_remove,
+ .usbdrv.id_table = rtw_usb_id_tbl,
+ .usbdrv.suspend = rtw_suspend,
+ .usbdrv.resume = rtw_resume,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+ .usbdrv.reset_resume = rtw_resume,
+#endif
+#ifdef CONFIG_AUTOSUSPEND
+ .usbdrv.supports_autosuspend = 1,
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
+ .usbdrv.drvwrap.driver.shutdown = rtw_dev_shutdown,
+#else
+ .usbdrv.driver.shutdown = rtw_dev_shutdown,
+#endif
+};
+
+static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+}
+
+static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
+}
+
+static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT;
+}
+
+static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+ return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK;
+}
+
+static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+ return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+ return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd);
+}
+
+static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+ return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+ return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj)
+{
+ u8 rst = _SUCCESS;
+
+#ifdef CONFIG_USB_VENDOR_REQ_MUTEX
+ _rtw_mutex_init(&dvobj->usb_vendor_req_mutex);
+#endif
+
+
+#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC
+ dvobj->usb_alloc_vendor_req_buf = rtw_zmalloc(MAX_USB_IO_CTL_SIZE);
+ if (dvobj->usb_alloc_vendor_req_buf == NULL) {
+ RTW_INFO("alloc usb_vendor_req_buf failed... /n");
+ rst = _FAIL;
+ goto exit;
+ }
+ dvobj->usb_vendor_req_buf =
+ (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(dvobj->usb_alloc_vendor_req_buf), ALIGNMENT_UNIT);
+exit:
+#endif
+
+ return rst;
+
+}
+
+static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj)
+{
+ u8 rst = _SUCCESS;
+
+#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC
+ if (dvobj->usb_vendor_req_buf)
+ rtw_mfree(dvobj->usb_alloc_vendor_req_buf, MAX_USB_IO_CTL_SIZE);
+#endif
+
+#ifdef CONFIG_USB_VENDOR_REQ_MUTEX
+ _rtw_mutex_free(&dvobj->usb_vendor_req_mutex);
+#endif
+
+ return rst;
+}
+static void rtw_decide_chip_type_by_usb_info(struct dvobj_priv *pdvobjpriv, const struct usb_device_id *pdid)
+{
+ pdvobjpriv->chip_type = pdid->driver_info;
+
+ if (pdvobjpriv->chip_type == RTL8188E)
+ rtl8188eu_set_hw_type(pdvobjpriv);
+}
+
+static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf, const struct usb_device_id *pdid)
+{
+ int i;
+ u8 val8;
+ int status = _FAIL;
+ struct dvobj_priv *pdvobjpriv;
+ struct usb_device_descriptor *pdev_desc;
+ struct usb_host_config *phost_conf;
+ struct usb_config_descriptor *pconf_desc;
+ struct usb_host_interface *phost_iface;
+ struct usb_interface_descriptor *piface_desc;
+ struct usb_host_endpoint *phost_endp;
+ struct usb_endpoint_descriptor *pendp_desc;
+ struct usb_device *pusbd;
+
+
+
+ pdvobjpriv = devobj_init();
+ if (pdvobjpriv == NULL)
+ goto exit;
+
+
+ pdvobjpriv->pusbintf = usb_intf ;
+ pusbd = pdvobjpriv->pusbdev = interface_to_usbdev(usb_intf);
+ usb_set_intfdata(usb_intf, pdvobjpriv);
+
+ pdvobjpriv->RtNumInPipes = 0;
+ pdvobjpriv->RtNumOutPipes = 0;
+
+ pdev_desc = &pusbd->descriptor;
+
+ phost_conf = pusbd->actconfig;
+ pconf_desc = &phost_conf->desc;
+
+ phost_iface = &usb_intf->altsetting[0];
+ piface_desc = &phost_iface->desc;
+
+ pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces;
+ pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber;
+ pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
+
+ for (i = 0; i < pdvobjpriv->nr_endpoint; i++) {
+ phost_endp = phost_iface->endpoint + i;
+ if (phost_endp) {
+ pendp_desc = &phost_endp->desc;
+
+ RTW_INFO("\nusb_endpoint_descriptor(%d):\n", i);
+ RTW_INFO("bLength=%x\n", pendp_desc->bLength);
+ RTW_INFO("bDescriptorType=%x\n", pendp_desc->bDescriptorType);
+ RTW_INFO("bEndpointAddress=%x\n", pendp_desc->bEndpointAddress);
+ RTW_INFO("wMaxPacketSize=%d\n", le16_to_cpu(pendp_desc->wMaxPacketSize));
+ RTW_INFO("bInterval=%x\n", pendp_desc->bInterval);
+
+ if (RT_usb_endpoint_is_bulk_in(pendp_desc)) {
+ RTW_INFO("RT_usb_endpoint_is_bulk_in = %x\n", RT_usb_endpoint_num(pendp_desc));
+ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumInPipes++;
+ } else if (RT_usb_endpoint_is_int_in(pendp_desc)) {
+ RTW_INFO("RT_usb_endpoint_is_int_in = %x, Interval = %x\n", RT_usb_endpoint_num(pendp_desc), pendp_desc->bInterval);
+ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] = RT_usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumInPipes++;
+ } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) {
+ RTW_INFO("RT_usb_endpoint_is_bulk_out = %x\n", RT_usb_endpoint_num(pendp_desc));
+ pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] = RT_usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumOutPipes++;
+ }
+ pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc);
+ }
+ }
+
+ RTW_INFO("nr_endpoint=%d, in_num=%d, out_num=%d\n\n", pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes, pdvobjpriv->RtNumOutPipes);
+
+ switch (pusbd->speed) {
+ case USB_SPEED_LOW:
+ RTW_INFO("USB_SPEED_LOW\n");
+ pdvobjpriv->usb_speed = RTW_USB_SPEED_1_1;
+ break;
+ case USB_SPEED_FULL:
+ RTW_INFO("USB_SPEED_FULL\n");
+ pdvobjpriv->usb_speed = RTW_USB_SPEED_1_1;
+ break;
+ case USB_SPEED_HIGH:
+ RTW_INFO("USB_SPEED_HIGH\n");
+ pdvobjpriv->usb_speed = RTW_USB_SPEED_2;
+ break;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
+ case USB_SPEED_SUPER:
+ RTW_INFO("USB_SPEED_SUPER\n");
+ pdvobjpriv->usb_speed = RTW_USB_SPEED_3;
+ break;
+#endif
+ default:
+ RTW_INFO("USB_SPEED_UNKNOWN(%x)\n", pusbd->speed);
+ pdvobjpriv->usb_speed = RTW_USB_SPEED_UNKNOWN;
+ break;
+ }
+
+ if (pdvobjpriv->usb_speed == RTW_USB_SPEED_UNKNOWN) {
+ RTW_INFO("UNKNOWN USB SPEED MODE, ERROR !!!\n");
+ goto free_dvobj;
+ }
+
+ if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) {
+ goto free_dvobj;
+ }
+
+ /*step 1-1., decide the chip_type via driver_info*/
+ pdvobjpriv->interface_type = RTW_USB;
+ rtw_decide_chip_type_by_usb_info(pdvobjpriv, pdid);
+
+ /* .3 misc */
+ sema_init(&(pdvobjpriv->usb_suspend_sema), 0);
+ rtw_reset_continual_io_error(pdvobjpriv);
+
+ usb_get_dev(pusbd);
+
+ status = _SUCCESS;
+
+free_dvobj:
+ if (status != _SUCCESS && pdvobjpriv) {
+ usb_set_intfdata(usb_intf, NULL);
+
+ devobj_deinit(pdvobjpriv);
+
+ pdvobjpriv = NULL;
+ }
+exit:
+ return pdvobjpriv;
+}
+
+static void usb_dvobj_deinit(struct usb_interface *usb_intf)
+{
+ struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf);
+
+
+ usb_set_intfdata(usb_intf, NULL);
+ if (dvobj) {
+ /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */
+ if ((dvobj->NumInterfaces != 2 && dvobj->NumInterfaces != 3)
+ || (dvobj->InterfaceNumber == 1)) {
+ if (interface_to_usbdev(usb_intf)->state != USB_STATE_NOTATTACHED) {
+ /* If we didn't unplug usb dongle and remove/insert modlue, driver fails on sitesurvey for the first time when device is up . */
+ /* Reset usb port for sitesurvey fail issue. 2009.8.13, by Thomas */
+ RTW_INFO("usb attached..., try to reset usb device\n");
+ usb_reset_device(interface_to_usbdev(usb_intf));
+ }
+ }
+
+ rtw_deinit_intf_priv(dvobj);
+
+ devobj_deinit(dvobj);
+ }
+
+ /* RTW_INFO("%s %d\n", __func__, ATOMIC_READ(&usb_intf->dev.kobj.kref.refcount)); */
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+}
+
+static int usb_reprobe_switch_usb_mode(PADAPTER Adapter)
+{
+ struct registry_priv *registry_par = &Adapter->registrypriv;
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
+ u8 ret = false;
+
+ /* efuse not allow driver to switch usb mode */
+ if (pHalData->EEPROMUsbSwitch == false)
+ goto exit;
+
+ /* registry not allow driver to switch usb mode */
+ if (registry_par->switch_usb_mode == 0)
+ goto exit;
+
+ rtw_hal_set_hwreg(Adapter, HW_VAR_USB_MODE, &ret);
+
+exit:
+ return ret;
+}
+
+u8 rtw_set_hal_ops(_adapter *padapter)
+{
+ /* alloc memory for HAL DATA */
+ if (rtw_hal_data_init(padapter) == _FAIL)
+ return _FAIL;
+
+ if (rtw_get_chip_type(padapter) == RTL8188E)
+ rtl8188eu_set_hal_ops(padapter);
+
+ if (_FAIL == rtw_hal_ops_check(padapter))
+ return _FAIL;
+
+ if (hal_spec_init(padapter) == _FAIL)
+ return _FAIL;
+
+ return _SUCCESS;
+}
+
+static void usb_intf_start(_adapter *padapter)
+{
+ PHAL_DATA_TYPE hal = GET_HAL_DATA(padapter);
+
+ rtw_hal_inirp_init(padapter);
+ hal->usb_intf_start = true;
+
+
+}
+
+static void usb_intf_stop(_adapter *padapter)
+{
+ PHAL_DATA_TYPE hal = GET_HAL_DATA(padapter);
+
+ /* disabel_hw_interrupt */
+ if (!rtw_is_surprise_removed(padapter)) {
+ /* device still exists, so driver can do i/o operation */
+ /* TODO: */
+ }
+
+ /* cancel in irp */
+ rtw_hal_inirp_deinit(padapter);
+
+ /* cancel out irp */
+ rtw_write_port_cancel(padapter);
+
+ /* todo:cancel other irps */
+
+ hal->usb_intf_start = false;
+
+}
+
+static void process_spec_devid(const struct usb_device_id *pdid)
+{
+ u16 vid, pid;
+ u32 flags;
+ int i;
+ int num = sizeof(specific_device_id_tbl) / sizeof(struct specific_device_id);
+
+ for (i = 0; i < num; i++) {
+ vid = specific_device_id_tbl[i].idVendor;
+ pid = specific_device_id_tbl[i].idProduct;
+ flags = specific_device_id_tbl[i].flags;
+
+ if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && (flags & SPEC_DEV_ID_DISABLE_HT)) {
+ rtw_ht_enable = 0;
+ rtw_bw_mode = 0;
+ rtw_ampdu_enable = 0;
+ }
+#ifdef RTK_DMP_PLATFORM
+ /* Change the ifname to wlan10 when PC side WFD dongle plugin on DMP platform. */
+ /* It is used to distinguish between normal and PC-side wifi dongle/module. */
+ if ((pdid->idVendor == vid) && (pdid->idProduct == pid) && (flags & SPEC_DEV_ID_ASSIGN_IFNAME)) {
+ extern char *ifname;
+ strncpy(ifname, "wlan10", 6);
+ /* RTW_INFO("%s()-%d: ifname=%s, vid=%04X, pid=%04X\n", __func__, __LINE__, ifname, vid, pid); */
+ }
+#endif /* RTK_DMP_PLATFORM */
+
+ }
+}
+
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+int rtw_hw_suspend(_adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv;
+ struct usb_interface *pusb_intf;
+ struct net_device *pnetdev;
+
+ if (NULL == padapter)
+ goto error_exit;
+
+ if ((false == padapter->bup) || RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("padapter->bup=%d bDriverStopped=%s bSurpriseRemoved = %s\n"
+ , padapter->bup
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+ goto error_exit;
+ }
+
+ pwrpriv = adapter_to_pwrctl(padapter);
+ pusb_intf = adapter_to_dvobj(padapter)->pusbintf;
+ pnetdev = padapter->pnetdev;
+
+ LeaveAllPowerSaveMode(padapter);
+
+ RTW_INFO("==> rtw_hw_suspend\n");
+ _enter_pwrlock(&pwrpriv->lock);
+ pwrpriv->bips_processing = true;
+ /* padapter->net_closed = true; */
+ /* s1. */
+ if (pnetdev) {
+ netif_carrier_off(pnetdev);
+ rtw_netif_stop_queue(pnetdev);
+ }
+
+ /* s2. */
+ rtw_disassoc_cmd(padapter, 500, false);
+
+ /* s2-2. indicate disconnect to os */
+ /* rtw_indicate_disconnect(padapter); */
+ {
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+ _clr_fwstate_(pmlmepriv, _FW_LINKED);
+ rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+ rtw_os_indicate_disconnect(padapter, 0, false);
+
+#ifdef CONFIG_LPS
+ /* donnot enqueue cmd */
+ rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 0);
+#endif
+ }
+ }
+ /* s2-3. */
+ rtw_free_assoc_resources(padapter, 1);
+
+ /* s2-4. */
+ rtw_free_network_queue(padapter, true);
+#ifdef CONFIG_IPS
+ rtw_ips_dev_unload(padapter);
+#endif
+ pwrpriv->rf_pwrstate = rf_off;
+ pwrpriv->bips_processing = false;
+ _exit_pwrlock(&pwrpriv->lock);
+
+ return 0;
+
+error_exit:
+ RTW_INFO("%s, failed\n", __func__);
+ return -1;
+
+}
+
+int rtw_hw_resume(_adapter *padapter)
+{
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct usb_interface *pusb_intf = adapter_to_dvobj(padapter)->pusbintf;
+ struct net_device *pnetdev = padapter->pnetdev;
+
+ RTW_INFO("==> rtw_hw_resume\n");
+ _enter_pwrlock(&pwrpriv->lock);
+ pwrpriv->bips_processing = true;
+ rtw_reset_drv_sw(padapter);
+
+ if (pm_netdev_open(pnetdev, false) != 0) {
+ _exit_pwrlock(&pwrpriv->lock);
+ goto error_exit;
+ }
+
+ rtw_netif_carrier_on(pnetdev);
+
+ rtw_netif_wake_queue(pnetdev);
+
+ pwrpriv->bkeepfwalive = false;
+ pwrpriv->brfoffbyhw = false;
+
+ pwrpriv->rf_pwrstate = rf_on;
+ pwrpriv->bips_processing = false;
+ _exit_pwrlock(&pwrpriv->lock);
+
+
+ return 0;
+error_exit:
+ RTW_INFO("%s, Open net dev failed\n", __func__);
+ return -1;
+}
+#endif
+
+static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
+{
+ struct dvobj_priv *dvobj;
+ struct pwrctrl_priv *pwrpriv;
+ struct debug_priv *pdbgpriv;
+ PADAPTER padapter;
+ int ret = 0;
+
+
+ dvobj = usb_get_intfdata(pusb_intf);
+ pwrpriv = dvobj_to_pwrctl(dvobj);
+ pdbgpriv = &dvobj->drv_dbg;
+ padapter = dvobj_get_primary_adapter(dvobj);
+
+ if (pwrpriv->bInSuspend == true) {
+ RTW_INFO("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
+ pdbgpriv->dbg_suspend_error_cnt++;
+ goto exit;
+ }
+
+ if ((padapter->bup) || !rtw_is_drv_stopped(padapter) || !rtw_is_surprise_removed(padapter)) {
+#ifdef CONFIG_AUTOSUSPEND
+ if (pwrpriv->bInternalAutoSuspend) {
+
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ /* The FW command register update must after MAC and FW init ready. */
+ if ((padapter->bFWReady) && (pwrpriv->bHWPwrPindetect) && (padapter->registrypriv.usbss_enable)) {
+ u8 bOpen = true;
+ rtw_interface_ps_func(padapter, HAL_USB_SELECT_SUSPEND, &bOpen);
+ }
+#endif/* SUPPORT_HW_RFOFF_DETECTED */
+ }
+#endif/* CONFIG_AUTOSUSPEND */
+ }
+
+ ret = rtw_suspend_common(padapter);
+
+exit:
+ return ret;
+}
+
+static int rtw_resume_process(_adapter *padapter)
+{
+ int ret, pm_cnt = 0;
+ struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter);
+ struct dvobj_priv *pdvobj = padapter->dvobj;
+ struct debug_priv *pdbgpriv = &pdvobj->drv_dbg;
+
+
+ if (pwrpriv->bInSuspend == false) {
+ pdbgpriv->dbg_resume_error_cnt++;
+ RTW_INFO("%s bInSuspend = %d\n", __func__, pwrpriv->bInSuspend);
+ return -1;
+ }
+
+#if defined(CONFIG_BT_COEXIST) && defined(CONFIG_AUTOSUSPEND) /* add by amy for 8723as-vau */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+ RTW_INFO("%s...pm_usage_cnt(%d) pwrpriv->bAutoResume=%x. ....\n", __func__, atomic_read(&(adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt)), pwrpriv->bAutoResume);
+ pm_cnt = atomic_read(&(adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt));
+#else /* kernel < 2.6.32 */
+ RTW_INFO("...pm_usage_cnt(%d).....\n", adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt);
+ pm_cnt = adapter_to_dvobj(padapter)->pusbintf->pm_usage_cnt;
+#endif /* kernel < 2.6.32 */
+
+ RTW_INFO("pwrpriv->bAutoResume (%x)\n", pwrpriv->bAutoResume);
+ if (pwrpriv->bAutoResume) {
+ pwrpriv->bInternalAutoSuspend = false;
+ pwrpriv->bAutoResume = false;
+ RTW_INFO("pwrpriv->bAutoResume (%x) pwrpriv->bInternalAutoSuspend(%x)\n", pwrpriv->bAutoResume, pwrpriv->bInternalAutoSuspend);
+
+ }
+#endif /* #ifdef CONFIG_BT_COEXIST &CONFIG_AUTOSUSPEND& */
+
+ /*
+ * Due to usb wow suspend flow will cancel read/write port via intf_stop and
+ * bReadPortCancel and bWritePortCancel are set true in intf_stop.
+ * But they will not be clear in intf_start during wow resume flow.
+ * It should move to os_intf in the feature.
+ */
+ RTW_ENABLE_FUNC(padapter, DF_RX_BIT);
+ RTW_ENABLE_FUNC(padapter, DF_TX_BIT);
+
+ ret = rtw_resume_common(padapter);
+
+#ifdef CONFIG_AUTOSUSPEND
+ if (pwrpriv->bInternalAutoSuspend) {
+#ifdef SUPPORT_HW_RFOFF_DETECTED
+ /* The FW command register update must after MAC and FW init ready. */
+ if ((padapter->bFWReady) && (pwrpriv->bHWPwrPindetect) && (padapter->registrypriv.usbss_enable)) {
+ u8 bOpen = false;
+ rtw_interface_ps_func(padapter, HAL_USB_SELECT_SUSPEND, &bOpen);
+ }
+#endif
+#ifdef CONFIG_BT_COEXIST /* for 8723as-vau */
+ RTW_INFO("pwrpriv->bAutoResume (%x)\n", pwrpriv->bAutoResume);
+ if (pwrpriv->bAutoResume) {
+ pwrpriv->bInternalAutoSuspend = false;
+ pwrpriv->bAutoResume = false;
+ RTW_INFO("pwrpriv->bAutoResume (%x) pwrpriv->bInternalAutoSuspend(%x)\n", pwrpriv->bAutoResume, pwrpriv->bInternalAutoSuspend);
+ }
+
+#else /* #ifdef CONFIG_BT_COEXIST */
+ pwrpriv->bInternalAutoSuspend = false;
+#endif /* #ifdef CONFIG_BT_COEXIST */
+ pwrpriv->brfoffbyhw = false;
+ }
+#endif/* CONFIG_AUTOSUSPEND */
+
+
+ return ret;
+}
+
+static int rtw_resume(struct usb_interface *pusb_intf)
+{
+ struct dvobj_priv *dvobj;
+ struct pwrctrl_priv *pwrpriv;
+ struct debug_priv *pdbgpriv;
+ PADAPTER padapter;
+ struct mlme_ext_priv *pmlmeext;
+ int ret = 0;
+
+
+ dvobj = usb_get_intfdata(pusb_intf);
+ pwrpriv = dvobj_to_pwrctl(dvobj);
+ pdbgpriv = &dvobj->drv_dbg;
+ padapter = dvobj_get_primary_adapter(dvobj);
+ pmlmeext = &padapter->mlmeextpriv;
+
+ RTW_INFO("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+ pdbgpriv->dbg_resume_cnt++;
+
+ if (pwrpriv->bInternalAutoSuspend)
+ ret = rtw_resume_process(padapter);
+ else {
+ if (pwrpriv->wowlan_mode || pwrpriv->wowlan_ap_mode) {
+ rtw_resume_lock_suspend();
+ ret = rtw_resume_process(padapter);
+ rtw_resume_unlock_suspend();
+ } else {
+#ifdef CONFIG_RESUME_IN_WORKQUEUE
+ rtw_resume_in_workqueue(pwrpriv);
+#else
+ if (rtw_is_earlysuspend_registered(pwrpriv)) {
+ /* jeff: bypass resume here, do in late_resume */
+ rtw_set_do_late_resume(pwrpriv, true);
+ } else {
+ rtw_resume_lock_suspend();
+ ret = rtw_resume_process(padapter);
+ rtw_resume_unlock_suspend();
+ }
+#endif
+ }
+ }
+
+ pmlmeext->last_scan_time = jiffies;
+ RTW_INFO("<======== %s return %d\n", __func__, ret);
+
+ return ret;
+}
+
+
+
+#ifdef CONFIG_AUTOSUSPEND
+void autosuspend_enter(_adapter *padapter)
+{
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj);
+
+ RTW_INFO("==>autosuspend_enter...........\n");
+
+ pwrpriv->bInternalAutoSuspend = true;
+ pwrpriv->bips_processing = true;
+
+ if (rf_off == pwrpriv->change_rfpwrstate) {
+#ifndef CONFIG_BT_COEXIST
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ usb_enable_autosuspend(dvobj->pusbdev);
+#else
+ dvobj->pusbdev->autosuspend_disabled = 0;/* autosuspend disabled by the user */
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+ usb_autopm_put_interface(dvobj->pusbintf);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+ usb_autopm_enable(dvobj->pusbintf);
+#else
+ usb_autosuspend_device(dvobj->pusbdev, 1);
+#endif
+#else /* #ifndef CONFIG_BT_COEXIST */
+ if (1 == pwrpriv->autopm_cnt) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ usb_enable_autosuspend(dvobj->pusbdev);
+#else
+ dvobj->pusbdev->autosuspend_disabled = 0;/* autosuspend disabled by the user */
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+ usb_autopm_put_interface(dvobj->pusbintf);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+ usb_autopm_enable(dvobj->pusbintf);
+#else
+ usb_autosuspend_device(dvobj->pusbdev, 1);
+#endif
+ pwrpriv->autopm_cnt--;
+ } else
+ RTW_INFO("0!=pwrpriv->autopm_cnt[%d] didn't usb_autopm_put_interface\n", pwrpriv->autopm_cnt);
+
+#endif /* #ifndef CONFIG_BT_COEXIST */
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+ RTW_INFO("...pm_usage_cnt(%d).....\n", atomic_read(&(dvobj->pusbintf->pm_usage_cnt)));
+#else
+ RTW_INFO("...pm_usage_cnt(%d).....\n", dvobj->pusbintf->pm_usage_cnt);
+#endif
+
+}
+
+int autoresume_enter(_adapter *padapter)
+{
+ int result = _SUCCESS;
+ struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+ struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj);
+
+ RTW_INFO("====> autoresume_enter\n");
+
+ if (rf_off == pwrpriv->rf_pwrstate) {
+ pwrpriv->ps_flag = false;
+#ifndef CONFIG_BT_COEXIST
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+ if (usb_autopm_get_interface(dvobj->pusbintf) < 0) {
+ RTW_INFO("can't get autopm: %d\n", result);
+ result = _FAIL;
+ goto error_exit;
+ }
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+ usb_autopm_disable(dvobj->pusbintf);
+#else
+ usb_autoresume_device(dvobj->pusbdev, 1);
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+ RTW_INFO("...pm_usage_cnt(%d).....\n", atomic_read(&(dvobj->pusbintf->pm_usage_cnt)));
+#else
+ RTW_INFO("...pm_usage_cnt(%d).....\n", dvobj->pusbintf->pm_usage_cnt);
+#endif
+#else /* #ifndef CONFIG_BT_COEXIST */
+ pwrpriv->bAutoResume = true;
+ if (0 == pwrpriv->autopm_cnt) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+ if (usb_autopm_get_interface(dvobj->pusbintf) < 0) {
+ RTW_INFO("can't get autopm: %d\n", result);
+ result = _FAIL;
+ goto error_exit;
+ }
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+ usb_autopm_disable(dvobj->pusbintf);
+#else
+ usb_autoresume_device(dvobj->pusbdev, 1);
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+ RTW_INFO("...pm_usage_cnt(%d).....\n", atomic_read(&(dvobj->pusbintf->pm_usage_cnt)));
+#else
+ RTW_INFO("...pm_usage_cnt(%d).....\n", dvobj->pusbintf->pm_usage_cnt);
+#endif
+ pwrpriv->autopm_cnt++;
+ } else
+ RTW_INFO("0!=pwrpriv->autopm_cnt[%d] didn't usb_autopm_get_interface\n", pwrpriv->autopm_cnt);
+#endif /* #ifndef CONFIG_BT_COEXIST */
+ }
+ RTW_INFO("<==== autoresume_enter\n");
+error_exit:
+
+ return result;
+}
+#endif
+
+#ifdef CONFIG_PLATFORM_RTD2880B
+extern void rtd2885_wlan_netlink_sendMsg(char *action_string, char *name);
+#endif
+
+/*
+ * drv_init() - a device potentially for us
+ *
+ * notes: drv_init() is called when the bus driver has located a card for us to support.
+ * We accept the new device by returning 0.
+*/
+
+static _adapter *rtw_sw_export = NULL;
+
+static _adapter *rtw_usb_primary_adapter_init(struct dvobj_priv *dvobj,
+ struct usb_interface *pusb_intf)
+{
+ _adapter *padapter = NULL;
+ int status = _FAIL;
+
+ padapter = (_adapter *)rtw_zvmalloc(sizeof(*padapter));
+ if (padapter == NULL)
+ goto exit;
+
+ if (loadparam(padapter) != _SUCCESS)
+ goto free_adapter;
+
+ padapter->dvobj = dvobj;
+
+
+ rtw_set_drv_stopped(padapter);/*init*/
+
+ dvobj->padapters[dvobj->iface_nums++] = padapter;
+ padapter->iface_id = IFACE_ID0;
+
+ /* set adapter_type/iface type for primary padapter */
+ padapter->isprimary = true;
+ padapter->adapter_type = PRIMARY_ADAPTER;
+#ifdef CONFIG_MI_WITH_MBSSID_CAM/*Configure all IFACE to PORT0-MBSSID*/
+ padapter->hw_port = HW_PORT0;
+#else
+ padapter->hw_port = HW_PORT0;
+#endif
+
+ /* step init_io_priv */
+ if (rtw_init_io_priv(padapter, usb_set_intf_ops) == _FAIL)
+ goto free_adapter;
+
+ /* step 2. hook HalFunc, allocate HalData */
+ if (rtw_set_hal_ops(padapter) == _FAIL)
+ goto free_hal_data;
+
+
+ padapter->intf_start = &usb_intf_start;
+ padapter->intf_stop = &usb_intf_stop;
+
+ /* step read_chip_version */
+ rtw_hal_read_chip_version(padapter);
+
+ /* step usb endpoint mapping */
+ rtw_hal_chip_configure(padapter);
+
+ /* step read efuse/eeprom data and get mac_addr */
+ if (rtw_hal_read_chip_info(padapter) == _FAIL)
+ goto free_hal_data;
+
+ /* step 5. */
+ if (rtw_init_drv_sw(padapter) == _FAIL) {
+ goto free_hal_data;
+ }
+
+#ifdef CONFIG_BT_COEXIST
+ if (GET_HAL_DATA(padapter)->EEPROMBluetoothCoexist)
+ rtw_btcoex_Initialize(padapter);
+ else
+ rtw_btcoex_wifionly_initialize(padapter);
+#else /* !CONFIG_BT_COEXIST */
+ rtw_btcoex_wifionly_initialize(padapter);
+#endif /* CONFIG_BT_COEXIST */
+
+#ifdef CONFIG_PM
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+ if (dvobj_to_pwrctl(dvobj)->bSupportRemoteWakeup) {
+ dvobj->pusbdev->do_remote_wakeup = 1;
+ pusb_intf->needs_remote_wakeup = 1;
+ device_init_wakeup(&pusb_intf->dev, 1);
+ RTW_INFO("pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n");
+ RTW_INFO("pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", device_may_wakeup(&pusb_intf->dev));
+ }
+#endif
+#endif
+
+#ifdef CONFIG_AUTOSUSPEND
+ if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE) {
+ if (padapter->registrypriv.usbss_enable) { /* autosuspend (2s delay) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38))
+ dvobj->pusbdev->dev.power.autosuspend_delay = 0 * HZ;/* 15 * HZ; idle-delay time */
+#else
+ dvobj->pusbdev->autosuspend_delay = 0 * HZ;/* 15 * HZ; idle-delay time */
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ usb_enable_autosuspend(dvobj->pusbdev);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34))
+ padapter->bDisableAutosuspend = dvobj->pusbdev->autosuspend_disabled ;
+ dvobj->pusbdev->autosuspend_disabled = 0;/* autosuspend disabled by the user */
+#endif
+
+ /* usb_autopm_get_interface(adapter_to_dvobj(padapter)->pusbintf ); */ /* init pm_usage_cnt ,let it start from 1 */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32))
+ RTW_INFO("%s...pm_usage_cnt(%d).....\n", __func__, atomic_read(&(dvobj->pusbintf->pm_usage_cnt)));
+#else
+ RTW_INFO("%s...pm_usage_cnt(%d).....\n", __func__, dvobj->pusbintf->pm_usage_cnt);
+#endif
+ }
+ }
+#endif
+ /* 2012-07-11 Move here to prevent the 8723AS-VAU BT auto suspend influence */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+ if (usb_autopm_get_interface(pusb_intf) < 0)
+ RTW_INFO("can't get autopm:\n");
+#endif
+#ifdef CONFIG_BT_COEXIST
+ dvobj_to_pwrctl(dvobj)->autopm_cnt = 1;
+#endif
+
+ /* set mac addr */
+ rtw_macaddr_cfg(adapter_mac_addr(padapter), get_hal_mac_addr(padapter));
+#ifdef CONFIG_MI_WITH_MBSSID_CAM
+ rtw_mbid_camid_alloc(padapter, adapter_mac_addr(padapter));
+#endif
+
+#ifdef CONFIG_P2P
+ rtw_init_wifidirect_addrs(padapter, adapter_mac_addr(padapter), adapter_mac_addr(padapter));
+#endif /* CONFIG_P2P */
+ RTW_INFO("bDriverStopped:%s, bSurpriseRemoved:%s, bup:%d, hw_init_completed:%d\n"
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False"
+ , padapter->bup
+ , rtw_get_hw_init_completed(padapter)
+ );
+
+ status = _SUCCESS;
+
+free_hal_data:
+ if (status != _SUCCESS && padapter->HalData)
+ rtw_hal_free_data(padapter);
+free_adapter:
+ if (status != _SUCCESS && padapter) {
+ rtw_vmfree((u8 *)padapter, sizeof(*padapter));
+ padapter = NULL;
+ }
+exit:
+ return padapter;
+}
+
+static void rtw_usb_primary_adapter_deinit(_adapter *padapter)
+{
+ struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+ RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+ if (check_fwstate(pmlmepriv, _FW_LINKED))
+ rtw_disassoc_cmd(padapter, 0, false);
+
+#ifdef CONFIG_AP_MODE
+ if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) {
+ free_mlme_ap_info(padapter);
+ #ifdef CONFIG_HOSTAPD_MLME
+ hostapd_mode_unload(padapter);
+ #endif
+ }
+#endif
+
+ /*rtw_cancel_all_timer(if1);*/
+
+#ifdef CONFIG_WOWLAN
+ pwrctl->wowlan_mode = false;
+#endif /* CONFIG_WOWLAN */
+
+ rtw_dev_unload(padapter);
+
+ RTW_INFO("+r871xu_dev_remove, hw_init_completed=%d\n", rtw_get_hw_init_completed(padapter));
+
+#ifdef CONFIG_BT_COEXIST
+ if (1 == pwrctl->autopm_cnt) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+ usb_autopm_put_interface(adapter_to_dvobj(padapter)->pusbintf);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
+ usb_autopm_enable(adapter_to_dvobj(padapter)->pusbintf);
+#else
+ usb_autosuspend_device(adapter_to_dvobj(padapter)->pusbdev, 1);
+#endif
+ pwrctl->autopm_cnt--;
+ }
+#endif
+
+ rtw_free_drv_sw(padapter);
+
+ /* TODO: use rtw_os_ndevs_deinit instead at the first stage of driver's dev deinit function */
+ rtw_os_ndev_free(padapter);
+
+#ifdef RTW_HALMAC
+ rtw_halmac_deinit_adapter(adapter_to_dvobj(padapter));
+#endif /* RTW_HALMAC */
+
+ rtw_vmfree((u8 *)padapter, sizeof(_adapter));
+
+#ifdef CONFIG_PLATFORM_RTD2880B
+ RTW_INFO("wlan link down\n");
+ rtd2885_wlan_netlink_sendMsg("linkdown", "8712");
+#endif
+
+}
+
+static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid)
+{
+ _adapter *padapter = NULL;
+ int status = _FAIL;
+ struct dvobj_priv *dvobj;
+#ifdef CONFIG_CONCURRENT_MODE
+ int i;
+#endif
+
+ /* RTW_INFO("+rtw_drv_init\n"); */
+
+ /* step 0. */
+ process_spec_devid(pdid);
+
+ /* Initialize dvobj_priv */
+ dvobj = usb_dvobj_init(pusb_intf, pdid);
+ if (dvobj == NULL) {
+ goto exit;
+ }
+
+ padapter = rtw_usb_primary_adapter_init(dvobj, pusb_intf);
+ if (padapter == NULL) {
+ RTW_INFO("rtw_usb_primary_adapter_init Failed!\n");
+ goto free_dvobj;
+ }
+
+ if (usb_reprobe_switch_usb_mode(padapter) == true)
+ goto free_if_prim;
+
+#ifdef CONFIG_CONCURRENT_MODE
+ if (padapter->registrypriv.virtual_iface_num > (CONFIG_IFACE_NUMBER - 1))
+ padapter->registrypriv.virtual_iface_num = (CONFIG_IFACE_NUMBER - 1);
+
+ for (i = 0; i < padapter->registrypriv.virtual_iface_num; i++) {
+ if (rtw_drv_add_vir_if(padapter, usb_set_intf_ops) == NULL) {
+ RTW_INFO("rtw_drv_add_iface failed! (%d)\n", i);
+ goto free_if_vir;
+ }
+ }
+#endif
+
+#ifdef CONFIG_INTEL_PROXIM
+ rtw_sw_export = padapter;
+#endif
+
+#ifdef CONFIG_GLOBAL_UI_PID
+ if (ui_pid[1] != 0) {
+ RTW_INFO("ui_pid[1]:%d\n", ui_pid[1]);
+ rtw_signal_process(ui_pid[1], SIGUSR2);
+ }
+#endif
+
+ /* dev_alloc_name && register_netdev */
+ if (rtw_os_ndevs_init(dvobj) != _SUCCESS)
+ goto free_if_vir;
+
+#ifdef CONFIG_HOSTAPD_MLME
+ hostapd_mode_init(padapter);
+#endif
+
+#ifdef CONFIG_PLATFORM_RTD2880B
+ RTW_INFO("wlan link up\n");
+ rtd2885_wlan_netlink_sendMsg("linkup", "8712");
+#endif
+ status = _SUCCESS;
+free_if_vir:
+ if (status != _SUCCESS) {
+ #ifdef CONFIG_CONCURRENT_MODE
+ rtw_drv_stop_vir_ifaces(dvobj);
+ rtw_drv_free_vir_ifaces(dvobj);
+ #endif
+ }
+
+free_if_prim:
+ if (status != _SUCCESS && padapter)
+ rtw_usb_primary_adapter_deinit(padapter);
+
+free_dvobj:
+ if (status != _SUCCESS)
+ usb_dvobj_deinit(pusb_intf);
+exit:
+ return status == _SUCCESS ? 0 : -ENODEV;
+}
+
+/*
+ * dev_remove() - our device is being removed
+*/
+/* rmmod module & unplug(SurpriseRemoved) will call r871xu_dev_remove() => how to recognize both */
+static void rtw_dev_remove(struct usb_interface *pusb_intf)
+{
+ struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+ struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(dvobj);
+ _adapter *padapter = dvobj_get_primary_adapter(dvobj);
+ struct net_device *pnetdev = padapter->pnetdev;
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+
+ RTW_INFO("+rtw_dev_remove\n");
+
+ dvobj->processing_dev_remove = true;
+
+ /* TODO: use rtw_os_ndevs_deinit instead at the first stage of driver's dev deinit function */
+ rtw_os_ndevs_unregister(dvobj);
+
+ if (usb_drv.drv_registered == true) {
+ /* RTW_INFO("r871xu_dev_remove():padapter->bSurpriseRemoved == true\n"); */
+ rtw_set_surprise_removed(padapter);
+ }
+ /*else
+ {
+
+ padapter->HalData->hw_init_completed = false;
+ }*/
+
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER)
+ rtw_unregister_early_suspend(pwrctl);
+#endif
+
+ if (padapter->bFWReady == true) {
+ rtw_pm_set_ips(padapter, IPS_NONE);
+ rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
+
+ LeaveAllPowerSaveMode(padapter);
+ }
+ rtw_set_drv_stopped(padapter); /*for stop thread*/
+ rtw_stop_cmd_thread(padapter);
+#ifdef CONFIG_CONCURRENT_MODE
+ rtw_drv_stop_vir_ifaces(dvobj);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+#ifdef CONFIG_BT_COEXIST
+#ifdef CONFIG_BT_COEXIST_SOCKET_TRX
+ if (GET_HAL_DATA(padapter)->EEPROMBluetoothCoexist)
+ rtw_btcoex_close_socket(padapter);
+#endif
+ rtw_btcoex_HaltNotify(padapter);
+#endif
+
+ rtw_usb_primary_adapter_deinit(padapter);
+
+#ifdef CONFIG_CONCURRENT_MODE
+ rtw_drv_free_vir_ifaces(dvobj);
+#endif /* CONFIG_CONCURRENT_MODE */
+
+ usb_dvobj_deinit(pusb_intf);
+
+ RTW_INFO("-r871xu_dev_remove, done\n");
+
+
+#ifdef CONFIG_INTEL_PROXIM
+ rtw_sw_export = NULL;
+#endif
+
+
+ return;
+
+}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
+extern int console_suspend_enabled;
+#endif
+
+static int __init rtw_drv_entry(void)
+{
+ int ret = 0;
+
+ RTW_INFO("module init start\n");
+ dump_drv_version(RTW_DBGDUMP);
+#ifdef BTCOEXVERSION
+ RTW_INFO(DRV_NAME" BT-Coex version = %s\n", BTCOEXVERSION);
+#endif /* BTCOEXVERSION */
+
+ usb_drv.drv_registered = true;
+ rtw_suspend_lock_init();
+ rtw_drv_proc_init();
+ rtw_ndev_notifier_register();
+
+ ret = usb_register(&usb_drv.usbdrv);
+
+ if (ret != 0) {
+ usb_drv.drv_registered = false;
+ rtw_suspend_lock_uninit();
+ rtw_drv_proc_deinit();
+ rtw_ndev_notifier_unregister();
+ goto exit;
+ }
+
+exit:
+ RTW_INFO("module init ret=%d\n", ret);
+ return ret;
+}
+
+static void __exit rtw_drv_halt(void)
+{
+ RTW_INFO("module exit start\n");
+
+ usb_drv.drv_registered = false;
+
+ usb_deregister(&usb_drv.usbdrv);
+
+ rtw_suspend_lock_uninit();
+ rtw_drv_proc_deinit();
+ rtw_ndev_notifier_unregister();
+
+ RTW_INFO("module exit success\n");
+
+ rtw_mstat_dump(RTW_DBGDUMP);
+}
+
+
+module_init(rtw_drv_entry);
+module_exit(rtw_drv_halt);
+
+#ifdef CONFIG_INTEL_PROXIM
+_adapter *rtw_usb_get_sw_pointer(void)
+{
+ return rtw_sw_export;
+}
+EXPORT_SYMBOL(rtw_usb_get_sw_pointer);
+#endif /* CONFIG_INTEL_PROXIM */
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
new file mode 100644
index 000000000000..10705b33e737
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -0,0 +1,1082 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _USB_OPS_LINUX_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+#include <rtw_sreset.h>
+
+struct rtw_async_write_data {
+ u8 data[VENDOR_CMD_MAX_DATA_LEN];
+ struct usb_ctrlrequest dr;
+};
+
+int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
+{
+ _adapter *padapter = pintfhdl->padapter;
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+ struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobjpriv);
+ struct usb_device *udev = pdvobjpriv->pusbdev;
+
+ unsigned int pipe;
+ int status = 0;
+ u32 tmp_buflen = 0;
+ u8 reqtype;
+ u8 *pIo_buf;
+ int vendorreq_times = 0;
+
+#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE
+ u8 *tmp_buf;
+#else /* use stack memory */
+ u8 tmp_buf[MAX_USB_IO_CTL_SIZE];
+#endif
+
+ /* RTW_INFO("%s %s:%d\n",__func__, current->comm, current->pid); */
+
+ if (RTW_CANNOT_IO(padapter)) {
+ status = -EPERM;
+ goto exit;
+ }
+
+ if (len > MAX_VENDOR_REQ_CMD_SIZE) {
+ RTW_INFO("[%s] Buffer len error ,vendor request failed\n", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+
+#ifdef CONFIG_USB_VENDOR_REQ_MUTEX
+ _enter_critical_mutex(&pdvobjpriv->usb_vendor_req_mutex, NULL);
+#endif
+
+
+ /* Acquire IO memory for vendorreq */
+#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_PREALLOC
+ pIo_buf = pdvobjpriv->usb_vendor_req_buf;
+#else
+ #ifdef CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE
+ tmp_buf = rtw_malloc((u32) len + ALIGNMENT_UNIT);
+ tmp_buflen = (u32)len + ALIGNMENT_UNIT;
+ #else /* use stack memory */
+ tmp_buflen = MAX_USB_IO_CTL_SIZE;
+ #endif
+
+ /* Added by Albert 2010/02/09 */
+ /* For mstar platform, mstar suggests the address for USB IO should be 16 bytes alignment. */
+ /* Trying to fix it here. */
+ pIo_buf = (tmp_buf == NULL) ? NULL : tmp_buf + ALIGNMENT_UNIT - ((SIZE_PTR)(tmp_buf) & 0x0f);
+#endif
+
+ if (pIo_buf == NULL) {
+ RTW_INFO("[%s] pIo_buf == NULL\n", __func__);
+ status = -ENOMEM;
+ goto release_mutex;
+ }
+
+ while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) {
+ memset(pIo_buf, 0, len);
+
+ if (requesttype == 0x01) {
+ pipe = usb_rcvctrlpipe(udev, 0);/* read_in */
+ reqtype = REALTEK_USB_VENQT_READ;
+ } else {
+ pipe = usb_sndctrlpipe(udev, 0);/* write_out */
+ reqtype = REALTEK_USB_VENQT_WRITE;
+ memcpy(pIo_buf, pdata, len);
+ }
+
+ status = rtw_usb_control_msg(udev, pipe, request, reqtype, value, index, pIo_buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
+
+ if (status == len) { /* Success this control transfer. */
+ rtw_reset_continual_io_error(pdvobjpriv);
+ if (requesttype == 0x01) {
+ /* For Control read transfer, we have to copy the read data from pIo_buf to pdata. */
+ memcpy(pdata, pIo_buf, len);
+ }
+ } else { /* error cases */
+ RTW_INFO("reg 0x%x, usb %s %u fail, status:%d value=0x%x, vendorreq_times:%d\n"
+ , value, (requesttype == 0x01) ? "read" : "write" , len, status, *(u32 *)pdata, vendorreq_times);
+
+ if (status < 0) {
+ if (status == (-ESHUTDOWN) || status == -ENODEV)
+ rtw_set_surprise_removed(padapter);
+ else {
+ #ifdef DBG_CONFIG_ERROR_DETECT
+ {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ pHalData->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL;
+ }
+ #endif
+ }
+ } else { /* status != len && status >= 0 */
+ if (status > 0) {
+ if (requesttype == 0x01) {
+ /* For Control read transfer, we have to copy the read data from pIo_buf to pdata. */
+ memcpy(pdata, pIo_buf, len);
+ }
+ }
+ }
+
+ if (rtw_inc_and_chk_continual_io_error(pdvobjpriv) == true) {
+ rtw_set_surprise_removed(padapter);
+ break;
+ }
+
+ }
+
+ /* firmware download is checksumed, don't retry */
+ if ((value >= FW_START_ADDRESS) || status == len)
+ break;
+
+ }
+
+ /* release IO memory used by vendorreq */
+#ifdef CONFIG_USB_VENDOR_REQ_BUFFER_DYNAMIC_ALLOCATE
+ rtw_mfree(tmp_buf, tmp_buflen);
+#endif
+
+release_mutex:
+#ifdef CONFIG_USB_VENDOR_REQ_MUTEX
+ _exit_critical_mutex(&pdvobjpriv->usb_vendor_req_mutex, NULL);
+#endif
+exit:
+ return status;
+
+}
+
+#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ
+static void _usbctrl_vendorreq_async_callback(struct urb *urb, struct pt_regs *regs)
+{
+ if (urb) {
+ if (urb->context)
+ rtw_mfree(urb->context, sizeof(struct rtw_async_write_data));
+ usb_free_urb(urb);
+ }
+}
+
+int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request,
+ u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
+{
+ int rc;
+ unsigned int pipe;
+ u8 reqtype;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct rtw_async_write_data *buf;
+
+
+ if (requesttype == VENDOR_READ) {
+ pipe = usb_rcvctrlpipe(udev, 0);/* read_in */
+ reqtype = REALTEK_USB_VENQT_READ;
+ } else {
+ pipe = usb_sndctrlpipe(udev, 0);/* write_out */
+ reqtype = REALTEK_USB_VENQT_WRITE;
+ }
+
+ buf = (struct rtl819x_async_write_data *)rtw_zmalloc(sizeof(*buf));
+ if (!buf) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ rtw_mfree((u8 *)buf, sizeof(*buf));
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ dr = &buf->dr;
+
+ dr->bRequestType = reqtype;
+ dr->bRequest = request;
+ dr->wValue = cpu_to_le16(value);
+ dr->wIndex = cpu_to_le16(index);
+ dr->wLength = cpu_to_le16(len);
+
+ memcpy(buf, pdata, len);
+
+ usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, buf, len,
+ _usbctrl_vendorreq_async_callback, buf);
+
+ rc = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rc < 0) {
+ rtw_mfree((u8 *)buf, sizeof(*buf));
+ usb_free_urb(urb);
+ }
+
+exit:
+ return rc;
+}
+
+
+#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */
+
+unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr)
+{
+ unsigned int pipe = 0, ep_num = 0;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+ if (addr == RECV_BULK_IN_ADDR)
+ pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
+
+ else if (addr == RECV_INT_IN_ADDR)
+ pipe = usb_rcvintpipe(pusbd, pdvobj->RtInPipe[1]);
+
+ else if (addr < HW_QUEUE_ENTRY) {
+#ifdef RTW_HALMAC
+ /* halmac already translate queue id to bulk out id */
+ ep_num = pdvobj->RtOutPipe[addr];
+#else
+ ep_num = pdvobj->Queue2Pipe[addr];
+#endif
+ pipe = usb_sndbulkpipe(pusbd, ep_num);
+ }
+
+ return pipe;
+}
+
+struct zero_bulkout_context {
+ void *pbuf;
+ void *purb;
+ void *pirp;
+ void *padapter;
+};
+
+static void usb_bulkout_zero_complete(struct urb *purb, struct pt_regs *regs)
+{
+ struct zero_bulkout_context *pcontext = (struct zero_bulkout_context *)purb->context;
+
+ /* RTW_INFO("+usb_bulkout_zero_complete\n"); */
+
+ if (pcontext) {
+ if (pcontext->pbuf)
+ rtw_mfree(pcontext->pbuf, sizeof(int));
+
+ if (pcontext->purb && (pcontext->purb == purb))
+ usb_free_urb(pcontext->purb);
+
+
+ rtw_mfree((u8 *)pcontext, sizeof(struct zero_bulkout_context));
+ }
+
+
+}
+
+static u32 usb_bulkout_zero(struct intf_hdl *pintfhdl, u32 addr)
+{
+ int pipe, status, len;
+ u32 ret;
+ unsigned char *pbuf;
+ struct zero_bulkout_context *pcontext;
+ PURB purb = NULL;
+ _adapter *padapter = (_adapter *)pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+ struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+ /* RTW_INFO("%s\n", __func__); */
+
+
+ if (RTW_CANNOT_TX(padapter))
+ return _FAIL;
+
+
+ pcontext = (struct zero_bulkout_context *)rtw_zmalloc(sizeof(struct zero_bulkout_context));
+ if (pcontext == NULL)
+ return _FAIL;
+
+ pbuf = (unsigned char *)rtw_zmalloc(sizeof(int));
+ purb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ /* translate DMA FIFO addr to pipehandle */
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+
+ len = 0;
+ pcontext->pbuf = pbuf;
+ pcontext->purb = purb;
+ pcontext->pirp = NULL;
+ pcontext->padapter = padapter;
+
+
+ /* translate DMA FIFO addr to pipehandle */
+ /* pipe = ffaddr2pipehdl(pdvobj, addr); */
+
+ usb_fill_bulk_urb(purb, pusbd, pipe,
+ pbuf,
+ len,
+ usb_bulkout_zero_complete,
+ pcontext);/* context is pcontext */
+
+ status = usb_submit_urb(purb, GFP_ATOMIC);
+
+ if (!status)
+ ret = _SUCCESS;
+ else
+ ret = _FAIL;
+
+
+ return _SUCCESS;
+
+}
+
+void usb_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+
+}
+
+void usb_write_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+
+}
+
+
+void usb_read_port_cancel(struct intf_hdl *pintfhdl)
+{
+ int i;
+ struct recv_buf *precvbuf;
+ _adapter *padapter = pintfhdl->padapter;
+ precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
+
+ RTW_INFO("%s\n", __func__);
+
+ for (i = 0; i < NR_RECVBUFF ; i++) {
+
+ if (precvbuf->purb) {
+ /* RTW_INFO("usb_read_port_cancel : usb_kill_urb\n"); */
+ usb_kill_urb(precvbuf->purb);
+ }
+ precvbuf++;
+ }
+
+#ifdef CONFIG_USB_INTERRUPT_IN_PIPE
+ usb_kill_urb(padapter->recvpriv.int_in_urb);
+#endif
+}
+
+static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+ unsigned long irqL;
+ int i;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
+ /* struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; */
+ /* _adapter *padapter = pxmitframe->padapter; */
+ _adapter *padapter = pxmitbuf->padapter;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ /* struct pkt_attrib *pattrib = &pxmitframe->attrib; */
+
+
+ switch (pxmitbuf->flags) {
+ case VO_QUEUE_INX:
+ pxmitpriv->voq_cnt--;
+ break;
+ case VI_QUEUE_INX:
+ pxmitpriv->viq_cnt--;
+ break;
+ case BE_QUEUE_INX:
+ pxmitpriv->beq_cnt--;
+ break;
+ case BK_QUEUE_INX:
+ pxmitpriv->bkq_cnt--;
+ break;
+ default:
+ break;
+ }
+
+
+ /*
+ _enter_critical(&pxmitpriv->lock, &irqL);
+
+ pxmitpriv->txirp_cnt--;
+
+ switch(pattrib->priority)
+ {
+ case 1:
+ case 2:
+ pxmitpriv->bkq_cnt--;
+
+ break;
+ case 4:
+ case 5:
+ pxmitpriv->viq_cnt--;
+
+ break;
+ case 6:
+ case 7:
+ pxmitpriv->voq_cnt--;
+
+ break;
+ case 0:
+ case 3:
+ default:
+ pxmitpriv->beq_cnt--;
+
+ break;
+
+ }
+
+ _exit_critical(&pxmitpriv->lock, &irqL);
+
+
+ if(pxmitpriv->txirp_cnt==0)
+ {
+ up(&(pxmitpriv->tx_retevt));
+ }
+ */
+ /* rtw_free_xmitframe(pxmitpriv, pxmitframe); */
+
+ if (RTW_CANNOT_TX(padapter)) {
+ RTW_INFO("%s(): TX Warning! bDriverStopped(%s) OR bSurpriseRemoved(%s) pxmitbuf->buf_tag(%x)\n"
+ , __func__
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False"
+ , pxmitbuf->buf_tag);
+
+ goto check_completion;
+ }
+
+
+ if (purb->status == 0) {
+
+ } else {
+ RTW_INFO("###=> urb_write_port_complete status(%d)\n", purb->status);
+ if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
+ /* usb_clear_halt(pusbdev, purb->pipe); */
+ /* msleep(10); */
+ sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL);
+ } else if (purb->status == -EINPROGRESS) {
+ goto check_completion;
+
+ } else if (purb->status == -ENOENT) {
+ RTW_INFO("%s: -ENOENT\n", __func__);
+ goto check_completion;
+
+ } else if (purb->status == -ECONNRESET) {
+ RTW_INFO("%s: -ECONNRESET\n", __func__);
+ goto check_completion;
+
+ } else if (purb->status == -ESHUTDOWN) {
+ rtw_set_drv_stopped(padapter);
+
+ goto check_completion;
+ } else {
+ rtw_set_surprise_removed(padapter);
+ RTW_INFO("bSurpriseRemoved=true\n");
+
+ goto check_completion;
+ }
+ }
+
+ #ifdef DBG_CONFIG_ERROR_DETECT
+ {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ pHalData->srestpriv.last_tx_complete_time = jiffies;
+ }
+ #endif
+
+check_completion:
+ _enter_critical(&pxmitpriv->lock_sctx, &irqL);
+ rtw_sctx_done_err(&pxmitbuf->sctx,
+ purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS);
+ _exit_critical(&pxmitpriv->lock_sctx, &irqL);
+
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+
+ /* if(rtw_txframes_pending(padapter)) */
+ {
+ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+ }
+
+
+}
+
+u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+ unsigned long irqL;
+ unsigned int pipe;
+ int status;
+ u32 ret = _FAIL, bwritezero = false;
+ PURB purb = NULL;
+ _adapter *padapter = (_adapter *)pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+ struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem;
+ struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+ struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+
+
+ if (RTW_CANNOT_TX(padapter)) {
+#ifdef DBG_TX
+ RTW_INFO(" DBG_TX %s:%d bDriverStopped%s, bSurpriseRemoved:%s\n", __func__, __LINE__
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+#endif
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
+ goto exit;
+ }
+
+ _enter_critical(&pxmitpriv->lock, &irqL);
+
+ switch (addr) {
+ case VO_QUEUE_INX:
+ pxmitpriv->voq_cnt++;
+ pxmitbuf->flags = VO_QUEUE_INX;
+ break;
+ case VI_QUEUE_INX:
+ pxmitpriv->viq_cnt++;
+ pxmitbuf->flags = VI_QUEUE_INX;
+ break;
+ case BE_QUEUE_INX:
+ pxmitpriv->beq_cnt++;
+ pxmitbuf->flags = BE_QUEUE_INX;
+ break;
+ case BK_QUEUE_INX:
+ pxmitpriv->bkq_cnt++;
+ pxmitbuf->flags = BK_QUEUE_INX;
+ break;
+ case HIGH_QUEUE_INX:
+ pxmitbuf->flags = HIGH_QUEUE_INX;
+ break;
+ default:
+ pxmitbuf->flags = MGT_QUEUE_INX;
+ break;
+ }
+
+ _exit_critical(&pxmitpriv->lock, &irqL);
+
+ purb = pxmitbuf->pxmit_urb[0];
+
+ /* translate DMA FIFO addr to pipehandle */
+#ifdef RTW_HALMAC
+ pipe = ffaddr2pipehdl(pdvobj, pxmitbuf->bulkout_id);
+#else
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+#endif
+
+#ifdef CONFIG_REDUCE_USB_TX_INT
+ if ((pxmitpriv->free_xmitbuf_cnt % NR_XMITBUFF == 0)
+ || (pxmitbuf->buf_tag > XMITBUF_DATA))
+ purb->transfer_flags &= (~URB_NO_INTERRUPT);
+ else {
+ purb->transfer_flags |= URB_NO_INTERRUPT;
+ /* RTW_INFO("URB_NO_INTERRUPT "); */
+ }
+#endif
+
+
+ usb_fill_bulk_urb(purb, pusbd, pipe,
+ pxmitframe->buf_addr, /* = pxmitbuf->pbuf */
+ cnt,
+ usb_write_port_complete,
+ pxmitbuf);/* context is pxmitbuf */
+
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
+ purb->transfer_dma = pxmitbuf->dma_transfer_addr;
+ purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ purb->transfer_flags |= URB_ZERO_PACKET;
+#endif /* CONFIG_USE_USB_BUFFER_ALLOC_TX */
+
+#ifdef USB_PACKET_OFFSET_SZ
+#if (USB_PACKET_OFFSET_SZ == 0)
+ purb->transfer_flags |= URB_ZERO_PACKET;
+#endif
+#endif
+ status = usb_submit_urb(purb, GFP_ATOMIC);
+ if (!status) {
+ #ifdef DBG_CONFIG_ERROR_DETECT
+ {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ pHalData->srestpriv.last_tx_time = jiffies;
+ }
+ #endif
+ } else {
+ rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
+ RTW_INFO("usb_write_port, status=%d\n", status);
+
+ switch (status) {
+ case -ENODEV:
+ rtw_set_drv_stopped(padapter);
+ break;
+ default:
+ break;
+ }
+ goto exit;
+ }
+
+ ret = _SUCCESS;
+
+ /* Commented by Albert 2009/10/13
+ * We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */
+ /*
+ if(bwritezero == true)
+ {
+ usb_bulkout_zero(pintfhdl, addr);
+ }
+ */
+
+
+exit:
+ if (ret != _SUCCESS)
+ rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
+ return ret;
+
+}
+
+void usb_write_port_cancel(struct intf_hdl *pintfhdl)
+{
+ int i, j;
+ _adapter *padapter = pintfhdl->padapter;
+ struct xmit_buf *pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmitbuf;
+
+ RTW_INFO("%s\n", __func__);
+
+ for (i = 0; i < NR_XMITBUFF; i++) {
+ for (j = 0; j < 8; j++) {
+ if (pxmitbuf->pxmit_urb[j])
+ usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+ }
+ pxmitbuf++;
+ }
+
+ pxmitbuf = (struct xmit_buf *)padapter->xmitpriv.pxmit_extbuf;
+ for (i = 0; i < NR_XMIT_EXTBUFF ; i++) {
+ for (j = 0; j < 8; j++) {
+ if (pxmitbuf->pxmit_urb[j])
+ usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+ }
+ pxmitbuf++;
+ }
+}
+
+static void usb_init_recvbuf(_adapter *padapter, struct recv_buf *precvbuf)
+{
+
+ precvbuf->transfer_len = 0;
+
+ precvbuf->len = 0;
+
+ precvbuf->ref_cnt = 0;
+
+ if (precvbuf->pbuf) {
+ precvbuf->pdata = precvbuf->phead = precvbuf->ptail = precvbuf->pbuf;
+ precvbuf->pend = precvbuf->pdata + MAX_RECVBUF_SZ;
+ }
+
+}
+
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX
+void usb_recv_tasklet(void *priv)
+{
+ struct recv_buf *precvbuf = NULL;
+ _adapter *padapter = (_adapter *)priv;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ while (NULL != (precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue))) {
+ if (RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("recv_tasklet => bDriverStopped(%s) OR bSurpriseRemoved(%s)\n"
+ , rtw_is_drv_stopped(padapter)? "True" : "False"
+ , rtw_is_surprise_removed(padapter)? "True" : "False");
+ break;
+ }
+
+ recvbuf2recvframe(padapter, precvbuf);
+
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ }
+}
+
+void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+ struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
+ _adapter *padapter = (_adapter *)precvbuf->adapter;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ ATOMIC_DEC(&(precvpriv->rx_pending_cnt));
+
+ if (RTW_CANNOT_RX(padapter)) {
+ RTW_INFO("%s() RX Warning! bDriverStopped(%s) OR bSurpriseRemoved(%s)\n"
+ , __func__
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+ goto exit;
+ }
+
+ if (purb->status == 0) {
+
+ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) {
+ RTW_INFO("%s()-%d: urb->actual_length:%u, MAX_RECVBUF_SZ:%u, RXDESC_SIZE:%u\n"
+ , __func__, __LINE__, purb->actual_length, MAX_RECVBUF_SZ, RXDESC_SIZE);
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ } else {
+ rtw_reset_continual_io_error(adapter_to_dvobj(padapter));
+
+ precvbuf->transfer_len = purb->actual_length;
+
+ rtw_enqueue_recvbuf(precvbuf, &precvpriv->recv_buf_pending_queue);
+
+ tasklet_schedule(&precvpriv->recv_tasklet);
+ }
+ } else {
+
+ RTW_INFO("###=> usb_read_port_complete => urb.status(%d)\n", purb->status);
+
+ if (rtw_inc_and_chk_continual_io_error(adapter_to_dvobj(padapter)) == true)
+ rtw_set_surprise_removed(padapter);
+
+ switch (purb->status) {
+ case -EINVAL:
+ case -EPIPE:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ rtw_set_drv_stopped(padapter);
+ break;
+ case -EPROTO:
+ case -EILSEQ:
+ case -ETIME:
+ case -ECOMM:
+ case -EOVERFLOW:
+ #ifdef DBG_CONFIG_ERROR_DETECT
+ {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ pHalData->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL;
+ }
+ #endif
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ break;
+ case -EINPROGRESS:
+ RTW_INFO("ERROR: URB IS IN PROGRESS!/n");
+ break;
+ default:
+ break;
+ }
+ }
+
+exit:
+
+}
+
+u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+ int err;
+ unsigned int pipe;
+ u32 ret = _SUCCESS;
+ PURB purb = NULL;
+ struct recv_buf *precvbuf = (struct recv_buf *)rmem;
+ _adapter *adapter = pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
+ struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
+ struct recv_priv *precvpriv = &adapter->recvpriv;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+
+ if (RTW_CANNOT_RX(adapter) || (precvbuf == NULL)) {
+ return _FAIL;
+ }
+
+ usb_init_recvbuf(adapter, precvbuf);
+
+ if (precvbuf->pbuf) {
+ ATOMIC_INC(&(precvpriv->rx_pending_cnt));
+ purb = precvbuf->purb;
+
+ /* translate DMA FIFO addr to pipehandle */
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+
+ usb_fill_bulk_urb(purb, pusbd, pipe,
+ precvbuf->pbuf,
+ MAX_RECVBUF_SZ,
+ usb_read_port_complete,
+ precvbuf);/* context is precvbuf */
+
+ purb->transfer_dma = precvbuf->dma_transfer_addr;
+ purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ err = usb_submit_urb(purb, GFP_ATOMIC);
+ if ((err) && (err != (-EPERM))) {
+ RTW_INFO("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n", err, purb->status);
+ ret = _FAIL;
+ }
+
+ }
+
+
+ return ret;
+}
+#else /* CONFIG_USE_USB_BUFFER_ALLOC_RX */
+
+void usb_recv_tasklet(void *priv)
+{
+ _pkt *pskb;
+ _adapter *padapter = (_adapter *)priv;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+ struct recv_buf *precvbuf = NULL;
+
+ while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
+
+ if (RTW_CANNOT_RUN(padapter)) {
+ RTW_INFO("recv_tasklet => bDriverStopped(%s) OR bSurpriseRemoved(%s)\n"
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+ #ifdef CONFIG_PREALLOC_RX_SKB_BUFFER
+ if (rtw_free_skb_premem(pskb) != 0)
+ #endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */
+ rtw_skb_free(pskb);
+ break;
+ }
+
+ recvbuf2recvframe(padapter, pskb);
+
+ skb_reset_tail_pointer(pskb);
+ pskb->len = 0;
+
+ skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+
+ precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);
+ if (NULL != precvbuf) {
+ precvbuf->pskb = NULL;
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ }
+ }
+}
+
+static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+ struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
+ _adapter *padapter = (_adapter *)precvbuf->adapter;
+ struct recv_priv *precvpriv = &padapter->recvpriv;
+
+ ATOMIC_DEC(&(precvpriv->rx_pending_cnt));
+
+ if (RTW_CANNOT_RX(padapter)) {
+ RTW_INFO("%s() RX Warning! bDriverStopped(%s) OR bSurpriseRemoved(%s)\n"
+ , __func__
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+ goto exit;
+ }
+
+ if (purb->status == 0) {
+
+ if ((purb->actual_length > MAX_RECVBUF_SZ) || (purb->actual_length < RXDESC_SIZE)) {
+ RTW_INFO("%s()-%d: urb->actual_length:%u, MAX_RECVBUF_SZ:%u, RXDESC_SIZE:%u\n"
+ , __func__, __LINE__, purb->actual_length, MAX_RECVBUF_SZ, RXDESC_SIZE);
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ } else {
+ rtw_reset_continual_io_error(adapter_to_dvobj(padapter));
+
+ precvbuf->transfer_len = purb->actual_length;
+ skb_put(precvbuf->pskb, purb->actual_length);
+ skb_queue_tail(&precvpriv->rx_skb_queue, precvbuf->pskb);
+
+ #ifndef CONFIG_FIX_NR_BULKIN_BUFFER
+ if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1)
+ #endif
+ tasklet_schedule(&precvpriv->recv_tasklet);
+
+ precvbuf->pskb = NULL;
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ }
+ } else {
+
+ RTW_INFO("###=> usb_read_port_complete => urb.status(%d)\n", purb->status);
+
+ if (rtw_inc_and_chk_continual_io_error(adapter_to_dvobj(padapter)) == true)
+ rtw_set_surprise_removed(padapter);
+
+ switch (purb->status) {
+ case -EINVAL:
+ case -EPIPE:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ rtw_set_drv_stopped(padapter);
+ break;
+ case -EPROTO:
+ case -EILSEQ:
+ case -ETIME:
+ case -ECOMM:
+ case -EOVERFLOW:
+ #ifdef DBG_CONFIG_ERROR_DETECT
+ {
+ HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
+ pHalData->srestpriv.Wifi_Error_Status = USB_READ_PORT_FAIL;
+ }
+ #endif
+ rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, (unsigned char *)precvbuf);
+ break;
+ case -EINPROGRESS:
+ RTW_INFO("ERROR: URB IS IN PROGRESS!/n");
+ break;
+ default:
+ break;
+ }
+ }
+
+exit:
+ return;
+}
+
+u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+ int err;
+ unsigned int pipe;
+ u32 ret = _FAIL;
+ PURB purb = NULL;
+ struct recv_buf *precvbuf = (struct recv_buf *)rmem;
+ _adapter *adapter = pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
+ struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj);
+ struct recv_priv *precvpriv = &adapter->recvpriv;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+
+ if (RTW_CANNOT_RX(adapter) || (precvbuf == NULL)) {
+ goto exit;
+ }
+
+ usb_init_recvbuf(adapter, precvbuf);
+
+ if (precvbuf->pskb == NULL) {
+ SIZE_PTR tmpaddr = 0;
+ SIZE_PTR alignment = 0;
+
+ precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
+ if (NULL != precvbuf->pskb)
+ goto recv_buf_hook;
+
+ #ifndef CONFIG_FIX_NR_BULKIN_BUFFER
+ precvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
+ #endif
+
+ if (precvbuf->pskb == NULL) {
+ if (0)
+ RTW_INFO("usb_read_port() enqueue precvbuf=%p\n", precvbuf);
+ /* enqueue precvbuf and wait for free skb */
+ rtw_enqueue_recvbuf(precvbuf, &precvpriv->recv_buf_pending_queue);
+ goto exit;
+ }
+
+ tmpaddr = (SIZE_PTR)precvbuf->pskb->data;
+ alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1);
+ skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
+ }
+
+recv_buf_hook:
+ precvbuf->phead = precvbuf->pskb->head;
+ precvbuf->pdata = precvbuf->pskb->data;
+ precvbuf->ptail = skb_tail_pointer(precvbuf->pskb);
+ precvbuf->pend = skb_end_pointer(precvbuf->pskb);
+ precvbuf->pbuf = precvbuf->pskb->data;
+
+ purb = precvbuf->purb;
+
+ /* translate DMA FIFO addr to pipehandle */
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+
+ usb_fill_bulk_urb(purb, pusbd, pipe,
+ precvbuf->pbuf,
+ MAX_RECVBUF_SZ,
+ usb_read_port_complete,
+ precvbuf);
+
+ err = usb_submit_urb(purb, GFP_ATOMIC);
+ if (err && err != (-EPERM)) {
+ RTW_INFO("cannot submit rx in-token(err = 0x%08x),urb_status = %d\n"
+ , err, purb->status);
+ goto exit;
+ }
+
+ ATOMIC_INC(&(precvpriv->rx_pending_cnt));
+ ret = _SUCCESS;
+
+exit:
+
+
+ return ret;
+}
+#endif /* CONFIG_USE_USB_BUFFER_ALLOC_RX */
+
+#ifdef CONFIG_USB_INTERRUPT_IN_PIPE
+void usb_read_interrupt_complete(struct urb *purb, struct pt_regs *regs)
+{
+ int err;
+ _adapter *padapter = (_adapter *)purb->context;
+
+ if (RTW_CANNOT_RX(padapter)) {
+ RTW_INFO("%s() RX Warning! bDriverStopped(%s) OR bSurpriseRemoved(%s)\n"
+ , __func__
+ , rtw_is_drv_stopped(padapter) ? "True" : "False"
+ , rtw_is_surprise_removed(padapter) ? "True" : "False");
+
+ return;
+ }
+
+ if (purb->status == 0) {/*SUCCESS*/
+ if (purb->actual_length > INTERRUPT_MSG_FORMAT_LEN)
+ RTW_INFO("usb_read_interrupt_complete: purb->actual_length > INTERRUPT_MSG_FORMAT_LEN(%d)\n", INTERRUPT_MSG_FORMAT_LEN);
+
+ rtw_hal_interrupt_handler(padapter, purb->actual_length, purb->transfer_buffer);
+
+ err = usb_submit_urb(purb, GFP_ATOMIC);
+ if ((err) && (err != (-EPERM)))
+ RTW_INFO("cannot submit interrupt in-token(err = 0x%08x),urb_status = %d\n", err, purb->status);
+ } else {
+ RTW_INFO("###=> usb_read_interrupt_complete => urb status(%d)\n", purb->status);
+
+ switch (purb->status) {
+ case -EINVAL:
+ case -EPIPE:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ rtw_set_drv_stopped(padapter);
+ break;
+ case -EPROTO:
+ break;
+ case -EINPROGRESS:
+ RTW_INFO("ERROR: URB IS IN PROGRESS!/n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr)
+{
+ int err;
+ unsigned int pipe;
+ u32 ret = _SUCCESS;
+ _adapter *adapter = pintfhdl->padapter;
+ struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
+ struct recv_priv *precvpriv = &adapter->recvpriv;
+ struct usb_device *pusbd = pdvobj->pusbdev;
+
+
+ if (RTW_CANNOT_RX(adapter)) {
+ return _FAIL;
+ }
+
+ /*translate DMA FIFO addr to pipehandle*/
+ pipe = ffaddr2pipehdl(pdvobj, addr);
+
+ usb_fill_int_urb(precvpriv->int_in_urb, pusbd, pipe,
+ precvpriv->int_in_buf,
+ INTERRUPT_MSG_FORMAT_LEN,
+ usb_read_interrupt_complete,
+ adapter,
+ 1);
+
+ err = usb_submit_urb(precvpriv->int_in_urb, GFP_ATOMIC);
+ if ((err) && (err != (-EPERM))) {
+ RTW_INFO("cannot submit interrupt in-token(err = 0x%08x), urb_status = %d\n", err, precvpriv->int_in_urb->status);
+ ret = _FAIL;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */
diff --git a/drivers/staging/rtl8188eu/os_dep/wifi_regd.c b/drivers/staging/rtl8188eu/os_dep/wifi_regd.c
new file mode 100644
index 000000000000..24b6799cd1d6
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/wifi_regd.c
@@ -0,0 +1,354 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ *****************************************************************************/
+
+#include <drv_types.h>
+
+#ifdef CONFIG_IOCTL_CFG80211
+
+#include <rtw_wifi_regd.h>
+
+static struct country_code_to_enum_rd allCountries[] = {
+ {COUNTRY_CODE_USER, "RD"},
+};
+
+/*
+ * REG_RULE(freq start, freq end, bandwidth, max gain, eirp, reg_flags)
+ */
+
+/*
+ *Only these channels all allow active
+ *scan on all world regulatory domains
+ */
+
+/* 2G chan 01 - chan 11 */
+#define RTW_2GHZ_CH01_11 \
+ REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
+
+/*
+ *We enable active scan on these a case
+ *by case basis by regulatory domain
+ */
+
+/* 2G chan 12 - chan 13, PASSIV SCAN */
+#define RTW_2GHZ_CH12_13 \
+ REG_RULE(2467-10, 2472+10, 40, 0, 20, \
+ NL80211_RRF_PASSIVE_SCAN)
+
+/* 2G chan 14, PASSIVS SCAN, NO OFDM (B only) */
+#define RTW_2GHZ_CH14 \
+ REG_RULE(2484-10, 2484+10, 40, 0, 20, \
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)
+
+/* 5G chan 36 - chan 64 */
+#define RTW_5GHZ_5150_5350 \
+ REG_RULE(5150-10, 5350+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+
+/* 5G chan 100 - chan 165 */
+#define RTW_5GHZ_5470_5850 \
+ REG_RULE(5470-10, 5850+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+
+/* 5G chan 149 - chan 165 */
+#define RTW_5GHZ_5725_5850 \
+ REG_RULE(5725-10, 5850+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+
+/* 5G chan 36 - chan 165 */
+#define RTW_5GHZ_5150_5850 \
+ REG_RULE(5150-10, 5850+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)
+
+static const struct ieee80211_regdomain rtw_regdom_rd = {
+ .n_reg_rules = 3,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ RTW_2GHZ_CH12_13,
+ RTW_5GHZ_5150_5850,
+ }
+};
+
+static const struct ieee80211_regdomain rtw_regdom_11 = {
+ .n_reg_rules = 1,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ }
+};
+
+static const struct ieee80211_regdomain rtw_regdom_12_13 = {
+ .n_reg_rules = 2,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ RTW_2GHZ_CH12_13,
+ }
+};
+
+static const struct ieee80211_regdomain rtw_regdom_no_midband = {
+ .n_reg_rules = 3,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ RTW_5GHZ_5150_5350,
+ RTW_5GHZ_5725_5850,
+ }
+};
+
+static const struct ieee80211_regdomain rtw_regdom_60_64 = {
+ .n_reg_rules = 3,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ RTW_2GHZ_CH12_13,
+ RTW_5GHZ_5725_5850,
+ }
+};
+
+static const struct ieee80211_regdomain rtw_regdom_14_60_64 = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ RTW_2GHZ_CH12_13,
+ RTW_2GHZ_CH14,
+ RTW_5GHZ_5725_5850,
+ }
+};
+
+static const struct ieee80211_regdomain rtw_regdom_14 = {
+ .n_reg_rules = 3,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTW_2GHZ_CH01_11,
+ RTW_2GHZ_CH12_13,
+ RTW_2GHZ_CH14,
+ }
+};
+
+static bool _rtw_is_radar_freq(u16 center_freq)
+{
+ return center_freq >= 5260 && center_freq <= 5700;
+}
+
+/*
+ * Always apply Radar/DFS rules on
+ * freq range 5260 MHz - 5700 MHz
+ */
+static void _rtw_reg_apply_radar_flags(struct wiphy *wiphy)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ unsigned int i;
+
+ if (!wiphy->bands[NL80211_BAND_5GHZ])
+ return;
+
+ sband = wiphy->bands[NL80211_BAND_5GHZ];
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (!_rtw_is_radar_freq(ch->center_freq))
+ continue;
+#ifdef CONFIG_DFS
+ if (!(ch->flags & IEEE80211_CHAN_DISABLED)
+ #if defined(CONFIG_DFS_MASTER)
+ && rtw_odm_dfs_domain_unknown(wiphy_to_adapter(wiphy))
+ #endif
+ ) {
+ ch->flags |= IEEE80211_CHAN_RADAR;
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ ch->flags |= (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN);
+ #else
+ ch->flags |= IEEE80211_CHAN_NO_IR;
+ #endif
+ }
+#endif /* CONFIG_DFS */
+ }
+}
+
+static void _rtw_reg_apply_flags(struct wiphy *wiphy)
+{
+ _adapter *padapter = wiphy_to_adapter(wiphy);
+ u8 channel_plan = padapter->mlmepriv.ChannelPlan;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ RT_CHANNEL_INFO *channel_set = pmlmeext->channel_set;
+ u8 max_chan_nums = pmlmeext->max_chan_nums;
+
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ unsigned int i, j;
+ u16 channel;
+ u32 freq;
+
+ /* all channels disable */
+ for (i = 0; i < NUM_NL80211_BANDS; i++) {
+ sband = wiphy->bands[i];
+
+ if (sband) {
+ for (j = 0; j < sband->n_channels; j++) {
+ ch = &sband->channels[j];
+
+ if (ch)
+ ch->flags = IEEE80211_CHAN_DISABLED;
+ }
+ }
+ }
+
+ /* channels apply by channel plans. */
+ for (i = 0; i < max_chan_nums; i++) {
+ channel = channel_set[i].ChannelNum;
+ freq = rtw_ch2freq(channel);
+
+ ch = ieee80211_get_channel(wiphy, freq);
+ if (ch) {
+ if (channel_set[i].ScanType == SCAN_PASSIVE
+ #if defined(CONFIG_DFS_MASTER)
+ && rtw_odm_dfs_domain_unknown(wiphy_to_adapter(wiphy))
+ #endif
+ ) {
+ #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ ch->flags = (IEEE80211_CHAN_NO_IBSS | IEEE80211_CHAN_PASSIVE_SCAN);
+ #else
+ ch->flags = IEEE80211_CHAN_NO_IR;
+ #endif
+ } else
+ ch->flags = 0;
+ }
+ }
+}
+
+static void _rtw_reg_apply_world_flags(struct wiphy *wiphy,
+ enum nl80211_reg_initiator initiator,
+ struct rtw_regulatory *reg)
+{
+ /* _rtw_reg_apply_beaconing_flags(wiphy, initiator); */
+ /* _rtw_reg_apply_active_scan_flags(wiphy, initiator); */
+ return;
+}
+
+static int _rtw_reg_notifier_apply(struct wiphy *wiphy,
+ struct regulatory_request *request,
+ struct rtw_regulatory *reg)
+{
+
+ /* Hard code flags */
+ _rtw_reg_apply_flags(wiphy);
+
+ /* We always apply this */
+ _rtw_reg_apply_radar_flags(wiphy);
+
+ switch (request->initiator) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ RTW_INFO("%s: %s\n", __func__, "NL80211_REGDOM_SET_BY_DRIVER");
+ _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
+ reg);
+ break;
+ case NL80211_REGDOM_SET_BY_CORE:
+ RTW_INFO("%s: %s\n", __func__,
+ "NL80211_REGDOM_SET_BY_CORE to DRV");
+ _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
+ reg);
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ RTW_INFO("%s: %s\n", __func__,
+ "NL80211_REGDOM_SET_BY_USER to DRV");
+ _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER,
+ reg);
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ RTW_INFO("%s: %s\n", __func__,
+ "NL80211_REGDOM_SET_BY_COUNTRY_IE");
+ _rtw_reg_apply_world_flags(wiphy, request->initiator, reg);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct ieee80211_regdomain *_rtw_regdomain_select(struct
+ rtw_regulatory
+ *reg)
+{
+ return &rtw_regdom_rd;
+}
+
+static void _rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+{
+ struct rtw_regulatory *reg = NULL;
+
+ RTW_INFO("%s\n", __func__);
+
+ _rtw_reg_notifier_apply(wiphy, request, reg);
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+static int rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+#else
+static void rtw_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
+#endif
+{
+ _rtw_reg_notifier(wiphy, request);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return 0;
+#endif
+}
+
+void rtw_reg_notify_by_driver(_adapter *adapter)
+{
+ if ((adapter->rtw_wdev != NULL) && (adapter->rtw_wdev->wiphy)) {
+ struct regulatory_request request;
+ request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+ rtw_reg_notifier(adapter->rtw_wdev->wiphy, &request);
+ }
+}
+
+static void _rtw_regd_init_wiphy(struct rtw_regulatory *reg, struct wiphy *wiphy)
+{
+ const struct ieee80211_regdomain *regd;
+
+ wiphy->reg_notifier = rtw_reg_notifier;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
+ wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
+#else
+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+ wiphy->regulatory_flags &= ~REGULATORY_STRICT_REG;
+ wiphy->regulatory_flags &= ~REGULATORY_DISABLE_BEACON_HINTS;
+#endif
+
+ regd = _rtw_regdomain_select(reg);
+ wiphy_apply_custom_regulatory(wiphy, regd);
+
+ /* Hard code flags */
+ _rtw_reg_apply_flags(wiphy);
+ _rtw_reg_apply_radar_flags(wiphy);
+ _rtw_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
+}
+
+static struct country_code_to_enum_rd *_rtw_regd_find_country(u16 countrycode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+ if (allCountries[i].countrycode == countrycode)
+ return &allCountries[i];
+ }
+ return NULL;
+}
+
+int rtw_regd_init(_adapter *padapter)
+{
+ struct wiphy *wiphy = padapter->rtw_wdev->wiphy;
+
+ _rtw_regd_init_wiphy(NULL, wiphy);
+
+ return 0;
+}
+#endif /* CONFIG_IOCTL_CFG80211 */
diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
new file mode 100644
index 000000000000..d7690a39f0f4
--- /dev/null
+++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c
@@ -0,0 +1,489 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. */
+
+#define _XMIT_OSDEP_C_
+
+#include <drv_types.h>
+#include <hal_data.h>
+
+#define DBG_DUMP_OS_QUEUE_CTL 0
+
+uint rtw_remainder_len(struct pkt_file *pfile)
+{
+ return pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start));
+}
+
+void _rtw_open_pktfile(_pkt *pktptr, struct pkt_file *pfile)
+{
+
+ pfile->pkt = pktptr;
+ pfile->cur_addr = pfile->buf_start = pktptr->data;
+ pfile->pkt_len = pfile->buf_len = pktptr->len;
+
+ pfile->cur_buffer = pfile->buf_start ;
+
+}
+
+uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
+{
+ uint len = 0;
+
+
+ len = rtw_remainder_len(pfile);
+ len = (rlen > len) ? len : rlen;
+
+ if (rmem)
+ skb_copy_bits(pfile->pkt, pfile->buf_len - pfile->pkt_len, rmem, len);
+
+ pfile->cur_addr += len;
+ pfile->pkt_len -= len;
+
+
+ return len;
+}
+
+sint rtw_endofpktfile(struct pkt_file *pfile)
+{
+
+ if (pfile->pkt_len == 0) {
+ return true;
+ }
+
+
+ return false;
+}
+
+void rtw_set_tx_chksum_offload(_pkt *pkt, struct pkt_attrib *pattrib)
+{
+
+#ifdef CONFIG_TCP_CSUM_OFFLOAD_TX
+ struct sk_buff *skb = (struct sk_buff *)pkt;
+ pattrib->hw_tcp_csum = 0;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_shinfo(skb)->nr_frags == 0) {
+ const struct iphdr *ip = ip_hdr(skb);
+ if (ip->protocol == IPPROTO_TCP) {
+ /* TCP checksum offload by HW */
+ RTW_INFO("CHECKSUM_PARTIAL TCP\n");
+ pattrib->hw_tcp_csum = 1;
+ /* skb_checksum_help(skb); */
+ } else if (ip->protocol == IPPROTO_UDP) {
+ /* RTW_INFO("CHECKSUM_PARTIAL UDP\n"); */
+ skb_checksum_help(skb);
+ } else {
+ RTW_INFO("%s-%d TCP CSUM offload Error!!\n", __func__, __LINE__);
+ WARN_ON(1); /* we need a WARN() */
+ }
+ } else { /* IP fragmentation case */
+ RTW_INFO("%s-%d nr_frags != 0, using skb_checksum_help(skb);!!\n", __func__, __LINE__);
+ skb_checksum_help(skb);
+ }
+ }
+#endif
+
+}
+
+int rtw_os_xmit_resource_alloc(_adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz, u8 flag)
+{
+ if (alloc_sz > 0) {
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+ struct usb_device *pusbd = pdvobjpriv->pusbdev;
+
+ pxmitbuf->pallocated_buf = rtw_usb_buffer_alloc(pusbd, (size_t)alloc_sz, &pxmitbuf->dma_transfer_addr);
+ pxmitbuf->pbuf = pxmitbuf->pallocated_buf;
+ if (pxmitbuf->pallocated_buf == NULL)
+ return _FAIL;
+#else /* CONFIG_USE_USB_BUFFER_ALLOC_TX */
+
+ pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz);
+ if (pxmitbuf->pallocated_buf == NULL)
+ return _FAIL;
+
+ pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ);
+
+#endif /* CONFIG_USE_USB_BUFFER_ALLOC_TX */
+ }
+
+ if (flag) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (pxmitbuf->pxmit_urb[i] == NULL) {
+ RTW_INFO("pxmitbuf->pxmit_urb[i]==NULL");
+ return _FAIL;
+ }
+ }
+ }
+ return _SUCCESS;
+}
+
+void rtw_os_xmit_resource_free(_adapter *padapter, struct xmit_buf *pxmitbuf, u32 free_sz, u8 flag)
+{
+ if (flag) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (pxmitbuf->pxmit_urb[i]) {
+ /* usb_kill_urb(pxmitbuf->pxmit_urb[i]); */
+ usb_free_urb(pxmitbuf->pxmit_urb[i]);
+ }
+ }
+ }
+
+ if (free_sz > 0) {
+#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX
+ struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+ struct usb_device *pusbd = pdvobjpriv->pusbdev;
+
+ rtw_usb_buffer_free(pusbd, (size_t)free_sz, pxmitbuf->pallocated_buf, pxmitbuf->dma_transfer_addr);
+ pxmitbuf->pallocated_buf = NULL;
+ pxmitbuf->dma_transfer_addr = 0;
+#else /* CONFIG_USE_USB_BUFFER_ALLOC_TX */
+ if (pxmitbuf->pallocated_buf)
+ rtw_mfree(pxmitbuf->pallocated_buf, free_sz);
+#endif /* CONFIG_USE_USB_BUFFER_ALLOC_TX */
+ }
+}
+
+void dump_os_queue(void *sel, _adapter *padapter)
+{
+ struct net_device *ndev = padapter->pnetdev;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ RTW_PRINT_SEL(sel, "os_queue[%d]:%s\n"
+ , i, __netif_subqueue_stopped(ndev, i) ? "stopped" : "waked");
+ }
+#else
+ RTW_PRINT_SEL(sel, "os_queue:%s\n"
+ , netif_queue_stopped(ndev) ? "stopped" : "waked");
+#endif
+}
+
+#define WMM_XMIT_THRESHOLD (NR_XMITFRAME*2/5)
+
+static inline bool rtw_os_need_wake_queue(_adapter *padapter, u16 qidx)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+ if (padapter->registrypriv.wifi_spec) {
+ if (pxmitpriv->hwxmits[qidx].accnt < WMM_XMIT_THRESHOLD)
+ return true;
+ } else {
+#ifdef CONFIG_MCC_MODE
+ if (MCC_EN(padapter)) {
+ if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)
+ && MCC_STOP(padapter))
+ return false;
+ }
+#endif /* CONFIG_MCC_MODE */
+ return true;
+ }
+ return false;
+#else
+#ifdef CONFIG_MCC_MODE
+ if (MCC_EN(padapter)) {
+ if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)
+ && MCC_STOP(padapter))
+ return false;
+ }
+#endif /* CONFIG_MCC_MODE */
+ return true;
+#endif
+}
+
+static inline bool rtw_os_need_stop_queue(_adapter *padapter, u16 qidx)
+{
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ if (padapter->registrypriv.wifi_spec) {
+ /* No free space for Tx, tx_worker is too slow */
+ if (pxmitpriv->hwxmits[qidx].accnt > WMM_XMIT_THRESHOLD)
+ return true;
+ } else {
+ if (pxmitpriv->free_xmitframe_cnt <= 4)
+ return true;
+ }
+#else
+ if (pxmitpriv->free_xmitframe_cnt <= 4)
+ return true;
+#endif
+ return false;
+}
+
+void rtw_os_pkt_complete(_adapter *padapter, _pkt *pkt)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ u16 qidx;
+
+ qidx = skb_get_queue_mapping(pkt);
+ if (rtw_os_need_wake_queue(padapter, qidx)) {
+ if (DBG_DUMP_OS_QUEUE_CTL)
+ RTW_INFO(FUNC_ADPT_FMT": netif_wake_subqueue[%d]\n", FUNC_ADPT_ARG(padapter), qidx);
+ netif_wake_subqueue(padapter->pnetdev, qidx);
+ }
+#else
+ if (rtw_os_need_wake_queue(padapter, 0)) {
+ if (DBG_DUMP_OS_QUEUE_CTL)
+ RTW_INFO(FUNC_ADPT_FMT": netif_wake_queue\n", FUNC_ADPT_ARG(padapter));
+ netif_wake_queue(padapter->pnetdev);
+ }
+#endif
+
+ rtw_skb_free(pkt);
+}
+
+void rtw_os_xmit_complete(_adapter *padapter, struct xmit_frame *pxframe)
+{
+ if (pxframe->pkt)
+ rtw_os_pkt_complete(padapter, pxframe->pkt);
+
+ pxframe->pkt = NULL;
+}
+
+void rtw_os_xmit_schedule(_adapter *padapter)
+{
+ unsigned long irqL;
+ struct xmit_priv *pxmitpriv;
+
+ if (!padapter)
+ return;
+
+ pxmitpriv = &padapter->xmitpriv;
+
+ _enter_critical_bh(&pxmitpriv->lock, &irqL);
+
+ if (rtw_txframes_pending(padapter))
+ tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+
+ _exit_critical_bh(&pxmitpriv->lock, &irqL);
+}
+
+static bool rtw_check_xmit_resource(_adapter *padapter, _pkt *pkt)
+{
+ bool busy = false;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ u16 qidx;
+
+ qidx = skb_get_queue_mapping(pkt);
+ if (rtw_os_need_stop_queue(padapter, qidx)) {
+ if (DBG_DUMP_OS_QUEUE_CTL)
+ RTW_INFO(FUNC_ADPT_FMT": netif_stop_subqueue[%d]\n", FUNC_ADPT_ARG(padapter), qidx);
+ netif_stop_subqueue(padapter->pnetdev, qidx);
+ busy = true;
+ }
+#else
+ if (rtw_os_need_stop_queue(padapter, 0)) {
+ if (DBG_DUMP_OS_QUEUE_CTL)
+ RTW_INFO(FUNC_ADPT_FMT": netif_stop_queue\n", FUNC_ADPT_ARG(padapter));
+ rtw_netif_stop_queue(padapter->pnetdev);
+ busy = true;
+ }
+#endif
+ return busy;
+}
+
+void rtw_os_wake_queue_at_free_stainfo(_adapter *padapter, int *qcnt_freed)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (qcnt_freed[i] == 0)
+ continue;
+
+ if (rtw_os_need_wake_queue(padapter, i)) {
+ if (DBG_DUMP_OS_QUEUE_CTL)
+ RTW_INFO(FUNC_ADPT_FMT": netif_wake_subqueue[%d]\n", FUNC_ADPT_ARG(padapter), i);
+ netif_wake_subqueue(padapter->pnetdev, i);
+ }
+ }
+#else
+ if (qcnt_freed[0] || qcnt_freed[1] || qcnt_freed[2] || qcnt_freed[3]) {
+ if (rtw_os_need_wake_queue(padapter, 0)) {
+ if (DBG_DUMP_OS_QUEUE_CTL)
+ RTW_INFO(FUNC_ADPT_FMT": netif_wake_queue\n", FUNC_ADPT_ARG(padapter));
+ netif_wake_queue(padapter->pnetdev);
+ }
+ }
+#endif
+}
+
+#ifdef CONFIG_TX_MCAST2UNI
+static int rtw_mlcst2unicst(_adapter *padapter, struct sk_buff *skb)
+{
+ struct sta_priv *pstapriv = &padapter->stapriv;
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+ unsigned long irqL;
+ _list *phead, *plist;
+ struct sk_buff *newskb;
+ struct sta_info *psta = NULL;
+ u8 chk_alive_num = 0;
+ char chk_alive_list[NUM_STA];
+ u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ int i;
+ s32 res;
+
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u);
+
+ _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+ phead = &pstapriv->asoc_list;
+ plist = get_next(phead);
+
+ /* free sta asoc_queue */
+ while ((rtw_end_of_queue_search(phead, plist)) == false) {
+ int stainfo_offset;
+ psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
+ plist = get_next(plist);
+
+ stainfo_offset = rtw_stainfo_offset(pstapriv, psta);
+ if (stainfo_offset_valid(stainfo_offset))
+ chk_alive_list[chk_alive_num++] = stainfo_offset;
+ }
+ _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
+
+ for (i = 0; i < chk_alive_num; i++) {
+ psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]);
+ if (!(psta->state & _FW_LINKED)) {
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked);
+ continue;
+ }
+
+ /* avoid come from STA1 and send back STA1 */
+ if (!memcmp(psta->hwaddr, &skb->data[6], 6)
+ || !memcmp(psta->hwaddr, null_addr, 6)
+ || !memcmp(psta->hwaddr, bc_addr, 6)
+ ) {
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self);
+ continue;
+ }
+
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry);
+
+ newskb = rtw_skb_copy(skb);
+
+ if (newskb) {
+ memcpy(newskb->data, psta->hwaddr, 6);
+ res = rtw_xmit(padapter, &newskb);
+ if (res < 0) {
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_xmit);
+ RTW_INFO("%s()-%d: rtw_xmit() return error! res=%d\n", __func__, __LINE__, res);
+ pxmitpriv->tx_drop++;
+ rtw_skb_free(newskb);
+ }
+ } else {
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_entry_err_skb);
+ RTW_INFO("%s-%d: rtw_skb_copy() failed!\n", __func__, __LINE__);
+ pxmitpriv->tx_drop++;
+ /* rtw_skb_free(skb); */
+ return false; /* Caller shall tx this multicast frame via normal way. */
+ }
+ }
+
+ rtw_skb_free(skb);
+ return true;
+}
+#endif /* CONFIG_TX_MCAST2UNI */
+
+
+int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+#ifdef CONFIG_TX_MCAST2UNI
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif /* CONFIG_TX_MCAST2UNI */
+ s32 res = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+ u16 queue;
+#endif
+
+
+ if (padapter->registrypriv.mp_mode) {
+ RTW_INFO("MP_TX_DROP_OS_FRAME\n");
+ goto drop_packet;
+ }
+ DBG_COUNTER(padapter->tx_logs.os_tx);
+
+ if (rtw_if_up(padapter) == false) {
+ DBG_COUNTER(padapter->tx_logs.os_tx_err_up);
+ #ifdef DBG_TX_DROP_FRAME
+ RTW_INFO("DBG_TX_DROP_FRAME %s if_up fail\n", __func__);
+ #endif
+ goto drop_packet;
+ }
+
+ rtw_check_xmit_resource(padapter, pkt);
+
+#ifdef CONFIG_TX_MCAST2UNI
+ if (!rtw_mc2u_disable
+ && check_fwstate(pmlmepriv, WIFI_AP_STATE)
+ && (IP_MCAST_MAC(pkt->data)
+ || ICMPV6_MCAST_MAC(pkt->data)
+ #ifdef CONFIG_TX_BCAST2UNI
+ || is_broadcast_mac_addr(pkt->data)
+ #endif
+ )
+ && (padapter->registrypriv.wifi_spec == 0)
+ ) {
+ if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME / 4)) {
+ res = rtw_mlcst2unicst(padapter, pkt);
+ if (res)
+ goto exit;
+ } else {
+ /* RTW_INFO("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */
+ /* RTW_INFO("!m2u ); */
+ DBG_COUNTER(padapter->tx_logs.os_tx_m2u_stop);
+ }
+ }
+#endif /* CONFIG_TX_MCAST2UNI */
+
+ res = rtw_xmit(padapter, &pkt);
+ if (res < 0) {
+ #ifdef DBG_TX_DROP_FRAME
+ RTW_INFO("DBG_TX_DROP_FRAME %s rtw_xmit fail\n", __func__);
+ #endif
+ goto drop_packet;
+ }
+
+ goto exit;
+
+drop_packet:
+ pxmitpriv->tx_drop++;
+ rtw_os_pkt_complete(padapter, pkt);
+
+exit:
+
+
+ return 0;
+}
+
+int rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev)
+{
+ _adapter *padapter = (_adapter *)rtw_netdev_priv(pnetdev);
+ struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ int ret = 0;
+
+ if (pkt) {
+ if (check_fwstate(pmlmepriv, WIFI_MONITOR_STATE)) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24))
+ rtw_monitor_xmit_entry((struct sk_buff *)pkt, pnetdev);
+#endif
+ }
+ else {
+ rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, pkt->truesize);
+ ret = _rtw_xmit_entry(pkt, pnetdev);
+ }
+
+ }
+
+ return ret;
+}
--
2.31.1
Powered by blists - more mailing lists