MT7601u/src/os/linux/cfg80211.c
Murat Demirtas 612db32659 FIXED
2016-10-30 14:40:00 +00:00

1966 lines
49 KiB
C

/****************************************************************************
* Ralink Tech Inc.
* Taiwan, R.O.C.
*
* (c) Copyright 2009, Ralink Technology, Inc.
*
* All rights reserved. Ralink's source code is an unpublished work and the
* use of a copyright notice does not imply otherwise. This source code
* contains confidential trade secret material of Ralink Tech. Any attemp
* or participation in deciphering, decoding, reverse engineering or in any
* way altering the source code is stricitly prohibited, unless the prior
* written consent of Ralink Technology, Inc. is obtained.
***************************************************************************/
/****************************************************************************
Abstract:
All related CFG80211 function body.
History:
1. 2009/09/17 Sample Lin
(1) Init version.
2. 2009/10/27 Sample Lin
(1) Do not use ieee80211_register_hw() to create virtual interface.
Use wiphy_register() to register nl80211 command handlers.
(2) Support iw utility.
3. 2009/11/03 Sample Lin
(1) Change name MAC80211 to CFG80211.
(2) Modify CFG80211_OpsChannelSet().
(3) Move CFG80211_Register()/CFG80211_UnRegister() to open/close.
4. 2009/12/16 Sample Lin
(1) Patch for Linux 2.6.32.
(2) Add more supported functions in CFG80211_Ops.
5. 2010/12/10 Sample Lin
(1) Modify for OS_ABL.
6. 2011/04/19 Sample Lin
(1) Add more supported functions in CFG80211_Ops v33 ~ 38.
Note:
The feature is supported only in "LINUX" 2.6.28 ~ 2.6.38.
***************************************************************************/
/* #include "rt_config.h" */
#define RTMP_MODULE_OS
/*#include "rt_config.h" */
#include "rtmp_comm.h"
#include "rt_os_util.h"
#include "rt_os_net.h"
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
#ifdef RT_CFG80211_SUPPORT
/* 36 ~ 64, 100 ~ 136, 140 ~ 161 */
#define CFG80211_NUM_OF_CHAN_5GHZ \
(sizeof(Cfg80211_Chan)-CFG80211_NUM_OF_CHAN_2GHZ)
#ifdef OS_ABL_FUNC_SUPPORT
/*
Array of bitrates the hardware can operate with
in this band. Must be sorted to give a valid "supported
rates" IE, i.e. CCK rates first, then OFDM.
For HT, assign MCS in another structure, ieee80211_sta_ht_cap.
*/
const struct ieee80211_rate Cfg80211_SupRate[12] = {
{
.flags = IEEE80211_RATE_SHORT_PREAMBLE,
.bitrate = 10,
.hw_value = 0,
.hw_value_short = 0,
},
{
.flags = IEEE80211_RATE_SHORT_PREAMBLE,
.bitrate = 20,
.hw_value = 1,
.hw_value_short = 1,
},
{
.flags = IEEE80211_RATE_SHORT_PREAMBLE,
.bitrate = 55,
.hw_value = 2,
.hw_value_short = 2,
},
{
.flags = IEEE80211_RATE_SHORT_PREAMBLE,
.bitrate = 110,
.hw_value = 3,
.hw_value_short = 3,
},
{
.flags = 0,
.bitrate = 60,
.hw_value = 4,
.hw_value_short = 4,
},
{
.flags = 0,
.bitrate = 90,
.hw_value = 5,
.hw_value_short = 5,
},
{
.flags = 0,
.bitrate = 120,
.hw_value = 6,
.hw_value_short = 6,
},
{
.flags = 0,
.bitrate = 180,
.hw_value = 7,
.hw_value_short = 7,
},
{
.flags = 0,
.bitrate = 240,
.hw_value = 8,
.hw_value_short = 8,
},
{
.flags = 0,
.bitrate = 360,
.hw_value = 9,
.hw_value_short = 9,
},
{
.flags = 0,
.bitrate = 480,
.hw_value = 10,
.hw_value_short = 10,
},
{
.flags = 0,
.bitrate = 540,
.hw_value = 11,
.hw_value_short = 11,
},
};
#endif /* OS_ABL_FUNC_SUPPORT */
/* all available channels */
static const UCHAR Cfg80211_Chan[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
/* 802.11 UNI / HyperLan 2 */
36, 38, 40, 44, 46, 48, 52, 54, 56, 60, 62, 64,
/* 802.11 HyperLan 2 */
100, 104, 108, 112, 116, 118, 120, 124, 126, 128, 132, 134, 136,
/* 802.11 UNII */
140, 149, 151, 153, 157, 159, 161, 165, 167, 169, 171, 173,
/* Japan */
184, 188, 192, 196, 208, 212, 216,
};
static const UINT32 CipherSuites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
};
/*
The driver's regulatory notification callback.
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
static INT32 CFG80211_RegNotifier(
IN struct wiphy *pWiphy,
IN struct regulatory_request *pRequest);
#else
static INT32 CFG80211_RegNotifier(
IN struct wiphy *pWiphy,
IN enum reg_set_by Request);
#endif /* LINUX_VERSION_CODE */
/* =========================== Private Function ============================== */
/* get RALINK pAd control block in 80211 Ops */
#define MAC80211_PAD_GET(__pAd, __pWiphy) \
{ \
ULONG *__pPriv; \
__pPriv = (ULONG *)(wiphy_priv(__pWiphy)); \
__pAd = (VOID *)(*__pPriv); \
if (__pAd == NULL) \
{ \
DBGPRINT(RT_DEBUG_ERROR, \
("80211> %s but pAd = NULL!", __FUNCTION__)); \
return -EINVAL; \
} \
}
/*
========================================================================
Routine Description:
Set channel.
Arguments:
pWiphy - Wireless hardware description
pChan - Channel information
ChannelType - Channel type
Return Value:
0 - success
-x - fail
Note:
For iw utility: set channel, set freq
enum nl80211_channel_type {
NL80211_CHAN_NO_HT,
NL80211_CHAN_HT20,
NL80211_CHAN_HT40MINUS,
NL80211_CHAN_HT40PLUS
};
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
static int CFG80211_OpsChannelSet(
IN struct wiphy *pWiphy,
IN struct net_device *pDev,
IN struct ieee80211_channel *pChan,
IN enum nl80211_channel_type ChannelType)
#else
static int CFG80211_OpsChannelSet(
IN struct wiphy *pWiphy,
IN struct ieee80211_channel *pChan,
IN enum nl80211_channel_type ChannelType)
#endif /* LINUX_VERSION_CODE */
{
VOID *pAd;
CFG80211_CB *p80211CB;
CMD_RTPRIV_IOCTL_80211_CHAN ChanInfo;
UINT32 ChanId;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
/* get channel number */
ChanId = ieee80211_frequency_to_channel(pChan->center_freq);
CFG80211DBG(RT_DEBUG_ERROR, ("80211> Channel = %d\n", ChanId));
CFG80211DBG(RT_DEBUG_ERROR, ("80211> ChannelType = %d\n", ChannelType));
/* init */
memset(&ChanInfo, 0, sizeof(ChanInfo));
ChanInfo.ChanId = ChanId;
p80211CB = NULL;
RTMP_DRIVER_80211_CB_GET(pAd, &p80211CB);
if (p80211CB == NULL)
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> p80211CB == NULL!\n"));
return 0;
}
if (p80211CB->pCfg80211_Wdev->iftype == NL80211_IFTYPE_STATION)
ChanInfo.IfType = RT_CMD_80211_IFTYPE_STATION;
else if (p80211CB->pCfg80211_Wdev->iftype == NL80211_IFTYPE_ADHOC)
ChanInfo.IfType = RT_CMD_80211_IFTYPE_ADHOC;
else if (p80211CB->pCfg80211_Wdev->iftype == NL80211_IFTYPE_MONITOR)
ChanInfo.IfType = RT_CMD_80211_IFTYPE_MONITOR;
if (ChannelType == NL80211_CHAN_NO_HT)
ChanInfo.ChanType = RT_CMD_80211_CHANTYPE_NOHT;
else if (ChannelType == NL80211_CHAN_HT20)
ChanInfo.ChanType = RT_CMD_80211_CHANTYPE_HT20;
else if (ChannelType == NL80211_CHAN_HT40MINUS)
ChanInfo.ChanType = RT_CMD_80211_CHANTYPE_HT40MINUS;
else if (ChannelType == NL80211_CHAN_HT40PLUS)
ChanInfo.ChanType = RT_CMD_80211_CHANTYPE_HT40PLUS;
ChanInfo.MonFilterFlag = p80211CB->MonFilterFlag;
/* set channel */
RTMP_DRIVER_80211_CHAN_SET(pAd, &ChanInfo);
return 0;
} /* End of CFG80211_OpsChannelSet */
/*
========================================================================
Routine Description:
Change type/configuration of virtual interface.
Arguments:
pWiphy - Wireless hardware description
IfIndex - Interface index
Type - Interface type, managed/adhoc/ap/station, etc.
pFlags - Monitor flags
pParams - Mesh parameters
Return Value:
0 - success
-x - fail
Note:
For iw utility: set type, set monitor
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
static int CFG80211_OpsVirtualInfChg(
IN struct wiphy *pWiphy,
IN struct net_device *pNetDevIn,
IN enum nl80211_iftype Type,
IN u32 *pFlags,
struct vif_params *pParams)
#else
static int CFG80211_OpsVirtualInfChg(
IN struct wiphy *pWiphy,
IN int IfIndex,
IN enum nl80211_iftype Type,
IN u32 *pFlags,
struct vif_params *pParams)
#endif /* LINUX_VERSION_CODE */
{
VOID *pAd;
CFG80211_CB *pCfg80211_CB;
struct net_device *pNetDev;
UINT32 Filter;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
CFG80211DBG(RT_DEBUG_ERROR, ("80211> Type = %d\n", Type));
/* sanity check */
#ifdef CONFIG_STA_SUPPORT
if ((Type != NL80211_IFTYPE_ADHOC) &&
(Type != NL80211_IFTYPE_STATION) &&
(Type != NL80211_IFTYPE_MONITOR))
#endif /* CONFIG_STA_SUPPORT */
{
DBGPRINT(RT_DEBUG_ERROR, ("80211> Wrong interface type %d!\n", Type));
return -EINVAL;
} /* End of if */
/* update interface type */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
pNetDev = pNetDevIn;
#else
pNetDev = __dev_get_by_index(&init_net, IfIndex);
#endif /* LINUX_VERSION_CODE */
if (pNetDev == NULL)
return -ENODEV;
/* End of if */
pNetDev->ieee80211_ptr->iftype = Type;
if (pFlags != NULL)
{
Filter = 0;
if (((*pFlags) & NL80211_MNTR_FLAG_FCSFAIL) == NL80211_MNTR_FLAG_FCSFAIL)
Filter |= RT_CMD_80211_FILTER_FCSFAIL;
if (((*pFlags) & NL80211_MNTR_FLAG_FCSFAIL) == NL80211_MNTR_FLAG_PLCPFAIL)
Filter |= RT_CMD_80211_FILTER_PLCPFAIL;
if (((*pFlags) & NL80211_MNTR_FLAG_CONTROL) == NL80211_MNTR_FLAG_CONTROL)
Filter |= RT_CMD_80211_FILTER_CONTROL;
if (((*pFlags) & NL80211_MNTR_FLAG_CONTROL) == NL80211_MNTR_FLAG_OTHER_BSS)
Filter |= RT_CMD_80211_FILTER_OTHER_BSS;
} /* End of if */
RTMP_DRIVER_80211_VIF_SET(pAd, Filter, Type);
RTMP_DRIVER_80211_CB_GET(pAd, &pCfg80211_CB);
pCfg80211_CB->MonFilterFlag = Filter;
return 0;
} /* End of CFG80211_OpsVirtualInfChg */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
#if defined(SIOCGIWSCAN) || defined(RT_CFG80211_SUPPORT)
extern int rt_ioctl_siwscan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wreq, char *extra);
#endif
/*
========================================================================
Routine Description:
Request to do a scan. If returning zero, the scan request is given
the driver, and will be valid until passed to cfg80211_scan_done().
For scan results, call cfg80211_inform_bss(); you can call this outside
the scan/scan_done bracket too.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
pRequest - Scan request
Return Value:
0 - success
-x - fail
Note:
For iw utility: scan
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
int n_ssids;
struct ieee80211_channel **channels;
u32 n_channels;
const u8 *ie;
size_t ie_len;
* @ssids: SSIDs to scan for (active scan only)
* @n_ssids: number of SSIDs
* @channels: channels to scan on.
* @n_channels: number of channels for each band
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
========================================================================
*/
static int CFG80211_OpsScan(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN struct cfg80211_scan_request *pRequest)
{
#ifdef CONFIG_STA_SUPPORT
VOID *pAd;
CFG80211_CB *pCfg80211_CB;
#ifdef WPA_SUPPLICANT_SUPPORT
struct iw_scan_req IwReq;
union iwreq_data Wreq;
#endif /* WPA_SUPPLICANT_SUPPORT */
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
/* sanity check */
if ((pNdev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) &&
(pNdev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC))
{
return -EOPNOTSUPP;
} /* End of if */
if (RTMP_DRIVER_IOCTL_SANITY_CHECK(pAd, NULL) != NDIS_STATUS_SUCCESS)
{
DBGPRINT(RT_DEBUG_TRACE, ("80211> Network is down!\n"));
return -ENETDOWN;
} /* End of if */
if (RTMP_DRIVER_80211_SCAN(pAd) != NDIS_STATUS_SUCCESS)
return -EBUSY; /* scanning */
/* End of if */
RTMP_DRIVER_80211_CB_GET(pAd, &pCfg80211_CB);
pCfg80211_CB->pCfg80211_ScanReq = pRequest; /* used in scan end */
#ifdef WPA_SUPPLICANT_SUPPORT
memset(&Wreq, 0, sizeof(Wreq));
memset(&IwReq, 0, sizeof(IwReq));
if ((pRequest->ssids != NULL) &&
(sizeof(pRequest->ssids->ssid) <= sizeof(IwReq.essid)))
{
/* use 1st SSID in the requested SSID list */
IwReq.essid_len = pRequest->ssids->ssid_len;
memcpy(IwReq.essid, pRequest->ssids->ssid, sizeof(IwReq.essid));
#if WIRELESS_EXT > 17
Wreq.data.flags |= IW_SCAN_THIS_ESSID;
Wreq.data.length = sizeof(struct iw_scan_req);
#endif /* WIRELESS_EXT */
}
rt_ioctl_siwscan(pNdev, NULL, &Wreq, (char *)&IwReq);
#else
rt_ioctl_siwscan(pNdev, NULL, NULL, NULL);
#endif /* WPA_SUPPLICANT_SUPPORT */
return 0;
#else
return -EOPNOTSUPP;
#endif /* CONFIG_STA_SUPPORT */
} /* End of CFG80211_OpsScan */
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Join the specified IBSS (or create if necessary). Once done, call
cfg80211_ibss_joined(), also call that function when changing BSSID due
to a merge.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
pParams - IBSS parameters
Return Value:
0 - success
-x - fail
Note:
For iw utility: ibss join
No fixed-freq and fixed-bssid support.
========================================================================
*/
static int CFG80211_OpsIbssJoin(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN struct cfg80211_ibss_params *pParams)
{
VOID *pAd;
CMD_RTPRIV_IOCTL_80211_IBSS IbssInfo;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
CFG80211DBG(RT_DEBUG_ERROR, ("80211> SSID = %s\n",
pParams->ssid));
CFG80211DBG(RT_DEBUG_ERROR, ("80211> Beacon Interval = %d\n",
pParams->beacon_interval));
/* init */
memset(&IbssInfo, 0, sizeof(IbssInfo));
IbssInfo.BeaconInterval = pParams->beacon_interval;
IbssInfo.pSsid = pParams->ssid;
/* ibss join */
RTMP_DRIVER_80211_IBSS_JOIN(pAd, &IbssInfo);
return 0;
} /* End of CFG80211_OpsIbssJoin */
/*
========================================================================
Routine Description:
Leave the IBSS.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
Return Value:
0 - success
-x - fail
Note:
For iw utility: ibss leave
========================================================================
*/
static int CFG80211_OpsIbssLeave(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev)
{
VOID *pAd;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
RTMP_DRIVER_80211_STA_LEAVE(pAd);
return 0;
} /* End of CFG80211_OpsIbssLeave */
#endif /* CONFIG_STA_SUPPORT */
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
/*
========================================================================
Routine Description:
Set the transmit power according to the parameters.
Arguments:
pWiphy - Wireless hardware description
Type -
dBm - dBm
Return Value:
0 - success
-x - fail
Note:
Type -
TX_POWER_AUTOMATIC: the dbm parameter is ignored
TX_POWER_LIMITED: limit TX power by the dbm parameter
TX_POWER_FIXED: fix TX power to the dbm parameter
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36))
static int CFG80211_OpsTxPwrSet(
IN struct wiphy *pWiphy,
IN enum nl80211_tx_power_setting Type,
IN int dBm)
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -EOPNOTSUPP;
} /* End of CFG80211_OpsTxPwrSet */
#else
static int CFG80211_OpsTxPwrSet(
IN struct wiphy *pWiphy,
IN enum tx_power_setting Type,
IN int dBm)
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -EOPNOTSUPP;
} /* End of CFG80211_OpsTxPwrSet */
#endif /* LINUX_VERSION_CODE */
/*
========================================================================
Routine Description:
Store the current TX power into the dbm variable.
Arguments:
pWiphy - Wireless hardware description
pdBm - dBm
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsTxPwrGet(
IN struct wiphy *pWiphy,
IN int *pdBm)
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -EOPNOTSUPP;
} /* End of CFG80211_OpsTxPwrGet */
/*
========================================================================
Routine Description:
Power management.
Arguments:
pWiphy - Wireless hardware description
pNdev -
FlgIsEnabled -
Timeout -
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsPwrMgmt(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN bool FlgIsEnabled,
IN int Timeout)
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -EOPNOTSUPP;
} /* End of CFG80211_OpsPwrMgmt */
/*
========================================================================
Routine Description:
Get information for a specific station.
Arguments:
pWiphy - Wireless hardware description
pNdev -
pMac - STA MAC
pSinfo - STA INFO
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsStaGet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 *pMac,
IN struct station_info *pSinfo)
{
VOID *pAd;
CMD_RTPRIV_IOCTL_80211_STA StaInfo;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
/* init */
memset(pSinfo, 0, sizeof(*pSinfo));
memset(&StaInfo, 0, sizeof(StaInfo));
memcpy(StaInfo.MAC, pMac, 6);
/* get sta information */
if (RTMP_DRIVER_80211_STA_GET(pAd, &StaInfo) != NDIS_STATUS_SUCCESS)
return -ENOENT;
if (StaInfo.TxRateFlags != RT_CMD_80211_TXRATE_LEGACY)
{
pSinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
if (StaInfo.TxRateFlags & RT_CMD_80211_TXRATE_BW_40)
pSinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
/* End of if */
if (StaInfo.TxRateFlags & RT_CMD_80211_TXRATE_SHORT_GI)
pSinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
/* End of if */
pSinfo->txrate.mcs = StaInfo.TxRateMCS;
}
else
{
pSinfo->txrate.legacy = StaInfo.TxRateMCS;
} /* End of if */
pSinfo->filled |= STATION_INFO_TX_BITRATE;
/* fill signal */
pSinfo->signal = StaInfo.Signal;
pSinfo->filled |= STATION_INFO_SIGNAL;
#ifdef CONFIG_AP_SUPPORT
/* fill tx count */
pSinfo->tx_packets = StaInfo.TxPacketCnt;
pSinfo->filled |= STATION_INFO_TX_PACKETS;
/* fill inactive time */
pSinfo->inactive_time = StaInfo.InactiveTime;
pSinfo->filled |= STATION_INFO_INACTIVE_TIME;
#endif /* CONFIG_AP_SUPPORT */
return 0;
} /* End of CFG80211_OpsStaGet */
/*
========================================================================
Routine Description:
List all stations known, e.g. the AP on managed interfaces.
Arguments:
pWiphy - Wireless hardware description
pNdev -
Idx -
pMac -
pSinfo -
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsStaDump(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN int Idx,
IN UINT8 *pMac,
IN struct station_info *pSinfo)
{
VOID *pAd;
if (Idx != 0)
return -ENOENT;
/* End of if */
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
#ifdef CONFIG_STA_SUPPORT
if (RTMP_DRIVER_AP_SSID_GET(pAd, pMac) != NDIS_STATUS_SUCCESS)
return -EBUSY;
else
return CFG80211_OpsStaGet(pWiphy, pNdev, pMac, pSinfo);
#endif /* CONFIG_STA_SUPPORT */
return -EOPNOTSUPP;
} /* End of CFG80211_OpsStaDump */
/*
========================================================================
Routine Description:
Notify that wiphy parameters have changed.
Arguments:
pWiphy - Wireless hardware description
Changed -
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsWiphyParamsSet(
IN struct wiphy *pWiphy,
IN UINT32 Changed)
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -EOPNOTSUPP;
} /* End of CFG80211_OpsWiphyParamsSet */
/*
========================================================================
Routine Description:
Add a key with the given parameters.
Arguments:
pWiphy - Wireless hardware description
pNdev -
KeyIdx -
Pairwise -
pMacAddr -
pParams -
Return Value:
0 - success
-x - fail
Note:
pMacAddr will be NULL when adding a group key.
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
static int CFG80211_OpsKeyAdd(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN bool Pairwise,
IN const UINT8 *pMacAddr,
IN struct key_params *pParams)
#else
static int CFG80211_OpsKeyAdd(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN const UINT8 *pMacAddr,
IN struct key_params *pParams)
#endif /* LINUX_VERSION_CODE */
{
VOID *pAd;
CMD_RTPRIV_IOCTL_80211_KEY KeyInfo;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
#ifdef RT_CFG80211_DEBUG
hex_dump("KeyBuf=", (UINT8 *)pParams->key, pParams->key_len);
#endif /* RT_CFG80211_DEBUG */
CFG80211DBG(RT_DEBUG_ERROR, ("80211> KeyIdx = %d\n", KeyIdx));
if (pParams->key_len >= sizeof(KeyInfo.KeyBuf))
return -EINVAL;
/* End of if */
#ifdef CONFIG_STA_SUPPORT
/* init */
memset(&KeyInfo, 0, sizeof(KeyInfo));
memcpy(KeyInfo.KeyBuf, pParams->key, pParams->key_len);
KeyInfo.KeyBuf[pParams->key_len] = 0x00;
if ((pParams->cipher == WLAN_CIPHER_SUITE_WEP40) ||
(pParams->cipher == WLAN_CIPHER_SUITE_WEP104))
{
KeyInfo.KeyType = RT_CMD_80211_KEY_WEP;
}
else if ((pParams->cipher == WLAN_CIPHER_SUITE_TKIP) ||
(pParams->cipher == WLAN_CIPHER_SUITE_CCMP))
{
KeyInfo.KeyType = RT_CMD_80211_KEY_WPA;
}
else
return -ENOTSUPP;
KeyInfo.KeyId = KeyIdx+1;
/* add key */
RTMP_DRIVER_80211_KEY_ADD(pAd, &KeyInfo);
return 0;
#endif /* CONFIG_STA_SUPPORT */
#ifdef CONFIG_AP_SUPPORT
return -ENOTSUPP;
#endif /* CONFIG_AP_SUPPORT */
} /* End of CFG80211_OpsKeyAdd */
/*
========================================================================
Routine Description:
Get information about the key with the given parameters.
Arguments:
pWiphy - Wireless hardware description
pNdev -
KeyIdx -
Pairwise -
pMacAddr -
pCookie -
pCallback -
Return Value:
0 - success
-x - fail
Note:
pMacAddr will be NULL when requesting information for a group key.
All pointers given to the pCallback function need not be valid after
it returns.
This function should return an error if it is not possible to
retrieve the key, -ENOENT if it doesn't exist.
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
static int CFG80211_OpsKeyGet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN bool Pairwise,
IN const UINT8 *pMacAddr,
IN void *pCookie,
IN void (*pCallback)(void *cookie,
struct key_params *))
#else
static int CFG80211_OpsKeyGet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN const UINT8 *pMacAddr,
IN void *pCookie,
IN void (*pCallback)(void *cookie,
struct key_params *))
#endif /* LINUX_VERSION_CODE */
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -ENOTSUPP;
} /* End of CFG80211_OpsKeyGet */
/*
========================================================================
Routine Description:
Remove a key given the pMacAddr (NULL for a group key) and KeyIdx.
Arguments:
pWiphy - Wireless hardware description
pNdev -
KeyIdx -
pMacAddr -
Return Value:
0 - success
-x - fail
Note:
return -ENOENT if the key doesn't exist.
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
static int CFG80211_OpsKeyDel(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN bool Pairwise,
IN const UINT8 *pMacAddr)
#else
static int CFG80211_OpsKeyDel(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN const UINT8 *pMacAddr)
#endif /* LINUX_VERSION_CODE */
{
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
return -ENOTSUPP;
} /* End of CFG80211_OpsKeyDel */
/*
========================================================================
Routine Description:
Set the default key on an interface.
Arguments:
pWiphy - Wireless hardware description
pNdev -
KeyIdx -
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
static int CFG80211_OpsKeyDefaultSet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx,
IN bool Unicast,
IN bool Multicast)
#else
static int CFG80211_OpsKeyDefaultSet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN UINT8 KeyIdx)
#endif /* LINUX_VERSION_CODE */
{
VOID *pAd;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
CFG80211DBG(RT_DEBUG_ERROR, ("80211> KeyIdx = %d\n", KeyIdx));
RTMP_DRIVER_80211_KEY_DEFAULT_SET(pAd, KeyIdx);
return 0;
} /* End of CFG80211_OpsKeyDefaultSet */
#ifdef CONFIG_STA_SUPPORT
/*
========================================================================
Routine Description:
Connect to the ESS with the specified parameters. When connected,
call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS.
If the connection fails for some reason, call cfg80211_connect_result()
with the status from the AP.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
pSme -
Return Value:
0 - success
-x - fail
Note:
For iw utility: connect
You must use "iw ra0 connect xxx", then "iw ra0 disconnect";
You can not use "iw ra0 connect xxx" twice without disconnect;
Or you will suffer "command failed: Operation already in progress (-114)".
You must support add_key and set_default_key function;
Or kernel will crash without any error message in linux 2.6.32.
========================================================================
*/
static int CFG80211_OpsConnect(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN struct cfg80211_connect_params *pSme)
{
VOID *pAd;
CMD_RTPRIV_IOCTL_80211_CONNECT ConnInfo;
struct ieee80211_channel *pChannel = pSme->channel;
INT32 Pairwise = 0;
INT32 Groupwise = 0;
INT32 Keymgmt = 0;
INT32 WpaVersion = NL80211_WPA_VERSION_2;
INT32 Chan = -1, Idx;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
/* init */
MAC80211_PAD_GET(pAd, pWiphy);
if (pChannel != NULL)
Chan = ieee80211_frequency_to_channel(pChannel->center_freq);
Groupwise = pSme->crypto.cipher_group;
for(Idx=0; Idx<pSme->crypto.n_ciphers_pairwise; Idx++)
Pairwise |= pSme->crypto.ciphers_pairwise[Idx];
/* End of for */
for(Idx=0; Idx<pSme->crypto.n_akm_suites; Idx++)
Keymgmt |= pSme->crypto.akm_suites[Idx];
/* End of for */
WpaVersion = pSme->crypto.wpa_versions;
memset(&ConnInfo, 0, sizeof(ConnInfo));
if (WpaVersion & NL80211_WPA_VERSION_2)
ConnInfo.WpaVer = 2;
else if (WpaVersion & NL80211_WPA_VERSION_1)
ConnInfo.WpaVer = 1;
else
ConnInfo.WpaVer = 0;
if (Keymgmt & WLAN_AKM_SUITE_8021X)
ConnInfo.FlgIs8021x = TRUE;
else
ConnInfo.FlgIs8021x = FALSE;
if (pSme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
ConnInfo.FlgIsAuthOpen = FALSE;
else
ConnInfo.FlgIsAuthOpen = TRUE;
if (Pairwise & WLAN_CIPHER_SUITE_CCMP)
ConnInfo.PairwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_CCMP;
else if (Pairwise & WLAN_CIPHER_SUITE_TKIP)
ConnInfo.PairwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_TKIP;
else if ((Pairwise & WLAN_CIPHER_SUITE_WEP40) ||
(Pairwise & WLAN_CIPHER_SUITE_WEP104))
{
ConnInfo.PairwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_WEP;
}
else
ConnInfo.PairwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_NONE;
if (Groupwise & WLAN_CIPHER_SUITE_CCMP)
ConnInfo.GroupwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_CCMP;
else if (Groupwise & WLAN_CIPHER_SUITE_TKIP)
ConnInfo.GroupwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_TKIP;
else
ConnInfo.GroupwiseEncrypType |= RT_CMD_80211_CONN_ENCRYPT_NONE;
/* End of if */
ConnInfo.pKey = (UINT8 *)(pSme->key);
ConnInfo.KeyLen = pSme->key_len;
ConnInfo.pSsid = pSme->ssid;
ConnInfo.SsidLen = pSme->ssid_len;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> SME %x\n", pSme->auth_type));
RTMP_DRIVER_80211_CONNECT(pAd, &ConnInfo);
return 0;
} /* End of CFG80211_OpsConnect */
/*
========================================================================
Routine Description:
Disconnect from the BSS/ESS.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
ReasonCode -
Return Value:
0 - success
-x - fail
Note:
For iw utility: connect
========================================================================
*/
static int CFG80211_OpsDisconnect(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN u16 ReasonCode)
{
VOID *pAd;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
CFG80211DBG(RT_DEBUG_ERROR, ("80211> ReasonCode = %d\n", ReasonCode));
MAC80211_PAD_GET(pAd, pWiphy);
RTMP_DRIVER_80211_STA_LEAVE(pAd);
return 0;
} /* End of CFG80211_OpsDisconnect */
#endif /* CONFIG_STA_SUPPORT */
#endif /* LINUX_VERSION_CODE */
#ifdef RFKILL_HW_SUPPORT
static int CFG80211_OpsRFKill(
IN struct wiphy *pWiphy)
{
VOID *pAd;
BOOLEAN active;
MAC80211_PAD_GET(pAd, pWiphy);
RTMP_DRIVER_80211_RFKILL(pAd, &active);
wiphy_rfkill_set_hw_state(pWiphy, !active);
return active;
}
VOID CFG80211_RFKillStatusUpdate(
IN PVOID pAd,
IN BOOLEAN active)
{
struct wiphy *pWiphy;
CFG80211_CB *pCfg80211_CB;
RTMP_DRIVER_80211_CB_GET(pAd, &pCfg80211_CB);
pWiphy = pCfg80211_CB->pCfg80211_Wdev->wiphy;
wiphy_rfkill_set_hw_state(pWiphy, !active);
return;
}
#endif /* RFKILL_HW_SUPPORT */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
/*
========================================================================
Routine Description:
Get site survey information.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
Idx -
pSurvey -
Return Value:
0 - success
-x - fail
Note:
For iw utility: survey dump
========================================================================
*/
static int CFG80211_OpsSurveyGet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN int Idx,
IN struct survey_info *pSurvey)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
VOID *pAd;
CMD_RTPRIV_IOCTL_80211_SURVEY SurveyInfo;
if (Idx != 0)
return -ENOENT;
/* End of if */
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
/* get information from driver */
RTMP_DRIVER_80211_SURVEY_GET(pAd, &SurveyInfo);
/* return the information to upper layer */
pSurvey->channel = ((CFG80211_CB *)(SurveyInfo.pCfg80211))->pCfg80211_Channels;
pSurvey->filled = SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
pSurvey->channel_time_busy = SurveyInfo.ChannelTimeBusy; /* unit: us */
pSurvey->channel_time_ext_busy = SurveyInfo.ChannelTimeExtBusy;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> busy time = %ld %ld\n",
(ULONG)SurveyInfo.ChannelTimeBusy,
(ULONG)SurveyInfo.ChannelTimeExtBusy));
return 0;
#else
return -ENOTSUPP;
#endif /* LINUX_VERSION_CODE */
} /* End of CFG80211_OpsSurveyGet */
/*
========================================================================
Routine Description:
Cache a PMKID for a BSSID.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
pPmksa - PMKID information
Return Value:
0 - success
-x - fail
Note:
This is mostly useful for fullmac devices running firmwares capable of
generating the (re) association RSN IE.
It allows for faster roaming between WPA2 BSSIDs.
========================================================================
*/
static int CFG80211_OpsPmksaSet(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN struct cfg80211_pmksa *pPmksa)
{
#ifdef CONFIG_STA_SUPPORT
VOID *pAd;
RT_CMD_STA_IOCTL_PMA_SA IoctlPmaSa, *pIoctlPmaSa = &IoctlPmaSa;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
if ((pPmksa->bssid == NULL) || (pPmksa->pmkid == NULL))
return -ENOENT;
/* End of if */
pIoctlPmaSa->Cmd = RT_CMD_STA_IOCTL_PMA_SA_ADD;
pIoctlPmaSa->pBssid = (UCHAR *)pPmksa->bssid;
pIoctlPmaSa->pPmkid = pPmksa->pmkid;
RTMP_DRIVER_80211_PMKID_CTRL(pAd, pIoctlPmaSa);
#endif /* CONFIG_STA_SUPPORT */
return 0;
} /* End of CFG80211_OpsPmksaSet */
/*
========================================================================
Routine Description:
Delete a cached PMKID.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
pPmksa - PMKID information
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsPmksaDel(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev,
IN struct cfg80211_pmksa *pPmksa)
{
#ifdef CONFIG_STA_SUPPORT
VOID *pAd;
RT_CMD_STA_IOCTL_PMA_SA IoctlPmaSa, *pIoctlPmaSa = &IoctlPmaSa;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
if ((pPmksa->bssid == NULL) || (pPmksa->pmkid == NULL))
return -ENOENT;
/* End of if */
pIoctlPmaSa->Cmd = RT_CMD_STA_IOCTL_PMA_SA_REMOVE;
pIoctlPmaSa->pBssid = (UCHAR *)pPmksa->bssid;
pIoctlPmaSa->pPmkid = pPmksa->pmkid;
RTMP_DRIVER_80211_PMKID_CTRL(pAd, pIoctlPmaSa);
#endif /* CONFIG_STA_SUPPORT */
return 0;
} /* End of CFG80211_OpsPmksaDel */
/*
========================================================================
Routine Description:
Flush a cached PMKID.
Arguments:
pWiphy - Wireless hardware description
pNdev - Network device interface
Return Value:
0 - success
-x - fail
Note:
========================================================================
*/
static int CFG80211_OpsPmksaFlush(
IN struct wiphy *pWiphy,
IN struct net_device *pNdev)
{
#ifdef CONFIG_STA_SUPPORT
VOID *pAd;
RT_CMD_STA_IOCTL_PMA_SA IoctlPmaSa, *pIoctlPmaSa = &IoctlPmaSa;
CFG80211DBG(RT_DEBUG_ERROR, ("80211> %s ==>\n", __FUNCTION__));
MAC80211_PAD_GET(pAd, pWiphy);
pIoctlPmaSa->Cmd = RT_CMD_STA_IOCTL_PMA_SA_FLUSH;
RTMP_DRIVER_80211_PMKID_CTRL(pAd, pIoctlPmaSa);
#endif /* CONFIG_STA_SUPPORT */
return 0;
} /* End of CFG80211_OpsPmksaFlush */
#endif /* LINUX_VERSION_CODE */
struct cfg80211_ops CFG80211_Ops = {
/* set channel for a given wireless interface */
.set_channel = CFG80211_OpsChannelSet,
/* change type/configuration of virtual interface */
.change_virtual_intf = CFG80211_OpsVirtualInfChg,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
/* request to do a scan */
/*
Note: must exist whatever AP or STA mode; Or your kernel will crash
in v2.6.38.
*/
.scan = CFG80211_OpsScan,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))
#ifdef CONFIG_STA_SUPPORT
/* join the specified IBSS (or create if necessary) */
.join_ibss = CFG80211_OpsIbssJoin,
/* leave the IBSS */
.leave_ibss = CFG80211_OpsIbssLeave,
#endif /* CONFIG_STA_SUPPORT */
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
/* set the transmit power according to the parameters */
.set_tx_power = CFG80211_OpsTxPwrSet,
/* store the current TX power into the dbm variable */
.get_tx_power = CFG80211_OpsTxPwrGet,
/* configure WLAN power management */
.set_power_mgmt = CFG80211_OpsPwrMgmt,
/* get station information for the station identified by @mac */
.get_station = CFG80211_OpsStaGet,
/* dump station callback */
.dump_station = CFG80211_OpsStaDump,
/* notify that wiphy parameters have changed */
.set_wiphy_params = CFG80211_OpsWiphyParamsSet,
/* add a key with the given parameters */
.add_key = CFG80211_OpsKeyAdd,
/* get information about the key with the given parameters */
.get_key = CFG80211_OpsKeyGet,
/* remove a key given the @mac_addr */
.del_key = CFG80211_OpsKeyDel,
/* set the default key on an interface */
.set_default_key = CFG80211_OpsKeyDefaultSet,
#ifdef CONFIG_STA_SUPPORT
/* connect to the ESS with the specified parameters */
.connect = CFG80211_OpsConnect,
/* disconnect from the BSS/ESS */
.disconnect = CFG80211_OpsDisconnect,
#endif /* CONFIG_STA_SUPPORT */
#endif /* LINUX_VERSION_CODE */
#ifdef RFKILL_HW_SUPPORT
/* polls the hw rfkill line */
.rfkill_poll = CFG80211_OpsRFKill,
#endif /* RFKILL_HW_SUPPORT */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
/* get site survey information */
.dump_survey = CFG80211_OpsSurveyGet,
/* cache a PMKID for a BSSID */
.set_pmksa = CFG80211_OpsPmksaSet,
/* delete a cached PMKID */
.del_pmksa = CFG80211_OpsPmksaDel,
/* flush all cached PMKIDs */
.flush_pmksa = CFG80211_OpsPmksaFlush,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
/*
Request the driver to remain awake on the specified
channel for the specified duration to complete an off-channel
operation (e.g., public action frame exchange).
*/
.remain_on_channel = NULL,
/* cancel an on-going remain-on-channel operation */
.cancel_remain_on_channel = NULL,
#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,34))
/* transmit an action frame */
.action = NULL,
#endif /* LINUX_VERSION_CODE */
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
/* configure connection quality monitor RSSI threshold */
.set_cqm_rssi_config = NULL,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
/* notify driver that a management frame type was registered */
.mgmt_frame_register = NULL,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
/* set antenna configuration (tx_ant, rx_ant) on the device */
.set_antenna = NULL,
/* get current antenna configuration from device (tx_ant, rx_ant) */
.get_antenna = NULL,
#endif /* LINUX_VERSION_CODE */
};
/* =========================== Global Function ============================== */
/*
========================================================================
Routine Description:
Allocate a wireless device.
Arguments:
pAd - WLAN control block pointer
pDev - Generic device interface
Return Value:
wireless device
Note:
========================================================================
*/
static struct wireless_dev *CFG80211_WdevAlloc(
IN CFG80211_CB *pCfg80211_CB,
IN CFG80211_BAND *pBandInfo,
IN VOID *pAd,
IN struct device *pDev)
{
struct wireless_dev *pWdev;
ULONG *pPriv;
/*
* We're trying to have the following memory layout:
*
* +------------------------+
* | struct wiphy |
* +------------------------+
* | pAd pointer |
* +------------------------+
*/
pWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (pWdev == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("80211> Wireless device allocation fail!\n"));
return NULL;
} /* End of if */
pWdev->wiphy = wiphy_new(&CFG80211_Ops, sizeof(ULONG *));
if (pWdev->wiphy == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("80211> Wiphy device allocation fail!\n"));
goto LabelErrWiphyNew;
} /* End of if */
/* keep pAd pointer */
pPriv = (ULONG *)(wiphy_priv(pWdev->wiphy));
*pPriv = (ULONG)pAd;
set_wiphy_dev(pWdev->wiphy, pDev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
pWdev->wiphy->max_scan_ssids = pBandInfo->MaxBssTable;
#endif /* KERNEL_VERSION */
#ifdef CONFIG_AP_SUPPORT
pWdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP);
#endif /* CONFIG_STA_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
pWdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MONITOR);
#endif /* CONFIG_STA_SUPPORT */
pWdev->wiphy->reg_notifier = CFG80211_RegNotifier;
/* init channel information */
CFG80211_SupBandInit(pCfg80211_CB, pBandInfo, pWdev->wiphy, NULL, NULL);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
/* CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm) */
pWdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
#endif /* KERNEL_VERSION */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
pWdev->wiphy->cipher_suites = CipherSuites;
pWdev->wiphy->n_cipher_suites = ARRAY_SIZE(CipherSuites);
#endif /* LINUX_VERSION_CODE */
if (wiphy_register(pWdev->wiphy) < 0)
{
DBGPRINT(RT_DEBUG_ERROR, ("80211> Register wiphy device fail!\n"));
goto LabelErrReg;
} /* End of if */
return pWdev;
LabelErrReg:
wiphy_free(pWdev->wiphy);
LabelErrWiphyNew:
os_free_mem(NULL, pWdev);
return NULL;
} /* End of CFG80211_WdevAlloc */
/*
========================================================================
Routine Description:
Register MAC80211 Module.
Arguments:
pAdCB - WLAN control block pointer
pDev - Generic device interface
pNetDev - Network device
Return Value:
NONE
Note:
pDev != pNetDev
#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev))
Can not use pNetDev to replace pDev; Or kernel panic.
========================================================================
*/
BOOLEAN CFG80211_Register(
IN VOID *pAd,
IN struct device *pDev,
IN struct net_device *pNetDev)
{
CFG80211_CB *pCfg80211_CB = NULL;
CFG80211_BAND BandInfo;
/* allocate MAC80211 structure */
os_alloc_mem(NULL, (UCHAR **)&pCfg80211_CB, sizeof(CFG80211_CB));
if (pCfg80211_CB == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("80211> Allocate MAC80211 CB fail!\n"));
return FALSE;
} /* End of if */
/* allocate wireless device */
RTMP_DRIVER_80211_BANDINFO_GET(pAd, &BandInfo);
pCfg80211_CB->pCfg80211_Wdev = \
CFG80211_WdevAlloc(pCfg80211_CB, &BandInfo, pAd, pDev);
if (pCfg80211_CB->pCfg80211_Wdev == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("80211> Allocate Wdev fail!\n"));
os_free_mem(NULL, pCfg80211_CB);
return FALSE;
} /* End of if */
/* bind wireless device with net device */
#ifdef CONFIG_AP_SUPPORT
/* default we are AP mode */
pCfg80211_CB->pCfg80211_Wdev->iftype = NL80211_IFTYPE_AP;
#endif /* CONFIG_AP_SUPPORT */
#ifdef CONFIG_STA_SUPPORT
/* default we are station mode */
pCfg80211_CB->pCfg80211_Wdev->iftype = NL80211_IFTYPE_STATION;
#endif /* CONFIG_STA_SUPPORT */
pNetDev->ieee80211_ptr = pCfg80211_CB->pCfg80211_Wdev;
SET_NETDEV_DEV(pNetDev, wiphy_dev(pCfg80211_CB->pCfg80211_Wdev->wiphy));
pCfg80211_CB->pCfg80211_Wdev->netdev = pNetDev;
#ifdef RFKILL_HW_SUPPORT
wiphy_rfkill_start_polling(pCfg80211_CB->pCfg80211_Wdev->wiphy);
#endif /* RFKILL_HW_SUPPORT */
RTMP_DRIVER_80211_CB_SET(pAd, pCfg80211_CB);
CFG80211DBG(RT_DEBUG_ERROR, ("80211> CFG80211_Register\n"));
return TRUE;
} /* End of CFG80211_Register */
/* =========================== Local Function =============================== */
/*
========================================================================
Routine Description:
The driver's regulatory notification callback.
Arguments:
pWiphy - Wireless hardware description
pRequest - Regulatory request
Return Value:
0
Note:
========================================================================
*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
static INT32 CFG80211_RegNotifier(
IN struct wiphy *pWiphy,
IN struct regulatory_request *pRequest)
{
VOID *pAd;
ULONG *pPriv;
/* sanity check */
pPriv = (ULONG *)(wiphy_priv(pWiphy));
pAd = (VOID *)(*pPriv);
if (pAd == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("crda> reg notify but pAd = NULL!"));
return 0;
} /* End of if */
/*
Change the band settings (PASS scan, IBSS allow, or DFS) in mac80211
based on EEPROM.
IEEE80211_CHAN_DISABLED: This channel is disabled.
IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
on this channel.
IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
is not permitted.
IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
is not permitted.
*/
/*
Change regulatory rule here.
struct ieee80211_channel {
enum ieee80211_band band;
u16 center_freq;
u8 max_bandwidth;
u16 hw_value;
u32 flags;
int max_antenna_gain;
int max_power;
bool beacon_found;
u32 orig_flags;
int orig_mag, orig_mpwr;
};
In mac80211 layer, it will change flags, max_antenna_gain,
max_bandwidth, max_power.
*/
switch(pRequest->initiator)
{
case NL80211_REGDOM_SET_BY_CORE:
/*
Core queried CRDA for a dynamic world regulatory domain.
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by core: "));
break;
case NL80211_REGDOM_SET_BY_USER:
/*
User asked the wireless core to set the regulatory domain.
(when iw, network manager, wpa supplicant, etc.)
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by user: "));
break;
case NL80211_REGDOM_SET_BY_DRIVER:
/*
A wireless drivers has hinted to the wireless core it thinks
its knows the regulatory domain we should be in.
(when driver initialization, calling regulatory_hint)
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by driver: "));
break;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
/*
The wireless core has received an 802.11 country information
element with regulatory information it thinks we should consider.
(when beacon receive, calling regulatory_hint_11d)
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by country IE: "));
break;
} /* End of switch */
CFG80211DBG(RT_DEBUG_ERROR,
("%c%c\n", pRequest->alpha2[0], pRequest->alpha2[1]));
/* only follow rules from user */
if (pRequest->initiator == NL80211_REGDOM_SET_BY_USER)
{
/* keep Alpha2 and we can re-call the function when interface is up */
CMD_RTPRIV_IOCTL_80211_REG_NOTIFY RegInfo;
RegInfo.Alpha2[0] = pRequest->alpha2[0];
RegInfo.Alpha2[1] = pRequest->alpha2[1];
RegInfo.pWiphy = pWiphy;
RTMP_DRIVER_80211_REG_NOTIFY(pAd, &RegInfo);
} /* End of if */
return 0;
} /* End of CFG80211_RegNotifier */
#else
static INT32 CFG80211_RegNotifier(
IN struct wiphy *pWiphy,
IN enum reg_set_by Request)
{
struct device *pDev = pWiphy->dev.parent;
struct net_device *pNetDev = dev_get_drvdata(pDev);
VOID *pAd = (VOID *)RTMP_OS_NETDEV_GET_PRIV(pNetDev);
UINT32 ReqType = Request;
/* sanity check */
if (pAd == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, ("crda> reg notify but pAd = NULL!"));
return 0;
} /* End of if */
/*
Change the band settings (PASS scan, IBSS allow, or DFS) in mac80211
based on EEPROM.
IEEE80211_CHAN_DISABLED: This channel is disabled.
IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted
on this channel.
IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.
IEEE80211_CHAN_RADAR: Radar detection is required on this channel.
IEEE80211_CHAN_NO_FAT_ABOVE: extension channel above this channel
is not permitted.
IEEE80211_CHAN_NO_FAT_BELOW: extension channel below this channel
is not permitted.
*/
/*
Change regulatory rule here.
struct ieee80211_channel {
enum ieee80211_band band;
u16 center_freq;
u8 max_bandwidth;
u16 hw_value;
u32 flags;
int max_antenna_gain;
int max_power;
bool beacon_found;
u32 orig_flags;
int orig_mag, orig_mpwr;
};
In mac80211 layer, it will change flags, max_antenna_gain,
max_bandwidth, max_power.
*/
switch(ReqType)
{
case REGDOM_SET_BY_CORE:
/*
Core queried CRDA for a dynamic world regulatory domain.
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by core: "));
break;
case REGDOM_SET_BY_USER:
/*
User asked the wireless core to set the regulatory domain.
(when iw, network manager, wpa supplicant, etc.)
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by user: "));
break;
case REGDOM_SET_BY_DRIVER:
/*
A wireless drivers has hinted to the wireless core it thinks
its knows the regulatory domain we should be in.
(when driver initialization, calling regulatory_hint)
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by driver: "));
break;
case REGDOM_SET_BY_COUNTRY_IE:
/*
The wireless core has received an 802.11 country information
element with regulatory information it thinks we should consider.
(when beacon receive, calling regulatory_hint_11d)
*/
CFG80211DBG(RT_DEBUG_ERROR, ("crda> requlation requestion by country IE: "));
break;
} /* End of switch */
DBGPRINT(RT_DEBUG_ERROR, ("00\n"));
/* only follow rules from user */
if (ReqType == REGDOM_SET_BY_USER)
{
/* keep Alpha2 and we can re-call the function when interface is up */
CMD_RTPRIV_IOCTL_80211_REG_NOTIFY RegInfo;
RegInfo.Alpha2[0] = '0';
RegInfo.Alpha2[1] = '0';
RegInfo.pWiphy = pWiphy;
RTMP_DRIVER_80211_REG_NOTIFY(pAd, &RegInfo);
} /* End of if */
return 0;
} /* End of CFG80211_RegNotifier */
#endif /* LINUX_VERSION_CODE */
#endif /* RT_CFG80211_SUPPORT */
#endif /* LINUX_VERSION_CODE */
/* End of crda.c */