blob: c021b55892b8a121684baaedde130b1c56b54cce [file] [log] [blame]
/******************************************************************************
*
* 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.
*
*****************************************************************************/
/*
** Id: @(#) gl_p2p.c@@
*/
/*! \file gl_p2p.c
* \brief Main routines of Linux driver interface for Wi-Fi Direct
*
* This file contains the main routines of Linux driver for MediaTek Inc. 802.11
* Wireless LAN Adapters.
*/
/*******************************************************************************
* 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 <linux/poll.h>
#include <linux/kmod.h>
#include "gl_os.h"
#include "debug.h"
#include "wlan_lib.h"
#include "gl_wext.h"
/* #include <net/cfg80211.h> */
#include "gl_p2p_ioctl.h"
#include "precomp.h"
#include "gl_vendor.h"
#include "gl_cfg80211.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
#define ARGV_MAX_NUM (4)
/*For CFG80211 - wiphy parameters*/
#define MAX_SCAN_LIST_NUM (1)
#define MAX_SCAN_IE_LEN (512)
#if 0
#define RUNNING_P2P_MODE 0
#define RUNNING_AP_MODE 1
#define RUNNING_DUAL_AP_MODE 2
#endif
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
struct net_device *g_P2pPrDev;
struct wireless_dev *gprP2pWdev;
struct wireless_dev *gprP2pRoleWdev[KAL_P2P_NUM];
struct net_device *gPrP2pDev[KAL_P2P_NUM];
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
static struct cfg80211_ops mtk_p2p_ops = {
#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0)
/* Froyo */
.add_virtual_intf = mtk_p2p_cfg80211_add_iface,
.change_virtual_intf = mtk_p2p_cfg80211_change_iface, /* 1 st */
.del_virtual_intf = mtk_p2p_cfg80211_del_iface,
.change_bss = mtk_p2p_cfg80211_change_bss,
.scan = mtk_p2p_cfg80211_scan,
.remain_on_channel = mtk_p2p_cfg80211_remain_on_channel,
.cancel_remain_on_channel = mtk_p2p_cfg80211_cancel_remain_on_channel,
.mgmt_tx = mtk_p2p_cfg80211_mgmt_tx,
.mgmt_tx_cancel_wait = mtk_p2p_cfg80211_mgmt_tx_cancel_wait,
.connect = mtk_p2p_cfg80211_connect,
.disconnect = mtk_p2p_cfg80211_disconnect,
.deauth = mtk_p2p_cfg80211_deauth,
.disassoc = mtk_p2p_cfg80211_disassoc,
.start_ap = mtk_p2p_cfg80211_start_ap,
.change_beacon = mtk_p2p_cfg80211_change_beacon,
.stop_ap = mtk_p2p_cfg80211_stop_ap,
.set_wiphy_params = mtk_p2p_cfg80211_set_wiphy_params,
.del_station = mtk_p2p_cfg80211_del_station,
.set_bitrate_mask = mtk_p2p_cfg80211_set_bitrate_mask,
.mgmt_frame_register = mtk_p2p_cfg80211_mgmt_frame_register,
.get_station = mtk_p2p_cfg80211_get_station,
.add_key = mtk_p2p_cfg80211_add_key,
.get_key = mtk_p2p_cfg80211_get_key,
.del_key = mtk_p2p_cfg80211_del_key,
.set_default_key = mtk_p2p_cfg80211_set_default_key,
.set_default_mgmt_key = mtk_p2p_cfg80211_set_mgmt_key,
.join_ibss = mtk_p2p_cfg80211_join_ibss,
.leave_ibss = mtk_p2p_cfg80211_leave_ibss,
.set_tx_power = mtk_p2p_cfg80211_set_txpower,
.get_tx_power = mtk_p2p_cfg80211_get_txpower,
.set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt,
#if (CFG_SUPPORT_DFS_MASTER == 1)
.start_radar_detection = mtk_p2p_cfg80211_start_radar_detection,
#if KERNEL_VERSION(3, 13, 0) <= CFG80211_VERSION_CODE
.channel_switch = mtk_p2p_cfg80211_channel_switch,
#endif
#endif
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = mtk_p2p_cfg80211_testmode_cmd,
#endif
#endif
};
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
static const struct wiphy_vendor_command mtk_p2p_vendor_ops[] = {
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_GET_CHANNEL_LIST
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_get_channel_list
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = mtk_cfg80211_vendor_set_country_code
},
};
#endif
/* There isn't a lot of sense in it, but you can transmit anything you like */
static const struct ieee80211_txrx_stypes
mtk_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_PROBE_REQ >> 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_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ACTION >> 4)
}
};
#endif
static const struct iw_priv_args rP2PIwPrivTable[] = {
#if 0
{
.cmd = IOC_P2P_CFG_DEVICE,
.set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CFG_DEVICE_TYPE),
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_CFG_DEVICE"}
,
{
.cmd = IOC_P2P_START_STOP_DISCOVERY,
.set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_REQ_DEVICE_TYPE),
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_DISCOVERY"}
,
{
.cmd = IOC_P2P_DISCOVERY_RESULTS,
.set_args = IW_PRIV_TYPE_NONE,
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_RESULT"}
,
{
.cmd = IOC_P2P_WSC_BEACON_PROBE_RSP_IE,
.set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_HOSTAPD_PARAM),
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_WSC_IE"}
,
{
.cmd = IOC_P2P_CONNECT_DISCONNECT,
.set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_CONNECT_DEVICE),
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_CONNECT"}
,
{
.cmd = IOC_P2P_PASSWORD_READY,
.set_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_PASSWORD_READY),
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_PASSWD_RDY"}
,
{
.cmd = IOC_P2P_GET_STRUCT,
.set_args = IW_PRIV_TYPE_NONE,
.get_args = 256,
.name = "P2P_GET_STRUCT"}
,
{
.cmd = IOC_P2P_SET_STRUCT,
.set_args = 256,
.get_args = IW_PRIV_TYPE_NONE,
.name = "P2P_SET_STRUCT"}
,
{
.cmd = IOC_P2P_GET_REQ_DEVICE_INFO,
.set_args = IW_PRIV_TYPE_NONE,
.get_args = IW_PRIV_TYPE_BYTE | (__u16) sizeof(IW_P2P_DEVICE_REQ),
.name = "P2P_GET_REQDEV"}
,
{
/* SET STRUCT sub-ioctls commands */
.cmd = PRIV_CMD_OID,
.set_args = 256,
.get_args = IW_PRIV_TYPE_NONE,
.name = "set_oid"}
,
{
/* GET STRUCT sub-ioctls commands */
.cmd = PRIV_CMD_OID,
.set_args = IW_PRIV_TYPE_NONE,
.get_args = 256,
.name = "get_oid"}
,
#endif
{IOCTL_GET_DRIVER, IW_PRIV_TYPE_CHAR | 2000, IW_PRIV_TYPE_CHAR | 2000, "driver"},
};
#if 0
const struct iw_handler_def mtk_p2p_wext_handler_def = {
.num_standard = (__u16) sizeof(rP2PIwStandardHandler) / sizeof(iw_handler),
/* .num_private = (__u16)sizeof(rP2PIwPrivHandler)/sizeof(iw_handler), */
.num_private_args = (__u16) sizeof(rP2PIwPrivTable) / sizeof(struct iw_priv_args),
.standard = rP2PIwStandardHandler,
/* .private = rP2PIwPrivHandler, */
.private_args = rP2PIwPrivTable,
#if CFG_SUPPORT_P2P_RSSI_QUERY
.get_wireless_stats = mtk_p2p_wext_get_wireless_stats,
#else
.get_wireless_stats = NULL,
#endif
};
#endif
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support mtk_p2p_wowlan_support = {
.flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY,
};
#endif
static const struct ieee80211_iface_limit mtk_p2p_sta_go_limits[] = {
{
.max = 3,
.types = BIT(NL80211_IFTYPE_STATION),
},
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
},
};
#if ((CFG_SUPPORT_DFS_MASTER == 1) && (KERNEL_VERSION(3, 17, 0) > CFG80211_VERSION_CODE))
static const struct ieee80211_iface_limit mtk_ap_limits[] = {
{
.max = 1,
.types = BIT(NL80211_IFTYPE_AP),
},
};
#endif
static const struct ieee80211_iface_combination
mtk_iface_combinations_sta[] = {
{
#ifdef CFG_NUM_DIFFERENT_CHANNELS_STA
.num_different_channels = CFG_NUM_DIFFERENT_CHANNELS_STA,
#else
.num_different_channels = 2,
#endif /* CFG_NUM_DIFFERENT_CHANNELS_STA */
.max_interfaces = 3,
/*.beacon_int_infra_match = true,*/
.limits = mtk_p2p_sta_go_limits,
.n_limits = 1, /* include p2p */
},
};
static const struct ieee80211_iface_combination
mtk_iface_combinations_p2p[] = {
{
#ifdef CFG_NUM_DIFFERENT_CHANNELS_P2P
.num_different_channels = CFG_NUM_DIFFERENT_CHANNELS_P2P,
#else
.num_different_channels = 2,
#endif /* CFG_NUM_DIFFERENT_CHANNELS_P2P */
.max_interfaces = 3,
/*.beacon_int_infra_match = true,*/
.limits = mtk_p2p_sta_go_limits,
.n_limits = ARRAY_SIZE(mtk_p2p_sta_go_limits), /* include p2p */
},
#if ((CFG_SUPPORT_DFS_MASTER == 1) && (KERNEL_VERSION(3, 17, 0) > CFG80211_VERSION_CODE))
/* ONLY for passing checks in cfg80211_can_use_iftype_chan before linux-3.17.0 */
{
.num_different_channels = 1,
.max_interfaces = 1,
.limits = mtk_ap_limits,
.n_limits = ARRAY_SIZE(mtk_ap_limits),
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_80P80),
},
#endif
};
const struct ieee80211_iface_combination *p_mtk_iface_combinations_sta = mtk_iface_combinations_sta;
const INT_32 mtk_iface_combinations_sta_num = ARRAY_SIZE(mtk_iface_combinations_sta);
const struct ieee80211_iface_combination *p_mtk_iface_combinations_p2p = mtk_iface_combinations_p2p;
const INT_32 mtk_iface_combinations_p2p_num = ARRAY_SIZE(mtk_iface_combinations_p2p);
/*******************************************************************************
* 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
********************************************************************************
*/
/* Net Device Hooks */
static int p2pOpen(IN struct net_device *prDev);
static int p2pStop(IN struct net_device *prDev);
static struct net_device_stats *p2pGetStats(IN struct net_device *prDev);
static void p2pSetMulticastList(IN struct net_device *prDev);
static int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev);
static int p2pSetMACAddress(IN struct net_device *prDev, void *addr);
static int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIFReq, int i4Cmd);
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->init
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution of wlanInit succeeds.
* \retval -ENXIO No such device.
*/
/*----------------------------------------------------------------------------*/
static int p2pInit(struct net_device *prDev)
{
if (!prDev)
return -ENXIO;
return 0; /* success */
} /* end of p2pInit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for prDev->uninit
*
* \param[in] prDev Pointer to struct net_device.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
static void p2pUninit(IN struct net_device *prDev)
{
} /* end of p2pUninit() */
const struct net_device_ops p2p_netdev_ops = {
.ndo_open = p2pOpen,
.ndo_stop = p2pStop,
.ndo_set_mac_address = p2pSetMACAddress,
.ndo_set_rx_mode = p2pSetMulticastList,
.ndo_get_stats = p2pGetStats,
.ndo_do_ioctl = p2pDoIOCTL,
.ndo_start_xmit = p2pHardStartXmit,
/* .ndo_select_queue = p2pSelectQueue, */
.ndo_select_queue = wlanSelectQueue,
.ndo_init = p2pInit,
.ndo_uninit = p2pUninit,
};
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* \brief Allocate memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS
* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO
*
* \param[in] prGlueInfo Pointer to glue info
*
* \return TRUE
* FALSE
*/
/*----------------------------------------------------------------------------*/
BOOLEAN p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo, IN UINT_8 ucIdex)
{
P_ADAPTER_T prAdapter = NULL;
P_WIFI_VAR_T prWifiVar = NULL;
/* UINT_32 u4Idx = 0; */
ASSERT(prGlueInfo);
if (!prGlueInfo) {
DBGLOG(P2P, ERROR, "prGlueInfo error\n");
return FALSE;
}
prAdapter = prGlueInfo->prAdapter;
prWifiVar = &(prAdapter->rWifiVar);
ASSERT(prAdapter);
ASSERT(prWifiVar);
do {
if (prGlueInfo->prP2PInfo[ucIdex] == NULL) {
/*alloc memory for p2p info */
prGlueInfo->prP2PInfo[ucIdex] = kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE);
if (ucIdex == 0) {
/*printk("[CHECK!]p2PAllocInfo : Alloc Common part only first interface\n");*/
prGlueInfo->prP2PDevInfo = kalMemAlloc(sizeof(GL_P2P_DEV_INFO_T), VIR_MEM_TYPE);
prAdapter->prP2pInfo = kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE);
prWifiVar->prP2pDevFsmInfo = kalMemAlloc(sizeof(P2P_DEV_FSM_INFO_T), VIR_MEM_TYPE);
}
prWifiVar->prP2PConnSettings[ucIdex] =
kalMemAlloc(sizeof(P2P_CONNECTION_SETTINGS_T), VIR_MEM_TYPE);
prWifiVar->prP2pSpecificBssInfo[ucIdex] =
kalMemAlloc(sizeof(P2P_SPECIFIC_BSS_INFO_T), VIR_MEM_TYPE);
/* TODO: It can be moved to the interface been created. */
#if 0
for (u4Idx = 0; u4Idx < BSS_P2P_NUM; u4Idx++) {
prWifiVar->aprP2pRoleFsmInfo[u4Idx] =
kalMemAlloc(sizeof(P2P_ROLE_FSM_INFO_T), VIR_MEM_TYPE);
}
#endif
} else {
ASSERT(prAdapter->prP2pInfo != NULL);
ASSERT(prWifiVar->prP2PConnSettings[ucIdex] != NULL);
/* ASSERT(prWifiVar->prP2pFsmInfo != NULL); */
ASSERT(prWifiVar->prP2pSpecificBssInfo[ucIdex] != NULL);
}
/*MUST set memory to 0 */
kalMemZero(prGlueInfo->prP2PInfo[ucIdex], sizeof(GL_P2P_INFO_T));
if (ucIdex == 0) {
kalMemZero(prGlueInfo->prP2PDevInfo, sizeof(GL_P2P_DEV_INFO_T));
kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T));
kalMemZero(prWifiVar->prP2pDevFsmInfo, sizeof(P2P_DEV_FSM_INFO_T));
}
kalMemZero(prWifiVar->prP2PConnSettings[ucIdex], sizeof(P2P_CONNECTION_SETTINGS_T));
/* kalMemZero(prWifiVar->prP2pFsmInfo, sizeof(P2P_FSM_INFO_T)); */
kalMemZero(prWifiVar->prP2pSpecificBssInfo[ucIdex], sizeof(P2P_SPECIFIC_BSS_INFO_T));
} while (FALSE);
if (!prGlueInfo->prP2PDevInfo)
DBGLOG(P2P, ERROR, "prP2PDevInfo error\n");
else
DBGLOG(P2P, INFO, "prP2PDevInfo ok\n");
if (!prGlueInfo->prP2PInfo[ucIdex])
DBGLOG(P2P, ERROR, "prP2PInfo error\n");
else
DBGLOG(P2P, INFO, "prP2PInfo ok\n");
/* chk if alloc successful or not */
if (prGlueInfo->prP2PInfo[ucIdex] && prGlueInfo->prP2PDevInfo && prAdapter->prP2pInfo &&
prWifiVar->prP2PConnSettings[ucIdex] &&
/* prWifiVar->prP2pFsmInfo && */
prWifiVar->prP2pSpecificBssInfo[ucIdex])
return TRUE;
DBGLOG(P2P, ERROR, "[fail!]p2PAllocInfo :fail\n");
if (prWifiVar->prP2pSpecificBssInfo[ucIdex]) {
kalMemFree(prWifiVar->prP2pSpecificBssInfo[ucIdex], VIR_MEM_TYPE, sizeof(P2P_SPECIFIC_BSS_INFO_T));
prWifiVar->prP2pSpecificBssInfo[ucIdex] = NULL;
}
/* if (prWifiVar->prP2pFsmInfo) { */
/* kalMemFree(prWifiVar->prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); */
/* prWifiVar->prP2pFsmInfo = NULL; */
/* } */
if (prWifiVar->prP2PConnSettings[ucIdex]) {
kalMemFree(prWifiVar->prP2PConnSettings[ucIdex], VIR_MEM_TYPE, sizeof(P2P_CONNECTION_SETTINGS_T));
prWifiVar->prP2PConnSettings[ucIdex] = NULL;
}
if (prGlueInfo->prP2PDevInfo) {
kalMemFree(prGlueInfo->prP2PDevInfo, VIR_MEM_TYPE, sizeof(GL_P2P_DEV_INFO_T));
prGlueInfo->prP2PDevInfo = NULL;
}
if (prGlueInfo->prP2PInfo[ucIdex]) {
kalMemFree(prGlueInfo->prP2PInfo[ucIdex], VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T));
prGlueInfo->prP2PInfo[ucIdex] = NULL;
}
if (prAdapter->prP2pInfo) {
kalMemFree(prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T));
prAdapter->prP2pInfo = NULL;
}
return FALSE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Free memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS
* P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO
*
* \param[in] prGlueInfo Pointer to glue info
*
* \return TRUE
* FALSE
*/
/*----------------------------------------------------------------------------*/
BOOLEAN p2PFreeInfo(P_GLUE_INFO_T prGlueInfo)
{
UINT_8 i;
ASSERT(prGlueInfo);
ASSERT(prGlueInfo->prAdapter);
/* free memory after p2p module is ALREADY unregistered */
if (prGlueInfo->prAdapter->fgIsP2PRegistered == FALSE) {
kalMemFree(prGlueInfo->prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T));
for (i = 0; i < KAL_P2P_NUM; i++)
if (prGlueInfo->prP2PInfo[i] != NULL) {
kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings[i], VIR_MEM_TYPE,
sizeof(P2P_CONNECTION_SETTINGS_T));
prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings[i] = NULL;
kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo[i], VIR_MEM_TYPE,
sizeof(P2P_SPECIFIC_BSS_INFO_T));
prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo[i] = NULL;
}
kalMemFree(prGlueInfo->prP2PDevInfo, VIR_MEM_TYPE, sizeof(GL_P2P_DEV_INFO_T));
for (i = 0; i < KAL_P2P_NUM; i++) {
if (prGlueInfo->prP2PInfo[i] != NULL) {
kalMemFree(prGlueInfo->prP2PInfo[i], VIR_MEM_TYPE, sizeof(GL_P2P_INFO_T));
prGlueInfo->prP2PInfo[i] = NULL;
}
}
/* kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo, VIR_MEM_TYPE, sizeof(P2P_FSM_INFO_T)); */
kalMemFree(prGlueInfo->prAdapter->rWifiVar.prP2pDevFsmInfo, VIR_MEM_TYPE, sizeof(P2P_DEV_FSM_INFO_T));
/*Reomve p2p bss scan list */
scanRemoveAllP2pBssDesc(prGlueInfo->prAdapter);
/*reset all pointer to NULL */
/*prGlueInfo->prP2PInfo[0] = NULL;*/
prGlueInfo->prAdapter->prP2pInfo = NULL;
/* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo = NULL; */
prGlueInfo->prAdapter->rWifiVar.prP2pDevFsmInfo = NULL;
return TRUE;
} else {
return FALSE;
}
}
BOOLEAN p2pNetRegister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired)
{
BOOLEAN fgDoRegister = FALSE;
BOOLEAN fgRollbackRtnlLock = FALSE;
BOOLEAN ret;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(prGlueInfo);
ASSERT(prGlueInfo->prAdapter);
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_UNREGISTERED) {
prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERING;
fgDoRegister = TRUE;
}
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (!fgDoRegister)
return TRUE;
if (fgIsRtnlLockAcquired && rtnl_is_locked()) {
fgRollbackRtnlLock = TRUE;
rtnl_unlock();
}
/* net device initialize */
netif_carrier_off(prGlueInfo->prP2PInfo[0]->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->prDevHandler);
/* register for net device */
if (register_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler) < 0) {
DBGLOG(INIT, WARN, "unable to register netdevice for p2p\n");
free_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler);
ret = FALSE;
} else {
prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED;
gPrP2pDev[0] = prGlueInfo->prP2PInfo[0]->prDevHandler;
ret = TRUE;
}
if (prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum == RUNNING_DUAL_AP_MODE) {
/* net device initialize */
netif_carrier_off(prGlueInfo->prP2PInfo[1]->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[1]->prDevHandler);
/* register for net device */
if (register_netdev(prGlueInfo->prP2PInfo[1]->prDevHandler) < 0) {
DBGLOG(INIT, WARN, "unable to register netdevice for p2p\n");
free_netdev(prGlueInfo->prP2PInfo[1]->prDevHandler);
ret = FALSE;
} else {
prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED;
gPrP2pDev[1] = prGlueInfo->prP2PInfo[1]->prDevHandler;
ret = TRUE;
}
DBGLOG(P2P, INFO, "P2P 2nd interface work\n");
}
if (fgRollbackRtnlLock)
rtnl_lock();
return ret;
}
BOOLEAN p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, BOOLEAN fgIsRtnlLockAcquired)
{
BOOLEAN fgDoUnregister = FALSE;
BOOLEAN fgRollbackRtnlLock = FALSE;
UINT_8 ucRoleIdx;
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(prGlueInfo);
ASSERT(prGlueInfo->prAdapter);
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (prGlueInfo->prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_REGISTERED) {
prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERING;
fgDoUnregister = TRUE;
}
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (!fgDoUnregister)
return TRUE;
/* prepare for removal */
if (prGlueInfo->prP2PInfo[0]->prDevHandler != prGlueInfo->prP2PInfo[0]->aprRoleHandler) {
if (netif_carrier_ok(prGlueInfo->prP2PInfo[0]->aprRoleHandler))
netif_carrier_off(prGlueInfo->prP2PInfo[0]->aprRoleHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->aprRoleHandler);
}
if (netif_carrier_ok(prGlueInfo->prP2PInfo[0]->prDevHandler))
netif_carrier_off(prGlueInfo->prP2PInfo[0]->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->prDevHandler);
if (fgIsRtnlLockAcquired && rtnl_is_locked()) {
fgRollbackRtnlLock = TRUE;
rtnl_unlock();
}
/* Here are functions which need rtnl_lock */
if (prGlueInfo->prP2PInfo[0]->prDevHandler != prGlueInfo->prP2PInfo[0]->aprRoleHandler) {
DBGLOG(INIT, INFO, "unregister p2p[0]\n");
unregister_netdev(prGlueInfo->prP2PInfo[0]->aprRoleHandler);
}
DBGLOG(INIT, INFO, "unregister p2pdev\n");
unregister_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler);
/* unregister the netdev and index > 0 */
if (prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum >= 2) {
for (ucRoleIdx = 1; ucRoleIdx < BSS_P2P_NUM; ucRoleIdx++) {
/* prepare for removal */
if (netif_carrier_ok(prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler))
netif_carrier_off(prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler);
if (fgIsRtnlLockAcquired && rtnl_is_locked()) {
fgRollbackRtnlLock = TRUE;
rtnl_unlock();
}
/* Here are functions which need rtnl_lock */
unregister_netdev(prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler);
}
}
if (fgRollbackRtnlLock)
rtnl_lock();
prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED;
return TRUE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Register for cfg80211 for Wi-Fi Direct
*
* \param[in] prGlueInfo Pointer to glue info
*
* \return TRUE
* FALSE
*/
/*----------------------------------------------------------------------------*/
BOOLEAN glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, const char *prDevName2, UINT_8 ucApMode)
{
P_ADAPTER_T prAdapter = NULL;
P_GL_HIF_INFO_T prHif = NULL;
PARAM_MAC_ADDRESS rMacAddr;
P_NETDEV_PRIVATE_GLUE_INFO prNetDevPriv = (P_NETDEV_PRIVATE_GLUE_INFO) NULL;
BOOLEAN fgIsApMode = FALSE;
UINT_8 ucRegisterNum = 1, i = 0;
struct wireless_dev *prP2pWdev;
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
struct device *prDev;
#endif
const char *prSetDevName;
ASSERT(prGlueInfo);
prAdapter = prGlueInfo->prAdapter;
ASSERT(prAdapter);
prHif = &prGlueInfo->rHifInfo;
ASSERT(prHif);
if ((ucApMode == RUNNING_AP_MODE) || (ucApMode == RUNNING_DUAL_AP_MODE || (ucApMode == RUNNING_P2P_AP_MODE))) {
fgIsApMode = TRUE;
if ((ucApMode == RUNNING_DUAL_AP_MODE) || (ucApMode == RUNNING_P2P_AP_MODE)) {
ucRegisterNum = 2;
glP2pCreateWirelessDevice(prGlueInfo);
}
}
prSetDevName = prDevName;
do {
if ((ucApMode == RUNNING_P2P_AP_MODE) && (i == 0)) {
prSetDevName = prDevName;
fgIsApMode = FALSE;
} else if ((ucApMode == RUNNING_P2P_AP_MODE) && (i == 1)) {
prSetDevName = prDevName2;
fgIsApMode = TRUE;
}
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
if (!gprP2pRoleWdev[i]) {
DBGLOG(P2P, ERROR, "gl_p2p, wireless device is not exist\n");
return FALSE;
}
#endif
prP2pWdev = gprP2pRoleWdev[i];
DBGLOG(INIT, INFO, "glRegisterP2P(%d)\n", i);
/*0. allocate p2pinfo */
if (!p2PAllocInfo(prGlueInfo, i)) {
DBGLOG(INIT, WARN, "Allocate memory for p2p FAILED\n");
ASSERT(0);
return FALSE;
}
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
/* 1.1 fill wiphy parameters */
glGetHifDev(prHif, &prDev);
if (!prDev)
DBGLOG(INIT, INFO, "unable to get struct dev for p2p\n");
prGlueInfo->prP2PInfo[i]->prWdev = prP2pWdev;
/*prGlueInfo->prP2PInfo[i]->prRoleWdev[0] = prP2pWdev;*//* TH3 multiple P2P */
ASSERT(prP2pWdev);
ASSERT(prP2pWdev->wiphy);
ASSERT(prDev);
ASSERT(prGlueInfo->prAdapter);
set_wiphy_dev(prP2pWdev->wiphy, prDev);
if (!prGlueInfo->prAdapter->fgEnable5GBand)
prP2pWdev->wiphy->bands[BAND_5G] = NULL;
/* 2.2 wdev initialization */
if (fgIsApMode)
prP2pWdev->iftype = NL80211_IFTYPE_AP;
else
prP2pWdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */
/* 3. allocate netdev */
#if KERNEL_VERSION(3, 17, 0) <= CFG80211_VERSION_CODE
prGlueInfo->prP2PInfo[i]->prDevHandler =
alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), prSetDevName,
NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM);
#else
prGlueInfo->prP2PInfo[i]->prDevHandler =
alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), prSetDevName,
ether_setup, CFG_MAX_TXQ_NUM);
#endif
if (!prGlueInfo->prP2PInfo[i]->prDevHandler) {
DBGLOG(INIT, WARN, "unable to allocate netdevice for p2p\n");
goto err_alloc_netdev;
}
/* 4. setup netdev */
/* 4.1 Point to shared glue structure */
/* *((P_GLUE_INFO_T *) netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = prGlueInfo; */
prNetDevPriv = (P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(prGlueInfo->prP2PInfo[i]->prDevHandler);
prNetDevPriv->prGlueInfo = prGlueInfo;
/* 4.2 fill hardware address */
COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr);
rMacAddr[0] |= 0x2;
rMacAddr[0] ^= i << 2; /* change to local administrated address */
kalMemCopy(prGlueInfo->prP2PInfo[i]->prDevHandler->dev_addr, rMacAddr, ETH_ALEN);
kalMemCopy(prGlueInfo->prP2PInfo[i]->prDevHandler->perm_addr,
prGlueInfo->prP2PInfo[i]->prDevHandler->dev_addr,
ETH_ALEN);
/* 4.3 register callback functions */
prGlueInfo->prP2PInfo[i]->prDevHandler->needed_headroom += NIC_TX_HEAD_ROOM;
prGlueInfo->prP2PInfo[i]->prDevHandler->netdev_ops = &p2p_netdev_ops;
/* prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def; */
#if defined(_HIF_SDIO)
#if (MTK_WCN_HIF_SDIO == 0)
SET_NETDEV_DEV(prGlueInfo->prP2PInfo[i]->prDevHandler, &(prHif->func->dev));
#endif
#endif
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
prGlueInfo->prP2PInfo[i]->prDevHandler->ieee80211_ptr = prP2pWdev;
prP2pWdev->netdev = prGlueInfo->prP2PInfo[i]->prDevHandler;
#endif
#if CFG_TCP_IP_CHKSUM_OFFLOAD
/* set HW checksum offload */
if (prAdapter->fgIsSupportCsumOffload)
prGlueInfo->prP2PInfo[i]->prDevHandler->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM;
#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */
kalResetStats(prGlueInfo->prP2PInfo[i]->prDevHandler);
#if 0
/* 7. net device initialize */
netif_carrier_off(prGlueInfo->prP2PInfo->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo->prDevHandler);
/* 8. register for net device */
if (register_netdev(prGlueInfo->prP2PInfo->prDevHandler) < 0) {
DBGLOG(INIT, WARN, "unable to register netdevice for p2p\n");
goto err_reg_netdev;
}
#endif
/* 8. set p2p net device register state */
prGlueInfo->prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED;
/* 9. setup running mode */
/* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode = fgIsApMode; */
/* 10. finish */
/* 13. bind netdev pointer to netdev index */
wlanBindBssIdxToNetInterface(prGlueInfo, p2pDevFsmInit(prAdapter),
(PVOID) prGlueInfo->prP2PInfo[i]->prDevHandler);
prGlueInfo->prP2PInfo[i]->aprRoleHandler = prGlueInfo->prP2PInfo[i]->prDevHandler;
DBGLOG(P2P, INFO, "check prDevHandler = %p\n", prGlueInfo->prP2PInfo[i]->prDevHandler);
DBGLOG(P2P, INFO, "aprRoleHandler = %p\n", prGlueInfo->prP2PInfo[i]->aprRoleHandler);
prNetDevPriv->ucBssIdx = p2pRoleFsmInit(prAdapter, i);
/* 11. Currently wpasupplicant can't support create interface. */
/* so initial the corresponding data structure here. */
wlanBindBssIdxToNetInterface(prGlueInfo, prNetDevPriv->ucBssIdx,
(PVOID) prGlueInfo->prP2PInfo[i]->aprRoleHandler);
/* 13. bind netdev pointer to netdev index */
/* wlanBindNetInterface(prGlueInfo, NET_DEV_P2P_IDX, (PVOID)prGlueInfo->prP2PInfo->prDevHandler); */
/* 12. setup running mode */
p2pFuncInitConnectionSettings(prAdapter, prAdapter->rWifiVar.prP2PConnSettings[i], fgIsApMode);
/* Active network too early would cause HW not able to sleep.
* Defer the network active time.
*/
/* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */
i++;
} while (i < ucRegisterNum);
if ((ucApMode == RUNNING_DUAL_AP_MODE) || (ucApMode == RUNNING_P2P_AP_MODE))
prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum = 2;
else
prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum = 1;
return TRUE;
#if 0
err_reg_netdev:
free_netdev(prGlueInfo->prP2PInfo->prDevHandler);
#endif
err_alloc_netdev:
return FALSE;
} /* end of glRegisterP2P() */
BOOLEAN glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo)
{
struct wiphy *prWiphy = NULL;
struct wireless_dev *prWdev = NULL;
UINT_8 i = 0;
u32 band_idx, ch_idx;
struct ieee80211_supported_band *sband = NULL;
struct ieee80211_channel *chan = NULL;
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!prWdev) {
DBGLOG(P2P, ERROR, "allocate p2p wireless device fail, no memory\n");
return FALSE;
}
/* 1. allocate WIPHY */
prWiphy = wiphy_new(&mtk_p2p_ops, sizeof(P_GLUE_INFO_T));
if (!prWiphy) {
DBGLOG(P2P, ERROR, "unable to allocate wiphy for p2p\n");
goto free_wdev;
}
prWiphy->interface_modes = BIT(NL80211_IFTYPE_AP)
| BIT(NL80211_IFTYPE_P2P_CLIENT)
| BIT(NL80211_IFTYPE_P2P_GO)
| BIT(NL80211_IFTYPE_STATION);
prWiphy->software_iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
prWiphy->iface_combinations = p_mtk_iface_combinations_p2p;
prWiphy->n_iface_combinations = mtk_iface_combinations_p2p_num;
prWiphy->bands[KAL_BAND_2GHZ] = &mtk_band_2ghz;
prWiphy->bands[KAL_BAND_5GHZ] = &mtk_band_5ghz;
/*
* Clear flags in ieee80211_channel before p2p registers to resolve
* overriding flags issue. For example, when country is changed to US,
* both WW and US flags are applied. The issue flow is:
*
* 1. Register wlan wiphy (wiphy_register()@core.c)
* chan->orig_flags = chan->flags = 0
* 2. Apply WW regdomain (handle_channel()@reg.c):
* chan->flags = chan->orig_flags|reg_channel_flags = 0|WW_channel_flags
* 3. Register p2p wiphy:
* chan->orig_flags = chan->flags = WW channel flags
* 4. Apply US regdomain:
* chan->flags = chan->orig_flags|reg_channel_flags
* = WW_channel_flags|US_channel_flags
* (Unexpected! It includes WW flags)
*/
for (band_idx = 0; band_idx < KAL_NUM_BANDS; band_idx++) {
sband = prWiphy->bands[band_idx];
if (!sband)
continue;
for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) {
chan = &sband->channels[ch_idx];
chan->flags = 0;
}
}
prWiphy->mgmt_stypes = mtk_cfg80211_default_mgmt_stypes;
prWiphy->max_remain_on_channel_duration = 5000;
prWiphy->n_cipher_suites = 5;
prWiphy->cipher_suites = mtk_cipher_suites;
#if KERNEL_VERSION(3, 14, 0) > CFG80211_VERSION_CODE
prWiphy->flags = WIPHY_FLAG_CUSTOM_REGULATORY | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME;
#else
#if (CFG_SUPPORT_DFS_MASTER == 1)
prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_HAS_CHANNEL_SWITCH;
#else
prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME;
#endif
prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG;
#endif
prWiphy->ap_sme_capa = 1;
prWiphy->max_scan_ssids = MAX_SCAN_LIST_NUM;
prWiphy->max_scan_ie_len = MAX_SCAN_IE_LEN;
prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
#if KERNEL_VERSION(3, 18, 0) <= CFG80211_VERSION_CODE
prWiphy->vendor_commands = mtk_p2p_vendor_ops;
prWiphy->n_vendor_commands = sizeof(mtk_p2p_vendor_ops) / sizeof(struct wiphy_vendor_command);
#endif
#ifdef CONFIG_PM
#if KERNEL_VERSION(3, 9, 0) > CFG80211_VERSION_CODE
prWiphy->wowlan = &mtk_p2p_wowlan_support;
#endif
#endif
cfg80211_regd_set_wiphy(prWiphy);
/* 2.1 set priv as pointer to glue structure */
*((P_GLUE_INFO_T *) wiphy_priv(prWiphy)) = prGlueInfo;
/* Here are functions which need rtnl_lock */
if (wiphy_register(prWiphy) < 0) {
DBGLOG(INIT, WARN, "fail to register wiphy for p2p\n");
goto free_wiphy;
}
prWdev->wiphy = prWiphy;
for (i = 0 ; i < KAL_P2P_NUM; i++) {
if (!gprP2pRoleWdev[i]) {
gprP2pRoleWdev[i] = prWdev;
DBGLOG(INIT, INFO, "glP2pCreateWirelessDevice (%x)\n", gprP2pRoleWdev[i]->wiphy);
break;
}
}
if (i == KAL_P2P_NUM) {
DBGLOG(INIT, WARN, "fail to register wiphy to driver\n");
goto free_wiphy;
}
return TRUE;
free_wiphy:
wiphy_free(prWiphy);
free_wdev:
kfree(prWdev);
#endif
return FALSE;
}
void glP2pDestroyWirelessDevice(void)
{
#if 0
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
set_wiphy_dev(gprP2pWdev->wiphy, NULL);
wiphy_unregister(gprP2pWdev->wiphy);
wiphy_free(gprP2pWdev->wiphy);
kfree(gprP2pWdev);
gprP2pWdev = NULL;
#endif
#else
int i = 0;
set_wiphy_dev(gprP2pWdev->wiphy, NULL);
wiphy_unregister(gprP2pWdev->wiphy);
wiphy_free(gprP2pWdev->wiphy);
kfree(gprP2pWdev);
for (i = 0; i < KAL_P2P_NUM; i++) {
if (gprP2pRoleWdev[i] == NULL)
continue;
if (i != 0) { /* The P2P is always in index 0 and shares Wiphy with P2PWdev */
DBGLOG(INIT, INFO, "glP2pDestroyWirelessDevice (%p)\n", gprP2pRoleWdev[i]->wiphy);
set_wiphy_dev(gprP2pRoleWdev[i]->wiphy, NULL);
wiphy_unregister(gprP2pRoleWdev[i]->wiphy);
wiphy_free(gprP2pRoleWdev[i]->wiphy);
}
if (gprP2pRoleWdev[i] && (gprP2pWdev != gprP2pRoleWdev[i]))
kfree(gprP2pRoleWdev[i]);
gprP2pRoleWdev[i] = NULL;
}
gprP2pWdev = NULL;
#endif
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Unregister Net Device for Wi-Fi Direct
*
* \param[in] prGlueInfo Pointer to glue info
*
* \return TRUE
* FALSE
*/
/*----------------------------------------------------------------------------*/
BOOLEAN glUnregisterP2P(P_GLUE_INFO_T prGlueInfo)
{
UINT_8 ucRoleIdx;
P_ADAPTER_T prAdapter;
P_GL_P2P_INFO_T prP2PInfo;
ASSERT(prGlueInfo);
prAdapter = prGlueInfo->prAdapter;
/* 4 <1> Uninit P2P dev FSM */
/* Uninit P2P device FSM */
p2pDevFsmUninit(prAdapter);
/* 4 <2> Uninit P2P role FSM */
for (ucRoleIdx = 0; ucRoleIdx < BSS_P2P_NUM; ucRoleIdx++) {
if (P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx))
p2pRoleFsmUninit(prGlueInfo->prAdapter, ucRoleIdx);
}
/* 4 <3> Free Wiphy & netdev */
for (ucRoleIdx = 0; ucRoleIdx < BSS_P2P_NUM; ucRoleIdx++) {
prP2PInfo = prGlueInfo->prP2PInfo[ucRoleIdx];
if (prP2PInfo == NULL)
continue;
/* For P2P interfaces, prDevHandler points to the net_device of p2p0 interface. */
/* And aprRoleHandler points to the net_device of p2p virtual interface (i.e., p2p1) */
/* when it was created. And when p2p virtual interface is deleted, aprRoleHandler will */
/* change to point to prDevHandler. Hence, when aprRoleHandler & prDevHandler are pointing */
/* to different addresses, it means vif p2p1 exists. Otherwise it means p2p1 was */
/* already deleted. */
if ((prP2PInfo->aprRoleHandler != NULL) &&
(prP2PInfo->aprRoleHandler != prP2PInfo->prDevHandler)) {
/* This device is added by the P2P, and use ndev->destructor to free. */
prP2PInfo->aprRoleHandler = NULL;
DBGLOG(P2P, INFO, "aprRoleHandler idx %d set NULL\n", ucRoleIdx);
}
if (prP2PInfo->prDevHandler) {
free_netdev(prP2PInfo->prDevHandler);
prP2PInfo->prDevHandler = NULL;
}
}
/* 4 <4> Free P2P internal memory */
if (!p2PFreeInfo(prGlueInfo)) {
DBGLOG(INIT, WARN, "Free memory for p2p FAILED\n");
ASSERT(0);
return FALSE;
}
return TRUE;
#if 0
p2pFsmUninit(prGlueInfo->prAdapter);
nicDeactivateNetwork(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX);
#if 0
/* Release command, mgmt and security frame belong to P2P network in
* prGlueInfo->prCmdQue
* prAdapter->rPendingCmdQueue
* prAdapter->rTxCtrl.rTxMgmtTxingQueue
* To ensure there is no pending CmdDone/TxDone handler to be executed after p2p module is removed.
*/
/* Clear CmdQue */
kalClearMgmtFramesByBssIdx(prGlueInfo, NETWORK_TYPE_P2P_INDEX);
kalClearSecurityFramesByBssIdx(prGlueInfo, NETWORK_TYPE_P2P_INDEX);
/* Clear PendingCmdQue */
wlanReleasePendingCMDbyBssIdx(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX);
/* Clear PendingTxMsdu */
nicFreePendingTxMsduInfoByBssIdx(prGlueInfo->prAdapter, NETWORK_TYPE_P2P_INDEX);
#endif
#if 0
/* prepare for removal */
if (netif_carrier_ok(prGlueInfo->prP2PInfo[0]->prDevHandler))
netif_carrier_off(prGlueInfo->prP2PInfo[0]->prDevHandler);
netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->prDevHandler);
/* netdevice unregistration & free */
unregister_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler);
#endif
free_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler);
prGlueInfo->prP2PInfo[0]->prDevHandler = NULL;
#if CFG_ENABLE_WIFI_DIRECT_CFG_80211
#if 0
wiphy_unregister(prGlueInfo->prP2PInfo[0]->wdev.wiphy);
#endif
wiphy_free(prGlueInfo->prP2PInfo[0]->wdev.wiphy);
prGlueInfo->prP2PInfo[0]->wdev.wiphy = NULL;
#endif
/* Free p2p memory */
#if 1
if (!p2PFreeInfo(prGlueInfo)) {
DBGLOG(INIT, WARN, "Free memory for p2p FAILED\n");
ASSERT(0);
return FALSE;
}
#endif
return TRUE;
#else
return 0;
#endif
} /* end of glUnregisterP2P() */
/* Net Device Hooks */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for net_device open (ifup)
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution succeeds.
* \retval < 0 The execution failed.
*/
/*----------------------------------------------------------------------------*/
static int p2pOpen(IN struct net_device *prDev)
{
/* P_GLUE_INFO_T prGlueInfo = NULL; */
/* P_ADAPTER_T prAdapter = NULL; */
/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */
ASSERT(prDev);
#if 0 /* Move after device name set. (mtk_p2p_set_local_dev_info) */
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
ASSERT(prGlueInfo);
prAdapter = prGlueInfo->prAdapter;
ASSERT(prAdapter);
/* 1. switch P2P-FSM on */
/* 1.1 allocate for message */
prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter,
RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T));
if (!prFuncSwitch) {
ASSERT(0); /* Can't trigger P2P FSM */
return -ENOMEM;
}
/* 1.2 fill message */
prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH;
prFuncSwitch->fgIsFuncOn = TRUE;
/* 1.3 send message */
mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF);
#endif
/* 2. carrier on & start TX queue */
/*DFS todo 20161220_DFS*/
#if (CFG_SUPPORT_DFS_MASTER == 1)
if (prDev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
netif_carrier_on(prDev);
netif_tx_start_all_queues(prDev);
}
#else
netif_carrier_on(prDev);
netif_tx_start_all_queues(prDev);
#endif
return 0; /* success */
} /* end of p2pOpen() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A function for net_device stop (ifdown)
*
* \param[in] prDev Pointer to struct net_device.
*
* \retval 0 The execution succeeds.
* \retval < 0 The execution failed.
*/
/*----------------------------------------------------------------------------*/
static int p2pStop(IN struct net_device *prDev)
{
P_GLUE_INFO_T prGlueInfo = NULL;
P_ADAPTER_T prAdapter = NULL;
P_GL_P2P_DEV_INFO_T prP2pGlueDevInfo = (P_GL_P2P_DEV_INFO_T) NULL;
UINT_8 ucRoleIdx = 0;
struct net_device *prTargetDev = NULL;
struct cfg80211_scan_request *prScanRequest = NULL;
/* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */
GLUE_SPIN_LOCK_DECLARATION();
ASSERT(prDev);
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
ASSERT(prGlueInfo);
prAdapter = prGlueInfo->prAdapter;
ASSERT(prAdapter);
prP2pGlueDevInfo = prGlueInfo->prP2PDevInfo;
ASSERT(prP2pGlueDevInfo);
/* 0. Do the scan done and set parameter to abort if the scan pending */
/* Default : P2P dev */
prTargetDev = prGlueInfo->prP2PInfo[0]->prDevHandler;
if (mtk_Netdev_To_RoleIdx(prGlueInfo, prDev, &ucRoleIdx) != 0)
prTargetDev = prGlueInfo->prP2PInfo[ucRoleIdx]->aprRoleHandler;
/*DBGLOG(INIT, INFO, "p2pStop and ucRoleIdx = %u\n", ucRoleIdx);*/
GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if ((prP2pGlueDevInfo->prScanRequest != NULL) &&
(prP2pGlueDevInfo->prScanRequest->wdev == prTargetDev->ieee80211_ptr)) {
prScanRequest = prP2pGlueDevInfo->prScanRequest;
prP2pGlueDevInfo->prScanRequest = NULL;
}
GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV);
if (prScanRequest) {
DBGLOG(INIT, INFO, "p2pStop and abort scan!!\n");
kalCfg80211ScanDone(prScanRequest, TRUE);
}
/* 1. stop TX queue */
netif_tx_stop_all_queues(prDev);
#if 0
/* 2. switch P2P-FSM off */
/* 2.1 allocate for message */
prFuncSwitch = (P_MSG_P2P_FUNCTION_SWITCH_T) cnmMemAlloc(prAdapter,
RAM_TYPE_MSG, sizeof(MSG_P2P_FUNCTION_SWITCH_T));
if (!prFuncSwitch) {
ASSERT(0); /* Can't trigger P2P FSM */
return -ENOMEM;
}
/* 2.2 fill message */
prFuncSwitch->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH;
prFuncSwitch->fgIsFuncOn = FALSE;
/* 2.3 send message */
mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T) prFuncSwitch, MSG_SEND_METHOD_BUF);
#endif
/* 3. stop queue and turn off carrier */
/*prGlueInfo->prP2PInfo[0]->eState = PARAM_MEDIA_STATE_DISCONNECTED;*//* TH3 multiple P2P */
netif_tx_stop_all_queues(prDev);
if (netif_carrier_ok(prDev))
netif_carrier_off(prDev);
return 0;
} /* end of p2pStop() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, to get the network interface statistical
* information.
*
* Whenever an application needs to get statistics for the interface, this method
* is called. This happens, for example, when ifconfig or netstat -i is run.
*
* \param[in] prDev Pointer to struct net_device.
*
* \return net_device_stats buffer pointer.
*/
/*----------------------------------------------------------------------------*/
struct net_device_stats *p2pGetStats(IN struct net_device *prDev)
{
return (struct net_device_stats *)kalGetStats(prDev);
} /* end of p2pGetStats() */
static void p2pSetMulticastList(IN struct net_device *prDev)
{
P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T) NULL;
prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL;
ASSERT(prDev);
ASSERT(prGlueInfo);
if (!prDev || !prGlueInfo) {
DBGLOG(INIT, WARN, " abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo);
return;
}
g_P2pPrDev = prDev;
/* 4 Mark HALT, notify main thread to finish current job */
set_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag);
/* wake up main thread */
wake_up_interruptible(&prGlueInfo->waitq);
} /* p2pSetMulticastList */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is to set multicast list and set rx mode.
*
* \param[in] prDev Pointer to struct net_device
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
void mtk_p2p_wext_set_Multicastlist(P_GLUE_INFO_T prGlueInfo)
{
UINT_32 u4SetInfoLen = 0;
UINT_32 u4McCount;
struct net_device *prDev = g_P2pPrDev;
prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *) netdev_priv(prDev)) : NULL;
ASSERT(prDev);
ASSERT(prGlueInfo);
if (!prDev || !prGlueInfo) {
DBGLOG(INIT, WARN, " abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, prGlueInfo);
return;
}
if (prDev->flags & IFF_PROMISC)
prGlueInfo->prP2PDevInfo->u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS;
if (prDev->flags & IFF_BROADCAST)
prGlueInfo->prP2PDevInfo->u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST;
u4McCount = netdev_mc_count(prDev);
if (prDev->flags & IFF_MULTICAST) {
if ((prDev->flags & IFF_ALLMULTI) || (u4McCount > MAX_NUM_GROUP_ADDR))
prGlueInfo->prP2PDevInfo->u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST;
else
prGlueInfo->prP2PDevInfo->u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST;
}
if (prGlueInfo->prP2PDevInfo->u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) {
/* Prepare multicast address list */
struct netdev_hw_addr *ha;
UINT_32 i = 0;
netdev_for_each_mc_addr(ha, prDev) {
if (i < MAX_NUM_GROUP_ADDR) {
COPY_MAC_ADDR(&(prGlueInfo->prP2PDevInfo->aucMCAddrList[i]), GET_ADDR(ha));
i++;
}
}
DBGLOG(P2P, TRACE, "SEt Multicast Address List\n");
if (i >= MAX_NUM_GROUP_ADDR)
return;
wlanoidSetP2PMulticastList(prGlueInfo->prAdapter,
&(prGlueInfo->prP2PDevInfo->aucMCAddrList[0]),
(i * ETH_ALEN), &u4SetInfoLen);
}
} /* end of p2pSetMulticastList() */
/*----------------------------------------------------------------------------*/
/*!
* * \brief This function is TX entry point of NET DEVICE.
* *
* * \param[in] prSkb Pointer of the sk_buff to be sent
* * \param[in] prDev Pointer to struct net_device
* *
* * \retval NETDEV_TX_OK - on success.
* * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer.
*/
/*----------------------------------------------------------------------------*/
int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev)
{
P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
UINT_8 ucBssIndex;
ASSERT(prSkb);
ASSERT(prDev);
prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO) netdev_priv(prDev);
prGlueInfo = prNetDevPrivate->prGlueInfo;
ucBssIndex = prNetDevPrivate->ucBssIdx;
kalResetPacket(prGlueInfo, (P_NATIVE_PACKET) prSkb);
kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex);
return NETDEV_TX_OK;
} /* end of p2pHardStartXmit() */
/*----------------------------------------------------------------------------*/
/*!
* \brief A method of struct net_device, a primary SOCKET interface to configure
* the interface lively. Handle an ioctl call on one of our devices.
* Everything Linux ioctl specific is done here. Then we pass the contents
* of the ifr->data to the request message handler.
*
* \param[in] prDev Linux kernel netdevice
*
* \param[in] prIFReq Our private ioctl request structure, typed for the generic
* struct ifreq so we can use ptr to function
*
* \param[in] cmd Command ID
*
* \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully.
* \retval OTHER The execution of IOCTL command is failed.
*/
/*----------------------------------------------------------------------------*/
int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd)
{
P_GLUE_INFO_T prGlueInfo = NULL;
int ret = 0;
/* char *prExtraBuf = NULL; */
/* UINT_32 u4ExtraSize = 0; */
struct iwreq *prIwReq = (struct iwreq *)prIfReq;
struct iw_request_info rIwReqInfo;
/* fill rIwReqInfo */
rIwReqInfo.cmd = (__u16) i4Cmd;
rIwReqInfo.flags = 0;
ASSERT(prDev && prIfReq);
DBGLOG(P2P, ERROR, "p2pDoIOCTL In %x %x\n", i4Cmd, SIOCDEVPRIVATE);
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
if (!prGlueInfo) {
DBGLOG(P2P, ERROR, "prGlueInfo is NULL\n");
return -EFAULT;
}
if (prGlueInfo->u4ReadyFlag == 0) {
DBGLOG(P2P, ERROR, "Adapter is not ready\n");
return -EINVAL;
}
if (i4Cmd == IOCTL_GET_DRIVER)
ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd);
else if (i4Cmd == SIOCGIWPRIV)
ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL);
else {
DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n", i4Cmd);
ret = -1;
}
#if 0
/* fill rIwReqInfo */
rIwReqInfo.cmd = (__u16) i4Cmd;
rIwReqInfo.flags = 0;
switch (i4Cmd) {
case SIOCSIWENCODEEXT:
/* Set Encryption Material after 4-way handshaking is done */
if (prIwReq->u.encoding.pointer) {
u4ExtraSize = prIwReq->u.encoding.length;
prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, prIwReq->u.encoding.pointer, prIwReq->u.encoding.length))
ret = -EFAULT;
} else if (prIwReq->u.encoding.length != 0) {
ret = -EINVAL;
break;
}
if (ret == 0)
ret = mtk_p2p_wext_set_key(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf);
kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize);
prExtraBuf = NULL;
break;
case SIOCSIWMLME:
/* IW_MLME_DISASSOC used for disconnection */
if (prIwReq->u.data.length != sizeof(struct iw_mlme)) {
DBGLOG(INIT, INFO, "MLME buffer strange:%d\n", prIwReq->u.data.length);
ret = -EINVAL;
break;
}
if (!prIwReq->u.data.pointer) {
ret = -EINVAL;
break;
}
prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE);
if (!prExtraBuf) {
ret = -ENOMEM;
break;
}
if (copy_from_user(prExtraBuf, prIwReq->u.data.pointer, sizeof(struct iw_mlme)))
ret = -EFAULT;
else
ret = mtk_p2p_wext_mlme_handler(prDev, &rIwReqInfo, &(prIwReq->u), prExtraBuf);
kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme));
prExtraBuf = NULL;
break;
case SIOCGIWPRIV:
/* This ioctl is used to list all IW privilege ioctls */
ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL);
break;
case SIOCGIWSCAN:
ret = mtk_p2p_wext_discovery_results(prDev, &rIwReqInfo, &(prIwReq->u), NULL);
break;
case SIOCSIWAUTH:
ret = mtk_p2p_wext_set_auth(prDev, &rIwReqInfo, &(prIwReq->u), NULL);
break;
case IOC_P2P_CFG_DEVICE:
case IOC_P2P_PROVISION_COMPLETE:
case IOC_P2P_START_STOP_DISCOVERY:
case IOC_P2P_DISCOVERY_RESULTS:
case IOC_P2P_WSC_BEACON_PROBE_RSP_IE:
case IOC_P2P_CONNECT_DISCONNECT:
case IOC_P2P_PASSWORD_READY:
case IOC_P2P_GET_STRUCT:
case IOC_P2P_SET_STRUCT:
case IOC_P2P_GET_REQ_DEVICE_INFO:
#if 0
ret = rP2PIwPrivHandler[i4Cmd - SIOCIWFIRSTPRIV](prDev,
&rIwReqInfo,
&(prIwReq->u),
(char *)&(prIwReq->u));
#endif
break;
#if CFG_SUPPORT_P2P_RSSI_QUERY
case SIOCGIWSTATS:
ret = mtk_p2p_wext_get_rssi(prDev, &rIwReqInfo, &(prIwReq->u), NULL);
break;
#endif
default:
ret = -ENOTTY;
}
#endif /* 0 */
return ret;
} /* end of p2pDoIOCTL() */
/*----------------------------------------------------------------------------*/
/*!
* \brief To override p2p interface address
*
* \param[in] prDev Net device requested.
* \param[in] addr Pointer to address
*
* \retval 0 For success.
* \retval -E2BIG For user's buffer size is too small.
* \retval -EFAULT For fail.
*
*/
/*----------------------------------------------------------------------------*/
int p2pSetMACAddress(IN struct net_device *prDev, void *addr)
{
P_ADAPTER_T prAdapter = NULL;
P_GLUE_INFO_T prGlueInfo = NULL;
ASSERT(prDev);
prGlueInfo = *((P_GLUE_INFO_T *) netdev_priv(prDev));
ASSERT(prGlueInfo);
prAdapter = prGlueInfo->prAdapter;
ASSERT(prAdapter);
/* @FIXME */
return eth_mac_addr(prDev, addr);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief To report the private supported IOCTLs table to user space.
*
* \param[in] prDev Net device requested.
* \param[out] prIfReq Pointer to ifreq structure, content is copied back to
* user space buffer in gl_iwpriv_table.
*
* \retval 0 For success.
* \retval -E2BIG For user's buffer size is too small.
* \retval -EFAULT For fail.
*
*/
/*----------------------------------------------------------------------------*/
int
mtk_p2p_wext_get_priv(IN struct net_device *prDev,
IN struct iw_request_info *info, IN OUT union iwreq_data *wrqu, IN OUT char *extra)
{
struct iw_point *prData = (struct iw_point *)&wrqu->data;
UINT_16 u2BufferSize = 0;
ASSERT(prDev);
u2BufferSize = prData->length;
/* update our private table size */
prData->length = (__u16) sizeof(rP2PIwPrivTable) / sizeof(struct iw_priv_args);
if (u2BufferSize < prData->length)
return -E2BIG;
if (prData->length) {
if (copy_to_user(prData->pointer, rP2PIwPrivTable, sizeof(rP2PIwPrivTable)))
return -EFAULT;
}
return 0;
} /* end of mtk_p2p_wext_get_priv() */