| /****************************************************************************** |
| * |
| * This file is provided under a dual license. When you use or |
| * distribute this software, you may choose to be licensed under |
| * version 2 of the GNU General Public License ("GPLv2 License") |
| * or BSD License. |
| * |
| * GPLv2 License |
| * |
| * Copyright(C) 2016 MediaTek Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * See http://www.gnu.org/licenses/gpl-2.0.html for more details. |
| * |
| * BSD LICENSE |
| * |
| * Copyright(C) 2016 MediaTek Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of the copyright holder nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| *****************************************************************************/ |
| /* |
| ** gl_vendor.c |
| ** |
| ** |
| */ |
| |
| /******************************************************************************* |
| * C O M P I L E R F L A G S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * E X T E R N A L R E F E R E N C E S |
| ******************************************************************************** |
| */ |
| #include "gl_os.h" |
| #include "debug.h" |
| #include "wlan_lib.h" |
| #include "gl_wext.h" |
| #include "precomp.h" |
| #include <linux/can/netlink.h> |
| #include <net/netlink.h> |
| #include <net/cfg80211.h> |
| #include "gl_cfg80211.h" |
| #include "gl_vendor.h" |
| #include "wlan_oid.h" |
| |
| /******************************************************************************* |
| * C O N S T A N T S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * D A T A T Y P E S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * P U B L I C D A T A |
| ******************************************************************************** |
| */ |
| |
| P_SW_RFB_T g_arGscnResultsTempBuffer[MAX_BUFFERED_GSCN_RESULTS]; |
| UINT_8 g_GscanResultsTempBufferIndex; |
| UINT_8 g_arGscanResultsIndicateNumber[MAX_BUFFERED_GSCN_RESULTS] = { 0, 0, 0, 0, 0 }; |
| |
| UINT_8 g_GetResultsBufferedCnt; |
| UINT_8 g_GetResultsCmdCnt; |
| |
| /******************************************************************************* |
| * P R I V A T E D A T A |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * M A C R O S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * F U N C T I O N D E C L A R A T I O N S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * F U N C T I O N S |
| ******************************************************************************** |
| */ |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) |
| |
| int mtk_cfg80211_NLA_PUT(struct sk_buff *skb, int attrtype, int attrlen, const void *data) |
| { |
| if (unlikely(nla_put(skb, attrtype, attrlen, data) < 0)) |
| return 0; |
| return 1; |
| } |
| |
| int mtk_cfg80211_nla_put_type(struct sk_buff *skb, ENUM_NLA_PUT_DATE_TYPE type, int attrtype, const void *value) |
| { |
| u8 u8data = 0; |
| u16 u16data = 0; |
| u32 u32data = 0; |
| u64 u64data = 0; |
| |
| switch (type) { |
| case NLA_PUT_DATE_U8: |
| u8data = *(u8 *)value; |
| return mtk_cfg80211_NLA_PUT(skb, attrtype, sizeof(u8), &u8data); |
| case NLA_PUT_DATE_U16: |
| u16data = *(u16 *)value; |
| return mtk_cfg80211_NLA_PUT(skb, attrtype, sizeof(u16), &u16data); |
| case NLA_PUT_DATE_U32: |
| u32data = *(u32 *)value; |
| return mtk_cfg80211_NLA_PUT(skb, attrtype, sizeof(u32), &u32data); |
| case NLA_PUT_DATE_U64: |
| u64data = *(u64 *)value; |
| return mtk_cfg80211_NLA_PUT(skb, attrtype, sizeof(u64), &u64data); |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| #if 0 |
| int mtk_cfg80211_vendor_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| INT_32 i4Status = -EINVAL; |
| PARAM_WIFI_GSCAN_CAPABILITIES_STRUCT_T rGscanCapabilities; |
| struct sk_buff *skb; |
| |
| DBGLOG(REQ, TRACE, "for vendor command\r\n"); |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| |
| skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(rGscanCapabilities)); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed:%x\n", __func__, i4Status); |
| return -ENOMEM; |
| } |
| |
| kalMemZero(&rGscanCapabilities, sizeof(rGscanCapabilities)); |
| |
| /*rStatus = kalIoctl(prGlueInfo, |
| * wlanoidQueryStatistics, |
| * &rGscanCapabilities, |
| * sizeof(rGscanCapabilities), |
| * TRUE, |
| * TRUE, |
| * TRUE, |
| * FALSE, |
| * &u4BufLen); |
| */ |
| rGscanCapabilities.max_scan_cache_size = PSCAN_MAX_SCAN_CACHE_SIZE; |
| rGscanCapabilities.max_scan_buckets = GSCAN_MAX_BUCKETS; |
| rGscanCapabilities.max_ap_cache_per_scan = PSCAN_MAX_AP_CACHE_PER_SCAN; |
| rGscanCapabilities.max_rssi_sample_size = 10; |
| rGscanCapabilities.max_scan_reporting_threshold = GSCAN_MAX_REPORT_THRESHOLD; |
| rGscanCapabilities.max_hotlist_aps = MAX_HOTLIST_APS; |
| rGscanCapabilities.max_significant_wifi_change_aps = MAX_SIGNIFICANT_CHANGE_APS; |
| rGscanCapabilities.max_bssid_history_entries = PSCAN_MAX_AP_CACHE_PER_SCAN * PSCAN_MAX_SCAN_CACHE_SIZE; |
| |
| /* NLA_PUT_U8(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, 0); */ |
| /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_ID, GOOGLE_OUI); */ |
| /* NLA_PUT_U32(skb, NL80211_ATTR_VENDOR_SUBCMD, GSCAN_SUBCMD_GET_CAPABILITIES); */ |
| NLA_PUT(skb, NL80211_ATTR_VENDOR_CAPABILITIES, sizeof(rGscanCapabilities), &rGscanCapabilities); |
| |
| i4Status = cfg80211_vendor_cmd_reply(skb); |
| |
| return i4Status; |
| } |
| |
| int mtk_cfg80211_vendor_set_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| /* CMD_GSCN_REQ_T rCmdGscnParam; */ |
| |
| /* INT_32 i4Status = -EINVAL; */ |
| P_PARAM_WIFI_GSCAN_CMD_PARAMS prWifiScanCmd; |
| struct nlattr *attr[GSCAN_ATTRIBUTE_REPORT_EVENTS + 1]; |
| struct nlattr *pbucket, *pchannel; |
| UINT_32 len_basic, len_bucket, len_channel; |
| int i, j, k; |
| static struct nla_policy policy[GSCAN_ATTRIBUTE_REPORT_EVENTS + 1] = { |
| [GSCAN_ATTRIBUTE_NUM_BUCKETS] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_BASE_PERIOD] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_BUCKETS_BAND] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_BUCKET_ID] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_BUCKET_PERIOD] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_BUCKET_CHANNELS] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_REPORT_EVENTS] = {.type = NLA_U32}, |
| }; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| |
| prWifiScanCmd = (P_PARAM_WIFI_GSCAN_CMD_PARAMS) kalMemAlloc(sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), VIR_MEM_TYPE); |
| if (!prWifiScanCmd) { |
| DBGLOG(REQ, ERROR, "Can not alloc memory for PARAM_WIFI_GSCAN_CMD_PARAMS\n"); |
| return -ENOMEM; |
| } |
| |
| DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d\r\n", __func__, data_len); |
| kalMemZero(prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS)); |
| kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_REPORT_EVENTS + 1)); |
| |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)(data - NLA_HDRLEN), policy); |
| len_basic = 0; |
| for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_BASE_PERIOD: |
| prWifiScanCmd->base_period = nla_get_u32(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_NUM_BUCKETS: |
| prWifiScanCmd->num_buckets = nla_get_u32(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| DBGLOG(REQ, TRACE, "attr=0x%x, num_buckets=%d nla_len=%d\r\n", |
| *(UINT_32 *) attr[k], prWifiScanCmd->num_buckets, attr[k]->nla_len); |
| break; |
| } |
| } |
| } |
| pbucket = (struct nlattr *)((UINT_8 *) data + len_basic); |
| DBGLOG(REQ, TRACE, "+++basic attribute size=%d pbucket=%p\r\n", len_basic, pbucket); |
| |
| for (i = 0; i < prWifiScanCmd->num_buckets; i++) { |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_REPORT_EVENTS, (struct nlattr *)pbucket, policy); |
| len_bucket = 0; |
| for (k = GSCAN_ATTRIBUTE_NUM_BUCKETS; k <= GSCAN_ATTRIBUTE_REPORT_EVENTS; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_BUCKETS_BAND: |
| prWifiScanCmd->buckets[i].band = nla_get_u32(attr[k]); |
| len_bucket += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_BUCKET_ID: |
| prWifiScanCmd->buckets[i].bucket = nla_get_u32(attr[k]); |
| len_bucket += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_BUCKET_PERIOD: |
| prWifiScanCmd->buckets[i].period = nla_get_u32(attr[k]); |
| len_bucket += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_REPORT_EVENTS: |
| prWifiScanCmd->buckets[i].report_events = nla_get_u32(attr[k]); |
| len_bucket += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS: |
| prWifiScanCmd->buckets[i].num_channels = nla_get_u32(attr[k]); |
| len_bucket += NLA_ALIGN(attr[k]->nla_len); |
| DBGLOG(REQ, TRACE, |
| "bucket%d: attr=0x%x, num_channels=%d nla_len=%d\r\n", |
| i, *(UINT_32 *) attr[k], nla_get_u32(attr[k]), attr[k]->nla_len); |
| break; |
| } |
| } |
| } |
| pbucket = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); |
| /* request.attr_start(i) as nested attribute */ |
| DBGLOG(REQ, TRACE, "+++pure bucket size=%d pbucket=%p\r\n", len_bucket, pbucket); |
| pbucket = (struct nlattr *)((UINT_8 *) pbucket + len_bucket); |
| /* pure bucket payload, not include channels */ |
| |
| /*don't need to use nla_parse_nested to parse channels */ |
| /* the header of channel in bucket i */ |
| pchannel = (struct nlattr *)((UINT_8 *) pbucket + NLA_HDRLEN); |
| for (j = 0; j < prWifiScanCmd->buckets[i].num_channels; j++) { |
| prWifiScanCmd->buckets[i].channels[j].channel = nla_get_u32(pchannel); |
| len_channel = NLA_ALIGN(pchannel->nla_len); |
| DBGLOG(REQ, TRACE, |
| "attr=0x%x, channel=%d\r\n", *(UINT_32 *) pchannel, nla_get_u32(pchannel)); |
| |
| pchannel = (struct nlattr *)((UINT_8 *) pchannel + len_channel); |
| } |
| pbucket = pchannel; |
| } |
| |
| DBGLOG(REQ, TRACE, "base_period=%d, num_buckets=%d, bucket0: %d %d %d %d", |
| prWifiScanCmd->base_period, prWifiScanCmd->num_buckets, |
| prWifiScanCmd->buckets[0].bucket, prWifiScanCmd->buckets[0].period, |
| prWifiScanCmd->buckets[0].band, prWifiScanCmd->buckets[0].report_events); |
| |
| DBGLOG(REQ, TRACE, "num_channels=%d, channel0=%d, channel1=%d; num_channels=%d, channel0=%d, channel1=%d", |
| prWifiScanCmd->buckets[0].num_channels, |
| prWifiScanCmd->buckets[0].channels[0].channel, prWifiScanCmd->buckets[0].channels[1].channel, |
| prWifiScanCmd->buckets[1].num_channels, |
| prWifiScanCmd->buckets[1].channels[0].channel, prWifiScanCmd->buckets[1].channels[1].channel); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetGSCNAParam, |
| prWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| |
| int mtk_cfg80211_vendor_set_scan_config(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| |
| PARAM_WIFI_GSCAN_CMD_PARAMS rWifiScanCmd; |
| struct nlattr *attr[GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1]; |
| int i, k; |
| static struct nla_policy policy[GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1] = { |
| [GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_REPORT_THRESHOLD] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE] = {.type = NLA_U32}, |
| }; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| |
| DBGLOG(SCN, INFO, "%s for vendor command: data_len=%d \r\n", __func__, data_len); |
| for (i = 0; i < 2; i++) |
| DBGLOG(SCN, INFO, "0x%x 0x%x 0x%x 0x%x \r\n", *((UINT_32 *) data + i * 4), |
| *((UINT_32 *) data + i * 4 + 1), *((UINT_32 *) data + i * 4 + 2), |
| *((UINT_32 *) data + i * 4 + 3)); |
| kalMemZero(&rWifiScanCmd, sizeof(rWifiScanCmd)); |
| kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE + 1)); |
| |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE, (struct nlattr *)(data - NLA_HDRLEN), policy); |
| for (k = GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN; k <= GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN: |
| rWifiScanCmd.max_ap_per_scan = nla_get_u32(attr[k]); |
| break; |
| case GSCAN_ATTRIBUTE_REPORT_THRESHOLD: |
| rWifiScanCmd.report_threshold = nla_get_u32(attr[k]); |
| break; |
| case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE: |
| rWifiScanCmd.num_scans = nla_get_u32(attr[k]); |
| break; |
| } |
| } |
| } |
| DBGLOG(REQ, TRACE, "attr=0x%x, attr2=0x%x", *(UINT_32 *)attr[GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN], |
| *(UINT_32 *)attr[GSCAN_ATTRIBUTE_REPORT_THRESHOLD]); |
| |
| DBGLOG(REQ, TRACE, "max_ap_per_scan=%d, report_threshold=%d num_scans=%d\r\n", |
| rWifiScanCmd.max_ap_per_scan, rWifiScanCmd.report_threshold, rWifiScanCmd.num_scans); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetGSCNAConfig, |
| &rWifiScanCmd, sizeof(PARAM_WIFI_GSCAN_CMD_PARAMS), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| |
| int mtk_cfg80211_vendor_set_significant_change(struct wiphy *wiphy, struct wireless_dev *wdev, |
| const void *data, int data_len) |
| { |
| PARAM_WIFI_SIGNIFICANT_CHANGE rWifiChangeCmd; |
| UINT_8 flush = 0; |
| struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; |
| struct nlattr *paplist; |
| int i, k; |
| UINT_32 len_basic, len_aplist; |
| static struct nla_policy policy[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1] = { |
| [GSCAN_ATTRIBUTE_BSSID] = {.type = NLA_UNSPEC}, |
| [GSCAN_ATTRIBUTE_RSSI_LOW] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_RSSI_HIGH] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE] = {.type = NLA_U16}, |
| [GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE] = {.type = NLA_U16}, |
| [GSCAN_ATTRIBUTE_MIN_BREACHING] = {.type = NLA_U16}, |
| [GSCAN_ATTRIBUTE_NUM_AP] = {.type = NLA_U16}, |
| [GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH] = {.type = NLA_U8}, |
| }; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d\r\n", __func__, data_len); |
| for (i = 0; i < 6; i++) |
| DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x\r\n", |
| *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), |
| *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); |
| kalMemZero(&rWifiChangeCmd, sizeof(rWifiChangeCmd)); |
| kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); |
| |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH, (struct nlattr *)(data - NLA_HDRLEN), policy); |
| len_basic = 0; |
| for (k = GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE; k <= GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE: |
| rWifiChangeCmd.rssi_sample_size = nla_get_u16(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: |
| rWifiChangeCmd.lost_ap_sample_size = nla_get_u16(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_MIN_BREACHING: |
| rWifiChangeCmd.min_breaching = nla_get_u16(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_NUM_AP: |
| rWifiChangeCmd.num_ap = nla_get_u16(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d\r\n", |
| *(UINT_32 *) attr[k], rWifiChangeCmd.num_ap, attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH: |
| flush = nla_get_u8(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| } |
| } |
| } |
| paplist = (struct nlattr *)((UINT_8 *) data + len_basic); |
| DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); |
| |
| if (paplist->nla_type == GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS) |
| paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); |
| |
| for (i = 0; i < rWifiChangeCmd.num_ap; i++) { |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, policy); |
| paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); |
| /* request.attr_start(i) as nested attribute */ |
| len_aplist = 0; |
| for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_BSSID: |
| kalMemCopy(rWifiChangeCmd.ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); |
| len_aplist += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_RSSI_LOW: |
| rWifiChangeCmd.ap[i].low = nla_get_u32(attr[k]); |
| len_aplist += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_RSSI_HIGH: |
| rWifiChangeCmd.ap[i].high = nla_get_u32(attr[k]); |
| len_aplist += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| } |
| } |
| } |
| if (((i + 1) % 4 == 0) || (i == rWifiChangeCmd.num_ap - 1)) |
| DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); |
| else |
| DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\t", i, len_aplist); |
| paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); |
| } |
| |
| DBGLOG(REQ, TRACE, |
| "flush=%d, rssi_sample_size=%d lost_ap_sample_size=%d min_breaching=%d", |
| flush, rWifiChangeCmd.rssi_sample_size, rWifiChangeCmd.lost_ap_sample_size, |
| rWifiChangeCmd.min_breaching); |
| DBGLOG(REQ, TRACE, |
| "ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", |
| rWifiChangeCmd.ap[0].channel, rWifiChangeCmd.ap[0].low, rWifiChangeCmd.ap[0].high, |
| rWifiChangeCmd.ap[1].channel, rWifiChangeCmd.ap[1].low, rWifiChangeCmd.ap[1].high); |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| |
| int mtk_cfg80211_vendor_set_hotlist(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| CMD_SET_PSCAN_ADD_HOTLIST_BSSID rCmdPscnAddHotlist; |
| |
| PARAM_WIFI_BSSID_HOTLIST rWifiHotlistCmd; |
| UINT_8 flush = 0; |
| struct nlattr *attr[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1]; |
| struct nlattr *paplist; |
| int i, k; |
| UINT_32 len_basic, len_aplist; |
| static struct nla_policy policy[GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1] = { |
| [GSCAN_ATTRIBUTE_BSSID] = {.type = NLA_UNSPEC}, |
| [GSCAN_ATTRIBUTE_RSSI_LOW] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_RSSI_HIGH] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE] = {.type = NLA_U32}, |
| [GSCAN_ATTRIBUTE_NUM_AP] = {.type = NLA_U16}, |
| [GSCAN_ATTRIBUTE_HOTLIST_FLUSH] = {.type = NLA_U8}, |
| }; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d\r\n", __func__, data_len); |
| for (i = 0; i < 5; i++) |
| DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x\r\n", |
| *((UINT_32 *) data + i * 4), *((UINT_32 *) data + i * 4 + 1), |
| *((UINT_32 *) data + i * 4 + 2), *((UINT_32 *) data + i * 4 + 3)); |
| kalMemZero(&rWifiHotlistCmd, sizeof(rWifiHotlistCmd)); |
| kalMemZero(attr, sizeof(struct nlattr *) * (GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH + 1)); |
| |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_NUM_AP, (struct nlattr *)(data - NLA_HDRLEN), policy); |
| len_basic = 0; |
| for (k = GSCAN_ATTRIBUTE_HOTLIST_FLUSH; k <= GSCAN_ATTRIBUTE_NUM_AP; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE: |
| rWifiHotlistCmd.lost_ap_sample_size = nla_get_u32(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_NUM_AP: |
| rWifiHotlistCmd.num_ap = nla_get_u16(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| DBGLOG(REQ, TRACE, "attr=0x%x, num_ap=%d nla_len=%d\r\n", |
| *(UINT_32 *) attr[k], rWifiHotlistCmd.num_ap, attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_HOTLIST_FLUSH: |
| flush = nla_get_u8(attr[k]); |
| len_basic += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| } |
| } |
| } |
| paplist = (struct nlattr *)((UINT_8 *) data + len_basic); |
| DBGLOG(REQ, TRACE, "+++basic attribute size=%d flush=%d\r\n", len_basic, flush); |
| |
| if (paplist->nla_type == GSCAN_ATTRIBUTE_HOTLIST_BSSIDS) |
| paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); |
| |
| for (i = 0; i < rWifiHotlistCmd.num_ap; i++) { |
| nla_parse_nested(attr, GSCAN_ATTRIBUTE_RSSI_HIGH, (struct nlattr *)paplist, policy); |
| paplist = (struct nlattr *)((UINT_8 *) paplist + NLA_HDRLEN); |
| /* request.attr_start(i) as nested attribute */ |
| len_aplist = 0; |
| for (k = GSCAN_ATTRIBUTE_BSSID; k <= GSCAN_ATTRIBUTE_RSSI_HIGH; k++) { |
| if (attr[k]) { |
| switch (k) { |
| case GSCAN_ATTRIBUTE_BSSID: |
| kalMemCopy(rWifiHotlistCmd.ap[i].bssid, nla_data(attr[k]), sizeof(mac_addr)); |
| len_aplist += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_RSSI_LOW: |
| rWifiHotlistCmd.ap[i].low = nla_get_u32(attr[k]); |
| len_aplist += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| case GSCAN_ATTRIBUTE_RSSI_HIGH: |
| rWifiHotlistCmd.ap[i].high = nla_get_u32(attr[k]); |
| len_aplist += NLA_ALIGN(attr[k]->nla_len); |
| break; |
| } |
| } |
| } |
| if (((i + 1) % 4 == 0) || (i == rWifiHotlistCmd.num_ap - 1)) |
| DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\n", i, len_aplist); |
| else |
| DBGLOG(REQ, TRACE, "ap[%d], len_aplist=%d\t", i, len_aplist); |
| paplist = (struct nlattr *)((UINT_8 *) paplist + len_aplist); |
| } |
| |
| DBGLOG(REQ, TRACE, |
| "flush=%d, lost_ap_sample_size=%d, Hotlist:ap[0].channel=%d low=%d high=%d, ap[1].channel=%d low=%d high=%d", |
| flush, rWifiHotlistCmd.lost_ap_sample_size, |
| rWifiHotlistCmd.ap[0].channel, rWifiHotlistCmd.ap[0].low, rWifiHotlistCmd.ap[0].high, |
| rWifiHotlistCmd.ap[1].channel, rWifiHotlistCmd.ap[1].low, rWifiHotlistCmd.ap[1].high); |
| |
| memcpy(&(rCmdPscnAddHotlist.aucMacAddr), &(rWifiHotlistCmd.ap[0].bssid), 6 * sizeof(UINT_8)); |
| rCmdPscnAddHotlist.ucFlags = (UINT_8) TRUE; |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| |
| int mtk_cfg80211_vendor_enable_scan(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS rWifiScanActionCmd; |
| |
| struct nlattr *attr; |
| UINT_8 gGScanEn = 0; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", |
| __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); |
| |
| attr = (struct nlattr *)data; |
| if (attr->nla_type == GSCAN_ATTRIBUTE_ENABLE_FEATURE) |
| gGScanEn = nla_get_u32(attr); |
| DBGLOG(REQ, INFO, "gGScanEn=%d\r\n", gGScanEn); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| if (gGScanEn == TRUE) |
| rWifiScanActionCmd.ucPscanAct = ENABLE; |
| else |
| rWifiScanActionCmd.ucPscanAct = DISABLE; |
| |
| rStatus = kalIoctl(prGlueInfo, |
| wlanoidSetGSCNAction, |
| &rWifiScanActionCmd, |
| sizeof(PARAM_WIFI_GSCAN_ACTION_CMD_PARAMS), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| /* mtk_cfg80211_vendor_get_scan_results(wiphy, wdev, data, data_len ); */ |
| |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| |
| int mtk_cfg80211_vendor_enable_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, |
| const void *data, int data_len) |
| { |
| struct nlattr *attr; |
| UINT_8 gFullScanResultsEn = 0; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| DBGLOG(REQ, INFO, "%s for vendor command: data_len=%d, data=0x%x 0x%x\r\n", |
| __func__, data_len, *((UINT_32 *) data), *((UINT_32 *) data + 1)); |
| |
| attr = (struct nlattr *)data; |
| if (attr->nla_type == GSCAN_ENABLE_FULL_SCAN_RESULTS) |
| gFullScanResultsEn = nla_get_u32(attr); |
| DBGLOG(REQ, INFO, "gFullScanResultsEn=%d, \r\n", gFullScanResultsEn); |
| |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| |
| int mtk_cfg80211_vendor_get_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| UINT_32 u4BufLen; |
| P_GLUE_INFO_T prGlueInfo = NULL; |
| PARAM_WIFI_GSCAN_GET_RESULT_PARAMS rGSscnResultParm; |
| |
| struct nlattr *attr; |
| UINT_32 get_num, real_num; |
| UINT_8 flush = 0; |
| int i; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| get_num = 0; |
| real_num = 0; |
| if ((data == NULL) || !data_len) |
| goto nla_put_failure; |
| DBGLOG(REQ, TRACE, "%s for vendor command: data_len=%d\r\n", __func__, data_len); |
| for (i = 0; i < 2; i++) |
| DBGLOG(REQ, LOUD, "0x%x 0x%x 0x%x 0x%x\r\n", *((UINT_32 *) data + i * 4), |
| *((UINT_32 *) data + i * 4 + 1), *((UINT_32 *) data + i * 4 + 2), |
| *((UINT_32 *) data + i * 4 + 3)); |
| |
| attr = (struct nlattr *)data; |
| if (attr->nla_type == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) { |
| get_num = nla_get_u32(attr); |
| attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); |
| } |
| if (attr->nla_type == GSCAN_ATTRIBUTE_FLUSH_RESULTS) { |
| flush = nla_get_u8(attr); |
| attr = (struct nlattr *)((UINT_8 *) attr + attr->nla_len); |
| } |
| DBGLOG(REQ, TRACE, "number=%d, flush=%d\r\n", get_num, flush); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| ASSERT(prGlueInfo); |
| |
| real_num = (get_num < PSCAN_MAX_SCAN_CACHE_SIZE) ? get_num : PSCAN_MAX_SCAN_CACHE_SIZE; |
| get_num = real_num; |
| |
| rGSscnResultParm.get_num = get_num; |
| rGSscnResultParm.flush = flush; |
| |
| kalIoctl(prGlueInfo, |
| wlanoidGetGSCNResult, |
| &rGSscnResultParm, sizeof(PARAM_WIFI_GSCAN_GET_RESULT_PARAMS), FALSE, FALSE, TRUE, &u4BufLen); |
| |
| scnGscnGetResultReplyCheck(prGlueInfo->prAdapter); |
| |
| return 0; |
| |
| nla_put_failure: |
| return -1; |
| } |
| #endif |
| int mtk_cfg80211_vendor_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| P_GLUE_INFO_T prGlueInfo; |
| struct nlattr *attr; |
| UINT_32 band = 0; |
| UINT_8 ucNumOfChannel, i, j; |
| RF_CHANNEL_INFO_T aucChannelList[MAX_CHN_NUM]; |
| UINT_32 num_channels; |
| wifi_channel channels[MAX_CHN_NUM]; |
| struct sk_buff *skb; |
| |
| ASSERT(wiphy && wdev); |
| if ((data == NULL) || !data_len) |
| return -EINVAL; |
| |
| DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); |
| |
| attr = (struct nlattr *)data; |
| if (attr->nla_type == WIFI_ATTRIBUTE_BAND) |
| band = nla_get_u32(attr); |
| |
| DBGLOG(REQ, INFO, "Get channel list for band: %d\n", band); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| if (!prGlueInfo) |
| return -EFAULT; |
| |
| if (band == 0) { /* 2.4G band */ |
| rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, TRUE, |
| MAX_CHN_NUM, &ucNumOfChannel, aucChannelList); |
| } else { /* 5G band */ |
| rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_5G, TRUE, |
| MAX_CHN_NUM, &ucNumOfChannel, aucChannelList); |
| } |
| |
| kalMemZero(channels, sizeof(channels)); |
| for (i = 0, j = 0; i < ucNumOfChannel; i++) { |
| /* We need to report frequency list to HAL */ |
| channels[j] = nicChannelNum2Freq(aucChannelList[i].ucChannelNum) / 1000; |
| if (channels[j] == 0) |
| continue; |
| else if ((prGlueInfo->prAdapter->rWifiVar.rConnSettings.u2CountryCode == COUNTRY_CODE_TW) && |
| (channels[j] >= 5180 && channels[j] <= 5260)) { |
| /* Taiwan NCC has resolution to follow FCC spec to support 5G Band 1/2/3/4 |
| * (CH36~CH48, CH52~CH64, CH100~CH140, CH149~CH165) |
| * Filter CH36~CH52 for compatible with some old devices. |
| */ |
| continue; |
| } else { |
| DBGLOG(REQ, INFO, "channels[%d] = %d\n", j, channels[j]); |
| j++; |
| } |
| } |
| num_channels = j; |
| |
| skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(channels)); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "Allocate skb failed\n"); |
| return -ENOMEM; |
| } |
| |
| if (unlikely(nla_put_u32(skb, WIFI_ATTRIBUTE_NUM_CHANNELS, num_channels) < 0)) |
| goto nla_put_failure; |
| |
| if (unlikely(nla_put(skb, WIFI_ATTRIBUTE_CHANNEL_LIST, |
| (sizeof(wifi_channel) * num_channels), channels) < 0)) |
| goto nla_put_failure; |
| |
| return cfg80211_vendor_cmd_reply(skb); |
| |
| nla_put_failure: |
| kfree_skb(skb); |
| return -EFAULT; |
| } |
| |
| |
| |
| int mtk_cfg80211_vendor_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| P_GLUE_INFO_T prGlueInfo; |
| WLAN_STATUS rStatus; |
| UINT_32 u4BufLen; |
| struct nlattr *attr; |
| UINT_8 country[2]; |
| |
| ASSERT(wiphy && wdev); |
| if ((data == NULL) || (data_len == 0)) |
| return -EINVAL; |
| |
| DBGLOG(REQ, INFO, "vendor command: data_len=%d\n", data_len); |
| |
| attr = (struct nlattr *)data; |
| if (attr->nla_type == WIFI_ATTRIBUTE_COUNTRY_CODE) { |
| country[0] = *((PUINT_8)nla_data(attr)); |
| country[1] = *((PUINT_8)nla_data(attr) + 1); |
| } |
| |
| DBGLOG(REQ, INFO, "Set country code: %c%c\n", country[0], country[1]); |
| |
| prGlueInfo = (P_GLUE_INFO_T) wiphy_priv(wiphy); |
| if (!prGlueInfo) |
| return -EFAULT; |
| |
| rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, country, 2, FALSE, FALSE, TRUE, &u4BufLen); |
| if (rStatus != WLAN_STATUS_SUCCESS) { |
| DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); |
| return -EFAULT; |
| } |
| |
| return 0; |
| } |
| |
| |
| #if 0 |
| int mtk_cfg80211_vendor_llstats_get_info(struct wiphy *wiphy, struct wireless_dev *wdev, const void *data, int data_len) |
| { |
| INT_32 i4Status = -EINVAL; |
| WIFI_RADIO_STAT *pRadioStat; |
| struct sk_buff *skb; |
| UINT_32 u4BufLen; |
| |
| DBGLOG(REQ, INFO, "%s for vendor command\r\n", __func__); |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| |
| u4BufLen = sizeof(WIFI_RADIO_STAT) + sizeof(WIFI_IFACE_STAT); |
| pRadioStat = kalMemAlloc(u4BufLen, VIR_MEM_TYPE); |
| if (!pRadioStat) { |
| DBGLOG(REQ, ERROR, "%s kalMemAlloc pRadioStat failed\n", __func__); |
| return -ENOMEM; |
| } |
| kalMemZero(pRadioStat, u4BufLen); |
| |
| skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, u4BufLen); |
| if (!skb) { |
| DBGLOG(REQ, TRACE, "%s allocate skb failed:%x\n", __func__, i4Status); |
| return -ENOMEM; |
| } |
| |
| /*rStatus = kalIoctl(prGlueInfo, |
| * wlanoidQueryStatistics, |
| * &rRadioStat, |
| * sizeof(rRadioStat), |
| * TRUE, |
| * TRUE, |
| * TRUE, |
| * FALSE, |
| * &u4BufLen); |
| */ |
| /* only for test */ |
| pRadioStat->radio = 10; |
| pRadioStat->on_time = 11; |
| pRadioStat->tx_time = 12; |
| pRadioStat->num_channels = 4; |
| |
| NLA_PUT(skb, NL80211_ATTR_VENDOR_LLSTAT, u4BufLen, pRadioStat); |
| |
| i4Status = cfg80211_vendor_cmd_reply(skb); |
| |
| kalMemFree(pRadioStat, VIR_MEM_TYPE, u4BufLen); |
| |
| return i4Status; |
| } |
| |
| int mtk_cfg80211_vendor_event_complete_scan(struct wiphy *wiphy, struct wireless_dev *wdev, WIFI_SCAN_EVENT complete) |
| { |
| struct sk_buff *skb; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| /* WIFI_SCAN_EVENT complete_scan; */ |
| |
| DBGLOG(REQ, INFO, "%s for vendor command\r\n", __func__); |
| |
| skb = cfg80211_vendor_event_alloc(wiphy, sizeof(complete), GSCAN_EVENT_COMPLETE_SCAN, GFP_KERNEL); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); |
| return -ENOMEM; |
| } |
| /* complete_scan = WIFI_SCAN_COMPLETE; */ |
| if (!NLA_PUT_U32(skb, GSCAN_EVENT_COMPLETE_SCAN, &complete)) |
| return -1; |
| |
| cfg80211_vendor_event(skb, GFP_KERNEL); |
| return 0; |
| |
| } |
| |
| int mtk_cfg80211_vendor_event_scan_results_available(struct wiphy *wiphy, struct wireless_dev *wdev, UINT_32 num) |
| { |
| struct sk_buff *skb; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| /* UINT_32 scan_result; */ |
| |
| DBGLOG(REQ, INFO, "%s for vendor command %d\r\n", __func__, num); |
| |
| skb = cfg80211_vendor_event_alloc(wiphy, sizeof(num), GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, GFP_KERNEL); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); |
| return -ENOMEM; |
| } |
| /* scan_result = 2; */ |
| if (!NLA_PUT_U32(skb, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE, &num)) |
| return -1; |
| |
| cfg80211_vendor_event(skb, GFP_KERNEL); |
| DBGLOG(SCN, INFO, "%s for vendor command done\r\n", __func__); |
| return 0; |
| |
| } |
| |
| int mtk_cfg80211_vendor_event_full_scan_results(struct wiphy *wiphy, struct wireless_dev *wdev, |
| P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) |
| { |
| PARAM_WIFI_GSCAN_RESULT result; |
| struct sk_buff *skb; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| DBGLOG(REQ, INFO, "%s for vendor command\r\n", __func__); |
| |
| skb = cfg80211_vendor_event_alloc(wiphy, sizeof(result), GSCAN_EVENT_FULL_SCAN_RESULTS, GFP_KERNEL); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); |
| return -ENOMEM; |
| } |
| |
| kalMemZero(&result, sizeof(result)); |
| kalMemCopy(result.ssid, "Gscan_full_test", sizeof("Gscan_full_test")); |
| result.channel = 2437; |
| |
| /* kalMemCopy(&result, pdata, sizeof(PARAM_WIFI_GSCAN_RESULT); */ |
| if (!NLA_PUT(skb, GSCAN_EVENT_FULL_SCAN_RESULTS, sizeof(result), &result)) |
| return -1; |
| |
| cfg80211_vendor_event(skb, GFP_KERNEL); |
| return 0; |
| |
| } |
| |
| int mtk_cfg80211_vendor_event_significant_change_results(struct wiphy *wiphy, |
| struct wireless_dev *wdev, |
| P_PARAM_WIFI_CHANGE_RESULT pdata, UINT_32 data_len) |
| { |
| struct sk_buff *skb; |
| PARAM_WIFI_CHANGE_RESULT result[2], *presult; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| DBGLOG(REQ, INFO, "%s for vendor command\r\n", __func__); |
| |
| skb = cfg80211_vendor_event_alloc(wiphy, sizeof(PARAM_WIFI_CHANGE_RESULT), |
| GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS, GFP_KERNEL); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); |
| return -ENOMEM; |
| } |
| |
| presult = result; |
| kalMemZero(presult, (sizeof(PARAM_WIFI_CHANGE_RESULT) * 2)); |
| cfg80211_vendor_event(skb, GFP_KERNEL); |
| return 0; |
| |
| } |
| |
| int mtk_cfg80211_vendor_event_hotlist_ap_found(struct wiphy *wiphy, struct wireless_dev *wdev, |
| P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) |
| { |
| struct sk_buff *skb; |
| PARAM_WIFI_GSCAN_RESULT result[2], *presult; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| DBGLOG(REQ, INFO, "%s for vendor command\r\n", __func__); |
| |
| skb = cfg80211_vendor_event_alloc(wiphy, sizeof(PARAM_WIFI_GSCAN_RESULT), |
| GSCAN_EVENT_HOTLIST_RESULTS_FOUND, GFP_KERNEL); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); |
| return -ENOMEM; |
| } |
| |
| presult = result; |
| kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); |
| cfg80211_vendor_event(skb, GFP_KERNEL); |
| return 0; |
| |
| } |
| |
| int mtk_cfg80211_vendor_event_hotlist_ap_lost(struct wiphy *wiphy, struct wireless_dev *wdev, |
| P_PARAM_WIFI_GSCAN_RESULT pdata, UINT_32 data_len) |
| { |
| struct sk_buff *skb; |
| PARAM_WIFI_GSCAN_RESULT result[2], *presult; |
| |
| ASSERT(wiphy); |
| ASSERT(wdev); |
| DBGLOG(REQ, INFO, "%s for vendor command\r\n", __func__); |
| |
| skb = cfg80211_vendor_event_alloc(wiphy, sizeof(PARAM_WIFI_GSCAN_RESULT), |
| GSCAN_EVENT_HOTLIST_RESULTS_LOST, GFP_KERNEL); |
| if (!skb) { |
| DBGLOG(REQ, ERROR, "%s allocate skb failed\n", __func__); |
| return -ENOMEM; |
| } |
| |
| presult = result; |
| kalMemZero(presult, (sizeof(PARAM_WIFI_GSCAN_RESULT) * 2)); |
| cfg80211_vendor_event(skb, GFP_KERNEL); |
| return 0; |
| } |
| |
| #endif |
| #endif |
| |