diff -Nur -p linux-2.6-orig/drivers/net/wireless/Kconfig linux-2.6-libertas/drivers/net/wireless/Kconfig --- linux-2.6-orig/drivers/net/wireless/Kconfig 2006-08-06 15:20:11.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/Kconfig 2006-08-22 01:37:03.000000000 -0300 @@ -291,6 +291,19 @@ config IPW2200_DEBUG If you are not trying to debug or develop the IPW2200 driver, you most likely want to say N here. +config LIBERTAS_USB + tristate "Marvell Libertas 802.11a/b/g cards" + depends on NET_RADIO && USB + select FW_LOADER + ---help--- + A driver for Marvel Libertas USB devices. + +config LIBERTAS_USB_DEBUG + bool "Enable full debugging output in the Libertas USB module." + depends on LIBERTAS_USB + ---help--- + Debugging support. + config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/config/hostcmd.conf linux-2.6-libertas/drivers/net/wireless/libertas/config/hostcmd.conf --- linux-2.6-orig/drivers/net/wireless/libertas/config/hostcmd.conf 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/config/hostcmd.conf 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,75 @@ +# File : hostcmd.conf +# +# (c) Copyright © 2003-2006, Marvell International Ltd. +# All Rights Reserved +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available along with the File in the license.txt file or by writing to +# the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. +# + + +######################### Subscribe Events command ################## +subevent_get={ + CmdCode=0x0075 # do NOT change this line + + Action:2=0 # GET + Events:2=0 +} + +subevent_set={ + CmdCode=0x0075 # do NOT change this line + + Action:2=1 # SET + Events:2=0x3f # bit0 - RSSI_LOW; bit1 - SNR_LOW + # bit2 - FAILED_COUNT; bit3 - Beacon Missed + # bit4 - RSSI_HIGH; bit5 - SNR_HIGH + # bit6-15 reserved + + LowRssiTlvType:2=0x0104 + LowRssiTlvLength:2={ + Threshold:1=40 + ReportingFreq:1=0 + } + + LowSnrTlvType:2=0x0105 + LowSnrTlvLength:2={ + Threshold:1=56 + ReportingFreq:1=0 + } + + FailedCountTlvType:2=0x0106 + FailedCountTlvLength:2={ + Threshold:1=5 + ReportingFreq:1=0 + } + + BeaconMissTlvType:2=0x0107 + BeaconMissTlvLength:2={ + BeaconMissed:1=60 + Reserved:1=0 + } + + HighRssiTlvType:2=0x0116 + HighRssiTlvLength:2={ + Threshold:1=70 + ReportingFreq:1=0 + } + + HighSnrTlvType:2=0x0117 + HighSnrTlvLength:2={ + Threshold:1=86 + ReportingFreq:1=0 + } +} +######################### Subscribe Events command ################## + diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/hostcmd.h linux-2.6-libertas/drivers/net/wireless/libertas/hostcmd.h --- linux-2.6-orig/drivers/net/wireless/libertas/hostcmd.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/hostcmd.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,965 @@ +/* @file hostcmd.h + * + * @brief This file contains the function prototypes, data structure + * and defines for all the host/station commands + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/11/05: Add Doxygen format comments + 01/11/06: Update association struct to reflect IEEE passthrough response + Conditionalize new scan/join structures + 04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API + +********************************************************/ + +#ifndef __HOSTCMD__H +#define __HOSTCMD__H + +#include "wlan_11d.h" +#include "wlan_types.h" + +/* 802.11-related definitions */ + +/* TxPD descriptor */ +struct TxPD { + /* Current Tx packet status */ + u32 TxStatus; + /* Tx Control */ + u32 TxControl; + u32 TxPacketLocation; + /* Tx packet length */ + u16 TxPacketLength; + /* First 2 byte of destination MAC address */ + u8 TxDestAddrHigh[2]; + /* Last 4 byte of destination MAC address */ + u8 TxDestAddrLow[4]; + /* Pkt Priority */ + u8 Priority; + /* Pkt Trasnit Power control */ + u8 PowerMgmt; + /* Amount of time the packet has been queued in the driver (units = 2ms) */ + u8 PktDelay_2ms; + /* Reserved */ + u8 Reserved1; +}; + +/* RxPD Descriptor */ +struct RxPD { + /* Current Rx packet status */ + u16 Status; + + /* SNR */ + u8 SNR; + + /* Tx Control */ + u8 RxControl; + + /* Pkt Length */ + u16 PktLen; + + /* Noise Floor */ + u8 NF; + + /* Rx Packet Rate */ + u8 RxRate; + + /* Pkt addr */ + u32 PktPtr; + + /* Next Rx RxPD addr */ + u32 NextRxPDPtr; + + /* Pkt Priority */ + u8 Priority; + u8 Reserved[3]; +}; + +#if defined(__KERNEL__) + +/* CmdCtrlNode */ +struct CmdCtrlNode { + /* CMD link list */ + struct list_head list; + + u32 Status; + + /* CMD ID */ + u32 cmd_oid; + + /*CMD wait option: wait for finish or no wait */ + u16 wait_option; + + /* command parameter */ + void *pdata_buf; + + /*command data */ + u8 *BufVirtualAddr; + + u16 CmdFlags; + + /* wait queue */ + u16 CmdWaitQWoken; + wait_queue_head_t cmdwait_q; +} __attribute__ ((packed)); + +#endif + +/* MRVL_WEP_KEY */ +struct MRVL_WEP_KEY { + u32 Length; + u32 KeyIndex; + u32 KeyLength; + u8 KeyMaterial[MRVL_KEY_BUFFER_SIZE_IN_BYTE]; +}; + +/* WLAN_802_11_KEY */ +struct WLAN_802_11_KEY { + u32 Length; + u32 KeyIndex; + u32 KeyLength; + u8 BSSID[ETH_ALEN]; + unsigned long long KeyRSC; + u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH]; +} __attribute__ ((packed)); + +/* MRVL_WPA_KEY */ +struct MRVL_WPA_KEY { + u32 KeyIndex; + u32 KeyLength; + u32 KeyRSC; + u8 KeyMaterial[MRVL_MAX_KEY_WPA_KEY_LENGTH]; +}; + +/* MRVL_WLAN_WPA_KEY */ +#if 0 +// unused at the moment +struct MRVL_WLAN_WPA_KEY { + u8 EncryptionKey[16]; + u8 MICKey1[8]; + u8 MICKey2[8]; +}; +#endif + +/* IE_WPA */ +struct IE_WPA { + u8 Elementid; + u8 Len; + u8 oui[4]; + u16 version; +}; + +/* WLAN_802_11_WEP */ +#if 0 +// unused at the moment +struct WLAN_802_11_WEP { + /* Length of this structure */ + u32 Length; + + /* 0 is the per-client key, 1-N are the global keys */ + u32 KeyIndex; + + /* length of key in bytes */ + u32 KeyLength; + + /* variable length depending on above field */ + u8 KeyMaterial[1]; +} __attribute__ ((packed)); +#endif + +/* WLAN_802_11_SSID */ +struct WLAN_802_11_SSID { + /* SSID Length */ + u32 SsidLength; + + /* SSID information field */ + u8 Ssid[WLAN_MAX_SSID_LENGTH]; +}; + +struct WPA_SUPPLICANT { + u8 Wpa_ie[256]; + u8 Wpa_ie_len; +}; + +/* wlan_offset_value */ +struct wlan_offset_value { + u32 offset; + u32 value; +}; + +/* WLAN_802_11_FIXED_IEs */ +struct WLAN_802_11_FIXED_IEs { + u8 Timestamp[8]; + u16 BeaconInterval; + u16 Capabilities; +}; + +/* WLAN_802_11_VARIABLE_IEs */ +struct WLAN_802_11_VARIABLE_IEs { + u8 ElementID; + u8 Length; + u8 data[1]; +}; + +/* WLAN_802_11_AI_RESFI */ +struct WLAN_802_11_AI_RESFI { + u16 Capabilities; + u16 StatusCode; + u16 AssociationId; +}; + +/* WLAN_802_11_AI_REQFI */ +struct WLAN_802_11_AI_REQFI { + u16 Capabilities; + u16 ListenInterval; + u8 CurrentAPAddress[ETH_ALEN]; +}; + +/* Define general data structure */ +/* HostCmd_DS_GEN */ +struct HostCmd_DS_GEN { + u16 Command; + u16 Size; + u16 SeqNum; + u16 Result; +}; + +#define S_DS_GEN sizeof(struct HostCmd_DS_GEN) +/* + * Define data structure for HostCmd_CMD_GET_HW_SPEC + * This structure defines the response for the GET_HW_SPEC command + */ +/* HostCmd_DS_GET_HW_SPEC */ +struct HostCmd_DS_GET_HW_SPEC { + /* HW Interface version number */ + u16 HWIfVersion; + + /* HW version number */ + u16 Version; + + /* Max number of TxPD FW can handle */ + u16 NumOfTxPD; + + /* Max no of Multicast address */ + u16 NumOfMCastAdr; + + /* MAC address */ + u8 PermanentAddr[6]; + + /* Region Code */ + u16 RegionCode; + + /* Number of antenna used */ + u16 NumberOfAntenna; + + /* FW release number, example 0x1234=1.2.3.4 */ + u32 FWReleaseNumber; + + /* Base Address of TxPD queue */ + u32 WcbBase; + /* Read Pointer of RxPd queue */ + u32 RxPdRdPtr; + + /* Write Pointer of RxPd queue */ + u32 RxPdWrPtr; + + /*FW/HW Capability */ + u32 fwCapInfo; +} __attribute__ ((packed)); + +/* HostCmd_CMD_EEPROM_UPDATE */ +struct HostCmd_DS_EEPROM_UPDATE { + u16 Action; + u32 Value; +} __attribute__ ((packed)); + +/* HostCmd_CMD_802_11_RESET */ +struct HostCmd_DS_802_11_RESET { + u16 Action; +}; + +struct HostCmd_DS_802_11_SUBSCRIBE_EVENT { + u16 Action; + u16 Events; +}; + +/* + * This scan handle Country Information IE(802.11d compliant) + * Define data structure for HostCmd_CMD_802_11_SCAN + */ +/* HostCmd_DS_802_11_SCAN */ +struct HostCmd_DS_802_11_SCAN { + u8 BSSType; + u8 BSSID[ETH_ALEN]; + u8 TlvBuffer[1]; +#if 0 + MrvlIEtypes_SsIdParamSet_t SsIdParamSet; + MrvlIEtypes_ChanListParamSet_t ChanListParamSet; + MrvlIEtypes_RatesParamSet_t OpRateSet; +#endif +}; + +struct HostCmd_DS_802_11_SCAN_RSP { + u16 BSSDescriptSize; + u8 NumberOfSets; + u8 BssDescAndTlvBuffer[1]; +}; + +/* HostCmd_CMD_802_11_GET_LOG */ +struct HostCmd_DS_802_11_GET_LOG { + u32 mcasttxframe; + u32 failed; + u32 retry; + u32 multiretry; + u32 framedup; + u32 rtssuccess; + u32 rtsfailure; + u32 ackfailure; + u32 rxfrag; + u32 mcastrxframe; + u32 fcserror; + u32 txframe; + u32 wepundecryptable; +}; + +/* HostCmd_CMD_MAC_CONTROL */ +struct HostCmd_DS_MAC_CONTROL { + u16 Action; + u16 Reserved; +}; + +/* HostCmd_CMD_MAC_MULTICAST_ADR */ +struct HostCmd_DS_MAC_MULTICAST_ADR { + u16 Action; + u16 NumOfAdrs; + u8 MACList[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; +}; + +/* HostCmd_CMD_802_11_AUTHENTICATE */ +struct HostCmd_DS_802_11_AUTHENTICATE { + u8 MacAddr[ETH_ALEN]; + u8 AuthType; + u8 Reserved[10]; +}; + +/* HostCmd_RET_802_11_AUTHENTICATE */ +struct HostCmd_DS_802_11_AUTHENTICATE_RSP { + u8 MacAddr[6]; + u8 AuthType; + u8 AuthStatus; +}; + +/* HostCmd_CMD_802_11_DEAUTHENTICATE */ +struct HostCmd_DS_802_11_DEAUTHENTICATE { + u8 MacAddr[6]; + u16 ReasonCode; +}; + +/* HostCmd_DS_802_11_ASSOCIATE */ +struct HostCmd_DS_802_11_ASSOCIATE { + u8 PeerStaAddr[6]; + struct IEEEtypes_CapInfo CapInfo; + u16 ListenInterval; + u16 BcnPeriod; + u8 DtimPeriod; + +#if 0 + MrvlIEtypes_SsIdParamSet_t SsIdParamSet; + MrvlIEtypes_PhyParamSet_t PhyParamSet; + MrvlIEtypes_SsParamSet_t SsParamSet; + MrvlIEtypes_RatesParamSet_t RatesParamSet; +#endif +} __attribute__ ((packed)); + +/* HostCmd_CMD_802_11_DISASSOCIATE */ +struct HostCmd_DS_802_11_DISASSOCIATE { + u8 DestMacAddr[6]; + u16 ReasonCode; +}; + +/* HostCmd_RET_802_11_ASSOCIATE */ +struct HostCmd_DS_802_11_ASSOCIATE_RSP { + struct IEEEtypes_AssocRsp assocRsp; +} __attribute__ ((packed)); + +/* HostCmd_RET_802_11_AD_HOC_JOIN */ +struct HostCmd_DS_802_11_AD_HOC_RESULT { + u8 PAD[3]; + u8 BSSID[ETH_ALEN]; +}; + +/* HostCmd_CMD_802_11_SET_WEP */ +struct HostCmd_DS_802_11_SET_WEP { + /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ + u16 Action; + + /* Key Index selected for Tx */ + u16 KeyIndex; + + /* 40, 128bit or TXWEP */ + u8 WEPTypeForKey1; + + u8 WEPTypeForKey2; + u8 WEPTypeForKey3; + u8 WEPTypeForKey4; + u8 WEP1[16]; + u8 WEP2[16]; + u8 WEP3[16]; + u8 WEP4[16]; +}; + +/* HostCmd_CMD_802_3_GET_STAT */ +struct HostCmd_DS_802_3_GET_STAT { + u32 XmitOK; + u32 RcvOK; + u32 XmitError; + u32 RcvError; + u32 RcvNoBuffer; + u32 RcvCRCError; +}; + +/* HostCmd_CMD_802_11_GET_STAT */ +struct HostCmd_DS_802_11_GET_STAT { + u32 TXFragmentCnt; + u32 MCastTXFrameCnt; + u32 FailedCnt; + u32 RetryCnt; + u32 MultipleRetryCnt; + u32 RTSSuccessCnt; + u32 RTSFailureCnt; + u32 ACKFailureCnt; + u32 FrameDuplicateCnt; + u32 RXFragmentCnt; + u32 MCastRXFrameCnt; + u32 FCSErrorCnt; + u32 BCastTXFrameCnt; + u32 BCastRXFrameCnt; + u32 TXBeacon; + u32 RXBeacon; + u32 WEPUndecryptable; +}; + +/* HostCmd_DS_802_11_AD_HOC_STOP */ +/* wtf? -- pjones */ +struct HostCmd_DS_802_11_AD_HOC_STOP { + +}; + +/* HostCmd_DS_802_11_BEACON_STOP */ +/* wtf? -- pjones */ +struct HostCmd_DS_802_11_BEACON_STOP { + +}; + +/* HostCmd_CMD_802_11_SNMP_MIB */ +struct HostCmd_DS_802_11_SNMP_MIB { + u16 QueryType; + u16 OID; + u16 BufSize; + u8 Value[128]; +}; + +/* HostCmd_CMD_MAC_REG_MAP */ +struct HostCmd_DS_MAC_REG_MAP { + u16 BufferSize; + u8 RegMap[128]; + u16 Reserved; +}; + +/* HostCmd_CMD_BBP_REG_MAP */ +struct HostCmd_DS_BBP_REG_MAP { + u16 BufferSize; + u8 RegMap[128]; + u16 Reserved; +}; + +/* HostCmd_CMD_RF_REG_MAP */ +struct HostCmd_DS_RF_REG_MAP { + u16 BufferSize; + u8 RegMap[64]; + u16 Reserved; +}; + +/* HostCmd_CMD_MAC_REG_ACCESS */ +struct HostCmd_DS_MAC_REG_ACCESS { + u16 Action; + u16 Offset; + u32 Value; +}; + +/* HostCmd_CMD_BBP_REG_ACCESS */ +struct HostCmd_DS_BBP_REG_ACCESS { + u16 Action; + u16 Offset; + u8 Value; + u8 Reserved[3]; +}; + +/* HostCmd_CMD_RF_REG_ACCESS */ +struct HostCmd_DS_RF_REG_ACCESS { + u16 Action; + u16 Offset; + u8 Value; + u8 Reserved[3]; +}; + +/* HostCmd_CMD_802_11_RADIO_CONTROL */ +struct HostCmd_DS_802_11_RADIO_CONTROL { + u16 Action; + u16 Control; +}; + +/* HostCmd_DS_802_11_SLEEP_PARAMS */ +struct HostCmd_DS_802_11_SLEEP_PARAMS { + /* ACT_GET/ACT_SET */ + u16 Action; + + /* Sleep clock error in ppm */ + u16 Error; + + /* Wakeup offset in usec */ + u16 Offset; + + /* Clock stabilization time in usec */ + u16 StableTime; + + /* Control periodic calibration */ + u8 CalControl; + + /* Control the use of external sleep clock */ + u8 ExternalSleepClk; + + /* Reserved field, should be set to zero */ + u16 Reserved; +}; + +/* HostCmd_DS_802_11_SLEEP_PERIOD */ +struct HostCmd_DS_802_11_SLEEP_PERIOD { + /* ACT_GET/ACT_SET */ + u16 Action; + + /* Sleep Period in msec */ + u16 Period; +}; + +/* HostCmd_DS_802_11_INACTIVITY_TIMEOUT */ +struct HostCmd_DS_802_11_INACTIVITY_TIMEOUT { + /* ACT_GET/ACT_SET */ + u16 Action; + + /* Inactivity timeout in msec */ + u16 Timeout; +}; + +/* HostCmd_CMD_802_11_RF_CHANNEL */ +struct HostCmd_DS_802_11_RF_CHANNEL { + u16 Action; + u16 CurrentChannel; + u16 RFType; + u16 Reserved; + u8 ChannelList[32]; +}; + +/* HostCmd_CMD_802_11_RSSI */ +struct HostCmd_DS_802_11_RSSI { + /* weighting factor */ + u16 N; + + u16 Reserved_0; + u16 Reserved_1; + u16 Reserved_2; +}; + +/* HostCmd_DS_802_11_RSSI_RSP */ +struct HostCmd_DS_802_11_RSSI_RSP { + u16 SNR; + u16 NoiseFloor; + u16 AvgSNR; + u16 AvgNoiseFloor; +}; + +/* HostCmd_DS_802_11_MAC_ADDRESS */ +struct HostCmd_DS_802_11_MAC_ADDRESS { + u16 Action; + u8 MacAdd[ETH_ALEN]; +}; + +/* HostCmd_CMD_802_11_RF_TX_POWER */ +struct HostCmd_DS_802_11_RF_TX_POWER { + u16 Action; + u16 CurrentLevel; +}; + +/* HostCmd_CMD_802_11_RF_ANTENNA */ +struct HostCmd_DS_802_11_RF_ANTENNA { + u16 Action; + + /* Number of antennas or 0xffff(diversity) */ + u16 AntennaMode; + +}; + +/* HostCmd_CMD_802_11_PS_MODE */ +struct HostCmd_DS_802_11_PS_MODE { + u16 Action; + u16 NullPktInterval; + u16 MultipleDtim; + u16 Reserved; + u16 LocalListenInterval; +}; + +/* PS_CMD_ConfirmSleep */ +struct PS_CMD_ConfirmSleep { + u16 Command; + u16 Size; + u16 SeqNum; + u16 Result; + + u16 Action; + u16 Reserved1; + u16 MultipleDtim; + u16 Reserved; + u16 LocalListenInterval; +}; + +/* HostCmd_CMD_802_11_DATA_RATE */ +struct HostCmd_DS_802_11_DATA_RATE { + u16 Action; + u16 Reserverd; + u8 DataRate[HOSTCMD_SUPPORTED_RATES]; +}; + +/* HostCmd_DS_802_11_RATE_ADAPT_RATESET */ +struct HostCmd_DS_802_11_RATE_ADAPT_RATESET { + u16 Action; + u16 EnableHwAuto; + u16 Bitmap; +}; + +/* HostCmd_DS_802_11_AD_HOC_START*/ +struct HostCmd_DS_802_11_AD_HOC_START { + u8 SSID[MRVDRV_MAX_SSID_LENGTH]; + u8 BSSType; + u16 BeaconPeriod; + u8 DTIMPeriod; + union IEEEtypes_SsParamSet SsParamSet; + union IEEEtypes_PhyParamSet PhyParamSet; + u16 ProbeDelay; + struct IEEEtypes_CapInfo Cap; + u8 DataRate[HOSTCMD_SUPPORTED_RATES]; + u8 tlv_memory_size_pad[100]; +} __attribute__ ((packed)); + +/* AdHoc_BssDesc_t */ +struct AdHoc_BssDesc { + u8 BSSID[6]; + u8 SSID[32]; + u8 BSSType; + u16 BeaconPeriod; + u8 DTIMPeriod; + u8 TimeStamp[8]; + u8 LocalTime[8]; + union IEEEtypes_PhyParamSet PhyParamSet; + union IEEEtypes_SsParamSet SsParamSet; + struct IEEEtypes_CapInfo Cap; + u8 DataRates[HOSTCMD_SUPPORTED_RATES]; + + /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + * Adhoc join command and will cause a binary layout mismatch with + * the firmware + */ +} __attribute__ ((packed)); + +/* HostCmd_DS_802_11_AD_HOC_JOIN */ +struct HostCmd_DS_802_11_AD_HOC_JOIN { + struct AdHoc_BssDesc BssDescriptor; + u16 FailTimeOut; + u16 ProbeDelay; + +} __attribute__ ((packed)); + +/* HostCmd_DS_802_11_ENABLE_RSN */ +struct HostCmd_DS_802_11_ENABLE_RSN { + u16 Action; + u16 Enable; +}; + +/* HostCmd_DS_802_11_QUERY_TKIP_REPLY_CNTRS */ +struct HostCmd_DS_802_11_QUERY_TKIP_REPLY_CNTRS { + u16 CmdCode; + u16 Size; + u16 SeqNum; + u16 Result; + u32 NumTkipCntrs; +}; + +/* HostCmd_DS_802_11_PAIRWISE_TSC */ +struct HostCmd_DS_802_11_PAIRWISE_TSC { + u16 CmdCode; + u16 Size; + u16 SeqNum; + u16 Result; + u16 Action; + u32 Txlv32; + u16 Txlv16; +}; + +/* HostCmd_DS_802_11_GROUP_TSC */ +struct HostCmd_DS_802_11_GROUP_TSC { + u16 CmdCode; + u16 Size; + u16 SeqNum; + u16 Result; + u16 Action; + u32 Txlv32; + u16 Txlv16; +}; + +#if 0 +union KeyInfo_WEP_t { + u8 Reserved; + + /* bits 1-4: Specifies the index of key */ + u8 WepKeyIndex; + + /* bit 0: Specifies that this key is + * to be used as the default for TX data packets */ + u8 isWepDefaultKey; +}; + +union KeyInfo_TKIP_t { + u8 Reserved; + + /* bit 2: Specifies that this key is + * enabled and valid to use */ + u8 isKeyEnabled; + + /* bit 1: Specifies that this key is + * to be used as the unicast key */ + u8 isUnicastKey; + + /* bit 0: Specifies that this key is + * to be used as the multicast key */ + u8 isMulticastKey; +}; + +union KeyInfo_AES_t { + u8 Reserved; + + /* bit 2: Specifies that this key is + * enabled and valid to use */ + u8 isKeyEnabled; + + /* bit 1: Specifies that this key is + * to be used as the unicast key */ + u8 isUnicastKey; + + /* bit 0: Specifies that this key is + * to be used as the multicast key */ + u8 isMulticastKey; +} KeyInfo_AES_t; + +/* KeyMaterial_TKIP_t */ +struct KeyMaterial_TKIP_t { + /* TKIP encryption/decryption key */ + u8 TkipKey[16]; + + /* TKIP TX MIC Key */ + u8 TkipTxMicKey[16]; + + /* TKIP RX MIC Key */ + u8 TkipRxMicKey[16]; +}; + +/* KeyMaterial_AES_t */ +struct KeyMaterial_AES_t { + /* AES encryption/decryption key */ + u8 AesKey[16]; +}; +#endif + +/* MrvlIEtype_KeyParamSet_t */ +struct MrvlIEtype_KeyParamSet { + /* Type ID */ + u16 Type; + + /* Length of Payload */ + u16 Length; + + /* Type of Key: WEP=0, TKIP=1, AES=2 */ + u16 KeyTypeId; + + /* Key Control Info specific to a KeyTypeId */ + u16 KeyInfo; + + /* Length of key */ + u16 KeyLen; + + /* Key material of size KeyLen */ + u8 Key[32]; +}; + +/* HostCmd_DS_802_11_KEY_MATERIAL */ +struct HostCmd_DS_802_11_KEY_MATERIAL { + u16 Action; + struct MrvlIEtype_KeyParamSet KeyParamSet; +} __attribute__ ((packed)); + +/* HostCmd_DS_802_11_EEPROM_ACCESS */ +struct HostCmd_DS_802_11_EEPROM_ACCESS { + u16 Action; + + /* multiple 4 */ + u16 Offset; + u16 ByteCount; + u8 Value; +} __attribute__ ((packed)); + +/* HostCmd_DS_802_11_TPC_CFG */ +struct HostCmd_DS_802_11_TPC_CFG { + u16 Action; + u8 Enable; + s8 P0; + s8 P1; + s8 P2; + u8 UseSNR; +} __attribute__ ((packed)); + +/* HostCmd_DS_802_11_LED_CTRL */ +struct HostCmd_DS_802_11_LED_CTRL { + u16 Action; + u16 NumLed; + u8 data[256]; +} __attribute__ ((packed)); + +/** HostCmd_DS_802_11_PWR_CFG */ +struct HostCmd_DS_802_11_PWR_CFG { + u16 Action; + u8 Enable; + s8 PA_P0; + s8 PA_P1; + s8 PA_P2; +} __attribute__ ((packed)); + +/* HostCmd_DS_802_11_AFC */ +struct HostCmd_DS_802_11_AFC { + u16 afc_auto; + union { + struct { + u16 threshold; + u16 period; + } auto_mode; + struct { + s16 timing_offset; + s16 carrier_offset; + } manual_mode; + } b; +} __attribute__ ((packed)); + +#define afc_data b.data +#define afc_thre b.auto_mode.threshold +#define afc_period b.auto_mode.period +#define afc_toff b.manual_mode.timing_offset +#define afc_foff b.manual_mode.carrier_offset + +struct HostCmd_TX_RATE_QUERY { + u16 TxRate; +} __attribute__ ((packed)); + +struct HostCmd_DS_GET_TSF { + u64 TsfValue; +} __attribute__ ((packed)); + +/* HostCmd_CMD_DFT_ACCESS */ +struct HostCmd_DS_DFT_ACCESS { + u16 action; + u32 id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; +} __attribute__ ((packed)); + +/* HostCmd_DS_COMMAND */ +struct HostCmd_DS_COMMAND { + /* Command Header */ + u16 Command; + u16 Size; + u16 SeqNum; + u16 Result; + + /* Command Body */ + union { + struct HostCmd_DS_GET_HW_SPEC hwspec; + struct HostCmd_DS_802_11_PS_MODE psmode; + struct HostCmd_DS_802_11_SCAN scan; + struct HostCmd_DS_802_11_SCAN_RSP scanresp; + struct HostCmd_DS_MAC_CONTROL macctrl; + struct HostCmd_DS_802_11_ASSOCIATE associate; + struct HostCmd_DS_802_11_ASSOCIATE_RSP associatersp; + struct HostCmd_DS_802_11_DEAUTHENTICATE deauth; + struct HostCmd_DS_802_11_SET_WEP wep; + struct HostCmd_DS_802_11_AD_HOC_START ads; + struct HostCmd_DS_802_11_RESET reset; + struct HostCmd_DS_802_11_AD_HOC_RESULT result; + struct HostCmd_DS_802_11_GET_LOG glog; + struct HostCmd_DS_802_11_AUTHENTICATE auth; + struct HostCmd_DS_802_11_AUTHENTICATE_RSP rauth; + struct HostCmd_DS_802_11_GET_STAT gstat; + struct HostCmd_DS_802_3_GET_STAT gstat_8023; + struct HostCmd_DS_802_11_SNMP_MIB smib; + struct HostCmd_DS_802_11_RF_TX_POWER txp; + struct HostCmd_DS_802_11_RF_ANTENNA rant; + struct HostCmd_DS_802_11_DATA_RATE drate; + struct HostCmd_DS_802_11_RATE_ADAPT_RATESET rateset; + struct HostCmd_DS_MAC_MULTICAST_ADR madr; + struct HostCmd_DS_802_11_AD_HOC_JOIN adj; + struct HostCmd_DS_802_11_RADIO_CONTROL radio; + struct HostCmd_DS_802_11_RF_CHANNEL rfchannel; + struct HostCmd_DS_802_11_RSSI rssi; + struct HostCmd_DS_802_11_RSSI_RSP rssirsp; + struct HostCmd_DS_802_11_DISASSOCIATE dassociate; + struct HostCmd_DS_802_11_AD_HOC_STOP adhoc_stop; + struct HostCmd_DS_802_11_MAC_ADDRESS macadd; + struct HostCmd_DS_802_11_ENABLE_RSN enbrsn; + struct HostCmd_DS_802_11_KEY_MATERIAL keymaterial; + struct HostCmd_DS_MAC_REG_ACCESS macreg; + struct HostCmd_DS_BBP_REG_ACCESS bbpreg; + struct HostCmd_DS_RF_REG_ACCESS rfreg; + struct HostCmd_DS_802_11_BEACON_STOP beacon_stop; + struct HostCmd_DS_802_11_EEPROM_ACCESS rdeeprom; + + struct HostCmd_DS_802_11D_DOMAIN_INFO domaininfo; + struct HostCmd_DS_802_11D_DOMAIN_INFO_RSP domaininforesp; + + struct HostCmd_DS_802_11_SLEEP_PARAMS sleep_params; + struct HostCmd_DS_802_11_INACTIVITY_TIMEOUT inactivity_timeout; + struct HostCmd_DS_802_11_SLEEP_PERIOD ps_sleeppd; + struct HostCmd_DS_802_11_TPC_CFG tpccfg; + struct HostCmd_DS_802_11_PWR_CFG pwrcfg; + struct HostCmd_DS_802_11_AFC afc; + struct HostCmd_DS_802_11_LED_CTRL ledgpio; + + struct HostCmd_TX_RATE_QUERY txrate; + struct HostCmd_DS_DFT_ACCESS dft; + struct HostCmd_DS_GET_TSF gettsf; + } params; +} __attribute__ ((packed)); + +#endif diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/host.h linux-2.6-libertas/drivers/net/wireless/libertas/host.h --- linux-2.6-orig/drivers/net/wireless/libertas/host.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/host.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,460 @@ +/** @file host.h + * + * @brief This file contains definitions of WLAN commands. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/11/05: Add Doxygen format comments + 01/11/06: Remove assoc response codes; full IEEE assoc resp now returned + 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support + 04/10/06: Add power_adapt_cfg_ext command + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API +********************************************************/ + +#ifndef _HOST_H_ +#define _HOST_H_ + +/** PUBLIC DEFINITIONS */ +#define DEFAULT_CHANNEL 1 +#define DEFAULT_CHANNEL_A 36 +#define DEFAULT_AD_HOC_CHANNEL 6 +#define DEFAULT_AD_HOC_CHANNEL_A 36 + +/** IEEE 802.11 OIDs */ +#define OID_802_11_BSSID 0x00008001 +#define OID_802_11_SSID 0x00008002 +#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x00008003 +#define OID_802_11_NETWORK_TYPE_IN_USE 0x00008004 +#define OID_802_11_RSSI 0x00008006 +#define OID_802_11_RSSI_TRIGGER 0x00008007 +#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 +#define OID_802_11_RTS_THRESHOLD 0x0000800A +#define OID_802_11_NUMBER_OF_ANTENNAS 0x0000800B +#define OID_802_11_RX_ANTENNA_SELECTED 0x0000800C +#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D +#define OID_802_11_SUPPORTED_RATES 0x0000800E +#define OID_802_11_DESIRED_RATES 0x00008010 +#define OID_802_11_CONFIGURATION 0x00008011 +#define OID_802_11_STATISTICS 0x00008012 +#define OID_802_11_ADD_WEP 0x00008013 +#define OID_802_11_REMOVE_WEP 0x00008014 +#define OID_802_11_DISASSOCIATE 0x00008015 +#define OID_802_11_POWER_MODE 0x00008016 +#define OID_802_11_BSSID_LIST 0x00008017 +#define OID_802_11_AUTHENTICATION_MODE 0x00008018 +#define OID_802_11_PRIVACY_FILTER 0x00008019 +#define OID_802_11_BSSID_LIST_SCAN 0x0000801A +#define OID_802_11_WEP_STATUS 0x0000801B +#define OID_802_11_RELOAD_DEFAULTS 0x0000801C +#define OID_802_11_TX_RETRYCOUNT 0x0000801D +#define OID_802_11D_ENABLE 0x00008020 + +/** Marvel specific OIDs */ +#define OID_MRVL_OEM_GET_ULONG 0xff010201 +#define OID_MRVL_OEM_SET_ULONG 0xff010202 +#define OID_MRVL_OEM_GET_STRING 0xff010203 +#define OID_MRVL_OEM_COMMAND 0xff010204 + +/** Command Processing States and Options */ +#define HostCmd_STATE_IDLE 0x0000 +#define HostCmd_STATE_IN_USE_BY_HOST 0x0001 +#define HostCmd_STATE_IN_USE_BY_MINIPORT 0x0002 +#define HostCmd_STATE_FINISHED 0x000f + +#define HostCmd_Q_NONE 0x0000 +#define HostCmd_Q_INIT 0x0001 +#define HostCmd_Q_RESET 0x0002 +#define HostCmd_Q_STAT 0x0003 + +#define HostCmd_OPTION_WAITFORRSP 0x0002 + +/* 512 usec */ +#define HostCmd_DELAY_NORMAL 0x00000200 +/* 256 usec */ +#define HostCmd_DELAY_MIN 0x00000100 +/* 1024 usec */ +#define HostCmd_DELAY_MAX 0x00000400 + +/** Host Command ID */ +#define HostCmd_CMD_NONE 0x0000 +#define HostCmd_CMD_CODE_DNLD 0x0002 +#define HostCmd_CMD_GET_HW_SPEC 0x0003 +#define HostCmd_CMD_EEPROM_UPDATE 0x0004 +#define HostCmd_CMD_802_11_RESET 0x0005 +#define HostCmd_CMD_802_11_SCAN 0x0006 +#define HostCmd_CMD_802_11_GET_LOG 0x000b +#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010 +#define HostCmd_CMD_802_11_AUTHENTICATE 0x0011 +#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 +#define HostCmd_CMD_802_11_ASSOCIATE 0x0050 +#define HostCmd_CMD_802_11_SET_WEP 0x0013 +#define HostCmd_CMD_802_11_GET_STAT 0x0014 +#define HostCmd_CMD_802_3_GET_STAT 0x0015 +#define HostCmd_CMD_802_11_SNMP_MIB 0x0016 +#define HostCmd_CMD_MAC_REG_MAP 0x0017 +#define HostCmd_CMD_BBP_REG_MAP 0x0018 +#define HostCmd_CMD_MAC_REG_ACCESS 0x0019 +#define HostCmd_CMD_BBP_REG_ACCESS 0x001a +#define HostCmd_CMD_RF_REG_ACCESS 0x001b +#define HostCmd_CMD_802_11_RADIO_CONTROL 0x001c +#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d +#define HostCmd_CMD_802_11_RF_TX_POWER 0x001e +#define HostCmd_CMD_802_11_RSSI 0x001f +#define HostCmd_CMD_802_11_RF_ANTENNA 0x0020 + +#define HostCmd_CMD_802_11_PS_MODE 0x0021 + +#define HostCmd_CMD_802_11_DATA_RATE 0x0022 +#define HostCmd_CMD_RF_REG_MAP 0x0023 +#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 +#define HostCmd_CMD_802_11_REASSOCIATE 0x0025 +#define HostCmd_CMD_802_11_DISASSOCIATE 0x0026 +#define HostCmd_CMD_MAC_CONTROL 0x0028 +#define HostCmd_CMD_802_11_AD_HOC_START 0x002b +#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c + +#define HostCmd_CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e +#define HostCmd_CMD_802_11_ENABLE_RSN 0x002f +#define HostCmd_CMD_802_11_PAIRWISE_TSC 0x0036 +#define HostCmd_CMD_802_11_GROUP_TSC 0x0037 +#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e + +#define HostCmd_CMD_802_11_SET_AFC 0x003c +#define HostCmd_CMD_802_11_GET_AFC 0x003d + +#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040 + +#define HostCmd_CMD_802_11_BEACON_STOP 0x0049 + +#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D +#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059 + +#define HostCmd_CMD_802_11_BAND_CONFIG 0x0058 + +#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b + +#define HostCmd_CMD_802_11_SLEEP_PARAMS 0x0066 + +#define HostCmd_CMD_802_11_INACTIVITY_TIMEOUT 0x0067 + +#define HostCmd_CMD_802_11_SLEEP_PERIOD 0x0068 + +#define HostCmd_CMD_802_11_TPC_CFG 0x0072 +#define HostCmd_CMD_802_11_PWR_CFG 0x0073 + +#define HostCmd_CMD_802_11_LED_GPIO_CTRL 0x004e + +#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 + +#define HostCmd_CMD_802_11_RATE_ADAPT_RATESET 0x0076 + +#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f + +#define HostCmd_CMD_GET_TSF 0x0080 + +#define HostCmd_CMD_DFT_ACCESS 0x0087 +#define HostCmd_RET_DFT_ACCESS 0x8087 + +/* For the IEEE Power Save */ +#define HostCmd_SubCmd_Enter_PS 0x0030 +#define HostCmd_SubCmd_Exit_PS 0x0031 +#define HostCmd_SubCmd_Sleep_Confirmed 0x0034 +#define HostCmd_SubCmd_Full_PowerDown 0x0035 +#define HostCmd_SubCmd_Full_PowerUp 0x0036 + +/* Command RET code, MSB is set to 1 */ +#define HostCmd_RET_NONE 0x8000 +#define HostCmd_RET_HW_SPEC_INFO 0x8003 +#define HostCmd_RET_EEPROM_UPDATE 0x8004 +#define HostCmd_RET_802_11_RESET 0x8005 +#define HostCmd_RET_802_11_SCAN 0x8006 +#define HostCmd_RET_802_11_GET_LOG 0x800b +#define HostCmd_RET_MAC_CONTROL 0x8028 +#define HostCmd_RET_MAC_MULTICAST_ADR 0x8010 +#define HostCmd_RET_802_11_AUTHENTICATE 0x8011 +#define HostCmd_RET_802_11_DEAUTHENTICATE 0x8024 +#define HostCmd_RET_802_11_ASSOCIATE 0x8012 +#define HostCmd_RET_802_11_REASSOCIATE 0x8025 +#define HostCmd_RET_802_11_DISASSOCIATE 0x8026 +#define HostCmd_RET_802_11_SET_WEP 0x8013 +#define HostCmd_RET_802_11_STAT 0x8014 +#define HostCmd_RET_802_3_STAT 0x8015 +#define HostCmd_RET_802_11_SNMP_MIB 0x8016 +#define HostCmd_RET_MAC_REG_MAP 0x8017 +#define HostCmd_RET_BBP_REG_MAP 0x8018 +#define HostCmd_RET_RF_REG_MAP 0x8023 +#define HostCmd_RET_MAC_REG_ACCESS 0x8019 +#define HostCmd_RET_BBP_REG_ACCESS 0x801a +#define HostCmd_RET_RF_REG_ACCESS 0x801b +#define HostCmd_RET_802_11_RADIO_CONTROL 0x801c +#define HostCmd_RET_802_11_RF_CHANNEL 0x801d +#define HostCmd_RET_802_11_RSSI 0x801f +#define HostCmd_RET_802_11_RF_TX_POWER 0x801e +#define HostCmd_RET_802_11_RF_ANTENNA 0x8020 +#define HostCmd_RET_802_11_PS_MODE 0x8021 +#define HostCmd_RET_802_11_DATA_RATE 0x8022 + +#define HostCmd_RET_802_11_AD_HOC_START 0x802B +#define HostCmd_RET_802_11_AD_HOC_JOIN 0x802C + +#define HostCmd_RET_802_11_QUERY_TKIP_REPLY_CNTRS 0x802e +#define HostCmd_RET_802_11_ENABLE_RSN 0x802f +#define HostCmd_RET_802_11_PAIRWISE_TSC 0x8036 +#define HostCmd_RET_802_11_GROUP_TSC 0x8037 +#define HostCmd_RET_802_11_KEY_MATERIAL 0x805e + +#define HostCmd_ENABLE_RSN 0x0001 +#define HostCmd_DISABLE_RSN 0x0000 +#define TYPE_ANTENNA_DIVERSITY 0xffff + +#define HostCmd_ACT_SET 0x0001 +#define HostCmd_ACT_GET 0x0000 + +#define HostCmd_ACT_GET_AES (HostCmd_ACT_GET + 2) +#define HostCmd_ACT_SET_AES (HostCmd_ACT_SET + 2) +#define HostCmd_ACT_REMOVE_AES (HostCmd_ACT_SET + 3) + +#define HostCmd_RET_802_11_SET_AFC 0x803c +#define HostCmd_RET_802_11_GET_AFC 0x803d + +#define HostCmd_RET_802_11_AD_HOC_STOP 0x8040 + +#define HostCmd_RET_802_11_BEACON_STOP 0x8049 + +#define HostCmd_RET_802_11_MAC_ADDRESS 0x804D +#define HostCmd_RET_802_11_EEPROM_ACCESS 0x8059 + +#define HostCmd_RET_802_11_BAND_CONFIG 0x8058 + +#define HostCmd_RET_802_11_SLEEP_PARAMS 0x8066 + +#define HostCmd_RET_802_11_INACTIVITY_TIMEOUT 0x8067 + +#define HostCmd_RET_802_11_SLEEP_PERIOD 0x8068 + +#define HostCmd_RET_802_11D_DOMAIN_INFO (0x8000 | \ + HostCmd_CMD_802_11D_DOMAIN_INFO) + +#define HostCmd_RET_802_11_TPC_CFG (HostCmd_CMD_802_11_TPC_CFG | 0x8000) +#define HostCmd_RET_802_11_PWR_CFG (HostCmd_CMD_802_11_PWR_CFG | 0x8000) + +#define HostCmd_RET_802_11_LED_GPIO_CTRL 0x804e + +#define HostCmd_RET_802_11_SUBSCRIBE_EVENT (HostCmd_CMD_802_11_SUBSCRIBE_EVENT | 0x8000) + +#define HostCmd_RET_802_11_RATE_ADAPT_RATESET (HostCmd_CMD_802_11_RATE_ADAPT_RATESET | 0x8000) + +#define HostCmd_RTE_802_11_TX_RATE_QUERY (HostCmd_CMD_802_11_TX_RATE_QUERY | 0x8000) + +#define HostCmd_RET_GET_TSF 0x8080 + +/** General Result Code*/ +/* OK */ +#define HostCmd_RESULT_OK 0x0000 +/* Genenral error */ +#define HostCmd_RESULT_ERROR 0x0001 +/* Command is not valid */ +#define HostCmd_RESULT_NOT_SUPPORT 0x0002 +/* Command is pending */ +#define HostCmd_RESULT_PENDING 0x0003 +/* System is busy (command ignored) */ +#define HostCmd_RESULT_BUSY 0x0004 +/* Data buffer is not big enough */ +#define HostCmd_RESULT_PARTIAL_DATA 0x0005 + +/* Definition of action or option for each command */ + +/* Define general purpose action */ +#define HostCmd_ACT_GEN_READ 0x0000 +#define HostCmd_ACT_GEN_WRITE 0x0001 +#define HostCmd_ACT_GEN_GET 0x0000 +#define HostCmd_ACT_GEN_SET 0x0001 +#define HostCmd_ACT_GEN_REMOVE 0x0002 +#define HostCmd_ACT_GEN_OFF 0x0000 +#define HostCmd_ACT_GEN_ON 0x0001 + +/* Define action or option for HostCmd_CMD_802_11_AUTHENTICATE */ +#define HostCmd_ACT_AUTHENTICATE 0x0001 +#define HostCmd_ACT_DEAUTHENTICATE 0x0002 + +/* Define action or option for HostCmd_CMD_802_11_ASSOCIATE */ +#define HostCmd_ACT_ASSOCIATE 0x0001 +#define HostCmd_ACT_DISASSOCIATE 0x0002 +#define HostCmd_ACT_REASSOCIATE 0x0003 + +#define HostCmd_CAPINFO_ESS 0x0001 +#define HostCmd_CAPINFO_IBSS 0x0002 +#define HostCmd_CAPINFO_CF_POLLABLE 0x0004 +#define HostCmd_CAPINFO_CF_REQUEST 0x0008 +#define HostCmd_CAPINFO_PRIVACY 0x0010 + +/* Define action or option for HostCmd_CMD_802_11_SET_WEP */ +#define HostCmd_ACT_ADD 0x0002 +#define HostCmd_ACT_REMOVE 0x0004 +#define HostCmd_ACT_USE_DEFAULT 0x0008 + +#define HostCmd_TYPE_WEP_40_BIT 0x0001 +#define HostCmd_TYPE_WEP_104_BIT 0x0002 + +#define HostCmd_NUM_OF_WEP_KEYS 4 + +#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff + +/* Define action or option for HostCmd_CMD_802_11_RESET */ +#define HostCmd_ACT_NOT_REVERT_MIB 0x0001 +#define HostCmd_ACT_REVERT_MIB 0x0002 +#define HostCmd_ACT_HALT 0x0003 + +/* Define action or option for HostCmd_CMD_802_11_SCAN */ +#define HostCmd_BSS_TYPE_BSS 0x0001 +#define HostCmd_BSS_TYPE_IBSS 0x0002 +#define HostCmd_BSS_TYPE_ANY 0x0003 + +/* Define action or option for HostCmd_CMD_802_11_SCAN */ +#define HostCmd_SCAN_TYPE_ACTIVE 0x0000 +#define HostCmd_SCAN_TYPE_PASSIVE 0x0001 + +#define HostCmd_SCAN_802_11_B_CHANNELS 11 + +#define HostCmd_SCAN_MIN_CH_TIME 6 + +#define HostCmd_SCAN_MAX_CH_TIME 100 + +#define HostCmd_SCAN_RADIO_TYPE_BG 0 +#define HostCmd_SCAN_RADIO_TYPE_A 1 +#define HostCmd_SCAN_PASSIVE_MAX_CH_TIME 100 + +#define HostCmd_SCAN_PROBE_DELAY_TIME 0 + +/* Define action or option for HostCmd_CMD_MAC_CONTROL */ +#define HostCmd_ACT_MAC_RX_ON 0x0001 +#define HostCmd_ACT_MAC_TX_ON 0x0002 +#define HostCmd_ACT_MAC_LOOPBACK_ON 0x0004 +#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008 +#define HostCmd_ACT_MAC_INT_ENABLE 0x0010 +#define HostCmd_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define HostCmd_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define HostCmd_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 +/* Define action or option or constant for HostCmd_CMD_MAC_MULTICAST_ADR */ +#define HostCmd_SIZE_MAC_ADR 6 +#define HostCmd_MAX_MCAST_ADRS 32 + +/* Define action or option for HostCmd_CMD_802_11_SNMP_MIB */ +/* Boolean */ +#define HostCmd_TYPE_MIB_FLD_BOOLEAN 0x0001 +/* Integer */ +#define HostCmd_TYPE_MIB_FLD_INTEGER 0x0002 +/* Counter */ +#define HostCmd_TYPE_MIB_FLD_COUNTER 0x0003 +/* Octet string */ +#define HostCmd_TYPE_MIB_FLD_OCT_STR 0x0004 +/* String */ +#define HostCmd_TYPE_MIB_FLD_DISPLAY_STR 0x0005 +/* MAC address */ +#define HostCmd_TYPE_MIB_FLD_MAC_ADR 0x0006 +/* IP address */ +#define HostCmd_TYPE_MIB_FLD_IP_ADR 0x0007 +/* WEP */ +#define HostCmd_TYPE_MIB_FLD_WEP 0x0008 + +/* Define action or option for HostCmd_CMD_802_11_RADIO_CONTROL */ +#define HostCmd_TYPE_AUTO_PREAMBLE 0x0001 +#define HostCmd_TYPE_SHORT_PREAMBLE 0x0002 +#define HostCmd_TYPE_LONG_PREAMBLE 0x0003 + +#define TURN_ON_RF 0x01 +#define RADIO_ON 0x01 +#define RADIO_OFF 0x00 + +#define SET_AUTO_PREAMBLE 0x05 +#define SET_SHORT_PREAMBLE 0x03 +#define SET_LONG_PREAMBLE 0x01 + +/* Define action or option for CMD_802_11_RF_CHANNEL */ +#define HostCmd_OPT_802_11_RF_CHANNEL_GET 0x00 +#define HostCmd_OPT_802_11_RF_CHANNEL_SET 0x01 + +/* Define action or option for HostCmd_CMD_802_11_RF_TX_POWER */ +#define HostCmd_ACT_TX_POWER_OPT_GET 0x0000 +#define HostCmd_ACT_TX_POWER_OPT_SET_HIGH 0x8007 +#define HostCmd_ACT_TX_POWER_OPT_SET_MID 0x8004 +#define HostCmd_ACT_TX_POWER_OPT_SET_LOW 0x8000 + +#define HostCmd_ACT_TX_POWER_INDEX_HIGH 0x0007 +#define HostCmd_ACT_TX_POWER_INDEX_MID 0x0004 +#define HostCmd_ACT_TX_POWER_INDEX_LOW 0x0000 + +/* Define action or option for HostCmd_CMD_802_11_DATA_RATE */ +#define HostCmd_ACT_SET_TX_AUTO 0x0000 +#define HostCmd_ACT_SET_TX_FIX_RATE 0x0001 +#define HostCmd_ACT_GET_TX_RATE 0x0002 + +#define HostCmd_ACT_SET_RX 0x0001 +#define HostCmd_ACT_SET_TX 0x0002 +#define HostCmd_ACT_SET_BOTH 0x0003 +#define HostCmd_ACT_GET_RX 0x0004 +#define HostCmd_ACT_GET_TX 0x0008 +#define HostCmd_ACT_GET_BOTH 0x000c + +/* Define action or option for HostCmd_CMD_802_11_PS_MODE */ +#define HostCmd_TYPE_CAM 0x0000 +#define HostCmd_TYPE_MAX_PSP 0x0001 +#define HostCmd_TYPE_FAST_PSP 0x0002 + +/* Define action or option for HostCmd_CMD_DFT_ACCESS */ +enum HostCmd_CMD_DFT_ACCESS_OPTS { + HostCmd_ACT_DFT_ACCESS_ADD = 1, + HostCmd_ACT_DFT_ACCESS_DEL, + HostCmd_ACT_DFT_ACCESS_LIST, + HostCmd_ACT_DFT_ACCESS_RESET, + HostCmd_ACT_BT_ACCESS_ADD, + HostCmd_ACT_BT_ACCESS_DEL, + HostCmd_ACT_BT_ACCESS_LIST, + HostCmd_ACT_BT_ACCESS_RESET +}; + +/** Card Event definition */ +#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000 +#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001 +#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002 +#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003 +#define MACREG_INT_CODE_LINK_SENSED 0x00000004 +#define MACREG_INT_CODE_CMD_FINISHED 0x00000005 +#define MACREG_INT_CODE_MIB_CHANGED 0x00000006 +#define MACREG_INT_CODE_INIT_DONE 0x00000007 +#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008 +#define MACREG_INT_CODE_DISASSOCIATED 0x00000009 +#define MACREG_INT_CODE_PS_AWAKE 0x0000000a +#define MACREG_INT_CODE_PS_SLEEP 0x0000000b +#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d +#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e +#define MACREG_INT_CODE_WM_AWAKE 0x0000000f +#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011 +#define MACREG_INT_CODE_RSSI_LOW 0x00000019 +#define MACREG_INT_CODE_SNR_LOW 0x0000001a +#define MACREG_INT_CODE_MAX_FAIL 0x0000001b +#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c +#define MACREG_INT_CODE_SNR_HIGH 0x0000001d + +#endif /* _HOST_H_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/if_usb.c linux-2.6-libertas/drivers/net/wireless/libertas/if_usb.c --- linux-2.6-orig/drivers/net/wireless/libertas/if_usb.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/if_usb.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,1085 @@ +/** @file if_usb.c + * @brief This file contains functions used in USB interface module. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 09/29/05: Add Doxygen format comments + 02/01/06: Correct the usage of compile flag HELPER_IMAGE + 02/13/06: Add a FW ready flag for interoperability issue + 02/22/06: Add support for new VID/PID + 03/02/06: Add receive exception handling, fix some memory leak issues + 03/03/06: Add FW download failure handling + 03/10/06: Fix the rmmod/insmod issue + 04/07/06: Add Linux kernel 2.6 support + 04/21/06: Add hotplug firmware loading + +********************************************************/ + +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include "if_usb.h" +#include "host.h" +#include "sbi.h" +#include "wlan_decl.h" +#include "wlan_defs.h" +#include "wlan_dev.h" + +/* Context definition for Interrupt simulation */ +#define TX_SUCCESS 1 +#define RX_SUCCESS 2 +#define TX_FAILURE -1 + +#define MESSAGE_HEADER_LEN 4 + +static usb_notifier_fn_add wlan_card_add_cb = NULL; +static usb_notifier_fn_remove wlan_card_remove_cb = NULL; +static const char usbdriver_name[] = "usb8xxx"; +static u8 usb_int_cause = 0; + +/** struct This structure contains the device signature */ +static struct usb_device_id if_usb_table[] = { + /* Enter the device signature inside */ + { + USB_DEVICE(USB8388_VID_1, USB8388_PID_1), + }, + { + USB_DEVICE(USB8388_VID_2, USB8388_PID_2), + }, + {} /* Terminating entry */ +}; + +static int if_prog_firmware(wlan_private * priv); +static void if_usb_receive(struct urb *urb, struct pt_regs *regs); +static void if_usb_receive_fwload(struct urb *urb, struct pt_regs *regs); +static int if_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void if_usb_disconnect(struct usb_interface *intf); +#ifdef CONFIG_PM +static int if_usb_suspend(struct usb_interface *intf, pm_message_t message); +static int if_usb_resume(struct usb_interface *intf); +#else +#define if_usb_suspend NULL +#define if_usb_resume NULL +#endif + +static int __if_usb_submit_rx_urb(wlan_private * priv, + void (*callbackfn) + (struct urb *urb, struct pt_regs *regs)); + +/** if_usb_driver */ +static struct usb_driver if_usb_driver = { + /* driver name */ + .name = usbdriver_name, + /* probe function name */ + .probe = if_usb_probe, + /* disconnect function name */ + .disconnect = if_usb_disconnect, + /* device signature table */ + .id_table = if_usb_table, + .suspend = if_usb_suspend, + .resume = if_usb_resume, +}; + +MODULE_DEVICE_TABLE(usb, if_usb_table); + +/** + * @brief Interrupt handler + * @param priv pointer to wlan_private + * @param flag flag + * @param context context parameter + * @return N/A + */ +static void if_usb_interrupt(wlan_private * priv, u8 flags, int context) +{ + libertas_interrupt(priv->wlan_dev.netdev); +} + +/** + * @brief call back function to handle the status of the URB + * @param urb pointer to urb structure + * @return N/A + */ +static void if_usb_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +{ + wlan_private *priv = (wlan_private *) (urb->context); + wlan_adapter *adapter = priv->adapter; + struct net_device *dev = priv->wlan_dev.netdev; + + ENTER(); + + /* handle the transmission complete validations */ + + if (urb->status != 0) { + /* print the failure status number for debug */ + PRINTM(FATAL, "URB in failure status\n"); + } else { + PRINTM(INFO, "URB status is successfull\n"); + PRINTM(INFO, "Actual length transmitted %d\n", + urb->actual_length); + priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; + if ((adapter->MediaConnectStatus == WlanMediaStateConnected)) + netif_wake_queue(dev); + } + + LEAVE(); + return; +} + +/** + * @brief free tx/rx urb, skb and rx buffer + * @param cardp pointer usb_card_rec + * @return N/A + */ +static void if_usb_free(struct usb_card_rec *cardp) +{ + ENTER(); + + /* Unlink tx & rx urb */ + usb_kill_urb(cardp->tx_urb); + usb_kill_urb(cardp->rx_urb); + + usb_free_urb(cardp->tx_urb); + cardp->tx_urb = NULL; + + usb_free_urb(cardp->rx_urb); + cardp->rx_urb = NULL; + + kfree(cardp->bulk_out_buffer); + cardp->bulk_out_buffer = NULL; + + LEAVE(); + return; +} + +/** + * @brief sets the configuration values + * @param ifnum interface number + * @param id pointer to usb_device_id + * @return 0 on success, error code on failure + */ +static int if_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + wlan_private *pwlanpriv; + struct usb_card_rec *usb_cardp; + int i; + + ENTER(); + + udev = interface_to_usbdev(intf); + + /* Check probe is for our device */ + for (i = 0; if_usb_table[i].idVendor; i++) { + if (udev->descriptor.idVendor == if_usb_table[i].idVendor && + udev->descriptor.idProduct == if_usb_table[i].idProduct) { + PRINTM(INFO, "VID/PID = %X/%X, matched\n", + udev->descriptor.idVendor, + udev->descriptor.idProduct); + break; + } + } + + if (!if_usb_table[i].idVendor) { + PRINTM(INFO, "Discard the Probe request\n"); + PRINTM(INFO, "VID = 0x%X PID = 0x%X\n", + udev->descriptor.idVendor, udev->descriptor.idProduct); + LEAVE(); + return -ENODEV; + } + + usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); + if (!usb_cardp) { + PRINTM(FATAL, "Out of memory allocating private data.\n"); + goto error; + } + + usb_cardp->add = wlan_card_add_cb; + usb_cardp->remove = wlan_card_remove_cb; + usb_cardp->udev = udev; + iface_desc = intf->cur_altsetting; + + PRINTM(INFO, "bcdUSB = 0x%X bDeviceClass = 0x%X" + " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", + udev->descriptor.bcdUSB, + udev->descriptor.bDeviceClass, + udev->descriptor.bDeviceSubClass, + udev->descriptor.bDeviceProtocol); + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + if ((endpoint->bEndpointAddress & BULK_ENDPOINT_PRESENT) + && ((endpoint->bmAttributes & BULK_ENDPOINT_MASK) == + BULK_ENDPOINT_FOUND)) { + /* we found a bulk in endpoint */ + PRINTM(INFO, "Bulk in size is %d\n", + endpoint->wMaxPacketSize); + if (! + (usb_cardp->rx_urb = + usb_alloc_urb(0, GFP_KERNEL))) { + PRINTM(INFO, + "Rx URB allocation failed\n"); + goto dealloc; + } + usb_cardp->rx_urb_recall = 0; + + usb_cardp->bulk_in_size = + endpoint->wMaxPacketSize; + usb_cardp->bulk_in_endpointAddr = + (endpoint-> + bEndpointAddress & ENDPOINT_NUMBER_MASK); + PRINTM(INFO, "in_endpoint = %d\n", + endpoint->bEndpointAddress); + } + + if (((endpoint-> + bEndpointAddress & BULK_ENDPOINT_PRESENT) == + BULK_OUT_PRESENT) + && ((endpoint->bmAttributes & BULK_ENDPOINT_MASK) == + BULK_ENDPOINT_FOUND)) { + /* We found bulk out endpoint */ + if (! + (usb_cardp->tx_urb = + usb_alloc_urb(0, GFP_KERNEL))) { + PRINTM(INFO, + "Tx URB allocation failed\n"); + goto dealloc; + } + + usb_cardp->bulk_out_size = + endpoint->wMaxPacketSize; + PRINTM(INFO, "Bulk out size is %d\n", + endpoint->wMaxPacketSize); + usb_cardp->bulk_out_endpointAddr = + endpoint->bEndpointAddress; + PRINTM(INFO, "out_endpoint = %d\n", + endpoint->bEndpointAddress); + usb_cardp->bulk_out_buffer = + kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, + GFP_DMA); + + if (!usb_cardp->bulk_out_buffer) { + PRINTM(INFO, + "Could not allocate buffer\n"); + goto dealloc; + } + } + } + + /* At this point wlan_add_card() will be called. Don't worry + * about keeping pwlanpriv around since it will be set on our + * usb device data in -> add() -> libertas_sbi_register_dev(). + */ + if (!(pwlanpriv = usb_cardp->add(usb_cardp))) { + goto dealloc; + } + + usb_get_dev(udev); + usb_set_intfdata(intf, usb_cardp); + LEAVE(); + + /* + * return card structure, which can be got back in the + * diconnect function as the ptr + * argument. + */ + return 0; + +dealloc: + if_usb_free(usb_cardp); + +error: + LEAVE(); + return (-ENOMEM); +} + +/** + * @brief free resource and cleanup + * @param udev pointer to usb_device + * @param ptr pointer to usb_cardp + * @return N/A + */ +static void if_usb_disconnect(struct usb_interface *intf) +{ + struct usb_card_rec *cardp = usb_get_intfdata(intf); + wlan_private *priv = (wlan_private *) cardp->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* + * Update Surprie removed to TRUE + * Free all the URB's allocated + */ + if (!Adapter->SurpriseRemoved) { + Adapter->SurpriseRemoved = 1; + } + + /* Unlink and free urb */ + if_usb_free(cardp); + + /* card is removed and we can call wlan_remove_card */ + PRINTM(INFO, "call remove card\n"); + cardp->remove(cardp); + + usb_set_intfdata(intf, NULL); + usb_put_dev(interface_to_usbdev(intf)); + + LEAVE(); + return; +} + +/** + * @brief This function transfer the data to the device. + * @param priv pointer to wlan_private + * @param payload pointer to payload data + * @param nb data length + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) +{ + /* pointer to card structure */ + struct usb_card_rec *cardp = priv->wlan_dev.card; + int ret = WLAN_STATUS_FAILURE; + + ENTER(); + + /* check if device is removed */ + if (priv->adapter->SurpriseRemoved) { + PRINTM(INFO, "Device removed\n"); + goto tx_ret; + } + + /* use USB API macro FILL_BULK_URB or API function + * usb_fill_bulk_urb() used to set the + * configuration information to send the bulk URB + */ + usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, + usb_sndbulkpipe(cardp->udev, + cardp->bulk_out_endpointAddr), + payload, nb, if_usb_write_bulk_callback, priv); + + cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; + + if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { + /* transfer failed */ + PRINTM(INFO, "usb_submit_urb Failed\n"); + + ret = WLAN_STATUS_FAILURE; + } else { + PRINTM(INFO, "usb_submit_urb Success\n"); + ret = WLAN_STATUS_SUCCESS; + } + +tx_ret: + LEAVE(); + return ret; +} + +/* read callback private data */ +struct read_cb_info { + wlan_private *priv; + struct sk_buff *skb; +}; + +/** + * @brief This function submit the rx data to OS, used at firmware load time. + * @param priv pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) +{ + return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); +} + +/** + * @brief This function submit the rx data to OS + * @param priv pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static inline int if_usb_submit_rx_urb(wlan_private * priv) +{ + return __if_usb_submit_rx_urb(priv, &if_usb_receive); +} + + +/** + * @brief This function submit the rx data to OS + * @param priv pointer to wlan_private structure + * @callbackfn pointer to callback function to use + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int __if_usb_submit_rx_urb(wlan_private * priv, + void (*callbackfn) + (struct urb *urb, struct pt_regs *regs)) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + struct sk_buff *skb; + struct read_cb_info *rinfo; + int ret = WLAN_STATUS_FAILURE; + + ENTER(); + + if (!(rinfo = kmalloc(sizeof(struct read_cb_info), GFP_ATOMIC))) { + PRINTM(FATAL, "No free read_callback_info\n"); + goto rx_ret; + } + + if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { + PRINTM(FATAL, "No free skb\n"); + kfree(rinfo); + goto rx_ret; + } + + rinfo->skb = skb; + rinfo->priv = priv; + + /* Fill the receive configuration URB and initialise the Rx call back */ + usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, + usb_rcvbulkpipe(cardp->udev, + cardp->bulk_in_endpointAddr), + skb->tail + IPFIELD_ALIGN_OFFSET, + MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, + rinfo); + + cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; + + PRINTM(INFO, "Pointer for rx_urb %p\n", cardp->rx_urb); + if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { + /* handle failure conditions */ + PRINTM(INFO, "Submit Rx URB failed\n"); + ret = WLAN_STATUS_FAILURE; + } else { + PRINTM(INFO, "Submit Rx URB Success\n"); + ret = WLAN_STATUS_SUCCESS; + } + +rx_ret: + LEAVE(); + return ret; +} + + +static void if_usb_receive_fwload(struct urb *urb, struct pt_regs *regs) +{ + struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; + wlan_private *priv = rinfo->priv; + struct sk_buff *skb = rinfo->skb; + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + struct FWSyncHeader *SyncFWHeader; + + ENTER(); + + kfree(rinfo); + + if (urb->status) { + PRINTM(INFO, "URB Status is failed during fw load\n"); + kfree_skb(skb); + return; + } + + SyncFWHeader = kmalloc(sizeof(struct FWSyncHeader), GFP_ATOMIC); + if (!SyncFWHeader) { + PRINTM(INFO, "Failure to allocate SyncFWHeader\n"); + kfree_skb(skb); + return; + } + + memcpy(SyncFWHeader, skb->data + IPFIELD_ALIGN_OFFSET, + sizeof(struct FWSyncHeader)); + + if (!SyncFWHeader->Cmd) { + PRINTM(INFO, "FW received Blk with correct CRC\n"); + PRINTM(INFO, "FW received Blk SeqNum = %d\n", + SyncFWHeader->SeqNum); + cardp->CRC_OK = 1; + } else { + PRINTM(INFO, "FW received Blk with CRC error\n"); + cardp->CRC_OK = 0; + } + + kfree_skb(skb); + + if (cardp->FWFinalBlk) { + cardp->FwDnldOver = 1; + goto exit; + } + + if_prog_firmware(priv); + + if_usb_submit_rx_urb_fwload(priv); +exit: + kfree(SyncFWHeader); + + return; + +} + +/** + * @brief This function reads of the packet into the upload buff, + * wake up the main thread and initialise the Rx callack. + * + * @param urb pointer to struct urb + * @return N/A + */ +static void if_usb_receive(struct urb *urb, struct pt_regs *regs) +{ + struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; + wlan_private *priv = rinfo->priv; + struct sk_buff *skb = rinfo->skb; + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + + int RecvLength = urb->actual_length; + u8 *RecvBuff = NULL; + u32 RecvType; + u8 *cmdBuf; + +#define MRVDRV_MIN_PKT_LEN 30 + + ENTER(); + + kfree(rinfo); + + if (RecvLength) { + if (urb->status) { + PRINTM(INFO, "URB Status is failed\n"); + kfree_skb(skb); + goto setup_for_next; + } + + RecvBuff = skb->data + IPFIELD_ALIGN_OFFSET; + memcpy(&RecvType, RecvBuff, sizeof(u32)); + PRINTM(INFO, "Recv length = 0x%x\n", RecvLength); + PRINTM(INFO, "Receive type = 0x%X\n", RecvType); + RecvType = wlan_le32_to_cpu(RecvType); + PRINTM(INFO, "Receive type after = 0x%X\n", RecvType); + } else if (urb->status) { + if (!cardp->rx_urb_recall) { + PRINTM(INFO, "Card Is Removed\n"); + priv->adapter->SurpriseRemoved = 1; + // Wake up main thread to handle card removal. + if_usb_interrupt(priv, 0, 0); + } + goto rx_exit; + } + + + switch (RecvType) { + case CMD_TYPE_DATA: + if (RecvLength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + + MESSAGE_HEADER_LEN || RecvLength < MRVDRV_MIN_PKT_LEN) { + PRINTM(INFO, "Packet length is Invalid\n"); + + kfree_skb(skb); + + break; + } + + skb_reserve(skb, IPFIELD_ALIGN_OFFSET); + skb_put(skb, RecvLength); + skb_pull(skb, MESSAGE_HEADER_LEN); + libertas_process_rxed_packet(priv, skb); + + priv->wlan_dev.upld_len = (RecvLength - MESSAGE_HEADER_LEN); + + break; + + case CMD_TYPE_REQUEST: + if (RecvLength > MRVDRV_SIZE_OF_CMD_BUFFER) { + PRINTM(INFO, "The receive buffer is too large\n"); + kfree_skb(skb); + + break; + } + + /* take care of CurCmd = NULL case by reading the + * data to clear the interrupt */ + if (!priv->adapter->CurCmd) { + cmdBuf = priv->wlan_dev.upld_buf; + priv->adapter->HisRegCpy &= ~HIS_CmdUpLdRdy; + } else { + cmdBuf = priv->adapter->CurCmd->BufVirtualAddr; + } + + usb_int_cause |= HIS_CmdUpLdRdy; + priv->wlan_dev.upld_len = (RecvLength - MESSAGE_HEADER_LEN); + memcpy(cmdBuf, RecvBuff + MESSAGE_HEADER_LEN, + priv->wlan_dev.upld_len); + + kfree_skb(skb); + + PRINTM(INFO, "Wake up main thread to handle cmd response\n"); + if_usb_interrupt(priv, HIS_CmdUpLdRdy, RX_SUCCESS); + break; + + case CMD_TYPE_INDICATION: + /* Event cause handling */ + cardp->usb_event_cause = *(u32 *) (RecvBuff + MESSAGE_HEADER_LEN); + + PRINTM(INFO, "**EVENT** 0x%X\n", cardp->usb_event_cause); + if (cardp->usb_event_cause & 0xffff0000) { + libertas_send_tx_feedback(priv); + break; + } + cardp->usb_event_cause = wlan_le32_to_cpu(cardp->usb_event_cause) << 3; + usb_int_cause |= HIS_CardEvent; + kfree_skb(skb); + if_usb_interrupt(priv, HIS_CardEvent, RX_SUCCESS); + goto rx_exit; + + default: + kfree_skb(skb); + break; + } + +setup_for_next: + if_usb_submit_rx_urb(priv); +rx_exit: + LEAVE(); + return; +} + +/** + * @brief This function downloads data to FW + * @param priv pointer to wlan_private structure + * @param type type of data + * @param buf pointer to data buffer + * @param len number of bytes + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) +{ + int ret = WLAN_STATUS_FAILURE; + u32 tmp; + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + + ENTER(); + + PRINTM(INFO, "*** type = %u\n", type); + PRINTM(INFO, "Size after = %d\n", nb); + + if (type == MVMS_CMD) { + tmp = wlan_cpu_to_le32(CMD_TYPE_REQUEST); + priv->wlan_dev.dnld_sent = DNLD_CMD_SENT; + memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, + MESSAGE_HEADER_LEN); + + } else { + tmp = wlan_cpu_to_le32(CMD_TYPE_DATA); + priv->wlan_dev.dnld_sent = DNLD_DATA_SENT; + memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, + MESSAGE_HEADER_LEN); + } + + memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); + + ret = + usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); + + return ret; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_reenable_host_interrupt(wlan_private * priv, u8 bits) +{ + return WLAN_STATUS_SUCCESS; +} + +/* called with libertas_driver_lock held */ +int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg) +{ + ENTER(); + + *ireg = usb_int_cause; + usb_int_cause = 0; + + PRINTM(INFO, "Int cause is 0x%X\n", *ireg); + + LEAVE(); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_read_event_cause(wlan_private * priv) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + priv->adapter->EventCause = cardp->usb_event_cause; + /* Re-submit rx urb here to avoid event lost issue */ + if_usb_submit_rx_urb(priv); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_get_cis_info(wlan_private * priv) +{ + return WLAN_STATUS_SUCCESS; +} + +static int reset_device(wlan_private *priv) +{ + int ret; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RESET, + HostCmd_ACT_HALT, 0, 0, NULL); + msleep_interruptible(10); + + return ret; +} + +/** + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_unregister_dev(wlan_private * priv) +{ + int ret = WLAN_STATUS_SUCCESS; + + /* Need to send a Reset command to device before USB resources freed + * and wlan_remove_card() called, then device can handle FW download + * again. + */ + if (priv) + reset_device(priv); + + return ret; +} + +/** + * @brief This function registers driver. + * @param add pointer to add_card callback function + * @param remove pointer to remove card callback function + * @param arg pointer to call back function parameter + * @return dummy success variable + */ +int *libertas_sbi_register(wlan_notifier_fn_add add, wlan_notifier_fn_remove remove, + void *arg) +{ + ENTER(); + + wlan_card_add_cb = (usb_notifier_fn_add) add; + wlan_card_remove_cb = (usb_notifier_fn_remove) remove; + + /* + * API registers the Marvell USB driver + * to the USB system + */ + usb_register(&if_usb_driver); + + LEAVE(); + + /* Return success to wlan layer */ + return (int *)0x1; +} + +/** + * @brief This function removes usb driver. + * @return N/A + */ +void libertas_sbi_unregister(void) +{ + ENTER(); + + wlan_card_add_cb = NULL; + wlan_card_remove_cb = NULL; + + /* API unregisters the driver from USB subsystem */ + usb_deregister(&if_usb_driver); + + LEAVE(); + return; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_probe_card(void *card_p) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function register usb device and initialize parameter + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_sbi_register_dev(wlan_private * priv) +{ + + struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; + ENTER(); + + cardp->priv = priv; + cardp->eth_dev = priv->wlan_dev.netdev; + priv->hotplug_device = &(cardp->udev->dev); + + SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev)); + + PRINTM(INFO, "udev pointer is at %p\n", cardp->udev); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief stub function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_verify_fw_download(wlan_private * priv) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function download FW + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +static int if_prog_firmware(wlan_private * priv) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + struct FWData *fwdata; + struct FWHeader *fwheader; + u8 *firmware = priv->firmware->data; + + ENTER(); + + fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); + + if (!fwdata) + return WLAN_STATUS_FAILURE; + + fwheader = &fwdata->fwheader; + + if (!cardp->CRC_OK) { + cardp->TotalBytes = cardp->FwLastBlkSent; + cardp->FWSeqNum = cardp->LastSeqNum - 1; + } + + PRINTM(INFO, "TotalBytes = %d\n", cardp->TotalBytes); + + memcpy(fwheader, &firmware[cardp->TotalBytes], + sizeof(struct FWHeader)); + + cardp->FwLastBlkSent = cardp->TotalBytes; + cardp->TotalBytes += sizeof(struct FWHeader); + + PRINTM(INFO, "Copy Data\n"); + memcpy(fwdata->data, &firmware[cardp->TotalBytes], + fwdata->fwheader.DataLength); + + PRINTM(INFO, "Data Length = %d\n", fwdata->fwheader.DataLength); + + cardp->FWSeqNum = cardp->FWSeqNum + 1; + + fwdata->SeqNum = cardp->FWSeqNum; + cardp->LastSeqNum = fwdata->SeqNum; + cardp->TotalBytes += fwdata->fwheader.DataLength; + + if (fwheader->DnldCmd == FW_HAS_DATA_TO_RECV) { + PRINTM(INFO, "There is data to follow\n"); + PRINTM(INFO, "SeqNum = %d TotalBytes = %d\n", cardp->FWSeqNum, + cardp->TotalBytes); + memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); + usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + + } else if (fwdata->fwheader.DnldCmd == FW_HAS_LAST_BLOCK) { + PRINTM(INFO, "Host has finished FW downloading\n"); + PRINTM(INFO, "Donwloading FW JUMP BLOCK\n"); + memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); + usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); + cardp->FWFinalBlk = 1; + } + + PRINTM(INFO, "The firmware download is done size is %d\n", + cardp->TotalBytes); + + kfree(fwdata); + + LEAVE(); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function download fw + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_prog_firmware(wlan_private * priv) +{ + struct usb_card_rec *cardp = priv->wlan_dev.card; + int i = 0; + + ENTER(); + + if (if_usb_submit_rx_urb_fwload(priv) < 0) { + PRINTM(INFO, "URB submission is failed\n"); + libertas_sbi_unregister(); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + +restart: + priv->adapter->fw_ready = 0; + + cardp->TotalBytes = 0; + cardp->FwLastBlkSent = 0; + cardp->CRC_OK = 1; + cardp->FwDnldOver = 0; + cardp->FWSeqNum = -1; + cardp->TotalBytes = 0; + cardp->FWFinalBlk = 0; + + if_prog_firmware(priv); + + do { + PRINTM(INFO, "Wlan sched timeout\n"); + i++; + msleep_interruptible(100); + if (priv->adapter->SurpriseRemoved || i >= 20) + break; + } while (!cardp->FwDnldOver); + + if (!cardp->FwDnldOver) { + PRINTM(FATAL, "Failed to load fw, resetting device!\n"); + if (!usb_reset_device(cardp->udev)) { + msleep(10); + reset_device(priv); + msleep(10); + goto restart; + } + PRINTM(FATAL, "FW download failure, time = %d ms\n", i * 100); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + if_usb_submit_rx_urb(priv); + + /* Delay 200 ms to waiting for the FW ready */ + msleep_interruptible(200); + + priv->adapter->fw_ready = 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_enable_host_int(wlan_private * priv) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_disable_host_int(wlan_private * priv) +{ + return WLAN_STATUS_SUCCESS; +} + +#ifdef ENABLE_PM +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_suspend(wlan_private * priv) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This is a dummy function + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS + */ +int libertas_sbi_resume(wlan_private * priv) +{ + return WLAN_STATUS_SUCCESS; +} +#endif + +#ifdef CONFIG_PM +static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usb_card_rec *cardp = usb_get_intfdata(intf); + wlan_private *priv = cardp->priv; + + ENTER(); + + if (priv->adapter->PSState != PS_STATE_FULL_POWER) + return -1; + + netif_device_detach(cardp->eth_dev); + + /* Unlink tx & rx urb */ + usb_kill_urb(cardp->tx_urb); + usb_kill_urb(cardp->rx_urb); + + cardp->rx_urb_recall = 1; + + LEAVE(); + return 0; +} + +static int if_usb_resume(struct usb_interface *intf) +{ + struct usb_card_rec *cardp = usb_get_intfdata(intf); + + ENTER(); + + cardp->rx_urb_recall = 0; + + if_usb_submit_rx_urb(cardp->priv); + + netif_device_attach(cardp->eth_dev); + + LEAVE(); + return 0; +} +#endif diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/if_usb.h linux-2.6-libertas/drivers/net/wireless/libertas/if_usb.h --- linux-2.6-orig/drivers/net/wireless/libertas/if_usb.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/if_usb.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,114 @@ +/** @file if_usb.h + * + * @brief This file contains definition for USB interface. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/11/05: Add Doxygen format comments + +********************************************************/ + +#define CMD_TYPE_REQUEST 0xF00DFACE +#define CMD_TYPE_DATA 0xBEADC0DE +#define CMD_TYPE_INDICATION 0xBEEFFACE + +#define BULK_ENDPOINT_PRESENT USB_ENDPOINT_DIR_MASK +#define BULK_ENDPOINT_MASK USB_ENDPOINT_XFERTYPE_MASK +#define BULK_ENDPOINT_FOUND USB_ENDPOINT_XFER_BULK +#define ENDPOINT_NUMBER_MASK USB_ENDPOINT_NUMBER_MASK + +#define BULK_OUT_PRESENT 0x00 + +#define IPFIELD_ALIGN_OFFSET 2 + +#define USB8388_VID_1 0x1286 +#define USB8388_PID_1 0x2001 +#define USB8388_VID_2 0x05a3 +#define USB8388_PID_2 0x8388 + +/** USB card description structure*/ +struct usb_card_rec { + struct net_device *eth_dev; + struct usb_device *udev; + struct urb *rx_urb, *tx_urb; + u16 irq; + u32 port; + u8 flag; + u16 host_int_mask; + void *(*add) (struct usb_card_rec * card); + int (*remove) (struct usb_card_rec * card); + void (*user_isr) (int, void *, struct pt_regs *); + void *priv; + + int bulk_in_size; + u8 bulk_in_endpointAddr; + + u8 *bulk_out_buffer; + int bulk_out_size; + u8 bulk_out_endpointAddr; + + u8 CRC_OK; + u8 SendNextBlk; + u32 FWSeqNum; + u32 LastSeqNum; + u32 TotalBytes; + u32 FwLastBlkSent; + u8 FwDnldOver; + u8 FWFinalBlk; + + u32 usb_event_cause; + + u8 rx_urb_recall; +}; + +typedef void *(*usb_notifier_fn_add) (struct usb_card_rec *); +typedef int (*usb_notifier_fn_remove) (struct usb_card_rec *); + +/** FWHeader */ +struct FWHeader { + u32 DnldCmd; + u32 BaseAddr; + u32 DataLength; + u32 CRC; +}; + +#define FW_MAX_DATA_BLK_SIZE 600 +/** FWData */ +struct FWData { + struct FWHeader fwheader; + u32 SeqNum; + u8 data[FW_MAX_DATA_BLK_SIZE]; +}; + +/** FWSyncHeader */ +struct FWSyncHeader { + u32 Cmd; + u32 SeqNum; +}; + +#define REQ_TYPE 0 /* for compilation only */ +#define REQ_CTRL 0 /* for compilation only */ +#define TIME_OUT_VALUE 0 /* for compilation only */ + +#define FW_HAS_DATA_TO_RECV 0x00000001 +#define FW_HAS_LAST_BLOCK 0x00000004 + +#define FW_DATA_XMIT_SIZE \ + sizeof(struct FWHeader) + fwdata->fwheader.DataLength + sizeof(u32) diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/Makefile linux-2.6-libertas/drivers/net/wireless/libertas/Makefile --- linux-2.6-orig/drivers/net/wireless/libertas/Makefile 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/Makefile 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,16 @@ +# EXTRA_CFLAGS += -Wpacked + +usb8xxx-objs := wlan_main.o wlan_fw.o wlan_wext.o \ + wlan_rx.o wlan_tx.o wlan_cmd.o \ + wlan_cmdresp.o wlan_scan.o \ + wlan_join.o wlan_11d.o \ + wlan_ioctl.o wlan_debugfs.o + +ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y) +EXTRA_CFLAGS = -DDEBUG_LEVEL4 -DPROC_DEBUG +endif + +usb8xxx-objs += if_usb.o + +obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o + diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/Makefile.old linux-2.6-libertas/drivers/net/wireless/libertas/Makefile.old --- linux-2.6-orig/drivers/net/wireless/libertas/Makefile.old 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/Makefile.old 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,205 @@ +# +# File: Makefile +# +# (c) Copyright © 2003-2006, Marvell International Ltd. +# All Rights Reserved +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available along with the File in the license.txt file or by writing to +# the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. +# + +############################################################################# +# Directories +############################################################################# + +# Directory of kernel source +KERNELVER := $(shell uname -r) +KERNELDIR = /lib/modules/$(KERNELVER)/build + +# Directory of driver binary +BINDIR = ../bin_usb8388 +INSTALLDIR = /lib/modules/$(KERNELVER)/kernel/drivers/usb + + +############################################################################# +# Configuration Options +############################################################################# + +# Debug Option +# DEBUG LEVEL n/1/2/3/4: +# n: NO DEBUG +# 1: Only PRINTM(MSG,...) +# 2: PRINTM(MSG,...) and PRINTM(FATAL,...) +# 3: PRINTM(MSG,...), PRINTM(FATAL,...) and PRINTM(WARN,...) +# 4: PRINTM(MSG,...), PRINTM(FATAL,...), PRINTM(WARN,...) and PRINTM(INFO,...) +CONFIG_DEBUG=1 + +# Proc in /proc/net/wlan +CONFIG_PROC_DEBUG=y + +# Linux Power Management +CONFIG_ENABLE_PM=n + +# Re-association in driver +CONFIG_REASSOCIATION=y + + +############################################################################# +# Compiler Flags +############################################################################# + +CFLAGS += -I$(PWD)/os/linux +CFLAGS += -I$(PWD)/wlan +CFLAGS += -I$(PWD)/if/if_usb +CFLAGS += -I$(KERNELDIR)/include + +CFLAGS += -DFPNUM='"14"' + +ifeq ($(CONFIG_DEBUG),1) + CFLAGS += -DDEBUG_LEVEL1 +endif + +ifeq ($(CONFIG_DEBUG),2) + CFLAGS += -DDEBUG_LEVEL1 + CFLAGS += -DDEBUG_LEVEL2 + DBG= -dbg +endif + +ifeq ($(CONFIG_DEBUG),3) + CFLAGS += -DDEBUG_LEVEL1 + CFLAGS += -DDEBUG_LEVEL2 + CFLAGS += -DDEBUG_LEVEL3 + DBG= -dbg +endif + +ifeq ($(CONFIG_DEBUG),4) + CFLAGS += -DDEBUG_LEVEL1 + CFLAGS += -DDEBUG_LEVEL2 + CFLAGS += -DDEBUG_LEVEL3 + CFLAGS += -DDEBUG_LEVEL4 + DBG= -dbg +endif + +ifeq ($(CONFIG_PROC_DEBUG),y) + CFLAGS += -DPROC_DEBUG +endif + +ifeq ($(CONFIG_ENABLE_PM),y) + CFLAGS += -DENABLE_PM +endif + +ifeq ($(CONFIG_REASSOCIATION),y) + CFLAGS += -DREASSOCIATION +endif + + +############################################################################# +# Make Targets +############################################################################# + +# If KERNELRELEASE is defined, we've been invoked from the kernel build +# system and can use it's language. + +ifneq ($(KERNELRELEASE),) + +WLANOBJS = wlan/wlan_main.o wlan/wlan_fw.o wlan/wlan_wext.o \ + wlan/wlan_rx.o wlan/wlan_tx.o \ + wlan/wlan_cmd.o wlan/wlan_cmdresp.o \ + wlan/wlan_proc.o wlan/wlan_scan.o wlan/wlan_join.o \ + wlan/wlan_11d.o + +ifeq ($(CONFIG_PROC_DEBUG), y) +WLANOBJS += wlan/wlan_debug.o +endif + +IFOBJS := if/if_usb/if_usb.o +obj-m := usb8xxx.o +usb8xxx-objs := $(WLANOBJS) $(IFOBJS) + +# Otherwise we were called directly from the command line; invoke the kernel build system. +else + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +############################################################### + +export CFLAGS KERNELDIR + +.PHONY: app/wlanconfig wlan clean distclean + + @echo "Finished Making Marvell Wlan Linux Driver" + + +wlan app/wlanconfig: + $(MAKE) -C $@ + +echo: + @echo "===> Driver will be put to ../bin_usb8388 directory..." + +build: echo default + + @if [ ! -d $(BINDIR) ]; then \ + mkdir $(BINDIR); \ + fi + + mv usb8xxx.ko $(BINDIR)/usb8388$(DBG).ko + cp -f README $(BINDIR) + $(MAKE) -C app/wlanconfig $@ INSTALLDIR=$(BINDIR) + cp -r config $(BINDIR) + +install: default + cp -f usb8xxx.ko $(INSTALLDIR)/usb8388$(DBG).ko + @echo $(INSTALLDIR) + @echo "===> USB8388 driver installed" + +clean: + rm -f *.ko .*.ko.cmd + -find . -name "*.o" -exec rm {} \; + -find . -name ".*.o.cmd" -exec rm {} \; + -find . -name "*.mod.c" -exec rm {} \; + $(MAKE) -C app/wlanconfig $@ + +distclean: + -find . -name "*.o" -exec rm {} \; + -find . -name ".*.o.cmd" -exec rm {} \; + -find . -name "*.orig" -exec rm {} \; + -find . -name "*.swp" -exec rm {} \; + -find . -name "*.*~" -exec rm {} \; + -find . -name "*~" -exec rm {} \; + -find . -name "*.d" -exec rm {} \; + -find . -name "*.a" -exec rm {} \; + -find . -name "tags" -exec rm {} \; + -find . -name "*.mod.c" -exec rm {} \; + -find . -name "*.ko" -exec rm {} \; + -find . -name ".*.ko.cmd" -exec rm {} \; + -find . -name ".*" -exec rm -rf 2> /dev/null \; + -rm -rf .tmp_versions/ + $(MAKE) -C app/wlanconfig $@ + +newlogs: + rm -f /var/log/message* + sleep 1 + /etc/rc.d/init.d/syslog restart + +rmtags: + rm -f tags + +tags: rmtags + ctags -R *.[ch] wlan/*.[ch] if/if_usb/*.[ch] os/linux/*.[ch] \ + $(KERNELDIR)/include/linux \ + $(KERNELDIR)/include/net $(KERNELDIR)/include/asm + +# End of file diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/radiotap.h linux-2.6-libertas/drivers/net/wireless/libertas/radiotap.h --- linux-2.6-orig/drivers/net/wireless/libertas/radiotap.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/radiotap.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,96 @@ +/** + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#include <net/ieee80211_radiotap.h> + +/* XXX: move to net/ieee_80211_radiotap.h, this are from the new header file */ +/* For IEEE80211_RADIOTAP_RX_FLAGS */ +#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ + +/* For IEEE80211_RADIOTAP_TX_FLAGS */ +#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive + * retries */ +#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ +#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ + +struct IEEE80211_Hdr { + u16 FrameControl; + u16 DurationID; + u8 address1[ETH_ALEN]; + u8 address2[ETH_ALEN]; + u8 address3[ETH_ALEN]; + u16 SeqControl; + u8 address4[ETH_ALEN]; +} __attribute__ ((packed)); + +struct TxRadiotapHdr { + struct ieee80211_radiotap_header hdr; + u8 rate; + u8 txpower; + u8 rts_retries; + u8 data_retries; +#if 0 + u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; +#endif +} __attribute__ ((packed)); + +#define TX_RADIOTAP_PRESENT ( \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \ + (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \ + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ + 0) + +#define IEEE80211_FC_VERSION_MASK 0x0003 +#define IEEE80211_FC_TYPE_MASK 0x000c +#define IEEE80211_FC_TYPE_MGT 0x0000 +#define IEEE80211_FC_TYPE_CTL 0x0004 +#define IEEE80211_FC_TYPE_DATA 0x0008 +#define IEEE80211_FC_SUBTYPE_MASK 0x00f0 +#define IEEE80211_FC_TOFROMDS_MASK 0x0300 +#define IEEE80211_FC_TODS_MASK 0x0100 +#define IEEE80211_FC_FROMDS_MASK 0x0200 +#define IEEE80211_FC_NODS 0x0000 +#define IEEE80211_FC_TODS 0x0100 +#define IEEE80211_FC_FROMDS 0x0200 +#define IEEE80211_FC_DSTODS 0x0300 + +struct RxRadiotapHdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + u16 chan_freq; + u16 chan_flags; + u8 antenna; + u8 antsignal; + u16 rx_flags; +#if 0 + u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18]; +#endif +} __attribute__ ((packed)); + +#define RX_RADIOTAP_PRESENT ( \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\ + (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \ + 0) + diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/README linux-2.6-libertas/drivers/net/wireless/libertas/README --- linux-2.6-orig/drivers/net/wireless/libertas/README 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/README 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,831 @@ +================================================================================ + README for USB8388 + + (c) Copyright © 2003-2006, Marvell International Ltd. + All Rights Reserved + + This software file (the "File") is distributed by Marvell International + Ltd. under the terms of the GNU General Public License Version 2, June 1991 + (the "License"). You may use, redistribute and/or modify this File in + accordance with the terms and conditions of the License, a copy of which + is available along with the File in the license.txt file or by writing to + the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + + THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + ARE EXPRESSLY DISCLAIMED. The License provides additional details about + this warranty disclaimer. +================================================================================ + +******************* This driver works in kernel 2.6.x only ********************* + +=================== +1) FOR DRIVER BUILD +=================== + + o. Untar the source into a directory + + tar xvzf usb8388-xxxx.tgz + + o. Change to the source directory + + cd usb8388-xxxx/src + + o. Modify Makefile if needed to set correct directory of kernel source + + o. Build the driver + + make distclean + make build + + This should create the files including usb8388.ko which is the driver as + a loadable module. + +===================== +2) FOR DRIVER LOADING +===================== + + o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/ + + o. Load driver by using the following command: + + insmod usb8388.ko [fw_name=usb8388.bin] + +===================== +3) FOR IWPRIV COMMAND +===================== + +NAME + This manual describes the usage of private commands used in Marvell WLAN + Linux Driver. All the commands available in Wlanconfig will not be available + in the iwpriv. + +SYNOPSIS + iwpriv <ethX> <command> [sub-command] ... + + iwpriv ethX version + iwpriv ethX scantype [sub-command] + iwpriv ethX getSNR <n> + iwpriv ethX getNF <n> + iwpriv ethX getRSSI <n> + iwpriv ethX setrxant <n> + iwpriv ethX getrxant + iwpriv ethX settxant <n> + iwpriv ethX gettxant + iwpriv ethX authalgs <n> + iwpriv ethX pre-TBTT <n> + iwpriv ethX 8021xauthalgs <n> + iwpriv ethX encryptionmode <n> + iwpriv ethX setregioncode <n> + iwpriv ethX getregioncode + iwpriv ethX setbcnavg <n> + iwpriv ethX getbcnavg + iwpriv ethX setdataavg <n> + iwpriv ethX setlisteninter <n> + iwpriv ethX getlisteninter + iwpriv ethX setmultipledtim <n> + iwpriv ethX getmultipledtim + iwpriv ethX atimwindow <n> + iwpriv ethX deauth + iwpriv ethX adhocstop + iwpriv ethX radioon + iwpriv ethX radiooff + iwpriv ethX reasso-on + iwpriv ethX reasso-off + iwpriv ethX scanmode [sub-command] + iwpriv ethX setwpaie <n> + iwpriv ethX wlanidle-off + iwpriv ethX wlanidle-on + iwpriv ethX getcis + iwpriv ethX getlog + iwpriv ethX getadhocstatus + iwpriv ethX adhocgrate <n> + +Version 4 Command: + iwpriv ethX inactvityto <n> + iwpriv ethX sleeppd <n> + iwpriv ethX enable11d <n> + iwpriv ethX tpccfg <n> + iwpriv ethX powercfg <n> + iwpriv ethX setafc <n> + iwpriv ethX getafc + +Version 5 Command: + iwpriv ethX ledgpio <n> + iwpriv ethX scanprobes <n> + iwpriv ethX lolisteninter <n> + iwpriv ethX rateadapt <n> <m> + iwpriv ethX txcontrol <n> + iwpriv ethX psnullinterval <n> + iwpriv ethX prescan <n> + iwpriv ethX getrxinfo + iwpriv ethX gettxrate + iwpriv ethX beaconinterval + +DESCRIPTION + Those commands are used to send additional commands to the Marvell WLAN + card via the Linux device driver. + + The ethX parameter specifies the network device that is to be used to + perform this command on. it could be eth0, eth1 etc. + +version + This is used to get the current version of the driver and the firmware. + +scantype + This command is used to set the scan type to be used by the driver in + the scan command. This setting will not be used while performing a scan + for a specific SSID, as it is always done with scan type being active. + + where the sub-commands are: - + active -- to set the scan type to active + passive -- to set the scan type to passive + get -- to get the scan type set in the driver + +getSNR + This command gets the average and non average value of Signal to Noise + Ratio of Beacon and Data. + + where value is:- + 0 -- Beacon non-average. + 1 -- Beacon average. + 2 -- Data non-average. + 3 -- Data average. + + If no value is given, all four values are returned in the order mentioned + above. + + Note: This command is available only when STA is connected. + +getRSSI + This command gets the average and non average value os Receive Signal + Strength of Beacon and Data. + + where value is:- + 0 -- Beacon non-average. + 1 -- Beacon average. + 2 -- Data non-average. + 3 -- Data average. + + Note: This command is available only when STA is connected. + +getNF + This command gets the average and non average value of Noise Floor of + Beacon and Data. + + where value is:- + 0 -- Beacon non-average. + 1 -- Beacon average. + 2 -- Data non-average. + 3 -- Data average. + + Note: This command is available only when STA is connected. + +setrxant + This command is used to set the mode for Rx antenna. + + The options that can be sent are:- + 1 -- Antenna 1. + 2 -- Antenna 2. + 0xFFFF -- Diversity. + + Usage: + iwpriv ethX setrxant 0x01: select Antenna 1. + +getrxant + This command is used to get the mode for Rx antenna. + + +settxant + This command is used to set the mode for Tx antenna. + The options that can be sent are:- + 1 -- Antenna 1. + 2 -- Antenna 2. + 0xFFFF -- Diversity. + Usage: + iwpriv ethX settxant 0x01: select Antenna 1. + +gettxant + This command is used to get the mode for Tx antenna. + +authalgs + This command is used by the WPA supplicant to set the authentication + algorithms in the station. + +8021xauthalgs + This command is used by the WPA supplicant to set the 8021.x authentication algorithm type + station. + + where values can be:- + 1 -- None + 2 -- LEAP + 4 -- TLS + 8 -- TTLs + 16 -- MD5 + + +encryptionmode + This command is used by the WPA supplicant to set the encryption algorithm. + + where values can be:- + 0 -- NONE + 1 -- WEP40 + 2 -- TKIP + 3 -- CCMP + 4 -- WEP104 + +pre-TBTT + This command is used to set pre-TBTT time period where value is in microseconds. + +setregioncode + This command is used to set the region code in the station. + where value is 'region code' for various regions like + USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ... + + Usage: + iwpriv ethX setregioncode 0x10: set region code to USA (0x10). + +getregioncode + This command is used to get the region code information set in the + station. + +setbcnavg + Set the weighting factor for calculating RSSI. + +getbcnavg + Get weighting factor for calculating RSSI. + +setdataavg + Set the weighting factor for calculating SNR. + +setlisteninter + This command is used to set the listen interval in the + station. + + where the value ranges between 1 - 255 + +getlisteninter + This command is used to get the listen interval value set in the + station. + +setmultipledtim + This command is used to set the multiple dtim value in the + station. + where the value is 1,2,3,4,5,0xfffe + 0xfffe means the firmware will use listen interval in association + command for waking up + +getmultipledtim + This command is used to get the multiple dtim value set in the station. + +atimwindow + This command is used to set the atim value in the + station. + + where the value ranges between 0 - 50 + +deauth + This command is used to send the de-authentication to the AP with which + the station is associated. This command is valid only when + station is in Infrastructure mode. + + Note: This command is available only when STA is connected. + +reasso-on + This command is used to enable re-association function in dirver. + +reasso-off + This command is used to disable re-association function in driver + +adhocstop + This command is used to stop beacon transmission from the station and + go into idle state in ad-hoc mode. + + Note: This command is available only when STA is connected. + +radioon + This command is used to turn on the RF antenna. + +radiooff + This command is sued to turn off the RF antenna. + +scanmode + This command is used to set the station to scan for either IBSS + networks or BSS networks or both BSS and IBSS networks. This + command can be used with sub commands, + + where the value for + bss -- Scan All the BSS networks. + ibss -- Scan All the IBSS networks. + any -- Scan both BSS and IBSS networks. + + + +setwpaie + This command is used by WPA supplicant to send the WPA-IE to the driver. + +wlanidle-off + This command is used to get into idle state. + + Note: This command is available only when STA is connected. + +wlanidle-on + This command is used to get off the idle state. + + Note: This command is available only when STA is connected. + + + +getcis + This command is used to read the Card Info Structure Table. + +getlog + This command is used to get the 802.11 statistics available in the + station. + + Note: This command is available only when STA is connected. + +getadhocstatus + This command is used to get the ad-hoc Network Status. + + The various status codes are: + AdhocStarted + AdhocJoined + AdhocIdle + InfraMode + AutoUnknownMode + + Note: This command is available only when STA is connected. + +adhocgrate + This command is used to enable(1) g_rate, Disable(0) g_rate + and request(2) the status which g_rate is disabled/enabled, + for Ad-hoc creator. + + where value is:- + 0 -- Disabled + 1 -- Enabled + 2 -- Get + +ledgpio + This command is used to set/get LEDs. + + iwpriv ethX ledgpio <LEDs> + will set the corresponding LED for the GPIO Line. + + iwpriv ethX ledgpio + will give u which LEDs are Enabled. + + Usage: + iwpriv eth1 ledgpio 1 0 2 1 3 4 + will enable + LED 1 -> GPIO 0 + LED 2 -> GPIO 1 + LED 3 -> GPIO 4 + + iwpriv eth1 ledgpio + shows LED information in the format as mentioned above. + + Note: LED0 is invalid + Note: Maximum Number of LEDs are 16. + +inactivityto + This command is used by the host to set/get the inactivity timeout value, + which specifies when WLAN device is put to sleep. + + Usage: + iwpriv ethX inactivityto [<timeout>] + + where the parameter are: + timeout: timeout value in milliseconds. + + Example: + iwpriv eth1 inactivityto + "get the timeout value" + + iwpriv eth1 inactivityto X + "set timeout value to X ms" + + +sleeppd + This command is used to configure the sleep period of the WLAN device. + + Usage: + iwpriv ethX sleeppd [<sleep period>] + + where the parameter are: + Period: sleep period in milliseconds. Range 10~60. + + Example: + iwpriv eth1 sleeppd 10 + "set period as 10 ms" + iwpriv eth1 sleeppd + "get the sleep period configuration" + +enable11d + This command is used to control 11d + where value is:- + 1 -- Enabled + 0 -- Disabled + 2 -- Get + + + + +tpccfg + Enables or disables automatic transmit power control. + + The first parameter turns this feature on (1) or off (0). When turning + on, the user must also supply four more parameters in the following + order: + -UseSNR (Use SNR (in addition to PER) for TPC algorithm), + -P0 (P0 power level for TPC), + -P1 (P1 power level for TPC), + -P2 (P2 power level for TPC). + + Usage: + iwpriv ethX tpccfg: Get current configuration + iwpriv ethX tpccfg 0: disable auto TPC + iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR; + P0=0x05; P1=0x0a; P2=0x0d; + iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR; + P0=0x05; P1=0x0a; P2=0x0d. + +powercfg + Enables or disables power adaptation. + + The first parameter turns this feature on (1) or off (0). When turning + on, the user must also supply three more parameters in the following + order: + -P0 (P0 power level for Power Adaptation), + -P1 (P1 power level for Power Adaptation), + -P2 (P2 power level for Power Adaptation). + + Usage: + iwpriv ethX powercfg: Get current configuration + iwpriv ethX powercfg 0: disable power adaptation + iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation; + P0=0x0d; P1=0x0f; P2=0x12. + +getafc + This command returns automatic frequency control parameters. It returns + three integers: + -P0: automatic is on (1), or off (0), + -P1: current timing offset in PPM (part per million), and + -P2: current frequency offset in PPM. + +setafc + Set automatic frequency control options. + + The first parameter turns automatic on (1) or off (0). + The user must supply two more parameters in either case, in the following + order: + + When auto is on: + + -P0 (automatic adjustment frequency threshold in PPM), + -P1 (automatic adjustment period in beacon period), + + When auto is off: + + -P0 (manual adjustment timing offset in PPM), and + -P1 (manual adjustment frequency offset in PPM). + + Usage: + iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy + offset are 10 PPM. + + iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment, + frequency threshold 10 PPM, for every 10 beacon periods. + + + +scanprobes + This command sets number of probe requests per channel. + + Usage: + iwpriv ethX scanprobes 3 (set scan probes to 3) + iwpriv ethX scanprobes (get scan probes) + +lolisteninter + This command sets the value of listen interval. + + Usage: + iwpriv ethX lolisteninter 234 (set the lolisteninter to 234) + iwpriv ethX lolisteninter (get the lolisteninter value) + +rateadapt + This command sets the data rates bitmap. + Where <n> + 0: Disable auto rate adapt + 1: Enable auto rate adapt + + <m> + data rate bitmap + Bit Data rate + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 Reserved + 5 6 Mbps + 6 9 Mbps + 7 12 Mbps + 8 18 Mbps + 9 24 Mbps + 10 36 Mbps + 11 48 Mbps + 12 54 Mbps + 12-15 Reserved + + Usage: + iwpriv ethX rateadapt + read the currect data rate setting + iwpriv ethX rateadapt 1 0x07 + enable auto data rate adapt and + data rates are 1Mbps, 2Mbsp and 5.5Mbps + + +txcontrol + This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis. + + Where value <n> is: + if bit[4] == 1: + bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16 + Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv + + bit[12:8] + if bit[12] == 1, bit[11:8] specifies the Tx retry limit. + + bit[14:13] specifies per packet ack policy: + bit[14:13] + 1 0 use immediate ack policy for this packet + 1 1 use no ack policy for this packet + 0 x use the per-packet ack policy setting + + Usage: + iwpriv ethX txcontrol 0x7513 + Use no-ack policy, 5 retires for Tx, 11Mbps rate + + + +psnullinterval + This command is used to set/request NULL package interval for Power Save + under infrastructure mode. + + where value is:- + -1 -- Disabled + n>0 -- Set interval as n (seconds) + +prescan + This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap + + where value is:- + 0 -- Disabled + 1 -- Enabled + 2 -- Get + +getrxinfo + This command gets non average value of Signal to Noise Ratio of Data and rate index. + + The following table shows RateIndex and Rate + + RateIndex Data rate + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 Reserved + 5 6 Mbps + 6 9 Mbps + 7 12 Mbps + 8 18 Mbps + 9 24 Mbps + 10 36 Mbps + 11 48 Mbps + 12 54 Mbps + 13-15 Reserved + +gettxrate + This command gets current Tx rate index of the first packet associated with Rate Adaptation. + + The following table shows RateIndex and Rate + + RateIndex Data rate + 0 1 Mbps + 1 2 Mbps + 2 5.5 Mbps + 3 11 Mbps + 4 Reserved + 5 6 Mbps + 6 9 Mbps + 7 12 Mbps + 8 18 Mbps + 9 24 Mbps + 10 36 Mbps + 11 48 Mbps + 12 54 Mbps + 13-15 Reserved + +bcninterval + This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc + beacon interval when no argument is given. The valid beacon interval is between 20 - 1000, + default beacon interval is 100. + + Usage: + iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100) + iwpriv ethX bcninterval (get adhoc beacon interval) + +========================= +4) FOR WLANCONFIG COMMAND +========================= + +NAME +wlanconfig - configure the additional parameters available for the Marvell + WLAN Linux Driver. + +SYNOPSIS +wlanconfig <ethX> <command> [parameters] ... +wlanconfig ethX version +wlanconfig ethX <rdmac|rdbbp|rdrf> <offset> +wlanconfig ethX <wrmac|wrbbp|wrrf> <offset> <n> +wlanconfig ethX rdeeprom <offset> <length> +wlanconfig ethX sleepparams <config values> +wlanconfig ethX extscan <ssid> +wlanconfig ethX getscanlist + +Version 4 Command: + +Version 5 Command: +wlanconfig ethX hostcmd <hostcmd.conf> <subevent_get> +wlanconfig ethX hostcmd <hostcmd.conf> <subevent_set> + + +Version 6 Command: +wlanconfig ethX setuserscan [ARGS] +wlanconfig ethX getscantable + +Version 8 + + + + +DESCRIPTION + +those commands are used in Marvell specic applicaion called wlanconfig. + +=========== +rdmac +rdbbp +rdrf + These commands are used to read the MAC, BBP and RF registers from the + card. These commands take one parameter that specifies the offset + location that is to be read. This parameter can be specified either in + decimal or in hexadecimal (by preceding the number with a "0x"). + + Usage: + wlanconfig ethX rdmac 0xa123 + wlanconfig ethX rdbbp 0x0123 + wlanconfig ethX rdrf 0x0123 + +wrmac +wrbbp +wrrf + These commands are used to write the MAC, BBP and RF registers in the + card. These commands take two parameters that specify the offset + location and the value that is to be written. This parameters can be + specified either in decimal or in hexadecimal (by preceding the number + with a "0x"). + + Usage: + wlanconfig ethX wrmac 0xa123 0xaa + wlanconfig ethX wrbbp 0x0123 0xaa + wlanconfig ethX wrrf 0x0123 0xaa + + + + +rdeeprom + To read the EEPROM contents of the card. + + Usage: + wlanconfig ethX rdeeprom 0x00 0x10 + +sleepparams + This command is used to set the sleepclock configurations + + Usage: + wlanconfig ethX sleepparams get: reads the current sleepclock configuration + + wlanconfig ethX sleepparams set p1 p2 p3 p4 p5 p6: writes the sleepclock configuration. + + where: + p1 is Sleep clock error in ppm (0-65535) + p2 is Wakeup offset in usec (0-65535) + p3 is Clock stabilization time in usec (0-65535) + p4 is Control periodic calibration (0-2) + p5 is Control the use of external sleep clock (0-2) + p6 is reserved for debug (0-65535) + + + + + +hostcmd <hostcmd.conf> <subevent_get> +hostcmd <hostcmd.conf> <subevent_set> + This command is used to set the configurations for + event descriptor interface command. + hostcmd.conf is a generic configuration file containing multiple configuration enties + for subscrive event API + subsvent_get: get subscribed event parameters + subsvent_set: set subscribed event parameters + + Usage: + wlanconfig ethX hostcmd hostcmd.conf subevent_get + wlanconfig ethX hostcmd hostcmd.conf subevent_set + + +extscan + This command is used to do a specific scan. + + Usage: wlanconfig ethX extscan <SSID> + + Example: + wlanconfig ethX extscan LINKSYS-AP + + To see the results of use getscanlist command. + +getscanlist + This command is used to get the scan results. + + Usage: wlanconfig ethX getscanlist + + Example: + wlanconfig ethX getscanlist + + + + +setuserscan + Initiate a customized scan and retrieve the results + + Usage: + wlanconfig ethX setuserscan [ARGS] + + where [ARGS]: + + chan=[chan#][band][mode] where band is [a,b,g] and mode is + blank for active or 'p' for passive + bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan + ssid="[SSID]" specify a SSID filter for the scan + keep=[0 or 1] keep the previous scan results (1), discard (0) + dur=[scan time] time to scan for each channel in milliseconds + probes=[#] number of probe requests to send on each chan + type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) + + Any combination of the above arguments can be supplied on the command line. + If the chan token is absent, a full channel scan will be completed by + the driver. If the dur or probes tokens are absent, the driver default + setting will be used. The bssid and ssid fields, if blank, + will produce an unfiltered scan. The type field will default to 3 (Any) + and the keep field will default to 0 (Discard). + + Examples: + 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band: + setuserscan chan=1g,6g,11g + + 2) Perform a passive scan on channel 11 for 20 ms: + setuserscan chan=11gp dur=20 + + 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on + channel 36 in the 'a' band: + setuserscan chan=1g,6g,11g,36ap + + 4) Perform an active scan on channel 6 and 36 for a specific SSID: + setuserscan chan=6g,36a ssid="TestAP" + + 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep + the current scan table intact, update existing or append new scan data: + setuserscan bssid=00:50:43:20:12:82 keep=1 + + 6) Scan channel 6, for all infrastructure networks, sending two probe + requests. Keep the previous scan table intact. Update any duplicate + BSSID/SSID matches with the new scan data: + setuserscan chan=6g type=1 probes=2 keep=1 + + All entries in the scan table (not just the new scan data when keep=1) + will be displayed upon completion by use of the getscantable ioctl. + + +getscantable + Display the current contents of the driver scan table + + Usage: + wlanconfig ethX getscantable + + + + + +============================================================================== diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/sbi.h linux-2.6-libertas/drivers/net/wireless/libertas/sbi.h --- linux-2.6-orig/drivers/net/wireless/libertas/sbi.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/sbi.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,125 @@ +/** @file sbi.h + * + * @brief This file contains IF layer definitions. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/11/05: Add Doxygen format comments + 01/05/06: Add kernel 2.6.x support + +********************************************************/ + +#ifndef _SBI_H_ +#define _SBI_H_ + +#include <linux/interrupt.h> + +#include "wlan_defs.h" + +/**Bit Definition*/ +#define B_BIT_0 0x01 +#define B_BIT_1 0x02 +#define B_BIT_2 0x04 +#define B_BIT_3 0x08 +#define B_BIT_4 0x10 +#define B_BIT_5 0x20 +#define B_BIT_6 0x40 +#define B_BIT_7 0x80 +#define B_BIT_8 0x100 +#define B_BIT_9 0X200 +#define B_BIT_10 0x400 + +/** INT Status Bit Definition*/ +#define HIS_CmdDnLdRdy B_BIT_2 +#define HIS_CardEvent B_BIT_3 +#define HIS_CmdUpLdRdy B_BIT_4 +#define HIS_WrFifoOvrflow B_BIT_5 +#define HIS_RdFifoUndrflow B_BIT_6 +#define HIS_WlanReady B_BIT_7 + +#define HIM_DISABLE 0xff +#define HIM_ENABLE 0x03 + +#define FIRMWARE_READY 0xfedc +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif +#define MAXKEYLEN 13 + +/* The number of times to try when polling for status bits */ +#define MAX_POLL_TRIES 100 + +/* The number of times to try when waiting for downloaded firmware to + become active. (polling the scratch register). */ + +#define MAX_FIRMWARE_POLL_TRIES 100 + +#define FIRMWARE_TRANSFER_NBLOCK 2 +#define SBI_EVENT_CAUSE_SHIFT 3 + +enum mv_sd_type { + MVSD_DAT, + MVSD_CMD, + MVSD_TXDONE, + MVSD_EVENT, +}; + +/** Function Prototype Declaration */ +typedef wlan_private *(*wlan_notifier_fn_add) (void *dev_id); +typedef int (*wlan_notifier_fn_remove) (void *dev_id); + +typedef irqreturn_t(*isr_notifier_fn_t) (s32 irq, void *dev_id, + struct pt_regs * reg); +typedef irqreturn_t(*handler_fn_t) (s32 irq, void *dev_id, struct pt_regs *); + +/* Probe and Check if the card is present*/ +int libertas_sbi_probe_card(void *card); +int libertas_sbi_register_dev(wlan_private * priv); +int libertas_sbi_unregister_dev(wlan_private *); +int libertas_sbi_disable_host_int(wlan_private * priv); +int libertas_sbi_get_int_status(wlan_private * priv, u8 *); +int *libertas_sbi_register(wlan_notifier_fn_add, wlan_notifier_fn_remove, void *); +void libertas_sbi_unregister(void); +int libertas_sbi_prog_firmware(wlan_private *); +int libertas_sbi_verify_fw_download(wlan_private *); + +int libertas_sbi_read_event_cause(wlan_private *); +int libertas_sbi_reenable_host_interrupt(wlan_private *, u8); +int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); +int libertas_sbi_enable_host_int(wlan_private *); + +#ifdef ENABLE_PM +int libertas_sbi_suspend(wlan_private *); +int libertas_sbi_resume(wlan_private *); +#endif + +int libertas_sbi_get_cis_info(wlan_private * priv); + +static inline u32 libertas_get_utimeofday(void) +{ + struct timeval t; + u32 ut; + + do_gettimeofday(&t); + ut = (u32) t.tv_sec * 1000000 + ((u32) t.tv_usec); + return ut; +} + +#endif /* _SBI_H */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_11d.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_11d.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_11d.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_11d.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,872 @@ +/** @file wlan_11d.c + * @brief This file contains functions for 802.11D. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +#include <linux/ctype.h> +#include <linux/kernel.h> +#include <linux/wireless.h> + +#include "host.h" +#include "wlan_decl.h" +#include "wlan_11d.h" +#include "wlan_dev.h" +#include "wlan_wext.h" + +#define TX_PWR_DEFAULT 10 + +static struct region_code_mapping region_code_mapping[] = { + {"US ", 0x10}, /* US FCC */ + {"CA ", 0x10}, /* IC Canada */ + {"SG ", 0x10}, /* Singapore */ + {"EU ", 0x30}, /* ETSI */ + {"AU ", 0x30}, /* Australia */ + {"KR ", 0x30}, /* Republic Of Korea */ + {"ES ", 0x31}, /* Spain */ + {"FR ", 0x32}, /* France */ + {"JP ", 0x40}, /* Japan */ +}; + +/* Following 2 structure defines the supported channels */ +static struct chan_freq_power channel_freq_power_UN_BG[] = { + {1, 2412, TX_PWR_DEFAULT}, + {2, 2417, TX_PWR_DEFAULT}, + {3, 2422, TX_PWR_DEFAULT}, + {4, 2427, TX_PWR_DEFAULT}, + {5, 2432, TX_PWR_DEFAULT}, + {6, 2437, TX_PWR_DEFAULT}, + {7, 2442, TX_PWR_DEFAULT}, + {8, 2447, TX_PWR_DEFAULT}, + {9, 2452, TX_PWR_DEFAULT}, + {10, 2457, TX_PWR_DEFAULT}, + {11, 2462, TX_PWR_DEFAULT}, + {12, 2467, TX_PWR_DEFAULT}, + {13, 2472, TX_PWR_DEFAULT}, + {14, 2484, TX_PWR_DEFAULT} +}; + +extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, + u8 band, int *cfp_no); + +/** + * @brief This function convert Region string to code integer + * @param region region string + * @return region id +*/ +static u8 wlan_region_2_code(s8 * region) +{ + u8 i; + u8 size = sizeof(region_code_mapping)/ + sizeof(struct region_code_mapping); + + for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) + region[i] = toupper(region[i]); + + for (i = 0; i < size; i++) { + if (!memcmp(region, region_code_mapping[i].region, + COUNTRY_CODE_LEN)) + return (region_code_mapping[i].code); + } + + /* default is US */ + return (region_code_mapping[0].code); +} + +/** + * @brief This function converts interger code to region string + * @param code region code + * @return region string +*/ +static u8 *wlan_code_2_region(u8 code) +{ + u8 i; + u8 size = sizeof(region_code_mapping) + / sizeof(struct region_code_mapping); + for (i = 0; i < size; i++) { + if (region_code_mapping[i].code == code) + return (region_code_mapping[i].region); + } + /* default is US */ + return (region_code_mapping[0].region); +} + +/** + * @brief This function finds the NoOfChan-th chan after the firstChan + * @param band band + * @param firstChan first channel number + * @param NoOfChan number of channels + * @return the NoOfChan-th chan number +*/ +static u8 wlan_get_chan_11d(u8 band, u8 firstChan, u8 NoOfChan, u8 * chan) +/*find the NoOfChan-th chan after the firstChan*/ +{ + u8 i; + struct chan_freq_power *cfp; + u8 cfp_no; + + ENTER(); + + { + cfp = channel_freq_power_UN_BG; + cfp_no = sizeof(channel_freq_power_UN_BG) / + sizeof(struct chan_freq_power); + } + + for (i = 0; i < cfp_no; i++) { + if ((cfp + i)->Channel == firstChan) { + PRINTM(INFO, "firstChan found\n"); + break; + } + } + + if (i < cfp_no) { + /*if beyond the boundary */ + if (i + NoOfChan < cfp_no) { + *chan = (cfp + i + NoOfChan)->Channel; + return 1; + } + } + + LEAVE(); + return 0; +} + +/** + * @brief This function Checks if chan txpwr is learned from AP/IBSS + * @param chan chan number + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return TRUE; FALSE +*/ +static u8 wlan_channel_known_11d(u8 chan, + struct parsed_region_chan_11d * parsed_region_chan) +{ + struct chan_power_11d *chanPwr = parsed_region_chan->chanPwr; + u8 NoOfChan = parsed_region_chan->NoOfChan; + u8 i = 0; + + ENTER(); + HEXDUMP("11D:parsed_region_chan:", (char *)chanPwr, + sizeof(struct chan_power_11d) * NoOfChan); + + for (i = 0; i < NoOfChan; i++) { + if (chan == chanPwr[i].chan) { + PRINTM(INFO, "11D: Found Chan:%d\n", chan); + LEAVE(); + return 1; + } + } + + PRINTM(INFO, "11D: Not Find Chan:%d\n", chan); + LEAVE(); + return 0; +} + +/** + * @brief This function Converts chan to frequency + * @param chan channel number + * @param band band + * @return channel frequency +*/ +u32 libertas_chan_2_freq(u8 chan, u8 band) +{ + struct chan_freq_power *cf; + u16 cnt; + u16 i; + u32 freq = 0; + + ENTER(); + + { + cf = channel_freq_power_UN_BG; + cnt = + sizeof(channel_freq_power_UN_BG) / + sizeof(struct chan_freq_power); + } + + for (i = 0; i < cnt; i++) { + if (chan == cf[i].Channel) + freq = cf[i].Freq; + } + + LEAVE(); + return freq; +} + +/** + * @brief This function generates domaininfo from parsed_region_chan + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @param domaininfo pointer to wlan_802_11d_domain_reg + * @return WLAN_STATUS_SUCCESS +*/ +static int wlan_generate_domain_info_11d(struct parsed_region_chan_11d + *parsed_region_chan, + struct wlan_802_11d_domain_reg * domaininfo) +{ + u8 NoOfSubband = 0; + + u8 NoOfChan = parsed_region_chan->NoOfChan; + u8 NoOfParsedChan = 0; + + u8 firstChan = 0, nextChan = 0, maxPwr = 0; + + u8 i, flag = 0; + + ENTER(); + + memcpy(domaininfo->CountryCode, parsed_region_chan->CountryCode, + COUNTRY_CODE_LEN); + + PRINTM(INFO, "11D:NoOfChan=%d\n", NoOfChan); + HEXDUMP("11D:parsed_region_chan:", (char *)parsed_region_chan, + sizeof(struct parsed_region_chan_11d)); + + for (i = 0; i < NoOfChan; i++) { + if (!flag) { + flag = 1; + nextChan = firstChan = + parsed_region_chan->chanPwr[i].chan; + maxPwr = parsed_region_chan->chanPwr[i].pwr; + NoOfParsedChan = 1; + continue; + } + + if (parsed_region_chan->chanPwr[i].chan == nextChan + 1 && + parsed_region_chan->chanPwr[i].pwr == maxPwr) { + nextChan++; + NoOfParsedChan++; + } else { + domaininfo->Subband[NoOfSubband].FirstChan = firstChan; + domaininfo->Subband[NoOfSubband].NoOfChan = + NoOfParsedChan; + domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr; + NoOfSubband++; + nextChan = firstChan = + parsed_region_chan->chanPwr[i].chan; + maxPwr = parsed_region_chan->chanPwr[i].pwr; + } + } + + if (flag) { + domaininfo->Subband[NoOfSubband].FirstChan = firstChan; + domaininfo->Subband[NoOfSubband].NoOfChan = NoOfParsedChan; + domaininfo->Subband[NoOfSubband].MaxTxPwr = maxPwr; + NoOfSubband++; + } + domaininfo->NoOfSubband = NoOfSubband; + + PRINTM(INFO, "NoOfSubband=%x\n", domaininfo->NoOfSubband); + HEXDUMP("11D:domaininfo:", (char *)domaininfo, + COUNTRY_CODE_LEN + 1 + + sizeof(struct IEEEtypes_SubbandSet) * NoOfSubband); + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS + * @param region_chan pointer to struct region_channel + * @param *parsed_region_chan pointer to parsed_region_chan_11d + * @return N/A +*/ +static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan, + struct parsed_region_chan_11d * + parsed_region_chan) +{ + u8 i; + struct chan_freq_power *cfp; + + ENTER(); + + if (region_chan == NULL) { + PRINTM(INFO, "11D: region_chan is NULL\n"); + return; + } + + cfp = region_chan->CFP; + if (cfp == NULL) { + PRINTM(INFO, "11D: cfp equal NULL \n"); + return; + } + + parsed_region_chan->band = region_chan->Band; + parsed_region_chan->region = region_chan->Region; + memcpy(parsed_region_chan->CountryCode, + wlan_code_2_region(region_chan->Region), COUNTRY_CODE_LEN); + + PRINTM(INFO, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region, + parsed_region_chan->band); + + for (i = 0; i < region_chan->NrCFP; i++, cfp++) { + parsed_region_chan->chanPwr[i].chan = cfp->Channel; + parsed_region_chan->chanPwr[i].pwr = cfp->MaxTxPower; + PRINTM(INFO, "11D: Chan[%d] Pwr[%d]\n", + parsed_region_chan->chanPwr[i].chan, + parsed_region_chan->chanPwr[i].pwr); + } + parsed_region_chan->NoOfChan = region_chan->NrCFP; + + PRINTM(INFO, "11D: NoOfChan[%d]\n", parsed_region_chan->NoOfChan); + + LEAVE(); + return; +} + +/** + * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS + * @param region region ID + * @param band band + * @param chan chan + * @return TRUE;FALSE +*/ +static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) +{ + struct chan_freq_power *cfp; + int cfp_no; + u8 idx; + + ENTER(); + + if ((cfp = libertas_get_region_cfp_table(region, band, &cfp_no)) == NULL) { + return 0; + } + + for (idx = 0; idx < cfp_no; idx++) { + if (chan == (cfp + idx)->Channel) { + /* If Mrvl Chip Supported? */ + if ((cfp + idx)->Unsupported) { + return 0; + } else { + return 1; + } + } + } + + /*chan is not in the region table */ + LEAVE(); + return 0; +} + +/** + * @brief This function checks if chan txpwr is learned from AP/IBSS + * @param chan chan number + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return WLAN_STATUS_SUCCESS +*/ +static int wlan_parse_domain_info_11d(struct IEEEtypes_CountryInfoFullSet* CountryInfo, + u8 band, + struct parsed_region_chan_11d * + parsed_region_chan) +{ + u8 NoOfSubband, NoOfChan; + u8 lastChan, firstChan; + u8 region; + u8 curChan = 0; + + u8 idx = 0; /*chan index in parsed_region_chan */ + + u8 j, i; + + ENTER(); + + /*Validation Rules: + 1. Valid Region Code + 2. First Chan increment + 3. Channel range no overlap + 4. Channel is valid? + 5. Channel is supported by Region? + 6. Others + */ + + HEXDUMP("CountryInfo:", (s8 *) CountryInfo, 30); + + if ((*(CountryInfo->CountryCode)) == 0 + || (CountryInfo->Len <= COUNTRY_CODE_LEN)) { + /* No region Info or Wrong region info: treat as No 11D info */ + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + /*Step1: check region_code */ + parsed_region_chan->region = region = + wlan_region_2_code(CountryInfo->CountryCode); + + PRINTM(INFO, "regioncode=%x\n", (u8) parsed_region_chan->region); + HEXDUMP("CountryCode:", (char *)CountryInfo->CountryCode, + COUNTRY_CODE_LEN); + + parsed_region_chan->band = band; + + memcpy(parsed_region_chan->CountryCode, CountryInfo->CountryCode, + COUNTRY_CODE_LEN); + + NoOfSubband = (CountryInfo->Len - COUNTRY_CODE_LEN) / + sizeof(struct IEEEtypes_SubbandSet); + + for (j = 0, lastChan = 0; j < NoOfSubband; j++) { + + if (CountryInfo->Subband[j].FirstChan <= lastChan) { + /*Step2&3. Check First Chan Num increment and no overlap */ + PRINTM(INFO, "11D: Chan[%d>%d] Overlap\n", + CountryInfo->Subband[j].FirstChan, lastChan); + continue; + } + + firstChan = CountryInfo->Subband[j].FirstChan; + NoOfChan = CountryInfo->Subband[j].NoOfChan; + + for (i = 0; idx < MAX_NO_OF_CHAN && i < NoOfChan; i++) { + /*step4: channel is supported? */ + + if (!wlan_get_chan_11d(band, firstChan, i, &curChan)) { + /* Chan is not found in UN table */ + PRINTM(INFO, "chan is not supported: %d \n", i); + break; + } + + lastChan = curChan; + + if (wlan_region_chan_supported_11d + (region, band, curChan)) { + /*step5: Check if curChan is supported by mrvl in region */ + parsed_region_chan->chanPwr[idx].chan = curChan; + parsed_region_chan->chanPwr[idx].pwr = + CountryInfo->Subband[j].MaxTxPwr; + idx++; + } else { + /*not supported and ignore the chan */ + PRINTM(INFO, + "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", + i, curChan, region, band); + } + } + + /*Step6: Add other checking if any */ + + } + + parsed_region_chan->NoOfChan = idx; + + PRINTM(INFO, "NoOfChan=%x\n", parsed_region_chan->NoOfChan); + HEXDUMP("11D:parsed_region_chan:", (s8 *) parsed_region_chan, + 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function calculates the scan type for channels + * @param chan chan number + * @param parsed_region_chan pointer to parsed_region_chan_11d + * @return PASSIVE if chan is unknown; ACTIVE if chan is known +*/ +u8 libertas_get_scan_type_11d(u8 chan, + struct parsed_region_chan_11d * parsed_region_chan) +{ + u8 scan_type = HostCmd_SCAN_TYPE_PASSIVE; + + ENTER(); + + if (wlan_channel_known_11d(chan, parsed_region_chan)) { + PRINTM(INFO, "11D: Found and do Active Scan\n"); + scan_type = HostCmd_SCAN_TYPE_ACTIVE; + } else { + PRINTM(INFO, "11D: Not Find and do Passive Scan\n"); + } + + LEAVE(); + return scan_type; + +} + +/** + * @brief This function gets if 11D is enabled + * @param priv pointer to wlan_private + * @return ENABLE_11D;DISABLE_11D +*/ +enum state_11d libertas_get_state_11d(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + struct wlan_802_11d_state *state = &Adapter->State11D; + return (state->Enable11D); +} + +/** + * @brief initialize internal variable for 11D + * @param priv pointer to wlan_private + * @return N/A +*/ +void libertas_init_11d(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + struct wlan_802_11d_state *state = &Adapter->State11D; + + state->Enable11D = DISABLE_11D; + + memset(&(priv->adapter->parsed_region_chan), 0, + sizeof(struct parsed_region_chan_11d)); + + return; +} + +/** + * @brief This function enable/disable 11D + * @param priv pointer to wlan_private + * @param flag enable/disable flag + * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE +*/ +static int wlan_enable_11d(wlan_private * priv, enum state_11d flag) +{ + wlan_adapter *Adapter = priv->adapter; + struct wlan_802_11d_state *state = &Adapter->State11D; + int ret; + enum state_11d enable = flag; + + ENTER(); + + state->Enable11D = flag; + + /* send cmd to FW to enable/disable 11D fucntion in FW */ + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_SET, + HostCmd_OPTION_WAITFORRSP, + OID_802_11D_ENABLE, &enable); + if (ret) { + PRINTM(INFO, "11D: Fail to enable 11D \n"); + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function sets DOMAIN INFO to FW + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE +*/ +static int wlan_set_domain_info_11d(wlan_private * priv) +{ + int ret; + + if (!libertas_get_state_11d(priv)) { + PRINTM(INFO, "11D: dnld domain Info with 11d disabled\n"); + return WLAN_STATUS_SUCCESS; + } + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, + HostCmd_ACT_GEN_SET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + if (ret) { + PRINTM(INFO, "11D: Fail to dnld domain Info\n"); + } + + LEAVE(); + return ret; +} + +/** + * @brief This function setups scan channels + * @param priv pointer to wlan_private + * @param band band + * @return WLAN_STATUS_SUCCESS +*/ +int libertas_set_universaltable(wlan_private * priv, u8 band) +{ + wlan_adapter *Adapter = priv->adapter; + u16 size = sizeof(struct chan_freq_power); + u16 i = 0; + + ENTER(); + + memset(Adapter->universal_channel, 0, + sizeof(Adapter->universal_channel)); + + { + Adapter->universal_channel[i].NrCFP = + sizeof(channel_freq_power_UN_BG) / size; + PRINTM(INFO, "11D: BG-band NrCFP=%d\n", + Adapter->universal_channel[i].NrCFP); + + Adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; + Adapter->universal_channel[i].Valid = 1; + Adapter->universal_channel[i].Region = UNIVERSAL_REGION_CODE; + Adapter->universal_channel[i].Band = band; + i++; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function implements command CMD_802_11D_DOMAIN_INFO + * @param priv pointer to wlan_private + * @param cmd pointer to cmd buffer + * @param cmdno cmd ID + * @param CmdOption cmd action + * @return WLAN_STATUS_SUCCESS +*/ +int libertas_cmd_802_11d_domain_info(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, u16 cmdno, + u16 CmdOption) +{ + struct HostCmd_DS_802_11D_DOMAIN_INFO *pDomainInfo = + &cmd->params.domaininfo; + struct MrvlIEtypes_DomainParamSet *domain = &pDomainInfo->Domain; + wlan_adapter *Adapter = priv->adapter; + u8 NoOfSubband = Adapter->DomainReg.NoOfSubband; + + ENTER(); + + PRINTM(INFO, "NoOfSubband=%x\n", NoOfSubband); + + cmd->Command = wlan_cpu_to_le16(cmdno); + pDomainInfo->Action = wlan_cpu_to_le16(CmdOption); + if (CmdOption == HostCmd_ACT_GET) { + cmd->Size = + wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN); + HEXDUMP("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, + (int)(cmd->Size)); + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + domain->Header.Type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN); + memcpy(domain->CountryCode, Adapter->DomainReg.CountryCode, + sizeof(domain->CountryCode)); + + domain->Header.Len = + wlan_cpu_to_le16(NoOfSubband * sizeof(struct IEEEtypes_SubbandSet) + + sizeof(domain->CountryCode)); + + if (NoOfSubband) { + memcpy(domain->Subband, Adapter->DomainReg.Subband, + NoOfSubband * sizeof(struct IEEEtypes_SubbandSet)); + + cmd->Size = wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + + domain->Header.Len + + sizeof(struct MrvlIEtypesHeader) + + S_DS_GEN); + } else { + cmd->Size = + wlan_cpu_to_le16(sizeof(pDomainInfo->Action) + S_DS_GEN); + } + + HEXDUMP("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->Size)); + + LEAVE(); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function implements private cmd: enable/disable 11D + * @param priv pointer to wlan_private + * @param wrq pointer to user data + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) +{ + int data = 0; + int *val; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + data = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + + PRINTM(INFO, "Enable 11D: %s\n", + (data == CMD_ENABLED) ? "Enable" : "Disable"); + switch (data) { + case CMD_ENABLED: + wlan_enable_11d(priv, ENABLE_11D); + break; + case CMD_DISABLED: + wlan_enable_11d(priv, DISABLE_11D); + break; + default: + break; + } + + data = + (Adapter->State11D.Enable11D == + ENABLE_11D) ? CMD_ENABLED : CMD_DISABLED; + val = (int *)wrq->u.name; + *val = data; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function parses countryinfo from AP and download country info to FW + * @param priv pointer to wlan_private + * @param resp pointer to command response buffer + * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE + */ +int libertas_ret_802_11d_domain_info(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11D_DOMAIN_INFO_RSP + *domaininfo = &resp->params.domaininforesp; + struct MrvlIEtypes_DomainParamSet *domain = &domaininfo->Domain; + u16 Action = wlan_le16_to_cpu(domaininfo->Action); + s16 ret = WLAN_STATUS_SUCCESS; + u8 NoOfSubband = 0; + + ENTER(); + + HEXDUMP("11D DOMAIN Info Rsp Data:", (u8 *) resp, + (int)wlan_le16_to_cpu(resp->Size)); + + NoOfSubband = (domain->Header.Len - 3) / sizeof(struct IEEEtypes_SubbandSet); + /* countrycode 3 bytes */ + + PRINTM(INFO, "11D Domain Info Resp: NoOfSubband=%d\n", NoOfSubband); + + if (NoOfSubband > MRVDRV_MAX_SUBBAND_802_11D) { + PRINTM(INFO, "Invalid Numrer of Subband returned!!\n"); + return WLAN_STATUS_FAILURE; + } + + switch (Action) { + case HostCmd_ACT_SET: /*Proc Set Action */ + break; + + case HostCmd_ACT_GET: + break; + default: + PRINTM(INFO, "Invalid Action:%d\n", domaininfo->Action); + ret = WLAN_STATUS_FAILURE; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief This function parses countryinfo from AP and download country info to FW + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE + */ +int libertas_parse_dnld_countryinfo_11d(wlan_private * priv) +{ + int ret; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + if (libertas_get_state_11d(priv) == ENABLE_11D) { + + memset(&Adapter->parsed_region_chan, 0, + sizeof(struct parsed_region_chan_11d)); + + ret = + wlan_parse_domain_info_11d(&Adapter->pAttemptedBSSDesc-> + CountryInfo, 0, + &Adapter->parsed_region_chan); + + if (ret == WLAN_STATUS_FAILURE) { + PRINTM(INFO, "11D: Err Parse domain_info from AP..\n"); + LEAVE(); + return ret; + } + + memset(&Adapter->DomainReg, 0, + sizeof(struct wlan_802_11d_domain_reg)); + wlan_generate_domain_info_11d(&Adapter->parsed_region_chan, + &Adapter->DomainReg); + + ret = wlan_set_domain_info_11d(priv); + + if (ret) { + PRINTM(INFO, "11D: Err set domainInfo to FW\n"); + LEAVE(); + return ret; + } + } + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function generates 11D info from user specified regioncode and download to FW + * @param priv pointer to wlan_private + * @return WLAN_STATUS_SUCCESS; WLAN_STATUS_FAILURE + */ +int libertas_create_dnld_countryinfo_11d(wlan_private * priv) +{ + int ret; + wlan_adapter *Adapter = priv->adapter; + struct region_channel *region_chan; + u8 j; + + ENTER(); + PRINTM(INFO, "11D:CurBssParams.Band[%d]\n", Adapter->CurBssParams.band); + + if (libertas_get_state_11d(priv) == ENABLE_11D) { + /* update parsed_region_chan_11; dnld domaininf to FW */ + + for (j = 0; j < sizeof(Adapter->region_channel) / + sizeof(Adapter->region_channel[0]); j++) { + region_chan = &Adapter->region_channel[j]; + + PRINTM(INFO, "11D:[%d] region_chan->Band[%d]\n", j, + region_chan->Band); + + if (!region_chan || !region_chan->Valid + || !region_chan->CFP) + continue; + if (region_chan->Band != Adapter->CurBssParams.band) + continue; + break; + } + + if (j >= sizeof(Adapter->region_channel) / + sizeof(Adapter->region_channel[0])) { + PRINTM(INFO, "11D:region_chan not found. Band[%d]\n", + Adapter->CurBssParams.band); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + memset(&Adapter->parsed_region_chan, 0, + sizeof(struct parsed_region_chan_11d)); + wlan_generate_parsed_region_chan_11d(region_chan, + &Adapter-> + parsed_region_chan); + + memset(&Adapter->DomainReg, 0, + sizeof(struct wlan_802_11d_domain_reg)); + wlan_generate_domain_info_11d(&Adapter->parsed_region_chan, + &Adapter->DomainReg); + + ret = wlan_set_domain_info_11d(priv); + + if (ret) { + PRINTM(INFO, "11D: Err set domainInfo to FW\n"); + LEAVE(); + return ret; + } + + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_11d.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_11d.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_11d.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_11d.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,160 @@ +/** @file wlan_11d.h + * @brief This header file contains data structures and + * function declarations of 802.11d + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change log: + 09/26/05: add Doxygen format comments + ************************************************************/ + +#ifndef _WLAN_11D_ +#define _WLAN_11D_ + +#include "wlan_types.h" +#include "wlan_defs.h" + +#define MAX_CHAN_NUM 255 + +#define UNIVERSAL_REGION_CODE 0xff + +/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) + */ +#define MRVDRV_MAX_SUBBAND_802_11D 83 + +#define COUNTRY_CODE_LEN 3 +#define MAX_NO_OF_CHAN 40 + +struct HostCmd_DS_COMMAND; + +enum state_11d { + DISABLE_11D, + ENABLE_11D, +}; + +/** Data structure for Country IE*/ +struct IEEEtypes_SubbandSet { + u8 FirstChan; + u8 NoOfChan; + u8 MaxTxPwr; +} __attribute__ ((packed)); + +struct IEEEtypes_CountryInfoSet { + u8 ElementId; + u8 Len; + u8 CountryCode[COUNTRY_CODE_LEN]; + struct IEEEtypes_SubbandSet Subband[1]; +}; + +struct IEEEtypes_CountryInfoFullSet { + u8 ElementId; + u8 Len; + u8 CountryCode[COUNTRY_CODE_LEN]; + struct IEEEtypes_SubbandSet Subband[MRVDRV_MAX_SUBBAND_802_11D]; +} __attribute__ ((packed)); + +struct MrvlIEtypes_DomainParamSet { + struct MrvlIEtypesHeader Header; + u8 CountryCode[COUNTRY_CODE_LEN]; + struct IEEEtypes_SubbandSet Subband[1]; +} __attribute__ ((packed)); + +/** Define data structure for HostCmd_CMD_802_11D_DOMAIN_INFO */ +struct HostCmd_DS_802_11D_DOMAIN_INFO { + u16 Action; + struct MrvlIEtypes_DomainParamSet Domain; +} __attribute__ ((packed)); + +/** Define data structure for HostCmd_RET_802_11D_DOMAIN_INFO */ +struct HostCmd_DS_802_11D_DOMAIN_INFO_RSP { + u16 Action; + struct MrvlIEtypes_DomainParamSet Domain; +} __attribute__ ((packed)); + +/** domain regulatory information */ +struct wlan_802_11d_domain_reg { + /** country Code*/ + u8 CountryCode[COUNTRY_CODE_LEN]; + /** No. of subband*/ + u8 NoOfSubband; + struct IEEEtypes_SubbandSet Subband[MRVDRV_MAX_SUBBAND_802_11D]; +}; + +struct chan_power_11d { + u8 chan; + u8 pwr; +} __attribute__ ((packed)); + +struct parsed_region_chan_11d { + u8 band; + u8 region; + s8 CountryCode[COUNTRY_CODE_LEN]; + struct chan_power_11d chanPwr[MAX_NO_OF_CHAN]; + u8 NoOfChan; +} __attribute__ ((packed)); + +/** Data for state machine */ +struct wlan_802_11d_state { + /** True for Enabling 11D*/ + u8 Enable11D; +}; + +struct region_code_mapping { + s8 region[COUNTRY_CODE_LEN]; + u8 code; +}; + +#if 0 +/* function prototypes*/ +int wlan_generate_domain_info_11d(struct parsed_region_chan_11d + *parsed_region_chan, + struct wlan_802_11d_domain_reg * domaininfo); + +int wlan_parse_domain_info_11d(struct IEEEtypes_CountryInfoFullSet* CountryInfo, + u8 band, + struct parsed_region_chan_11d + *parsed_region_chan); +#endif + +u8 libertas_get_scan_type_11d(u8 chan, + struct parsed_region_chan_11d *parsed_region_chan); + +u32 libertas_chan_2_freq(u8 chan, u8 band); + +enum state_11d libertas_get_state_11d(wlan_private * priv); + +void libertas_init_11d(wlan_private * priv); + +int libertas_set_universaltable(wlan_private * priv, u8 band); + +int libertas_cmd_802_11d_domain_info(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, u16 cmdno, + u16 CmdOption); + +struct iwreq; +int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); + +int libertas_ret_802_11d_domain_info(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); + +int libertas_parse_dnld_countryinfo_11d(wlan_private * priv); + +int libertas_create_dnld_countryinfo_11d(wlan_private * priv); + +#endif /* _WLAN_11D_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_cmd.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_cmd.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_cmd.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_cmd.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,2282 @@ +/** @file wlan_cmd.c + * + * @brief This file contains the handling of command. + * it prepares command and sends it to firmware when + * it is ready. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/04/05: Add Doxygen format comments + 01/05/06: Add kernel 2.6.x support + 01/11/06: Change compile flag BULVERDE_SDIO to SD to support + Monahans/Zylonite + 01/11/06: Conditionalize new scan/join structures + 01/31/06: Add support to selectively enabe the FW Scan channel filter + 02/16/06: Clear scan in progress flag when scan command failed and dropped + 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API +********************************************************/ + +#include <net/iw_handler.h> + +#include "host.h" +#include "hostcmd.h" +#include "sbi.h" +#include "wlan_decl.h" +#include "wlan_defs.h" +#include "wlan_dev.h" +#include "wlan_join.h" +#include "wlan_wext.h" + +static void CleanUpCmdCtrlNode(struct CmdCtrlNode *pTempNode); + +static u16 Commands_Allowed_In_PS[] = { + HostCmd_CMD_802_11_RSSI, +}; + +/** + * @brief This function checks if the commans is allowed + * in PS mode not. + * + * @param Command the command ID + * @return TRUE or FALSE + */ +static u8 Is_Command_Allowed_In_PS(u16 Command) +{ + int count = sizeof(Commands_Allowed_In_PS) + / sizeof(Commands_Allowed_In_PS[0]); + int i; + + for (i = 0; i < count; i++) { + if (Command == wlan_cpu_to_le16(Commands_Allowed_In_PS[i])) + return 1; + } + + return 0; +} + +/** + * @brief This function prepares command of get_hw_spec. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_hw_spec(wlan_private * priv, struct HostCmd_DS_COMMAND *cmd) +{ + struct HostCmd_DS_GET_HW_SPEC *hwspec = &cmd->params.hwspec; + + ENTER(); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_HW_SPEC); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_GET_HW_SPEC) + S_DS_GEN); + memcpy(hwspec->PermanentAddr, priv->adapter->CurrentAddr, ETH_ALEN); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of ps_mode. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_ps_mode(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + struct HostCmd_DS_802_11_PS_MODE *psm = &cmd->params.psmode; + u16 Action = cmd_action; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_PS_MODE) + + S_DS_GEN); + psm->Action = wlan_cpu_to_le16(cmd_action); + psm->MultipleDtim = 0; + switch (Action) { + case HostCmd_SubCmd_Enter_PS: + PRINTM(INFO, "PS Command:" "SubCode- Enter PS\n"); + PRINTM(INFO, "LocalListenInterval = %d\n", + Adapter->LocalListenInterval); + + psm->LocalListenInterval = + wlan_cpu_to_le16(Adapter->LocalListenInterval); + psm->NullPktInterval = + wlan_cpu_to_le16(Adapter->NullPktInterval); + psm->MultipleDtim = + wlan_cpu_to_le16(priv->adapter->MultipleDtim); + break; + + case HostCmd_SubCmd_Exit_PS: + PRINTM(INFO, "PS Command:" "SubCode- Exit PS\n"); + break; + + case HostCmd_SubCmd_Sleep_Confirmed: + PRINTM(INFO, "PS Command: SubCode- sleep confirm\n"); + break; + + default: + break; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of inactivity_timeout. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action Action: GET SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action, void *pdata_buf) +{ + u16 *timeout = (u16 *) pdata_buf; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_INACTIVITY_TIMEOUT); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_INACTIVITY_TIMEOUT) + + S_DS_GEN); + + cmd->params.inactivity_timeout.Action = wlan_cpu_to_le16(cmd_action); + + if (cmd_action) + cmd->params.inactivity_timeout.Timeout = + wlan_cpu_to_le16(*timeout); + else + cmd->params.inactivity_timeout.Timeout = 0; + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of sleep_period. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_sleep_period(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action, void *pdata_buf) +{ + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PERIOD); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_SLEEP_PERIOD) + + S_DS_GEN); + memmove(&cmd->params.ps_sleeppd, pdata_buf, + sizeof(struct HostCmd_DS_802_11_SLEEP_PERIOD)); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of sleep_params. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_sleep_params(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_SLEEP_PARAMS *sp = &cmd->params.sleep_params; + + ENTER(); + + cmd->Size = + wlan_cpu_to_le16((sizeof(struct HostCmd_DS_802_11_SLEEP_PARAMS)) + + S_DS_GEN); + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SLEEP_PARAMS); + + if (cmd_action == HostCmd_ACT_GEN_GET) { + memset(&Adapter->sp, 0, sizeof(struct sleep_params)); + memset(sp, 0, sizeof(struct HostCmd_DS_802_11_SLEEP_PARAMS)); + sp->Action = wlan_cpu_to_le16(cmd_action); + } else if (cmd_action == HostCmd_ACT_GEN_SET) { + sp->Action = wlan_cpu_to_le16(cmd_action); + sp->Error = wlan_cpu_to_le16(Adapter->sp.sp_error); + sp->Offset = wlan_cpu_to_le16(Adapter->sp.sp_offset); + sp->StableTime = wlan_cpu_to_le16(Adapter->sp.sp_stabletime); + sp->CalControl = (u8) Adapter->sp.sp_calcontrol; + sp->ExternalSleepClk = (u8) Adapter->sp.sp_extsleepclk; + sp->Reserved = wlan_cpu_to_le16(Adapter->sp.sp_reserved); + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +#define WEP_40_BIT_LEN 5 +#define WEP_104_BIT_LEN 13 + +/** + * @brief This function prepares command of set_wep. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_oid OID: ADD_WEP KEY or REMOVE_WEP KEY + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_set_wep(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, u32 cmd_oid) +{ + struct HostCmd_DS_802_11_SET_WEP *wep = &cmd->params.wep; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (cmd_oid == OID_802_11_ADD_WEP) { + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP); + cmd->Size = + wlan_cpu_to_le16((sizeof(struct HostCmd_DS_802_11_SET_WEP)) + + S_DS_GEN); + wep->Action = wlan_cpu_to_le16(HostCmd_ACT_ADD); + + /* default tx key index */ + wep->KeyIndex = wlan_cpu_to_le16(Adapter->CurrentWepKeyIndex & + HostCmd_WEP_KEY_INDEX_MASK); + + PRINTM(INFO, "Tx Key Index: %u\n", wep->KeyIndex); + + switch (Adapter->WepKey[0].KeyLength) { + case WEP_40_BIT_LEN: + wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_40_BIT; + memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial, + Adapter->WepKey[0].KeyLength); + break; + case WEP_104_BIT_LEN: + wep->WEPTypeForKey1 = HostCmd_TYPE_WEP_104_BIT; + memmove(wep->WEP1, Adapter->WepKey[0].KeyMaterial, + Adapter->WepKey[0].KeyLength); + break; + case 0: + break; + default: + PRINTM(INFO, "Key1 Length = %d is incorrect\n", + Adapter->WepKey[0].KeyLength); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + switch (Adapter->WepKey[1].KeyLength) { + case WEP_40_BIT_LEN: + wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_40_BIT; + memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial, + Adapter->WepKey[1].KeyLength); + break; + case WEP_104_BIT_LEN: + wep->WEPTypeForKey2 = HostCmd_TYPE_WEP_104_BIT; + memmove(wep->WEP2, Adapter->WepKey[1].KeyMaterial, + Adapter->WepKey[1].KeyLength); + break; + case 0: + break; + default: + PRINTM(INFO, "Key2 Length = %d is incorrect\n", + Adapter->WepKey[1].KeyLength); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + switch (Adapter->WepKey[2].KeyLength) { + case WEP_40_BIT_LEN: + wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_40_BIT; + memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial, + Adapter->WepKey[2].KeyLength); + break; + case WEP_104_BIT_LEN: + wep->WEPTypeForKey3 = HostCmd_TYPE_WEP_104_BIT; + memmove(wep->WEP3, Adapter->WepKey[2].KeyMaterial, + Adapter->WepKey[2].KeyLength); + break; + case 0: + break; + default: + PRINTM(INFO, "Key3 Length = %d is incorrect\n", + Adapter->WepKey[2].KeyLength); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + switch (Adapter->WepKey[3].KeyLength) { + case WEP_40_BIT_LEN: + wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_40_BIT; + memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial, + Adapter->WepKey[3].KeyLength); + break; + case WEP_104_BIT_LEN: + wep->WEPTypeForKey4 = HostCmd_TYPE_WEP_104_BIT; + memmove(wep->WEP4, Adapter->WepKey[3].KeyMaterial, + Adapter->WepKey[3].KeyLength); + break; + case 0: + break; + default: + PRINTM(INFO, "Key4 Length = %d is incorrect\n", + Adapter->WepKey[3].KeyLength); + ret = WLAN_STATUS_FAILURE; + goto done; + } + } else if (cmd_oid == OID_802_11_REMOVE_WEP) { + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SET_WEP); + cmd->Size = + wlan_cpu_to_le16((sizeof(struct HostCmd_DS_802_11_SET_WEP)) + + S_DS_GEN); + wep->Action = wlan_cpu_to_le16(HostCmd_ACT_REMOVE); + + /* default tx key index */ + wep->KeyIndex = + wlan_cpu_to_le16((u16) + (Adapter-> + CurrentWepKeyIndex & (u32) + HostCmd_WEP_KEY_INDEX_MASK)); + } + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + return ret; +} + +/** + * @brief This function prepares command of enable_rsn. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + struct HostCmd_DS_802_11_ENABLE_RSN *pEnableRSN = &cmd->params.enbrsn; + wlan_adapter *Adapter = priv->adapter; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ENABLE_RSN); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_ENABLE_RSN) + + S_DS_GEN); + pEnableRSN->Action = wlan_cpu_to_le16(cmd_action); + if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled) { + pEnableRSN->Enable = wlan_cpu_to_le16(HostCmd_ENABLE_RSN); + } else { + pEnableRSN->Enable = wlan_cpu_to_le16(HostCmd_DISABLE_RSN); + } + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of key_material. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param cmd_oid OID: ENABLE or DISABLE + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_key_material(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action, + u32 cmd_oid, void *pdata_buf) +{ + struct HostCmd_DS_802_11_KEY_MATERIAL *pKeyMaterial = + &cmd->params.keymaterial; + struct WLAN_802_11_KEY *pKey = (struct WLAN_802_11_KEY *)pdata_buf; + u16 KeyParamSet_len; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); + pKeyMaterial->Action = wlan_cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_GET) { + cmd->Size = wlan_cpu_to_le16(2 + S_DS_GEN); + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + memset(&pKeyMaterial->KeyParamSet, 0, + sizeof(struct MrvlIEtype_KeyParamSet)); + + if (pKey->KeyLength == WPA_AES_KEY_LEN) { + PRINTM(INFO, "WPA_AES\n"); + pKeyMaterial->KeyParamSet.KeyTypeId = + wlan_cpu_to_le16(KEY_TYPE_ID_AES); + + if (cmd_oid == (u32) KEY_INFO_ENABLED) + pKeyMaterial->KeyParamSet.KeyInfo = + wlan_cpu_to_le16(KEY_INFO_AES_ENABLED); + else + pKeyMaterial->KeyParamSet.KeyInfo = + !(wlan_cpu_to_le16(KEY_INFO_AES_ENABLED)); + + if (pKey->KeyIndex & 0x40000000) //AES pairwise key: unicast + pKeyMaterial->KeyParamSet.KeyInfo |= + wlan_cpu_to_le16(KEY_INFO_AES_UNICAST); + else //AES group key: multicast + pKeyMaterial->KeyParamSet.KeyInfo |= + wlan_cpu_to_le16(KEY_INFO_AES_MCAST); + } else if (pKey->KeyLength == WPA_TKIP_KEY_LEN) { + PRINTM(INFO, "WPA_TKIP\n"); + pKeyMaterial->KeyParamSet.KeyTypeId = + wlan_cpu_to_le16(KEY_TYPE_ID_TKIP); + pKeyMaterial->KeyParamSet.KeyInfo = + wlan_cpu_to_le16(KEY_INFO_TKIP_ENABLED); + + if (pKey->KeyIndex & 0x40000000) //TKIP pairwise key: unicast + pKeyMaterial->KeyParamSet.KeyInfo |= + wlan_cpu_to_le16(KEY_INFO_TKIP_UNICAST); + else //TKIP group key: multicast + pKeyMaterial->KeyParamSet.KeyInfo |= + wlan_cpu_to_le16(KEY_INFO_TKIP_MCAST); + } + + if (pKeyMaterial->KeyParamSet.KeyTypeId) { + pKeyMaterial->KeyParamSet.Type = + wlan_cpu_to_le16(TLV_TYPE_KEY_MATERIAL); + pKeyMaterial->KeyParamSet.KeyLen = + wlan_cpu_to_le16(pKey->KeyLength); + memcpy(pKeyMaterial->KeyParamSet.Key, pKey->KeyMaterial, + pKey->KeyLength); + pKeyMaterial->KeyParamSet.Length = + wlan_cpu_to_le16(pKey->KeyLength + 6); + +#define TYPE_LEN_FIELDS_LEN 4 + KeyParamSet_len = + pKeyMaterial->KeyParamSet.Length + TYPE_LEN_FIELDS_LEN; +#define ACTION_FIELD_LEN 2 + cmd->Size = + wlan_cpu_to_le16(KeyParamSet_len + ACTION_FIELD_LEN + + S_DS_GEN); + } + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + return ret; +} + +/** + * @brief This function prepares command of reset. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_reset(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, int cmd_action) +{ + struct HostCmd_DS_802_11_RESET *reset = &cmd->params.reset; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RESET); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_RESET) + S_DS_GEN); + reset->Action = wlan_cpu_to_le16(cmd_action); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of get_log. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_get_log(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd) +{ + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_GET_LOG) + + S_DS_GEN); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of get_stat. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_get_stat(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd) +{ + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_GET_STAT); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_GET_STAT) + + S_DS_GEN); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of snmp_mib. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param cmd_oid the OID of SNMP MIB + * @param pdata_buf the pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + int cmd_action, + int cmd_oid, void *pdata_buf) +{ + struct HostCmd_DS_802_11_SNMP_MIB *pSNMPMIB = &cmd->params.smib; + wlan_adapter *Adapter = priv->adapter; + u8 ucTemp; + + ENTER(); + + PRINTM(INFO, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_SNMP_MIB) + + S_DS_GEN); + + switch (cmd_oid) { + case OID_802_11_INFRASTRUCTURE_MODE: + pSNMPMIB->QueryType = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pSNMPMIB->OID = wlan_cpu_to_le16((u16) DesiredBssType_i); + pSNMPMIB->BufSize = sizeof(u8); + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) + ucTemp = SNMP_MIB_VALUE_INFRA; + else + ucTemp = SNMP_MIB_VALUE_ADHOC; + + memmove(pSNMPMIB->Value, &ucTemp, sizeof(u8)); + + break; + + case OID_802_11D_ENABLE: + { + u32 ulTemp; + + pSNMPMIB->OID = wlan_cpu_to_le16((u16) Dot11D_i); + + if (cmd_action == HostCmd_ACT_SET) { + pSNMPMIB->QueryType = HostCmd_ACT_GEN_SET; + pSNMPMIB->BufSize = sizeof(u16); + ulTemp = *(u32 *) pdata_buf; + *((unsigned short *)(pSNMPMIB->Value)) = + wlan_cpu_to_le16((u16) ulTemp); + } + break; + } + + case OID_802_11_FRAGMENTATION_THRESHOLD: + { + u32 ulTemp; + + pSNMPMIB->OID = wlan_cpu_to_le16((u16) FragThresh_i); + + if (cmd_action == HostCmd_ACT_GET) { + pSNMPMIB->QueryType = + wlan_cpu_to_le16(HostCmd_ACT_GEN_GET); + } else if (cmd_action == HostCmd_ACT_SET) { + pSNMPMIB->QueryType = + wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pSNMPMIB->BufSize = + wlan_cpu_to_le16(sizeof(u16)); + ulTemp = *((u32 *) pdata_buf); + *((unsigned short *)(pSNMPMIB->Value)) = + wlan_cpu_to_le16((u16) ulTemp); + + } + + break; + } + + case OID_802_11_RTS_THRESHOLD: + { + + u32 ulTemp; + pSNMPMIB->OID = wlan_le16_to_cpu((u16) RtsThresh_i); + + if (cmd_action == HostCmd_ACT_GET) { + pSNMPMIB->QueryType = + wlan_cpu_to_le16(HostCmd_ACT_GEN_GET); + } else if (cmd_action == HostCmd_ACT_SET) { + pSNMPMIB->QueryType = + wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pSNMPMIB->BufSize = + wlan_cpu_to_le16(sizeof(u16)); + ulTemp = *((u32 *) + pdata_buf); + *(unsigned short *)(pSNMPMIB->Value) = + wlan_cpu_to_le16((u16) ulTemp); + + } + break; + } + case OID_802_11_TX_RETRYCOUNT: + pSNMPMIB->OID = wlan_cpu_to_le16((u16) ShortRetryLim_i); + + if (cmd_action == HostCmd_ACT_GET) { + pSNMPMIB->QueryType = + wlan_cpu_to_le16(HostCmd_ACT_GEN_GET); + } else if (cmd_action == HostCmd_ACT_SET) { + pSNMPMIB->QueryType = + wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pSNMPMIB->BufSize = wlan_cpu_to_le16(sizeof(u16)); + *((unsigned short *)(pSNMPMIB->Value)) = + wlan_cpu_to_le16((u16) Adapter->TxRetryCount); + } + + break; + default: + break; + } + + PRINTM(INFO, + "SNMP_CMD: Command=0x%x, Size=0x%x, SeqNum=0x%x, Result=0x%x\n", + cmd->Command, cmd->Size, cmd->SeqNum, cmd->Result); + + PRINTM(INFO, + "SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x, Value=0x%x\n", + pSNMPMIB->QueryType, pSNMPMIB->OID, pSNMPMIB->BufSize, + *(u16 *) pSNMPMIB->Value); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of radio_control. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_radio_control(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + int cmd_action) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_RADIO_CONTROL *pRadioControl = + &cmd->params.radio; + + ENTER(); + + cmd->Size = + wlan_cpu_to_le16((sizeof(struct HostCmd_DS_802_11_RADIO_CONTROL)) + + S_DS_GEN); + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RADIO_CONTROL); + + pRadioControl->Action = wlan_cpu_to_le16(cmd_action); + + switch (Adapter->Preamble) { + case HostCmd_TYPE_SHORT_PREAMBLE: + pRadioControl->Control = wlan_cpu_to_le16(SET_SHORT_PREAMBLE); + break; + + case HostCmd_TYPE_LONG_PREAMBLE: + pRadioControl->Control = wlan_cpu_to_le16(SET_LONG_PREAMBLE); + break; + + case HostCmd_TYPE_AUTO_PREAMBLE: + default: + pRadioControl->Control = wlan_cpu_to_le16(SET_AUTO_PREAMBLE); + break; + } + + if (Adapter->RadioOn) + pRadioControl->Control |= wlan_cpu_to_le16(TURN_ON_RF); + else + pRadioControl->Control &= wlan_cpu_to_le16(~TURN_ON_RF); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of rf_tx_power. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action, void *pdata_buf) +{ + + struct HostCmd_DS_802_11_RF_TX_POWER *pRTP = &cmd->params.txp; + + ENTER(); + + cmd->Size = + wlan_cpu_to_le16((sizeof(struct HostCmd_DS_802_11_RF_TX_POWER)) + + S_DS_GEN); + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_TX_POWER); + pRTP->Action = cmd_action; + + PRINTM(INFO, "RF_TX_POWER_CMD: Size:%d Cmd:0x%x Act:%d\n", cmd->Size, + cmd->Command, pRTP->Action); + + switch (cmd_action) { + case HostCmd_ACT_TX_POWER_OPT_GET: + pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET); + pRTP->CurrentLevel = 0; + break; + + case HostCmd_ACT_TX_POWER_OPT_SET_HIGH: + pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pRTP->CurrentLevel = + wlan_cpu_to_le16(HostCmd_ACT_TX_POWER_INDEX_HIGH); + break; + + case HostCmd_ACT_TX_POWER_OPT_SET_MID: + pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pRTP->CurrentLevel = + wlan_cpu_to_le16(HostCmd_ACT_TX_POWER_INDEX_MID); + break; + + case HostCmd_ACT_TX_POWER_OPT_SET_LOW: + pRTP->Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + pRTP->CurrentLevel = wlan_cpu_to_le16(*((u16 *) pdata_buf)); + break; + } + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of rf_antenna. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct HostCmd_DS_802_11_RF_ANTENNA *rant = &cmd->params.rant; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_ANTENNA); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_RF_ANTENNA) + + S_DS_GEN); + + rant->Action = wlan_cpu_to_le16(cmd_action); + if ((cmd_action == HostCmd_ACT_SET_RX) || + (cmd_action == HostCmd_ACT_SET_TX)) { + rant->AntennaMode = + wlan_cpu_to_le16((u16) (*(u32 *) pdata_buf)); + } + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of rate_adapt_rateset. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + struct HostCmd_DS_802_11_RATE_ADAPT_RATESET + *rateadapt = &cmd->params.rateset; + wlan_adapter *Adapter = priv->adapter; + + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_RATE_ADAPT_RATESET) + + S_DS_GEN); + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RATE_ADAPT_RATESET); + + ENTER(); + + rateadapt->Action = cmd_action; + rateadapt->EnableHwAuto = Adapter->EnableHwAuto; + rateadapt->Bitmap = Adapter->RateBitmap; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of rate_adapt_rateset. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_data_rate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + struct HostCmd_DS_802_11_DATA_RATE *pDataRate = &cmd->params.drate; + wlan_adapter *Adapter = priv->adapter; + u16 Action = cmd_action; + + ENTER(); + + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_DATA_RATE) + + S_DS_GEN); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DATA_RATE); + + memset(pDataRate, 0, sizeof(struct HostCmd_DS_802_11_DATA_RATE)); + + pDataRate->Action = wlan_cpu_to_le16(cmd_action); + + if (Action == HostCmd_ACT_SET_TX_FIX_RATE) { + pDataRate->DataRate[0] = libertas_data_rate_to_index(Adapter->DataRate); + PRINTM(INFO, "Setting FW for fixed rate 0x%02X\n", + Adapter->DataRate); + } else if (Action == HostCmd_ACT_SET_TX_AUTO) { + PRINTM(INFO, "Setting FW for AUTO rate\n"); + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of mac_multicast_adr. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_mac_multicast_adr(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + struct HostCmd_DS_MAC_MULTICAST_ADR *pMCastAdr = &cmd->params.madr; + wlan_adapter *Adapter = priv->adapter; + + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_MAC_MULTICAST_ADR) + + S_DS_GEN); + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); + + pMCastAdr->Action = wlan_cpu_to_le16(cmd_action); + pMCastAdr->NumOfAdrs = + wlan_cpu_to_le16((u16) Adapter->NumOfMulticastMACAddr); + memcpy(pMCastAdr->MACList, Adapter->MulticastList, + Adapter->NumOfMulticastMACAddr * ETH_ALEN); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of rf_channel. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_rf_channel(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + int option, void *pdata_buf) +{ + struct HostCmd_DS_802_11_RF_CHANNEL *rfchan = &cmd->params.rfchannel; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); + cmd->Size = wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_RF_CHANNEL) + + S_DS_GEN); + + if (option == HostCmd_OPT_802_11_RF_CHANNEL_SET) { + rfchan->CurrentChannel = wlan_cpu_to_le16(*((u16 *) pdata_buf)); + } + + rfchan->Action = wlan_cpu_to_le16(option); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of rssi. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_rssi(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd) +{ + wlan_adapter *Adapter = priv->adapter; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_RSSI); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_RSSI) + S_DS_GEN); + cmd->params.rssi.N = priv->adapter->bcn_avg_factor; + + /* reset Beacon SNR/NF/RSSI values */ + Adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; + Adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0; + Adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0; + Adapter->NF[TYPE_BEACON][TYPE_AVG] = 0; + Adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; + Adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of reg_access. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_reg_access(wlan_private * priv, + struct HostCmd_DS_COMMAND *CmdPtr, + u8 cmd_action, void *pdata_buf) +{ + struct wlan_offset_value *offval; + + ENTER(); + + offval = (struct wlan_offset_value *)pdata_buf; + + switch (CmdPtr->Command) { + case HostCmd_CMD_MAC_REG_ACCESS: + { + struct HostCmd_DS_MAC_REG_ACCESS *macreg; + + CmdPtr->Size = + wlan_cpu_to_le16(sizeof + (struct HostCmd_DS_MAC_REG_ACCESS) + + S_DS_GEN); + macreg = + (struct HostCmd_DS_MAC_REG_ACCESS *)&CmdPtr->params. + macreg; + + macreg->Action = wlan_cpu_to_le16(cmd_action); + macreg->Offset = wlan_cpu_to_le16((u16) offval->offset); + macreg->Value = wlan_cpu_to_le32(offval->value); + + break; + } + + case HostCmd_CMD_BBP_REG_ACCESS: + { + struct HostCmd_DS_BBP_REG_ACCESS *bbpreg; + + CmdPtr->Size = + wlan_cpu_to_le16(sizeof + (struct HostCmd_DS_BBP_REG_ACCESS) + + S_DS_GEN); + bbpreg = + (struct HostCmd_DS_BBP_REG_ACCESS *)&CmdPtr->params. + bbpreg; + + bbpreg->Action = wlan_cpu_to_le16(cmd_action); + bbpreg->Offset = wlan_cpu_to_le16((u16) offval->offset); + bbpreg->Value = (u8) offval->value; + + break; + } + + case HostCmd_CMD_RF_REG_ACCESS: + { + struct HostCmd_DS_RF_REG_ACCESS *rfreg; + + CmdPtr->Size = + wlan_cpu_to_le16(sizeof + (struct HostCmd_DS_RF_REG_ACCESS) + + S_DS_GEN); + rfreg = + (struct HostCmd_DS_RF_REG_ACCESS *)&CmdPtr->params. + rfreg; + + rfreg->Action = wlan_cpu_to_le16(cmd_action); + rfreg->Offset = wlan_cpu_to_le16((u16) offval->offset); + rfreg->Value = (u8) offval->value; + + break; + } + + default: + break; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of mac_address. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_mac_address(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action) +{ + wlan_adapter *Adapter = priv->adapter; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_MAC_ADDRESS) + + S_DS_GEN); + cmd->Result = 0; + + cmd->params.macadd.Action = wlan_cpu_to_le16(cmd_action); + + if (cmd_action == HostCmd_ACT_SET) { + memcpy(cmd->params.macadd.MacAdd, + Adapter->CurrentAddr, ETH_ALEN); + HEXDUMP("SET_CMD: MAC ADDRESS-", Adapter->CurrentAddr, 6); + } + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of eeprom_access. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: GET or SET + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + int cmd_action, void *pdata_buf) +{ + wlan_ioctl_regrdwr *ea = pdata_buf; + + ENTER(); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_EEPROM_ACCESS); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_EEPROM_ACCESS) + + S_DS_GEN); + cmd->Result = 0; + + cmd->params.rdeeprom.Action = wlan_cpu_to_le16(ea->Action); + cmd->params.rdeeprom.Offset = wlan_cpu_to_le16(ea->Offset); + cmd->params.rdeeprom.ByteCount = wlan_cpu_to_le16(ea->NOB); + cmd->params.rdeeprom.Value = 0; + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of DFT access. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param cmd_action the action: ADD, DEL, RESET, or LIST + * @param pdata_buf A pointer to data buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_dft_access(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + u16 cmd_action, void *pdata_buf) +{ + struct HostCmd_DS_DFT_ACCESS *dft_access = &cmd->params.dft; + PRINTM(INFO, "DFT CMD(%d)\n", cmd_action); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_DFT_ACCESS); + cmd->Size = wlan_cpu_to_le16(sizeof(struct HostCmd_DS_DFT_ACCESS) + + S_DS_GEN); + cmd->Result = 0; + dft_access->action = wlan_cpu_to_le16(cmd_action); + + switch (cmd_action) { + case HostCmd_ACT_DFT_ACCESS_ADD: + memcpy(dft_access->addr1, pdata_buf, 2 * ETH_ALEN); + HEXDUMP("DFT_ADD: index mac address-", dft_access->addr1, 6); + HEXDUMP("DFT_ADD: yield mac address-", dft_access->addr2, 6); + break; + case HostCmd_ACT_DFT_ACCESS_DEL: + memcpy(dft_access->addr1, pdata_buf, 1 * ETH_ALEN); + HEXDUMP("DFT_DEL: index mac address-", dft_access->addr1, 6); + break; + case HostCmd_ACT_DFT_ACCESS_LIST: + dft_access->id = wlan_cpu_to_le32(*(u32 *) pdata_buf); + break; + case HostCmd_ACT_DFT_ACCESS_RESET: + break; + case HostCmd_ACT_BT_ACCESS_ADD: + memcpy(dft_access->addr1, pdata_buf, 2 * ETH_ALEN); + HEXDUMP("BT_ADD: blinded mac address-", dft_access->addr1, 6); + break; + case HostCmd_ACT_BT_ACCESS_DEL: + memcpy(dft_access->addr1, pdata_buf, 1 * ETH_ALEN); + HEXDUMP("BT_DEL: blinded mac address-", dft_access->addr1, 6); + break; + case HostCmd_ACT_BT_ACCESS_LIST: + dft_access->id = wlan_cpu_to_le32(*(u32 *) pdata_buf); + break; + case HostCmd_ACT_BT_ACCESS_RESET: + break; + default: + break; + } + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function queues the command to cmd list. + * + * @param Adapter A pointer to wlan_adapter structure + * @param CmdNode A pointer to CmdCtrlNode structure + * @param addtail specify if the cmd needs to be queued in the header or tail + * @return n/a + */ +void libertas_queue_cmd(wlan_adapter * Adapter, struct CmdCtrlNode *CmdNode, u8 addtail) +{ + ulong flags; + struct HostCmd_DS_COMMAND *CmdPtr; + + ENTER(); + + if (!CmdNode) { + PRINTM(INFO, "QUEUE_CMD: CmdNode is NULL\n"); + goto done; + } + + CmdPtr = (struct HostCmd_DS_COMMAND *)CmdNode->BufVirtualAddr; + if (!CmdPtr) { + PRINTM(INFO, "QUEUE_CMD: CmdPtr is NULL\n"); + goto done; + } + + /* Exit_PS command needs to be queued in the header always. */ + if (CmdPtr->Command == HostCmd_CMD_802_11_PS_MODE) { + struct HostCmd_DS_802_11_PS_MODE *psm = &CmdPtr->params.psmode; + if (psm->Action == HostCmd_SubCmd_Exit_PS) { + if (Adapter->PSState != PS_STATE_FULL_POWER) + addtail = 0; + } + } + + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + + if (addtail) + list_add_tail((struct list_head *)CmdNode, + &Adapter->CmdPendingQ); + else + list_add((struct list_head *)CmdNode, &Adapter->CmdPendingQ); + + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + PRINTM(INFO, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in CmdPendingQ\n", + (u32) CmdNode, + ((struct HostCmd_DS_GEN *)CmdNode->BufVirtualAddr)->Command); + + done: + LEAVE(); + return; +} + +/* + * TODO: Fix the issue when DownloadCommandToStation is being called the + * second time when the command timesout. All the CmdPtr->xxx are in little + * endian and therefore all the comparissions will fail. + * For now - we are not performing the endian conversion the second time - but + * for PS and DEEP_SLEEP we need to worry + */ + +/** + * @brief This function downloads the command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param CmdNode A pointer to CmdCtrlNode structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int DownloadCommandToStation(wlan_private * priv, + struct CmdCtrlNode *CmdNode) +{ + ulong flags; + struct HostCmd_DS_COMMAND *CmdPtr; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + u16 CmdSize; + u16 Command; + + ENTER(); + + if (!Adapter || !CmdNode) { + PRINTM(INFO, "DNLD_CMD: Adapter = %#x, CmdNode = %#x\n", + (int)Adapter, (int)CmdNode); + if (CmdNode) + libertas_cleanup_and_insert_cmd(priv, CmdNode); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + CmdPtr = (struct HostCmd_DS_COMMAND *)CmdNode->BufVirtualAddr; + + if (!CmdPtr || !CmdPtr->Size) { + PRINTM(INFO, "DNLD_CMD: CmdPtr is Null or Cmd Size is Zero, " + "Not sending\n"); + libertas_cleanup_and_insert_cmd(priv, CmdNode); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = CmdNode; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + Adapter->CurCmdRetCode = 0; + PRINTM(INFO, "DNLD_CMD:: Before download, Size of Cmd = %d\n", + CmdPtr->Size); + + CmdSize = CmdPtr->Size; + + Command = wlan_cpu_to_le16(CmdPtr->Command); + + CmdNode->CmdWaitQWoken = 0; + CmdSize = wlan_cpu_to_le16(CmdSize); + + ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) CmdPtr, CmdSize); + + if (ret != 0) { + PRINTM(INFO, "DNLD_CMD: Host to Card Failed\n"); + libertas_cleanup_and_insert_cmd(priv, Adapter->CurCmd); + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = NULL; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + PRINTM(INFO, "DNLD_CMD: Sent command 0x%x @ %lu\n", Command, jiffies); + HEXDUMP("DNLD_CMD: Command", CmdNode->BufVirtualAddr, CmdSize); + + /* Setup the timer after transmit command */ + if (Command == HostCmd_CMD_802_11_SCAN + || Command == HostCmd_CMD_802_11_AUTHENTICATE + || Command == HostCmd_CMD_802_11_ASSOCIATE) + mod_timer(&Adapter->command_timer, jiffies + (10*HZ)); + else + mod_timer(&Adapter->command_timer, jiffies + (5*HZ)); + + ret = WLAN_STATUS_SUCCESS; + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function prepares command of mac_control. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_cmd_mac_control(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd) +{ + struct HostCmd_DS_MAC_CONTROL *mac = &cmd->params.macctrl; + + ENTER(); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_MAC_CONTROL); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_MAC_CONTROL) + S_DS_GEN); + mac->Action = wlan_cpu_to_le16(priv->adapter->CurrentPacketFilter); + + PRINTM(INFO, "wlan_cmd_mac_control(): Action=0x%X Size=%d\n", + mac->Action, cmd->Size); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function inserts command node to CmdFreeQ + * after cleans it. + * + * @param priv A pointer to wlan_private structure + * @param pTempCmd A pointer to CmdCtrlNode structure + * @return n/a + */ +void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct CmdCtrlNode *pTempCmd) +{ + ulong flags; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (!pTempCmd) + goto done; + + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + CleanUpCmdCtrlNode(pTempCmd); + list_add_tail((struct list_head *)pTempCmd, &Adapter->CmdFreeQ); + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + done: + LEAVE(); +} + +/** + * @brief This function sets radio control. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_set_radio_control(wlan_private * priv) +{ + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RADIO_CONTROL, + HostCmd_ACT_GEN_SET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + PRINTM(INFO, "RADIO_SET: on or off: 0x%X, Preamble = 0x%X\n", + priv->adapter->RadioOn, priv->adapter->Preamble); + + LEAVE(); + return ret; +} + +/** + * @brief This function sets packet filter. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_set_mac_packet_filter(wlan_private * priv) +{ + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + PRINTM(INFO, "libertas_set_mac_packet_filter Value = %x\n", + priv->adapter->CurrentPacketFilter); + + /* Send MAC control command to station */ + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_MAC_CONTROL, 0, 0, 0, NULL); + + LEAVE(); + return ret; +} + +/** + * @brief This function prepare the command before send to firmware. + * + * @param priv A pointer to wlan_private structure + * @param cmd_no command number + * @param cmd_action command action: GET or SET + * @param wait_option wait option: wait response or not + * @param cmd_oid cmd oid: treated as sub command + * @param pdata_buf A pointer to informaion buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_prepare_and_send_command(wlan_private * priv, + u16 cmd_no, + u16 cmd_action, + u16 wait_option, u32 cmd_oid, void *pdata_buf) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + struct CmdCtrlNode *CmdNode; + struct HostCmd_DS_COMMAND *CmdPtr; + + ENTER(); + + if (!Adapter) { + PRINTM(INFO, "PREP_CMD: Adapter is Null\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + if (Adapter->SurpriseRemoved) { + PRINTM(INFO, "PREP_CMD: Card is Removed\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + CmdNode = libertas_get_free_cmd_ctrl_node(priv); + + if (CmdNode == NULL) { + PRINTM(MSG, "PREP_CMD: No free CmdNode\n"); + + /* Wake up main thread to execute next command */ + wake_up_interruptible(&priv->MainThread.waitQ); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + libertas_set_cmd_ctrl_node(priv, CmdNode, cmd_oid, wait_option, pdata_buf); + + CmdPtr = (struct HostCmd_DS_COMMAND *)CmdNode->BufVirtualAddr; + + PRINTM(INFO, "PREP_CMD: Val of Cmd ptr =0x%x, command=0x%X\n", + (u32) CmdPtr, cmd_no); + + if (!CmdPtr) { + PRINTM(MSG, "PREP_CMD: BufVirtualAddr of CmdNode is NULL\n"); + libertas_cleanup_and_insert_cmd(priv, CmdNode); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + /* Set sequence number, command and INT option */ + Adapter->SeqNum++; + CmdPtr->SeqNum = wlan_cpu_to_le16(Adapter->SeqNum); + + CmdPtr->Command = cmd_no; + CmdPtr->Result = 0; + + switch (cmd_no) { + case HostCmd_CMD_GET_HW_SPEC: + ret = wlan_cmd_hw_spec(priv, CmdPtr); + break; + case HostCmd_CMD_802_11_PS_MODE: + ret = wlan_cmd_802_11_ps_mode(priv, CmdPtr, cmd_action); + break; + + case HostCmd_CMD_802_11_SCAN: + ret = libertas_cmd_80211_scan(priv, CmdPtr, pdata_buf); + break; + + case HostCmd_CMD_MAC_CONTROL: + ret = wlan_cmd_mac_control(priv, CmdPtr); + break; + + case HostCmd_CMD_802_11_ASSOCIATE: + case HostCmd_CMD_802_11_REASSOCIATE: + ret = libertas_cmd_80211_associate(priv, CmdPtr, pdata_buf); + break; + + case HostCmd_CMD_802_11_DEAUTHENTICATE: + ret = libertas_cmd_80211_deauthenticate(priv, CmdPtr); + break; + + case HostCmd_CMD_802_11_SET_WEP: + ret = wlan_cmd_802_11_set_wep(priv, CmdPtr, cmd_oid); + break; + + case HostCmd_CMD_802_11_AD_HOC_START: + ret = libertas_cmd_80211_ad_hoc_start(priv, CmdPtr, pdata_buf); + break; + case HostCmd_CMD_CODE_DNLD: + break; + + case HostCmd_CMD_802_11_RESET: + ret = wlan_cmd_802_11_reset(priv, CmdPtr, cmd_action); + break; + + case HostCmd_CMD_802_11_GET_LOG: + ret = wlan_cmd_802_11_get_log(priv, CmdPtr); + break; + + case HostCmd_CMD_802_11_AUTHENTICATE: + ret = libertas_cmd_80211_authenticate(priv, CmdPtr, pdata_buf); + break; + + case HostCmd_CMD_802_11_GET_STAT: + ret = wlan_cmd_802_11_get_stat(priv, CmdPtr); + break; + + case HostCmd_CMD_802_11_SNMP_MIB: + ret = wlan_cmd_802_11_snmp_mib(priv, CmdPtr, + cmd_action, cmd_oid, pdata_buf); + break; + + case HostCmd_CMD_MAC_REG_ACCESS: + case HostCmd_CMD_BBP_REG_ACCESS: + case HostCmd_CMD_RF_REG_ACCESS: + ret = wlan_cmd_reg_access(priv, CmdPtr, cmd_action, pdata_buf); + break; + + case HostCmd_CMD_802_11_RF_CHANNEL: + ret = wlan_cmd_802_11_rf_channel(priv, CmdPtr, + cmd_action, pdata_buf); + break; + + case HostCmd_CMD_802_11_RF_TX_POWER: + ret = wlan_cmd_802_11_rf_tx_power(priv, CmdPtr, + cmd_action, pdata_buf); + break; + + case HostCmd_CMD_802_11_RADIO_CONTROL: + ret = wlan_cmd_802_11_radio_control(priv, CmdPtr, cmd_action); + break; + + case HostCmd_CMD_802_11_RF_ANTENNA: + ret = wlan_cmd_802_11_rf_antenna(priv, CmdPtr, + cmd_action, pdata_buf); + break; + + case HostCmd_CMD_802_11_DATA_RATE: + ret = wlan_cmd_802_11_data_rate(priv, CmdPtr, cmd_action); + break; + case HostCmd_CMD_802_11_RATE_ADAPT_RATESET: + ret = wlan_cmd_802_11_rate_adapt_rateset(priv, + CmdPtr, cmd_action); + break; + + case HostCmd_CMD_MAC_MULTICAST_ADR: + ret = wlan_cmd_mac_multicast_adr(priv, CmdPtr, cmd_action); + break; + + case HostCmd_CMD_802_11_AD_HOC_JOIN: + ret = libertas_cmd_80211_ad_hoc_join(priv, CmdPtr, pdata_buf); + break; + + case HostCmd_CMD_802_11_RSSI: + ret = wlan_cmd_802_11_rssi(priv, CmdPtr); + break; + + case HostCmd_CMD_802_11_AD_HOC_STOP: + ret = libertas_cmd_80211_ad_hoc_stop(priv, CmdPtr); + break; + + case HostCmd_CMD_802_11_ENABLE_RSN: + ret = wlan_cmd_802_11_enable_rsn(priv, CmdPtr, cmd_action); + break; + + case HostCmd_CMD_802_11_KEY_MATERIAL: + ret = wlan_cmd_802_11_key_material(priv, CmdPtr, + cmd_action, cmd_oid, + pdata_buf); + break; + + case HostCmd_CMD_802_11_PAIRWISE_TSC: + break; + case HostCmd_CMD_802_11_GROUP_TSC: + break; + + case HostCmd_CMD_802_11_MAC_ADDRESS: + ret = wlan_cmd_802_11_mac_address(priv, CmdPtr, cmd_action); + break; + + case HostCmd_CMD_802_11_EEPROM_ACCESS: + ret = wlan_cmd_802_11_eeprom_access(priv, CmdPtr, + cmd_action, pdata_buf); + break; + + case HostCmd_CMD_802_11_SET_AFC: + case HostCmd_CMD_802_11_GET_AFC: + + CmdPtr->Command = wlan_cpu_to_le16(cmd_no); + CmdPtr->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_AFC) + + S_DS_GEN); + + memmove(&CmdPtr->params.afc, + pdata_buf, sizeof(struct HostCmd_DS_802_11_AFC)); + + ret = WLAN_STATUS_SUCCESS; + goto done; + + case HostCmd_CMD_802_11D_DOMAIN_INFO: + ret = libertas_cmd_802_11d_domain_info(priv, CmdPtr, + cmd_no, cmd_action); + break; + + case HostCmd_CMD_802_11_SLEEP_PARAMS: + ret = wlan_cmd_802_11_sleep_params(priv, CmdPtr, cmd_action); + break; + case HostCmd_CMD_802_11_INACTIVITY_TIMEOUT: + ret = wlan_cmd_802_11_inactivity_timeout(priv, CmdPtr, + cmd_action, pdata_buf); + libertas_set_cmd_ctrl_node(priv, CmdNode, 0, 0, pdata_buf); + break; + + case HostCmd_CMD_802_11_TPC_CFG: + CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_TPC_CFG); + CmdPtr->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_TPC_CFG) + + S_DS_GEN); + + memmove(&CmdPtr->params.tpccfg, + pdata_buf, sizeof(struct HostCmd_DS_802_11_TPC_CFG)); + + ret = WLAN_STATUS_SUCCESS; + break; + case HostCmd_CMD_802_11_LED_GPIO_CTRL: + { + struct MrvlIEtypes_LedGpio *gpio = + (struct MrvlIEtypes_LedGpio*) + CmdPtr->params.ledgpio.data; + + memmove(&CmdPtr->params.ledgpio, + pdata_buf, + sizeof(struct HostCmd_DS_802_11_LED_CTRL)); + + CmdPtr->Command = + wlan_cpu_to_le16(HostCmd_CMD_802_11_LED_GPIO_CTRL); + +#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 + CmdPtr->Size = + wlan_cpu_to_le16(gpio->Header.Len + S_DS_GEN + + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); + gpio->Header.Len = wlan_cpu_to_le16(gpio->Header.Len); + + ret = WLAN_STATUS_SUCCESS; + break; + } + case HostCmd_CMD_802_11_PWR_CFG: + CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_PWR_CFG); + CmdPtr->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_PWR_CFG) + + S_DS_GEN); + memmove(&CmdPtr->params.pwrcfg, pdata_buf, + sizeof(struct HostCmd_DS_802_11_PWR_CFG)); + + ret = WLAN_STATUS_SUCCESS; + break; + case HostCmd_CMD_802_11_SLEEP_PERIOD: + ret = wlan_cmd_802_11_sleep_period(priv, CmdPtr, + cmd_action, pdata_buf); + break; + + case HostCmd_CMD_DFT_ACCESS: + ret = wlan_cmd_dft_access(priv, CmdPtr, cmd_action, pdata_buf); + break; + + case HostCmd_CMD_GET_TSF: + CmdPtr->Command = wlan_cpu_to_le16(HostCmd_CMD_GET_TSF); + CmdPtr->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_GET_TSF) + + S_DS_GEN); + ret = WLAN_STATUS_SUCCESS; + break; + case HostCmd_CMD_802_11_TX_RATE_QUERY: + CmdPtr->Command = + wlan_cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); + CmdPtr->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_TX_RATE_QUERY) + + S_DS_GEN); + Adapter->TxRate = 0; + ret = WLAN_STATUS_SUCCESS; + break; + default: + PRINTM(INFO, "PREP_CMD: unknown command- %#x\n", cmd_no); + ret = WLAN_STATUS_FAILURE; + break; + } + + /* return error, since the command preparation failed */ + if (ret != WLAN_STATUS_SUCCESS) { + PRINTM(INFO, "PREP_CMD: Command preparation failed\n"); + libertas_cleanup_and_insert_cmd(priv, CmdNode); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + CmdNode->CmdWaitQWoken = 0; + + libertas_queue_cmd(Adapter, CmdNode, 1); + wake_up_interruptible(&priv->MainThread.waitQ); + + libertas_sbi_reenable_host_interrupt(priv, 0x00); + + if (wait_option & HostCmd_OPTION_WAITFORRSP) { + PRINTM(INFO, "PREP_CMD: Wait for CMD response\n"); + wait_event_interruptible(CmdNode->cmdwait_q, + CmdNode->CmdWaitQWoken); + } + + if (Adapter->CurCmdRetCode) { + PRINTM(INFO, "PREP_CMD: Command failed with return code=%d\n", + Adapter->CurCmdRetCode); + Adapter->CurCmdRetCode = 0; + ret = WLAN_STATUS_FAILURE; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function allocates the command buffer and link + * it to command free queue. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_allocate_cmd_buffer(wlan_private * priv) +{ + int ret = WLAN_STATUS_SUCCESS; + u32 ulBufSize; + u32 i; + struct CmdCtrlNode *TempCmdArray; + u8 *pTempVirtualAddr; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* Allocate and initialize CmdCtrlNode */ + ulBufSize = sizeof(struct CmdCtrlNode) * MRVDRV_NUM_OF_CMD_BUFFER; + + if (!(TempCmdArray = kmalloc(ulBufSize, GFP_KERNEL))) { + PRINTM(INFO, + "ALLOC_CMD_BUF: Failed to allocate TempCmdArray\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + Adapter->CmdArray = TempCmdArray; + memset(Adapter->CmdArray, 0, ulBufSize); + + /* Allocate and initialize command buffers */ + ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER; + for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { + if (!(pTempVirtualAddr = kmalloc(ulBufSize, GFP_KERNEL))) { + PRINTM(INFO, + "ALLOC_CMD_BUF: pTempVirtualAddr: out of memory\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + memset(pTempVirtualAddr, 0, ulBufSize); + + /* Update command buffer virtual */ + TempCmdArray[i].BufVirtualAddr = pTempVirtualAddr; + } + + for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { + init_waitqueue_head(&TempCmdArray[i].cmdwait_q); + libertas_cleanup_and_insert_cmd(priv, &TempCmdArray[i]); + } + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + return ret; +} + +/** + * @brief This function frees the command buffer. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_free_cmd_buffer(wlan_private * priv) +{ + u32 ulBufSize; + unsigned int i; + struct CmdCtrlNode *TempCmdArray; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* need to check if cmd array is allocated or not */ + if (Adapter->CmdArray == NULL) { + PRINTM(INFO, "FREE_CMD_BUF: CmdArray is Null\n"); + goto done; + } + + TempCmdArray = Adapter->CmdArray; + + /* Release shared memory buffers */ + ulBufSize = MRVDRV_SIZE_OF_CMD_BUFFER; + for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { + if (TempCmdArray[i].BufVirtualAddr) { + PRINTM(INFO, "Free all the array\n"); + kfree(TempCmdArray[i].BufVirtualAddr); + TempCmdArray[i].BufVirtualAddr = NULL; + } + } + + /* Release CmdCtrlNode */ + if (Adapter->CmdArray) { + PRINTM(INFO, "Free CmdArray\n"); + kfree(Adapter->CmdArray); + Adapter->CmdArray = NULL; + } + + done: + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function gets a free command node if available in + * command free queue. + * + * @param priv A pointer to wlan_private structure + * @return CmdCtrlNode A pointer to CmdCtrlNode structure or NULL + */ +struct CmdCtrlNode *libertas_get_free_cmd_ctrl_node(wlan_private * priv) +{ + struct CmdCtrlNode *TempNode; + wlan_adapter *Adapter = priv->adapter; + ulong flags; + + ENTER(); + + if (!Adapter) + return NULL; + + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + + if (!list_empty(&Adapter->CmdFreeQ)) { + TempNode = (struct CmdCtrlNode *)Adapter->CmdFreeQ.next; + list_del((struct list_head *)TempNode); + } else { + PRINTM(INFO, "GET_CMD_NODE: CmdCtrlNode is not available\n"); + TempNode = NULL; + } + + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + if (TempNode) { + PRINTM(INFO, "GET_CMD_NODE: CmdCtrlNode available\n"); + PRINTM(INFO, "GET_CMD_NODE: CmdCtrlNode Address = %p\n", + TempNode); + CleanUpCmdCtrlNode(TempNode); + } + + LEAVE(); + return TempNode; +} + +/** + * @brief This function cleans command node. + * + * @param pTempNode A pointer to CmdCtrlNode structure + * @return n/a + */ +static void CleanUpCmdCtrlNode(struct CmdCtrlNode *pTempNode) +{ + ENTER(); + + if (!pTempNode) + return; + pTempNode->CmdWaitQWoken = 1; + wake_up_interruptible(&pTempNode->cmdwait_q); + pTempNode->Status = 0; + pTempNode->cmd_oid = (u32) 0; + pTempNode->wait_option = 0; + pTempNode->pdata_buf = NULL; + + if (pTempNode->BufVirtualAddr != NULL) + memset(pTempNode->BufVirtualAddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + + LEAVE(); + return; +} + +/** + * @brief This function initializes the command node. + * + * @param priv A pointer to wlan_private structure + * @param pTempNode A pointer to CmdCtrlNode structure + * @param cmd_oid cmd oid: treated as sub command + * @param wait_option wait option: wait response or not + * @param pdata_buf A pointer to informaion buffer + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +void libertas_set_cmd_ctrl_node(wlan_private * priv, + struct CmdCtrlNode *pTempNode, + u32 cmd_oid, u16 wait_option, void *pdata_buf) +{ + ENTER(); + + if (!pTempNode) + return; + + pTempNode->cmd_oid = cmd_oid; + pTempNode->wait_option = wait_option; + pTempNode->pdata_buf = pdata_buf; + + LEAVE(); +} + +/** + * @brief This function executes next command in command + * pending queue. It will put fimware back to PS mode + * if applicable. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_execute_next_command(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + struct CmdCtrlNode *CmdNode = NULL; + struct HostCmd_DS_COMMAND *CmdPtr; + ulong flags; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (!Adapter) { + PRINTM(MSG, "EXEC_NEXT_CMD: Adapter is NULL\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + + if (Adapter->CurCmd) { + PRINTM(MSG, "EXEC_NEXT_CMD: there is command in processing!\n"); + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + if (!list_empty(&Adapter->CmdPendingQ)) { + CmdNode = (struct CmdCtrlNode *) + Adapter->CmdPendingQ.next; + } + + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + if (CmdNode) { + PRINTM(INFO, + "EXEC_NEXT_CMD: Got next command from CmdPendingQ\n"); + CmdPtr = (struct HostCmd_DS_COMMAND *)CmdNode->BufVirtualAddr; + + if (Is_Command_Allowed_In_PS(CmdPtr->Command)) { + if ((Adapter->PSState == PS_STATE_SLEEP) + || (Adapter->PSState == PS_STATE_PRE_SLEEP) + ) { + PRINTM(INFO, + "EXEC_NEXT_CMD: Cannot send cmd 0x%x in PSState %d\n", + CmdPtr->Command, Adapter->PSState); + ret = WLAN_STATUS_FAILURE; + goto done; + } + PRINTM(INFO, "EXEC_NEXT_CMD: OK to send command " + "0x%x in PSState %d\n", + CmdPtr->Command, Adapter->PSState); + } else if (Adapter->PSState != PS_STATE_FULL_POWER) { + /* + * 1. Non-PS command: + * Queue it. set NeedToWakeup to TRUE if current state + * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS. + * 2. PS command but not Exit_PS: + * Ignore it. + * 3. PS command Exit_PS: + * Set NeedToWakeup to TRUE if current state is SLEEP, + * otherwise send this command down to firmware + * immediately. + */ + if (CmdPtr->Command != + wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE)) { + /* Prepare to send Exit PS, + * this non PS command will be sent later */ + if ((Adapter->PSState == PS_STATE_SLEEP) + || (Adapter->PSState == PS_STATE_PRE_SLEEP) + ) { + /* w/ new scheme, it will not reach here. + since it is blocked in main_thread. */ + Adapter->NeedToWakeup = 1; + } else + libertas_ps_wakeup(priv, 0); + + ret = WLAN_STATUS_SUCCESS; + goto done; + } else { + /* + * PS command. Ignore it if it is not Exit_PS. + * otherwise send it down immediately. + */ + struct HostCmd_DS_802_11_PS_MODE *psm = + &CmdPtr->params.psmode; + + PRINTM(INFO, + "EXEC_NEXT_CMD: PS cmd- Action=0x%x\n", + psm->Action); + if (psm->Action != + wlan_cpu_to_le16(HostCmd_SubCmd_Exit_PS)) { + PRINTM(INFO, + "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); + list_del((struct list_head *)CmdNode); + libertas_cleanup_and_insert_cmd(priv, CmdNode); + + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + if ((Adapter->PSState == PS_STATE_SLEEP) + || (Adapter->PSState == PS_STATE_PRE_SLEEP) + ) { + PRINTM(INFO, + "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n"); + list_del((struct list_head *)CmdNode); + libertas_cleanup_and_insert_cmd(priv, CmdNode); + Adapter->NeedToWakeup = 1; + + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + PRINTM(INFO, + "EXEC_NEXT_CMD: Sending Exit_PS down...\n"); + } + } + list_del((struct list_head *)CmdNode); + PRINTM(INFO, "EXEC_NEXT_CMD: Sending 0x%04X Command\n", + CmdPtr->Command); + DownloadCommandToStation(priv, CmdNode); + } else { + /* + * check if in power save mode, if yes, put the device back + * to PS mode + */ + if ((Adapter->PSMode != Wlan802_11PowerModeCAM) && + (Adapter->PSState == PS_STATE_FULL_POWER) && + (Adapter->MediaConnectStatus == WlanMediaStateConnected)) { + if (Adapter->SecInfo.WPAEnabled + || Adapter->SecInfo.WPA2Enabled) { + if (Adapter->IsGTK_SET) { + PRINTM(INFO, + "EXEC_NEXT_CMD: WPA enabled and GTK_SET" + " go back to PS_SLEEP"); + libertas_ps_sleep(priv, 0); + } + } else { + PRINTM(INFO, + "EXEC_NEXT_CMD: Command PendQ is empty," + " go back to PS_SLEEP"); + libertas_ps_sleep(priv, 0); + } + } + } + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + return ret; +} + +/** + * @brief This function sends customized event to application. + * + * @param priv A pointer to wlan_private structure + * @para str A pointer to event string + * @return n/a + */ +void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) +{ + union iwreq_data iwrq; + u8 buf[50]; + + ENTER(); + + memset(&iwrq, 0, sizeof(union iwreq_data)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, sizeof(buf) - 1, "%s", str); + + iwrq.data.pointer = buf; + iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; + + /* Send Event to upper layer */ + PRINTM(INFO, "Event Indication string = %s\n", + (char *)iwrq.data.pointer); + PRINTM(INFO, "Event Indication String Length = %d\n", iwrq.data.length); + + PRINTM(INFO, "Sending wireless event IWEVCUSTOM for %s\n", str); + wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf); + + LEAVE(); + return; +} + +/** + * @brief This function sends sleep confirm command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param cmdptr A pointer to the command + * @param size the size of command + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int SendConfirmSleep(wlan_private * priv, u8 * CmdPtr, u16 size) +{ + unsigned long flags; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + PRINTM(INFO, "SEND_SLEEPC_CMD: Before download, Size of cmd = %d\n", + size); + + HEXDUMP("SEND_SLEEPC_CMD: Sleep confirm Command", CmdPtr, size); + + ret = libertas_sbi_host_to_card(priv, MVMS_CMD, CmdPtr, size); + priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; + if (Adapter->IntCounter || Adapter->CurrentTxSkb) + PRINTM(INFO, "SEND_SLEEPC_CMD: IntCounter=%d CurrentTxSkb=%p\n", + Adapter->IntCounter, Adapter->CurrentTxSkb); + + if (ret) { + PRINTM(MSG, + "SEND_SLEEPC_CMD: Host to Card Failed for Confirm Sleep\n"); + } else { + spin_lock_irqsave(&libertas_driver_lock, flags); + if (!Adapter->IntCounter) { + Adapter->PSState = PS_STATE_SLEEP; + } else { + PRINTM(INFO, "SEND_SLEEPC_CMD: After sent,IntC=%d\n", + Adapter->IntCounter); + } + spin_unlock_irqrestore(&libertas_driver_lock, flags); + + PRINTM(INFO, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n"); + PRINTM(INFO, "+"); + } + + LEAVE(); + return ret; +} + +/** + * @brief This function sends Enter_PS command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param wait_option wait response or not + * @return n/a + */ +void libertas_ps_sleep(wlan_private * priv, int wait_option) +{ + + ENTER(); + + /* + * PS is currently supported only in Infrastructure Mode + * Remove this check if it is to be supported in IBSS mode also + */ + + libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_PS_MODE, + HostCmd_SubCmd_Enter_PS, wait_option, 0, NULL); + + LEAVE(); + return; +} + +/** + * @brief This function sends Eixt_PS command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param wait_option wait response or not + * @return n/a + */ +void libertas_ps_wakeup(wlan_private * priv, int wait_option) +{ + enum WLAN_802_11_POWER_MODE LocalPSMode; + + ENTER(); + + LocalPSMode = Wlan802_11PowerModeCAM; + + PRINTM(INFO, "Exit_PS: LocalPSMode = %d\n", LocalPSMode); + + libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_PS_MODE, + HostCmd_SubCmd_Exit_PS, + wait_option, 0, &LocalPSMode); + + LEAVE(); + return; +} + +/** + * @brief This function checks condition and prepares to + * send sleep confirm command to firmware if ok. + * + * @param priv A pointer to wlan_private structure + * @param PSMode Power Saving mode + * @return n/a + */ +void libertas_ps_confirm_sleep(wlan_private * priv, u16 PSMode) +{ + wlan_adapter *Adapter = priv->adapter; + u8 allowed = 1; + + ENTER(); + + if (priv->wlan_dev.dnld_sent) { + allowed = 0; + PRINTM(INFO, "D"); + } else if (Adapter->CurCmd) { + allowed = 0; + PRINTM(INFO, "C"); + } else if (Adapter->IntCounter > 0) { + allowed = 0; + PRINTM(INFO, "I%d", Adapter->IntCounter); + } + + if (allowed) { + PRINTM(INFO, "Sending libertas_ps_confirm_sleep\n"); + SendConfirmSleep(priv, (u8 *) & Adapter->libertas_ps_confirm_sleep, + sizeof(struct PS_CMD_ConfirmSleep)); + } else { + PRINTM(INFO, "Sleep Confirm has been delayed\n"); + } + + LEAVE(); +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_cmdresp.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_cmdresp.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_cmdresp.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_cmdresp.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,1243 @@ +/** @file wlan_cmdresp.c + * @brief This file contains the handling of command + * responses as well as events generated by firmware. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/10/05: Add Doxygen format comments + 11/11/05: Add support for WMM Status change event + 12/13/05: Add Proprietary periodic sleep support + 12/23/05: Fix bug in adhoc start where the current index was + not properly being assigned before it was used. + 01/05/06: Add kernel 2.6.x support + 01/11/06: Conditionalize new scan/join structures. + Update assoc response handling; entire IEEE response returned + 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support + 04/10/06: Add hostcmd generic API + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API + 05/08/06: Remove Adapter->PermanentAddr memcpy +********************************************************/ + +#include <linux/delay.h> +#include <linux/if_arp.h> +#include <linux/netdevice.h> + +#include <net/iw_handler.h> + +#include "host.h" +#include "sbi.h" +#include "wlan_decl.h" +#include "wlan_defs.h" +#include "wlan_dev.h" +#include "wlan_join.h" +#include "wlan_wext.h" + +/** + * @brief This function handles disconnect event. it + * reports disconnect to upper layer, clean tx/rx packets, + * reset link state etc. + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +void libertas_mac_event_disconnected(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + union iwreq_data wrqu; + + ENTER(); + + if (Adapter->MediaConnectStatus != WlanMediaStateConnected) + return; + + PRINTM(INFO, "Handles disconnect event.\n"); + + memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + + /* + * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. + * It causes problem in the Supplicant + */ + + msleep_interruptible(1000); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + /* Free Tx and Rx packets */ + kfree_skb(priv->adapter->CurrentTxSkb); + priv->adapter->CurrentTxSkb = NULL; + + /* report disconnect to upper layer */ + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + + /* reset SNR/NF/RSSI values */ + memset(Adapter->SNR, 0x00, sizeof(Adapter->SNR)); + memset(Adapter->NF, 0x00, sizeof(Adapter->NF)); + memset(Adapter->RSSI, 0x00, sizeof(Adapter->RSSI)); + memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR)); + memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF)); + Adapter->nextSNRNF = 0; + Adapter->numSNRNF = 0; + Adapter->RxPDRate = 0; + PRINTM(INFO, "Current SSID=%s, Ssid Length=%u\n", + Adapter->CurBssParams.ssid.Ssid, + Adapter->CurBssParams.ssid.SsidLength); + PRINTM(INFO, "Previous SSID=%s, Ssid Length=%u\n", + Adapter->PreviousSSID.Ssid, Adapter->PreviousSSID.SsidLength); + + /* reset internal flags */ + Adapter->AdHocCreated = 0; + + Adapter->SecInfo.WPAEnabled = 0; + Adapter->SecInfo.WPA2Enabled = 0; + Adapter->Wpa_ie_len = 0; + Adapter->SecInfo.Auth1XAlg = WLAN_1X_AUTH_ALG_NONE; + Adapter->SecInfo.EncryptionMode = CIPHER_NONE; + + Adapter->MediaConnectStatus = WlanMediaStateDisconnected; + Adapter->LinkSpeed = MRVDRV_LINK_SPEED_1mbps; + + /* + * memorize the previous SSID and BSSID + * it could be used for re-assoc + */ + memcpy(&Adapter->PreviousSSID, + &Adapter->CurBssParams.ssid, sizeof(struct WLAN_802_11_SSID)); + memcpy(Adapter->PreviousBSSID, + Adapter->CurBssParams.bssid, ETH_ALEN); + + /* need to erase the current SSID and BSSID info */ + Adapter->pAttemptedBSSDesc = 0; + memset(&Adapter->CurBssParams, 0, sizeof(Adapter->CurBssParams)); + + if (Adapter->PSState != PS_STATE_FULL_POWER) { + /* make firmware to exit PS mode */ + PRINTM(INFO, "Disconnected, so exit PS mode.\n"); + libertas_ps_wakeup(priv, 0); + } + + LEAVE(); +} + +/** + * @brief This function handles link lost, deauth and + * disassoc events. + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +static void HandleDisconnectEvent(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + libertas_mac_event_disconnected(priv); +#ifdef REASSOCIATION + if (Adapter->Reassoc_on) { + PRINTM(INFO, "RE-ASSOC: trigger the timer\n"); + mod_timer(&Adapter->reassoc_timer, 0); + } +#endif /* REASSOCIATION */ + } +} + +/** + * @brief This function handles MIC failure event. + * + * @param priv A pointer to wlan_private structure + * @para event the event id + * @return n/a + */ +static void HandleMICFailureEvent(wlan_private * priv, u32 event) +{ + u8 buf[50]; + + ENTER(); + + memset(buf, 0, sizeof(buf)); + + sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); + + if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { + strcat(buf, "unicast "); + } else { + strcat(buf, "multicast "); + } + + libertas_send_iwevcustom_event(priv, buf); + + LEAVE(); +} + +/** + * @brief This function handles the command response of reg_access + * + * @param priv A pointer to wlan_private structure + * @param type the type of reg access (MAC, BBP or RF) + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_reg_access(wlan_private * priv, + u16 type, struct HostCmd_DS_COMMAND *resp) +{ + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + switch (type) { + case HostCmd_RET_MAC_REG_ACCESS: + { + struct HostCmd_DS_MAC_REG_ACCESS *reg; + + reg = + (struct HostCmd_DS_MAC_REG_ACCESS *)&resp->params. + macreg; + + Adapter->OffsetValue.offset = reg->Offset; + Adapter->OffsetValue.value = reg->Value; + break; + } + + case HostCmd_RET_BBP_REG_ACCESS: + { + struct HostCmd_DS_BBP_REG_ACCESS *reg; + reg = + (struct HostCmd_DS_BBP_REG_ACCESS *)&resp->params. + bbpreg; + + Adapter->OffsetValue.offset = reg->Offset; + Adapter->OffsetValue.value = reg->Value; + break; + } + + case HostCmd_RET_RF_REG_ACCESS: + { + struct HostCmd_DS_RF_REG_ACCESS *reg; + reg = + (struct HostCmd_DS_RF_REG_ACCESS *)&resp->params. + rfreg; + + Adapter->OffsetValue.offset = reg->Offset; + Adapter->OffsetValue.value = reg->Value; + break; + } + + default: + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of get_hw_spec + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_get_hw_spec(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + u32 i; + struct HostCmd_DS_GET_HW_SPEC *hwspec = &resp->params.hwspec; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + Adapter->HardwareStatus = WlanHardwareStatusReady; + Adapter->fwCapInfo = wlan_le32_to_cpu(hwspec->fwCapInfo); + + Adapter->FWReleaseNumber = hwspec->FWReleaseNumber; + + PRINTM(INFO, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n", + Adapter->FWReleaseNumber); + PRINTM(INFO, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", + hwspec->PermanentAddr[0], hwspec->PermanentAddr[1], + hwspec->PermanentAddr[2], hwspec->PermanentAddr[3], + hwspec->PermanentAddr[4], hwspec->PermanentAddr[5]); + PRINTM(INFO, "GET_HW_SPEC: HWIfVersion=0x%X Version=0x%X\n", + hwspec->HWIfVersion, hwspec->Version); + + Adapter->RegionCode = wlan_le16_to_cpu(hwspec->RegionCode); + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + /* use the region code to search for the index */ + if (Adapter->RegionCode == libertas_region_code_to_index[i]) { + Adapter->RegionTableIndex = (u16) i; + break; + } + } + + /* if it's unidentified region code, use the default (USA) */ + if (i >= MRVDRV_MAX_REGION_CODE) { + Adapter->RegionCode = 0x10; + Adapter->RegionTableIndex = 0; + PRINTM(WARN, + "unidentified region code, use the default (USA)\n"); + } + + if (Adapter->CurrentAddr[0] == 0xff) { + memmove(Adapter->CurrentAddr, hwspec->PermanentAddr, + ETH_ALEN); + } + + memcpy(priv->wlan_dev.netdev->dev_addr, Adapter->CurrentAddr, ETH_ALEN); + + if (libertas_set_regiontable(priv, Adapter->RegionCode, 0)) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + if (libertas_set_universaltable(priv, 0)) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function handles the command response of sleep_params + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_sleep_params(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_SLEEP_PARAMS *sp = &resp->params.sleep_params; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + PRINTM(INFO, "error=%x offset=%x stabletime=%x calcontrol=%x\n" + " extsleepclk=%x\n", sp->Error, sp->Offset, + sp->StableTime, sp->CalControl, sp->ExternalSleepClk); + Adapter->sp.sp_error = wlan_le16_to_cpu(sp->Error); + Adapter->sp.sp_offset = wlan_le16_to_cpu(sp->Offset); + Adapter->sp.sp_stabletime = wlan_le16_to_cpu(sp->StableTime); + Adapter->sp.sp_calcontrol = wlan_le16_to_cpu(sp->CalControl); + Adapter->sp.sp_extsleepclk = wlan_le16_to_cpu(sp->ExternalSleepClk); + Adapter->sp.sp_reserved = wlan_le16_to_cpu(sp->Reserved); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of sleep_params + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_sleep_period(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_SLEEP_PERIOD *sp_period = + &resp->params.ps_sleeppd; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + Adapter->sleep_period.period = wlan_le16_to_cpu(sp_period->Period); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of mac_control + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_mac_control(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of set_wep + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_set_wep(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of reset + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_reset(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + ENTER(); + PRINTM(INFO, "HWAC - Reset command successful\n"); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of statistics + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_stat(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_GET_STAT *p11Stat = &resp->params.gstat; + wlan_adapter *Adapter = priv->adapter; + + /* TODO Convert it to Big endian befor copy */ + memcpy(&Adapter->wlan802_11Stat, + p11Stat, sizeof(struct HostCmd_DS_802_11_GET_STAT)); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of snmp_mib + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_snmp_mib(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_SNMP_MIB *smib = &resp->params.smib; + u16 OID = wlan_le16_to_cpu(smib->OID); + u16 QueryType = wlan_le16_to_cpu(smib->QueryType); + + ENTER(); + + PRINTM(INFO, "SNMP_RESP: value of the OID = %x, QueryType=%x\n", OID, + QueryType); + PRINTM(INFO, "SNMP_RESP: Buf size = %x\n", + wlan_le16_to_cpu(smib->BufSize)); + + if (QueryType == HostCmd_ACT_GEN_GET) { + switch (OID) { + case FragThresh_i: + priv->adapter->FragThsd = + wlan_le16_to_cpu(* + ((unsigned short *)(smib->Value))); + PRINTM(INFO, "SNMP_RESP: FragThsd =%u\n", + priv->adapter->FragThsd); + break; + case RtsThresh_i: + priv->adapter->RTSThsd = + wlan_le16_to_cpu(* + ((unsigned short *)(smib->Value))); + PRINTM(INFO, "SNMP_RESP: RTSThsd =%u\n", + priv->adapter->RTSThsd); + break; + case ShortRetryLim_i: + priv->adapter->TxRetryCount = + wlan_le16_to_cpu(* + ((unsigned short *)(smib->Value))); + PRINTM(INFO, "SNMP_RESP: TxRetryCount =%u\n", + priv->adapter->RTSThsd); + break; + default: + break; + } + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of radio_control + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_radio_control(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + ENTER(); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of key_material + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_key_material(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_KEY_MATERIAL *pKey = &resp->params.keymaterial; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (pKey->Action == HostCmd_ACT_SET) + Adapter->IsGTK_SET = 1; + + memcpy(Adapter->aeskey.KeyParamSet.Key, pKey->KeyParamSet.Key, + sizeof(pKey->KeyParamSet.Key)); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of mac_address + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_mac_address(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_MAC_ADDRESS *MacAdd = &resp->params.macadd; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + memcpy(Adapter->CurrentAddr, MacAdd->MacAdd, ETH_ALEN); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of rf_tx_power + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_RF_TX_POWER *rtp = &resp->params.txp; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + Adapter->TxPowerLevel = wlan_le16_to_cpu(rtp->CurrentLevel); + + PRINTM(INFO, "Current TxPower Level = %d\n", Adapter->TxPowerLevel); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of rf_antenna + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_rf_antenna(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_RF_ANTENNA *pAntenna = &resp->params.rant; + wlan_adapter *Adapter = priv->adapter; + u16 Action = wlan_le16_to_cpu(pAntenna->Action); + + if (Action == HostCmd_ACT_GET_RX) + Adapter->RxAntennaMode = + wlan_le16_to_cpu(pAntenna->AntennaMode); + + if (Action == HostCmd_ACT_GET_TX) + Adapter->TxAntennaMode = + wlan_le16_to_cpu(pAntenna->AntennaMode); + + PRINTM(INFO, "RF_ANT_RESP: Action = 0x%x, Mode = 0x%04x\n", + Action, wlan_le16_to_cpu(pAntenna->AntennaMode)); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of multicast_address + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_mac_multicast_adr(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of rate_adapt_rateset + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_RATE_ADAPT_RATESET *rates = + &resp->params.rateset; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (rates->Action == HostCmd_ACT_GET) { + Adapter->EnableHwAuto = rates->EnableHwAuto; + Adapter->RateBitmap = rates->Bitmap; + } + + LEAVE(); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of data_rate + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_data_rate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_DATA_RATE *pDataRate = &resp->params.drate; + wlan_adapter *Adapter = priv->adapter; + u8 Dot11DataRate; + + ENTER(); + + HEXDUMP("DATA_RATE_RESP: data_rate- ", + (u8 *) pDataRate, sizeof(struct HostCmd_DS_802_11_DATA_RATE)); + + Dot11DataRate = pDataRate->DataRate[0]; + if (pDataRate->Action == HostCmd_ACT_GET_TX_RATE) { + memcpy(Adapter->libertas_supported_rates, pDataRate->DataRate, + sizeof(Adapter->libertas_supported_rates)); + } + Adapter->DataRate = libertas_index_to_data_rate(Dot11DataRate); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of rf_channel + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_rf_channel(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_RF_CHANNEL *rfchannel = + &resp->params.rfchannel; + wlan_adapter *Adapter = priv->adapter; + u16 Action = wlan_le16_to_cpu(rfchannel->Action); + u16 newChannel = wlan_le16_to_cpu(rfchannel->CurrentChannel); + + ENTER(); + + if (Action == HostCmd_OPT_802_11_RF_CHANNEL_GET + && Adapter->CurBssParams.channel != newChannel) { + PRINTM(INFO, "Channel Switch: %d to %d\n", + Adapter->CurBssParams.channel, newChannel); + + /* Update the channel again */ + Adapter->CurBssParams.channel = newChannel; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of rssi + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_rssi(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_RSSI_RSP *rssirsp = &resp->params.rssirsp; + wlan_adapter *Adapter = priv->adapter; + + /* store the non average value */ + Adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = wlan_le16_to_cpu(rssirsp->SNR); + Adapter->NF[TYPE_BEACON][TYPE_NOAVG] = + wlan_le16_to_cpu(rssirsp->NoiseFloor); + + Adapter->SNR[TYPE_BEACON][TYPE_AVG] = wlan_le16_to_cpu(rssirsp->AvgSNR); + Adapter->NF[TYPE_BEACON][TYPE_AVG] = + wlan_le16_to_cpu(rssirsp->AvgNoiseFloor); + + Adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = + CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + Adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + + Adapter->RSSI[TYPE_BEACON][TYPE_AVG] = + CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, + Adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); + + PRINTM(INFO, "Beacon RSSI value = 0x%x\n", + Adapter->RSSI[TYPE_BEACON][TYPE_AVG]); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of eeprom_access + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_802_11_eeprom_access(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + wlan_adapter *Adapter = priv->adapter; + wlan_ioctl_regrdwr *pBuf = (wlan_ioctl_regrdwr *) Adapter->pRdeeprom; + PRINTM(INFO, "eeprom read len=%x\n", + wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)); + if (pBuf->NOB < wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)) { + pBuf->NOB = 0; + PRINTM(INFO, "eeprom read return length is too big\n"); + return WLAN_STATUS_FAILURE; + } + pBuf->NOB = wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount); + if (pBuf->NOB > 0) { + + memcpy(&pBuf->Value, (u8 *) & resp->params.rdeeprom.Value, + wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)); + HEXDUMP("Adapter", (char *)&pBuf->Value, + wlan_le16_to_cpu(resp->params.rdeeprom.ByteCount)); + } + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of get_log + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_ret_get_log(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + struct HostCmd_DS_802_11_GET_LOG *LogMessage = + (struct HostCmd_DS_802_11_GET_LOG *)&resp->params.glog; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* TODO Convert it to Big Endian before copy */ + memcpy(&Adapter->LogMsg, LogMessage, + sizeof(struct HostCmd_DS_802_11_GET_LOG)); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_process_rx_command(wlan_private * priv) +{ + u16 RespCmd; + struct HostCmd_DS_COMMAND *resp; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + ulong flags; + u16 Result; + + ENTER(); + + PRINTM(INFO, "CMD_RESP: @ %lu\n", jiffies); + + /* Now we got response from FW, cancel the command timer */ + del_timer(&Adapter->command_timer); + + if (!Adapter->CurCmd) { + PRINTM(INFO, "CMD_RESP: NULL CurCmd=%p\n", Adapter->CurCmd); + ret = WLAN_STATUS_FAILURE; + goto done; + } + resp = (struct HostCmd_DS_COMMAND *)(Adapter->CurCmd->BufVirtualAddr); + + HEXDUMP("CMD_RESP:", Adapter->CurCmd->BufVirtualAddr, + priv->wlan_dev.upld_len); + + RespCmd = wlan_le16_to_cpu(resp->Command); + + Result = wlan_le16_to_cpu(resp->Result); + + PRINTM(INFO, "CMD_RESP: %x Result: %d Length: %d\n", RespCmd, + Result, priv->wlan_dev.upld_len); + + if (!(RespCmd & 0x8000)) { + PRINTM(INFO, "Invalid response to command!"); + Adapter->CurCmdRetCode = WLAN_STATUS_FAILURE; + libertas_cleanup_and_insert_cmd(priv, Adapter->CurCmd); + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = NULL; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + ret = WLAN_STATUS_FAILURE; + goto done; + } + + /* Store the response code to CurCmdRetCode. */ + Adapter->CurCmdRetCode = wlan_le16_to_cpu(resp->Result); + + if (RespCmd == HostCmd_RET_802_11_PS_MODE) { + struct HostCmd_DS_802_11_PS_MODE *psmode; + + psmode = &resp->params.psmode; + PRINTM(INFO, + "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", + resp->Result, psmode->Action); + psmode->Action = wlan_cpu_to_le16(psmode->Action); + + if (Result) { + PRINTM(INFO, "CMD_RESP: PS command failed- %#x \n", + resp->Result); + if (Adapter->InfrastructureMode == Wlan802_11IBSS) { + /* + * We should not re-try enter-ps command in + * ad-hoc mode. It takes place in + * libertas_execute_next_command(). + */ + if (psmode->Action == HostCmd_SubCmd_Enter_PS) + Adapter->PSMode = + Wlan802_11PowerModeCAM; + } + } else if (psmode->Action == HostCmd_SubCmd_Enter_PS) { + Adapter->NeedToWakeup = 0; + Adapter->PSState = PS_STATE_AWAKE; + + PRINTM(INFO, "CMD_RESP: Enter_PS command response\n"); + if (Adapter->MediaConnectStatus != + WlanMediaStateConnected) { + /* + * When Deauth Event received before Enter_PS command + * response, We need to wake up the firmware. + */ + PRINTM(INFO, + "Disconnected, Going to invoke libertas_ps_wakeup\n"); + libertas_ps_wakeup(priv, 0); + } + } else if (psmode->Action == HostCmd_SubCmd_Exit_PS) { + Adapter->NeedToWakeup = 0; + Adapter->PSState = PS_STATE_FULL_POWER; + PRINTM(INFO, "CMD_RESP: Exit_PS command response\n"); + } else { + PRINTM(INFO, "CMD_RESP: PS- Action=0x%X\n", + psmode->Action); + } + + libertas_cleanup_and_insert_cmd(priv, Adapter->CurCmd); + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = NULL; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + if (Adapter->CurCmd->CmdFlags & CMD_F_HOSTCMD) { + /* Copy the response back to response buffer */ + memcpy(Adapter->CurCmd->pdata_buf, resp, resp->Size); + + Adapter->CurCmd->CmdFlags &= ~CMD_F_HOSTCMD; + } + + /* If the command is not successful, cleanup and return failure */ + if ((Result != HostCmd_RESULT_OK || !(RespCmd & 0x8000))) { + PRINTM(INFO, "CMD_RESP: command reply %#x result=%#x\n", + resp->Command, resp->Result); + /* + * Handling errors here + */ + switch (RespCmd) { + case HostCmd_RET_HW_SPEC_INFO: + case HostCmd_RET_802_11_RESET: + PRINTM(INFO, "CMD_RESP: Reset command Failed\n"); + Adapter->HardwareStatus = WlanHardwareStatusNotReady; + break; + + } + + libertas_cleanup_and_insert_cmd(priv, Adapter->CurCmd); + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = NULL; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + return WLAN_STATUS_FAILURE; + } + + switch (RespCmd) { + case HostCmd_RET_MAC_REG_ACCESS: + case HostCmd_RET_BBP_REG_ACCESS: + case HostCmd_RET_RF_REG_ACCESS: + ret = wlan_ret_reg_access(priv, RespCmd, resp); + break; + + case HostCmd_RET_HW_SPEC_INFO: + ret = wlan_ret_get_hw_spec(priv, resp); + break; + + case HostCmd_RET_802_11_SCAN: + ret = libertas_ret_80211_scan(priv, resp); + break; + + case HostCmd_RET_MAC_CONTROL: + ret = wlan_ret_mac_control(priv, resp); + break; + + case HostCmd_RET_802_11_GET_LOG: + ret = wlan_ret_get_log(priv, resp); + break; + + case HostCmd_RET_802_11_ASSOCIATE: + case HostCmd_RET_802_11_REASSOCIATE: + ret = libertas_ret_80211_associate(priv, resp); + break; + + case HostCmd_RET_802_11_DISASSOCIATE: + case HostCmd_RET_802_11_DEAUTHENTICATE: + ret = libertas_ret_80211_disassociate(priv, resp); + break; + + case HostCmd_RET_802_11_SET_WEP: + ret = wlan_ret_802_11_set_wep(priv, resp); + break; + + case HostCmd_RET_802_11_AD_HOC_START: + case HostCmd_RET_802_11_AD_HOC_JOIN: + ret = libertas_ret_80211_ad_hoc_start(priv, resp); + break; + + case HostCmd_RET_802_11_RESET: + ret = wlan_ret_802_11_reset(priv, resp); + break; + + case HostCmd_RET_802_11_AUTHENTICATE: + ret = libertas_ret_80211_authenticate(priv, resp); + break; + + case HostCmd_RET_802_11_STAT: + ret = wlan_ret_802_11_stat(priv, resp); + break; + + case HostCmd_RET_802_11_SNMP_MIB: + ret = wlan_ret_802_11_snmp_mib(priv, resp); + break; + + case HostCmd_RET_802_11_RF_TX_POWER: + ret = wlan_ret_802_11_rf_tx_power(priv, resp); + break; + + case HostCmd_RET_802_11_RADIO_CONTROL: + ret = wlan_ret_802_11_radio_control(priv, resp); + break; + + case HostCmd_RET_802_11_SET_AFC: + case HostCmd_RET_802_11_GET_AFC: + memmove(Adapter->CurCmd->pdata_buf, + &resp->params.afc, + sizeof(struct HostCmd_DS_802_11_AFC)); + + break; + case HostCmd_RET_802_11_RF_ANTENNA: + ret = wlan_ret_802_11_rf_antenna(priv, resp); + break; + + case HostCmd_RET_MAC_MULTICAST_ADR: + ret = wlan_ret_mac_multicast_adr(priv, resp); + break; + + case HostCmd_RET_802_11_DATA_RATE: + ret = wlan_ret_802_11_data_rate(priv, resp); + break; + case HostCmd_RET_802_11_RATE_ADAPT_RATESET: + ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); + break; + case HostCmd_RET_802_11_RF_CHANNEL: + ret = wlan_ret_802_11_rf_channel(priv, resp); + break; + + case HostCmd_RET_802_11_RSSI: + ret = wlan_ret_802_11_rssi(priv, resp); + break; + + case HostCmd_RET_802_11_MAC_ADDRESS: + ret = wlan_ret_802_11_mac_address(priv, resp); + break; + + case HostCmd_RET_802_11_AD_HOC_STOP: + ret = libertas_ret_80211_ad_hoc_stop(priv, resp); + break; + + case HostCmd_RET_802_11_BEACON_STOP: + break; + + case HostCmd_RET_802_11_ENABLE_RSN: + break; + case HostCmd_RET_802_11_KEY_MATERIAL: + PRINTM(INFO, "CMD_RESP: KEY_MATERIAL command response\n"); + ret = wlan_ret_802_11_key_material(priv, resp); + break; + + case HostCmd_RET_802_11_EEPROM_ACCESS: + ret = wlan_ret_802_11_eeprom_access(priv, resp); + break; + + case HostCmd_RET_802_11D_DOMAIN_INFO: + ret = libertas_ret_802_11d_domain_info(priv, resp); + break; + + case HostCmd_RET_802_11_SLEEP_PARAMS: + ret = wlan_ret_802_11_sleep_params(priv, resp); + break; + case HostCmd_RET_802_11_INACTIVITY_TIMEOUT: + *((u16 *) Adapter->CurCmd->pdata_buf) = + wlan_le16_to_cpu(resp->params.inactivity_timeout.Timeout); + break; + + case HostCmd_RET_802_11_SLEEP_PERIOD: + ret = wlan_ret_802_11_sleep_period(priv, resp); + break; + case HostCmd_RET_802_11_TPC_CFG: + memmove(Adapter->CurCmd->pdata_buf, + &resp->params.tpccfg, + sizeof(struct HostCmd_DS_802_11_TPC_CFG)); + break; + case HostCmd_RET_802_11_LED_GPIO_CTRL: + memmove(Adapter->CurCmd->pdata_buf, + &resp->params.ledgpio, + sizeof(struct HostCmd_DS_802_11_LED_CTRL)); + break; + case HostCmd_RET_802_11_PWR_CFG: + memmove(Adapter->CurCmd->pdata_buf, + &resp->params.pwrcfg, + sizeof(struct HostCmd_DS_802_11_PWR_CFG)); + + break; + + case HostCmd_RET_GET_TSF: + memcpy(priv->adapter->CurCmd->pdata_buf, + &resp->params.gettsf.TsfValue, sizeof(u64)); + break; + case HostCmd_RET_DFT_ACCESS: + if (Adapter->CurCmd->pdata_buf) + memcpy(Adapter->CurCmd->pdata_buf, + &resp->params.dft.addr1, 2 * ETH_ALEN); + break; + case HostCmd_RTE_802_11_TX_RATE_QUERY: + priv->adapter->TxRate = resp->params.txrate.TxRate; + break; + default: + PRINTM(INFO, "CMD_RESP: Unknown command response %#x\n", + resp->Command); + break; + } + + if (Adapter->CurCmd) { + /* Clean up and Put current command back to CmdFreeQ */ + libertas_cleanup_and_insert_cmd(priv, Adapter->CurCmd); + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = NULL; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function handles events generated by firmware + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_process_event(wlan_private * priv) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + PRINTM(INFO, "EVENT Cause %x\n", Adapter->EventCause); + + switch (Adapter->EventCause >> SBI_EVENT_CAUSE_SHIFT) { + case MACREG_INT_CODE_LINK_SENSED: + PRINTM(INFO, "EVENT: MACREG_INT_CODE_LINK_SENSED\n"); + break; + + case MACREG_INT_CODE_DEAUTHENTICATED: + PRINTM(INFO, "EVENT: Deauthenticated\n"); + HandleDisconnectEvent(priv); + break; + + case MACREG_INT_CODE_DISASSOCIATED: + PRINTM(INFO, "EVENT: Disassociated\n"); + HandleDisconnectEvent(priv); + break; + + case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: + PRINTM(INFO, "EVENT: Link lost\n"); + HandleDisconnectEvent(priv); + break; + + case MACREG_INT_CODE_PS_SLEEP: + PRINTM(INFO, "EVENT: SLEEP\n"); + PRINTM(INFO, "_"); + + /* handle unexpected PS SLEEP event */ + if (Adapter->PSState == PS_STATE_FULL_POWER) { + PRINTM(INFO, + "EVENT: In FULL POWER mode - ignore PS SLEEP\n"); + break; + } + Adapter->PSState = PS_STATE_PRE_SLEEP; + + libertas_ps_confirm_sleep(priv, (u16) Adapter->PSMode); + + break; + + case MACREG_INT_CODE_PS_AWAKE: + PRINTM(INFO, "EVENT: AWAKE \n"); + PRINTM(INFO, "|"); + + /* handle unexpected PS AWAKE event */ + if (Adapter->PSState == PS_STATE_FULL_POWER) { + PRINTM(INFO, + "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); + break; + } + + Adapter->TxLockFlag = 0; + if (libertas_check_last_packet_indication(priv)) { + if (Adapter->gen_null_pkg) { + libertas_send_null_packet(priv, + MRVDRV_TxPD_POWER_MGMT_NULL_PACKET + | + MRVDRV_TxPD_POWER_MGMT_LAST_PACKET); + Adapter->TxLockFlag = 1; + } + } + + Adapter->PSState = PS_STATE_AWAKE; + + if (Adapter->NeedToWakeup) { + /* + * wait for the command processing to finish + * before resuming sending + * Adapter->NeedToWakeup will be set to FALSE + * in libertas_ps_wakeup() + */ + PRINTM(INFO, "Waking up...\n"); + libertas_ps_wakeup(priv, 0); + } + break; + + case MACREG_INT_CODE_MIC_ERR_UNICAST: + PRINTM(INFO, "EVENT: UNICAST MIC ERROR\n"); + HandleMICFailureEvent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); + break; + + case MACREG_INT_CODE_MIC_ERR_MULTICAST: + PRINTM(INFO, "EVENT: MULTICAST MIC ERROR\n"); + HandleMICFailureEvent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); + break; + case MACREG_INT_CODE_MIB_CHANGED: + case MACREG_INT_CODE_INIT_DONE: + break; + + case MACREG_INT_CODE_ADHOC_BCN_LOST: + PRINTM(INFO, "EVENT: HWAC - ADHOC BCN LOST\n"); + break; + + case MACREG_INT_CODE_RSSI_LOW: + PRINTM(MSG, "EVENT: RSSI_LOW\n"); + break; + case MACREG_INT_CODE_SNR_LOW: + PRINTM(MSG, "EVENT: SNR_LOW\n"); + break; + case MACREG_INT_CODE_MAX_FAIL: + PRINTM(MSG, "EVENT: MAX_FAIL\n"); + break; + case MACREG_INT_CODE_RSSI_HIGH: + PRINTM(MSG, "EVENT: RSSI_HIGH\n"); + break; + case MACREG_INT_CODE_SNR_HIGH: + PRINTM(MSG, "EVENT: SNR_HIGH\n"); + break; + + default: + PRINTM(INFO, "EVENT: unknown event id: %#x\n", + Adapter->EventCause >> SBI_EVENT_CAUSE_SHIFT); + break; + } + + Adapter->EventCause = 0; + LEAVE(); + return ret; +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlanconfig/Makefile linux-2.6-libertas/drivers/net/wireless/libertas/wlanconfig/Makefile --- linux-2.6-orig/drivers/net/wireless/libertas/wlanconfig/Makefile 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlanconfig/Makefile 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,61 @@ +# +# File : app/Makefile +# +# (c) Copyright © 2003-2006, Marvell International Ltd. +# All Rights Reserved +# +# This software file (the "File") is distributed by Marvell International +# Ltd. under the terms of the GNU General Public License Version 2, June 1991 +# (the "License"). You may use, redistribute and/or modify this File in +# accordance with the terms and conditions of the License, a copy of which +# is available along with the File in the license.txt file or by writing to +# the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +# 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. +# +# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE +# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE +# ARE EXPRESSLY DISCLAIMED. The License provides additional details about +# this warranty disclaimer. +# + +# Path to the top directory of the wlan distribution +PATH_TO_TOP = .. + +# Determine how we should copy things to the install directory +ABSPATH := $(filter /%, $(INSTALLDIR)) +RELPATH := $(filter-out /%, $(INSTALLDIR)) +INSTALLPATH := $(ABSPATH) +ifeq ($(strip $(INSTALLPATH)),) +INSTALLPATH := $(PATH_TO_TOP)/$(RELPATH) +endif + +# Override CFLAGS for application sources, remove __ kernel namespace defines +CFLAGS := $(filter-out -D__%, $(CFLAGS)) + +# Add the wlan driver directory to the preprocessor include path +CFLAGS += -I$(PATH_TO_TOP)/ + +# +# List of application executables to create +# +TARGETS := wlanconfig + +# +# Make target rules +# + +# All rule compiles list of TARGETS using builtin program target from src rule +all : $(TARGETS) + +# Install rule; INSTALLPATH calculated above from passed INSTALLDIR variable +$(INSTALLPATH)/% : ./% + @cp -f $< $@ + +# Map build and install invocation to the install rule for each TARGET file +build install: $(addprefix $(INSTALLPATH)/, $(TARGETS)) + +clean: + @rm -f $(TARGETS) + +distclean: clean + @rm -f *~ core diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlanconfig/wlanconfig.c linux-2.6-libertas/drivers/net/wireless/libertas/wlanconfig/wlanconfig.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlanconfig/wlanconfig.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlanconfig/wlanconfig.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,2255 @@ +/** @file wlanconfig.c + * @brief Program to configure addition paramters into the wlan driver + * + * Usage: wlanconfig <ethX> <cmd> [...] + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/12/05: Add Doxygen format comments + 11/03/05: Load priv ioctls on demand, ifdef code for features in driver + 11/04/05: Add crypto_test + 12/14/05: Support wildcard SSID in BGSCAN + 01/11/06: Add getscantable, setuserscan, setmrvltlv, getassocrsp + 01/31/06: Add support to selectively enabe the FW Scan channel filter + 02/24/06: fix getscanlist function not work on linux 2.6.15 X86 + 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support + 04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API +********************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <string.h> +#include <stdlib.h> +#include <linux/if.h> +#include <sys/ioctl.h> +#include <linux/wireless.h> +#include <linux/if_ether.h> +#include <linux/byteorder/swab.h> +#include <errno.h> + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; +typedef unsigned long long u64; +typedef char s8; +typedef short s16; +typedef long s32; + +#ifdef BYTE_SWAP +#define cpu_to_le16(x) __swab16(x) +#else +#define cpu_to_le16(x) (x) +#endif + +#ifndef __ATTRIB_ALIGN__ +#define __ATTRIB_ALIGN__ __attribute__((aligned(4))) +#endif + +#ifndef __ATTRIB_PACK__ +#define __ATTRIB_PACK__ __attribute__((packed)) +#endif + +/* + * ctype from older glib installations defines BIG_ENDIAN. Check it + * and undef it if necessary to correctly process the wlan header + * files + */ +#if (BYTE_ORDER == LITTLE_ENDIAN) +#undef BIG_ENDIAN +#endif + +#include "wlan_defs.h" +#include "wlan_types.h" +#include "wlan_11d.h" +#include "host.h" +#include "hostcmd.h" +#include "wlan_scan.h" +#include "wlan_wext.h" +#include "wlanconfig.h" + +enum COMMANDS { + CMD_HOSTCMD, + CMD_RDMAC, + CMD_WRMAC, + CMD_RDBBP, + CMD_WRBBP, + CMD_RDRF, + CMD_WRRF, + CMD_RDEEPROM, + CMD_CMD52R, + CMD_CMD52W, + CMD_CMD53R, + CMD_CMD53W, + CMD_CFREGR, + CMD_CFREGW, + CMD_GETRATE, + CMD_SLEEPPARAMS, + CMD_BCA_TS, + CMD_EXTSCAN, + CMD_SCAN_LIST, + CMD_GET_SCAN_RSP, + CMD_SET_USER_SCAN, +}; + +#define IW_MAX_PRIV_DEF 128 + +/******************************************************** + Local Variables +********************************************************/ +static s8 *commands[] = { + "hostcmd", + "rdmac", + "wrmac", + "rdbbp", + "wrbbp", + "rdrf", + "wrrf", + "rdeeprom", + "sdcmd52r", + "sdcmd52w", + "sdcmd53r", + "sdcmd53w", + "rdcfreg", + "wrcfreg", + "getrate", + "sleepparams", + "bca-ts", + "extscan", + "getscanlist", + "getscantable", + "setuserscan", +}; + +static s8 *usage[] = { + "Usage: wlanconfig <ethX> <cmd> [...]", + "where", + " ethX : wireless network interface", + " cmd : hostcmd, rdmac, wrmac, rdbbp, wrbbp, rdrf, wrrf", + " : sdcmd52r, sdcmd52w, sdcmd53r", + " : caldataext, rdcfreg, wrcfreg, rdeeprom", + " : sleepparams, bca-ts", + " : setadhocch, getadhocch", + " : getscantable, setuserscan", + " [...] : additional parameters for read registers are", + " : <offset>", + " : additional parameters for write registers are", + " : <offset> <value>", + " : additonal parameter for hostcmd", + " : <filename> <cmd>", + " : addition parameters for caldataext", + " : <filename>", +}; + +static s32 sockfd; +static s8 dev_name[IFNAMSIZ + 1]; +static struct iw_priv_args Priv_args[IW_MAX_PRIV_DEF]; +static int we_version_compiled=0; +#define MRV_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ + (char *) NULL) + + + +static s8 * wlan_config_get_line(s8 *s, s32 size, FILE *stream, int *line); + +/******************************************************** + Global Variables +********************************************************/ + + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief convert char to hex integer + * + * @param chr char to convert + * @return hex integer or 0 + */ +static int hexval(s32 chr) +{ + if (chr >= '0' && chr <= '9') + return chr - '0'; + if (chr >= 'A' && chr <= 'F') + return chr - 'A' + 10; + if (chr >= 'a' && chr <= 'f') + return chr - 'a' + 10; + + return 0; +} + +/** + * @brief Hump hex data + * + * @param prompt A pointer prompt buffer + * @param p A pointer to data buffer + * @param len the len of data buffer + * @param delim delim char + * @return hex integer + */ +static void hexdump(s8 *prompt, void *p, s32 len, s8 delim) +{ + s32 i; + u8 *s = p; + + if (prompt) { + printf("%s: ", prompt); + } + for (i = 0; i < len; i++) { + if (i != len - 1) + printf("%02x%c", *s++, delim); + else + printf("%02x\n", *s); + } +} + +/** + * @brief convert char to hex integer + * + * @param chr char + * @return hex integer + */ +static u8 hexc2bin(s8 chr) +{ + if (chr >= '0' && chr <= '9') + chr -= '0'; + else if (chr >= 'A' && chr <= 'F') + chr -= ('A' - 10); + else if (chr >= 'a' && chr <= 'f') + chr -= ('a' - 10); + + return chr; +} + +/** + * @brief convert string to hex integer + * + * @param s A pointer string buffer + * @return hex integer + */ +static u32 a2hex(s8 *s) +{ + u32 val = 0; + while (*s && isxdigit(*s)) { + val = (val << 4) + hexc2bin(*s++); + } + + return val; +} + + +/* + * @brief convert String to integer + * + * @param value A pointer to string + * @return integer + */ +static u32 a2hex_or_atoi(s8 *value) +{ + if (value[0] == '0' && (value[1] == 'X' || value[1] == 'x')) + return a2hex(value + 2); + else + return atoi(value); +} + + +/** + * @brief convert string to integer + * + * @param ptr A pointer to data buffer + * @param chr A pointer to return integer + * @return A pointer to next data field + */ +s8 *convert2hex(s8 *ptr, u8 *chr) +{ + u8 val; + + for (val = 0; *ptr && isxdigit(*ptr); ptr++) { + val = (val * 16) + hexval(*ptr); + } + + *chr = val; + + return ptr; +} + +/** + * @brief Get private info. + * + * @param ifname A pointer to net name + * @return WLAN_STATUS_SUCCESS--success, otherwise --fail + */ +static int get_private_info(const s8 *ifname) +{ + /* This function sends the SIOCGIWPRIV command which is + * handled by the kernel. and gets the total number of + * private ioctl's available in the host driver. + */ + struct iwreq iwr; + int s, ret = WLAN_STATUS_SUCCESS; + struct iw_priv_args *pPriv = Priv_args; + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) { + perror("socket[PF_INET,SOCK_DGRAM]"); + return WLAN_STATUS_FAILURE; + } + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, ifname, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) pPriv; + iwr.u.data.length = IW_MAX_PRIV_DEF; + iwr.u.data.flags = 0; + + if (ioctl(s, SIOCGIWPRIV, &iwr) < 0) { + perror("ioctl[SIOCGIWPRIV]"); + ret = WLAN_STATUS_FAILURE; + } else { + /* Return the number of private ioctls */ + ret = iwr.u.data.length; + } + + close(s); + + return ret; +} + +/** + * @brief Get Sub command ioctl number + * + * @param i command index + * @param priv_cnt Total number of private ioctls availabe in driver + * @param ioctl_val A pointer to return ioctl number + * @param subioctl_val A pointer to return sub-ioctl number + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int marvell_get_subioctl_no(s32 i, + s32 priv_cnt, + int *ioctl_val, + int *subioctl_val) +{ + s32 j; + + if (Priv_args[i].cmd >= SIOCDEVPRIVATE) { + *ioctl_val = Priv_args[i].cmd; + *subioctl_val = 0; + return WLAN_STATUS_SUCCESS; + } + + j = -1; + + /* Find the matching *real* ioctl */ + + while ((++j < priv_cnt) + && ((Priv_args[j].name[0] != '\0') || + (Priv_args[j].set_args != Priv_args[i].set_args) || + (Priv_args[j].get_args != Priv_args[i].get_args))) { + } + + /* If not found... */ + if (j == priv_cnt) { + printf("%s: Invalid private ioctl definition for: 0x%x\n", + dev_name, Priv_args[i].cmd); + return WLAN_STATUS_FAILURE; + } + + /* Save ioctl numbers */ + *ioctl_val = Priv_args[j].cmd; + *subioctl_val = Priv_args[i].cmd; + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get ioctl number + * + * @param ifname A pointer to net name + * @param priv_cmd A pointer to priv command buffer + * @param ioctl_val A pointer to return ioctl number + * @param subioctl_val A pointer to return sub-ioctl number + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int marvell_get_ioctl_no(const s8 *ifname, + const s8 *priv_cmd, + int *ioctl_val, + int *subioctl_val) +{ + s32 i; + s32 priv_cnt; + + priv_cnt = get_private_info(ifname); + + /* Are there any private ioctls? */ + if (priv_cnt <= 0) { + /* Could skip this message ? */ + printf("%-8.8s no private ioctls.\n", ifname); + } else { + for (i = 0; i < priv_cnt; i++) { + if (Priv_args[i].name[0] && !strcmp(Priv_args[i].name, priv_cmd)) { + return marvell_get_subioctl_no(i, priv_cnt, + ioctl_val, subioctl_val); + } + } + } + + return WLAN_STATUS_FAILURE; +} + +/** + * @brief Retrieve the ioctl and sub-ioctl numbers for the given ioctl string + * + * @param ifname Private IOCTL string name + * @param ioctl_val A pointer to return ioctl number + * @param subioctl_val A pointer to return sub-ioctl number + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int get_priv_ioctl(char* ioctl_name, int* ioctl_val, int* subioctl_val) +{ + int retval; + + retval = marvell_get_ioctl_no(dev_name, + ioctl_name, + ioctl_val, + subioctl_val); + +#if 0 + /* Debug print discovered IOCTL values */ + printf("ioctl %s: %x, %x\n", ioctl_name, *ioctl_val, *subioctl_val); +#endif + + return retval; +} + + +/** + * @brief get range + * + * @return WLAN_STATUS_SUCCESS--success, otherwise --fail + */ +static int get_range(void) +{ + struct iw_range *range; + struct iwreq iwr; + size_t buflen; + WCON_HANDLE mhandle, *pHandle = &mhandle; + + buflen = sizeof(struct iw_range) + 500; + range = malloc(buflen); + if (range == NULL) + return WLAN_STATUS_FAILURE; + memset(range, 0, buflen); + + memset(pHandle, 0, sizeof(WCON_HANDLE)); + memset(&iwr, 0, sizeof(struct iwreq)); + + iwr.u.data.pointer = (caddr_t) range; + iwr.u.data.length = buflen; + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + + if ((ioctl(sockfd, SIOCGIWRANGE, &iwr)) < 0) { + printf("Get Range Results Failed\n"); + free(range); + return WLAN_STATUS_FAILURE; + } + we_version_compiled = range->we_version_compiled; + printf("Driver build with Wireless Extension %d\n",range->we_version_compiled); + free(range); + return WLAN_STATUS_SUCCESS; +} +#define WLAN_MAX_RATES 14 +#define GIGA 1e9 +#define MEGA 1e6 +#define KILO 1e3 + +/** + * @brief print bit rate + * + * @param rate rate to be print + * @param current if current is TRUE, data rate not need convert + * @param fixed not used + * @return WLAN_STATUS_SUCCESS + */ +static int print_bitrate(double rate, s32 current, s32 fixed) +{ + s8 scale = 'k', buf[128]; + s32 divisor = KILO; + + if (!current) + rate *= 500000; + + if (rate >= GIGA) { + scale = 'G'; + divisor = GIGA; + } else if (rate >= MEGA) { + scale = 'M'; + divisor = MEGA; + } + + snprintf(buf, sizeof(buf), "%g %cb/s", rate/divisor, scale); + + if (current) { + printf("\t Current Bit Rate%c%s\n\n", + (fixed) ? '=' : ':', buf); + } else { + printf("\t %s\n", buf); + } + + return WLAN_STATUS_SUCCESS; +} + +/* + * @brief get hostcmd data + * + * @param fp A pointer to file stream + * @param ln A pointer to line number + * @param buf A pointer to hostcmd data + * @param size A pointer to the return size of hostcmd buffer + * @return WLAN_STATUS_SUCCESS + */ +static int wlan_get_hostcmd_data(FILE *fp, int *ln, u8 *buf, u16 *size) +{ + s32 errors = 0, i; + s8 line[256], *pos, *pos1, *pos2, *pos3; + u16 len; + + + while ((pos = wlan_config_get_line(line, sizeof(line), fp, ln))) { + (*ln)++; + if (strcmp(pos, "}") == 0) { + break; + } + + pos1 = strchr(pos, ':'); + if (pos1 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, pos); + errors++; + continue; + } + *pos1++ = '\0'; + + pos2 = strchr(pos1, '='); + if (pos2 == NULL) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, pos); + errors++; + continue; + } + *pos2++ = '\0'; + + len = a2hex_or_atoi(pos1); + if (len < 1 || len > MRVDRV_SIZE_OF_CMD_BUFFER) { + printf("Line %d: Invalid hostcmd line '%s'\n", *ln, pos); + errors++; + continue; + } + + *size += len; + + if (*pos2 == '"') { + pos2++; + if ((pos3=strchr(pos2, '"')) == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, pos); + errors++; + continue; + } + *pos3 = '\0'; + memset(buf, 0, len); + memmove(buf, pos2, min(strlen(pos2),len)); + buf += len; + } + else if (*pos2 == '\'') { + pos2++; + if ((pos3=strchr(pos2, '\'')) == NULL) { + printf("Line %d: invalid quotation '%s'\n", *ln, pos); + errors++; + continue; + } + *pos3 = ','; + for (i=0; i<len; i++) { + if ((pos3=strchr(pos2, ',')) != NULL) { + *pos3 = '\0'; + *buf++ = (u8)a2hex_or_atoi(pos2); + pos2 = pos3 + 1; + } + else + *buf++ = 0; + } + } + else if (*pos2 == '{') { + u16 *tlvlen = (u16 *)buf; + wlan_get_hostcmd_data(fp, ln, buf+len, tlvlen); + *size += *tlvlen; + buf += len + *tlvlen; + } + else { + u32 value = a2hex_or_atoi(pos2); + while (len--) { + *buf++ = (u8)(value & 0xff); + value >>= 8; + } + } + } + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Process host_cmd + * @param hostcmd A pointer to HostCmd_DS_GEN data structure + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_host_cmd(int argc, char *argv[]) +{ + u8 line[256], cmdname[256], *pos; + s8 *buf; + FILE *fp; + struct HostCmd_DS_GEN *hostcmd; + struct ifreq userdata; + int ln = 0; + int cmdname_found = 0, cmdcode_found = 0; + int ret = WLAN_STATUS_SUCCESS; + + if (argc < 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./wlanconfig eth1 hostcmd <hostcmd.conf> <cmdname>\n"); + exit(1); + } + + if ((fp = fopen(argv[3], "r")) == NULL) { + fprintf(stderr, "Cannot open file %s\n", argv[4]); + exit(1); + } + + buf = (u8 *)malloc(MRVDRV_SIZE_OF_CMD_BUFFER); + memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER); + hostcmd = (struct HostCmd_DS_GEN *)buf; + + hostcmd->Command = 0xffff; + + sprintf(cmdname, "%s={", argv[4]); + cmdname_found = 0; + while ((pos = wlan_config_get_line(line, sizeof(line), fp, &ln))) { + if (strcmp(pos, cmdname) == 0) { + cmdname_found = 1; + sprintf(cmdname, "CmdCode="); + cmdcode_found = 0; + while ((pos = wlan_config_get_line(line, sizeof(line), fp, &ln))) { + if (strncmp(pos, cmdname, strlen(cmdname)) == 0) { + cmdcode_found = 1; + hostcmd->Command = a2hex_or_atoi(pos+strlen(cmdname)); + hostcmd->Size = S_DS_GEN; + wlan_get_hostcmd_data(fp, &ln, buf+hostcmd->Size, &hostcmd->Size); + break; + } + } + if (!cmdcode_found) { + fprintf(stderr, "wlanconfig: CmdCode not found in file '%s'\n", argv[3]); + } + break; + } + } + + fclose(fp); + + if (!cmdname_found) + fprintf(stderr, "wlanconfig: cmdname '%s' not found in file '%s'\n", argv[4],argv[3]); + + if (!cmdname_found || !cmdcode_found) { + ret = -1; + goto _exit_; + } + + buf = (u8 *)hostcmd; + + hostcmd->SeqNum = 0; + hostcmd->Result = 0; + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = (u8 *)hostcmd; + + if (ioctl(sockfd, WLANHOSTCMD, &userdata)) { + fprintf(stderr, "wlanconfig: WLANHOSTCMD is not supported by %s\n", dev_name); + ret = -1; + goto _exit_; + } + + if (!hostcmd->Result) { + switch (hostcmd->Command) { + case HostCmd_RET_802_11_SUBSCRIBE_EVENT: + { + struct HostCmd_DS_802_11_SUBSCRIBE_EVENT *se = (struct HostCmd_DS_802_11_SUBSCRIBE_EVENT *)(buf + S_DS_GEN); + if (se->Action == HostCmd_ACT_GET) { + int len = S_DS_GEN + sizeof(struct HostCmd_DS_802_11_SUBSCRIBE_EVENT); + printf("\nEvent\t\tValue\tFreq\tsubscribed\n\n"); + while (len < hostcmd->Size) { + MrvlIEtypesHeader_t *header = (MrvlIEtypesHeader_t *)(buf + len); + switch (header->Type) { + case TLV_TYPE_RSSI_LOW: + { + MrvlIEtypes_RssiParamSet_t *LowRssi = (MrvlIEtypes_RssiParamSet_t *)(buf + len); + printf("Low RSSI\t%d\t%d\t%s\n",LowRssi->RSSIValue,LowRssi->RSSIFreq,(se->Events & 0x0001)?"yes":"no"); + len += sizeof(MrvlIEtypes_RssiParamSet_t); + break; + } + case TLV_TYPE_SNR_LOW: + { + MrvlIEtypes_SnrThreshold_t *LowSnr = (MrvlIEtypes_SnrThreshold_t *)(buf + len); + printf("Low SNR\t\t%d\t%d\t%s\n",LowSnr->SNRValue,LowSnr->SNRFreq,(se->Events & 0x0002)?"yes":"no"); + len += sizeof(MrvlIEtypes_SnrThreshold_t); + break; + } + case TLV_TYPE_FAILCOUNT: + { + MrvlIEtypes_FailureCount_t *FailureCount = (MrvlIEtypes_FailureCount_t *)(buf + len); + printf("Failure Count\t%d\t%d\t%s\n",FailureCount->FailValue,FailureCount->FailFreq,(se->Events & 0x0004)?"yes":"no"); + len += sizeof(MrvlIEtypes_FailureCount_t); + break; + } + case TLV_TYPE_BCNMISS: + { + MrvlIEtypes_BeaconsMissed_t *BcnMissed = (MrvlIEtypes_BeaconsMissed_t *)(buf + len); + printf("Beacon Missed\t%d\tN/A\t%s\n",BcnMissed->BeaconMissed,(se->Events & 0x0008)?"yes":"no"); + len += sizeof(MrvlIEtypes_BeaconsMissed_t); + break; + } + case TLV_TYPE_RSSI_HIGH: + { + MrvlIEtypes_RssiParamSet_t *HighRssi = (MrvlIEtypes_RssiParamSet_t *)(buf + len); + printf("High RSSI\t%d\t%d\t%s\n",HighRssi->RSSIValue,HighRssi->RSSIFreq,(se->Events & 0x0010)?"yes":"no"); + len += sizeof(MrvlIEtypes_RssiParamSet_t); + break; + } + case TLV_TYPE_SNR_HIGH: + { + MrvlIEtypes_SnrThreshold_t *HighSnr = (MrvlIEtypes_SnrThreshold_t *)(buf + len); + printf("High SNR\t%d\t%d\t%s\n",HighSnr->SNRValue,HighSnr->SNRFreq,(se->Events & 0x0020)?"yes":"no"); + len += sizeof(MrvlIEtypes_SnrThreshold_t); + break; + } + default: + printf("unknown subscribed event TLV Type=%#x, Len=%d\n", header->Type, header->Len); + len += sizeof(MrvlIEtypesHeader_t) + header->Len; + break; + } + } + } + break; + } + default: + printf("HOSTCMD_RESP: ReturnCode=%#04x, Result=%#04x\n",hostcmd->Command,hostcmd->Result); + break; + } + } + else { + printf("HOSTCMD failed: ReturnCode=%#04x, Result=%#04x\n",hostcmd->Command,hostcmd->Result); + } + +_exit_: + if (buf) + free(buf); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Rate + * + * @return WLAN_STATUS_SUCCESS--success, otherwise --fail + */ +static int process_get_rate(void) +{ + u32 bitrate[WLAN_MAX_RATES]; + struct iwreq iwr; + s32 i = 0; + int ioctl_val, subioctl_val; + + if (get_priv_ioctl("getrate", + &ioctl_val, &subioctl_val) == WLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + memset(&iwr, 0, sizeof(iwr)); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) bitrate; + iwr.u.data.length = sizeof(bitrate); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("wlanconfig"); + return WLAN_STATUS_FAILURE; + } + + printf("%-8.16s %d available bit-rates :\n", + dev_name, iwr.u.data.length); + + for (i = 0; i < iwr.u.data.length; i++) { + print_bitrate(bitrate[i], 0, 0); + } + + if (ioctl(sockfd, SIOCGIWRATE, &iwr)) { + perror("wlanconfig"); + return WLAN_STATUS_FAILURE; + } + + print_bitrate(iwr.u.bitrate.value, 1, iwr.u.bitrate.fixed); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Check the Hex String + * @param s A pointer to the string + * @return 0--HexString, -1--not HexString + */ +static int ishexstring(s8 *s) +{ + int ret = -1; + s32 tmp; + + while(*s) { + tmp = toupper(*s); + if (tmp >= 'A' && tmp <= 'F') { + ret = 0; + break; + } + s++; + } + + return ret; +} + +/** + * @brief Convert String to Integer + * @param buf A pointer to the string + * @return Integer + */ +static int atoval(s8 *buf) +{ + if (!strncasecmp(buf, "0x", 2)) + return a2hex(buf+2); + else if (!ishexstring(buf)) + return a2hex(buf); + else + return atoi(buf); +} + + +/** + * @brief Display sleep params + * @param sp A pointer to wlan_ioctl_sleep_params_config structure + * @return NA + */ +void display_sleep_params(wlan_ioctl_sleep_params_config *sp) +{ + printf("Sleep Params for %s:\n", sp->Action ? "set" : "get"); + printf("----------------------------------------\n"); + printf("Error : %u\n", sp->Error); + printf("Offset : %u\n", sp->Offset); + printf("StableTime : %u\n", sp->StableTime); + printf("CalControl : %u\n", sp->CalControl); + printf("ExtSleepClk : %u\n", sp->ExtSleepClk); + printf("Reserved : %u\n", sp->Reserved); +} + +/** + * @brief Process sleep params + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_sleep_params(int argc, char *argv[]) +{ + struct iwreq iwr; + int ret; + wlan_ioctl_sleep_params_config sp; + int ioctl_val, subioctl_val; + + if (get_priv_ioctl("sleepparams", + &ioctl_val, &subioctl_val) == WLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc < 4) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./wlanconfig eth1 sleepparams get/set <p1>" + " <p2> <p3> <p4> <p5> <p6>\n"); + exit(1); + } + + memset(&sp, 0, sizeof(wlan_ioctl_sleep_params_config)); + if (!strcmp(argv[3], "get")) { + sp.Action = 0; + } else if (!strncmp(argv[3], "set", 3)) { + if (argc != 10) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./wlanconfig eth1 sleepparams get/set" + "<p1> <p2> <p3> <p4> <p5> <p6>\n"); + exit(1); + } + + sp.Action = 1; + if ((ret = atoval(argv[4])) < 0) + return -EINVAL; + sp.Error = (u16) ret; + if ((ret = atoval(argv[5])) < 0) + return -EINVAL; + sp.Offset = (u16) ret; + if ((ret = atoval(argv[6])) < 0) + return -EINVAL; + sp.StableTime = (u16) ret; + if ((ret = atoval(argv[7])) < 0) + return -EINVAL; + sp.CalControl = (u8) ret; + if ((ret = atoval(argv[8])) < 0) + return -EINVAL; + sp.ExtSleepClk = (u8) ret; + if ((ret = atoval(argv[9])) < 0) + return -EINVAL; + sp.Reserved = (u16) ret; + } else { + return -EINVAL; + } + + memset(&iwr, 0, sizeof(iwr)); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) &sp; + iwr.u.data.length = sizeof(wlan_ioctl_sleep_params_config); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("wlanconfig"); + return -1; + } + + display_sleep_params(&sp); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Display BCA Time Share Params + * @param sp A point to wlan_ioctl_bca_timeshare_config structure + * @return NA + */ +static void display_bca_ts_params(wlan_ioctl_bca_timeshare_config *bca_ts) +{ + printf("BCA Time Share Params for %s:\n", bca_ts->Action?"set" : "get"); + printf("----------------------------------------\n"); + printf("TrafficType : %u\n", bca_ts->TrafficType); + printf("TimeShareInterval : %lu\n", bca_ts->TimeShareInterval); + printf("BTTime : %lu\n", bca_ts->BTTime); +} + +/** + * @brief Process BCA Time Share Params + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_bca_ts(int argc, char *argv[]) +{ + int ret, i; + struct iwreq iwr; + wlan_ioctl_bca_timeshare_config bca_ts; + int ioctl_val, subioctl_val; + + if (get_priv_ioctl("bca-ts", + &ioctl_val, &subioctl_val) == WLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc < 5) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./wlanconfig eth1 bca_ts get/set <p1>" + " <p2> <p3>\n"); + exit(1); + } + + memset(&bca_ts, 0, sizeof(wlan_ioctl_bca_timeshare_config)); + + if ((ret = atoval(argv[4])) < 0) + return -EINVAL; + if (ret > 1) + return -EINVAL; + bca_ts.TrafficType = (u16) ret; // 0 or 1 + + if (!strcmp(argv[3], "get")) { + bca_ts.Action = 0; + } else if (!strncmp(argv[3], "set", 3)) { + if (argc != 7) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./wlanconfig eth1 bca_ts get/set" + " <p1> <p2> <p3>\n"); + exit(1); + } + + bca_ts.Action = 1; + + if ((ret = atoval(argv[5])) < 0) + return -EINVAL; + /* If value is not multiple of 10 then take the floor value */ + i = ret % 10; + ret -= i; + /* Valid Range for TimeShareInterval: < 20 ... 60_000 > ms */ + if (ret < 20 || ret > 60000) { + printf("Invalid TimeShareInterval Range:" + " < 20 ... 60000 > ms\n"); + return -EINVAL; + } + bca_ts.TimeShareInterval = (u32) ret; + + if ((ret = atoval(argv[6])) < 0) + return -EINVAL; + /* If value is not multiple of 10 then take the floor value */ + i = ret % 10; + ret -= i; + + if (ret > bca_ts.TimeShareInterval) { + printf("Invalid BTTime" + " Range: < 0 .. TimeShareInterval > ms\n"); + return -EINVAL; + } + bca_ts.BTTime = (u32) ret; + } else { + return -EINVAL; + } + + memset(&iwr, 0, sizeof(iwr)); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) &bca_ts; + iwr.u.data.length = sizeof(wlan_ioctl_bca_timeshare_config); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("wlanconfig"); + return -1; + } + + display_bca_ts_params(&bca_ts); + + return WLAN_STATUS_SUCCESS; +} + + + + + +/** + * @brief Retrieve and display the contents of the driver scan table. + * + * The ioctl to retrieve the scan table contents will be invoked, and portions + * of the scan data will be displayed on stdout. The entire beacon or + * probe response is also retrieved (if available in the driver). This + * data would be needed in case the application was explicitly controlling + * the association (inserting IEs, TLVs, etc). + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_getscantable(int argc, char *argv[]) +{ + int ioctl_val, subioctl_val; + struct iwreq iwr; + u8 scanRspBuffer[500]; /* Stack buffer can be as large as ioctl allows */ + + uint scanStart; + uint idx; + + u8* pCurrent; + u8* pNext; + IEEEtypes_ElementId_e* pElementId; + u8* pElementLen; + int bssInfoLen; + int ssidIdx; + u16 tmpCap; + u8* pByte; + + IEEEtypes_CapInfo_t capInfo; + u8 tsf[8]; + u16 beaconInterval; + + wlan_ioctl_get_scan_table_info* pRspInfo; + wlan_ioctl_get_scan_table_entry* pRspEntry; + + pRspInfo = (wlan_ioctl_get_scan_table_info*)scanRspBuffer; + + if (get_priv_ioctl("getscantable", + &ioctl_val, &subioctl_val) == WLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + scanStart = 0; + + printf("---------------------------------------"); + printf("---------------------------------------\n"); + printf("# | ch | ss | bssid | cap | SSID \n"); + printf("---------------------------------------"); + printf("---------------------------------------\n"); + + do { + pRspInfo->scanNumber = scanStart; + + /* + * Set up and execute the ioctl call + */ + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t)pRspInfo; + iwr.u.data.length = sizeof(scanRspBuffer); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("wlanconfig: getscantable ioctl"); + return -EFAULT; + } + + pCurrent = 0; + pNext = pRspInfo->scan_table_entry_buffer; + + for (idx = 0; idx < pRspInfo->scanNumber; idx++) { + + /* + * Set pCurrent to pNext in case pad bytes are at the end + * of the last IE we processed. + */ + pCurrent = pNext; + + pRspEntry = (wlan_ioctl_get_scan_table_entry*)pCurrent; + + printf("%02u| %03d | %03d | %02x:%02x:%02x:%02x:%02x:%02x |", + scanStart + idx, + pRspEntry->fixedFields.channel, + pRspEntry->fixedFields.rssi, + pRspEntry->fixedFields.bssid[0], + pRspEntry->fixedFields.bssid[1], + pRspEntry->fixedFields.bssid[2], + pRspEntry->fixedFields.bssid[3], + pRspEntry->fixedFields.bssid[4], + pRspEntry->fixedFields.bssid[5]); + +#if 0 + printf("fixed = %u, bssInfo = %u\n", + (unsigned int)pRspEntry->fixedFieldLength, + (unsigned int)pRspEntry->bssInfoLength); +#endif + + pCurrent += (sizeof(pRspEntry->fixedFieldLength) + + pRspEntry->fixedFieldLength); + + bssInfoLen = pRspEntry->bssInfoLength; + pCurrent += sizeof(pRspEntry->bssInfoLength); + pNext = pCurrent + pRspEntry->bssInfoLength; + + if (bssInfoLen >= (sizeof(tsf) + + sizeof(beaconInterval) + sizeof(capInfo))) { + /* time stamp is 8 byte long */ + memcpy(tsf, pCurrent, sizeof(tsf)); + pCurrent += sizeof(tsf); + bssInfoLen -= sizeof(tsf); + + /* beacon interval is 2 byte long */ + memcpy(&beaconInterval, pCurrent, sizeof(beaconInterval)); + pCurrent += sizeof(beaconInterval); + bssInfoLen -= sizeof(beaconInterval); + + /* capability information is 2 byte long */ + memcpy(&capInfo, pCurrent, sizeof(capInfo)); + memcpy(&tmpCap, pCurrent, sizeof(tmpCap)); + pCurrent += sizeof(capInfo); + bssInfoLen -= sizeof(capInfo); + + printf(" %04x-", tmpCap); + + printf("%c%c%c | ", + capInfo.Ibss ? 'A' : 'I', + capInfo.Privacy ? 'P' : ' ', + capInfo.SpectrumMgmt ? 'S' : ' '); + } else { + printf(" | "); + } + + while (bssInfoLen >= 2) { + pElementId = (IEEEtypes_ElementId_e*)pCurrent; + pElementLen = pCurrent + 1; + pCurrent += 2; + + switch (*pElementId) { + + case SSID: + if (*pElementLen && + *pElementLen <= MRVDRV_MAX_SSID_LENGTH) { + for (ssidIdx = 0; ssidIdx < *pElementLen; ssidIdx++) { + if (isprint(*(pCurrent + ssidIdx))) { + printf("%c", *(pCurrent + ssidIdx)); + } else { + printf("\\%02x", *(pCurrent + ssidIdx)); + } + } + } + break; + + default: +#if 0 + printf("% d(%d), bil=%d\n", + *pElementId, *pElementLen, bssInfoLen); +#endif + break; + } + + pCurrent += *pElementLen; + bssInfoLen -= (2 + *pElementLen); + } + + printf("\n"); + + if (argc > 3) { + /* TSF is a u64, some formatted printing libs have + * trouble printing long longs, so cast and dump as bytes + */ + pByte = (u8*)&pRspEntry->fixedFields.networkTSF; + printf(" TSF=%02x%02x%02x%02x%02x%02x%02x%02x\n", + pByte[7], pByte[6], pByte[5], pByte[4], + pByte[3], pByte[2], pByte[1], pByte[0]); + } + } + + scanStart += pRspInfo->scanNumber; + + + } while (pRspInfo->scanNumber); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Request a scan from the driver and display the scan table afterwards + * + * Command line interface for performing a specific immediate scan based + * on the following keyword parsing: + * + * chan=[chan#][band][mode] where band is [a,b,g] and mode is + * blank for active or 'p' for passive + * bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan + * ssid="[SSID]" specify a SSID filter for the scan + * keep=[0 or 1] keep the previous scan results (1), discard (0) + * dur=[scan time] time to scan for each channel in milliseconds + * probes=[#] number of probe requests to send on each chan + * type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) + * + * Any combination of the above arguments can be supplied on the command line. + * If the chan token is absent, a full channel scan will be completed by + * the driver. If the dur or probes tokens are absent, the driver default + * setting will be used. The bssid and ssid fields, if blank, + * will produce an unfiltered scan. The type field will default to 3 (Any) + * and the keep field will default to 0 (Discard). + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_setuserscan(int argc, char *argv[]) +{ + wlan_ioctl_user_scan_cfg scanReq; + int ioctl_val, subioctl_val; + struct iwreq iwr; + char* pArgTok; + char* pChanTok; + char* pArgCookie; + char* pChanCookie; + int argIdx; + int chanParseIdx; + int chanCmdIdx; + char chanScratch[10]; + char* pScratch; + int tmpIdx; + unsigned int mac[ETH_ALEN]; + int scanTime; + + memset(&scanReq, 0x00, sizeof(scanReq)); + chanCmdIdx = 0; + scanTime = 0; + + if (get_priv_ioctl("setuserscan", + &ioctl_val, &subioctl_val) == WLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + for (argIdx = 0; argIdx < argc; argIdx++) { + if (strncmp(argv[argIdx], "chan=", strlen("chan=")) == 0) { + /* + * "chan" token string handler + */ + pArgTok = argv[argIdx] + strlen("chan="); + + while ((pArgTok = strtok_r(pArgTok, ",", &pArgCookie)) != NULL) { + + memset(chanScratch, 0x00, sizeof(chanScratch)); + pScratch = chanScratch; + + for (chanParseIdx = 0; + chanParseIdx < strlen(pArgTok); chanParseIdx++) { + if (isalpha(*(pArgTok + chanParseIdx))) { + *pScratch++ = ' '; + } + + *pScratch++ = *(pArgTok + chanParseIdx); + } + *pScratch = 0; + pArgTok = NULL; + + pChanTok = chanScratch; + + while ((pChanTok = strtok_r(pChanTok, " ", + &pChanCookie)) != NULL) { + if (isdigit(*pChanTok)) { + scanReq.chanList[chanCmdIdx].chanNumber + = atoi(pChanTok); + } else { + switch (toupper(*pChanTok)) + { + case 'A': + scanReq.chanList[chanCmdIdx].radioType = 1; + break; + case 'B': + case 'G': + scanReq.chanList[chanCmdIdx].radioType = 0; + break; + case 'P': + scanReq.chanList[chanCmdIdx].scanType = 1; + break; + } + } + pChanTok = NULL; + } + chanCmdIdx++; + } + } else if (strncmp(argv[argIdx], "bssid=", strlen("bssid=")) == 0) { + /* + * "bssid" token string handler + */ + sscanf(argv[argIdx] + strlen("bssid="), "%2x:%2x:%2x:%2x:%2x:%2x", + mac + 0, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5); + + for (tmpIdx = 0; tmpIdx < NELEMENTS(mac); tmpIdx++){ + scanReq.specificBSSID[tmpIdx] = (u8)mac[tmpIdx]; + } + } else if (strncmp(argv[argIdx], "keep=", strlen("keep=")) == 0) { + /* + * "keep" token string handler + */ + scanReq.keepPreviousScan = atoi(argv[argIdx] + strlen("keep=")); + } else if (strncmp(argv[argIdx], "dur=", strlen("dur=")) == 0) { + /* + * "dur" token string handler + */ + scanTime = atoi(argv[argIdx] + strlen("dur=")); + } else if (strncmp(argv[argIdx], "ssid=", strlen("ssid=")) == 0) { + /* + * "ssid" token string handler + */ + strncpy(scanReq.specificSSID, argv[argIdx] + strlen("ssid="), + sizeof(scanReq.specificSSID)); + } else if (strncmp(argv[argIdx], "probes=", strlen("probes=")) == 0) { + /* + * "probes" token string handler + */ + scanReq.numProbes = atoi(argv[argIdx] + strlen("probes=")); + } else if (strncmp(argv[argIdx], "type=", strlen("type=")) == 0) { + /* + * "type" token string handler + */ + scanReq.bssType = atoi(argv[argIdx] + strlen("type=")); + switch (scanReq.bssType) + { + case WLAN_SCAN_BSS_TYPE_BSS: + case WLAN_SCAN_BSS_TYPE_IBSS: + break; + + default: + case WLAN_SCAN_BSS_TYPE_ANY: + /* Set any unknown types to ANY */ + scanReq.bssType = WLAN_SCAN_BSS_TYPE_ANY; + } + } + } + + /* + * Update all the channels to have the same scan time + */ + for (tmpIdx = 0; tmpIdx < chanCmdIdx; tmpIdx++){ + scanReq.chanList[tmpIdx].scanTime = scanTime; + } + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t)&scanReq; + iwr.u.data.length = sizeof(scanReq); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("wlanconfig: setuserscan ioctl"); + return -EFAULT; + } + + process_getscantable(0, 0); + + return WLAN_STATUS_SUCCESS; +} + + + +/** + * @brief scan network with specific ssid + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_extscan(int argc, char *argv[]) +{ + struct iwreq iwr; + WCON_SSID Ssid; + int ioctl_val, subioctl_val; + + if (get_priv_ioctl("extscan", + &ioctl_val, &subioctl_val) == WLAN_STATUS_FAILURE) { + return -EOPNOTSUPP; + } + + if (argc != 4) { + printf("Error: invalid no of arguments\n"); + printf("Syntax: ./wlanconfig eth1 extscan <SSID>\n"); + exit(1); + } + + printf("Ssid: %s\n", argv[3]); + + memset(&Ssid, 0, sizeof(Ssid)); + memset(&iwr, 0, sizeof(iwr)); + + Ssid.ssid_len = strlen(argv[3]); + memcpy(Ssid.ssid, argv[3], Ssid.ssid_len); + + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) &Ssid; + iwr.u.data.length = sizeof(Ssid); + iwr.u.data.flags = subioctl_val; + + if (ioctl(sockfd, ioctl_val, &iwr) < 0) { + perror("wlanconfig"); + return -1; + } + + return WLAN_STATUS_SUCCESS; +} + +#if WIRELESS_EXT > 14 +/** + * @brief parse custom info + * @param pHandle A pointer to WCON_HANDLE + * @param data A pointer to iw_point structure + * @param idx AP index + * @return NA + */ +static void parse_custom_info(WCON_HANDLE *pHandle, struct iw_point *data, s32 idx) +{ + s32 i = 0; + s8 *custom_cmd[] = { "wpa_ie", "rsn_ie", NULL }; + + if (!data->pointer || !data->length) { + printf("iw_point: Invalid Pointer/Length\n"); + return; + } + + if (!strncmp(data->pointer, "wmm_ie", strlen("wmm_ie"))) { + pHandle->ScanList[idx].Wmm = WCON_WMM_ENABLED; + } + + while (custom_cmd[i]) { + if (!strncmp(data->pointer, custom_cmd[i], + strlen(custom_cmd[i]))) { + pHandle->ScanList[idx].WpaAP = WCON_WPA_ENABLED; + break; + } + i++; + } + + printf("Wpa:\t %s\n", pHandle->ScanList[idx].WpaAP ? + "enabled" : "disabled"); + printf("Wmm:\t %s\n", pHandle->ScanList[idx].Wmm ? + "enabled" : "disabled"); +} +#endif + +/** + * @brief parse scan info + * @param pHandle A pointer to WCON_HANDLE + * @param buffer A pointer to scan result buffer + * @param length length of scan result buffer + * @return NA + */ +static void parse_scan_info(WCON_HANDLE *pHandle, u8 buffer[], s32 length) +{ + s32 len = 0; + s32 ap_index = -1; + s8 *mode[3] = {"auto", "ad-hoc", "infra"}; + struct iw_event iwe; + struct iw_point iwp; + + memset(pHandle->ScanList, 0, sizeof(pHandle->ScanList)); + pHandle->ApNum = 0; + + while (len + IW_EV_LCP_LEN < length) { + memcpy((s8 *)&iwe, buffer + len, sizeof(struct iw_event)); + if ((iwe.cmd == SIOCGIWESSID)||(iwe.cmd ==SIOCGIWENCODE)|| + (iwe.cmd ==IWEVCUSTOM)){ + if(we_version_compiled > 18) + memcpy((s8 *)&iwp, buffer + len + IW_EV_LCP_LEN - MRV_EV_POINT_OFF, + sizeof(struct iw_point)); + else + memcpy((s8 *)&iwp, buffer + len + IW_EV_LCP_LEN,sizeof(struct iw_point)); + iwp.pointer = buffer + len + IW_EV_POINT_LEN; + } + switch (iwe.cmd) { + case SIOCGIWAP: + ap_index++; + memcpy(pHandle->ScanList[ap_index].Bssid, + iwe.u.ap_addr.sa_data, ETH_ALEN); + printf("\nBSSID:\t %02X:%02X:%02X:%02X:%02X:%02X\n", + HWA_ARG(pHandle->ScanList[ap_index].Bssid)); + break; + + case SIOCGIWESSID: + if ((iwp.pointer) && (iwp.length)) { + memcpy(pHandle->ScanList[ap_index].Ssid.ssid, + (s8 *)iwp.pointer, + iwp.length); + pHandle->ScanList[ap_index].Ssid.ssid_len = + iwp.length; + } + printf("SSID:\t %s\n", + pHandle->ScanList[ap_index].Ssid.ssid); + break; + + case SIOCGIWENCODE: + if (!(iwp.flags & IW_ENCODE_DISABLED)) { + pHandle->ScanList[ap_index].Privacy = + WCON_ENC_ENABLED; + } + printf("Privacy: %s\n", + pHandle->ScanList[ap_index].Privacy ? + "enabled": "disabled"); + break; + + case SIOCGIWMODE: + pHandle->ScanList[ap_index].NetMode = iwe.u.mode; + printf("NetMode: %s\n", + mode[pHandle->ScanList[ap_index].NetMode]); + break; + +#if WIRELESS_EXT > 14 + case IWEVCUSTOM: + parse_custom_info(pHandle, &iwp, ap_index); + break; +#endif + + case IWEVQUAL: + pHandle->ScanList[ap_index].Rssi = iwe.u.qual.level; + printf("Quality: %d\n", + pHandle->ScanList[ap_index].Rssi); + break; + } + + len += iwe.len; + } + + pHandle->ApNum = ap_index + 1; + printf("\nNo of AP's = %d\n", pHandle->ApNum); + + return; +} + +/* + * @brief Process scan results + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_scan_results(int argc, char *argv[]) +{ + u8 buffer[IW_SCAN_MAX_DATA]; + struct iwreq iwr; + WCON_HANDLE mhandle, *pHandle = &mhandle; + + memset(pHandle, 0, sizeof(WCON_HANDLE)); + memset(&iwr, 0, sizeof(struct iwreq)); + + iwr.u.data.pointer = buffer; + iwr.u.data.length = sizeof(buffer); + strncpy(iwr.ifr_name, dev_name, IFNAMSIZ); + + if ((ioctl(sockfd, SIOCGIWSCAN, &iwr)) < 0) { + printf("Get Scan Results Failed\n"); + return -1; + } + + parse_scan_info(pHandle, buffer, iwr.u.data.length); + + return WLAN_STATUS_SUCCESS; +} + + +/** + * @brief Process read eeprom + * + * @param stroffset A pointer to the offset string + * @param strnob A pointer to NOB string + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_read_eeprom(s8 *stroffset, s8 *strnob) +{ + s8 buffer[MAX_EEPROM_DATA]; + struct ifreq userdata; + wlan_ioctl_regrdwr *reg = (wlan_ioctl_regrdwr *)buffer; + + memset(buffer, 0, sizeof(buffer)); + reg->WhichReg = REG_EEPROM; + reg->Action = 0; + + if (!strncasecmp(stroffset, "0x", 2)) + reg->Offset = a2hex((stroffset + 2)); + else + reg->Offset = atoi(stroffset); + + if (!strncasecmp(strnob, "0x", 2)) + reg->NOB = a2hex((strnob + 2)); + else + reg->NOB = atoi(strnob); + + if (reg->NOB > MAX_EEPROM_DATA) { + fprintf(stderr, "Number of bytes exceeds MAX EEPROM Read size\n"); + return WLAN_STATUS_FAILURE; + } + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = buffer; + + if (ioctl(sockfd, WLANREGRDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: EEPROM read not possible " + "by interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + + hexdump("RD EEPROM", ®->Value, reg->NOB, ' '); + + return WLAN_STATUS_SUCCESS; +} + +/* + * @brief Display usage + * + * @return NA + */ +static void display_usage(void) +{ + s32 i; + + for (i = 0; i < NELEMENTS(usage); i++) + fprintf(stderr, "%s\n", usage[i]); +} + +/* + * @brief Find command + * + * @param maxcmds max command number + * @param cmds A pointer to commands buffer + * @param cmd A pointer to command buffer + * @return index of command or WLAN_STATUS_FAILURE + */ +static int findcommand(s32 maxcmds, s8 *cmds[], s8 *cmd) +{ + s32 i; + + for (i = 0; i < maxcmds; i++) { + if (!strcasecmp(cmds[i], cmd)) { + return i; + } + } + + return WLAN_STATUS_FAILURE; +} + +/* + * @brief SD comand52 read + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_sdcmd52r(int argc, char *argv[]) +{ + struct ifreq userdata; + u8 buf[6]; + u32 tmp; + + buf[0] = 0; //CMD52 read + if (argc == 5) { + buf[1] = atoval(argv[3]); //func + tmp = atoval(argv[4]); //reg + buf[2] = tmp & 0xff; + buf[3] = (tmp >> 8) & 0xff; + buf[4] = (tmp >> 16) & 0xff; + buf[5] = (tmp >> 24) & 0xff; + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return WLAN_STATUS_FAILURE; + } + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = buf; + + if (ioctl(sockfd, WLANCMD52RDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: CMD52 R/W not supported by " + "interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + printf("sdcmd52r returns 0x%02X\n", buf[0]); + + return WLAN_STATUS_SUCCESS; +} + +/* + * @brief SD comand52 write + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_sdcmd52w(int argc, char *argv[]) +{ + struct ifreq userdata; + u8 buf[7]; + u32 tmp; + + buf[0] = 1; //CMD52 write + if (argc == 6) { + buf[1] = atoval(argv[3]); //func + tmp = atoval(argv[4]); //reg + buf[2] = tmp & 0xff; + buf[3] = (tmp >> 8) & 0xff; + buf[4] = (tmp >> 16) & 0xff; + buf[5] = (tmp >> 24) & 0xff; + buf[6] = atoval(argv[5]); //dat + } else { + fprintf(stderr, "Invalid number of parameters!\n"); + return WLAN_STATUS_FAILURE; + } + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = buf; + + if (ioctl(sockfd, WLANCMD52RDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: CMD52 R/W not supported by " + "interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + printf("sdcmd52w returns 0x%02X\n",buf[0]); + + return WLAN_STATUS_SUCCESS; +} + +/* + * @brief SD comand53 read + * + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static int process_sdcmd53r(void) +{ + struct ifreq userdata; + s8 buf[CMD53BUFLEN]; + int i; + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = buf; + + for(i=0; i < NELEMENTS(buf); i++) + buf[i] = i & 0xff; + + if (ioctl(sockfd, WLANCMD53RDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: CMD53 R/W not supported by " + "interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + + for(i=0; i < NELEMENTS(buf); i++) { + if (buf[i] != (i ^ 0xff)) + printf("i=%02X %02X\n",i,buf[i]); + } + + return WLAN_STATUS_SUCCESS; +} + + + +/* + * @brief Get one line from the File + * + * @param s Storage location for data. + * @param size Maximum number of characters to read. + * @param stream File stream + * @param line A pointer to return current line number + * @return returns string or NULL + */ +static s8 * wlan_config_get_line(s8 *s, s32 size, FILE *stream, int *line) +{ + s8 *pos, *end, *sstart; + + while (fgets(s, size, stream)) { + (*line)++; + s[size - 1] = '\0'; + pos = s; + + while (*pos == ' ' || *pos == '\t') + pos++; + if (*pos == '#' || (*pos == '\r' && *(pos+1) == '\n') || + *pos == '\n' || *pos == '\0') + continue; + + /* Remove # comments unless they are within a double quoted + * string. Remove trailing white space. */ + sstart = strchr(pos, '"'); + if (sstart) + sstart = strchr(sstart + 1, '"'); + if (!sstart) + sstart = pos; + end = strchr(sstart, '#'); + if (end) + *end-- = '\0'; + else + end = pos + strlen(pos) - 1; + while (end > pos && (*end == '\r' || *end == '\n' || + *end == ' ' || *end == '\t')) { + *end-- = '\0'; + } + if (*pos == '\0') + continue; + return pos; + } + + return NULL; +} + + + +/** + * @brief read register + * @param cmd the type of register + * @param stroffset A pointer to register index string + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int process_read_register(s32 cmd, s8 *stroffset) +{ + struct ifreq userdata; + wlan_ioctl_regrdwr reg; + s8 *whichreg; + + switch (cmd) { + case CMD_RDMAC: + /* + * HostCmd_CMD_MAC_REG_ACCESS + */ + reg.WhichReg = REG_MAC; + whichreg = "MAC"; + break; + case CMD_RDBBP: + /* + * HostCmd_CMD_BBP_REG_ACCESS + */ + reg.WhichReg = REG_BBP; + whichreg = "BBP"; + break; + case CMD_RDRF: + /* + * HostCmd_CMD_RF_REG_ACCESS + */ + reg.WhichReg = REG_RF; + whichreg = "RF"; + break; + default: + fprintf(stderr, + "Invalid Register set specified.\n"); + return -1; + } + + reg.Action = 0; /* READ */ + + if (!strncasecmp(stroffset, "0x", 2)) + reg.Offset = a2hex((stroffset + 2)); + else + reg.Offset = atoi(stroffset); + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = (s8 *) ® + + if (ioctl(sockfd, WLANREGRDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: Register Reading not supported by" + "interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + + printf("%s[0x%04lx] = 0x%08lx\n", + whichreg, reg.Offset, reg.Value); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief write register + * @param cmd the type of register + * @param stroffset A pointer to register index string + * @param strvalue A pointer to the register value + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int process_write_register(s32 cmd, s8 *stroffset, s8 *strvalue) +{ + struct ifreq userdata; + wlan_ioctl_regrdwr reg; + s8 *whichreg; + + switch (cmd) { + case CMD_WRMAC: + /* + * HostCmd_CMD_MAC_REG_ACCESS + */ + reg.WhichReg = REG_MAC; + whichreg = "MAC"; + break; + case CMD_WRBBP: + /* + * HostCmd_CMD_BBP_REG_ACCESS + */ + reg.WhichReg = REG_BBP; + whichreg = "BBP"; + break; + case CMD_WRRF: + /* + * HostCmd_CMD_RF_REG_ACCESS + */ + reg.WhichReg = REG_RF; + whichreg = "RF"; + break; + default: + fprintf(stderr, + "Invalid register set specified.\n"); + return -1; + } + + reg.Action = 1; /* WRITE */ + + if (!strncasecmp(stroffset, "0x", 2)) + reg.Offset = a2hex((stroffset + 2)); + else + reg.Offset = atoi(stroffset); + + if (!strncasecmp(strvalue, "0x", 2)) + reg.Value = a2hex((strvalue + 2)); + else + reg.Value = atoi(strvalue); + + printf("Writing %s Register 0x%04lx with 0x%08lx\n", whichreg, + reg.Offset, reg.Value); + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = (s8 *) ® + + if (ioctl(sockfd, WLANREGRDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: Register Writing not supported " + "by interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + + printf("%s[0x%04lx] = 0x%08lx\n", + whichreg, reg.Offset, reg.Value); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief read CF register + * + * @param stroffset A pointer to register index string + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int process_read_cfreg(s8 *stroffset) +{ + struct ifreq userdata; + wlan_ioctl_cfregrdwr reg; + + reg.Action = 0; //Read register + + if (!strncasecmp(stroffset, "0x", 2)) + reg.Offset = a2hex((stroffset + 2)); + else + reg.Offset = atoi(stroffset); + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = (s8 *) ® + + if (ioctl(sockfd, WLANREGCFRDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: Register reading not supported " + "by interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + + printf("CFREG[0x%04X] = 0x%04X\n", + reg.Offset, reg.Value); + + return WLAN_STATUS_SUCCESS; + +} + +/** + * @brief write CF register + * + * @param stroffset A pointer to register index string + * @param strvalue A pointer to the register value + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int process_write_cfreg(s8 *stroffset, s8 *strvalue) +{ + struct ifreq userdata; + wlan_ioctl_cfregrdwr reg; + + reg.Action = 1; //Write register + + if (!strncasecmp(stroffset, "0x", 2)) + reg.Offset = a2hex((stroffset + 2)); + else + reg.Offset = atoi(stroffset); + + if (!strncasecmp(strvalue, "0x", 2)) + reg.Value = a2hex((strvalue + 2)); + else + reg.Value = atoi(strvalue); + + strncpy(userdata.ifr_name, dev_name, IFNAMSIZ); + userdata.ifr_data = (s8 *) ® + + if (ioctl(sockfd, WLANREGCFRDWR, &userdata)) { + perror("wlanconfig"); + fprintf(stderr, + "wlanconfig: Register writing not supported " + "by interface %s\n", dev_name); + return WLAN_STATUS_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} + +/******************************************************** + Global Functions +********************************************************/ +/* + * @brief Entry function for wlanconfig + * @param argc number of arguments + * @param argv A pointer to arguments array + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int main(int argc, char *argv[]) +{ + s32 cmd; + + if (argc < 3) { + fprintf(stderr, "Invalid number of parameters!\n"); + display_usage(); + exit(1); + } + + strncpy(dev_name, argv[1], IFNAMSIZ); + + /* + * create a socket + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + fprintf(stderr, "wlanconfig: Cannot open socket.\n"); + exit(1); + } + if(get_range() < 0){ + fprintf(stderr, "wlanconfig: Cannot get range.\n"); + exit(1); + } + switch ((cmd = findcommand(NELEMENTS(commands), commands, argv[2]))) { + case CMD_HOSTCMD: + process_host_cmd(argc, argv); + break; + case CMD_RDMAC: + case CMD_RDBBP: + case CMD_RDRF: + if (argc < 4) { + fprintf(stderr, "Register offset required!\n"); + display_usage(); + exit(1); + } + + if (process_read_register(cmd, argv[3])) { + fprintf(stderr, "Read command failed!\n"); + exit(1); + } + break; + case CMD_WRMAC: + case CMD_WRBBP: + case CMD_WRRF: + if (argc < 5) { + fprintf(stderr, "Register offset required & value!\n"); + display_usage(); + exit(1); + } + if (process_write_register(cmd, argv[3], + argv[4])) { + fprintf(stderr, "Write command failed!\n"); + exit(1); + } + break; + case CMD_CMD52R: + process_sdcmd52r(argc,argv); + break; + case CMD_CMD52W: + process_sdcmd52w(argc,argv); + break; + case CMD_CMD53R: + process_sdcmd53r(); + break; + case CMD_CFREGR: + printf("process read cfreg\n"); + if (argc < 4) { + fprintf(stderr, "Register offset required!\n"); + display_usage(); + exit(1); + } + if (process_read_cfreg(argv[3])) { + fprintf(stderr, "Read CF register failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_CFREGW: + printf("process write cfreg\n"); + if (argc < 5) { + fprintf(stderr, "Register offset required!\n"); + display_usage(); + exit(1); + } + if (process_write_cfreg(argv[3], argv[4])) { + fprintf(stderr, "Read CF register failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_RDEEPROM: + printf("proces read eeprom\n"); + + if(argc < 5) { + fprintf(stderr, "Register offset, number of bytes required\n"); + display_usage(); + exit(1); + } + + if(process_read_eeprom(argv[3], argv[4])) { + fprintf(stderr, "EEPROM Read failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_GETRATE: + if (process_get_rate()) { + fprintf(stderr, "Get Rate Failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_SLEEPPARAMS: + if (process_sleep_params(argc, argv)) { + fprintf(stderr, "Sleep Params Failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_BCA_TS: + if (process_bca_ts(argc, argv)) { + fprintf(stderr, "SetBcaTs Failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_EXTSCAN: + if (process_extscan(argc, argv)) { + fprintf(stderr, "ExtScan Failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_SCAN_LIST: + if (process_scan_results(argc, argv)) { + fprintf(stderr, "getscanlist Failed\n"); + display_usage(); + exit(1); + } + break; + case CMD_GET_SCAN_RSP: + if (process_getscantable(argc, argv)) { + exit(1); + } + break; + + case CMD_SET_USER_SCAN: + if (process_setuserscan(argc, argv)) { + exit(1); + } + break; + + default: + fprintf(stderr, "Invalid command specified!\n"); + display_usage(); + exit(1); + } + + return WLAN_STATUS_SUCCESS; +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlanconfig/wlanconfig.h linux-2.6-libertas/drivers/net/wireless/libertas/wlanconfig/wlanconfig.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlanconfig/wlanconfig.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlanconfig/wlanconfig.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,82 @@ +/** @file wlan_config.h + * + * @brief This file contains definitions for application + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/**************************************************************** +Change log: + 09/26/05: add Doxygen format comments +****************************************************************/ + +#ifndef _WLANCONFIG_H_ +#define _WLANCONFIG_H_ + +#define NULLBSSID "\x00\x00\x00\x00\x00\x00" + +/* to create pointers to 6-byte hardware address */ +#define HWA_ARG(x) *(((u8 *)x + 0)), *(((u8 *)x + 1)), \ + *(((u8 *)x + 2)), *(((u8 *)x + 3)), \ + *(((u8 *)x + 4)), *(((u8 *)x + 5)) + +#define WCON_ENC_DISABLED 0 +#define WCON_ENC_ENABLED 1 + +#define WCON_WPA_DISABLED 0 +#define WCON_WPA_ENABLED 1 + +#define WCON_WMM_DISABLED 0 +#define WCON_WMM_ENABLED 1 + +/** struct of SSID network name */ +typedef struct _WCON_SSID { + /** SSID name length */ + u32 ssid_len; + /** SSID name string */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; +} WCON_SSID; + +typedef u8 WCON_BSSID[ETH_ALEN]; + +/** struct of SSID network information */ +typedef struct _WCON_NET_INFO { + /** SSID network name struct */ + WCON_SSID Ssid; + /** hardware address of the SSID network */ + WCON_BSSID Bssid; + /** rssi value */ + unsigned int Rssi; + /** network operating mode */ + int NetMode; + /** network privacy mode */ + int Privacy; + /** WPA enable */ + int WpaAP; + /** WMM enable */ + int Wmm; +} WCON_NET_INFO; + +/** struct of SSID list from scan */ +typedef struct _WCON_HANDLE { + /** list of scan result */ + WCON_NET_INFO ScanList[IW_MAX_AP]; + int ApNum; +} WCON_HANDLE; + +#endif /* _WLANCONFIG_H_ */ + diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_debugfs.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_debugfs.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_debugfs.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_debugfs.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,314 @@ + +#include <linux/module.h> +#include <linux/dcache.h> +#include <linux/debugfs.h> +#include "wlan_dev.h" +#include "wlan_decl.h" + +static struct dentry *libertas_dir = NULL; +static const int big_buffer_len = 4096; +static char big_buffer[4096]; +static DECLARE_MUTEX(big_buffer_sem); + +static char *szStates[] = { + "Connected", + "Disconnected" +}; + +void libertas_debug_init(wlan_private * priv, struct net_device *dev); + +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t write_file_dummy(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static ssize_t libertas_dev_info(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + wlan_private *priv = file->private_data; + size_t pos = 0; + const size_t len = big_buffer_len; + char *buf = big_buffer; + ssize_t res; + char fmt[64]; + + libertas_get_version(priv->adapter, fmt, sizeof(fmt) - 1); + down(&big_buffer_sem); + + pos += snprintf(buf+pos, len-pos, "libertas_driver_version = %s\n", fmt); + pos += snprintf(buf+pos, len-pos, "state=%s\n", + szStates[priv->adapter->MediaConnectStatus]); + pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", + (u32) priv->adapter->RegionCode); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + + up(&big_buffer_sem); + + return res; +} + +static struct file_operations libertas_devinfo_fops = { + .owner = THIS_MODULE, + .open = open_file_generic, + .write = write_file_dummy, + .read = libertas_dev_info, +}; + +void libertas_debugfs_init(void) +{ + if (!libertas_dir) { + libertas_dir = debugfs_create_dir("libertas_wireless", NULL); + if (!libertas_dir || IS_ERR(libertas_dir)) + libertas_dir = NULL; + } + return; +} + +void libertas_debugfs_remove(void) +{ + if (libertas_dir) + debugfs_remove(libertas_dir); + return; +} + +void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev) +{ + if (!libertas_dir) + goto exit; + + priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir); + if (!priv->debugfs_dir || IS_ERR(priv->debugfs_dir)) { + priv->debugfs_dir = NULL; + goto exit; + } + + priv->debugfs_devinfo = debugfs_create_file("info", 0444, + priv->debugfs_dir, + priv, + &libertas_devinfo_fops); + + if (!priv->debugfs_devinfo || IS_ERR(priv->debugfs_devinfo)) { + priv->debugfs_devinfo = NULL; + goto exit; + } +#ifdef PROC_DEBUG + libertas_debug_init(priv, dev); +#endif + +exit: + return; +} + +void libertas_debugfs_remove_one(wlan_private *priv) +{ +#ifdef PROC_DEBUG + debugfs_remove(priv->debugfs_debug); +#endif + debugfs_remove(priv->debugfs_devinfo); + debugfs_remove(priv->debugfs_dir); +} + +/* debug entry */ + +#define item_size(n) (sizeof ((wlan_adapter *)0)->n) +#define item_addr(n) ((u32) &((wlan_adapter *)0)->n) + +struct debug_data { + char name[32]; + u32 size; + u32 addr; +}; + +/* To debug any member of wlan_adapter, simply add one line here. + */ +static struct debug_data items[] = { + {"IntCounter", item_size(IntCounter), item_addr(IntCounter)}, + {"PSMode", item_size(PSMode), item_addr(PSMode)}, + {"PSState", item_size(PSState), item_addr(PSState)}, +}; + +static int num_of_items = sizeof(items) / sizeof(items[0]); + +/** + * @brief convert string to number + * + * @param s pointer to numbered string + * @return converted number from string s + */ +static int string_to_number(char *s) +{ + int r = 0; + int base = 0; + + if ((strncmp(s, "0x", 2) == 0) || (strncmp(s, "0X", 2) == 0)) + base = 16; + else + base = 10; + + if (base == 16) + s += 2; + + for (s = s; *s != 0; s++) { + if ((*s >= 48) && (*s <= 57)) + r = (r * base) + (*s - 48); + else if ((*s >= 65) && (*s <= 70)) + r = (r * base) + (*s - 55); + else if ((*s >= 97) && (*s <= 102)) + r = (r * base) + (*s - 87); + else + break; + } + + return r; +} + +/** + * @brief proc read function + * + * @param page pointer to buffer + * @param s read data starting position + * @param off offset + * @param cnt counter + * @param eof end of file flag + * @param data data to output + * @return number of output data + */ +static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + int val = 0; + size_t pos = 0; + ssize_t res; + char *p; + int i; + struct debug_data *d; + + down(&big_buffer_sem); + + p = big_buffer; + + d = (struct debug_data *)file->private_data; + + for (i = 0; i < num_of_items; i++) { + if (d[i].size == 1) + val = *((u8 *) d[i].addr); + else if (d[i].size == 2) + val = *((u16 *) d[i].addr); + else if (d[i].size == 4) + val = *((u32 *) d[i].addr); + + pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); + } + + res = simple_read_from_buffer(userbuf, count, ppos, p, pos); + + up(&big_buffer_sem); + + return res; +} + +/** + * @brief proc write function + * + * @param f file pointer + * @param buf pointer to data buffer + * @param cnt data number to write + * @param data data to write + * @return number of data + */ +static int wlan_debugfs_write(struct file *f, const char __user *buf, + size_t cnt, loff_t *ppos) +{ + int r, i; + char *pdata; + char *p; + char *p0; + char *p1; + char *p2; + struct debug_data *d = (struct debug_data *)f->private_data; + + pdata = (char *)kmalloc(cnt, GFP_KERNEL); + if (pdata == NULL) + return 0; + + if (copy_from_user(pdata, buf, cnt)) { + PRINTM(INFO, "Copy from user failed\n"); + return 0; + } + + p0 = pdata; + for (i = 0; i < num_of_items; i++) { + do { + p = strstr(p0, d[i].name); + if (p == NULL) + break; + p1 = strchr(p, '\n'); + if (p1 == NULL) + break; + p0 = p1++; + p2 = strchr(p, '='); + if (!p2) + break; + p2++; + r = string_to_number(p2); + if (d[i].size == 1) + *((u8 *) d[i].addr) = (u8) r; + else if (d[i].size == 2) + *((u16 *) d[i].addr) = (u16) r; + else if (d[i].size == 4) + *((u32 *) d[i].addr) = (u32) r; + break; + } while (1); + } + kfree(pdata); + + return cnt; +} + +static struct file_operations libertas_debug_fops = { + .owner = THIS_MODULE, + .open = open_file_generic, + .write = wlan_debugfs_write, + .read = wlan_debugfs_read, +}; + +/** + * @brief create debug proc file + * + * @param priv pointer wlan_private + * @param dev pointer net_device + * @return N/A + */ +void libertas_debug_init(wlan_private * priv, struct net_device *dev) +{ + int i; + + if (!priv->debugfs_dir) + return; + + for (i = 0; i < num_of_items; i++) + items[i].addr += (u32) priv->adapter; + + priv->debugfs_debug = debugfs_create_file("debug", 0644, + priv->debugfs_dir, &items[0], + &libertas_debug_fops); +} + +/** + * @brief remove proc file + * + * @param priv pointer wlan_private + * @return N/A + */ +void libertas_debug_remove(wlan_private * priv) +{ + debugfs_remove(priv->debugfs_debug); +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_debugfs.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_debugfs.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_debugfs.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_debugfs.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,6 @@ +void libertas_debugfs_init(void); +void libertas_debugfs_remove(void); + +void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev); +void libertas_debugfs_remove_one(wlan_private *priv); + diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_decl.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_decl.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_decl.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_decl.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,108 @@ +/** @file wlan_decl.h + * @brief This file contains declaration referring to + * functions defined in other source files + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/****************************************************** +Change log: + 09/29/05: add Doxygen format comments + 01/05/06: Add kernel 2.6.x support + 01/11/06: Change compile flag BULVERDE_SDIO to SD to support + Monahans/Zylonite + 01/11/06: Conditionalize new scan/join structures. + Move wlan_wext statics to their source file. +******************************************************/ + +#ifndef _WLAN_DECL_H_ +#define _WLAN_DECL_H_ + +#include "wlan_defs.h" + +/** Function Prototype Declaration */ +struct wlan_private; +struct sk_buff; +struct net_device; + +void libertas_free_adapter(wlan_private * priv); +int libertas_set_mac_packet_filter(wlan_private * priv); + +int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt); +void libertas_send_tx_feedback(wlan_private * priv); +u8 libertas_check_last_packet_indication(wlan_private * priv); + +int libertas_free_cmd_buffer(wlan_private * priv); +struct CmdCtrlNode; +struct CmdCtrlNode *libertas_get_free_cmd_ctrl_node(wlan_private * priv); + +void libertas_set_cmd_ctrl_node(wlan_private * priv, + struct CmdCtrlNode *pTempNode, + u32 cmd_oid, u16 wait_option, void *pdata_buf); + +int libertas_prepare_and_send_command(wlan_private * priv, + u16 cmd_no, + u16 cmd_action, + u16 wait_option, u32 cmd_oid, void *pdata_buf); + +void libertas_queue_cmd(wlan_adapter * Adapter, struct CmdCtrlNode *CmdNode, u8 addtail); + +int libertas_allocate_cmd_buffer(wlan_private * priv); +int libertas_execute_next_command(wlan_private * priv); +int libertas_process_event(wlan_private * priv); +void libertas_interrupt(struct net_device *); +int libertas_set_radio_control(wlan_private * priv); +u32 libertas_index_to_data_rate(u8 index); +u8 libertas_data_rate_to_index(u32 rate); +void libertas_get_version(wlan_adapter * adapter, char *version, int maxlen); + +int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); + +/** The proc fs interface */ +int libertas_process_rx_command(wlan_private * priv); +int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); +void libertas_cleanup_and_insert_cmd(wlan_private * priv, + struct CmdCtrlNode *pTempCmd); + +#ifdef REASSOCIATION +void libertas_reassoc_timer_fn(unsigned long data); +#endif /* REASSOCIATION */ + +struct iw_point; +struct iw_request_info; +int libertas_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra); +int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band); + +int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *); + +void libertas_ps_sleep(wlan_private * priv, int wait_option); +void libertas_ps_confirm_sleep(wlan_private * priv, u16 PSMode); +void libertas_ps_wakeup(wlan_private * priv, int wait_option); + +void libertas_tx_runqueue(wlan_private *priv); + +#define SDIO_HEADER_LEN 4 + +extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel( + wlan_adapter * adapter, u8 band, u16 channel); + +extern void libertas_mac_event_disconnected(wlan_private * priv); + +void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); + +#endif /* _WLAN_DECL_H_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_defs.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_defs.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_defs.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_defs.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,571 @@ +/** @file wlan_defs.h + * @brief This header file contains global constant/enum definitions, + * global variable declaration. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change log: + 10/11/05: add Doxygen format comments + 01/11/06: Change compile flag BULVERDE_SDIO to SD to support + Monahans/Zylonite + 01/11/06: Add NELEMENTS, BAND_XX defines + 04/10/06: Add hostcmd generic API and power_adapt_cfg_ext command +************************************************************/ + +#ifndef _WLAN_DEFS_H_ +#define _WLAN_DEFS_H_ + +#include <linux/spinlock.h> + +/** Double-Word(32Bit) Bit definition */ +#define DW_BIT_0 0x00000001 +#define DW_BIT_1 0x00000002 +#define DW_BIT_2 0x00000004 +#define DW_BIT_3 0x00000008 +#define DW_BIT_4 0x00000010 +#define DW_BIT_5 0x00000020 +#define DW_BIT_6 0x00000040 +#define DW_BIT_7 0x00000080 +#define DW_BIT_8 0x00000100 +#define DW_BIT_9 0x00000200 +#define DW_BIT_10 0x00000400 +#define DW_BIT_11 0x00000800 +#define DW_BIT_12 0x00001000 +#define DW_BIT_13 0x00002000 +#define DW_BIT_14 0x00004000 +#define DW_BIT_15 0x00008000 +#define DW_BIT_16 0x00010000 +#define DW_BIT_17 0x00020000 +#define DW_BIT_18 0x00040000 +#define DW_BIT_19 0x00080000 +#define DW_BIT_20 0x00100000 +#define DW_BIT_21 0x00200000 +#define DW_BIT_22 0x00400000 +#define DW_BIT_23 0x00800000 +#define DW_BIT_24 0x01000000 +#define DW_BIT_25 0x02000000 +#define DW_BIT_26 0x04000000 +#define DW_BIT_27 0x08000000 +#define DW_BIT_28 0x10000000 +#define DW_BIT_29 0x20000000 +#define DW_BIT_30 0x40000000 +#define DW_BIT_31 0x80000000 + +/** Word (16bit) Bit Definition*/ +#define W_BIT_0 0x0001 +#define W_BIT_1 0x0002 +#define W_BIT_2 0x0004 +#define W_BIT_3 0x0008 +#define W_BIT_4 0x0010 +#define W_BIT_5 0x0020 +#define W_BIT_6 0x0040 +#define W_BIT_7 0x0080 +#define W_BIT_8 0x0100 +#define W_BIT_9 0x0200 +#define W_BIT_10 0x0400 +#define W_BIT_11 0x0800 +#define W_BIT_12 0x1000 +#define W_BIT_13 0x2000 +#define W_BIT_14 0x4000 +#define W_BIT_15 0x8000 + +/** Byte (8Bit) Bit definition*/ +#define B_BIT_0 0x01 +#define B_BIT_1 0x02 +#define B_BIT_2 0x04 +#define B_BIT_3 0x08 +#define B_BIT_4 0x10 +#define B_BIT_5 0x20 +#define B_BIT_6 0x40 +#define B_BIT_7 0x80 + +/** Debug Macro definition*/ +#ifdef DEBUG_LEVEL4 +#define PRINTM_INFO(msg...) printk(KERN_DEBUG msg) +#ifndef DEBUG_LEVEL3 +#define DEBUG_LEVEL3 +#endif +#else +#define PRINTM_INFO(msg...) +#endif + +#ifdef DEBUG_LEVEL3 +#define PRINTM_WARN(msg...) printk(KERN_DEBUG msg) +#ifndef DEBUG_LEVEL2 +#define DEBUG_LEVEL2 +#endif +#else +#define PRINTM_WARN(msg...) +#endif + +#ifdef DEBUG_LEVEL2 +#define PRINTM_FATAL(msg...) printk(KERN_DEBUG msg) +#ifndef DEBUG_LEVEL1 +#define DEBUG_LEVEL1 +#endif +#else +#define PRINTM_FATAL(msg...) +#endif + +#ifdef DEBUG_LEVEL1 +#define PRINTM_MSG(msg...) printk(KERN_ALERT msg) +#else +#define PRINTM_MSG(msg...) +#endif + +#define PRINTM(level,msg...) PRINTM_##level(msg) + +#define ASSERT(cond) \ +do { \ + if (!(cond)) \ + PRINTM(INFO, "ASSERT: %s, %s:%i\n", \ + __FUNCTION__, __FILE__, __LINE__); \ +} while(0) +#define ENTER() PRINTM(INFO, "Enter: %s, %s:%i\n", __FUNCTION__, \ + __FILE__, __LINE__) +#define LEAVE() PRINTM(INFO, "Leave: %s, %s:%i\n", __FUNCTION__, \ + __FILE__, __LINE__) + +#if defined(DEBUG_LEVEL4) && defined(__KERNEL__) +static inline void HEXDUMP(char *prompt, u8 * buf, int len) +{ + int i = 0; + + printk(KERN_DEBUG "%s: ", prompt); + for (i = 1; i <= len; i++) { + printk("%02x ", (u8) * buf); + buf++; + } + printk("\n"); +} +#else +#define HEXDUMP(x,y,z) +#endif + +#ifndef NELEMENTS +#define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) +#endif + +/** Buffer Constants */ + +/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical +* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas +* driver has more local TxPDs. Each TxPD on the host memory is associated +* with a Tx control node. The driver maintains 8 RxPD descriptors for +* station firmware to store Rx packet information. +* +* Current version of MAC has a 32x6 multicast address buffer. +* +* 802.11b can have up to 14 channels, the driver keeps the +* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. +*/ + +#define MRVDRV_SIZE_OF_PPA 0x00000008 +#define MRVDRV_SIZE_OF_DPA 0x00000008 +#define MRVDRV_NUM_OF_TxPD 0x00000020 +#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 +#define MRVDRV_NUM_OF_CMD_BUFFER 10 +#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) +#define MRVDRV_MAX_CHANNEL_SIZE 14 +#define MRVDRV_MAX_BSSID_LIST 64 +#define MRVDRV_ASSOCIATION_TIME_OUT 255 +#define MRVDRV_SNAP_HEADER_LEN 8 + +#define WLAN_UPLD_SIZE 2312 +#define DEV_NAME_LEN 32 + +/** Misc constants */ +/* This section defines 802.11 specific contants */ + +#define MRVDRV_MAX_SSID_LENGTH 32 +#define MRVDRV_MAX_BSS_DESCRIPTS 16 +#define MRVDRV_MAX_REGION_CODE 6 + +#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe +#define MRVDRV_MIN_MULTIPLE_DTIM 1 +#define MRVDRV_MAX_MULTIPLE_DTIM 5 +#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1 + +#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10 +#define MRVDRV_DEFAULT_LOCAL_LISTEN_INTERVAL 0 + +#define MRVDRV_CHANNELS_PER_SCAN 4 +#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 + +#define MRVDRV_CHANNELS_PER_ACTIVE_SCAN 14 + +#define MRVDRV_DEBUG_RX_PATH 0x00000001 +#define MRVDRV_DEBUG_TX_PATH 0x00000002 + +#define MRVDRV_MIN_BEACON_INTERVAL 20 +#define MRVDRV_MAX_BEACON_INTERVAL 1000 +#define MRVDRV_BEACON_INTERVAL 100 + +/** TxPD Status */ + +/* Station firmware use TxPD status field to report final Tx transmit +* result, Bit masks are used to present combined situations. +*/ + +#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 +#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 + +/** Tx control node status */ + +#define MRVDRV_TX_CTRL_NODE_STATUS_IDLE 0x0000 + +/** RxPD Status */ + +#define MRVDRV_RXPD_STATUS_OK 0x0001 +#define MRVDRV_RXPD_STATUS_MULTICAST_RX 0x0002 + +/** RxPD Status - Received packet types */ + +#define MRVDRV_RXPD_STATUS_MAXTYPES_RX 6 + +/* Link spped */ +#define MRVDRV_LINK_SPEED_1mbps 10000 /* in unit of 100bps */ +#define MRVDRV_LINK_SPEED_11mbps 110000 + +/** RSSI-related defines */ +/* RSSI constants are used to implement 802.11 RSSI threshold +* indication. if the Rx packet signal got too weak for 5 consecutive +* times, miniport driver (driver) will report this event to wrapper +*/ + +#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) + +/** RTS/FRAG related defines */ +#define MRVDRV_RTS_MIN_VALUE 0 +#define MRVDRV_RTS_MAX_VALUE 2347 +#define MRVDRV_FRAG_MIN_VALUE 256 +#define MRVDRV_FRAG_MAX_VALUE 2346 + +/* Fixed IE size is 8 bytes time stamp + 2 bytes beacon interval + + * 2 bytes cap */ +#define MRVL_FIXED_IE_SIZE 12 + +/* This is for firmware specific length */ +#define EXTRA_LEN 36 + +#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct TxPD) + EXTRA_LEN) + +#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ + (ETH_FRAME_LEN + sizeof(struct RxPD) \ + + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) + +#define CMD_F_HOSTCMD (1 << 0) + +/** WEP list macros & data structures */ +#define MRVL_KEY_BUFFER_SIZE_IN_BYTE 16 + +/* to resolve CISCO AP extension */ +#define MRVDRV_SCAN_LIST_VAR_IE_SPACE 256 +#define FW_IS_WPA_ENABLED(_adapter) \ + (_adapter->fwCapInfo & FW_CAPINFO_WPA) + +#define FW_CAPINFO_WPA (1 << 0) +#define WLAN_802_11_AI_REQFI_CAPABILITIES 1 +#define WLAN_802_11_AI_REQFI_LISTENINTERVAL 2 +#define WLAN_802_11_AI_REQFI_CURRENTAPADDRESS 4 + +#define WLAN_802_11_AI_RESFI_CAPABILITIES 1 +#define WLAN_802_11_AI_RESFI_STATUSCODE 2 +#define WLAN_802_11_AI_RESFI_ASSOCIATIONID 4 + +/** WPA Key LENGTH*/ +/* Support 4 keys per key set */ +#define MRVL_NUM_WPA_KEY_PER_SET 4 +#define MRVL_MAX_WPA_KEY_LENGTH 32 +#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32 + +#define WPA_AES_KEY_LEN 16 +#define WPA_TKIP_KEY_LEN 32 + +/* A few details needed for WEP (Wireless Equivalent Privacy) */ +/* 104 bits */ +#define MAX_WEP_KEY_SIZE 13 +/*40 bits RC4 - WEP*/ +#define MIN_WEP_KEY_SIZE 5 + +#define RF_ANTENNA_1 0x1 +#define RF_ANTENNA_2 0x2 +#define RF_ANTENNA_AUTO 0xFFFF + +#define HOSTCMD_SUPPORTED_RATES G_SUPPORTED_RATES + +#define BAND_B (0x01) +#define BAND_G (0x02) +#define ALL_802_11_BANDS (BAND_B | BAND_G) + +#define KEY_INFO_ENABLED 0x01 + +/* For Wireless Extensions */ +#define OID_MRVL_MFG_COMMAND 1 + +#define SNR_BEACON 0 +#define SNR_RXPD 1 +#define NF_BEACON 2 +#define NF_RXPD 3 + +/** MACRO DEFINITIONS */ +#define CAL_NF(NF) ((s32)(-(s32)(NF))) +#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF))) +#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) + +#define DEFAULT_BCN_AVG_FACTOR 8 +#define DEFAULT_DATA_AVG_FACTOR 8 +#define AVG_SCALE 100 +#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \ + (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \ + ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ + AVG_SCALE)) / N)) + +#define WLAN_STATUS_SUCCESS (0) +#define WLAN_STATUS_FAILURE (-1) +#define WLAN_STATUS_NOT_ACCEPTED (-2) + +#define B_SUPPORTED_RATES 8 +#define G_SUPPORTED_RATES 14 + +#define WLAN_SUPPORTED_RATES 14 +#define WLAN_MAX_SSID_LENGTH 32 + +#define MAX_LEDS 8 + +/* S_SWAP : To swap 2 u8 */ +#define S_SWAP(a,b) do { \ + u8 t = SArr[a]; \ + SArr[a] = SArr[b]; SArr[b] = t; \ + } while(0) + +/* SWAP: swap u8 */ +#define SWAP_U8(a,b) {u8 t; t=a; a=b; b=t;} + +/* SWAP: swap u8 */ +#define SWAP_U16(a,b) {u16 t; t=a; a=b; b=t;} + +#define wlan_le16_to_cpu(x) x +#define wlan_le32_to_cpu(x) x +#define wlan_le64_to_cpu(x) x +#define wlan_cpu_to_le16(x) x +#define wlan_cpu_to_le32(x) x +#define wlan_cpu_to_le64(x) x + +/** Global Varibale Declaration */ +typedef struct _wlan_private wlan_private; +typedef struct _wlan_adapter wlan_adapter; + +extern spinlock_t libertas_driver_lock; +extern const char libertas_driver_version[]; +extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; + +extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES]; + +extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; + +extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES]; + +extern u8 libertas_adhoc_rates_b[4]; + +/** ENUM definition*/ +/** SNRNF_TYPE */ +enum SNRNF_TYPE { + TYPE_BEACON = 0, + TYPE_RXPD, + MAX_TYPE_B +}; + +/** SNRNF_DATA*/ +enum SNRNF_DATA { + TYPE_NOAVG = 0, + TYPE_AVG, + MAX_TYPE_AVG +}; + +/** WLAN_802_11_AUTH_ALG*/ +enum WLAN_802_11_AUTH_ALG { + AUTH_ALG_OPEN_SYSTEM = 1, + AUTH_ALG_SHARED_KEY = 2, + AUTH_ALG_NETWORK_EAP = 8, +}; + +/** WLAN_802_1X_AUTH_ALG */ +enum WLAN_802_1X_AUTH_ALG { + WLAN_1X_AUTH_ALG_NONE = 1, + WLAN_1X_AUTH_ALG_LEAP = 2, + WLAN_1X_AUTH_ALG_TLS = 4, + WLAN_1X_AUTH_ALG_TTLS = 8, + WLAN_1X_AUTH_ALG_MD5 = 16, +}; + +/** WLAN_802_11_ENCRYPTION_MODE */ +enum WLAN_802_11_ENCRYPTION_MODE { + CIPHER_NONE, + CIPHER_WEP40, + CIPHER_TKIP, + CIPHER_CCMP, + CIPHER_WEP104, +}; + +/** WLAN_802_11_POWER_MODE */ +enum WLAN_802_11_POWER_MODE { + Wlan802_11PowerModeCAM, + Wlan802_11PowerModeMAX_PSP, + Wlan802_11PowerModeFast_PSP, + + /*not a real mode, defined as an upper bound */ + Wlan802_11PowerModeMax +}; + +/** PS_STATE */ +enum PS_STATE { + PS_STATE_FULL_POWER, + PS_STATE_AWAKE, + PS_STATE_PRE_SLEEP, + PS_STATE_SLEEP +}; + +/** DNLD_STATE */ +enum DNLD_STATE { + DNLD_RES_RECEIVED, + DNLD_DATA_SENT, + DNLD_CMD_SENT +}; + +/** WLAN_MEDIA_STATE */ +enum WLAN_MEDIA_STATE { + WlanMediaStateConnected, + WlanMediaStateDisconnected +}; + +/** WLAN_802_11_PRIVACY_FILTER */ +enum WLAN_802_11_PRIVACY_FILTER { + Wlan802_11PrivFilterAcceptAll, + Wlan802_11PrivFilter8021xWEP +}; + +/** mv_ms_type */ +enum mv_ms_type { + MVMS_DAT = 0, + MVMS_CMD = 1, + MVMS_TXDONE = 2, + MVMS_EVENT +}; + +/* Hardware status codes (OID_GEN_HARDWARE_STATUS). */ +/** WLAN_HARDWARE_STATUS */ +enum WLAN_HARDWARE_STATUS { + WlanHardwareStatusReady, + WlanHardwareStatusInitializing, + WlanHardwareStatusReset, + WlanHardwareStatusClosing, + WlanHardwareStatusNotReady +}; + +/** WLAN_802_11_NETWORK_TYPE */ +enum WLAN_802_11_NETWORK_TYPE { + Wlan802_11FH, + Wlan802_11DS, + /*defined as upper bound */ + Wlan802_11NetworkTypeMax +}; + +/** WLAN_802_11_NETWORK_INFRASTRUCTURE */ +enum WLAN_802_11_NETWORK_INFRASTRUCTURE { + Wlan802_11IBSS, + Wlan802_11Infrastructure, + Wlan802_11AutoUnknown, + /*defined as upper bound */ + Wlan802_11InfrastructureMax +}; + +/** WLAN_802_11_AUTHENTICATION_MODE */ +enum WLAN_802_11_AUTHENTICATION_MODE { + Wlan802_11AuthModeOpen = 0x00, + Wlan802_11AuthModeShared = 0x01, + Wlan802_11AuthModeNetworkEAP = 0x80, +}; + +/** WLAN_802_11_WEP_STATUS */ +enum WLAN_802_11_WEP_STATUS { + Wlan802_11WEPEnabled, + Wlan802_11WEPDisabled, + Wlan802_11WEPKeyAbsent, + Wlan802_11WEPNotSupported, Wlan802_11Encryption2Enabled, + Wlan802_11Encryption2KeyAbsent, + Wlan802_11Encryption3Enabled, + Wlan802_11Encryption3KeyAbsent +}; + +/** SNMP_MIB_INDEX_e */ +enum SNMP_MIB_INDEX_e { + DesiredBssType_i = 0, + OpRateSet_i, + BcnPeriod_i, + DtimPeriod_i, + AssocRspTimeOut_i, + RtsThresh_i, + ShortRetryLim_i, + LongRetryLim_i, + FragThresh_i, + Dot11D_i, + Dot11H_i, + ManufId_i, + ProdId_i, + ManufOui_i, + ManufName_i, + ManufProdName_i, + ManufProdVer_i +}; + +/** KEY_TYPE_ID */ +enum KEY_TYPE_ID { + KEY_TYPE_ID_WEP = 0, + KEY_TYPE_ID_TKIP, + KEY_TYPE_ID_AES +}; + +/** KEY_INFO_WEP*/ +enum KEY_INFO_WEP { + KEY_INFO_WEP_DEFAULT_KEY = 0x01 +}; + +/** KEY_INFO_TKIP */ +enum KEY_INFO_TKIP { + KEY_INFO_TKIP_MCAST = 0x01, + KEY_INFO_TKIP_UNICAST = 0x02, + KEY_INFO_TKIP_ENABLED = 0x04 +}; + +/** KEY_INFO_AES*/ +enum KEY_INFO_AES { + KEY_INFO_AES_MCAST = 0x01, + KEY_INFO_AES_UNICAST = 0x02, + KEY_INFO_AES_ENABLED = 0x04 +}; + +/** SNMP_MIB_VALUE_e */ +enum SNMP_MIB_VALUE_e { + SNMP_MIB_VALUE_INFRA = 1, + SNMP_MIB_VALUE_ADHOC +}; + +#endif /* _WLAN_DEFS_H_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_dev.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_dev.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_dev.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_dev.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,412 @@ +/** @file wlan_dev.h + * @brief This file contains definitions and data structures specific + * to Marvell 802.11 NIC. It contains the Device Information + * structure wlan_adapter. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change log: + 09/26/05: add Doxygen format comments + 01/11/06: Conditionalize new scan/join structures. + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API + 05/08/06: Remove PermanentAddr from Adapter + + ************************************************************/ + +#ifndef _WLAN_DEV_H_ +#define _WLAN_DEV_H_ + +#include <linux/netdevice.h> +#include <linux/wireless.h> + +#include "wlan_defs.h" +#include "wlan_scan.h" +#include "wlan_thread.h" + +#define MAX_BSSID_PER_CHANNEL 16 + +#define NR_TX_QUEUE 3 + +/* For the extended Scan */ +#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \ + MRVDRV_MAX_CHANNEL_SIZE + 1 + +#if 0 +typedef struct _PER_CHANNEL_BSSID_LIST_DATA { + u8 ucStart; + u8 ucNumEntry; +} PER_CHANNEL_BSSID_LIST_DATA, *PPER_CHANNEL_BSSID_LIST_DATA; + +typedef struct _MRV_BSSID_IE_LIST { + struct WLAN_802_11_FIXED_IEs FixedIE; + u8 VariableIE[MRVDRV_SCAN_LIST_VAR_IE_SPACE]; +} MRV_BSSID_IE_LIST, *PMRV_BSSID_IE_LIST; +#endif + +#define MAX_REGION_CHANNEL_NUM 2 + +/** Chan-Freq-TxPower mapping table*/ +struct chan_freq_power { + /** Channel Number */ + u16 Channel; + /** Frequency of this Channel */ + u32 Freq; + /** Max allowed Tx power level */ + u16 MaxTxPower; + /** TRUE:channel unsupported; FLASE:supported*/ + u8 Unsupported; +}; + +/** region-band mapping table*/ +struct region_channel { + /** TRUE if this entry is valid */ + u8 Valid; + /** Region code for US, Japan ... */ + u8 Region; + /** Band B/G/A, used for BAND_CONFIG cmd */ + u8 Band; + /** Actual No. of elements in the array below */ + u8 NrCFP; + /** chan-freq-txpower mapping table*/ + struct chan_freq_power *CFP; +}; + +struct wlan_802_11_security { + u8 WPAEnabled; + u8 WPA2Enabled; + enum WLAN_802_11_WEP_STATUS WEPStatus; + enum WLAN_802_11_AUTHENTICATION_MODE AuthenticationMode; + enum WLAN_802_1X_AUTH_ALG Auth1XAlg; + enum WLAN_802_11_ENCRYPTION_MODE EncryptionMode; +}; + +/** Current Basic Service Set State Structure */ +struct current_bss_params { + struct bss_descriptor BSSDescriptor; + /** bssid */ + u8 bssid[ETH_ALEN]; + /** ssid */ + struct WLAN_802_11_SSID ssid; + + /** band */ + u8 band; + /** channel */ + u8 channel; + /** number of rates supported */ + int NumOfRates; + /** supported rates*/ + u8 DataRates[WLAN_SUPPORTED_RATES]; +}; + +/** sleep_params */ +struct sleep_params { + u16 sp_error; + u16 sp_offset; + u16 sp_stabletime; + u8 sp_calcontrol; + u8 sp_extsleepclk; + u16 sp_reserved; +}; + +/** sleep_period */ +struct sleep_period { + u16 period; + u16 reserved; +}; + +/** Data structure for the Marvell WLAN device */ +typedef struct _wlan_dev { + /** device name */ + char name[DEV_NAME_LEN]; + /** card pointer */ + void *card; + /** IO port */ + u32 ioport; + /** Upload received */ + u32 upld_rcv; + /** Upload type */ + u32 upld_typ; + /** Upload length */ + u32 upld_len; + /** netdev pointer */ + struct net_device *netdev; + /* Upload buffer */ + u8 upld_buf[WLAN_UPLD_SIZE]; + /* Download sent: + bit0 1/0=data_sent/data_tx_done, + bit1 1/0=cmd_sent/cmd_tx_done, + all other bits reserved 0 */ + u8 dnld_sent; +} wlan_dev_t, *pwlan_dev_t; + +/** Private structure for the MV device */ +struct _wlan_private { + int open; + + wlan_adapter *adapter; + wlan_dev_t wlan_dev; + + struct net_device_stats stats; + + struct iw_statistics wstats; + struct dentry *debugfs_dir; + struct dentry *debugfs_devinfo; + struct dentry *debugfs_debug; + const struct firmware *firmware; + struct device *hotplug_device; + + /** thread to service interrupts */ + struct wlan_thread MainThread; + +#ifdef REASSOCIATION + /** thread to service mac events */ + struct wlan_thread ReassocThread; +#endif /* REASSOCIATION */ +}; + +/** Wlan Adapter data structure*/ +struct _wlan_adapter { + /** STATUS variables */ + enum WLAN_HARDWARE_STATUS HardwareStatus; + u32 FWReleaseNumber; + u32 fwCapInfo; + + u8 TmpTxBuf[WLAN_UPLD_SIZE]; + u8 chip_rev; + + /** Command-related variables */ + u16 SeqNum; + struct CmdCtrlNode *CmdArray; + /** Current Command */ + struct CmdCtrlNode *CurCmd; + int CurCmdRetCode; + + /** Command Queues */ + /** Free command buffers */ + struct list_head CmdFreeQ; + /** Pending command buffers */ + struct list_head CmdPendingQ; + + /** Variables brought in from private structure */ + int irq; + + /** Async and Sync Event variables */ + u32 IntCounter; + u32 IntCounterSaved; /* save int for DS/PS */ + u32 EventCause; + u8 nodeName[16]; /* nickname */ + + /** spin locks */ + spinlock_t QueueSpinLock; + + /** Timers */ + struct timer_list command_timer; + +#ifdef REASSOCIATION + /**Reassociation timer*/ + struct timer_list reassoc_timer; +#endif /* REASSOCIATION */ + + /* TX queue used in PS mode */ + spinlock_t txqueue_lock; + struct sk_buff *tx_queue_ps[NR_TX_QUEUE]; + unsigned int tx_queue_idx; + + /** Event Queues */ + wait_queue_head_t ds_awake_q; + + u8 HisRegCpy; + + /** current ssid/bssid related parameters*/ + struct current_bss_params CurBssParams; + + enum WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + + struct bss_descriptor *pAttemptedBSSDesc; + + struct WLAN_802_11_SSID AttemptedSSIDBeforeScan; + struct WLAN_802_11_SSID PreviousSSID; + u8 PreviousBSSID[ETH_ALEN]; + + struct bss_descriptor *ScanTable; + u32 NumInScanTable; + + u8 ScanType; + u32 ScanMode; + + u16 BeaconPeriod; + u8 AdhocCreate; + + /** Capability Info used in Association, start, join */ + struct IEEEtypes_CapInfo capInfo; + +#ifdef REASSOCIATION + /** Reassociation on and off */ + u8 Reassoc_on; + struct semaphore ReassocSem; +#endif /* REASSOCIATION */ + + u8 ATIMEnabled; + + /** MAC address information */ + u8 CurrentAddr[ETH_ALEN]; + u8 MulticastList[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; + u32 NumOfMulticastMACAddr; + + /** 802.11 statistics */ + struct HostCmd_DS_802_11_GET_STAT wlan802_11Stat; + + u8 AdHocCreated; + u8 AdHocFailed; + + u16 EnableHwAuto; + u16 RateBitmap; + /** control G Rates */ + u8 adhoc_grate_enabled; + + u32 TxAntenna; + u32 RxAntenna; + + u8 AdhocChannel; + u32 FragThsd; + u32 RTSThsd; + + u32 DataRate; + u8 Is_DataRate_Auto; + + /** number of association attempts for the current SSID cmd */ + u32 m_NumAssociationAttemp; + u16 ListenInterval; + u16 Prescan; + u8 TxRetryCount; + + /** Tx-related variables (for single packet tx) */ + struct sk_buff *CurrentTxSkb; + u16 TxLockFlag; + u16 gen_null_pkg; + + /** NIC Operation characteristics */ + u32 LinkSpeed; + u16 CurrentPacketFilter; + u32 MediaConnectStatus; + u16 RegionCode; + u16 RegionTableIndex; + u16 TxPowerLevel; + + /** POWER MANAGEMENT AND PnP SUPPORT */ + u8 SurpriseRemoved; + u16 AtimWindow; + + u16 PSMode; /* Wlan802_11PowerModeCAM=disable + Wlan802_11PowerModeMAX_PSP=enable */ + u16 MultipleDtim; + u32 PSState; + u8 NeedToWakeup; + + struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; + u16 LocalListenInterval; + u16 NullPktInterval; + + /** Encryption parameter */ + struct wlan_802_11_security SecInfo; + + struct MRVL_WEP_KEY WepKey[4]; + u16 CurrentWepKeyIndex; + enum WLAN_802_11_WEP_STATUS EncryptionStatus; + + u8 IsGTK_SET; + + /** Encryption Key*/ + u8 Wpa_ie[256]; + u8 Wpa_ie_len; + + struct MRVL_WPA_KEY WpaPwkKey, WpaGrpKey; + + struct HostCmd_DS_802_11_KEY_MATERIAL aeskey; + + /* Advanced Encryption Standard */ + + u16 RxAntennaMode; + u16 TxAntennaMode; + + /** Requested Signal Strength*/ + u16 bcn_avg_factor; + u16 data_avg_factor; + u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; + u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; + u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; + u8 rawSNR[DEFAULT_DATA_AVG_FACTOR]; + u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; + u16 nextSNRNF; + u16 numSNRNF; + u32 RxPDSNRAge; + u16 RxPDRate; + + u8 RadioOn; + u32 Preamble; + + /** Multi Bands Parameter*/ + u8 libertas_supported_rates[G_SUPPORTED_RATES]; + + /** Blue Tooth Co-existence Arbitration */ + + /** sleep_params */ + struct sleep_params sp; + + /** sleep_period (Enhanced Power Save) */ + struct sleep_period sleep_period; + + /** RF calibration data */ + +#define MAX_REGION_CHANNEL_NUM 2 + /** Region Channel data */ + struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; + + struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; + + /** 11D and Domain Regulatory Data */ + struct wlan_802_11d_domain_reg DomainReg; + struct parsed_region_chan_11d parsed_region_chan; + + /** FSM variable for 11d support */ + struct wlan_802_11d_state State11D; + + /** MISCELLANEOUS */ + /* Card Information Structure */ + u8 CisInfoBuf[512]; + u16 CisInfoLen; + u8 *pRdeeprom; + struct wlan_offset_value OffsetValue; + + wait_queue_head_t cmd_get_log; + + struct HostCmd_DS_802_11_GET_LOG LogMsg; + u16 ScanProbes; + + u32 PktTxCtrl; + + u16 TxRate; + u32 linkmode; + u32 radiomode; + u32 debugmode; + u8 fw_ready; +}; + +#endif /* _WLAN_DEV_H_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_fw.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_fw.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_fw.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_fw.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,442 @@ +/** @file wlan_fw.c + * @brief This file contains the initialization for FW and HW + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 09/28/05: Add Doxygen format comments + 01/05/06: Add kernel 2.6.x support + 01/11/06: Conditionalize new scan/join functions. + Cleanup association response handler initialization. + 01/06/05: Add FW file read + 05/08/06: Remove the 2nd GET_HW_SPEC command and TempAddr/PermanentAddr + +********************************************************/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/config.h> + +#include <linux/vmalloc.h> +#include <linux/firmware.h> +#include <linux/version.h> + +#include "host.h" +#include "sbi.h" +#include "wlan_defs.h" +#include "wlan_decl.h" +#include "wlan_dev.h" +#include "wlan_fw.h" +#include "wlan_wext.h" + +char *libertas_fw_name = NULL; + +module_param_named(fw_name, libertas_fw_name, charp, 0644); + +/** + * @brief This function downloads firmware image, gets + * HW spec from firmware and set basic parameters to + * firmware. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_setup_station_hw(wlan_private * priv) +{ + int ret = WLAN_STATUS_FAILURE; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + libertas_sbi_disable_host_int(priv); + + if ((ret = request_firmware(&priv->firmware, libertas_fw_name, + priv->hotplug_device)) < 0) { + PRINTM(MSG, "request_firmware() failed, error code = %#x\n", + ret); + PRINTM(MSG, "%s not found in /lib/firmware\n", libertas_fw_name); + goto done; + } + + ret = libertas_sbi_prog_firmware(priv); + + release_firmware(priv->firmware); + + if (ret) { + PRINTM(INFO, "Bootloader in invalid state!\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + /* check if the fimware is downloaded successfully or not */ + if (libertas_sbi_verify_fw_download(priv)) { + PRINTM(INFO, "Firmware failed to be active in time!\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } +#define RF_REG_OFFSET 0x07 +#define RF_REG_VALUE 0xc8 + + libertas_sbi_enable_host_int(priv); + + /* + * Read MAC address from HW + */ + memset(adapter->CurrentAddr, 0xff, ETH_ALEN); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_GET_HW_SPEC, + 0, HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + libertas_set_mac_packet_filter(priv); + + /* Get the supported Data Rates */ + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_DATA_RATE, + HostCmd_ACT_GET_TX_RATE, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + ret = WLAN_STATUS_SUCCESS; +done: + LEAVE(); + + return (ret); +} + +/** + * @brief This function allocates buffer for the member of adapter + * structure like command buffer and BSSID list. + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_allocate_adapter(wlan_private * priv) +{ + u32 ulBufSize; + wlan_adapter *Adapter = priv->adapter; + + struct bss_descriptor *pTempScanTable; + + /* Allocate buffer to store the BSSID list */ + ulBufSize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST; + if (!(pTempScanTable = kmalloc(ulBufSize, GFP_KERNEL))) { + libertas_free_adapter(priv); + return WLAN_STATUS_FAILURE; + } + + Adapter->ScanTable = pTempScanTable; + memset(Adapter->ScanTable, 0, ulBufSize); + + spin_lock_init(&Adapter->QueueSpinLock); + + /* Allocate the command buffers */ + libertas_allocate_cmd_buffer(priv); + + memset(&Adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); + Adapter->libertas_ps_confirm_sleep.SeqNum = wlan_cpu_to_le16(++Adapter->SeqNum); + Adapter->libertas_ps_confirm_sleep.Command = + wlan_cpu_to_le16(HostCmd_CMD_802_11_PS_MODE); + Adapter->libertas_ps_confirm_sleep.Size = + wlan_cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); + Adapter->libertas_ps_confirm_sleep.Result = 0; + Adapter->libertas_ps_confirm_sleep.Action = + wlan_cpu_to_le16(HostCmd_SubCmd_Sleep_Confirmed); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function initializes the adapter structure + * and set default value to the member of adapter. + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +static void wlan_init_adapter(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + int i; + + Adapter->ScanProbes = 0; + + Adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; + Adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; + + /* ATIM params */ + Adapter->AtimWindow = 0; + Adapter->ATIMEnabled = 0; + + Adapter->MediaConnectStatus = WlanMediaStateDisconnected; + Adapter->LinkSpeed = MRVDRV_LINK_SPEED_1mbps; + memset(Adapter->CurrentAddr, 0xff, ETH_ALEN); + + /* Status variables */ + Adapter->HardwareStatus = WlanHardwareStatusInitializing; + + /* scan type */ + Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE; + + /* scan mode */ + Adapter->ScanMode = HostCmd_BSS_TYPE_ANY; + + /* 802.11 specific */ + Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled; + for (i = 0; i < sizeof(Adapter->WepKey) / sizeof(Adapter->WepKey[0]); + i++) + memset(&Adapter->WepKey[i], 0, sizeof(struct MRVL_WEP_KEY)); + Adapter->CurrentWepKeyIndex = 0; + Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen; + Adapter->SecInfo.Auth1XAlg = WLAN_1X_AUTH_ALG_NONE; + Adapter->SecInfo.EncryptionMode = CIPHER_NONE; + Adapter->InfrastructureMode = Wlan802_11Infrastructure; + + Adapter->NumInScanTable = 0; + Adapter->pAttemptedBSSDesc = NULL; +#ifdef REASSOCIATION + init_MUTEX(&Adapter->ReassocSem); +#endif + + Adapter->Prescan = CMD_ENABLED; + + memset(&Adapter->CurBssParams, 0, sizeof(Adapter->CurBssParams)); + + /* PnP and power profile */ + Adapter->SurpriseRemoved = 0; + + Adapter->CurrentPacketFilter = + HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON; + + Adapter->RadioOn = RADIO_ON; +#ifdef REASSOCIATION + Adapter->Reassoc_on = 1; +#endif /* REASSOCIATION */ + Adapter->TxAntenna = RF_ANTENNA_2; + Adapter->RxAntenna = RF_ANTENNA_AUTO; + + Adapter->Is_DataRate_Auto = 1; + Adapter->BeaconPeriod = MRVDRV_BEACON_INTERVAL; + + // set default value of capInfo. +#define SHORT_PREAMBLE_ALLOWED 1 + memset(&Adapter->capInfo, 0, sizeof(Adapter->capInfo)); + Adapter->capInfo.ShortPreamble = SHORT_PREAMBLE_ALLOWED; + + Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL; + + Adapter->PSMode = Wlan802_11PowerModeCAM; + Adapter->MultipleDtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; + + Adapter->ListenInterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; + + Adapter->PSState = PS_STATE_FULL_POWER; + Adapter->NeedToWakeup = 0; + Adapter->LocalListenInterval = 0; /* default value in firmware will be used */ + + Adapter->DataRate = 0; // Initially indicate the rate as auto + + Adapter->adhoc_grate_enabled = 0; + + Adapter->IntCounter = Adapter->IntCounterSaved = 0; + + Adapter->EncryptionStatus = Wlan802_11WEPDisabled; + + Adapter->CurrentTxSkb = NULL; + Adapter->PktTxCtrl = 0; + + memset(&Adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); + Adapter->tx_queue_idx = 0; + spin_lock_init(&Adapter->txqueue_lock); + + return; +} + +static void command_timer_fn(unsigned long data); + +/** + * @brief This function initializes firmware + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_init_fw(wlan_private * priv) +{ + int ret = WLAN_STATUS_FAILURE; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* Allocate adapter structure */ + if ((ret = wlan_allocate_adapter(priv)) != WLAN_STATUS_SUCCESS) { + goto done; + } + + /* init adapter structure */ + wlan_init_adapter(priv); + + /* init timer etc. */ + setup_timer(&Adapter->command_timer, command_timer_fn, + (unsigned long)priv); + +#ifdef REASSOCIATION + /* Initialize the timer for the reassociation */ + setup_timer(&Adapter->reassoc_timer, libertas_reassoc_timer_fn, + (unsigned long)priv); +#endif /* REASSOCIATION */ + + /* download fimrware etc. */ + if ((ret = wlan_setup_station_hw(priv)) != WLAN_STATUS_SUCCESS) { + del_timer_sync(&Adapter->command_timer); +#ifdef REASSOCIATION + del_timer_sync(&Adapter->reassoc_timer); +#endif + goto done; + } + + /* init 802.11d */ + libertas_init_11d(priv); + + ret = WLAN_STATUS_SUCCESS; +done: + LEAVE(); + return ret; +} + +/** + * @brief This function frees the structure of adapter + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +void libertas_free_adapter(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (!Adapter) { + PRINTM(INFO, "Why double free adapter?:)\n"); + return; + } + + PRINTM(INFO, "Free Command buffer\n"); + libertas_free_cmd_buffer(priv); + + PRINTM(INFO, "Free CommandTimer\n"); + del_timer(&Adapter->command_timer); +#ifdef REASSOCIATION + PRINTM(INFO, "Free reassoc_timer\n"); + del_timer(&Adapter->reassoc_timer); +#endif /* REASSOCIATION */ + + PRINTM(INFO, "Free ScanTable\n"); + if (Adapter->ScanTable) { + kfree(Adapter->ScanTable); + Adapter->ScanTable = NULL; + } + + PRINTM(INFO, "Free Adapter\n"); + + /* Free the adapter object itself */ + kfree(Adapter); + priv->adapter = NULL; + LEAVE(); +} + +/** + * @brief This function handles the timeout of command sending. + * It will re-send the same command again. + * + * @param FunctionContext A pointer to FunctionContext + * @return n/a + */ +static void command_timer_fn(unsigned long data) +{ + wlan_private *priv = (wlan_private *)data; + wlan_adapter *Adapter = priv->adapter; + struct CmdCtrlNode *pTempNode; + ulong flags; + + ENTER(); + + PRINTM(FATAL, "command_timer_fn fired.\n"); + + pTempNode = Adapter->CurCmd; + + if (!Adapter->fw_ready) + return; + + if (pTempNode == NULL) { + PRINTM(INFO, "PTempnode Empty\n"); + return; + } + + spin_lock_irqsave(&Adapter->QueueSpinLock, flags); + Adapter->CurCmd = NULL; + spin_unlock_irqrestore(&Adapter->QueueSpinLock, flags); + + PRINTM(INFO, "Re-sending same command as it timeout...!\n"); + libertas_queue_cmd(Adapter, pTempNode, 0); + + wake_up_interruptible(&priv->MainThread.waitQ); + + LEAVE(); + return; +} + +#ifdef REASSOCIATION +/** + * @brief This function triggers re-association by waking up + * re-assoc thread. + * + * @param FunctionContext A pointer to FunctionContext + * @return n/a + */ +void libertas_reassoc_timer_fn(unsigned long data) +{ + wlan_private *priv = (wlan_private *)data; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + PRINTM(INFO, "reassoc_timer fired.\n"); + if (Adapter->PSState != PS_STATE_FULL_POWER) { + /* wait until Exit_PS command returns */ + mod_timer(&Adapter->reassoc_timer, jiffies + 1*HZ); + PRINTM(INFO, "libertas_reassoc_timer_fn(PSState=%d) waiting" + "for Exit_PS done\n", Adapter->PSState); + LEAVE(); + return; + } + + PRINTM(INFO, "Waking Up the Event Thread\n"); + + wake_up_interruptible(&priv->ReassocThread.waitQ); + + LEAVE(); + return; +} +#endif /* REASSOCIATION */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_fw.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_fw.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_fw.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_fw.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,44 @@ +/** @file wlan_fw.h + * @brief This header file contains FW interface related definitions. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change log: + 09/26/05: add Doxygen format comments + ************************************************************/ + +#ifndef _WLAN_FW_H_ +#define _WLAN_FW_H_ + +#ifndef DEV_NAME_LEN +#define DEV_NAME_LEN 32 +#endif + +#define MAXKEYLEN 13 + +/* The number of times to try when waiting for downloaded firmware to + become active. (polling the scratch register). */ + +#define MAX_FIRMWARE_POLL_TRIES 100 + +#define FIRMWARE_TRANSFER_BLOCK_SIZE 1536 + +int libertas_init_fw(wlan_private * priv); + +#endif /* _WLAN_FW_H_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_ioctl.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_ioctl.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_ioctl.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_ioctl.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,2817 @@ +/** @file wlan_wext.c + * @brief This file contains ioctl functions + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/* + * Editor's comment: + * + * This whole file is a total mess, the author needs some education + * about ioctl handling. + * + * For now it probably needs to stay in order not to break existing + * tools, but we need to come up with some proper replacement for + * those calls that are actually needed. + * + * -arnd + */ + +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/wireless.h> + +#include <net/iw_handler.h> + +#include "host.h" +#include "radiotap.h" +#include "wlan_decl.h" +#include "wlan_defs.h" +#include "wlan_dev.h" +#include "wlan_join.h" +#include "wlan_wext.h" + +#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ + MRVDRV_MAX_SSID_LENGTH + \ + IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ + IW_EV_QUAL_LEN + MRVDRV_MAX_SSID_LENGTH + \ + IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ + +#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) + +/** + * @brief Set RX Antenna + * + * @param priv A pointer to wlan_private structure + * @param Mode RF antenna mode + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int SetRxAntenna(wlan_private * priv, int Mode) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + + if (Mode != RF_ANTENNA_1 && Mode != RF_ANTENNA_2 + && Mode != RF_ANTENNA_AUTO) { + return -EINVAL; + } + + Adapter->RxAntennaMode = Mode; + + PRINTM(INFO, "SET RX Antenna Mode to 0x%04x\n", Adapter->RxAntennaMode); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RF_ANTENNA, + HostCmd_ACT_SET_RX, + HostCmd_OPTION_WAITFORRSP, 0, + &Adapter->RxAntennaMode); + return ret; +} + +/** + * @brief Set TX Antenna + * + * @param priv A pointer to wlan_private structure + * @param Mode RF antenna mode + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int SetTxAntenna(wlan_private * priv, int Mode) +{ + int ret = 0; + wlan_adapter *Adapter = priv->adapter; + + if ((Mode != RF_ANTENNA_1) && (Mode != RF_ANTENNA_2) + && (Mode != RF_ANTENNA_AUTO)) { + return -EINVAL; + } + + Adapter->TxAntennaMode = Mode; + + PRINTM(INFO, "SET TX Antenna Mode to 0x%04x\n", Adapter->TxAntennaMode); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RF_ANTENNA, + HostCmd_ACT_SET_TX, + HostCmd_OPTION_WAITFORRSP, 0, + &Adapter->TxAntennaMode); + + return ret; +} + +/** + * @brief Get RX Antenna + * + * @param priv A pointer to wlan_private structure + * @param buf A pointer to recieve antenna mode + * @return length of buf + */ +static int GetRxAntenna(wlan_private * priv, char *buf) +{ + int ret = 0; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + // clear it, so we will know if the value + // returned below is correct or not. + Adapter->RxAntennaMode = 0; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RF_ANTENNA, + HostCmd_ACT_GET_RX, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + PRINTM(INFO, "Get Rx Antenna Mode:0x%04x\n", Adapter->RxAntennaMode); + + LEAVE(); + + return sprintf(buf, "0x%04x", Adapter->RxAntennaMode) + 1; +} + +/** + * @brief Get TX Antenna + * + * @param priv A pointer to wlan_private structure + * @param buf A pointer to recieve antenna mode + * @return length of buf + */ +static int GetTxAntenna(wlan_private * priv, char *buf) +{ + int ret = 0; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + // clear it, so we will know if the value + // returned below is correct or not. + Adapter->TxAntennaMode = 0; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RF_ANTENNA, + HostCmd_ACT_GET_TX, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + PRINTM(INFO, "Get Tx Antenna Mode:0x%04x\n", Adapter->TxAntennaMode); + + LEAVE(); + + return sprintf(buf, "0x%04x", Adapter->TxAntennaMode) + 1; +} + +/** + * @brief Set Region + * + * @param priv A pointer to wlan_private structure + * @param region_code region code + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_region(wlan_private * priv, u16 region_code) +{ + int i; + + ENTER(); + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + // use the region code to search for the index + if (region_code == libertas_region_code_to_index[i]) { + priv->adapter->RegionTableIndex = (u16) i; + priv->adapter->RegionCode = region_code; + break; + } + } + + // if it's unidentified region code + if (i >= MRVDRV_MAX_REGION_CODE) { + PRINTM(INFO, "Region Code not identified\n"); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + if (libertas_set_regiontable(priv, priv->adapter->RegionCode, 0)) { + LEAVE(); + return -EINVAL; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get/Set Firmware wakeup method + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *Adapter = priv->adapter; + int data; + ENTER(); + + if ((int)wrq->u.data.length == 0) { + if (copy_to_user + (wrq->u.data.pointer, &Adapter->PktTxCtrl, sizeof(u32))) { + PRINTM(MSG, "copy_to_user failed!\n"); + return -EFAULT; + } + } else { + if ((int)wrq->u.data.length > 1) { + PRINTM(MSG, "ioctl too many args!\n"); + return -EFAULT; + } + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + Adapter->PktTxCtrl = (u32) data; + } + + wrq->u.data.length = 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get/Set NULL Package generation interval + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *Adapter = priv->adapter; + int data; + ENTER(); + + if ((int)wrq->u.data.length == 0) { + data = Adapter->NullPktInterval; + + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(MSG, "copy_to_user failed!\n"); + return -EFAULT; + } + } else { + if ((int)wrq->u.data.length > 1) { + PRINTM(MSG, "ioctl too many args!\n"); + return -EFAULT; + } + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + Adapter->NullPktInterval = data; + } + + wrq->u.data.length = 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief wlan hostcmd ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd command + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_hostcmd_ioctl(struct net_device *dev, struct ifreq *req, + int cmd) +{ + u8 *tempResponseBuffer; + struct CmdCtrlNode *pCmdNode; + struct HostCmd_DS_GEN *gencmd, *pCmdPtr; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + u16 wait_option = 0; + + ENTER(); + + /* + * Get a free command control node + */ + if (!(pCmdNode = libertas_get_free_cmd_ctrl_node(priv))) { + PRINTM(INFO, "Failed libertas_get_free_cmd_ctrl_node\n"); + return -ENOMEM; + } + + if (!(tempResponseBuffer = kmalloc(3000, GFP_KERNEL))) { + PRINTM(INFO, "ERROR: Failed to allocate response buffer!\n"); + return -ENOMEM; + } + + wait_option |= HostCmd_OPTION_WAITFORRSP; + + libertas_set_cmd_ctrl_node(priv, pCmdNode, 0, wait_option, NULL); + init_waitqueue_head(&pCmdNode->cmdwait_q); + + pCmdPtr = (struct HostCmd_DS_GEN *)pCmdNode->BufVirtualAddr; + gencmd = (struct HostCmd_DS_GEN *)req->ifr_data; + + /* + * Copy the whole command into the command buffer + */ + if (copy_from_user(pCmdPtr, req->ifr_data, gencmd->Size)) { + PRINTM(INFO, "Copy from user failed\n"); + kfree(tempResponseBuffer); + return -EFAULT; + } + + pCmdNode->pdata_buf = tempResponseBuffer; + pCmdNode->CmdFlags |= CMD_F_HOSTCMD; + + pCmdPtr->SeqNum = ++priv->adapter->SeqNum; + pCmdPtr->Result = 0; + + PRINTM(INFO, "HOSTCMD Command: 0x%04x Size: %d SeqNum: %d\n", + pCmdPtr->Command, pCmdPtr->Size, pCmdPtr->SeqNum); + HEXDUMP("Command Data", (u8 *) (pCmdPtr), + min_t(u16, 32, pCmdPtr->Size)); + PRINTM(INFO, "Copying data from : (user)0x%p -> 0x%p(driver)\n", + req->ifr_data, pCmdPtr); + + pCmdNode->CmdWaitQWoken = 0; + libertas_queue_cmd(Adapter, pCmdNode, 1); + wake_up_interruptible(&priv->MainThread.waitQ); + + if (wait_option & HostCmd_OPTION_WAITFORRSP) { + /* Sleep until response is generated by FW */ + wait_event_interruptible(pCmdNode->cmdwait_q, + pCmdNode->CmdWaitQWoken); + } + + /* Copy the response back to user space */ + pCmdPtr = (struct HostCmd_DS_GEN *)tempResponseBuffer; + + if (copy_to_user(req->ifr_data, tempResponseBuffer, pCmdPtr->Size)) + PRINTM(INFO, "ERROR: copy_to_user failed!\n"); + + kfree(tempResponseBuffer); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Rx Info + * + * @param priv A pointer to wlan_private structure + * @param wreq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success + */ +static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *Adapter = priv->adapter; + int data[2]; + ENTER(); + data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + data[1] = Adapter->RxPDRate; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 2; + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get SNR + * + * @param priv A pointer to wlan_private structure + * @param wreq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + int data[4]; + + ENTER(); + memset(data, 0, sizeof(data)); + if (wrq->u.data.length) { + if (copy_from_user + (data, wrq->u.data.pointer, + min_t(size_t, wrq->u.data.length, 4) * sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + } + if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) { + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RSSI, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + } + + if (wrq->u.data.length == 0) { + data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; + data[1] = Adapter->SNR[TYPE_BEACON][TYPE_AVG]; + data[2] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + data[3] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 4; + } else if (data[0] == 0) { + data[0] = Adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 1; + } else if (data[0] == 1) { + data[0] = Adapter->SNR[TYPE_BEACON][TYPE_AVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 1; + } else if (data[0] == 2) { + data[0] = Adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 1; + } else if (data[0] == 3) { + data[0] = Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 1; + } else { + return -ENOTSUPP; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get/Set Adhoc beacon Interval + * + * @param priv A pointer to wlan_private structure + * @param wreq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq) +{ + int data; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (wrq->u.data.length > 0) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + PRINTM(INFO, "WLAN SET BEACON INTERVAL: %d\n", data); + if ((data > MRVDRV_MAX_BEACON_INTERVAL) + || (data < MRVDRV_MIN_BEACON_INTERVAL)) + return -ENOTSUPP; + Adapter->BeaconPeriod = data; + } + data = Adapter->BeaconPeriod; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get RSSI + * + * @param priv A pointer to wlan_private structure + * @param wreq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + int temp; + int data = 0; + int *val; + + ENTER(); + data = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + if ((data == 0) || (data == 1)) { + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RSSI, + 0, HostCmd_OPTION_WAITFORRSP, + 0, NULL); + if (ret) { + LEAVE(); + return ret; + } + } + + switch (data) { + case 0: + + temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + Adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + break; + case 1: + temp = CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_AVG], + Adapter->NF[TYPE_BEACON][TYPE_AVG]); + break; + case 2: + temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG], + Adapter->NF[TYPE_RXPD][TYPE_NOAVG]); + break; + case 3: + temp = CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + break; + default: + return -ENOTSUPP; + } + val = (int *)wrq->u.name; + *val = temp; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get NF + * + * @param priv A pointer to wlan_private structure + * @param wreq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + int temp; + int data = 0; + int *val; + + ENTER(); + data = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + if ((data == 0) || (data == 1)) { + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RSSI, + 0, HostCmd_OPTION_WAITFORRSP, + 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + + switch (data) { + case 0: + temp = Adapter->NF[TYPE_BEACON][TYPE_NOAVG]; + break; + case 1: + temp = Adapter->NF[TYPE_BEACON][TYPE_AVG]; + break; + case 2: + temp = Adapter->NF[TYPE_RXPD][TYPE_NOAVG]; + break; + case 3: + temp = Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + break; + default: + return -ENOTSUPP; + } + + temp = CAL_NF(temp); + + PRINTM(INFO, "***temp = %d\n", temp); + val = (int *)wrq->u.name; + *val = temp; + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get TxRate + * + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req) +{ + wlan_adapter *Adapter = priv->adapter; + int *pdata; + struct iwreq *wrq = (struct iwreq *)req; + int ret = WLAN_STATUS_SUCCESS; + ENTER(); + Adapter->TxRate = 0; + PRINTM(INFO, "wlan_get_txrate_ioctl\n"); + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP, + 0, NULL); + if (ret) { + LEAVE(); + return ret; + } + pdata = (int *)wrq->u.name; + *pdata = (int)Adapter->TxRate; + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Adhoc Status + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + char status[64]; + wlan_adapter *Adapter = priv->adapter; + + memset(status, 0, sizeof(status)); + + switch (Adapter->InfrastructureMode) { + case Wlan802_11IBSS: + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + if (Adapter->AdhocCreate) + memcpy(&status, "AdhocStarted", sizeof(status)); + else + memcpy(&status, "AdhocJoined", sizeof(status)); + } else { + memcpy(&status, "AdhocIdle", sizeof(status)); + } + break; + case Wlan802_11Infrastructure: + memcpy(&status, "InfraMode", sizeof(status)); + break; + default: + memcpy(&status, "AutoUnknownMode", sizeof(status)); + break; + } + + PRINTM(INFO, "Status = %s\n", status); + wrq->u.data.length = strlen(status) + 1; + + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, + &status, wrq->u.data.length)) + return -EFAULT; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Driver Version + * + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_version_ioctl(wlan_private * priv, struct ifreq *req) +{ + int len; + char buf[128]; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + libertas_get_version(priv->adapter, buf, sizeof(buf) - 1); + + len = strlen(buf); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, buf, len)) { + PRINTM(INFO, "CopyToUser failed\n"); + return -EFAULT; + } + wrq->u.data.length = len; + } + + PRINTM(INFO, "wlan version: %s\n", buf); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Read/Write adapter registers + * + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_regrdwr_ioctl(wlan_private * priv, struct ifreq *req) +{ + wlan_ioctl_regrdwr regrdwr; + struct wlan_offset_value offval; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (copy_from_user(®rdwr, req->ifr_data, sizeof(regrdwr))) { + PRINTM(INFO, + "copy of regrdwr for wlan_regrdwr_ioctl from user failed \n"); + LEAVE(); + return -EFAULT; + } + + if (regrdwr.WhichReg == REG_EEPROM) { + PRINTM(MSG, "Inside RDEEPROM\n"); + Adapter->pRdeeprom = + (char *)kmalloc((regrdwr.NOB + sizeof(regrdwr)), + GFP_KERNEL); + if (!Adapter->pRdeeprom) + return -ENOMEM; + memcpy(Adapter->pRdeeprom, ®rdwr, sizeof(regrdwr)); + /* +14 is for Action, Offset, and NOB in + * response */ + PRINTM(INFO, "Action:%d Offset: %x NOB: %02x\n", + regrdwr.Action, regrdwr.Offset, regrdwr.NOB); + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_EEPROM_ACCESS, + regrdwr.Action, + HostCmd_OPTION_WAITFORRSP, 0, + ®rdwr); + + if (ret) { + if (Adapter->pRdeeprom) + kfree(Adapter->pRdeeprom); + LEAVE(); + return ret; + } + + mdelay(10); + + /* + * Return the result back to the user + */ + + if (regrdwr.Action == HostCmd_ACT_GEN_READ) { + if (copy_to_user + (req->ifr_data, Adapter->pRdeeprom, + sizeof(regrdwr) + regrdwr.NOB)) { + if (Adapter->pRdeeprom) + kfree(Adapter->pRdeeprom); + PRINTM(INFO, + "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n"); + LEAVE(); + return -EFAULT; + } + } + + if (Adapter->pRdeeprom) + kfree(Adapter->pRdeeprom); + + return WLAN_STATUS_SUCCESS; + } + + offval.offset = regrdwr.Offset; + offval.value = (regrdwr.Action) ? regrdwr.Value : 0x00; + + PRINTM(INFO, "RegAccess: %02x Action:%d " + "Offset: %04x Value: %04x\n", + regrdwr.WhichReg, regrdwr.Action, offval.offset, offval.value); + + /* + * regrdwr.WhichReg should contain the command that + * corresponds to which register access is to be + * performed HostCmd_CMD_MAC_REG_ACCESS 0x0019 + * HostCmd_CMD_BBP_REG_ACCESS 0x001a + * HostCmd_CMD_RF_REG_ACCESS 0x001b + */ + ret = libertas_prepare_and_send_command(priv, regrdwr.WhichReg, + regrdwr.Action, HostCmd_OPTION_WAITFORRSP, + 0, &offval); + + if (ret) { + LEAVE(); + return ret; + } + + mdelay(10); + + /* + * Return the result back to the user + */ + regrdwr.Value = Adapter->OffsetValue.value; + if (regrdwr.Action == HostCmd_ACT_GEN_READ) { + if (copy_to_user(req->ifr_data, ®rdwr, sizeof(regrdwr))) { + PRINTM(INFO, + "copy of regrdwr for wlan_regrdwr_ioctl to user failed \n"); + LEAVE(); + return -EFAULT; + } + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set/Get WPA IE + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (wrq->u.data.length) { + if (wrq->u.data.length > sizeof(Adapter->Wpa_ie)) { + PRINTM(INFO, "failed to copy WPA IE, too big \n"); + return -EFAULT; + } + if (copy_from_user(Adapter->Wpa_ie, wrq->u.data.pointer, + wrq->u.data.length)) { + PRINTM(INFO, "failed to copy WPA IE \n"); + return -EFAULT; + } + Adapter->Wpa_ie_len = wrq->u.data.length; + PRINTM(INFO, "Set Wpa_ie_len=%d IE=%#x\n", Adapter->Wpa_ie_len, + Adapter->Wpa_ie[0]); + HEXDUMP("Wpa_ie", Adapter->Wpa_ie, Adapter->Wpa_ie_len); + if (Adapter->Wpa_ie[0] == WPA_IE) + Adapter->SecInfo.WPAEnabled = 1; + else if (Adapter->Wpa_ie[0] == WPA2_IE) + Adapter->SecInfo.WPA2Enabled = 1; + else { + Adapter->SecInfo.WPAEnabled = 0; + Adapter->SecInfo.WPA2Enabled = 0; + } + } else { + memset(Adapter->Wpa_ie, 0, sizeof(Adapter->Wpa_ie)); + Adapter->Wpa_ie_len = wrq->u.data.length; + PRINTM(INFO, "Reset Wpa_ie_len=%d IE=%#x\n", + Adapter->Wpa_ie_len, Adapter->Wpa_ie[0]); + Adapter->SecInfo.WPAEnabled = 0; + Adapter->SecInfo.WPA2Enabled = 0; + } + + // enable/disable RSN in firmware if WPA is enabled/disabled + // depending on variable Adapter->SecInfo.WPAEnabled is set or not + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_ENABLE_RSN, + HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP, + 0, NULL); + + LEAVE(); + return ret; +} + +/** + * @brief Set Auto Prescan + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int data; + wlan_adapter *Adapter = priv->adapter; + int *val; + + ENTER(); + + data = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + PRINTM(INFO, "WLAN_SUBCMD_SET_PRESCAN %d\n", data); + switch (data) { + case CMD_ENABLED: + Adapter->Prescan = 1; + break; + case CMD_DISABLED: + Adapter->Prescan = 0; + break; + default: + break; + } + + data = Adapter->Prescan; + val = (int *)wrq->u.name; + *val = data; + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set multiple dtim + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + u32 mdtim; + int idata; + int ret = -EINVAL; + + ENTER(); + + idata = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + mdtim = (u32) idata; + if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) + && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM)) + || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) { + priv->adapter->MultipleDtim = mdtim; + ret = WLAN_STATUS_SUCCESS; + } + if (ret) + PRINTM(INFO, "Invalid parameter, MultipleDtim not changed.\n"); + + LEAVE(); + return ret; +} + +/** + * @brief Set authentication mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req) +{ + int alg; + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + alg = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + } + + PRINTM(INFO, "auth alg is %#x\n", alg); + + switch (alg) { + case AUTH_ALG_SHARED_KEY: + Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared; + break; + case AUTH_ALG_NETWORK_EAP: + Adapter->SecInfo.AuthenticationMode = + Wlan802_11AuthModeNetworkEAP; + break; + case AUTH_ALG_OPEN_SYSTEM: + default: + Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen; + break; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set 802.1x authentication mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req) +{ + int alg; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + alg = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + } + PRINTM(INFO, "802.1x auth alg is %#x\n", alg); + priv->adapter->SecInfo.Auth1XAlg = alg; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Encryption mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + if (wrq->u.data.flags == 0) { + //from iwpriv subcmd + mode = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + } else { + //from wpa_supplicant subcmd + if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + } + PRINTM(INFO, "encryption mode is %#x\n", mode); + priv->adapter->SecInfo.EncryptionMode = mode; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +static void adjust_mtu(wlan_private * priv) +{ + int mtu_increment = 0; + + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + mtu_increment += sizeof(struct IEEE80211_Hdr); + + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) + mtu_increment += max(sizeof(struct TxRadiotapHdr), + sizeof(struct RxRadiotapHdr)); + priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN + - sizeof(struct EthII_Hdr) + + mtu_increment; +} + +/** + * @brief Set Link-Layer Layer mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + + ENTER(); + + mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; + + switch (mode) { + case WLAN_LINKMODE_802_3: + priv->adapter->linkmode = mode; + break; + case WLAN_LINKMODE_802_11: + priv->adapter->linkmode = mode; + break; + default: + PRINTM(FATAL, "usb8388-5: invalid link-layer mode (%#x)\n", + mode); + return WLAN_STATUS_NOT_ACCEPTED; + break; + } + PRINTM(INFO, "usb8388-5: link-layer mode is %#x\n", mode); + + adjust_mtu(priv); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Radio Header mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req) +{ + int mode; + + ENTER(); + + mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; + + switch (mode) { + case WLAN_RADIOMODE_NONE: + priv->adapter->radiomode = mode; + break; + case WLAN_RADIOMODE_RADIOTAP: + priv->adapter->radiomode = mode; + break; + default: + PRINTM(INFO, "usb8388-5: invalid radio header mode (%#x)\n", + mode); + return WLAN_STATUS_NOT_ACCEPTED; + break; + } + PRINTM(INFO, "usb8388-5: radio-header mode is %#x\n", mode); + + adjust_mtu(priv); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Debug Header mode + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req) +{ + ENTER(); + priv->adapter->debugmode = (int)((struct ifreq *) + ((u8 *) req + 4))->ifr_data; + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Rx antenna + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, + struct ifreq *req) +{ + int len; + char buf[8]; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + PRINTM(INFO, "WLAN_SUBCMD_GETRXANTENNA\n"); + len = GetRxAntenna(priv, buf); + + wrq->u.data.length = len; + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &buf, len)) { + PRINTM(INFO, "CopyToUser failed\n"); + return -EFAULT; + } + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Tx antenna + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, + struct ifreq *req) +{ + int len; + char buf[8]; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + PRINTM(INFO, "WLAN_SUBCMD_GETTXANTENNA\n"); + len = GetTxAntenna(priv, buf); + + wrq->u.data.length = len; + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &buf, len)) { + PRINTM(INFO, "CopyToUser failed\n"); + return -EFAULT; + } + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get the MAC TSF value from the firmware + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure containing buffer + * space to store a TSF value retrieved from the firmware + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + u64 tsfVal; + int ret; + + ENTER(); + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_GET_TSF, + 0, HostCmd_OPTION_WAITFORRSP, 0, &tsfVal); + + PRINTM(INFO, "IOCTL: Get TSF = 0x%016llx\n", tsfVal); + + if (ret != WLAN_STATUS_SUCCESS) { + PRINTM(INFO, "IOCTL: Get TSF; Command exec failed\n"); + ret = -EFAULT; + } else { + if (copy_to_user(wrq->u.data.pointer, + &tsfVal, + min_t(size_t, wrq->u.data.length, + sizeof(tsfVal))) != 0) { + + PRINTM(INFO, "IOCTL: Get TSF; Copy to user failed\n"); + ret = -EFAULT; + } else { + ret = 0; + } + } + + LEAVE(); + + return ret; +} + +/** + * @brief Get/Set sleep period + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_sleep_period(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + int data; + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_SLEEP_PERIOD sleeppd; + + ENTER(); + + if (wrq->u.data.length > 1) + return -ENOTSUPP; + + memset(&sleeppd, 0, sizeof(sleeppd)); + memset(&Adapter->sleep_period, 0, sizeof(struct sleep_period)); + + if (wrq->u.data.length == 0) { + sleeppd.Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_GET); + } else { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + /* sleep period is between 0 or 10 ... 60 */ + if ((data <= 60 && data >= 10) || (data == 0)) { + sleeppd.Action = wlan_cpu_to_le16(HostCmd_ACT_GEN_SET); + sleeppd.Period = data; + } else + return -EINVAL; + } + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SLEEP_PERIOD, + 0, HostCmd_OPTION_WAITFORRSP, + 0, (void *)&sleeppd); + + data = (int)Adapter->sleep_period.period; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = 1; + + LEAVE(); + return ret; +} + +/** + * @brief Get/Set adapt rate + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + wlan_adapter *Adapter = priv->adapter; + int data[2]; + + ENTER(); + memset(data, 0, sizeof(data)); + if (!wrq->u.data.length) { + PRINTM(INFO, "Get ADAPT RATE SET\n"); + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RATE_ADAPT_RATESET, + HostCmd_ACT_GEN_GET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + data[0] = Adapter->EnableHwAuto; + data[1] = Adapter->RateBitmap; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } +#define GET_TWO_INT 2 + wrq->u.data.length = GET_TWO_INT; + } else { + PRINTM(INFO, "Set ADAPT RATE SET\n"); + if (wrq->u.data.length > 2) + return -EINVAL; + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * wrq->u.data.length)) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + Adapter->EnableHwAuto = data[0]; + Adapter->RateBitmap = data[1]; + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RATE_ADAPT_RATESET, + HostCmd_ACT_GEN_SET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + } + + LEAVE(); + return ret; +} + +/** + * @brief Get/Set inactivity timeout + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + int data = 0; + u16 timeout = 0; + + ENTER(); + if (wrq->u.data.length > 1) + return -ENOTSUPP; + + if (wrq->u.data.length == 0) { + /* Get */ + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_INACTIVITY_TIMEOUT, + HostCmd_ACT_GET, + HostCmd_OPTION_WAITFORRSP, 0, + &timeout); + data = timeout; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + } else { + /* Set */ + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + timeout = data; + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_INACTIVITY_TIMEOUT, + HostCmd_ACT_SET, + HostCmd_OPTION_WAITFORRSP, 0, + &timeout); + } + + wrq->u.data.length = 1; + + LEAVE(); + return ret; +} + +/** + * @brief Get LOG + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + char buf[GETLOG_BUFSIZE - 1]; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + PRINTM(INFO, " GET STATS\n"); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_GET_LOG, + 0, HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + if (wrq->u.data.pointer) { + sprintf(buf, "\n mcasttxframe %u failed %u retry %u " + "multiretry %u framedup %u " + "rtssuccess %u rtsfailure %u ackfailure %u\n" + "rxfrag %u mcastrxframe %u fcserror %u " + "txframe %u wepundecryptable %u ", + Adapter->LogMsg.mcasttxframe, + Adapter->LogMsg.failed, + Adapter->LogMsg.retry, + Adapter->LogMsg.multiretry, + Adapter->LogMsg.framedup, + Adapter->LogMsg.rtssuccess, + Adapter->LogMsg.rtsfailure, + Adapter->LogMsg.ackfailure, + Adapter->LogMsg.rxfrag, + Adapter->LogMsg.mcastrxframe, + Adapter->LogMsg.fcserror, + Adapter->LogMsg.txframe, + Adapter->LogMsg.wepundecryptable); + wrq->u.data.length = strlen(buf) + 1; + if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief config sleep parameters + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_sleep_params_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + int ret; + wlan_adapter *Adapter = priv->adapter; + wlan_ioctl_sleep_params_config sp; + + ENTER(); + + memset(&sp, 0, sizeof(sp)); + + if (copy_from_user(&sp, wrq->u.data.pointer, + min_t(size_t, sizeof(sp), wrq->u.data.length))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + memcpy(&Adapter->sp, &sp.Error, sizeof(struct sleep_params)); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SLEEP_PARAMS, + sp.Action, HostCmd_OPTION_WAITFORRSP, + 0, NULL); + + if (!ret && !sp.Action && wrq->u.data.pointer) { + memcpy(&sp.Error, &Adapter->sp, sizeof(struct sleep_params)); + if (copy_to_user(wrq->u.data.pointer, &sp, sizeof(sp))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = sizeof(sp); + } + + LEAVE(); + return ret; +} + +/** + * @brief Read the CIS Table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_do_getcis_ioctl(wlan_private * priv, struct ifreq *req) +{ + int ret = WLAN_STATUS_SUCCESS; + struct iwreq *wrq = (struct iwreq *)req; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, Adapter->CisInfoBuf, + Adapter->CisInfoLen)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + wrq->u.data.length = Adapter->CisInfoLen; + } + + LEAVE(); + return ret; +} + +/** + * @brief Set scan type + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + u8 buf[12]; + u8 *option[] = { "active", "passive", "get", }; + int i, max_options = (sizeof(option) / sizeof(option[0])); + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (libertas_get_state_11d(priv) == ENABLE_11D) { + PRINTM(INFO, "11D: Cannot set scantype when 11D enabled\n"); + return -EFAULT; + } + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), + wrq->u.data.length))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + PRINTM(INFO, "Scan Type Option = %s\n", buf); + + buf[sizeof(buf) - 1] = '\0'; + + for (i = 0; i < max_options; i++) { + if (!strcmp(buf, option[i])) + break; + } + + switch (i) { + case 0: + Adapter->ScanType = HostCmd_SCAN_TYPE_ACTIVE; + break; + case 1: + Adapter->ScanType = HostCmd_SCAN_TYPE_PASSIVE; + break; + case 2: + wrq->u.data.length = strlen(option[Adapter->ScanType]) + 1; + + if (copy_to_user(wrq->u.data.pointer, + option[Adapter->ScanType], + wrq->u.data.length)) { + PRINTM(INFO, "Copy to user failed\n"); + ret = -EFAULT; + } + + break; + default: + PRINTM(INFO, "Invalid Scan Type Ioctl Option\n"); + ret = -EINVAL; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Set scan mode + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *Adapter = priv->adapter; + u8 buf[12]; + u8 *option[] = { "bss", "ibss", "any", "get" }; + int i, max_options = (sizeof(option) / sizeof(option[0])); + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + memset(buf, 0, sizeof(buf)); + + if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), + wrq->u.data.length))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + PRINTM(INFO, "Scan Mode Option = %s\n", buf); + + buf[sizeof(buf) - 1] = '\0'; + + for (i = 0; i < max_options; i++) { + if (!strcmp(buf, option[i])) + break; + } + + switch (i) { + + case 0: + Adapter->ScanMode = HostCmd_BSS_TYPE_BSS; + break; + case 1: + Adapter->ScanMode = HostCmd_BSS_TYPE_IBSS; + break; + case 2: + Adapter->ScanMode = HostCmd_BSS_TYPE_ANY; + break; + case 3: + + wrq->u.data.length = strlen(option[Adapter->ScanMode - 1]) + 1; + + PRINTM(INFO, "Get Scan Mode Option = %s\n", + option[Adapter->ScanMode - 1]); + + PRINTM(INFO, "Scan Mode Length %d\n", wrq->u.data.length); + + if (copy_to_user(wrq->u.data.pointer, + option[Adapter->ScanMode - 1], + wrq->u.data.length)) { + PRINTM(INFO, "Copy to user failed\n"); + ret = -EFAULT; + } + PRINTM(INFO, "GET Scan Type Option after copy = %s\n", + (char *)wrq->u.data.pointer); + + break; + + default: + PRINTM(INFO, "Invalid Scan Mode Ioctl Option\n"); + ret = -EINVAL; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get/Set Adhoc G Rate + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to user data + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *Adapter = priv->adapter; + int data, data1; + int *val; + + ENTER(); + + data1 = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + switch (data1) { + case 0: + Adapter->adhoc_grate_enabled = 0; + break; + case 1: + Adapter->adhoc_grate_enabled = 1; + break; + case 2: + break; + default: + return -EINVAL; + } + data = Adapter->adhoc_grate_enabled; + val = (int *)wrq->u.name; + *val = data; + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +static inline int hex2int(char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + return -1; +} + +/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") + into binary format (6 bytes). + + This function expects that each byte is represented with 2 characters + (e.g., 11:2:11:11:11:11 is invalid) + + */ +static char *eth_str2addr(char *ethstr, u8 * addr) +{ + int i, val, val2; + char *pos = ethstr; + + /* get rid of initial blanks */ + while (*pos == ' ' || *pos == '\t') + ++pos; + + for (i = 0; i < 6; i++) { + val = hex2int(*pos++); + if (val < 0) + return NULL; + val2 = hex2int(*pos++); + if (val2 < 0) + return NULL; + addr[i] = (val * 16 + val2) & 0xff; + + if (i < 5 && *pos++ != ':') + return NULL; + } + return pos; +} + +/* this writes xx:xx:xx:xx:xx:xx into ethstr + (ethstr must have space for 18 chars) */ +static int eth_addr2str(u8 * addr, char *ethstr) +{ + int i; + char *pos = ethstr; + + for (i = 0; i < 6; i++) { + sprintf(pos, "%02x", addr[i] & 0xff); + pos += 2; + if (i < 5) + *pos++ = ':'; + } + return 17; +} + +/** + * @brief Add an entry to the DFT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_dft_add_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[36]; + char *pos; + u8 ethaddrs[2 * ETH_ALEN]; +#define ethaddr1 (ethaddrs+0) +#define ethaddr2 (ethaddrs+6) + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr1)) == NULL) { + PRINTM(FATAL, "DFT_ADD: Invalid MAC address 1\n"); + return -EINVAL; + } + + if (eth_str2addr(pos, ethaddr2) == NULL) { + PRINTM(FATAL, "DFT_ADD: Invalid MAC address 2\n"); + return -EINVAL; + } +#ifdef DEBUG_LEVEL4 + { + char ethaddr1_str[18], ethaddr2_str[18]; + PRINTM(INFO, "DFT: adding %s\n", ethaddrs_str); + eth_addr2str(ethaddr1, ethaddr1_str); + eth_addr2str(ethaddr2, ethaddr2_str); + PRINTM(INFO, "DFT: adding (%s,%s)\n", ethaddr1_str, + ethaddr2_str); + } +#endif + + LEAVE(); + return (libertas_prepare_and_send_command(priv, HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_DFT_ACCESS_ADD, + HostCmd_OPTION_WAITFORRSP, 0, ethaddrs)); +} + +/** + * @brief Delete an entry from the DFT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_dft_del_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + u8 ethaddr[ETH_ALEN]; + char *pos; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + PRINTM(FATAL, "Invalid MAC address\n"); + return -EINVAL; + } + + PRINTM(INFO, "DFT: deleting %s\n", ethaddrs_str); + + LEAVE(); + return (libertas_prepare_and_send_command(priv, + HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_DFT_ACCESS_DEL, + HostCmd_OPTION_WAITFORRSP, 0, ethaddr)); +} + +/** + * @brief Reset all entries from the DFT table + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_dft_reset_ioctl(wlan_private * priv) +{ + ENTER(); + + PRINTM(MSG, "DFT: resetting\n"); + + LEAVE(); + return (libertas_prepare_and_send_command(priv, + HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_DFT_ACCESS_RESET, + HostCmd_OPTION_WAITFORRSP, 0, NULL)); +} + +/** + * @brief List an entry from the DFT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_dft_list_ioctl(wlan_private * priv, struct ifreq *req) +{ + int pos; + char *addr1, *addr2; + struct iwreq *wrq = (struct iwreq *)req; + /* used to pass id and store the dft entry returned by the FW */ + union { + int id; + char addr1addr2[2 * ETH_ALEN]; + } param; + static char outstr[64]; + char *pbuf = outstr; + int ret; + + ENTER(); + + if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { + PRINTM(INFO, "Copy from user failed\n"); + return WLAN_STATUS_FAILURE; + } + param.id = simple_strtoul(outstr, NULL, 10); + pos = sprintf(pbuf, "%d: ", param.id); + pbuf += pos; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_DFT_ACCESS_LIST, + HostCmd_OPTION_WAITFORRSP, 0, + (char *)¶m); + + if (ret == WLAN_STATUS_SUCCESS) { + addr1 = param.addr1addr2; + addr2 = param.addr1addr2 + ETH_ALEN; + + pos = sprintf(pbuf, "da "); + pbuf += pos; + pos = eth_addr2str(addr1, pbuf); + pbuf += pos; + pos = sprintf(pbuf, " next hop "); + pbuf += pos; + pos = eth_addr2str(addr2, pbuf); + pbuf += pos; + } else { + sprintf(pbuf, "(null)"); + pbuf += pos; + } + wrq->u.data.length = strlen(outstr); + if (copy_to_user(wrq->u.data.pointer, (char *)outstr, + wrq->u.data.length)) { + PRINTM(INFO, "DFT_LIST: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Add an entry to the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + char *pos; + u8 ethaddr[ETH_ALEN]; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + PRINTM(FATAL, "BT_ADD: Invalid MAC address\n"); + return -EINVAL; + } + + PRINTM(INFO, "BT: adding %s\n", ethaddrs_str); + LEAVE(); + return (libertas_prepare_and_send_command(priv, HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_BT_ACCESS_ADD, + HostCmd_OPTION_WAITFORRSP, 0, ethaddr)); +} + +/** + * @brief Delete an entry from the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *)req; + char ethaddrs_str[18]; + u8 ethaddr[ETH_ALEN]; + char *pos; + + ENTER(); + if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, + sizeof(ethaddrs_str))) + return -EFAULT; + + if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { + PRINTM(FATAL, "Invalid MAC address\n"); + return -EINVAL; + } + + PRINTM(INFO, "BT: deleting %s\n", ethaddrs_str); + + return (libertas_prepare_and_send_command(priv, + HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_BT_ACCESS_DEL, + HostCmd_OPTION_WAITFORRSP, 0, ethaddr)); + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Reset all entries from the BT table + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_bt_reset_ioctl(wlan_private * priv) +{ + ENTER(); + + PRINTM(MSG, "BT: resetting\n"); + + return (libertas_prepare_and_send_command(priv, + HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_BT_ACCESS_RESET, + HostCmd_OPTION_WAITFORRSP, 0, NULL)); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief List an entry from the BT table + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) +{ + int pos; + char *addr1; + struct iwreq *wrq = (struct iwreq *)req; + /* used to pass id and store the bt entry returned by the FW */ + union { + int id; + char addr1addr2[2 * ETH_ALEN]; + } param; + static char outstr[64]; + char *pbuf = outstr; + int ret; + + ENTER(); + + if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { + PRINTM(INFO, "Copy from user failed\n"); + return WLAN_STATUS_FAILURE; + } + param.id = simple_strtoul(outstr, NULL, 10); + pos = sprintf(pbuf, "%d: ", param.id); + pbuf += pos; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_DFT_ACCESS, + HostCmd_ACT_BT_ACCESS_LIST, + HostCmd_OPTION_WAITFORRSP, 0, + (char *)¶m); + + if (ret == WLAN_STATUS_SUCCESS) { + addr1 = param.addr1addr2; + + pos = sprintf(pbuf, "ignoring traffic from "); + pbuf += pos; + pos = eth_addr2str(addr1, pbuf); + pbuf += pos; + } else { + sprintf(pbuf, "(null)"); + pbuf += pos; + } + + wrq->u.data.length = strlen(outstr); + if (copy_to_user(wrq->u.data.pointer, (char *)outstr, + wrq->u.data.length)) { + PRINTM(INFO, "BT_LIST: Copy to user failed!\n"); + return -EFAULT; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +#ifdef REASSOCIATION +/** + * @brief Set Auto Reassociation On + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int reassociation_on(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + Adapter->Reassoc_on = 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Auto Reassociation Off + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int reassociation_off(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + del_timer(&Adapter->reassoc_timer); + + Adapter->Reassoc_on = 0; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} +#endif /* REASSOCIATION */ + +/** + * @brief ioctl function - entry point + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd command + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int subcmd = 0; + int idata = 0; + int *pdata; + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + struct iwreq *wrq = (struct iwreq *)req; + + ENTER(); + + PRINTM(INFO, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); + switch (cmd) { + case WLANEXTSCAN: + ret = libertas_extscan_ioctl(priv, req); + break; + case WLANHOSTCMD: + ret = wlan_hostcmd_ioctl(dev, req, cmd); + break; + + case WLANCISDUMP: /* Read CIS Table */ + ret = wlan_do_getcis_ioctl(priv, req); + break; + + case WLANSCAN_TYPE: + PRINTM(INFO, "Scan Type Ioctl\n"); + ret = wlan_scan_type_ioctl(priv, wrq); + break; + + case WLANREGRDWR: /* Register read write command */ + ret = wlan_regrdwr_ioctl(priv, req); + break; + + /* FIXME: this really should be handled by wireless extensions + already, so it can probably be dropped here. */ + case SIOCSIWENCODE: /* set encoding token & mode for WPA */ + ret = wlan_set_encode(dev, NULL, &(wrq->u.data), + wrq->u.data.pointer); + break; + + case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ + switch (wrq->u.data.flags) { + case WLANDEAUTH: + PRINTM(INFO, "Deauth\n"); + libertas_send_deauth(priv); + break; + + case WLANADHOCSTOP: + PRINTM(INFO, "Adhoc stop\n"); + ret = libertas_do_adhocstop_ioctl(priv); + break; + + case WLANRADIOON: + wlan_radio_ioctl(priv, RADIO_ON); + break; + + case WLANRADIOOFF: + wlan_radio_ioctl(priv, RADIO_OFF); + break; +#ifdef REASSOCIATION + case WLANREASSOCIATIONAUTO: + reassociation_on(priv); + break; + case WLANREASSOCIATIONUSER: + reassociation_off(priv); + break; +#endif /* REASSOCIATION */ + case WLANWLANIDLEON: + libertas_idle_on(priv); + break; + case WLANWLANIDLEOFF: + libertas_idle_off(priv); + break; + case WLAN_SUBCMD_DFT_RESET: /* dft_reset */ + wlan_dft_reset_ioctl(priv); + break; + case WLAN_SUBCMD_BT_RESET: /* bt_reset */ + wlan_bt_reset_ioctl(priv); + break; + } /* End of switch */ + break; + + case WLAN_SETWORDCHAR_GETNONE: + switch (wrq->u.data.flags) { + } + break; + + case WLAN_SETNONE_GETWORDCHAR: + switch (wrq->u.data.flags) { + case WLANVERSION: /* Get driver version */ + ret = wlan_version_ioctl(priv, req); + break; + } + break; + case WLANSETWPAIE: + ret = wlan_setwpaie_ioctl(priv, req); + break; + case WLAN_SETINT_GETINT: + /* The first 4 bytes of req->ifr_data is sub-ioctl number + * after 4 bytes sits the payload. + */ + subcmd = (int)req->ifr_data; //from iwpriv subcmd + switch (subcmd) { + case WLANNF: + ret = wlan_get_nf(priv, wrq); + break; + case WLANRSSI: + ret = wlan_get_rssi(priv, wrq); + break; + case WLANENABLE11D: + ret = libertas_cmd_enable_11d(priv, wrq); + break; + case WLANADHOCGRATE: + ret = wlan_do_set_grate_ioctl(priv, wrq); + break; + case WLAN_SUBCMD_SET_PRESCAN: + ret = wlan_subcmd_setprescan_ioctl(priv, wrq); + break; + } + break; + + case WLAN_SETONEINT_GETONEINT: + switch (wrq->u.data.flags) { + case WLAN_BEACON_INTERVAL: + ret = wlan_beacon_interval(priv, wrq); + break; + + case WLAN_LISTENINTRVL: + if (!wrq->u.data.length) { + int data; + PRINTM(INFO, "Get LocalListenInterval Value\n"); +#define GET_ONE_INT 1 + data = Adapter->LocalListenInterval; + if (copy_to_user(wrq->u.data.pointer, + &data, sizeof(int))) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = GET_ONE_INT; + } else { + int data; + if (copy_from_user + (&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + + PRINTM(INFO, "Set LocalListenInterval = %d\n", + data); +#define MAX_U16_VAL 65535 + if (data > MAX_U16_VAL) { + PRINTM(INFO, "Exceeds U16 value\n"); + return -EINVAL; + } + Adapter->LocalListenInterval = data; + } + break; + case WLAN_TXCONTROL: + ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl + break; + + case WLAN_NULLPKTINTERVAL: + ret = wlan_null_pkt_interval(priv, wrq); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + break; + + case WLAN_SETONEINT_GETNONE: + /* The first 4 bytes of req->ifr_data is sub-ioctl number + * after 4 bytes sits the payload. + */ + subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd + + if (!subcmd) + subcmd = (int)req->ifr_data; //from iwpriv subcmd + + switch (subcmd) { + case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */ + idata = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + ret = SetRxAntenna(priv, idata); + break; + case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */ + idata = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + ret = SetTxAntenna(priv, idata); + break; + case WLAN_SET_ATIM_WINDOW: + Adapter->AtimWindow = + *((int *)(wrq->u.name + SUBCMD_OFFSET)); + Adapter->AtimWindow = min_t(__u16, Adapter->AtimWindow, 50); + break; + case WLANSETBCNAVG: + Adapter->bcn_avg_factor = + *((int *)(wrq->u.name + SUBCMD_OFFSET)); + if (Adapter->bcn_avg_factor == 0) + Adapter->bcn_avg_factor = + DEFAULT_BCN_AVG_FACTOR; + if (Adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR) + Adapter->bcn_avg_factor = + DEFAULT_BCN_AVG_FACTOR; + break; + case WLANSETDATAAVG: + Adapter->data_avg_factor = + *((int *)(wrq->u.name + SUBCMD_OFFSET)); + if (Adapter->data_avg_factor == 0) + Adapter->data_avg_factor = + DEFAULT_DATA_AVG_FACTOR; + if (Adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR) + Adapter->data_avg_factor = + DEFAULT_DATA_AVG_FACTOR; + break; + case WLANSETREGION: + idata = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + ret = wlan_set_region(priv, (u16) idata); + break; + + case WLAN_SET_LISTEN_INTERVAL: + idata = *((int *)(wrq->u.name + SUBCMD_OFFSET)); + Adapter->ListenInterval = (u16) idata; + break; + + case WLAN_SET_MULTIPLE_DTIM: + ret = wlan_set_multiple_dtim_ioctl(priv, req); + break; + + case WLANSETAUTHALG: + ret = wlan_setauthalg_ioctl(priv, req); + break; + + case WLANSET8021XAUTHALG: + ret = wlan_set8021xauthalg_ioctl(priv, req); + break; + + case WLANSETENCRYPTIONMODE: + ret = wlan_setencryptionmode_ioctl(priv, req); + break; + + case WLAN_SET_LINKMODE: + ret = wlan_set_linkmode_ioctl(priv, req); + break; + + case WLAN_SET_RADIOMODE: + ret = wlan_set_radiomode_ioctl(priv, req); + break; + + case WLAN_SET_DEBUGMODE: + ret = wlan_set_debugmode_ioctl(priv, req); + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + break; + + case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */ + /* + * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is + * in flags of iwreq structure, otherwise it will be in + * mode member of iwreq structure. + */ + switch ((int)wrq->u.data.flags) { + case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */ + ret = wlan_subcmd_getrxantenna_ioctl(priv, req); + break; + + case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */ + ret = wlan_subcmd_gettxantenna_ioctl(priv, req); + break; + + case WLAN_GET_TSF: + ret = wlan_get_tsf_ioctl(priv, wrq); + break; + } + break; + + case WLAN_SET64CHAR_GET64CHAR: + switch ((int)wrq->u.data.flags) { + + case WLANSLEEPPARAMS: + ret = wlan_sleep_params_ioctl(priv, wrq); + break; + + case WLANSCAN_MODE: + PRINTM(INFO, "Scan Mode Ioctl\n"); + ret = wlan_scan_mode_ioctl(priv, wrq); + break; + + case WLAN_GET_ADHOC_STATUS: + ret = wlan_get_adhoc_status_ioctl(priv, wrq); + break; + case WLAN_SUBCMD_DFT_ADD: + ret = wlan_dft_add_ioctl(priv, req); + break; + case WLAN_SUBCMD_DFT_DEL: + ret = wlan_dft_del_ioctl(priv, req); + break; + case WLAN_SUBCMD_DFT_LIST: + ret = wlan_dft_list_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_ADD: + ret = wlan_bt_add_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_DEL: + ret = wlan_bt_del_ioctl(priv, req); + break; + case WLAN_SUBCMD_BT_LIST: + ret = wlan_bt_list_ioctl(priv, req); + break; + } + break; + + case WLAN_SETCONF_GETCONF: + PRINTM(INFO, "The WLAN_SETCONF_GETCONF=0x%x is %d\n", + WLAN_SETCONF_GETCONF, *(u8 *) req->ifr_data); + switch (*(u8 *) req->ifr_data) { + + } + break; + + case WLAN_SETNONE_GETONEINT: + switch ((int)req->ifr_data) { + case WLANGETBCNAVG: + pdata = (int *)wrq->u.name; + *pdata = (int)Adapter->bcn_avg_factor; + break; + + case WLANGETREGION: + pdata = (int *)wrq->u.name; + *pdata = (int)Adapter->RegionCode; + break; + + case WLAN_GET_LISTEN_INTERVAL: + pdata = (int *)wrq->u.name; + *pdata = (int)Adapter->ListenInterval; + break; + + case WLAN_GET_LINKMODE: + req->ifr_data = (char *)((u32) Adapter->linkmode); + break; + + case WLAN_GET_RADIOMODE: + req->ifr_data = (char *)((u32) Adapter->radiomode); + break; + + case WLAN_GET_DEBUGMODE: + req->ifr_data = (char *)((u32) Adapter->debugmode); + break; + + case WLAN_GET_MULTIPLE_DTIM: + pdata = (int *)wrq->u.name; + *pdata = (int)Adapter->MultipleDtim; + break; + case WLAN_GET_TX_RATE: + ret = wlan_get_txrate_ioctl(priv, req); + break; + default: + ret = -EOPNOTSUPP; + + } + + break; + + case WLAN_SETTENCHAR_GETNONE: + switch ((int)wrq->u.data.flags) { + + } + break; + + case WLAN_SETNONE_GETTENCHAR: + switch ((int)wrq->u.data.flags) { + } + break; + + case WLANGETLOG: + ret = wlan_do_getlog_ioctl(priv, wrq); + break; + + case WLAN_SET_GET_SIXTEEN_INT: + switch ((int)wrq->u.data.flags) { + case WLAN_TPCCFG: + { + int data[5]; + struct HostCmd_DS_802_11_TPC_CFG cfg; + memset(&cfg, 0, sizeof(cfg)); + if ((wrq->u.data.length > 1) + && (wrq->u.data.length != 5)) + return WLAN_STATUS_FAILURE; + + if (wrq->u.data.length == 0) { + cfg.Action = + wlan_cpu_to_le16 + (HostCmd_ACT_GEN_GET); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 5)) { + PRINTM(INFO, + "Copy from user failed\n"); + return -EFAULT; + } + + cfg.Action = + wlan_cpu_to_le16 + (HostCmd_ACT_GEN_SET); + cfg.Enable = data[0]; + cfg.UseSNR = data[1]; + cfg.P0 = data[2]; + cfg.P1 = data[3]; + cfg.P2 = data[4]; + } + + ret = + libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_TPC_CFG, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, (void *)&cfg); + + data[0] = cfg.Enable; + data[1] = cfg.UseSNR; + data[2] = cfg.P0; + data[3] = cfg.P1; + data[4] = cfg.P2; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 5)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 5; + } + break; + + case WLAN_POWERCFG: + { + int data[4]; + struct HostCmd_DS_802_11_PWR_CFG cfg; + memset(&cfg, 0, sizeof(cfg)); + if ((wrq->u.data.length > 1) + && (wrq->u.data.length != 4)) + return WLAN_STATUS_FAILURE; + if (wrq->u.data.length == 0) { + cfg.Action = + wlan_cpu_to_le16 + (HostCmd_ACT_GEN_GET); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 4)) { + PRINTM(INFO, + "Copy from user failed\n"); + return -EFAULT; + } + + cfg.Action = + wlan_cpu_to_le16 + (HostCmd_ACT_GEN_SET); + cfg.Enable = data[0]; + cfg.PA_P0 = data[1]; + cfg.PA_P1 = data[2]; + cfg.PA_P2 = data[3]; + } + ret = + libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_PWR_CFG, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, (void *)&cfg); + data[0] = cfg.Enable; + data[1] = cfg.PA_P0; + data[2] = cfg.PA_P1; + data[3] = cfg.PA_P2; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 4)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 4; + } + break; + case WLAN_AUTO_FREQ_SET: + { + int data[3]; + struct HostCmd_DS_802_11_AFC afc; + memset(&afc, 0, sizeof(afc)); + if (wrq->u.data.length != 3) + return WLAN_STATUS_FAILURE; + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * 3)) { + PRINTM(INFO, "Copy from user failed\n"); + return -EFAULT; + } + afc.afc_auto = data[0]; + + if (afc.afc_auto != 0) { + afc.afc_thre = data[1]; + afc.afc_period = data[2]; + } else { + afc.afc_toff = data[1]; + afc.afc_foff = data[2]; + } + ret = + libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SET_AFC, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, (void *)&afc); + } + break; + case WLAN_AUTO_FREQ_GET: + { + int data[3]; + struct HostCmd_DS_802_11_AFC afc; + memset(&afc, 0, sizeof(afc)); + ret = + libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_GET_AFC, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, (void *)&afc); + data[0] = afc.afc_auto; + data[1] = afc.afc_toff; + data[2] = afc.afc_foff; + if (copy_to_user + (wrq->u.data.pointer, data, + sizeof(int) * 3)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = 3; + } + break; + case WLAN_SCANPROBES: + { + int data; + if (wrq->u.data.length > 0) { + if (copy_from_user + (&data, wrq->u.data.pointer, + sizeof(int))) { + PRINTM(INFO, + "Copy from user failed\n"); + return -EFAULT; + } + + Adapter->ScanProbes = data; + } else { + data = Adapter->ScanProbes; + if (copy_to_user + (wrq->u.data.pointer, &data, + sizeof(int))) { + PRINTM(INFO, + "Copy to user failed\n"); + return -EFAULT; + } + } + wrq->u.data.length = 1; + } + break; + case WLAN_LED_GPIO_CTRL: + { + int i; + int data[16]; + + struct HostCmd_DS_802_11_LED_CTRL ctrl; + struct MrvlIEtypes_LedGpio *gpio = + (struct MrvlIEtypes_LedGpio *) ctrl.data; + + memset(&ctrl, 0, sizeof(ctrl)); + if (wrq->u.data.length > MAX_LEDS * 2) + return -ENOTSUPP; + if ((wrq->u.data.length % 2) != 0) + return -ENOTSUPP; + if (wrq->u.data.length == 0) { + ctrl.Action = + wlan_cpu_to_le16 + (HostCmd_ACT_GEN_GET); + } else { + if (copy_from_user + (data, wrq->u.data.pointer, + sizeof(int) * + wrq->u.data.length)) { + PRINTM(INFO, + "Copy from user failed\n"); + return -EFAULT; + } + + ctrl.Action = + wlan_cpu_to_le16 + (HostCmd_ACT_GEN_SET); + ctrl.NumLed = wlan_cpu_to_le16(0); + gpio->Header.Type = + wlan_cpu_to_le16(TLV_TYPE_LED_GPIO); + gpio->Header.Len = wrq->u.data.length; + for (i = 0; i < wrq->u.data.length; + i += 2) { + gpio->LedPin[i / 2].Led = + data[i]; + gpio->LedPin[i / 2].Pin = + data[i + 1]; + } + } + ret = + libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_LED_GPIO_CTRL, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, (void *)&ctrl); + for (i = 0; i < gpio->Header.Len; i += 2) { + data[i] = gpio->LedPin[i / 2].Led; + data[i + 1] = gpio->LedPin[i / 2].Pin; + } + if (copy_to_user(wrq->u.data.pointer, data, + sizeof(int) * + gpio->Header.Len)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + wrq->u.data.length = gpio->Header.Len; + } + break; + case WLAN_SLEEP_PERIOD: + ret = wlan_sleep_period(priv, wrq); + break; + case WLAN_ADAPT_RATESET: + ret = wlan_adapt_rateset(priv, wrq); + break; + case WLAN_INACTIVITY_TIMEOUT: + ret = wlan_inactivity_timeout(priv, wrq); + break; + case WLANSNR: + ret = wlan_get_snr(priv, wrq); + break; + case WLAN_GET_RXINFO: + ret = wlan_get_rxinfo(priv, wrq); + } + break; + + case WLAN_SET_GET_2K: + switch ((int)wrq->u.data.flags) { + case WLAN_SET_USER_SCAN: + ret = libertas_set_user_scan_ioctl(priv, wrq); + break; + case WLAN_GET_SCAN_TABLE: + ret = libertas_get_scan_table_ioctl(priv, wrq); + break; + + default: + ret = -EOPNOTSUPP; + } + break; + default: + ret = -EINVAL; + break; + } + LEAVE(); + return ret; +} + + diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_join.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_join.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_join.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_join.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,1602 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** @file wlan_join.c + * + * @brief Functions implementing wlan infrastructure and adhoc join routines + * + * IOCTL handlers as well as command preperation and response routines + * for sending adhoc start, adhoc join, and association commands + * to the firmware. + * + * @sa wlan_join.h + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change Log: + 01/11/06: Initial revision. Match new scan code, relocate related functions + 01/19/06: Fix failure to save adhoc ssid as current after adhoc start + 03/16/06: Add a semaphore to protect reassociation thread + +************************************************************/ + +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/wireless.h> + +#include <net/iw_handler.h> + +#include "host.h" +#include "wlan_decl.h" +#include "wlan_join.h" +#include "wlan_dev.h" + +static int wlan_associate(wlan_private * priv, struct bss_descriptor * pBSSDesc); + +/** + * @brief This function finds out the common rates between rate1 and rate2. + * + * It will fill common rates in rate1 as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param Adapter A pointer to wlan_adapter structure + * @param rate1 the buffer which keeps input and output + * @param rate1_size the size of rate1 buffer + * @param rate2 the buffer which keeps rate2 + * @param rate2_size the size of rate2 buffer. + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int get_common_rates(wlan_adapter * Adapter, u8 * rate1, + int rate1_size, u8 * rate2, int rate2_size) +{ + u8 *ptr = rate1; + int ret = WLAN_STATUS_SUCCESS; + u8 tmp[30]; + int i; + + memset(&tmp, 0, sizeof(tmp)); + memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); + memset(rate1, 0, rate1_size); + + /* Mask the top bit of the original values */ + for (i = 0; tmp[i] && i < sizeof(tmp); i++) + tmp[i] &= 0x7F; + + for (i = 0; rate2[i] && i < rate2_size; i++) { + /* Check for Card Rate in tmp, excluding the top bit */ + if (strchr(tmp, rate2[i] & 0x7F)) { + /* Values match, so copy the Card Rate to rate1 */ + *rate1++ = rate2[i]; + } + } + + HEXDUMP("rate1 (AP) Rates:", tmp, sizeof(tmp)); + HEXDUMP("rate2 (Card) Rates:", rate2, rate2_size); + HEXDUMP("Common Rates:", ptr, rate1_size); + PRINTM(INFO, "Tx DataRate is set to 0x%X\n", Adapter->DataRate); + + if (!Adapter->Is_DataRate_Auto) { + while (*ptr) { + if ((*ptr & 0x7f) == Adapter->DataRate) { + ret = WLAN_STATUS_SUCCESS; + goto done; + } + ptr++; + } + PRINTM(MSG, "Previously set fixed data rate %#x isn't " + "compatible with the network.\n", Adapter->DataRate); + + ret = WLAN_STATUS_FAILURE; + goto done; + } + + ret = WLAN_STATUS_SUCCESS; + done: + return ret; +} + +/** + * @brief Send Deauth Request + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS--success, otherwise fail + */ +int libertas_send_deauth(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure && + Adapter->MediaConnectStatus == WlanMediaStateConnected) { + + ret = libertas_send_deauthentication(priv); + + } else { + LEAVE(); + return -ENOTSUPP; + } + + LEAVE(); + return ret; +} + +/** + * @brief Stop Adhoc Network + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_do_adhocstop_ioctl(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (Adapter->InfrastructureMode == Wlan802_11IBSS && + Adapter->MediaConnectStatus == WlanMediaStateConnected) { + + ret = libertas_stop_adhoc_network(priv); + + } else { + LEAVE(); + return -ENOTSUPP; + } + + LEAVE(); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set essid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int libertas_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + struct WLAN_802_11_SSID reqSSID; + int i; + + ENTER(); + +#ifdef REASSOCIATION + // cancel re-association timer if there's one + del_timer(&Adapter->reassoc_timer); + + if (down_interruptible(&Adapter->ReassocSem)) { + PRINTM(FATAL, "Acquire semaphore error, libertas_set_essid\n"); + return -EBUSY; + } +#endif /* REASSOCIATION */ + + /* Check the size of the string */ + if (dwrq->length > IW_ESSID_MAX_SIZE + 1) { + ret = -E2BIG; + goto setessid_ret; + } + + memset(&reqSSID, 0, sizeof(struct WLAN_802_11_SSID)); + + /* + * Check if we asked for `any' or 'particular' + */ + if (!dwrq->flags) { + if (libertas_find_best_network_SSID(priv, &reqSSID)) { + PRINTM(INFO, "Could not find best network\n"); + ret = WLAN_STATUS_SUCCESS; + goto setessid_ret; + } + } else { + /* Set the SSID */ + memcpy(reqSSID.Ssid, extra, dwrq->length); + reqSSID.SsidLength = dwrq->length - 1; + } + + PRINTM(INFO, "Requested new SSID = %s\n", + (reqSSID.SsidLength > 0) ? (char *)reqSSID.Ssid : "NULL"); + + if (!reqSSID.SsidLength || reqSSID.Ssid[0] < 0x20) { + PRINTM(INFO, "Invalid SSID - aborting set_essid\n"); + ret = -EINVAL; + goto setessid_ret; + } + + /* If the requested SSID is not a NULL string, join */ + + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + /* infrastructure mode */ + PRINTM(INFO, "SSID requested = %s\n", reqSSID.Ssid); + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + PRINTM(INFO, "Already Connected ..\n"); + ret = libertas_send_deauthentication(priv); + + if (ret) { + goto setessid_ret; + } + } + if (Adapter->Prescan) + libertas_send_specific_SSID_scan(priv, &reqSSID, 1); + i = libertas_find_SSID_in_list(Adapter, &reqSSID, NULL, + Wlan802_11Infrastructure); + if (i >= 0) { + PRINTM(INFO, + "SSID found in scan list ... associating...\n"); + + ret = wlan_associate(priv, &Adapter->ScanTable[i]); + + if (ret) { + goto setessid_ret; + } + } else { /* i >= 0 */ + ret = i; /* return -ENETUNREACH, passed from libertas_find_SSID_in_list */ + goto setessid_ret; + } + } else { + /* ad hoc mode */ + /* If the requested SSID matches current SSID return */ + if (!libertas_SSID_cmp(&Adapter->CurBssParams.ssid, &reqSSID)) { + ret = WLAN_STATUS_SUCCESS; + goto setessid_ret; + } + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + /* + * Exit Adhoc mode + */ + PRINTM(INFO, "Sending Adhoc Stop\n"); + ret = libertas_stop_adhoc_network(priv); + + if (ret) { + goto setessid_ret; + } + + } + + /* Scan for the network, do not save previous results. Stale + * scan data will cause us to join a non-existant adhoc network + */ + libertas_send_specific_SSID_scan(priv, &reqSSID, 0); + + /* Search for the requested SSID in the scan table */ + i = libertas_find_SSID_in_list(Adapter, &reqSSID, NULL, Wlan802_11IBSS); + + if (i >= 0) { + PRINTM(INFO, "SSID found at %d in List, so join\n", i); + libertas_join_adhoc_network(priv, &Adapter->ScanTable[i]); + } else { + /* else send START command */ + PRINTM(INFO, "SSID not found in list, " + "so creating adhoc with ssid = %s\n", + reqSSID.Ssid); + + libertas_start_adhoc_network(priv, &reqSSID); + } /* end of else (START command) */ + } /* end of else (Ad hoc mode) */ + + /* + * The MediaConnectStatus change can be removed later when + * the ret code is being properly returned. + */ + /* Check to see if we successfully connected */ + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + ret = WLAN_STATUS_SUCCESS; + } else { + ret = -ENETDOWN; + } + + setessid_ret: +#ifdef REASSOCIATION + up(&Adapter->ReassocSem); +#endif + + LEAVE(); + return ret; +} + +/** + * @brief Connect to the AP or Ad-hoc Network with specific bssid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; + u8 reqBSSID[ETH_ALEN]; + int i; + + ENTER(); + +//Application should call scan before call this function. + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + PRINTM(INFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n", + (u8) awrq->sa_data[0], (u8) awrq->sa_data[1], + (u8) awrq->sa_data[2], (u8) awrq->sa_data[3], + (u8) awrq->sa_data[4], (u8) awrq->sa_data[5]); + +#ifdef REASSOCIATION + // cancel re-association timer if there's one + del_timer(&Adapter->reassoc_timer); +#endif /* REASSOCIATION */ + + if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) { + i = libertas_find_best_SSID_in_list(Adapter); + } else { + memcpy(reqBSSID, awrq->sa_data, ETH_ALEN); + + PRINTM(INFO, + "ASSOC: WAP: Bssid = %02x:%02x:%02x:%02x:%02x:%02x\n", + reqBSSID[0], reqBSSID[1], reqBSSID[2], reqBSSID[3], + reqBSSID[4], reqBSSID[5]); + + /* Search for index position in list for requested MAC */ + i = libertas_find_BSSID_in_list(Adapter, reqBSSID, + Adapter->InfrastructureMode); + } + + if (i < 0) { + PRINTM(INFO, + "ASSOC: WAP: MAC address not found in BSSID List\n"); + return -ENETUNREACH; + } + + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + ret = libertas_send_deauthentication(priv); + + if (ret) { + LEAVE(); + return ret; + } + } + ret = wlan_associate(priv, &Adapter->ScanTable[i]); + + if (ret) { + LEAVE(); + return ret; + } + } else { + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + /* Exit Adhoc mode */ + ret = libertas_stop_adhoc_network(priv); + + if (ret) { + LEAVE(); + return ret; + } + } + + libertas_join_adhoc_network(priv, &Adapter->ScanTable[i]); + } + + /* Check to see if we successfully connected */ + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + ret = WLAN_STATUS_SUCCESS; + } else { + ret = -ENETDOWN; + } + + LEAVE(); + return ret; +} + +/** + * @brief Associated to a specific BSS discovered in a scan + * + * @param priv A pointer to wlan_private structure + * @param pBSSDesc Pointer to the BSS descriptor to associate with. + * + * @return WLAN_STATUS_SUCCESS-success, otherwise fail + */ +static int wlan_associate(wlan_private * priv, struct bss_descriptor * pBSSDesc) +{ + int ret; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_AUTHENTICATE, + 0, HostCmd_OPTION_WAITFORRSP, + 0, pBSSDesc->MacAddress); + + if (ret) { + LEAVE(); + return ret; + } + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_ASSOCIATE, + 0, HostCmd_OPTION_WAITFORRSP, 0, pBSSDesc); + + LEAVE(); + return ret; +} + +/** + * @brief Start an Adhoc Network + * + * @param priv A pointer to wlan_private structure + * @param AdhocSSID The ssid of the Adhoc Network + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *AdhocSSID) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + Adapter->AdhocCreate = 1; + + if (!Adapter->capInfo.ShortPreamble) { + PRINTM(INFO, "AdhocStart: Long Preamble\n"); + Adapter->Preamble = HostCmd_TYPE_LONG_PREAMBLE; + } else { + PRINTM(INFO, "AdhocStart: Short Preamble\n"); + Adapter->Preamble = HostCmd_TYPE_SHORT_PREAMBLE; + } + + libertas_set_radio_control(priv); + + PRINTM(INFO, "Adhoc Channel = %d\n", Adapter->AdhocChannel); + PRINTM(INFO, "CurBssParams.channel = %d\n", + Adapter->CurBssParams.channel); + PRINTM(INFO, "CurBssParams.band = %d\n", Adapter->CurBssParams.band); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_AD_HOC_START, + 0, HostCmd_OPTION_WAITFORRSP, 0, AdhocSSID); + + LEAVE(); + return ret; +} + +/** + * @brief Join an adhoc network found in a previous scan + * + * @param priv A pointer to wlan_private structure + * @param pBSSDesc Pointer to a BSS descriptor found in a previous scan + * to attempt to join + * + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pBSSDesc) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + PRINTM(INFO, "libertas_join_adhoc_network: CurBss.ssid =%s\n", + Adapter->CurBssParams.ssid.Ssid); + PRINTM(INFO, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n", + Adapter->CurBssParams.ssid.SsidLength); + PRINTM(INFO, "libertas_join_adhoc_network: ssid =%s\n", pBSSDesc->Ssid.Ssid); + PRINTM(INFO, "libertas_join_adhoc_network: ssid len =%u\n", + pBSSDesc->Ssid.SsidLength); + + /* check if the requested SSID is already joined */ + if (Adapter->CurBssParams.ssid.SsidLength + && !libertas_SSID_cmp(&pBSSDesc->Ssid, &Adapter->CurBssParams.ssid) + && (Adapter->CurBssParams.BSSDescriptor.InfrastructureMode == + Wlan802_11IBSS)) { + + PRINTM(INFO, + "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " + "not attempting to re-join"); + + return WLAN_STATUS_FAILURE; + } + + /*Use ShortPreamble only when both creator and card supports + short preamble */ + if (!pBSSDesc->Cap.ShortPreamble || !Adapter->capInfo.ShortPreamble) { + PRINTM(INFO, "AdhocJoin: Long Preamble\n"); + Adapter->Preamble = HostCmd_TYPE_LONG_PREAMBLE; + } else { + PRINTM(INFO, "AdhocJoin: Short Preamble\n"); + Adapter->Preamble = HostCmd_TYPE_SHORT_PREAMBLE; + } + + libertas_set_radio_control(priv); + + PRINTM(INFO, "CurBssParams.channel = %d\n", + Adapter->CurBssParams.channel); + PRINTM(INFO, "CurBssParams.band = %c\n", Adapter->CurBssParams.band); + + Adapter->AdhocCreate = 0; + + // store the SSID info temporarily + memset(&Adapter->AttemptedSSIDBeforeScan, 0, + sizeof(struct WLAN_802_11_SSID)); + memcpy(&Adapter->AttemptedSSIDBeforeScan, &pBSSDesc->Ssid, + sizeof(struct WLAN_802_11_SSID)); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, + 0, HostCmd_OPTION_WAITFORRSP, + OID_802_11_SSID, pBSSDesc); + + LEAVE(); + return ret; +} + +/** + * @brief Stop the Adhoc Network + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +int libertas_stop_adhoc_network(wlan_private * priv) +{ + return libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_AD_HOC_STOP, + 0, HostCmd_OPTION_WAITFORRSP, 0, NULL); +} + +/** + * @brief Send Deauthentication Request + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +int libertas_send_deauthentication(wlan_private * priv) +{ + return libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, + 0, HostCmd_OPTION_WAITFORRSP, 0, NULL); +} + +/** + * @brief Set Idle Off + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_idle_off(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + const u8 zeroMac[] = { 0, 0, 0, 0, 0, 0 }; + int i; + + ENTER(); + + if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) { + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + if (memcmp(Adapter->PreviousBSSID, zeroMac, + sizeof(zeroMac)) != 0) { + + PRINTM(INFO, "Previous SSID = %s\n", + Adapter->PreviousSSID.Ssid); + PRINTM(INFO, "Previous BSSID = " + "%02x:%02x:%02x:%02x:%02x:%02x:\n", + Adapter->PreviousBSSID[0], + Adapter->PreviousBSSID[1], + Adapter->PreviousBSSID[2], + Adapter->PreviousBSSID[3], + Adapter->PreviousBSSID[4], + Adapter->PreviousBSSID[5]); + + i = libertas_find_SSID_in_list(Adapter, + &Adapter->PreviousSSID, + Adapter->PreviousBSSID, + Adapter->InfrastructureMode); + + if (i < 0) { + libertas_send_specific_BSSID_scan(priv, + Adapter-> + PreviousBSSID, + 1); + i = libertas_find_SSID_in_list(Adapter, + &Adapter-> + PreviousSSID, + Adapter-> + PreviousBSSID, + Adapter-> + InfrastructureMode); + } + + if (i < 0) { + /* If the BSSID could not be found, try just the SSID */ + i = libertas_find_SSID_in_list(Adapter, + &Adapter-> + PreviousSSID, NULL, + Adapter-> + InfrastructureMode); + } + + if (i < 0) { + libertas_send_specific_SSID_scan(priv, + &Adapter-> + PreviousSSID, + 1); + i = libertas_find_SSID_in_list(Adapter, + &Adapter-> + PreviousSSID, NULL, + Adapter-> + InfrastructureMode); + } + + if (i >= 0) { + ret = + wlan_associate(priv, + &Adapter-> + ScanTable[i]); + } + } + } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) { + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_AD_HOC_START, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, &Adapter->PreviousSSID); + } + } + /* else it is connected */ + + PRINTM(INFO, "\nwlanidle is off"); + LEAVE(); + return ret; +} + +/** + * @brief Set Idle On + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_idle_on(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + PRINTM(INFO, "Previous SSID = %s\n", + Adapter->PreviousSSID.Ssid); + memmove(&Adapter->PreviousSSID, + &Adapter->CurBssParams.ssid, + sizeof(struct WLAN_802_11_SSID)); + libertas_send_deauth(priv); + + } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) { + ret = libertas_stop_adhoc_network(priv); + } + + } +#ifdef REASSOCIATION + del_timer(&Adapter->reassoc_timer); +#endif /* REASSOCIATION */ + + PRINTM(INFO, "\nwlanidle is on"); + + LEAVE(); + return ret; +} + +/** + * @brief This function prepares command of authenticate. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param pdata_buf Void cast of pointer to a BSSID to authenticate with + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_80211_authenticate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + void *pdata_buf) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_AUTHENTICATE *pAuthenticate = + &cmd->params.auth; + u8 *bssid = (u8 *) pdata_buf; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AUTHENTICATE); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_AUTHENTICATE) + + S_DS_GEN); + + pAuthenticate->AuthType = Adapter->SecInfo.AuthenticationMode; + memcpy(pAuthenticate->MacAddr, bssid, ETH_ALEN); + + PRINTM(INFO, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n", + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of deauthenticat. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_80211_deauthenticate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_DEAUTHENTICATE *dauth = &cmd->params.deauth; + + ENTER(); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_DEAUTHENTICATE) + + S_DS_GEN); + + /* set AP MAC address */ + memmove(dauth->MacAddr, Adapter->CurBssParams.bssid, + ETH_ALEN); + + /* Reason code 3 = Station is leaving */ +#define REASON_CODE_STA_LEAVING 3 + dauth->ReasonCode = wlan_cpu_to_le16(REASON_CODE_STA_LEAVING); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of association. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param pdata_buf Void cast of BSSDescriptor_t from the scan table to assoc + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_80211_associate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, void *pdata_buf) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_ASSOCIATE *pAsso = &cmd->params.associate; + int ret = WLAN_STATUS_SUCCESS; + struct bss_descriptor *pBSSDesc; + u8 *card_rates; + u8 *pos; + int card_rates_size; + u16 TmpCap; + struct MrvlIEtypes_SsIdParamSet *ssid; + struct MrvlIEtypes_PhyParamSet *phy; + struct MrvlIEtypes_SsParamSet *ss; + struct MrvlIEtypes_RatesParamSet *rates; + struct MrvlIEtypes_RsnParamSet *rsn; + + ENTER(); + + pBSSDesc = (struct bss_descriptor *) pdata_buf; + pos = (u8 *) pAsso; + + if (!Adapter) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); + + /* Save so we know which BSS Desc to use in the response handler */ + Adapter->pAttemptedBSSDesc = pBSSDesc; + + memcpy(pAsso->PeerStaAddr, + pBSSDesc->MacAddress, sizeof(pAsso->PeerStaAddr)); + pos += sizeof(pAsso->PeerStaAddr); + + /* set preamble to firmware */ + if (Adapter->capInfo.ShortPreamble && pBSSDesc->Cap.ShortPreamble) { + Adapter->Preamble = HostCmd_TYPE_SHORT_PREAMBLE; + } else { + Adapter->Preamble = HostCmd_TYPE_LONG_PREAMBLE; + } + + libertas_set_radio_control(priv); + + /* set the listen interval */ + pAsso->ListenInterval = Adapter->ListenInterval; + + pos += sizeof(pAsso->CapInfo); + pos += sizeof(pAsso->ListenInterval); + pos += sizeof(pAsso->BcnPeriod); + pos += sizeof(pAsso->DtimPeriod); + + ssid = (struct MrvlIEtypes_SsIdParamSet *) pos; + ssid->Header.Type = wlan_cpu_to_le16(TLV_TYPE_SSID); + ssid->Header.Len = pBSSDesc->Ssid.SsidLength; + memcpy(ssid->SsId, pBSSDesc->Ssid.Ssid, ssid->Header.Len); + pos += sizeof(ssid->Header) + ssid->Header.Len; + ssid->Header.Len = wlan_cpu_to_le16(ssid->Header.Len); + + phy = (struct MrvlIEtypes_PhyParamSet *) pos; + phy->Header.Type = wlan_cpu_to_le16(TLV_TYPE_PHY_DS); + phy->Header.Len = sizeof(phy->fh_ds.DsParamSet); + memcpy(&phy->fh_ds.DsParamSet, + &pBSSDesc->PhyParamSet.DsParamSet.CurrentChan, + sizeof(phy->fh_ds.DsParamSet)); + pos += sizeof(phy->Header) + phy->Header.Len; + phy->Header.Len = wlan_cpu_to_le16(phy->Header.Len); + + ss = (struct MrvlIEtypes_SsParamSet *) pos; + ss->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CF); + ss->Header.Len = sizeof(ss->cf_ibss.CfParamSet); + pos += sizeof(ss->Header) + ss->Header.Len; + ss->Header.Len = wlan_cpu_to_le16(ss->Header.Len); + + rates = (struct MrvlIEtypes_RatesParamSet *) pos; + rates->Header.Type = wlan_cpu_to_le16(TLV_TYPE_RATES); + + memcpy(&rates->Rates, &pBSSDesc->libertas_supported_rates, WLAN_SUPPORTED_RATES); + + card_rates = libertas_supported_rates; + card_rates_size = sizeof(libertas_supported_rates); + + if (get_common_rates(Adapter, rates->Rates, WLAN_SUPPORTED_RATES, + card_rates, card_rates_size)) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + rates->Header.Len = min_t(size_t, strlen(rates->Rates), WLAN_SUPPORTED_RATES); + Adapter->CurBssParams.NumOfRates = rates->Header.Len; + + pos += sizeof(rates->Header) + rates->Header.Len; + rates->Header.Len = wlan_cpu_to_le16(rates->Header.Len); + + if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled) { + rsn = (struct MrvlIEtypes_RsnParamSet *) pos; + rsn->Header.Type = (u16) Adapter->Wpa_ie[0]; /* WPA_IE or WPA2_IE */ + rsn->Header.Type = wlan_cpu_to_le16(rsn->Header.Type); + rsn->Header.Len = (u16) Adapter->Wpa_ie[1]; + memcpy(rsn->RsnIE, &Adapter->Wpa_ie[2], rsn->Header.Len); + HEXDUMP("ASSOC_CMD: RSN IE", (u8 *) rsn, + sizeof(rsn->Header) + rsn->Header.Len); + pos += sizeof(rsn->Header) + rsn->Header.Len; + rsn->Header.Len = wlan_cpu_to_le16(rsn->Header.Len); + } + + /* update CurBssParams */ + Adapter->CurBssParams.channel = + (pBSSDesc->PhyParamSet.DsParamSet.CurrentChan); + + /* Copy the infra. association rates into Current BSS state structure */ + memcpy(&Adapter->CurBssParams.DataRates, &rates->Rates, + min_t(size_t, sizeof(Adapter->CurBssParams.DataRates), rates->Header.Len)); + + PRINTM(INFO, "ASSOC_CMD: rates->Header.Len = %d\n", rates->Header.Len); + + /* set IBSS field */ + if (pBSSDesc->InfrastructureMode == Wlan802_11Infrastructure) { +#define CAPINFO_ESS_MODE 1 + pAsso->CapInfo.Ess = CAPINFO_ESS_MODE; + } + + if (libertas_parse_dnld_countryinfo_11d(priv)) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + cmd->Size = wlan_cpu_to_le16((u16) (pos - (u8 *) pAsso) + S_DS_GEN); + + /* set the Capability info at last */ + memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(pAsso->CapInfo)); + TmpCap &= CAPINFO_MASK; + PRINTM(INFO, "ASSOC_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n", + TmpCap, CAPINFO_MASK); + TmpCap = wlan_cpu_to_le16(TmpCap); + memcpy(&pAsso->CapInfo, &TmpCap, sizeof(pAsso->CapInfo)); + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function prepares command of ad_hoc_start. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param pssid A pointer to WLAN_802_11_SSID structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, void *pssid) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_AD_HOC_START *adhs = &cmd->params.ads; + int ret = WLAN_STATUS_SUCCESS; + int cmdAppendSize = 0; + int i; + u16 TmpCap; + struct bss_descriptor *pBSSDesc; + + ENTER(); + + if (!Adapter) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); + + pBSSDesc = &Adapter->CurBssParams.BSSDescriptor; + Adapter->pAttemptedBSSDesc = pBSSDesc; + + /* + * Fill in the parameters for 2 data structures: + * 1. HostCmd_DS_802_11_AD_HOC_START Command + * 2. Adapter->ScanTable[i] + * + * Driver will fill up SSID, BSSType,IBSS param, Physical Param, + * probe delay, and Cap info. + * + * Firmware will fill up beacon period, DTIM, Basic rates + * and operational rates. + */ + + memset(adhs->SSID, 0, MRVDRV_MAX_SSID_LENGTH); + + memcpy(adhs->SSID, ((struct WLAN_802_11_SSID *)pssid)->Ssid, + ((struct WLAN_802_11_SSID *)pssid)->SsidLength); + + PRINTM(INFO, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID); + + memset(pBSSDesc->Ssid.Ssid, 0, MRVDRV_MAX_SSID_LENGTH); + memcpy(pBSSDesc->Ssid.Ssid, + ((struct WLAN_802_11_SSID *)pssid)->Ssid, + ((struct WLAN_802_11_SSID *)pssid)->SsidLength); + + pBSSDesc->Ssid.SsidLength = + ((struct WLAN_802_11_SSID *)pssid)->SsidLength; + + /* set the BSS type */ + adhs->BSSType = HostCmd_BSS_TYPE_IBSS; + pBSSDesc->InfrastructureMode = Wlan802_11IBSS; + adhs->BeaconPeriod = Adapter->BeaconPeriod; + + /* set Physical param set */ +#define DS_PARA_IE_ID 3 +#define DS_PARA_IE_LEN 1 + + adhs->PhyParamSet.DsParamSet.ElementId = DS_PARA_IE_ID; + adhs->PhyParamSet.DsParamSet.Len = DS_PARA_IE_LEN; + + ASSERT(Adapter->AdhocChannel); + + PRINTM(INFO, "ADHOC_S_CMD: Creating ADHOC on Channel %d\n", + Adapter->AdhocChannel); + + Adapter->CurBssParams.channel = Adapter->AdhocChannel; + + pBSSDesc->Channel = Adapter->AdhocChannel; + adhs->PhyParamSet.DsParamSet.CurrentChan = Adapter->AdhocChannel; + + memcpy(&pBSSDesc->PhyParamSet, + &adhs->PhyParamSet, sizeof(union IEEEtypes_PhyParamSet)); + + pBSSDesc->NetworkTypeInUse = Wlan802_11DS; + + /* set IBSS param set */ +#define IBSS_PARA_IE_ID 6 +#define IBSS_PARA_IE_LEN 2 + + adhs->SsParamSet.IbssParamSet.ElementId = IBSS_PARA_IE_ID; + adhs->SsParamSet.IbssParamSet.Len = IBSS_PARA_IE_LEN; + adhs->SsParamSet.IbssParamSet.AtimWindow = Adapter->AtimWindow; + memcpy(&pBSSDesc->SsParamSet, + &adhs->SsParamSet, sizeof(union IEEEtypes_SsParamSet)); + + /* set Capability info */ + adhs->Cap.Ess = 0; + adhs->Cap.Ibss = 1; + pBSSDesc->Cap.Ibss = 1; + + /* ProbeDelay */ + adhs->ProbeDelay = wlan_cpu_to_le16(HostCmd_SCAN_PROBE_DELAY_TIME); + + /* set up privacy in Adapter->ScanTable[i] */ + if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) { + +#define AD_HOC_CAP_PRIVACY_ON 1 + PRINTM(INFO, "ADHOC_S_CMD: WEPStatus set, Privacy to WEP\n"); + pBSSDesc->Privacy = Wlan802_11PrivFilter8021xWEP; + adhs->Cap.Privacy = AD_HOC_CAP_PRIVACY_ON; + } else { + PRINTM(INFO, "ADHOC_S_CMD: WEPStatus NOT set, Setting " + "Privacy to ACCEPT ALL\n"); + pBSSDesc->Privacy = Wlan802_11PrivFilterAcceptAll; + } + + memset(adhs->DataRate, 0, sizeof(adhs->DataRate)); + + if (Adapter->adhoc_grate_enabled) { + memcpy(adhs->DataRate, libertas_adhoc_rates_g, + min(sizeof(adhs->DataRate), sizeof(libertas_adhoc_rates_g))); + } else { + memcpy(adhs->DataRate, libertas_adhoc_rates_b, + min(sizeof(adhs->DataRate), sizeof(libertas_adhoc_rates_b))); + } + + /* Find the last non zero */ + for (i = 0; i < sizeof(adhs->DataRate) && adhs->DataRate[i]; i++) ; + + Adapter->CurBssParams.NumOfRates = i; + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memcpy(&Adapter->CurBssParams.DataRates, + &adhs->DataRate, Adapter->CurBssParams.NumOfRates); + + PRINTM(INFO, "ADHOC_S_CMD: Rates=%02x %02x %02x %02x \n", + adhs->DataRate[0], adhs->DataRate[1], + adhs->DataRate[2], adhs->DataRate[3]); + + PRINTM(INFO, "ADHOC_S_CMD: AD HOC Start command is ready\n"); + + if (libertas_create_dnld_countryinfo_11d(priv)) { + PRINTM(INFO, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_AD_HOC_START) + + S_DS_GEN + cmdAppendSize); + + memcpy(&TmpCap, &adhs->Cap, sizeof(u16)); + TmpCap = wlan_cpu_to_le16(TmpCap); + memcpy(&adhs->Cap, &TmpCap, sizeof(u16)); + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + return ret; +} + +/** + * @brief This function prepares command of ad_hoc_stop. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd) +{ + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_AD_HOC_STOP) + + S_DS_GEN); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prepares command of ad_hoc_join. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure + * @param pdata_buf Void cast of BSSDescriptor_t from the scan table to join + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, void *pdata_buf) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_AD_HOC_JOIN *pAdHocJoin = &cmd->params.adj; + struct bss_descriptor *pBSSDesc = (struct bss_descriptor *) pdata_buf; + int cmdAppendSize = 0; + int ret = WLAN_STATUS_SUCCESS; + u8 *card_rates; + int card_rates_size; + u16 TmpCap; + int i; + + ENTER(); + + Adapter->pAttemptedBSSDesc = pBSSDesc; + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); + + pAdHocJoin->BssDescriptor.BSSType = HostCmd_BSS_TYPE_IBSS; + + pAdHocJoin->BssDescriptor.BeaconPeriod = pBSSDesc->BeaconPeriod; + + memcpy(&pAdHocJoin->BssDescriptor.BSSID, + &pBSSDesc->MacAddress, ETH_ALEN); + + memcpy(&pAdHocJoin->BssDescriptor.SSID, + &pBSSDesc->Ssid.Ssid, pBSSDesc->Ssid.SsidLength); + + memcpy(&pAdHocJoin->BssDescriptor.PhyParamSet, + &pBSSDesc->PhyParamSet, sizeof(union IEEEtypes_PhyParamSet)); + + memcpy(&pAdHocJoin->BssDescriptor.SsParamSet, + &pBSSDesc->SsParamSet, sizeof(union IEEEtypes_SsParamSet)); + + memcpy(&TmpCap, &pBSSDesc->Cap, sizeof(struct IEEEtypes_CapInfo)); + + TmpCap &= CAPINFO_MASK; + + PRINTM(INFO, "ADHOC_J_CMD: TmpCap=%4X CAPINFO_MASK=%4X\n", + TmpCap, CAPINFO_MASK); + memcpy(&pAdHocJoin->BssDescriptor.Cap, &TmpCap, + sizeof(struct IEEEtypes_CapInfo)); + + /* information on BSSID descriptor passed to FW */ + PRINTM(INFO, + "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n", + pAdHocJoin->BssDescriptor.BSSID[0], + pAdHocJoin->BssDescriptor.BSSID[1], + pAdHocJoin->BssDescriptor.BSSID[2], + pAdHocJoin->BssDescriptor.BSSID[3], + pAdHocJoin->BssDescriptor.BSSID[4], + pAdHocJoin->BssDescriptor.BSSID[5], + pAdHocJoin->BssDescriptor.SSID); + + PRINTM(INFO, "ADHOC_J_CMD: Data Rate = %x\n", + (u32) pAdHocJoin->BssDescriptor.DataRates); + + /* FailTimeOut */ + pAdHocJoin->FailTimeOut = wlan_cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + + /* ProbeDelay */ + pAdHocJoin->ProbeDelay = + wlan_cpu_to_le16(HostCmd_SCAN_PROBE_DELAY_TIME); + + /* Copy Data Rates from the Rates recorded in scan response */ + memset(pAdHocJoin->BssDescriptor.DataRates, 0, + sizeof(pAdHocJoin->BssDescriptor.DataRates)); + memcpy(pAdHocJoin->BssDescriptor.DataRates, pBSSDesc->DataRates, + min(sizeof(pAdHocJoin->BssDescriptor.DataRates), + sizeof(pBSSDesc->DataRates))); + + card_rates = libertas_supported_rates; + card_rates_size = sizeof(libertas_supported_rates); + + Adapter->CurBssParams.channel = pBSSDesc->Channel; + + if (get_common_rates(Adapter, pAdHocJoin->BssDescriptor.DataRates, + sizeof(pAdHocJoin->BssDescriptor.DataRates), + card_rates, card_rates_size)) { + PRINTM(INFO, "ADHOC_J_CMD: get_common_rates returns error.\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + /* Find the last non zero */ + for (i = 0; i < sizeof(pAdHocJoin->BssDescriptor.DataRates) + && pAdHocJoin->BssDescriptor.DataRates[i]; i++) ; + + Adapter->CurBssParams.NumOfRates = i; + + /* + * Copy the adhoc joining rates to Current BSS State structure + */ + memcpy(Adapter->CurBssParams.DataRates, + pAdHocJoin->BssDescriptor.DataRates, + Adapter->CurBssParams.NumOfRates); + + pAdHocJoin->BssDescriptor.SsParamSet.IbssParamSet.AtimWindow = + wlan_cpu_to_le16(pBSSDesc->ATIMWindow); + + if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) { + pAdHocJoin->BssDescriptor.Cap.Privacy = AD_HOC_CAP_PRIVACY_ON; + } + + if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) { + /* wake up first */ + enum WLAN_802_11_POWER_MODE LocalPSMode; + + LocalPSMode = Wlan802_11PowerModeCAM; + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_PS_MODE, + HostCmd_ACT_GEN_SET, + 0, 0, &LocalPSMode); + + if (ret) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + } + + if (libertas_parse_dnld_countryinfo_11d(priv)) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + cmd->Size = + wlan_cpu_to_le16(sizeof(struct HostCmd_DS_802_11_AD_HOC_JOIN) + + S_DS_GEN + cmdAppendSize); + + memcpy(&TmpCap, &pAdHocJoin->BssDescriptor.Cap, + sizeof(struct IEEEtypes_CapInfo)); + TmpCap = wlan_cpu_to_le16(TmpCap); + + memcpy(&pAdHocJoin->BssDescriptor.Cap, + &TmpCap, sizeof(struct IEEEtypes_CapInfo)); + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function handles the command response of authenticate + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_ret_80211_authenticate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of associate + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_ret_80211_associate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + union iwreq_data wrqu; + struct IEEEtypes_AssocRsp *pAssocRsp; + struct bss_descriptor *pBSSDesc; + + ENTER(); + + pAssocRsp = (struct IEEEtypes_AssocRsp *) & resp->params; + + if (pAssocRsp->StatusCode) { + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + libertas_mac_event_disconnected(priv); + } + + PRINTM(INFO, + "ASSOC_RESP: Association Failed, status code = %d\n", + pAssocRsp->StatusCode); + + ret = WLAN_STATUS_FAILURE; + goto done; + } + + HEXDUMP("ASSOC_RESP:", (void *)&resp->params, + wlan_le16_to_cpu(resp->Size) - S_DS_GEN); + + /* Send a Media Connected event, according to the Spec */ + Adapter->MediaConnectStatus = WlanMediaStateConnected; + Adapter->LinkSpeed = MRVDRV_LINK_SPEED_11mbps; + + /* Set the attempted BSSID Index to current */ + pBSSDesc = Adapter->pAttemptedBSSDesc; + + PRINTM(INFO, "ASSOC_RESP: %s\n", pBSSDesc->Ssid.Ssid); + + /* Set the new SSID to current SSID */ + memcpy(&Adapter->CurBssParams.ssid, + &pBSSDesc->Ssid, sizeof(struct WLAN_802_11_SSID)); + + /* Set the new BSSID (AP's MAC address) to current BSSID */ + memcpy(Adapter->CurBssParams.bssid, + pBSSDesc->MacAddress, ETH_ALEN); + + /* Make a copy of current BSSID descriptor */ + memcpy(&Adapter->CurBssParams.BSSDescriptor, + pBSSDesc, sizeof(struct bss_descriptor)); + + PRINTM(INFO, "ASSOC_RESP: CurrentPacketFilter is %x\n", + Adapter->CurrentPacketFilter); + + Adapter->MediaConnectStatus = WlanMediaStateConnected; + + if (Adapter->SecInfo.WPAEnabled || Adapter->SecInfo.WPA2Enabled) + Adapter->IsGTK_SET = 0; + + Adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0; + Adapter->NF[TYPE_RXPD][TYPE_AVG] = 0; + + memset(Adapter->rawSNR, 0x00, sizeof(Adapter->rawSNR)); + memset(Adapter->rawNF, 0x00, sizeof(Adapter->rawNF)); + Adapter->nextSNRNF = 0; + Adapter->numSNRNF = 0; + + { + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + } + + PRINTM(INFO, "ASSOC_RESP: Associated \n"); + + memcpy(wrqu.ap_addr.sa_data, Adapter->CurBssParams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function handles the command response of disassociate + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_ret_80211_disassociate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + ENTER(); + + libertas_mac_event_disconnected(priv); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of ad_hoc_start + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_ret_80211_ad_hoc_start(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + u16 Command = wlan_le16_to_cpu(resp->Command); + u16 Result = wlan_le16_to_cpu(resp->Result); + struct HostCmd_DS_802_11_AD_HOC_RESULT *pAdHocResult; + union iwreq_data wrqu; + struct bss_descriptor *pBSSDesc; + + ENTER(); + + pAdHocResult = &resp->params.result; + + PRINTM(INFO, "ADHOC_S_RESP: Size = %d\n", wlan_le16_to_cpu(resp->Size)); + PRINTM(INFO, "ADHOC_S_RESP: Command = %x\n", Command); + PRINTM(INFO, "ADHOC_S_RESP: Result = %x\n", Result); + + pBSSDesc = Adapter->pAttemptedBSSDesc; + + /* + * Join result code 0 --> SUCCESS + */ + if (Result) { + PRINTM(INFO, "ADHOC_RESP Failed\n"); + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + libertas_mac_event_disconnected(priv); + } + + memset(&Adapter->CurBssParams.BSSDescriptor, + 0x00, sizeof(Adapter->CurBssParams.BSSDescriptor)); + + Adapter->AdHocFailed = 1; + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + /* + * Now the join cmd should be successful + * If BSSID has changed use SSID to compare instead of BSSID + */ + PRINTM(INFO, "ADHOC_J_RESP %s\n", pBSSDesc->Ssid.Ssid); + + /* Send a Media Connected event, according to the Spec */ + Adapter->MediaConnectStatus = WlanMediaStateConnected; + Adapter->LinkSpeed = MRVDRV_LINK_SPEED_11mbps; + + if (Command == HostCmd_RET_802_11_AD_HOC_START) { + Adapter->AdHocCreated = 1; + + /* Update the created network descriptor with the new BSSID */ + memcpy(pBSSDesc->MacAddress, + pAdHocResult->BSSID, ETH_ALEN); + } else { + + /* Make a copy of current BSSID descriptor, only needed for join since + * the current descriptor is already being used for adhoc start + */ + memmove(&Adapter->CurBssParams.BSSDescriptor, + pBSSDesc, sizeof(struct bss_descriptor)); + } + + /* Set the BSSID from the joined/started descriptor */ + memcpy(&Adapter->CurBssParams.bssid, + pBSSDesc->MacAddress, ETH_ALEN); + + /* Set the new SSID to current SSID */ + memcpy(&Adapter->CurBssParams.ssid, + &pBSSDesc->Ssid, sizeof(struct WLAN_802_11_SSID)); + + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, Adapter->CurBssParams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + PRINTM(INFO, "ADHOC_RESP: - Joined/Started Ad Hoc\n"); + PRINTM(INFO, "ADHOC_RESP: Channel = %d\n", Adapter->AdhocChannel); + PRINTM(INFO, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", + pAdHocResult->BSSID[0], pAdHocResult->BSSID[1], + pAdHocResult->BSSID[2], pAdHocResult->BSSID[3], + pAdHocResult->BSSID[4], pAdHocResult->BSSID[5]); + + LEAVE(); + return ret; +} + +/** + * @brief This function handles the command response of ad_hoc_stop + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp) +{ + ENTER(); + + libertas_mac_event_disconnected(priv); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +#ifdef REASSOCIATION +/** + * @brief This function handles re-association. it is triggered + * by re-assoc timer. + * + * @param data A pointer to wlan_thread structure + * @return WLAN_STATUS_SUCCESS + */ +int libertas_reassociation_thread(void *data) +{ + struct wlan_thread *thread = data; + wlan_private *priv = thread->priv; + wlan_adapter *Adapter = priv->adapter; + wait_queue_t wait; + int i; + + ENTER(); + + wlan_activate_thread(thread); + init_waitqueue_entry(&wait, current); + + for (;;) { + add_wait_queue(&thread->waitQ, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + PRINTM(INFO, "Reassoc: Thread sleeping...\n"); + + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&thread->waitQ, &wait); + try_to_freeze(); + + if (Adapter->SurpriseRemoved) { + break; + } + + if (kthread_should_stop()) { + break; + } + + PRINTM(INFO, "Reassoc: Thread waking up...\n"); + + if (Adapter->InfrastructureMode != Wlan802_11Infrastructure) { + PRINTM(MSG, + "Reassoc: non infra mode is not supported\n"); + continue; + } + + /* The semaphore is used to avoid reassociation thread and + libertas_set_scan/libertas_set_essid interrupting each other. + Reassociation should be disabled completely by application if + libertas_set_user_scan_ioctl/libertas_set_wap is used. + */ + if (down_interruptible(&Adapter->ReassocSem)) { + PRINTM(FATAL, + "Acquire semaphore error, reassociation thread\n"); + goto settimer; + } + + if (Adapter->MediaConnectStatus != WlanMediaStateDisconnected) { + up(&Adapter->ReassocSem); + PRINTM(MSG, + "Reassoc: Adapter->MediaConnectStatus is wrong\n"); + continue; + } + + PRINTM(INFO, "Reassoc: Required ESSID: %s\n", + Adapter->PreviousSSID.Ssid); + + PRINTM(INFO, "Reassoc: Performing Active Scan @ %lu\n", + jiffies); + + libertas_send_specific_SSID_scan(priv, &Adapter->PreviousSSID, 1); + + /* Try to find the specific BSSID we were associated to first */ + i = libertas_find_SSID_in_list(Adapter, + &Adapter->PreviousSSID, + Adapter->PreviousBSSID, + Adapter->InfrastructureMode); + + if (i < 0) { + /* If the BSSID could not be found, try just the SSID */ + i = libertas_find_SSID_in_list(Adapter, + &Adapter->PreviousSSID, + NULL, Adapter->InfrastructureMode); + } + + if (i >= 0) { + wlan_associate(priv, &Adapter->ScanTable[i]); + } + + up(&Adapter->ReassocSem); + + settimer: + if (Adapter->MediaConnectStatus == WlanMediaStateDisconnected) { + PRINTM(INFO, "Reassoc: No AP found or assoc failed." + "Restarting re-assoc Timer @ %lu\n", jiffies); + + mod_timer(&Adapter->reassoc_timer, jiffies + 10*HZ); /* 10s */ + } + } + + wlan_deactivate_thread(thread); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} +#endif /* REASSOCIATION */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_join.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_join.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_join.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_join.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,99 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** @file wlan_join.h + * + * @brief Interface for the wlan infrastructure and adhoc join routines + * + * Driver interface functions and type declarations for the join module + * implemented in wlan_join.c. Process all start/join requests for + * both adhoc and infrastructure networks + * + * @sa wlan_join.c + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change Log: + 01/11/06: Initial revision. Match new scan code, relocate related functions + +************************************************************/ + +#ifndef _WLAN_JOIN_H +#define _WLAN_JOIN_H + +#include "wlan_defs.h" + +//! Size of buffer allocated to store the association response from firmware +#define MRVDRV_ASSOC_RSP_BUF_SIZE 500 + +struct HostCmd_DS_COMMAND; +extern int libertas_cmd_80211_authenticate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + void *pdata_buf); +extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + void *pdata_buf); +extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd); +extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + void *pssid); +extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd); +extern int libertas_cmd_80211_associate(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + void *pdata_buf); + +extern int libertas_ret_80211_authenticate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); +extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); +extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); +extern int libertas_ret_80211_disassociate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); +extern int libertas_ret_80211_associate(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); + +extern int libertas_idle_on(wlan_private * priv); +extern int libertas_idle_off(wlan_private * priv); + +extern int libertas_do_adhocstop_ioctl(wlan_private * priv); +extern int libertas_reassociation_thread(void *data); + +struct WLAN_802_11_SSID; +struct bss_descriptor; + +extern int libertas_start_adhoc_network(wlan_private * priv, + struct WLAN_802_11_SSID *AdhocSSID); +extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pBSSDesc); +extern int libertas_stop_adhoc_network(wlan_private * priv); + +extern int libertas_send_deauthentication(wlan_private * priv); +extern int libertas_send_deauth(wlan_private * priv); + +extern int libertas_do_adhocstop_ioctl(wlan_private * priv); + +#ifdef __KERNEL__ +struct iw_request_info; +extern int libertas_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra); +#endif + +#endif diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_main.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_main.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_main.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_main.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,1163 @@ +/** @file wlan_main.c + * + * @brief This file contains the major functions in WLAN + * driver. It includes init, exit, open, close and main + * thread etc.. + * + */ +/** + * @mainpage M-WLAN Linux Driver + * + * @section overview_sec Overview + * + * The M-WLAN is a Linux reference driver for Marvell + * 802.11 (a/b/g) WLAN chipset. + * + * @section copyright_sec Copyright + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 09/30/05: Add Doxygen format comments + 12/09/05: Add TX_QUEUE support + 01/05/06: Add kernel 2.6.x support + 01/11/06: Change compile flag BULVERDE_SDIO to SD to support + Monahans/Zylonite + 01/11/06: Conditionalize new scan/join functions. + 01/12/06: Add TxLockFlag for UAPSD power save mode + and Proprietary Periodic sleep support + 02/13/06: Add a patch for USB interoperability issue +********************************************************/ + +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> + +#include <net/iw_handler.h> + +#include "host.h" +#include "sbi.h" +#include "wlan_decl.h" +#include "wlan_dev.h" +#include "wlan_fw.h" +#include "wlan_wext.h" +#include "wlan_debugfs.h" + +#ifdef REASSOCIATION +#include "wlan_join.h" +#endif + +#ifdef ENABLE_PM +static struct pm_dev *wlan_pm_dev = NULL; +#endif + +DEFINE_SPINLOCK(libertas_driver_lock); + +#define WLAN_TX_PWR_DEFAULT 20 /*100mW */ +#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */ +#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */ +#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */ +#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */ + +/* Format { Channel, Frequency (MHz), MaxTxPower } */ +/* Band: 'B/G', Region: USA FCC/Canada IC */ +static struct chan_freq_power channel_freq_power_US_BG[] = { + {1, 2412, WLAN_TX_PWR_US_DEFAULT}, + {2, 2417, WLAN_TX_PWR_US_DEFAULT}, + {3, 2422, WLAN_TX_PWR_US_DEFAULT}, + {4, 2427, WLAN_TX_PWR_US_DEFAULT}, + {5, 2432, WLAN_TX_PWR_US_DEFAULT}, + {6, 2437, WLAN_TX_PWR_US_DEFAULT}, + {7, 2442, WLAN_TX_PWR_US_DEFAULT}, + {8, 2447, WLAN_TX_PWR_US_DEFAULT}, + {9, 2452, WLAN_TX_PWR_US_DEFAULT}, + {10, 2457, WLAN_TX_PWR_US_DEFAULT}, + {11, 2462, WLAN_TX_PWR_US_DEFAULT} +}; + +/* Band: 'B/G', Region: Europe ETSI */ +static struct chan_freq_power channel_freq_power_EU_BG[] = { + {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT}, + {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT}, + {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT}, + {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT}, + {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT}, + {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT}, + {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT}, + {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT}, + {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT}, + {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT}, + {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT}, + {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT}, + {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT} +}; + +/* Band: 'B/G', Region: Spain */ +static struct chan_freq_power channel_freq_power_SPN_BG[] = { + {10, 2457, WLAN_TX_PWR_DEFAULT}, + {11, 2462, WLAN_TX_PWR_DEFAULT} +}; + +/* Band: 'B/G', Region: France */ +static struct chan_freq_power channel_freq_power_FR_BG[] = { + {10, 2457, WLAN_TX_PWR_FR_DEFAULT}, + {11, 2462, WLAN_TX_PWR_FR_DEFAULT}, + {12, 2467, WLAN_TX_PWR_FR_DEFAULT}, + {13, 2472, WLAN_TX_PWR_FR_DEFAULT} +}; + +/* Band: 'B/G', Region: Japan */ +static struct chan_freq_power channel_freq_power_JPN_BG[] = { + {1, 2412, WLAN_TX_PWR_JP_DEFAULT}, + {2, 2417, WLAN_TX_PWR_JP_DEFAULT}, + {3, 2422, WLAN_TX_PWR_JP_DEFAULT}, + {4, 2427, WLAN_TX_PWR_JP_DEFAULT}, + {5, 2432, WLAN_TX_PWR_JP_DEFAULT}, + {6, 2437, WLAN_TX_PWR_JP_DEFAULT}, + {7, 2442, WLAN_TX_PWR_JP_DEFAULT}, + {8, 2447, WLAN_TX_PWR_JP_DEFAULT}, + {9, 2452, WLAN_TX_PWR_JP_DEFAULT}, + {10, 2457, WLAN_TX_PWR_JP_DEFAULT}, + {11, 2462, WLAN_TX_PWR_JP_DEFAULT}, + {12, 2467, WLAN_TX_PWR_JP_DEFAULT}, + {13, 2472, WLAN_TX_PWR_JP_DEFAULT}, + {14, 2484, WLAN_TX_PWR_JP_DEFAULT} +}; + +/** + * the structure for channel, frequency and power + */ +struct region_cfp_table { + u8 region; + struct chan_freq_power *cfp_BG; + int cfp_no_BG; +}; + +/** + * the structure for the mapping between region and CFP + */ +static struct region_cfp_table region_cfp_table[] = { + {0x10, /*US FCC */ + channel_freq_power_US_BG, + sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + } + , + {0x20, /*CANADA IC */ + channel_freq_power_US_BG, + sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), + } + , + {0x30, /*EU*/ channel_freq_power_EU_BG, + sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power), + } + , + {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, + sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power), + } + , + {0x32, /*FRANCE*/ channel_freq_power_FR_BG, + sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power), + } + , + {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, + sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power), + } + , +/*Add new region here */ +}; + +/** + * the rates supported by the card + */ +u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] = + { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, + 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 +}; + +/** + * the rates supported + */ +u8 libertas_supported_rates[G_SUPPORTED_RATES] = + { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0 }; + +/** + * the rates supported for ad-hoc G mode + */ +u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = + { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, +0 }; + +/** + * the rates supported for ad-hoc B mode + */ +u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; + +/** + * the global variable of a pointer to wlan_private + * structure variable + */ +static wlan_private *wlanpriv = NULL; + +/** + * the table to keep region code + */ +u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = + { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; + +static u8 *default_fw_name = "usb8388.bin"; +extern u8 *libertas_fw_name; + +/** + * @brief This function opens the network device + * + * @param dev A pointer to net_device structure + * @return WLAN_STATUS_SUCCESS + */ +static int wlan_open(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv; + wlan_adapter *adapter = priv->adapter; + int i = 0; + + ENTER(); + + /* For USB adapter, on some systems the device open handler will be + * called before FW ready. Use the following flag check and wait + * function to work around the issue. + */ + while (!adapter->fw_ready && i < 20) { + i++; + msleep_interruptible(100); + } + if (!adapter->fw_ready) { + PRINTM(FATAL, + "FW not ready, wlan_open() return failure\n"); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + priv->open = 1; + + if (adapter->MediaConnectStatus == WlanMediaStateConnected) { + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + } else + netif_carrier_off(priv->wlan_dev.netdev); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function closes the network device + * + * @param dev A pointer to net_device structure + * @return WLAN_STATUS_SUCCESS + */ +static int wlan_close(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + + ENTER(); + + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + + priv->open = 0; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +#ifdef ENABLE_PM + +/** + * @brief This function is a callback function. it is called by + * kernel to enter or exit power saving mode. + * + * @param pmdev A pointer to pm_dev + * @param pmreq pm_request_t + * @param pmdata A pointer to pmdata + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq, + void *pmdata) +{ + wlan_private *priv = wlanpriv; + wlan_adapter *Adapter = priv->adapter; + struct net_device *dev = priv->wlan_dev.netdev; + + PRINTM(INFO, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq); + + switch (pmreq) { + case PM_SUSPEND: + PRINTM(INFO, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n"); + + /* in associated mode */ + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + if ((Adapter->PSState != PS_STATE_SLEEP) + ) { + PRINTM(INFO, + "wlan_pm_callback: can't enter sleep mode\n"); + return WLAN_STATUS_FAILURE; + } else { + + /* + * Detach the network interface + * if the network is running + */ + if (netif_running(dev)) { + netif_device_detach(dev); + PRINTM(INFO, + "netif_device_detach().\n"); + } + libertas_sbi_suspend(priv); + } + break; + } + + /* in non associated mode */ + + /* + * Detach the network interface + * if the network is running + */ + if (netif_running(dev)) + netif_device_detach(dev); + + /* + * Storing and restoring of the regs be taken care + * at the driver rest will be done at wlan driver + * this makes driver independent of the card + */ + + libertas_sbi_suspend(priv); + + break; + + case PM_RESUME: + /* in associated mode */ + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + { + /* + * Bring the inteface up first + * This case should not happen still ... + */ + libertas_sbi_resume(priv); + + /* + * Attach the network interface + * if the network is running + */ + if (netif_running(dev)) { + netif_device_attach(dev); + PRINTM(INFO, + "after netif_device_attach().\n"); + } + PRINTM(INFO, + "After netif attach, in associated mode.\n"); + } + break; + } + + /* in non associated mode */ + + /* + * Bring the inteface up first + * This case should not happen still ... + */ + + libertas_sbi_resume(priv); + + if (netif_running(dev)) + netif_device_attach(dev); + + PRINTM(INFO, "after netif attach, in NON associated mode.\n"); + break; + } + + return WLAN_STATUS_SUCCESS; +} +#endif /* ENABLE_PM */ + +/** + * @brief This function handles packet transmission + * + * @param skb A pointer to sk_buff structure + * @param dev A pointer to net_device structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret = 0; + wlan_private *priv = dev->priv; + + ENTER(); + + if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) { + priv->stats.tx_dropped++; + goto done; + } + + netif_stop_queue(priv->wlan_dev.netdev); + + if (libertas_process_tx(priv, skb) == 0) + dev->trans_start = jiffies; +done: + LEAVE(); + return ret; +} + +/** + * @brief This function handles the timeout of packet + * transmission + * + * @param dev A pointer to net_device structure + * @return n/a + */ +static void wlan_tx_timeout(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv; + + ENTER(); + + PRINTM(FATAL, "tx watch dog timeout!\n"); + + priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; + dev->trans_start = jiffies; + + if (priv->adapter->CurrentTxSkb) { + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + /* If we are here, we have not received feedback from + the previous packet. Assume TX_FAIL and move on. */ + priv->adapter->EventCause = 0x01000000; + libertas_send_tx_feedback(priv); + } else + wake_up_interruptible(&priv->MainThread.waitQ); + } else if (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) + netif_wake_queue(priv->wlan_dev.netdev); + + LEAVE(); +} + +/** + * @brief This function returns the network statistics + * + * @param dev A pointer to wlan_private structure + * @return A pointer to net_device_stats structure + */ +static struct net_device_stats *wlan_get_stats(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) dev->priv; + + return &priv->stats; +} + +/** + * @brief This function sets the MAC address to firmware. + * + * @param priv A pointer to wlan_private structure + * @param pRxPD A pointer to RxPD structure of received packet + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_set_mac_address(struct net_device *dev, void *addr) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = (wlan_private *) dev->priv; + wlan_adapter *Adapter = priv->adapter; + struct sockaddr *pHwAddr = (struct sockaddr *)addr; + + ENTER(); + + memset(Adapter->CurrentAddr, 0, ETH_ALEN); + + /* dev->dev_addr is 8 bytes */ + HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN); + + HEXDUMP("addr:", pHwAddr->sa_data, ETH_ALEN); + memcpy(Adapter->CurrentAddr, pHwAddr->sa_data, ETH_ALEN); + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_MAC_ADDRESS, + HostCmd_ACT_SET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + PRINTM(INFO, "set mac address failed.\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + HEXDUMP("Adapter->MacAddr:", Adapter->CurrentAddr, ETH_ALEN); + memcpy(dev->dev_addr, Adapter->CurrentAddr, ETH_ALEN); + + done: + LEAVE(); + return ret; +} + +static int wlan_copy_multicast_address(wlan_adapter * Adapter, + struct net_device *dev) +{ + int i = 0; + struct dev_mc_list *mcptr = dev->mc_list; + + for (i = 0; i < dev->mc_count; i++) { + memcpy(&Adapter->MulticastList[i], mcptr->dmi_addr, ETH_ALEN); + mcptr = mcptr->next; + } + + return i; + +} + +/** + * @brief This function sets multicast addresses to firmware + * + * @param dev A pointer to net_device structure + * @return n/a + */ +static void wlan_set_multicast_list(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int OldPacketFilter; + + ENTER(); + + OldPacketFilter = Adapter->CurrentPacketFilter; + + if (dev->flags & IFF_PROMISC) { + PRINTM(INFO, "Enable Promiscuous mode\n"); + Adapter->CurrentPacketFilter |= + HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + Adapter->CurrentPacketFilter &= + ~(HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE | + HostCmd_ACT_MAC_MULTICAST_ENABLE); + } else { + /* Multicast */ + Adapter->CurrentPacketFilter &= + ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; + + if (dev->flags & IFF_ALLMULTI || dev->mc_count > + MRVDRV_MAX_MULTICAST_LIST_SIZE) { + PRINTM(INFO, "Enabling All Multicast!\n"); + Adapter->CurrentPacketFilter |= + HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + Adapter->CurrentPacketFilter &= + ~HostCmd_ACT_MAC_MULTICAST_ENABLE; + } else { + Adapter->CurrentPacketFilter &= + ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; + + if (!dev->mc_count) { + PRINTM(INFO, "No multicast addresses - " + "disabling multicast!\n"); + Adapter->CurrentPacketFilter &= + ~HostCmd_ACT_MAC_MULTICAST_ENABLE; + } else { + int i; + + Adapter->CurrentPacketFilter |= + HostCmd_ACT_MAC_MULTICAST_ENABLE; + + Adapter->NumOfMulticastMACAddr = + wlan_copy_multicast_address(Adapter, dev); + + PRINTM(INFO, "Multicast addresses: %d\n", + dev->mc_count); + + for (i = 0; i < dev->mc_count; i++) { + PRINTM(INFO, "Multicast address %d:" + "%x %x %x %x %x %x\n", i, + Adapter->MulticastList[i][0], + Adapter->MulticastList[i][1], + Adapter->MulticastList[i][2], + Adapter->MulticastList[i][3], + Adapter->MulticastList[i][4], + Adapter->MulticastList[i][5]); + } + /* set multicast addresses to firmware */ + libertas_prepare_and_send_command(priv, + HostCmd_CMD_MAC_MULTICAST_ADR, + HostCmd_ACT_GEN_SET, 0, 0, + NULL); + } + } + } + + if (Adapter->CurrentPacketFilter != OldPacketFilter) { + libertas_set_mac_packet_filter(priv); + } + + LEAVE(); +} + +/** + * @brief This function hanldes the major job in WLAN driver. + * it handles the event generated by firmware, rx data received + * from firmware and tx data sent from kernel. + * + * @param data A pointer to wlan_thread structure + * @return WLAN_STATUS_SUCCESS + */ +static int wlan_service_main_thread(void *data) +{ + unsigned long flags; + struct wlan_thread *thread = data; + wlan_private *priv = thread->priv; + wlan_adapter *Adapter = priv->adapter; + wait_queue_t wait; + u8 ireg = 0; + + ENTER(); + + wlan_activate_thread(thread); + + init_waitqueue_entry(&wait, current); + + for (;;) { + PRINTM(INFO, "main-thread 111: IntCounter=%d " + "CurrentTxSkb=%p dnld_sent=%d\n", + Adapter->IntCounter, + Adapter->CurrentTxSkb, priv->wlan_dev.dnld_sent); + + add_wait_queue(&thread->waitQ, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + if ((Adapter->PSState == PS_STATE_SLEEP) || + (!Adapter->IntCounter + && (priv->wlan_dev.dnld_sent || Adapter->CurCmd || + list_empty(&Adapter->CmdPendingQ)) + ) + ) { + PRINTM(INFO, + "main-thread sleeping... Conn=%d IntC=%d PS_Mode=%d PS_State=%d\n", + Adapter->MediaConnectStatus, Adapter->IntCounter, + Adapter->PSMode, Adapter->PSState); + + schedule(); + } + + PRINTM(INFO, + "main-thread 222 (waking up): IntCounter=%d CurrentTxSkb=%p " + "dnld_sent=%d\n", Adapter->IntCounter, + Adapter->CurrentTxSkb, priv->wlan_dev.dnld_sent); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&thread->waitQ, &wait); + try_to_freeze(); + + PRINTM(INFO, "main-thread 333: IntCounter=%d CurrentTxSkb=%p " + "dnld_sent=%d\n", + Adapter->IntCounter, + Adapter->CurrentTxSkb, priv->wlan_dev.dnld_sent); + + if (kthread_should_stop() + || Adapter->SurpriseRemoved) { + PRINTM(INFO, + "main-thread: break from main thread: SurpriseRemoved=0x%x\n", + Adapter->SurpriseRemoved); + break; + } + + if (Adapter->IntCounter) { + u8 int_status; + + spin_lock_irqsave(&libertas_driver_lock, flags); + Adapter->IntCounter = 0; + int_status = libertas_sbi_get_int_status(priv, &ireg); + spin_unlock_irqrestore(&libertas_driver_lock, flags); + + if (int_status) { + PRINTM(INFO, + "main-thread: reading HOST_INT_STATUS_REG failed\n"); + continue; + } + spin_lock_irqsave(&libertas_driver_lock, flags); + Adapter->HisRegCpy |= ireg; + spin_unlock_irqrestore(&libertas_driver_lock, flags); + } + + PRINTM(INFO, "main-thread 444: IntCounter=%d CurrentTxSkb=%p " + "dnld_sent=%d\n", + Adapter->IntCounter, + Adapter->CurrentTxSkb, priv->wlan_dev.dnld_sent); + + /* Command response? */ + if (Adapter->HisRegCpy & HIS_CmdUpLdRdy) { + PRINTM(INFO, "main-thread: Cmd response ready.\n"); + + spin_lock_irqsave(&libertas_driver_lock, flags); + Adapter->HisRegCpy &= ~HIS_CmdUpLdRdy; + spin_unlock_irqrestore(&libertas_driver_lock, flags); + + libertas_process_rx_command(priv); + } + + /* Any Card Event */ + if (Adapter->HisRegCpy & HIS_CardEvent) { + PRINTM(INFO, "main-thread: Card Event Activity.\n"); + + spin_lock_irqsave(&libertas_driver_lock, flags); + Adapter->HisRegCpy &= ~HIS_CardEvent; + spin_unlock_irqrestore(&libertas_driver_lock, flags); + + if (libertas_sbi_read_event_cause(priv)) { + PRINTM(MSG, + "main-thread: libertas_sbi_read_event_cause failed.\n"); + continue; + } + libertas_process_event(priv); + } + + /* Check if we need to confirm Sleep Request received previously */ + if (Adapter->PSState == PS_STATE_PRE_SLEEP) { + if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) { + if (Adapter->MediaConnectStatus == + WlanMediaStateConnected) { + PRINTM(INFO, + "main_thread: PRE_SLEEP--IntCounter=%d CurrentTxSkb=%p " + "dnld_sent=%d CurCmd=%p, confirm now\n", + Adapter->IntCounter, + Adapter->CurrentTxSkb, + priv->wlan_dev.dnld_sent, + Adapter->CurCmd); + + libertas_ps_confirm_sleep(priv, + (u16) Adapter->PSMode); + } else { + /* workaround for firmware sending deauth/linkloss event + immediately after sleep request, remove this after + firmware fixes it */ + Adapter->PSState = PS_STATE_AWAKE; + PRINTM(MSG, + "main-thread: ignore PS_SleepConfirm in non-connected state\n"); + } + } + } + + /* The PS state is changed during processing of Sleep Request event above */ + if ((priv->adapter->PSState == PS_STATE_SLEEP) + || (priv->adapter->PSState == PS_STATE_PRE_SLEEP) + ) { + continue; + } + + /* Execute the next command */ + if (!priv->wlan_dev.dnld_sent && !Adapter->CurCmd) { + libertas_execute_next_command(priv); + } + + libertas_tx_runqueue(priv); + + } + + wlan_deactivate_thread(thread); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function adds the card. it will probe the + * card, allocate the wlan_priv and initialize the device. + * + * @param card A pointer to card + * @return A pointer to wlan_private structure + */ +static wlan_private *wlan_add_card(void *card) +{ + struct net_device *dev = NULL; + wlan_private *priv = NULL; + + ENTER(); + + /* probe the card */ + if (libertas_sbi_probe_card(card) < 0) { + PRINTM(MSG, "NO card found!\n"); + return NULL; + } + + /* Allocate an Ethernet device and register it */ + if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { + PRINTM(MSG, "Init ethernet device failed!\n"); + return NULL; + } + + priv = dev->priv; + + /* allocate buffer for wlan_adapter */ + if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) { + PRINTM(MSG, "Allocate buffer for wlan_adapter failed!\n"); + goto err_kmalloc; + } + + /* init wlan_adapter */ + memset(priv->adapter, 0, sizeof(wlan_adapter)); + + priv->wlan_dev.netdev = dev; + priv->wlan_dev.card = card; + wlanpriv = priv; + + SET_MODULE_OWNER(dev); + + /* Setup the OS Interface to our functions */ + dev->open = wlan_open; + dev->hard_start_xmit = wlan_hard_start_xmit; + dev->stop = wlan_close; + dev->do_ioctl = libertas_do_ioctl; + dev->set_mac_address = wlan_set_mac_address; + +#define WLAN_WATCHDOG_TIMEOUT (5 * HZ) + + dev->tx_timeout = wlan_tx_timeout; + dev->get_stats = wlan_get_stats; + dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT; + +#ifdef WIRELESS_EXT + dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; +#endif +#define NETIF_F_DYNALLOC 16 + dev->features |= NETIF_F_DYNALLOC; + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->set_multicast_list = wlan_set_multicast_list; + + init_waitqueue_head(&priv->adapter->ds_awake_q); + + INIT_LIST_HEAD(&priv->adapter->CmdFreeQ); + INIT_LIST_HEAD(&priv->adapter->CmdPendingQ); + + PRINTM(INFO, "Starting kthread...\n"); + priv->MainThread.priv = priv; + wlan_create_thread(wlan_service_main_thread, + &priv->MainThread, "wlan_main_service"); + +#ifdef REASSOCIATION + priv->ReassocThread.priv = priv; + wlan_create_thread(libertas_reassociation_thread, + &priv->ReassocThread, "wlan_reassoc_service"); +#endif /* REASSOCIATION */ + + /* + * Register the device. Fillup the private data structure with + * relevant information from the card and request for the required + * IRQ. + */ + if (libertas_sbi_register_dev(priv) < 0) { + PRINTM(FATAL, "Failed to register wlan device!\n"); + goto err_registerdev; + } + + /* Get the CIS Table */ + libertas_sbi_get_cis_info(priv); + + /* init FW and HW */ + if (libertas_init_fw(priv)) { + PRINTM(INFO, "Firmware Init Failed\n"); + goto err_registerdev; + } + + if (register_netdev(dev)) { + printk(KERN_ERR "Cannot register network device!\n"); + goto err_init_fw; + } + + PRINTM(WARN, "%s: Marvell Wlan 802.11 Adapter " + "revision 0x%02X at IRQ %i\n", dev->name, + priv->adapter->chip_rev, dev->irq); + + libertas_debugfs_init_one(priv, dev); + +#ifdef ENABLE_PM + if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback))) + PRINTM(MSG, "Failed to register PM callback\n"); +#endif + + LEAVE(); + return priv; + +err_init_fw: + libertas_sbi_unregister_dev(priv); +err_registerdev: + /* Stop the thread servicing the interrupts */ + wake_up_interruptible(&priv->MainThread.waitQ); + wlan_terminate_thread(&priv->MainThread); +#ifdef REASSOCIATION + wake_up_interruptible(&priv->ReassocThread.waitQ); + wlan_terminate_thread(&priv->ReassocThread); +#endif /* REASSOCIATION */ + kfree(priv->adapter); +err_kmalloc: + free_netdev(dev); + wlanpriv = NULL; + + LEAVE(); + return NULL; +} + +/** + * @brief This function removes the card. + * + * @param priv A pointer to card + * @return WLAN_STATUS_SUCCESS + */ +static int wlan_remove_card(void *card) +{ + wlan_private *priv = wlanpriv; + wlan_adapter *Adapter; + struct net_device *dev; + union iwreq_data wrqu; + + ENTER(); + + if (!priv) { + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + Adapter = priv->adapter; + + if (!Adapter) { + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + dev = priv->wlan_dev.netdev; + + wake_up_interruptible(&Adapter->ds_awake_q); + + if (Adapter->CurCmd) { + PRINTM(INFO, "Wake up current cmdwait_q\n"); + wake_up_interruptible(&Adapter->CurCmd->cmdwait_q); + } + + Adapter->CurCmd = NULL; + + if (Adapter->PSMode == Wlan802_11PowerModeMAX_PSP) { + Adapter->PSMode = Wlan802_11PowerModeCAM; + libertas_ps_wakeup(priv, HostCmd_OPTION_WAITFORRSP); + } + + memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); + + /* Disable interrupts on the card as we cannot handle them after RESET */ + libertas_sbi_disable_host_int(priv); + + libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RESET, + HostCmd_ACT_HALT, 0, 0, NULL); + + msleep_interruptible(200); + +#ifdef ENABLE_PM + pm_unregister(wlan_pm_dev); +#endif + + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + + Adapter->SurpriseRemoved = 1; + + /* Stop the thread servicing the interrupts */ + wake_up_interruptible(&priv->MainThread.waitQ); + +#ifdef REASSOCIATION + wake_up_interruptible(&priv->ReassocThread.waitQ); +#endif /* REASSOCIATION */ + + libertas_debugfs_remove_one(priv); + + PRINTM(INFO, "unregister dev\n"); + libertas_sbi_unregister_dev(priv); + + PRINTM(INFO, "Free Adapter\n"); + libertas_free_adapter(priv); + + /* Last reference is our one */ + PRINTM(INFO, "refcnt = %d\n", atomic_read(&dev->refcnt)); + + msleep(10); + + PRINTM(INFO, "netdev_finish_unregister: %s%s.\n", dev->name, + (dev->features & NETIF_F_DYNALLOC) ? "" : ", old style"); + + unregister_netdev(dev); + + PRINTM(INFO, "Unregister finish\n"); + + priv->wlan_dev.netdev = NULL; + free_netdev(dev); + wlanpriv = NULL; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function finds the CFP in + * region_cfp_table based on region and band parameter. + * + * @param region The region code + * @param band The band + * @param cfp_no A pointer to CFP number + * @return A pointer to CFP + */ +struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no) +{ + int i, end; + + ENTER(); + + end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table); + + for (i = 0; i < end ; i++) { + PRINTM(INFO, "region_cfp_table[i].region=%d\n", + region_cfp_table[i].region); + if (region_cfp_table[i].region == region) { + *cfp_no = region_cfp_table[i].cfp_no_BG; + LEAVE(); + return region_cfp_table[i].cfp_BG; + } + } + + LEAVE(); + return NULL; +} + +/** + * @brief This function sets region table. + * + * @param priv A pointer to wlan_private structure + * @param region The region code + * @param band The band + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band) +{ + wlan_adapter *Adapter = priv->adapter; + int i = 0; + + struct chan_freq_power *cfp; + int cfp_no; + + ENTER(); + + memset(Adapter->region_channel, 0, sizeof(Adapter->region_channel)); + + { + cfp = libertas_get_region_cfp_table(region, band, &cfp_no); + if (cfp != NULL) { + Adapter->region_channel[i].NrCFP = cfp_no; + Adapter->region_channel[i].CFP = cfp; + } else { + PRINTM(INFO, "wrong region code %#x in Band B-G\n", + region); + return WLAN_STATUS_FAILURE; + } + Adapter->region_channel[i].Valid = 1; + Adapter->region_channel[i].Region = region; + Adapter->region_channel[i].Band = band; + i++; + } + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the interrupt. it will change PS + * state if applicable. it will wake up main_thread to handle + * the interrupt event as well. + * + * @param dev A pointer to net_device structure + * @return n/a + */ +void libertas_interrupt(struct net_device *dev) +{ + wlan_private *priv = dev->priv; + + ENTER(); + + PRINTM(INFO, "libertas_interrupt: IntCounter=%d\n", + priv->adapter->IntCounter); + + priv->adapter->IntCounter++; + + if (priv->adapter->PSState == PS_STATE_SLEEP) { + priv->adapter->PSState = PS_STATE_AWAKE; + netif_wake_queue(dev); + } + + wake_up_interruptible(&priv->MainThread.waitQ); + + LEAVE(); +} + +/** + * @brief This function initializes module. + * + * @param n/a A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int wlan_init_module(void) +{ + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + + if (libertas_fw_name == NULL) { + libertas_fw_name = default_fw_name; + } + + if (libertas_sbi_register(wlan_add_card, wlan_remove_card, NULL) == NULL) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + libertas_debugfs_init(); + +done: + LEAVE(); + return ret; +} + +/** + * @brief This function cleans module + * + * @param priv n/a + * @return n/a + */ +static void wlan_cleanup_module(void) +{ + ENTER(); + + libertas_sbi_unregister(); + libertas_debugfs_remove(); + + LEAVE(); +} + +module_init(wlan_init_module); +module_exit(wlan_cleanup_module); + +MODULE_DESCRIPTION("M-WLAN Driver"); +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_LICENSE("GPL"); diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_rx.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_rx.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_rx.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_rx.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,482 @@ +/** @file wlan_rx.c + * @brief This file contains the handling of RX in wlan driver. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 09/28/05: Add Doxygen format comments + 12/09/05: ADD Sliding window SNR/NF Average Calculation support + +********************************************************/ + +#include <linux/etherdevice.h> +#include <linux/types.h> + +#include "hostcmd.h" +#include "radiotap.h" +#include "wlan_decl.h" +#include "wlan_dev.h" +#include "wlan_wext.h" + +struct Eth803Hdr { + u8 dest_addr[6]; + u8 src_addr[6]; + u16 h803_len; +} __attribute__ ((packed)); + +struct Rfc1042Hdr { + u8 llc_dsap; + u8 llc_ssap; + u8 llc_ctrl; + u8 snap_oui[3]; + u16 snap_type; +} __attribute__ ((packed)); + +struct RxPacketHdr { + struct RxPD rx_pd; + struct Eth803Hdr eth803_hdr; + struct Rfc1042Hdr rfc1042_hdr; +} __attribute__ ((packed)); + +struct Rx80211PacketHdr { + struct RxPD rx_pd; + void *eth80211_hdr; +} __attribute__ ((packed)); + +static int ProcessRxed_802_11_Packet(wlan_private * priv, struct sk_buff *skb); + +/** + * @brief This function computes the AvgSNR . + * + * @param priv A pointer to wlan_private structure + * @return AvgSNR + */ +static u8 wlan_getAvgSNR(wlan_private * priv) +{ + u8 i; + u16 temp = 0; + wlan_adapter *Adapter = priv->adapter; + if (Adapter->numSNRNF == 0) + return 0; + for (i = 0; i < Adapter->numSNRNF; i++) + temp += Adapter->rawSNR[i]; + return (u8) (temp / Adapter->numSNRNF); + +} + +/** + * @brief This function computes the AvgNF + * + * @param priv A pointer to wlan_private structure + * @return AvgNF + */ +static u8 wlan_getAvgNF(wlan_private * priv) +{ + u8 i; + u16 temp = 0; + wlan_adapter *Adapter = priv->adapter; + if (Adapter->numSNRNF == 0) + return 0; + for (i = 0; i < Adapter->numSNRNF; i++) + temp += Adapter->rawNF[i]; + return (u8) (temp / Adapter->numSNRNF); + +} + +/** + * @brief This function save the raw SNR/NF to our internel buffer + * + * @param priv A pointer to wlan_private structure + * @param pRxPD A pointer to RxPD structure of received packet + * @return n/a + */ +static void wlan_save_rawSNRNF(wlan_private * priv, struct RxPD *pRxPD) +{ + wlan_adapter *Adapter = priv->adapter; + if (Adapter->numSNRNF < Adapter->data_avg_factor) + Adapter->numSNRNF++; + Adapter->rawSNR[Adapter->nextSNRNF] = pRxPD->SNR; + Adapter->rawNF[Adapter->nextSNRNF] = pRxPD->NF; + Adapter->nextSNRNF++; + if (Adapter->nextSNRNF >= Adapter->data_avg_factor) + Adapter->nextSNRNF = 0; + return; +} + +/** + * @brief This function computes the RSSI in received packet. + * + * @param priv A pointer to wlan_private structure + * @param pRxPD A pointer to RxPD structure of received packet + * @return n/a + */ +static void wlan_compute_rssi(wlan_private * priv, struct RxPD *pRxPD) +{ + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + PRINTM(INFO, "RxPD: SNR = %d, NF = %d\n", pRxPD->SNR, pRxPD->NF); + PRINTM(INFO, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n", + Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + + Adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = pRxPD->SNR; + Adapter->NF[TYPE_RXPD][TYPE_NOAVG] = pRxPD->NF; + wlan_save_rawSNRNF(priv, pRxPD); + + Adapter->RxPDSNRAge = jiffies; + Adapter->RxPDRate = pRxPD->RxRate; + + Adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getAvgSNR(priv) * AVG_SCALE; + Adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getAvgNF(priv) * AVG_SCALE; + PRINTM(INFO, "After computing SNR: SNR-avg = %d, NF-avg = %d\n", + Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + + Adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] = + CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG], + Adapter->NF[TYPE_RXPD][TYPE_NOAVG]); + + Adapter->RSSI[TYPE_RXPD][TYPE_AVG] = + CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + + LEAVE(); +} + +/******************************************************** + Global functions +********************************************************/ + +int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) +{ + PRINTM(INFO, "skb->data=%p\n", skb->data); + + skb->dev = priv->wlan_dev.netdev; + skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); + + return 0; +} + +/** + * @brief This function processes received packet and forwards it + * to kernel/upper layer + * + * @param priv A pointer to wlan_private + * @param skb A pointer to skb which includes the received packet + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + struct RxPacketHdr *pRxPkt; + struct RxPD *pRxPD; + + int hdrChop; + struct EthII_Hdr *pEthHdr; + + const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + ENTER(); + + if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH) + HEXDUMP("RX packet: ", skb->data, + min_t(unsigned int, skb->len, 100)); + + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + return ProcessRxed_802_11_Packet(priv, skb); + + pRxPkt = (struct RxPacketHdr *) skb->data; + pRxPD = &pRxPkt->rx_pd; + + HEXDUMP("RX Data: Before chop RxPD", skb->data, + min_t(unsigned int, skb->len, 100)); + + if (skb->len < (ETH_HLEN + 8 + sizeof(struct RxPD))) { + PRINTM(INFO, "RX Error: FRAME RECEIVED WITH BAD LENGTH\n"); + priv->stats.rx_length_errors++; + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + /* + * Check RxPD status and update 802.3 stat, + */ + if (!(pRxPD->Status & MRVDRV_RXPD_STATUS_OK)) { + PRINTM(INFO, "RX Error: frame received with bad status\n"); + printk("<1> RxPD Not OK\n"); + priv->stats.rx_errors++; + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + PRINTM(INFO, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", + skb->len, sizeof(struct RxPD), skb->len - sizeof(struct RxPD)); + + HEXDUMP("RX Data: Dest", pRxPkt->eth803_hdr.dest_addr, + sizeof(pRxPkt->eth803_hdr.dest_addr)); + HEXDUMP("RX Data: Src", pRxPkt->eth803_hdr.src_addr, + sizeof(pRxPkt->eth803_hdr.src_addr)); + + if (memcmp(&pRxPkt->rfc1042_hdr, + rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { + /* + * Replace the 803 header and rfc1042 header (llc/snap) with an + * EthernetII header, keep the src/dst and snap_type (ethertype) + * + * The firmware only passes up SNAP frames converting + * all RX Data from 802.11 to 802.2/LLC/SNAP frames. + * + * To create the Ethernet II, just move the src, dst address right + * before the snap_type. + */ + pEthHdr = (struct EthII_Hdr *) + ((u8 *) & pRxPkt->eth803_hdr + + sizeof(pRxPkt->eth803_hdr) + sizeof(pRxPkt->rfc1042_hdr) + - sizeof(pRxPkt->eth803_hdr.dest_addr) + - sizeof(pRxPkt->eth803_hdr.src_addr) + - sizeof(pRxPkt->rfc1042_hdr.snap_type)); + + memcpy(pEthHdr->src_addr, pRxPkt->eth803_hdr.src_addr, + sizeof(pEthHdr->src_addr)); + memcpy(pEthHdr->dest_addr, pRxPkt->eth803_hdr.dest_addr, + sizeof(pEthHdr->dest_addr)); + + /* Chop off the RxPD + the excess memory from the 802.2/llc/snap header + * that was removed + */ + hdrChop = (u8 *) pEthHdr - (u8 *) pRxPkt; + } else { + HEXDUMP("RX Data: LLC/SNAP", + (u8 *) & pRxPkt->rfc1042_hdr, + sizeof(pRxPkt->rfc1042_hdr)); + + /* Chop off the RxPD */ + hdrChop = (u8 *) & pRxPkt->eth803_hdr - (u8 *) pRxPkt; + } + + /* Chop off the leading header bytes so the skb points to the start of + * either the reconstructed EthII frame or the 802.2/llc/snap frame + */ + skb_pull(skb, hdrChop); + + /* Take the data rate from the RxPD structure + * only if the rate is auto + */ + if (Adapter->Is_DataRate_Auto) { + Adapter->DataRate = libertas_index_to_data_rate(pRxPD->RxRate); + } + + wlan_compute_rssi(priv, pRxPD); + + PRINTM(INFO, "RX Data: Size of actual packet = %d\n", skb->len); + if (libertas_upload_rx_packet(priv, skb)) { + PRINTM(INFO, "RX Error: libertas_upload_rx_packet" + " returns failure\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + + return (ret); +} + +/** + * @brief This function converts Tx/Rx rates from the Marvell WLAN format + * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) + * + * @param rate Input rate + * @return Output Rate (0 if invalid) + */ +static u8 convert_mv_rate_to_radiotap(u8 rate) +{ + switch (rate) { + case 0: /* 1 Mbps */ + return 2; + case 1: /* 2 Mbps */ + return 4; + case 2: /* 5.5 Mbps */ + return 11; + case 3: /* 11 Mbps */ + return 22; + case 4: /* 6 Mbps */ + return 12; + case 5: /* 9 Mbps */ + return 18; + case 6: /* 12 Mbps */ + return 24; + case 7: /* 18 Mbps */ + return 36; + case 8: /* 24 Mbps */ + return 48; + case 9: /* 36 Mbps */ + return 72; + case 10: /* 48 Mbps */ + return 96; + case 11: /* 54 Mbps */ + return 108; + } + PRINTM(MSG, "Invalid Marvell WLAN rate (%i)\n", rate); + return 0; +} + +/** + * @brief This function processes a received 802.11 packet and forwards it + * to kernel/upper layer + * + * @param priv A pointer to wlan_private + * @param skb A pointer to skb which includes the received packet + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int ProcessRxed_802_11_Packet(wlan_private * priv, struct sk_buff *skb) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + struct Rx80211PacketHdr *pRxPkt; + struct RxPD *pRxPD; + struct RxRadiotapHdr radiotap_hdr; + struct RxRadiotapHdr *pradiotap_hdr; + + ENTER(); + + pRxPkt = (struct Rx80211PacketHdr *) skb->data; + pRxPD = &pRxPkt->rx_pd; + + // HEXDUMP("RX Data: Before chop RxPD", skb->data, min(skb->len, 100)); + + if (skb->len < (ETH_HLEN + 8 + sizeof(struct RxPD))) { + PRINTM(INFO, "RX Error: FRAME RECEIVED WITH BAD LENGTH\n"); + priv->stats.rx_length_errors++; + ret = WLAN_STATUS_SUCCESS; + goto done; + } + + /* + * Check RxPD status and update 802.3 stat, + */ + if (!(pRxPD->Status & MRVDRV_RXPD_STATUS_OK)) { + //PRINTM(INFO, "RX Error: frame received with bad status\n"); + priv->stats.rx_errors++; + } + + PRINTM(INFO, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", + skb->len, sizeof(struct RxPD), skb->len - sizeof(struct RxPD)); + + /* create the exported radio header */ + switch (priv->adapter->radiomode) { + case WLAN_RADIOMODE_NONE: + /* no radio header */ + /* chop the RxPD */ + skb_pull(skb, sizeof(struct RxPD)); + break; + + case WLAN_RADIOMODE_RADIOTAP: + /* radiotap header */ + radiotap_hdr.hdr.it_version = 0; + /* XXX must check this value for pad */ + radiotap_hdr.hdr.it_pad = 0; + radiotap_hdr.hdr.it_len = sizeof(struct RxRadiotapHdr); + radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT; + /* unknown values */ + radiotap_hdr.flags = 0; + radiotap_hdr.chan_freq = 0; + radiotap_hdr.chan_flags = 0; + radiotap_hdr.antenna = 0; + /* known values */ + radiotap_hdr.rate = convert_mv_rate_to_radiotap(pRxPD->RxRate); + /* XXX must check no carryout */ + radiotap_hdr.antsignal = pRxPD->SNR + pRxPD->NF; + radiotap_hdr.rx_flags = 0; + if (!(pRxPD->Status & MRVDRV_RXPD_STATUS_OK)) + radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; + //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); + + // HEXDUMP1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100)); + + /* chop the RxPD */ + skb_pull(skb, sizeof(struct RxPD)); + + /* add space for the new radio header */ + if ((skb_headroom(skb) < sizeof(struct RxRadiotapHdr)) && + pskb_expand_head(skb, sizeof(struct RxRadiotapHdr), 0, + GFP_ATOMIC)) { + PRINTM(MSG, "%s: couldn't pskb_expand_head\n", + __func__); + } + + pradiotap_hdr = + (struct RxRadiotapHdr *)skb_push(skb, + sizeof(struct + RxRadiotapHdr)); + memcpy(pradiotap_hdr, &radiotap_hdr, + sizeof(struct RxRadiotapHdr)); + //HEXDUMP1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100)); + break; + + default: + /* unknown header */ + PRINTM(MSG, "Unknown radiomode (%i)\n", + priv->adapter->radiomode); + /* don't export any header */ + /* chop the RxPD */ + skb_pull(skb, sizeof(struct RxPD)); + break; + } + + /* Take the data rate from the RxPD structure + * only if the rate is auto + */ + if (Adapter->Is_DataRate_Auto) { + Adapter->DataRate = libertas_index_to_data_rate(pRxPD->RxRate); + } + + wlan_compute_rssi(priv, pRxPD); + + PRINTM(INFO, "RX Data: Size of actual packet = %d\n", skb->len); + + if (libertas_upload_rx_packet(priv, skb)) { + PRINTM(INFO, "RX Error: libertas_upload_rx_packet " + "returns failure\n"); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + + ret = WLAN_STATUS_SUCCESS; + done: + LEAVE(); + + skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ + + return (ret); +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_scan.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_scan.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_scan.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_scan.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,2337 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** @file wlan_scan.c + * + * @brief Functions implementing wlan scan IOCTL and firmware command APIs + * + * IOCTL handlers as well as command preperation and response routines + * for sending scan commands to the firmware. + * + * @sa wlan_scan.h + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change Log: + 01/11/06: Initial revision. New scan code, relocate related functions + 01/19/06: Update specific scan routines to discard old results for adhoc + 01/31/06: Add support for selectively enabling the FW Scan channel filter + +************************************************************/ + +#include <linux/ctype.h> +#include <linux/if.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> + +#include <net/ieee80211.h> +#include <net/iw_handler.h> + +#include "host.h" +#include "wlan_decl.h" +#include "wlan_dev.h" +#include "wlan_scan.h" + +//! Approximate amount of data needed to pass a scan result back to iwlist +#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ + + MRVDRV_MAX_SSID_LENGTH \ + + IW_EV_UINT_LEN \ + + IW_EV_FREQ_LEN \ + + IW_EV_QUAL_LEN \ + + MRVDRV_MAX_SSID_LENGTH \ + + IW_EV_PARAM_LEN \ + + 40) /* 40 for WPAIE */ + +//! Memory needed to store a max sized Channel List TLV for a firmware scan +#define CHAN_TLV_MAX_SIZE (sizeof(struct MrvlIEtypesHeader) \ + + (MRVDRV_MAX_CHANNELS_PER_SCAN \ + * sizeof(struct ChanScanParamSet))) + +//! Memory needed to store a max number/size SSID TLV for a firmware scan +#define SSID_TLV_MAX_SIZE (1 * sizeof(struct MrvlIEtypes_SsIdParamSet)) + +//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max +#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \ + + sizeof(struct MrvlIEtypes_NumProbes) \ + + CHAN_TLV_MAX_SIZE \ + + SSID_TLV_MAX_SIZE) + +//! The maximum number of channels the firmware can scan per command +#define MRVDRV_MAX_CHANNELS_PER_SCAN 14 + +/** + * @brief Number of channels to scan per firmware scan command issuance. + * + * Number restricted to prevent hitting the limit on the amount of scan data + * returned in a single firmware scan command. + */ +#define MRVDRV_CHANNELS_PER_SCAN_CMD 4 + +//! Scan time specified in the channel TLV for each channel for passive scans +#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100 + +//! Scan time specified in the channel TLV for each channel for active scans +#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 + +//! Macro to enable/disable SSID checking before storing a scan table +#ifdef DISCARD_BAD_SSID +#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.Ssid) +#else +#define CHECK_SSID_IS_VALID(x) 1 +#endif + +/** + * @brief Interally used to send a configured scan cmd between driver routines + */ +union wlan_scan_cmd_config_tlv { + struct wlan_scan_cmd_config config; //!< Scan configuration (variable length) + u8 configAllocBuf[MAX_SCAN_CFG_ALLOC]; //!< Max allocated block +}; + +/** + * @brief Check if a scanned network compatible with the driver settings + * + * WEP WPA WPA2 ad-hoc encrypt Network + * enabled enabled enabled AES mode Privacy WPA WPA2 Compatible + * 0 0 0 0 NONE 0 0 0 yes No security + * 1 0 0 0 NONE 1 0 0 yes Static WEP + * 0 1 0 0 x 1x 1 x yes WPA + * 0 0 1 0 x 1x x 1 yes WPA2 + * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES + * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP + * + * + * @param Adapter A pointer to wlan_adapter + * @param index Index in ScanTable to check against current driver settings + * @param mode Network mode: Infrastructure or IBSS + * + * @return Index in ScanTable, or error code if negative + */ +static int IsNetworkCompatible(wlan_adapter * Adapter, int index, int mode) +{ + ENTER(); + + if (Adapter->ScanTable[index].InfrastructureMode == mode) { + if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled + && !Adapter->SecInfo.WPAEnabled + && !Adapter->SecInfo.WPA2Enabled + && Adapter->ScanTable[index].wpa_supplicant.Wpa_ie[0] != + WPA_IE + && Adapter->ScanTable[index].wpa2_supplicant.Wpa_ie[0] != + WPA2_IE && Adapter->SecInfo.EncryptionMode == CIPHER_NONE + && !Adapter->ScanTable[index].Privacy) { + /* no security */ + LEAVE(); + return index; + } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled + && !Adapter->SecInfo.WPAEnabled + && !Adapter->SecInfo.WPA2Enabled + && Adapter->ScanTable[index].Privacy) { + /* static WEP enabled */ + LEAVE(); + return index; + } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled + && Adapter->SecInfo.WPAEnabled + && !Adapter->SecInfo.WPA2Enabled + && (Adapter->ScanTable[index].wpa_supplicant. + Wpa_ie[0] + == WPA_IE) + /* Privacy bit may NOT be set in some APs like LinkSys WRT54G + && Adapter->ScanTable[index].Privacy */ + ) { + /* WPA enabled */ + PRINTM(INFO, + "IsNetworkCompatible() WPA: index=%d wpa_ie=%#x " + "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x " + "privacy=%#x\n", index, + Adapter->ScanTable[index].wpa_supplicant. + Wpa_ie[0], + Adapter->ScanTable[index].wpa2_supplicant. + Wpa_ie[0], + (Adapter->SecInfo.WEPStatus == + Wlan802_11WEPEnabled) ? "e" : "d", + (Adapter->SecInfo.WPAEnabled) ? "e" : "d", + (Adapter->SecInfo.WPA2Enabled) ? "e" : "d", + Adapter->SecInfo.EncryptionMode, + Adapter->ScanTable[index].Privacy); + LEAVE(); + return index; + } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled + && !Adapter->SecInfo.WPAEnabled + && Adapter->SecInfo.WPA2Enabled + && (Adapter->ScanTable[index].wpa2_supplicant. + Wpa_ie[0] + == WPA2_IE) + /* Privacy bit may NOT be set in some APs like LinkSys WRT54G + && Adapter->ScanTable[index].Privacy */ + ) { + /* WPA2 enabled */ + PRINTM(INFO, + "IsNetworkCompatible() WPA2: index=%d wpa_ie=%#x " + "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x " + "privacy=%#x\n", index, + Adapter->ScanTable[index].wpa_supplicant. + Wpa_ie[0], + Adapter->ScanTable[index].wpa2_supplicant. + Wpa_ie[0], + (Adapter->SecInfo.WEPStatus == + Wlan802_11WEPEnabled) ? "e" : "d", + (Adapter->SecInfo.WPAEnabled) ? "e" : "d", + (Adapter->SecInfo.WPA2Enabled) ? "e" : "d", + Adapter->SecInfo.EncryptionMode, + Adapter->ScanTable[index].Privacy); + LEAVE(); + return index; + } else if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPDisabled + && !Adapter->SecInfo.WPAEnabled + && !Adapter->SecInfo.WPA2Enabled + && (Adapter->ScanTable[index].wpa_supplicant. + Wpa_ie[0] + != WPA_IE) + && (Adapter->ScanTable[index].wpa2_supplicant. + Wpa_ie[0] + != WPA2_IE) + && Adapter->SecInfo.EncryptionMode != CIPHER_NONE + && Adapter->ScanTable[index].Privacy) { + /* dynamic WEP enabled */ + PRINTM(INFO, + "IsNetworkCompatible() dynamic WEP: index=%d " + "wpa_ie=%#x wpa2_ie=%#x EncMode=%#x privacy=%#x\n", + index, + Adapter->ScanTable[index].wpa_supplicant. + Wpa_ie[0], + Adapter->ScanTable[index].wpa2_supplicant. + Wpa_ie[0], Adapter->SecInfo.EncryptionMode, + Adapter->ScanTable[index].Privacy); + LEAVE(); + return index; + } + + /* security doesn't match */ + PRINTM(INFO, + "IsNetworkCompatible() FAILED: index=%d wpa_ie=%#x " + "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n", + index, + Adapter->ScanTable[index].wpa_supplicant.Wpa_ie[0], + Adapter->ScanTable[index].wpa2_supplicant.Wpa_ie[0], + (Adapter->SecInfo.WEPStatus == + Wlan802_11WEPEnabled) ? "e" : "d", + (Adapter->SecInfo.WPAEnabled) ? "e" : "d", + (Adapter->SecInfo.WPA2Enabled) ? "e" : "d", + Adapter->SecInfo.EncryptionMode, + Adapter->ScanTable[index].Privacy); + LEAVE(); + return -ECONNREFUSED; + } + + /* mode doesn't match */ + LEAVE(); + return -ENETUNREACH; +} + +/** + * @brief This function validates a SSID as being able to be printed + * + * @param pSsid SSID structure to validate + * + * @return TRUE or FALSE + */ +static u8 ssid_valid(struct WLAN_802_11_SSID *pSsid) +{ + int ssidIdx; + + for (ssidIdx = 0; ssidIdx < pSsid->SsidLength; ssidIdx++) { + if (!isprint(pSsid->Ssid[ssidIdx])) { + return 0; + } + } + + return 1; +} + +/** + * @brief Post process the scan table after a new scan command has completed + * + * Inspect each entry of the scan table and try to find an entry that + * matches our current associated/joined network from the scan. If + * one is found, update the stored copy of the BssDescriptor for our + * current network. + * + * Debug dump the current scan table contents if compiled accordingly. + * + * @param priv A pointer to wlan_private structure + * + * @return void + */ +static void wlan_scan_process_results(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + int foundCurrent; + int i; + + foundCurrent = 0; + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + /* try to find the current BSSID in the new scan list */ + for (i = 0; i < Adapter->NumInScanTable; i++) { + if (!libertas_SSID_cmp(&Adapter->ScanTable[i].Ssid, + &Adapter->CurBssParams.ssid) && + !memcmp(Adapter->CurBssParams.bssid, + Adapter->ScanTable[i].MacAddress, + ETH_ALEN)) { + foundCurrent = 1; + } + } + + if (foundCurrent) { + /* Make a copy of current BSSID descriptor */ + memcpy(&Adapter->CurBssParams.BSSDescriptor, + &Adapter->ScanTable[i], + sizeof(Adapter->CurBssParams.BSSDescriptor)); + } + } + + for (i = 0; i < Adapter->NumInScanTable; i++) { + PRINTM(INFO, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, " + "RSSI[%03d], SSID[%s]\n", + i, + Adapter->ScanTable[i].MacAddress[0], + Adapter->ScanTable[i].MacAddress[1], + Adapter->ScanTable[i].MacAddress[2], + Adapter->ScanTable[i].MacAddress[3], + Adapter->ScanTable[i].MacAddress[4], + Adapter->ScanTable[i].MacAddress[5], + (s32) Adapter->ScanTable[i].Rssi, + Adapter->ScanTable[i].Ssid.Ssid); + } +} + +/** + * @brief Create a channel list for the driver to scan based on region info + * + * Use the driver region/band information to construct a comprehensive list + * of channels to scan. This routine is used for any scan that is not + * provided a specific channel list to scan. + * + * @param priv A pointer to wlan_private structure + * @param scanChanList Output parameter: Resulting channel list to scan + * @param filteredScan Flag indicating whether or not a BSSID or SSID filter + * is being sent in the command to firmware. Used to + * increase the number of channels sent in a scan + * command and to disable the firmware channel scan + * filter. + * + * @return void + */ +static void wlan_scan_create_channel_list(wlan_private * priv, + struct ChanScanParamSet * scanChanList, + u8 filteredScan) +{ + + wlan_adapter *Adapter = priv->adapter; + struct region_channel *scanRegion; + struct chan_freq_power *cfp; + int rgnIdx; + int chanIdx; + int nextChan; + u8 scanType; + + chanIdx = 0; + + /* Set the default scan type to the user specified type, will later + * be changed to passive on a per channel basis if restricted by + * regulatory requirements (11d or 11h) + */ + scanType = Adapter->ScanType; + + for (rgnIdx = 0; rgnIdx < NELEMENTS(Adapter->region_channel); rgnIdx++) { + if (libertas_get_state_11d(priv) == ENABLE_11D && + Adapter->MediaConnectStatus != WlanMediaStateConnected) { + /* Scan all the supported chan for the first scan */ + if (!Adapter->universal_channel[rgnIdx].Valid) + continue; + scanRegion = &Adapter->universal_channel[rgnIdx]; + + /* clear the parsed_region_chan for the first scan */ + memset(&Adapter->parsed_region_chan, 0x00, + sizeof(Adapter->parsed_region_chan)); + } else { + if (!Adapter->region_channel[rgnIdx].Valid) + continue; + scanRegion = &Adapter->region_channel[rgnIdx]; + } + + for (nextChan = 0; + nextChan < scanRegion->NrCFP; nextChan++, chanIdx++) { + + cfp = scanRegion->CFP + nextChan; + + if (libertas_get_state_11d(priv) == ENABLE_11D) { + scanType = + libertas_get_scan_type_11d(cfp->Channel, + &Adapter-> + parsed_region_chan); + } + + switch (scanRegion->Band) { + case BAND_B: + case BAND_G: + default: + scanChanList[chanIdx].RadioType = + HostCmd_SCAN_RADIO_TYPE_BG; + break; + } + + if (scanType == HostCmd_SCAN_TYPE_PASSIVE) { + scanChanList[chanIdx].MaxScanTime = + wlan_cpu_to_le16 + (MRVDRV_PASSIVE_SCAN_CHAN_TIME); + scanChanList[chanIdx].ChanScanMode.PassiveScan = + 1; + } else { + scanChanList[chanIdx].MaxScanTime = + wlan_cpu_to_le16 + (MRVDRV_ACTIVE_SCAN_CHAN_TIME); + scanChanList[chanIdx].ChanScanMode.PassiveScan = + 0; + } + + scanChanList[chanIdx].ChanNumber = cfp->Channel; + + if (filteredScan) { + scanChanList[chanIdx].ChanScanMode. + DisableChanFilt = 1; + } + } + } +} + +/** + * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds + * + * Application layer or other functions can invoke wlan_scan_networks + * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct. + * This structure is used as the basis of one or many wlan_scan_cmd_config + * commands that are sent to the command processing module and sent to + * firmware. + * + * Create a wlan_scan_cmd_config based on the following user supplied + * parameters (if present): + * - SSID filter + * - BSSID filter + * - Number of Probes to be sent + * - Channel list + * + * If the SSID or BSSID filter is not present, disable/clear the filter. + * If the number of probes is not set, use the adapter default setting + * Qualify the channel + * + * @param priv A pointer to wlan_private structure + * @param pUserScanIn NULL or pointer to scan configuration parameters + * @param pScanCfgOut Output parameter: Resulting scan configuration + * @param ppChanTlvOut Output parameter: Pointer to the start of the + * channel TLV portion of the output scan config + * @param pScanChanList Output parameter: Pointer to the resulting channel + * list to scan + * @param pMaxChanPerScan Output parameter: Number of channels to scan for + * each issuance of the firmware scan command + * @param pFilteredScan Output parameter: Flag indicating whether or not + * a BSSID or SSID filter is being sent in the + * command to firmware. Used to increase the number + * of channels sent in a scan command and to + * disable the firmware channel scan filter. + * @param pScanCurrentOnly Output parameter: Flag indicating whether or not + * we are only scanning our current active channel + * + * @return void + */ +static +void wlan_scan_setup_scan_config(wlan_private * priv, + const struct wlan_ioctl_user_scan_cfg * pUserScanIn, + struct wlan_scan_cmd_config * pScanCfgOut, + struct MrvlIEtypes_ChanListParamSet ** ppChanTlvOut, + struct ChanScanParamSet * pScanChanList, + int *pMaxChanPerScan, + u8 * pFilteredScan, u8 * pScanCurrentOnly) +{ + wlan_adapter *Adapter = priv->adapter; + const u8 zeroMac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + struct MrvlIEtypes_NumProbes *pNumProbesTlv; + struct MrvlIEtypes_SsIdParamSet *pSsidTlv; + u8 *pTlvPos; + u16 numProbes; + u16 ssidLen; + int chanIdx; + int scanType; + int scanDur; + int channel; + int radioType; + + /* The tlvBufferLen is calculated for each scan command. The TLVs added + * in this routine will be preserved since the routine that sends + * the command will append channelTLVs at *ppChanTlvOut. The difference + * between the *ppChanTlvOut and the tlvBuffer start will be used + * to calculate the size of anything we add in this routine. + */ + pScanCfgOut->tlvBufferLen = 0; + + /* Running tlv pointer. Assigned to ppChanTlvOut at end of function + * so later routines know where channels can be added to the command buf + */ + pTlvPos = pScanCfgOut->tlvBuffer; + + /* + * Set the initial scan paramters for progressive scanning. If a specific + * BSSID or SSID is used, the number of channels in the scan command + * will be increased to the absolute maximum + */ + *pMaxChanPerScan = MRVDRV_CHANNELS_PER_SCAN_CMD; + + /* Initialize the scan as un-filtered by firmware, set to TRUE below if + * a SSID or BSSID filter is sent in the command + */ + *pFilteredScan = 0; + + /* Initialize the scan as not being only on the current channel. If + * the channel list is customized, only contains one channel, and + * is the active channel, this is set true and data flow is not halted. + */ + *pScanCurrentOnly = 0; + + if (pUserScanIn) { + + /* Set the bss type scan filter, use Adapter setting if unset */ + pScanCfgOut->bssType = + (pUserScanIn->bssType ? pUserScanIn->bssType : Adapter-> + ScanMode); + + /* Set the number of probes to send, use Adapter setting if unset */ + numProbes = (pUserScanIn->numProbes ? pUserScanIn->numProbes : + Adapter->ScanProbes); + + /* + * Set the BSSID filter to the incoming configuration, + * if non-zero. If not set, it will remain disabled (all zeros). + */ + memcpy(pScanCfgOut->specificBSSID, + pUserScanIn->specificBSSID, + sizeof(pScanCfgOut->specificBSSID)); + + ssidLen = strlen(pUserScanIn->specificSSID); + + if (ssidLen) { + pSsidTlv = + (struct MrvlIEtypes_SsIdParamSet *) pScanCfgOut-> + tlvBuffer; + pSsidTlv->Header.Type = wlan_cpu_to_le16(TLV_TYPE_SSID); + pSsidTlv->Header.Len = wlan_cpu_to_le16(ssidLen); + memcpy(pSsidTlv->SsId, pUserScanIn->specificSSID, + ssidLen); + pTlvPos += sizeof(pSsidTlv->Header) + ssidLen; + } + + /* + * The default number of channels sent in the command is low to + * ensure the response buffer from the firmware does not truncate + * scan results. That is not an issue with an SSID or BSSID + * filter applied to the scan results in the firmware. + */ + if (ssidLen || (memcmp(pScanCfgOut->specificBSSID, + &zeroMac, sizeof(zeroMac)) != 0)) { + *pMaxChanPerScan = MRVDRV_MAX_CHANNELS_PER_SCAN; + *pFilteredScan = 1; + } + } else { + pScanCfgOut->bssType = Adapter->ScanMode; + numProbes = Adapter->ScanProbes; + } + + /* If the input config or adapter has the number of Probes set, add tlv */ + if (numProbes) { + pNumProbesTlv = (struct MrvlIEtypes_NumProbes *) pTlvPos; + pNumProbesTlv->Header.Type = + wlan_cpu_to_le16(TLV_TYPE_NUMPROBES); + pNumProbesTlv->Header.Len = sizeof(pNumProbesTlv->NumProbes); + pNumProbesTlv->NumProbes = wlan_cpu_to_le16(numProbes); + + pTlvPos += + sizeof(pNumProbesTlv->Header) + pNumProbesTlv->Header.Len; + + pNumProbesTlv->Header.Len = + wlan_cpu_to_le16(pNumProbesTlv->Header.Len); + } + + /* + * Set the output for the channel TLV to the address in the tlv buffer + * past any TLVs that were added in this fuction (SSID, numProbes). + * Channel TLVs will be added past this for each scan command, preserving + * the TLVs that were previously added. + */ + *ppChanTlvOut = (struct MrvlIEtypes_ChanListParamSet *) pTlvPos; + + if (pUserScanIn && pUserScanIn->chanList[0].chanNumber) { + + PRINTM(INFO, "Scan: Using supplied channel list\n"); + + for (chanIdx = 0; + chanIdx < WLAN_IOCTL_USER_SCAN_CHAN_MAX + && pUserScanIn->chanList[chanIdx].chanNumber; chanIdx++) { + + channel = pUserScanIn->chanList[chanIdx].chanNumber; + (pScanChanList + chanIdx)->ChanNumber = channel; + + radioType = pUserScanIn->chanList[chanIdx].radioType; + (pScanChanList + chanIdx)->RadioType = radioType; + + scanType = pUserScanIn->chanList[chanIdx].scanType; + + if (scanType == HostCmd_SCAN_TYPE_PASSIVE) { + (pScanChanList + + chanIdx)->ChanScanMode.PassiveScan = 1; + } else { + (pScanChanList + + chanIdx)->ChanScanMode.PassiveScan = 0; + } + + if (pUserScanIn->chanList[chanIdx].scanTime) { + scanDur = + pUserScanIn->chanList[chanIdx].scanTime; + } else { + if (scanType == HostCmd_SCAN_TYPE_PASSIVE) { + scanDur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; + } else { + scanDur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; + } + } + + (pScanChanList + chanIdx)->MinScanTime = + wlan_cpu_to_le16(scanDur); + (pScanChanList + chanIdx)->MaxScanTime = + wlan_cpu_to_le16(scanDur); + } + + /* Check if we are only scanning the current channel */ + if ((chanIdx == 1) && (pUserScanIn->chanList[0].chanNumber + == + priv->adapter->CurBssParams.channel)) { + *pScanCurrentOnly = 1; + PRINTM(INFO, "Scan: Scanning current channel only"); + } + + } else { + PRINTM(INFO, "Scan: Creating full region channel list\n"); + wlan_scan_create_channel_list(priv, pScanChanList, + *pFilteredScan); + } +} + +/** + * @brief Construct and send multiple scan config commands to the firmware + * + * Previous routines have created a wlan_scan_cmd_config with any requested + * TLVs. This function splits the channel TLV into maxChanPerScan lists + * and sends the portion of the channel TLV along with the other TLVs + * to the wlan_cmd routines for execution in the firmware. + * + * @param priv A pointer to wlan_private structure + * @param maxChanPerScan Maximum number channels to be included in each + * scan command sent to firmware + * @param filteredScan Flag indicating whether or not a BSSID or SSID + * filter is being used for the firmware command + * scan command sent to firmware + * @param pScanCfgOut Scan configuration used for this scan. + * @param pChanTlvOut Pointer in the pScanCfgOut where the channel TLV + * should start. This is past any other TLVs that + * must be sent down in each firmware command. + * @param pScanChanList List of channels to scan in maxChanPerScan segments + * + * @return WLAN_STATUS_SUCCESS or error return otherwise + */ +static int wlan_scan_channel_list(wlan_private * priv, + int maxChanPerScan, + u8 filteredScan, + struct wlan_scan_cmd_config * pScanCfgOut, + struct MrvlIEtypes_ChanListParamSet * pChanTlvOut, + struct ChanScanParamSet * pScanChanList) +{ + struct ChanScanParamSet *pTmpChan; + struct ChanScanParamSet *pStartChan; + u8 scanBand; + int doneEarly; + int tlvIdx; + int ret; + + ENTER(); + + if (pScanCfgOut == 0 || pChanTlvOut == 0 || pScanChanList == 0) { + PRINTM(INFO, "Scan: Null detect: %p, %p, %p\n", + pScanCfgOut, pChanTlvOut, pScanChanList); + return WLAN_STATUS_FAILURE; + } + + ret = WLAN_STATUS_SUCCESS; + + pChanTlvOut->Header.Type = wlan_cpu_to_le16(TLV_TYPE_CHANLIST); + + /* Set the temp channel struct pointer to the start of the desired list */ + pTmpChan = pScanChanList; + + /* Loop through the desired channel list, sending a new firmware scan + * commands for each maxChanPerScan channels (or for 1,6,11 individually + * if configured accordingly) + */ + while (pTmpChan->ChanNumber) { + + tlvIdx = 0; + pChanTlvOut->Header.Len = 0; + scanBand = pTmpChan->RadioType; + pStartChan = pTmpChan; + doneEarly = 0; + + /* Construct the Channel TLV for the scan command. Continue to + * insert channel TLVs until: + * - the tlvIdx hits the maximum configured per scan command + * - the next channel to insert is 0 (end of desired channel list) + * - doneEarly is set (controlling individual scanning of 1,6,11) + */ + while (tlvIdx < maxChanPerScan && pTmpChan->ChanNumber + && !doneEarly) { + + PRINTM(INFO, + "Scan: Chan(%3d), Radio(%d), Mode(%d,%d), Dur(%d)\n", + pTmpChan->ChanNumber, pTmpChan->RadioType, + pTmpChan->ChanScanMode.PassiveScan, + pTmpChan->ChanScanMode.DisableChanFilt, + pTmpChan->MaxScanTime); + + /* Copy the current channel TLV to the command being prepared */ + memcpy(pChanTlvOut->ChanScanParam + tlvIdx, + pTmpChan, sizeof(pChanTlvOut->ChanScanParam)); + + /* Increment the TLV header length by the size appended */ + pChanTlvOut->Header.Len += + sizeof(pChanTlvOut->ChanScanParam); + + /* + * The tlv buffer length is set to the number of bytes of the + * between the channel tlv pointer and the start of the + * tlv buffer. This compensates for any TLVs that were appended + * before the channel list. + */ + pScanCfgOut->tlvBufferLen = ((u8 *) pChanTlvOut + - pScanCfgOut->tlvBuffer); + + /* Add the size of the channel tlv header and the data length */ + pScanCfgOut->tlvBufferLen += + (sizeof(pChanTlvOut->Header) + + pChanTlvOut->Header.Len); + + /* Increment the index to the channel tlv we are constructing */ + tlvIdx++; + + doneEarly = 0; + + /* Stop the loop if the *current* channel is in the 1,6,11 set + * and we are not filtering on a BSSID or SSID. + */ + if (!filteredScan && (pTmpChan->ChanNumber == 1 + || pTmpChan->ChanNumber == 6 + || pTmpChan->ChanNumber == 11)) { + doneEarly = 1; + } + + /* Increment the tmp pointer to the next channel to be scanned */ + pTmpChan++; + + /* Stop the loop if the *next* channel is in the 1,6,11 set. + * This will cause it to be the only channel scanned on the next + * interation + */ + if (!filteredScan && (pTmpChan->ChanNumber == 1 + || pTmpChan->ChanNumber == 6 + || pTmpChan->ChanNumber == 11)) { + doneEarly = 1; + } + } + + /* Send the scan command to the firmware with the specified cfg */ + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SCAN, 0, + HostCmd_OPTION_WAITFORRSP, 0, + pScanCfgOut); + } + + LEAVE(); + + if (ret) { + return WLAN_STATUS_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Internal function used to start a scan based on an input config + * + * Use the input user scan configuration information when provided in + * order to send the appropriate scan commands to firmware to populate or + * update the internal driver scan table + * + * @param priv A pointer to wlan_private structure + * @param pUserScanIn Pointer to the input configuration for the requested + * scan. + * + * @return WLAN_STATUS_SUCCESS or < 0 if error + */ +static int wlan_scan_networks(wlan_private * priv, + const struct wlan_ioctl_user_scan_cfg * pUserScanIn) +{ + wlan_adapter *Adapter = priv->adapter; + struct MrvlIEtypes_ChanListParamSet *pChanTlvOut; + + struct ChanScanParamSet scanChanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; + union wlan_scan_cmd_config_tlv scanCfgOut; + u8 keepPreviousScan; + u8 filteredScan; + u8 scanCurrentChanOnly; + int maxChanPerScan; + int ret; + + ENTER(); + + memset(scanChanList, 0x00, sizeof(scanChanList)); + memset(&scanCfgOut, 0x00, sizeof(scanCfgOut)); + + keepPreviousScan = 0; + + wlan_scan_setup_scan_config(priv, + pUserScanIn, + &scanCfgOut.config, + &pChanTlvOut, + scanChanList, + &maxChanPerScan, + &filteredScan, &scanCurrentChanOnly); + + if (pUserScanIn) { + keepPreviousScan = pUserScanIn->keepPreviousScan; + } + + if (!keepPreviousScan) { + memset(Adapter->ScanTable, 0x00, + sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST); + Adapter->NumInScanTable = 0; + } + + /* Keep the data path active if we are only scanning our current channel */ + if (!scanCurrentChanOnly) { + netif_stop_queue(priv->wlan_dev.netdev); + netif_carrier_off(priv->wlan_dev.netdev); + } + + ret = wlan_scan_channel_list(priv, + maxChanPerScan, + filteredScan, + &scanCfgOut.config, + pChanTlvOut, scanChanList); + + /* Process the resulting scan table: + * - Remove any bad ssids + * - Update our current BSS information from scan data + */ + wlan_scan_process_results(priv); + + if (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) { + netif_carrier_on(priv->wlan_dev.netdev); + netif_wake_queue(priv->wlan_dev.netdev); + } + + LEAVE(); + return ret; +} + +/** + * @brief Create a brief scan resp to relay basic BSS info to the app layer + * + * When the beacon/probe response has not been buffered, use the fixed field + * information available to provide a minimum response for the application + * ioctl retrieval routines. + * + * @param ppBuffer Output parameter: Buffer used to create basic scan rsp + * @param pBssDesc Pointer to a BSS entry in the scan table to create + * scan response from for delivery to the application layer + * + * @return void + */ +static void wlan_scan_create_brief_scan_table(u8 ** ppBuffer, + struct bss_descriptor * pBssDesc) +{ + u8 *pTmpBuf = *ppBuffer; + u8 tmpSSIDHdr[2]; + + if (copy_to_user + (pTmpBuf, pBssDesc->TimeStamp, sizeof(pBssDesc->TimeStamp))) { + PRINTM(INFO, "Copy to user failed\n"); + return; + } + pTmpBuf += sizeof(pBssDesc->TimeStamp); + + if (copy_to_user(pTmpBuf, &pBssDesc->BeaconPeriod, + sizeof(pBssDesc->BeaconPeriod))) { + PRINTM(INFO, "Copy to user failed\n"); + return; + } + pTmpBuf += sizeof(pBssDesc->BeaconPeriod); + + if (copy_to_user(pTmpBuf, &pBssDesc->Cap, sizeof(pBssDesc->Cap))) { + PRINTM(INFO, "Copy to user failed\n"); + return; + } + pTmpBuf += sizeof(pBssDesc->Cap); + + tmpSSIDHdr[0] = 0; /* Element ID for SSID is zero */ + tmpSSIDHdr[1] = pBssDesc->Ssid.SsidLength; + if (copy_to_user(pTmpBuf, tmpSSIDHdr, sizeof(tmpSSIDHdr))) { + PRINTM(INFO, "Copy to user failed\n"); + return; + } + pTmpBuf += sizeof(tmpSSIDHdr); + + if (copy_to_user(pTmpBuf, pBssDesc->Ssid.Ssid, + pBssDesc->Ssid.SsidLength)) { + PRINTM(INFO, "Copy to user failed\n"); + return; + } + pTmpBuf += pBssDesc->Ssid.SsidLength; + + *ppBuffer = pTmpBuf; +} + +/** + * @brief Inspect the scan response buffer for pointers to expected TLVs + * + * TLVs can be included at the end of the scan response BSS information. + * Parse the data in the buffer for pointers to TLVs that can potentially + * be passed back in the response + * + * @param pTlv Pointer to the start of the TLV buffer to parse + * @param tlvBufSize Size of the TLV buffer + * @param pTsfTlv Output parameter: Pointer to the TSF TLV if found + * + * @return void + */ +static +void wlan_ret_802_11_scan_get_tlv_ptrs(struct MrvlIEtypes_Data * pTlv, + int tlvBufSize, + struct MrvlIEtypes_TsfTimestamp ** pTsfTlv) +{ + struct MrvlIEtypes_Data *pCurrentTlv; + int tlvBufLeft; + u16 tlvType; + u16 tlvLen; + + pCurrentTlv = pTlv; + tlvBufLeft = tlvBufSize; + *pTsfTlv = NULL; + + PRINTM(INFO, "SCAN_RESP: tlvBufSize = %d\n", tlvBufSize); + HEXDUMP("SCAN_RESP: TLV Buf", (u8 *) pTlv, tlvBufSize); + + while (tlvBufLeft >= sizeof(struct MrvlIEtypesHeader)) { + tlvType = wlan_le16_to_cpu(pCurrentTlv->Header.Type); + tlvLen = wlan_le16_to_cpu(pCurrentTlv->Header.Len); + + switch (tlvType) { + case TLV_TYPE_TSFTIMESTAMP: + *pTsfTlv = (struct MrvlIEtypes_TsfTimestamp *) pCurrentTlv; + break; + + default: + PRINTM(INFO, "SCAN_RESP: Unhandled TLV = %d\n", + tlvType); + /* Give up, this seems corrupted */ + return; + } /* switch */ + + tlvBufLeft -= (sizeof(pTlv->Header) + tlvLen); + pCurrentTlv = + (struct MrvlIEtypes_Data *) (pCurrentTlv->Data + tlvLen); + } /* while */ +} + +/** + * @brief Interpret a BSS scan response returned from the firmware + * + * Parse the various fixed fields and IEs passed back for a a BSS probe + * response or beacon from the scan command. Record information as needed + * in the scan table struct bss_descriptor for that entry. + * + * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, + u8 ** pBeaconInfo, int *bytesLeft) +{ + enum IEEEtypes_ElementId elemID; + struct IEEEtypes_FhParamSet *pFH; + struct IEEEtypes_DsParamSet *pDS; + struct IEEEtypes_CfParamSet *pCF; + struct IEEEtypes_IbssParamSet *pIbss; + struct IEEEtypes_CapInfo *pCap; + struct WLAN_802_11_FIXED_IEs fixedIE; + u8 *pCurrentPtr; + u8 *pRate; + u8 elemLen; + u8 bytesToCopy; + u8 rateSize; + u16 beaconSize; + u8 foundDataRateIE; + int bytesLeftForCurrentBeacon; + + struct WPA_SUPPLICANT *pwpa_supplicant; + struct WPA_SUPPLICANT *pwpa2_supplicant; + struct IE_WPA *pIe; + const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; + + struct IEEEtypes_CountryInfoSet *pcountryinfo; + + ENTER(); + + foundDataRateIE = 0; + rateSize = 0; + beaconSize = 0; + + if (*bytesLeft >= sizeof(beaconSize)) { + /* Extract & convert beacon size from the command buffer */ + memcpy(&beaconSize, *pBeaconInfo, sizeof(beaconSize)); + beaconSize = wlan_le16_to_cpu(beaconSize); + *bytesLeft -= sizeof(beaconSize); + *pBeaconInfo += sizeof(beaconSize); + } + + if (beaconSize == 0 || beaconSize > *bytesLeft) { + + *pBeaconInfo += *bytesLeft; + *bytesLeft = 0; + + return WLAN_STATUS_FAILURE; + } + + /* Initialize the current working beacon pointer for this BSS iteration */ + pCurrentPtr = *pBeaconInfo; + + /* Advance the return beacon pointer past the current beacon */ + *pBeaconInfo += beaconSize; + *bytesLeft -= beaconSize; + + bytesLeftForCurrentBeacon = beaconSize; + + pwpa_supplicant = &pBSSEntry->wpa_supplicant; + pwpa2_supplicant = &pBSSEntry->wpa2_supplicant; + + memcpy(pBSSEntry->MacAddress, pCurrentPtr, ETH_ALEN); + PRINTM(INFO, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n", + pBSSEntry->MacAddress[0], pBSSEntry->MacAddress[1], + pBSSEntry->MacAddress[2], pBSSEntry->MacAddress[3], + pBSSEntry->MacAddress[4], pBSSEntry->MacAddress[5]); + + pCurrentPtr += ETH_ALEN; + bytesLeftForCurrentBeacon -= ETH_ALEN; + + if (bytesLeftForCurrentBeacon < 12) { + PRINTM(INFO, "InterpretIE: Not enough bytes left\n"); + return WLAN_STATUS_FAILURE; + } + + /* + * next 4 fields are RSSI, time stamp, beacon interval, + * and capability information + */ + + /* RSSI is 1 byte long */ + pBSSEntry->Rssi = wlan_le32_to_cpu((long)(*pCurrentPtr)); + PRINTM(INFO, "InterpretIE: RSSI=%02X\n", *pCurrentPtr); + pCurrentPtr += 1; + bytesLeftForCurrentBeacon -= 1; + + /* time stamp is 8 bytes long */ + memcpy(fixedIE.Timestamp, pCurrentPtr, 8); + memcpy(pBSSEntry->TimeStamp, pCurrentPtr, 8); + pCurrentPtr += 8; + bytesLeftForCurrentBeacon -= 8; + + /* beacon interval is 2 bytes long */ + memcpy(&fixedIE.BeaconInterval, pCurrentPtr, 2); + pBSSEntry->BeaconPeriod = wlan_le16_to_cpu(fixedIE.BeaconInterval); + pCurrentPtr += 2; + bytesLeftForCurrentBeacon -= 2; + + /* capability information is 2 bytes long */ + memcpy(&fixedIE.Capabilities, pCurrentPtr, 2); + PRINTM(INFO, "InterpretIE: fixedIE.Capabilities=0x%X\n", + fixedIE.Capabilities); + fixedIE.Capabilities = wlan_le16_to_cpu(fixedIE.Capabilities); + pCap = (struct IEEEtypes_CapInfo *) & fixedIE.Capabilities; + memcpy(&pBSSEntry->Cap, pCap, sizeof(struct IEEEtypes_CapInfo)); + pCurrentPtr += 2; + bytesLeftForCurrentBeacon -= 2; + + /* rest of the current buffer are IE's */ + PRINTM(INFO, "InterpretIE: IELength for this AP = %d\n", + bytesLeftForCurrentBeacon); + + HEXDUMP("InterpretIE: IE info", (u8 *) pCurrentPtr, + bytesLeftForCurrentBeacon); + + if (pCap->Privacy) { + PRINTM(INFO, "InterpretIE: AP WEP enabled\n"); + pBSSEntry->Privacy = Wlan802_11PrivFilter8021xWEP; + } else { + pBSSEntry->Privacy = Wlan802_11PrivFilterAcceptAll; + } + + if (pCap->Ibss == 1) { + pBSSEntry->InfrastructureMode = Wlan802_11IBSS; + } else { + pBSSEntry->InfrastructureMode = Wlan802_11Infrastructure; + } + + /* process variable IE */ + while (bytesLeftForCurrentBeacon >= 2) { + elemID = (enum IEEEtypes_ElementId) (*((u8 *) pCurrentPtr)); + elemLen = *((u8 *) pCurrentPtr + 1); + + if (bytesLeftForCurrentBeacon < elemLen) { + PRINTM(INFO, "InterpretIE: Error in processing IE, " + "bytes left < IE length\n"); + bytesLeftForCurrentBeacon = 0; + continue; + } + + switch (elemID) { + + case SSID: + pBSSEntry->Ssid.SsidLength = elemLen; + memcpy(pBSSEntry->Ssid.Ssid, (pCurrentPtr + 2), + elemLen); + PRINTM(INFO, "Ssid: %32s", pBSSEntry->Ssid.Ssid); + break; + + case SUPPORTED_RATES: + memcpy(pBSSEntry->DataRates, (pCurrentPtr + 2), + elemLen); + memmove(pBSSEntry->libertas_supported_rates, (pCurrentPtr + 2), + elemLen); + rateSize = elemLen; + foundDataRateIE = 1; + break; + + case EXTRA_IE: + PRINTM(INFO, "InterpretIE: EXTRA_IE Found!\n"); + pBSSEntry->extra_ie = 1; + break; + + case FH_PARAM_SET: + pFH = (struct IEEEtypes_FhParamSet *) pCurrentPtr; + pBSSEntry->NetworkTypeInUse = Wlan802_11FH; + memmove(&pBSSEntry->PhyParamSet.FhParamSet, pFH, + sizeof(struct IEEEtypes_FhParamSet)); + pBSSEntry->PhyParamSet.FhParamSet.DwellTime + = + wlan_le16_to_cpu(pBSSEntry->PhyParamSet.FhParamSet. + DwellTime); + break; + + case DS_PARAM_SET: + pDS = (struct IEEEtypes_DsParamSet *) pCurrentPtr; + + pBSSEntry->NetworkTypeInUse = Wlan802_11DS; + pBSSEntry->Channel = pDS->CurrentChan; + + memcpy(&pBSSEntry->PhyParamSet.DsParamSet, pDS, + sizeof(struct IEEEtypes_DsParamSet)); + break; + + case CF_PARAM_SET: + pCF = (struct IEEEtypes_CfParamSet *) pCurrentPtr; + + memcpy(&pBSSEntry->SsParamSet.CfParamSet, pCF, + sizeof(struct IEEEtypes_CfParamSet)); + break; + + case IBSS_PARAM_SET: + pIbss = (struct IEEEtypes_IbssParamSet *) pCurrentPtr; + pBSSEntry->ATIMWindow = + wlan_le32_to_cpu(pIbss->AtimWindow); + + memmove(&pBSSEntry->SsParamSet.IbssParamSet, pIbss, + sizeof(struct IEEEtypes_IbssParamSet)); + + pBSSEntry->SsParamSet.IbssParamSet.AtimWindow + = + wlan_le16_to_cpu(pBSSEntry->SsParamSet.IbssParamSet. + AtimWindow); + break; + + /* Handle Country Info IE */ + case COUNTRY_INFO: + pcountryinfo = + (struct IEEEtypes_CountryInfoSet *) pCurrentPtr; + + if (pcountryinfo->Len < + sizeof(pcountryinfo->CountryCode) + || pcountryinfo->Len > 254) { + PRINTM(INFO, "InterpretIE: 11D- Err " + "CountryInfo len =%d min=%d max=254\n", + pcountryinfo->Len, + sizeof(pcountryinfo->CountryCode)); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + memcpy(&pBSSEntry->CountryInfo, + pcountryinfo, pcountryinfo->Len + 2); + HEXDUMP("InterpretIE: 11D- CountryInfo:", + (u8 *) pcountryinfo, + (u32) (pcountryinfo->Len + 2)); + break; + + case EXTENDED_SUPPORTED_RATES: + /* + * only process extended supported rate + * if data rate is already found. + * data rate IE should come before + * extended supported rate IE + */ + if (foundDataRateIE) { + if ((elemLen + rateSize) > WLAN_SUPPORTED_RATES) { + bytesToCopy = + (WLAN_SUPPORTED_RATES - rateSize); + } else { + bytesToCopy = elemLen; + } + + pRate = (u8 *) pBSSEntry->DataRates; + pRate += rateSize; + memmove(pRate, (pCurrentPtr + 2), bytesToCopy); + + pRate = (u8 *) pBSSEntry->libertas_supported_rates; + + pRate += rateSize; + memmove(pRate, (pCurrentPtr + 2), bytesToCopy); + } + break; + + case VENDOR_SPECIFIC_221: +#define IE_ID_LEN_FIELDS_BYTES 2 + pIe = (struct IE_WPA *)pCurrentPtr; + + if (!memcmp(pIe->oui, oui01, sizeof(oui01))) { + pwpa_supplicant->Wpa_ie_len + = min_t(size_t, elemLen + IE_ID_LEN_FIELDS_BYTES, + sizeof(pwpa_supplicant->Wpa_ie)); + memcpy(pwpa_supplicant->Wpa_ie, + pCurrentPtr, + pwpa_supplicant->Wpa_ie_len); + HEXDUMP("InterpretIE: Resp WPA_IE", + pwpa_supplicant->Wpa_ie, elemLen); + } + break; + case WPA2_IE: + pIe = (struct IE_WPA *)pCurrentPtr; + pwpa2_supplicant->Wpa_ie_len + = min_t(size_t, elemLen + IE_ID_LEN_FIELDS_BYTES, + sizeof(pwpa2_supplicant->Wpa_ie)); + memcpy(pwpa2_supplicant->Wpa_ie, + pCurrentPtr, pwpa2_supplicant->Wpa_ie_len); + + HEXDUMP("InterpretIE: Resp WPA2_IE", + pwpa2_supplicant->Wpa_ie, elemLen); + break; + case TIM: + break; + + case CHALLENGE_TEXT: + break; + } + + pCurrentPtr += elemLen + 2; + + /* need to account for IE ID and IE Len */ + bytesLeftForCurrentBeacon -= (elemLen + 2); + + } /* while (bytesLeftForCurrentBeacon > 2) */ + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Compare two SSIDs + * + * @param ssid1 A pointer to ssid to compare + * @param ssid2 A pointer to ssid to compare + * + * @return 0--ssid is same, otherwise is different + */ +int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2) +{ + if (!ssid1 || !ssid2) + return -1; + + if (ssid1->SsidLength != ssid2->SsidLength) + return -1; + + return memcmp(ssid1->Ssid, ssid2->Ssid, ssid1->SsidLength); +} + +/** + * @brief This function finds a specific compatible BSSID in the scan list + * + * @param Adapter A pointer to wlan_adapter + * @param bssid BSSID to find in the scan list + * @param mode Network mode: Infrastructure or IBSS + * + * @return index in BSSID list, or error return code (< 0) + */ +int libertas_find_BSSID_in_list(wlan_adapter * Adapter, u8 * bssid, int mode) +{ + int ret = -ENETUNREACH; + int i; + + if (!bssid) + return -EFAULT; + + PRINTM(INFO, "FindBSSID: Num of BSSIDs = %d\n", + Adapter->NumInScanTable); + + /* Look through the scan table for a compatible match. The ret return + * variable will be equal to the index in the scan table (greater + * than zero) if the network is compatible. The loop will continue + * past a matched bssid that is not compatible in case there is an + * AP with multiple SSIDs assigned to the same BSSID + */ + for (i = 0; ret < 0 && i < Adapter->NumInScanTable; i++) { + if (!memcmp(Adapter->ScanTable[i].MacAddress, bssid, ETH_ALEN)) { + switch (mode) { + case Wlan802_11Infrastructure: + case Wlan802_11IBSS: + ret = IsNetworkCompatible(Adapter, i, mode); + break; + default: + ret = i; + break; + } + } + } + + return ret; +} + +/** + * @brief This function finds ssid in ssid list. + * + * @param Adapter A pointer to wlan_adapter + * @param ssid SSID to find in the list + * @param bssid BSSID to qualify the SSID selection (if provided) + * @param mode Network mode: Infrastructure or IBSS + * + * @return index in BSSID list + */ +int libertas_find_SSID_in_list(wlan_adapter * Adapter, + struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode) +{ + int net = -ENETUNREACH; + u8 bestrssi = 0; + int i; + int j; + + PRINTM(INFO, "Num of Entries in Table = %d\n", Adapter->NumInScanTable); + + for (i = 0; i < Adapter->NumInScanTable; i++) { + if (!libertas_SSID_cmp(&Adapter->ScanTable[i].Ssid, ssid) && + (!bssid || + !memcmp(Adapter->ScanTable[i]. + MacAddress, bssid, ETH_ALEN))) { + switch (mode) { + case Wlan802_11Infrastructure: + case Wlan802_11IBSS: + j = IsNetworkCompatible(Adapter, i, mode); + + if (j >= 0) { + if (bssid) { + return i; + } + + if (SCAN_RSSI + (Adapter->ScanTable[i].Rssi) + > bestrssi) { + bestrssi = + SCAN_RSSI(Adapter-> + ScanTable[i]. + Rssi); + net = i; + } + } else { + if (net == -ENETUNREACH) { + net = j; + } + } + break; + case Wlan802_11AutoUnknown: + default: + if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) + > bestrssi) { + bestrssi = + SCAN_RSSI(Adapter->ScanTable[i]. + Rssi); + net = i; + } + break; + } + } + } + + return net; +} + +/** + * @brief This function finds the best SSID in the Scan List + * + * Search the scan table for the best SSID that also matches the current + * adapter network preference (infrastructure or adhoc) + * + * @param Adapter A pointer to wlan_adapter + * + * @return index in BSSID list + */ +int libertas_find_best_SSID_in_list(wlan_adapter * Adapter) +{ + int mode = Adapter->InfrastructureMode; + int bestnet = -ENETUNREACH; + u8 bestrssi = 0; + int i; + + ENTER(); + + PRINTM(INFO, "Num of BSSIDs = %d\n", Adapter->NumInScanTable); + + for (i = 0; i < Adapter->NumInScanTable; i++) { + switch (mode) { + case Wlan802_11Infrastructure: + case Wlan802_11IBSS: + if (IsNetworkCompatible(Adapter, i, mode) >= 0) { + if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > + bestrssi) { + bestrssi = + SCAN_RSSI(Adapter->ScanTable[i]. + Rssi); + bestnet = i; + } + } + break; + case Wlan802_11AutoUnknown: + default: + if (SCAN_RSSI(Adapter->ScanTable[i].Rssi) > bestrssi) { + bestrssi = + SCAN_RSSI(Adapter->ScanTable[i].Rssi); + bestnet = i; + } + break; + } + } + + LEAVE(); + return bestnet; +} + +/** + * @brief Find the AP with specific ssid in the scan list + * + * @param priv A pointer to wlan_private structure + * @param pSSID A pointer to AP's ssid + * + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int libertas_find_best_network_SSID(wlan_private * priv, struct WLAN_802_11_SSID *pSSID) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + struct bss_descriptor *pReqBSSID; + int i; + + ENTER(); + + memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID)); + + wlan_scan_networks(priv, NULL); + + i = libertas_find_best_SSID_in_list(Adapter); + + if (i >= 0) { + + pReqBSSID = &Adapter->ScanTable[i]; + memcpy(pSSID, &pReqBSSID->Ssid, + sizeof(struct WLAN_802_11_SSID)); + + /* Make sure we are in the right mode */ + if (Adapter->InfrastructureMode == Wlan802_11AutoUnknown) { + Adapter->InfrastructureMode = + pReqBSSID->InfrastructureMode; + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_SET, + HostCmd_OPTION_WAITFORRSP, + OID_802_11_INFRASTRUCTURE_MODE, + NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + } + + if (!pSSID->SsidLength) { + ret = WLAN_STATUS_FAILURE; + } + + LEAVE(); + return ret; +} + +/** + * @brief Scan Network + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + union iwreq_data wrqu; + + ENTER(); + +#ifdef REASSOCIATION + if (down_interruptible(&Adapter->ReassocSem)) { + PRINTM(FATAL, "Acquire semaphore error, libertas_set_scan\n"); + return -EBUSY; + } +#endif + + if (!wlan_scan_networks(priv, NULL)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, + NULL); + } +#ifdef REASSOCIATION + up(&Adapter->ReassocSem); +#endif + + if (Adapter->SurpriseRemoved) + return WLAN_STATUS_FAILURE; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Send a scan command for all available channels filtered on a spec + * + * @param priv A pointer to wlan_private structure + * @param pRequestedSSID A pointer to AP's ssid + * @param keepPreviousScan Flag used to save/clear scan table before scan + * + * @return WLAN_STATUS_SUCCESS-success, otherwise fail + */ +int libertas_send_specific_SSID_scan(wlan_private * priv, + struct WLAN_802_11_SSID *pRequestedSSID, + u8 keepPreviousScan) +{ + wlan_adapter *Adapter = priv->adapter; + struct wlan_ioctl_user_scan_cfg scanCfg; + + ENTER(); + + if (pRequestedSSID == NULL) { + return WLAN_STATUS_FAILURE; + } + + memset(&scanCfg, 0x00, sizeof(scanCfg)); + + memcpy(scanCfg.specificSSID, pRequestedSSID->Ssid, + pRequestedSSID->SsidLength); + scanCfg.keepPreviousScan = keepPreviousScan; + + wlan_scan_networks(priv, &scanCfg); + + if (Adapter->SurpriseRemoved) + return WLAN_STATUS_FAILURE; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief scan an AP with specific BSSID + * + * @param priv A pointer to wlan_private structure + * @param bssid A pointer to AP's bssid + * @param keepPreviousScan Flag used to save/clear scan table before scan + * + * @return WLAN_STATUS_SUCCESS-success, otherwise fail + */ +int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keepPreviousScan) +{ + struct wlan_ioctl_user_scan_cfg scanCfg; + + ENTER(); + + if (bssid == NULL) { + return WLAN_STATUS_FAILURE; + } + + memset(&scanCfg, 0x00, sizeof(scanCfg)); + memcpy(scanCfg.specificBSSID, bssid, sizeof(scanCfg.specificBSSID)); + scanCfg.keepPreviousScan = keepPreviousScan; + + wlan_scan_networks(priv, &scanCfg); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Retrieve the scan table entries via wireless tools IOCTL call + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + char *current_ev = extra; + char *end_buf = extra + IW_SCAN_MAX_DATA; + struct chan_freq_power *cfp; + struct bss_descriptor *pScanTable; + char *current_val; /* For rates */ + struct iw_event iwe; /* Temporary buffer */ + int i; + int j; + int rate; +#define PERFECT_RSSI ((u8)50) +#define WORST_RSSI ((u8)0) +#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) + u8 rssi; + + u8 buf[16 + 256 * 2]; + u8 *ptr; + + ENTER(); + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) + PRINTM(INFO, "Current Ssid: %32s\n", + Adapter->CurBssParams.ssid.Ssid); + + PRINTM(INFO, "Scan: Get: NumInScanTable = %d\n", + Adapter->NumInScanTable); + + /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. + * The new API using SIOCGIWSCAN is only limited by buffer size + * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes + * which is 4096. + */ + for (i = 0; i < Adapter->NumInScanTable; i++) { + if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) { + PRINTM(INFO, "i=%d break out: current_ev=%p end_buf=%p " + "MAX_SCAN_CELL_SIZE=%d\n", + i, current_ev, end_buf, MAX_SCAN_CELL_SIZE); + break; + } + + pScanTable = &Adapter->ScanTable[i]; + + PRINTM(INFO, "i=%d Ssid: %32s\n", i, pScanTable->Ssid.Ssid); + + cfp = + libertas_find_cfp_by_band_and_channel(Adapter, 0, + pScanTable->Channel); + if (!cfp) { + PRINTM(INFO, "Invalid channel number %d\n", + pScanTable->Channel); + continue; + } + + if (!ssid_valid(&Adapter->ScanTable[i].Ssid)) { + continue; + } + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, + &Adapter->ScanTable[i].MacAddress, ETH_ALEN); + + iwe.len = IW_EV_ADDR_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + //Add the ESSID + iwe.u.data.length = Adapter->ScanTable[i].Ssid.SsidLength; + + if (iwe.u.data.length > 32) { + iwe.u.data.length = 32; + } + + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + Adapter->ScanTable[i].Ssid. + Ssid); + + //Add mode + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = Adapter->ScanTable[i].InfrastructureMode + 1; + iwe.len = IW_EV_UINT_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + //frequency + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = (long)cfp->Freq * 100000; + iwe.u.freq.e = 1; + iwe.len = IW_EV_FREQ_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; + iwe.u.qual.level = SCAN_RSSI(Adapter->ScanTable[i].Rssi); + + rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; + iwe.u.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / + (RSSI_DIFF * RSSI_DIFF); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + else if (iwe.u.qual.qual < 1) + iwe.u.qual.qual = 0; + + if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; + } else { + iwe.u.qual.noise = + CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + } + if ((Adapter->InfrastructureMode == Wlan802_11IBSS) && + !libertas_SSID_cmp(&Adapter->CurBssParams.ssid, + &Adapter->ScanTable[i].Ssid) + && Adapter->AdhocCreate) { + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RSSI, + 0, + HostCmd_OPTION_WAITFORRSP, + 0, NULL); + + if (!ret) { + iwe.u.qual.level = + CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / + AVG_SCALE, + Adapter->NF[TYPE_RXPD][TYPE_AVG] / + AVG_SCALE); + } + } + iwe.len = IW_EV_QUAL_LEN; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (Adapter->ScanTable[i].Privacy) { + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + iwe.u.data.length = 0; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + Adapter->ScanTable->Ssid. + Ssid); + + current_val = current_ev + IW_EV_LCP_LEN; + + iwe.cmd = SIOCGIWRATE; + + iwe.u.bitrate.fixed = 0; + iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = 0; + + /* Bit rate given in 500 kb/s units (+ 0x80) */ + for (j = 0; j < sizeof(Adapter->ScanTable[i].libertas_supported_rates); + j++) { + if (Adapter->ScanTable[i].libertas_supported_rates[j] == 0) { + break; + } + rate = + (Adapter->ScanTable[i].libertas_supported_rates[j] & 0x7F) * + 500000; + if (rate > iwe.u.bitrate.value) { + iwe.u.bitrate.value = rate; + } + + iwe.u.bitrate.value = + (Adapter->ScanTable[i].libertas_supported_rates[j] + & 0x7f) * 500000; + iwe.len = IW_EV_PARAM_LEN; + current_ev = + iwe_stream_add_value(current_ev, current_val, + end_buf, &iwe, iwe.len); + + } + if ((Adapter->ScanTable[i].InfrastructureMode == Wlan802_11IBSS) + && !libertas_SSID_cmp(&Adapter->CurBssParams.ssid, + &Adapter->ScanTable[i].Ssid) + && Adapter->AdhocCreate) { + iwe.u.bitrate.value = 22 * 500000; + } + iwe.len = IW_EV_PARAM_LEN; + current_ev = + iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, + iwe.len); + + /* Add new value to event */ + current_val = current_ev + IW_EV_LCP_LEN; + + if (Adapter->ScanTable[i].wpa2_supplicant.Wpa_ie[0] == WPA2_IE) { + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, sizeof(buf)); + memcpy(buf, Adapter->ScanTable[i]. + wpa2_supplicant.Wpa_ie, + Adapter->ScanTable[i].wpa2_supplicant. + Wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = Adapter->ScanTable[i]. + wpa2_supplicant.Wpa_ie_len; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + } + if (Adapter->ScanTable[i].wpa_supplicant.Wpa_ie[0] == WPA_IE) { + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, sizeof(buf)); + memcpy(buf, Adapter->ScanTable[i]. + wpa_supplicant.Wpa_ie, + Adapter->ScanTable[i].wpa_supplicant. + Wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = Adapter->ScanTable[i]. + wpa_supplicant.Wpa_ie_len; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + } + + + if (Adapter->ScanTable[i].extra_ie != 0) { + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, sizeof(buf)); + ptr = buf; + ptr += sprintf(ptr, "extra_ie"); + iwe.u.data.length = strlen(buf); + + PRINTM(INFO, "iwe.u.data.length %d\n", + iwe.u.data.length); + PRINTM(INFO, "BUF: %s \n", buf); + + iwe.cmd = IWEVCUSTOM; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = + iwe_stream_add_point(current_ev, end_buf, &iwe, + buf); + } + + current_val = current_ev + IW_EV_LCP_LEN; + + /* + * Check if we added any event + */ + if ((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + } + + dwrq->length = (current_ev - extra); + dwrq->flags = 0; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Retrieve the scan response/beacon table + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure + * + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + wlan_adapter *Adapter; + struct bss_descriptor *pBssInfo; + struct wlan_ioctl_get_scan_table_info *pRspInfo; + struct wlan_ioctl_get_scan_table_entry *pRspEntry; + struct wlan_ioctl_get_scan_table_entry tmpRspEntry; + int retcode; + int retlen; + int spaceNeeded; + int spaceLeft; + u8 *pCurrent; + u8 *pBufferEnd; + u32 scanStart; + u32 numScansDone; + int variableSize; + + const int fixedSize = (sizeof(tmpRspEntry.fixedFieldLength) + + sizeof(tmpRspEntry.fixedFields) + + sizeof(tmpRspEntry.bssInfoLength)); + + retlen = 0; + + if (copy_from_user(&scanStart, + wrq->u.data.pointer, sizeof(scanStart)) != 0) { + /* copy_from_user failed */ + PRINTM(INFO, "GetScanTable: copy from user failed\n"); + retcode = -EFAULT; + + } else { + + PRINTM(INFO, "GetScanTable: scanStart req = %d\n", scanStart); + PRINTM(INFO, "GetScanTable: length avail = %d\n", + wrq->u.data.length); + + Adapter = priv->adapter; + + numScansDone = 0; + + pRspInfo = + (struct wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer; + pCurrent = pRspInfo->scan_table_entry_buffer; + pBufferEnd = wrq->u.data.pointer + wrq->u.data.length - 1; + spaceLeft = pBufferEnd - pCurrent; + + while (spaceLeft && + scanStart + numScansDone < Adapter->NumInScanTable) { + + pBssInfo = + &Adapter->ScanTable[scanStart + numScansDone]; + + /* No beacon stored, variable size set to 0 */ + variableSize = 0; + + /* If we stored a beacon and its size was zero, set the variable + * size return value to the size of the brief scan response + * wlan_scan_create_brief_scan_table creates. Also used if + * we are not configured to store beacons in the first place + */ + if (variableSize == 0) { + variableSize = pBssInfo->Ssid.SsidLength + 2; + variableSize += (sizeof(pBssInfo->BeaconPeriod) + + sizeof(pBssInfo->TimeStamp) + + sizeof(pBssInfo->Cap)); + } + + spaceNeeded = fixedSize + variableSize; + spaceLeft = pBufferEnd - pCurrent; + + PRINTM(INFO, + "GetScanTable: bss[%d], need(%d), left(%d)\n", + scanStart + numScansDone, spaceNeeded, + spaceLeft); + + if (spaceNeeded >= spaceLeft) { + spaceLeft = 0; + } else { + + PRINTM(INFO, "GetScanTable: bss[%d] = " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + scanStart + numScansDone, + pBssInfo->MacAddress[0], + pBssInfo->MacAddress[1], + pBssInfo->MacAddress[2], + pBssInfo->MacAddress[3], + pBssInfo->MacAddress[4], + pBssInfo->MacAddress[5]); + + tmpRspEntry.fixedFieldLength + = sizeof(pRspEntry->fixedFields); + + memcpy(tmpRspEntry.fixedFields.bssid, + pBssInfo->MacAddress, + sizeof(pRspEntry->fixedFields.bssid)); + + tmpRspEntry.fixedFields.rssi = pBssInfo->Rssi; + tmpRspEntry.fixedFields.channel = + pBssInfo->Channel; + tmpRspEntry.fixedFields.networkTSF = + pBssInfo->networkTSF; + tmpRspEntry.bssInfoLength = variableSize; + + /* + * Copy fixed fields to user space + */ + if (copy_to_user + (pCurrent, &tmpRspEntry, fixedSize)) { + PRINTM(INFO, "Copy to user failed\n"); + return -EFAULT; + } + + pCurrent += fixedSize; + + wlan_scan_create_brief_scan_table(&pCurrent, + pBssInfo); + + numScansDone++; + + } /* else */ + + } /* while (spaceLeft && ... ) */ + + pRspInfo->scanNumber = numScansDone; + retlen = pCurrent - (u8 *) wrq->u.data.pointer; + + retcode = WLAN_STATUS_SUCCESS; + } + + wrq->u.data.length = retlen; + + return retcode; +} + +/** + * @brief Private IOCTL entry to perform an app configured immediate scan + * + * @param priv A pointer to wlan_private structure + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_user_scan_cfg requesting this scan + * + * @return 0 if successful; IOCTL error code otherwise + */ +int libertas_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq) +{ + struct wlan_ioctl_user_scan_cfg scanReq; + int retcode; + union iwreq_data wrqu; + + if (copy_from_user(&scanReq, + wrq->u.data.pointer, + min_t(size_t, wrq->u.data.length, sizeof(scanReq))) != 0) { + /* copy_from_user failed */ + PRINTM(INFO, "SetUserScan: copy from user failed\n"); + retcode = -EFAULT; + + } else { + retcode = wlan_scan_networks(priv, &scanReq); + + memset(&wrqu, 0x00, sizeof(union iwreq_data)); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, + NULL); + } + + return retcode; +} + +/** + * @brief Prepare a scan command to be sent to the firmware + * + * Use the wlan_scan_cmd_config sent to the command processing module in + * the libertas_prepare_and_send_command to configure a HostCmd_DS_802_11_SCAN command + * struct to send to firmware. + * + * The fixed fields specifying the BSS type and BSSID filters as well as a + * variable number/length of TLVs are sent in the command to firmware. + * + * @param priv A pointer to wlan_private structure + * @param cmd A pointer to HostCmd_DS_COMMAND structure to be sent to + * firmware with the HostCmd_DS_801_11_SCAN structure + * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used + * to set the fields/TLVs for the command sent to firmware + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + * + * @sa wlan_scan_create_channel_list + */ +int libertas_cmd_80211_scan(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, void *pdata_buf) +{ + struct HostCmd_DS_802_11_SCAN *pScan = &cmd->params.scan; + struct wlan_scan_cmd_config *pScanCfg; + + ENTER(); + + pScanCfg = (struct wlan_scan_cmd_config *) pdata_buf; + + /* Set fixed field variables in scan command */ + pScan->BSSType = pScanCfg->bssType; + memcpy(pScan->BSSID, pScanCfg->specificBSSID, sizeof(pScan->BSSID)); + memcpy(pScan->TlvBuffer, pScanCfg->tlvBuffer, pScanCfg->tlvBufferLen); + + cmd->Command = wlan_cpu_to_le16(HostCmd_CMD_802_11_SCAN); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->Size = wlan_cpu_to_le16(sizeof(pScan->BSSType) + + sizeof(pScan->BSSID) + + pScanCfg->tlvBufferLen + S_DS_GEN); + + PRINTM(INFO, "SCAN_CMD: Command=%x, Size=%x, SeqNum=%x\n", + cmd->Command, cmd->Size, cmd->SeqNum); + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief This function handles the command response of scan + * + * The response buffer for the scan command has the following + * memory layout: + * + * .-----------------------------------------------------------. + * | Header (4 * sizeof(u16)): Standard command response hdr | + * .-----------------------------------------------------------. + * | BufSize (u16) : sizeof the BSS Description data | + * .-----------------------------------------------------------. + * | NumOfSet (u8) : Number of BSS Descs returned | + * .-----------------------------------------------------------. + * | BSSDescription data (variable, size given in BufSize) | + * .-----------------------------------------------------------. + * | TLV data (variable, size calculated using Header->Size, | + * | BufSize and sizeof the fixed fields above) | + * .-----------------------------------------------------------. + * + * @param priv A pointer to wlan_private structure + * @param resp A pointer to HostCmd_DS_COMMAND + * + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +int libertas_ret_80211_scan(wlan_private * priv, struct HostCmd_DS_COMMAND *resp) +{ + wlan_adapter *Adapter = priv->adapter; + struct HostCmd_DS_802_11_SCAN_RSP *pScan; + struct bss_descriptor newBssEntry; + struct MrvlIEtypes_Data *pTlv; + struct MrvlIEtypes_TsfTimestamp *pTsfTlv; + u8 *pBssInfo; + u16 scanRespSize; + int bytesLeft; + int numInTable; + int bssIdx; + int idx; + int tlvBufSize; + u64 tsfVal; + + ENTER(); + + pScan = &resp->params.scanresp; + + if (pScan->NumberOfSets > MRVDRV_MAX_BSSID_LIST) { + PRINTM(INFO, + "SCAN_RESP: Invalid number of AP returned (%d)!!\n", + pScan->NumberOfSets); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + bytesLeft = wlan_le16_to_cpu(pScan->BSSDescriptSize); + PRINTM(INFO, "SCAN_RESP: BSSDescriptSize %d\n", bytesLeft); + + scanRespSize = wlan_le16_to_cpu(resp->Size); + PRINTM(INFO, "SCAN_RESP: returned %d AP before parsing\n", + pScan->NumberOfSets); + + numInTable = Adapter->NumInScanTable; + pBssInfo = pScan->BssDescAndTlvBuffer; + + /* The size of the TLV buffer is equal to the entire command response + * size (scanRespSize) minus the fixed fields (sizeof()'s), the + * BSS Descriptions (BSSDescriptSize as bytesLef) and the command + * response header (S_DS_GEN) + */ + tlvBufSize = scanRespSize - (bytesLeft + sizeof(pScan->BSSDescriptSize) + + sizeof(pScan->NumberOfSets) + + S_DS_GEN); + + pTlv = (struct MrvlIEtypes_Data *) (pScan->BssDescAndTlvBuffer + bytesLeft); + + /* Search the TLV buffer space in the scan response for any valid TLVs */ + wlan_ret_802_11_scan_get_tlv_ptrs(pTlv, tlvBufSize, &pTsfTlv); + + /* + * Process each scan response returned (pScan->NumberOfSets). Save + * the information in the newBssEntry and then insert into the + * driver scan table either as an update to an existing entry + * or as an addition at the end of the table + */ + for (idx = 0; idx < pScan->NumberOfSets && bytesLeft; idx++) { + /* Zero out the newBssEntry we are about to store info in */ + memset(&newBssEntry, 0x00, sizeof(newBssEntry)); + + /* Process the data fields and IEs returned for this BSS */ + if ((InterpretBSSDescriptionWithIE(&newBssEntry, + &pBssInfo, + &bytesLeft) == + WLAN_STATUS_SUCCESS) + && CHECK_SSID_IS_VALID(&newBssEntry.Ssid)) { + + PRINTM(INFO, + "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", + newBssEntry.MacAddress[0], + newBssEntry.MacAddress[1], + newBssEntry.MacAddress[2], + newBssEntry.MacAddress[3], + newBssEntry.MacAddress[4], + newBssEntry.MacAddress[5]); + + /* + * Search the scan table for the same bssid + */ + for (bssIdx = 0; bssIdx < numInTable; bssIdx++) { + if (memcmp(newBssEntry.MacAddress, + Adapter->ScanTable[bssIdx]. + MacAddress, + sizeof(newBssEntry.MacAddress)) == + 0) { + /* + * If the SSID matches as well, it is a duplicate of + * this entry. Keep the bssIdx set to this + * entry so we replace the old contents in the table + */ + if ((newBssEntry.Ssid.SsidLength == + Adapter->ScanTable[bssIdx].Ssid. + SsidLength) + && + (memcmp + (newBssEntry.Ssid.Ssid, + Adapter->ScanTable[bssIdx].Ssid. + Ssid, + newBssEntry.Ssid.SsidLength) == + 0)) { + PRINTM(INFO, + "SCAN_RESP: Duplicate of index: %d\n", + bssIdx); + break; + } + } + } + /* + * If the bssIdx is equal to the number of entries in the table, + * the new entry was not a duplicate; append it to the scan + * table + */ + if (bssIdx == numInTable) { + /* Range check the bssIdx, keep it limited to the last entry */ + if (bssIdx == MRVDRV_MAX_BSSID_LIST) { + bssIdx--; + } else { + numInTable++; + } + } + + /* + * If the TSF TLV was appended to the scan results, save the + * this entries TSF value in the networkTSF field. The + * networkTSF is the firmware's TSF value at the time the + * beacon or probe response was received. + */ + if (pTsfTlv) { + memcpy(&tsfVal, &pTsfTlv->tsfTable[idx], + sizeof(tsfVal)); + tsfVal = wlan_le64_to_cpu(tsfVal); + + memcpy(&newBssEntry.networkTSF, + &tsfVal, sizeof(newBssEntry.networkTSF)); + } + + /* Copy the locally created newBssEntry to the scan table */ + memcpy(&Adapter->ScanTable[bssIdx], + &newBssEntry, + sizeof(Adapter->ScanTable[bssIdx])); + + } else { + + /* Error parsing/interpreting the scan response, skipped */ + PRINTM(INFO, "SCAN_RESP: " + "InterpretBSSDescriptionWithIE returned ERROR\n"); + } + } + + PRINTM(INFO, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", + pScan->NumberOfSets, numInTable - Adapter->NumInScanTable, + numInTable); + + /* Update the total number of BSSIDs in the scan table */ + Adapter->NumInScanTable = numInTable; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief scan network with specific ssid + * + * @param priv A pointer to wlan_private structure + * @param req A pointer to ifreq structure + * + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int libertas_extscan_ioctl(wlan_private * priv, struct ifreq *req) +{ + struct WLAN_802_11_SSID Ext_Scan_SSID; + union iwreq_data wrqu; + + ENTER(); + + if (copy_from_user(&Ext_Scan_SSID, req->ifr_data, + sizeof(Ext_Scan_SSID))) { + PRINTM(INFO, "copy of SSID for ext scan from user failed \n"); + LEAVE(); + return -EFAULT; + } + libertas_send_specific_SSID_scan(priv, &Ext_Scan_SSID, 1); + + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_scan.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_scan.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_scan.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_scan.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,319 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ + +/** @file wlan_scan.h + * + * @brief Interface for the wlan network scan routines + * + * Driver interface functions and type declarations for the scan module + * implemented in wlan_scan.c. + * + * @sa wlan_scan.c + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change Log: + 01/11/06: Initial revision. New scan code, relocate related functions + +************************************************************/ + +#ifndef _WLAN_SCAN_H +#define _WLAN_SCAN_H + +#include "hostcmd.h" + +/** + * @brief Maximum number of channels that can be sent in a setuserscan ioctl + * + * @sa wlan_ioctl_user_scan_cfg + */ +#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 + +//! Infrastructure BSS scan type in wlan_scan_cmd_config +#define WLAN_SCAN_BSS_TYPE_BSS 1 + +//! Adhoc BSS scan type in wlan_scan_cmd_config +#define WLAN_SCAN_BSS_TYPE_IBSS 2 + +//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter +#define WLAN_SCAN_BSS_TYPE_ANY 3 + +/** + * @brief Structure used internally in the wlan driver to configure a scan. + * + * Sent to the command processing module to configure the firmware + * scan command prepared by libertas_cmd_80211_scan. + * + * @sa wlan_scan_networks + * + */ +struct wlan_scan_cmd_config { + /** + * @brief BSS Type to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) + * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) + * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bssType; + + /** + * @brief Specific BSSID used to filter scan results in the firmware + */ + u8 specificBSSID[ETH_ALEN]; + + /** + * @brief Length of TLVs sent in command starting at tlvBuffer + */ + int tlvBufferLen; + + /** + * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command + * + * @sa TLV_TYPE_CHANLIST, MrvlIEtypes_ChanListParamSet_t + * @sa TLV_TYPE_SSID, MrvlIEtypes_SsIdParamSet_t + */ + u8 tlvBuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here +}; + +/** + * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg + * + * Multiple instances of this structure are included in the IOCTL command + * to configure a instance of a scan on the specific channel. + */ +struct wlan_ioctl_user_scan_chan { + u8 chanNumber; //!< Channel Number to scan + u8 radioType; //!< Radio type: 'B/G' Band = 0, 'A' Band = 1 + u8 scanType; //!< Scan type: Active = 0, Passive = 1 + u16 scanTime; //!< Scan duration in milliseconds; if 0 default used +}; + +/** + * @brief IOCTL input structure to configure an immediate scan cmd to firmware + * + * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies + * a number of parameters to be used in general for the scan as well + * as a channel list (wlan_ioctl_user_scan_chan) for each scan period + * desired. + * + * @sa libertas_set_user_scan_ioctl + */ +struct wlan_ioctl_user_scan_cfg { + + /** + * @brief Flag set to keep the previous scan table intact + * + * If set, the scan results will accumulate, replacing any previous + * matched entries for a BSS with the new scan data + */ + u8 keepPreviousScan; //!< Do not erase the existing scan results + + /** + * @brief BSS Type to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) + * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) + * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) + */ + u8 bssType; + + /** + * @brief Configure the number of probe requests for active chan scans + */ + u8 numProbes; + + /** + * @brief BSSID filter sent in the firmware command to limit the results + */ + u8 specificBSSID[ETH_ALEN]; + + /** + * @brief SSID filter sent in the firmware command to limit the results + */ + char specificSSID[MRVDRV_MAX_SSID_LENGTH + 1]; + + /** + * @brief Variable number (fixed maximum) of channels to scan up + */ + struct wlan_ioctl_user_scan_chan chanList[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; +} __attribute__ ((packed)); + +/** + * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS + * + * Fixed field information returned for the scan response in the IOCTL + * response. + */ +struct wlan_ioctl_get_scan_table_fixed { + u8 bssid[6]; //!< BSSID of this network + u8 channel; //!< Channel this beacon/probe response was detected + u8 rssi; //!< RSSI for the received packet + u64 networkTSF; //!< TSF value from the firmware at packet reception +} __attribute__ ((packed)); + +/** + * @brief Structure passed in the wlan_ioctl_get_scan_table_info for each + * BSS returned in the WLAN_GET_SCAN_RESP IOCTL + * + * @sa libertas_get_scan_table_ioctl + */ +struct wlan_ioctl_get_scan_table_entry { + + /** + * @brief Fixed field length included in the response. + * + * Length value is included so future fixed fields can be added to the + * response without breaking backwards compatibility. Use the length + * to find the offset for the bssInfoLength field, not a sizeof() calc. + */ + u32 fixedFieldLength; + + /** + * @brief Always present, fixed length data fields for the BSS + */ + struct wlan_ioctl_get_scan_table_fixed fixedFields; + + /** + * @brief Length of the BSS Information (probe resp or beacon) that + * follows starting at bssInfoBuffer + */ + u32 bssInfoLength; + + /** + * @brief Probe response or beacon scanned for the BSS. + * + * Field layout: + * - TSF 8 octets + * - Beacon Interval 2 octets + * - Capability Info 2 octets + * + * - IEEE Infomation Elements; variable number & length per 802.11 spec + */ + u8 bssInfoBuffer[1]; +} __attribute__ ((packed)); + +/** + * @brief WLAN_GET_SCAN_RESP private IOCTL struct to retrieve the scan table + * + * @sa libertas_get_scan_table_ioctl + */ +struct wlan_ioctl_get_scan_table_info { + + /** + * - Zero based scan entry to start retrieval in command request + * - Number of scans entires returned in command response + */ + u32 scanNumber; + + /** + * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures. + * Each struct is padded to the nearest 32 bit boundary. + */ + u8 scan_table_entry_buffer[1]; + +} __attribute__ ((packed)); + +/** + * @brief Structure used to store information for each beacon/probe response + */ +struct bss_descriptor { + u8 MacAddress[ETH_ALEN]; + + struct WLAN_802_11_SSID Ssid; + + /* WEP encryption requirement */ + u32 Privacy; + + /* receive signal strength in dBm */ + long Rssi; + + u32 Channel; + + u16 BeaconPeriod; + + u32 ATIMWindow; + + enum WLAN_802_11_NETWORK_TYPE NetworkTypeInUse; + enum WLAN_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; + u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; + + int extra_ie; + + u8 TimeStamp[8]; //!< TSF value included in the beacon/probe response + union IEEEtypes_PhyParamSet PhyParamSet; + union IEEEtypes_SsParamSet SsParamSet; + struct IEEEtypes_CapInfo Cap; + u8 DataRates[WLAN_SUPPORTED_RATES]; + + u64 networkTSF; //!< TSF timestamp from the current firmware TSF + + struct IEEEtypes_CountryInfoFullSet CountryInfo; + + struct WPA_SUPPLICANT wpa_supplicant; + struct WPA_SUPPLICANT wpa2_supplicant; + +}; + +extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, + struct WLAN_802_11_SSID *ssid2); +extern int libertas_find_SSID_in_list(wlan_adapter * Adapter, struct WLAN_802_11_SSID *ssid, + u8 * bssid, int mode); +extern int libertas_find_best_SSID_in_list(wlan_adapter * Adapter); +extern int libertas_find_BSSID_in_list(wlan_adapter * Adapter, u8 * bssid, int mode); + +extern int libertas_find_best_network_SSID(wlan_private * priv, + struct WLAN_802_11_SSID *pSSID); + +extern int libertas_send_specific_SSID_scan(wlan_private * priv, + struct WLAN_802_11_SSID *pRequestedSSID, + u8 keepPreviousScan); +extern int libertas_send_specific_BSSID_scan(wlan_private * priv, + u8 * bssid, u8 keepPreviousScan); + +extern int libertas_get_scan_table_ioctl(wlan_private * priv, struct iwreq *wrq); +extern int libertas_set_user_scan_ioctl(wlan_private * priv, struct iwreq *wrq); + +extern int libertas_cmd_80211_scan(wlan_private * priv, + struct HostCmd_DS_COMMAND *cmd, + void *pdata_buf); + +extern int libertas_ret_80211_scan(wlan_private * priv, + struct HostCmd_DS_COMMAND *resp); + +struct ifreq; +extern int libertas_extscan_ioctl(wlan_private * priv, struct ifreq *req); + +#ifdef __KERNEL__ +struct iw_point; +struct iw_param; +struct iw_request_info; +extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra); +extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra); +#endif + +#endif /* _WLAN_SCAN_H */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_thread.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_thread.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_thread.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_thread.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,69 @@ +/** + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#ifndef __WLAN_THREAD_H_ +#define __WLAN_THREAD_H_ + +#include <linux/kthread.h> + +struct wlan_thread { + struct task_struct *task; + wait_queue_head_t waitQ; + pid_t pid; + void *priv; +}; + +static inline void wlan_activate_thread(struct wlan_thread * thr) +{ + /** Record the thread pid */ + thr->pid = current->pid; + + /** Initialize the wait queue */ + init_waitqueue_head(&thr->waitQ); +} + +static inline void wlan_deactivate_thread(struct wlan_thread * thr) +{ + ENTER(); + + LEAVE(); +} + +static inline void wlan_create_thread(int (*wlanfunc) (void *), + struct wlan_thread * thr, char *name) +{ + thr->task = kthread_run(wlanfunc, thr, "%s", name); +} + +static inline int wlan_terminate_thread(struct wlan_thread * thr) +{ + ENTER(); + + /* Check if the thread is active or not */ + if (!thr->pid) { + PRINTM(INFO, "Thread does not exist\n"); + return -1; + } + kthread_stop(thr->task); + + LEAVE(); + return 0; +} + +#endif diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_tx.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_tx.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_tx.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_tx.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,374 @@ +/** @file wlan_tx.c + * @brief This file contains the handling of TX in wlan driver. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 09/28/05: Add Doxygen format comments + 12/13/05: Add Proprietary periodic sleep support + 01/05/06: Add kernel 2.6.x support + 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support +********************************************************/ + +#include <linux/netdevice.h> + +#include "hostcmd.h" +#include "radiotap.h" +#include "sbi.h" +#include "wlan_decl.h" +#include "wlan_defs.h" +#include "wlan_dev.h" +#include "wlan_wext.h" + +/** + * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE + * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) + * + * @param rate Input rate + * @return Output Rate (0 if invalid) + */ +static u32 convert_radiotap_rate_to_mv(u8 rate) +{ + switch (rate) { + case 2: /* 1 Mbps */ + return 0 | (1 << 4); + case 4: /* 2 Mbps */ + return 1 | (1 << 4); + case 11: /* 5.5 Mbps */ + return 2 | (1 << 4); + case 22: /* 11 Mbps */ + return 3 | (1 << 4); + case 12: /* 6 Mbps */ + return 4 | (1 << 4); + case 18: /* 9 Mbps */ + return 5 | (1 << 4); + case 24: /* 12 Mbps */ + return 6 | (1 << 4); + case 36: /* 18 Mbps */ + return 7 | (1 << 4); + case 48: /* 24 Mbps */ + return 8 | (1 << 4); + case 72: /* 36 Mbps */ + return 9 | (1 << 4); + case 96: /* 48 Mbps */ + return 10 | (1 << 4); + case 108: /* 54 Mbps */ + return 11 | (1 << 4); + } + return 0; +} + +/** + * @brief This function processes a single packet and sends + * to IF layer + * + * @param priv A pointer to wlan_private structure + * @param skb A pointer to skb which includes TX packet + * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE + */ +static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) +{ + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + struct TxPD LocalTxPD; + struct TxPD *pLocalTxPD = &LocalTxPD; + u8 *p802x_hdr; + struct TxRadiotapHdr *pradiotap_hdr; + u32 new_rate; + u8 *ptr = priv->adapter->TmpTxBuf; + + ENTER(); + + if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) + HEXDUMP("TX packet: ", skb->data, + min_t(unsigned int, skb->len, 100)); + + if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { + PRINTM(INFO, "Tx Error: Bad skb length %d : %d\n", + skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); + ret = WLAN_STATUS_FAILURE; + goto done; + } + + memset(pLocalTxPD, 0, sizeof(struct TxPD)); + + pLocalTxPD->TxPacketLength = skb->len; + + if (Adapter->PSState != PS_STATE_FULL_POWER) { + if (libertas_check_last_packet_indication(priv)) { + Adapter->TxLockFlag = 1; + pLocalTxPD->PowerMgmt = + MRVDRV_TxPD_POWER_MGMT_LAST_PACKET; + } + } + /* offset of actual data */ + pLocalTxPD->TxPacketLocation = sizeof(struct TxPD); + + /* TxCtrl set by user or default */ + pLocalTxPD->TxControl = Adapter->PktTxCtrl; + + p802x_hdr = skb->data; + if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + + /* locate radiotap header */ + pradiotap_hdr = (struct TxRadiotapHdr *)skb->data; + + /* set TxPD fields from the radiotap header */ + new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); + if (new_rate != 0) { + /* erase TxControl[4:0] */ + pLocalTxPD->TxControl &= ~0x1f; + /* write new TxControl[4:0] */ + pLocalTxPD->TxControl |= new_rate; + } + + /* skip the radiotap header */ + p802x_hdr += sizeof(struct TxRadiotapHdr); + pLocalTxPD->TxPacketLength -= sizeof(struct TxRadiotapHdr); + + } + /* copy destination address from 802.3 or 802.11 header */ + if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) + memcpy(pLocalTxPD->TxDestAddrHigh, p802x_hdr + 4, ETH_ALEN); + else + memcpy(pLocalTxPD->TxDestAddrHigh, p802x_hdr, ETH_ALEN); + + HEXDUMP("TxPD", (u8 *) pLocalTxPD, sizeof(struct TxPD)); + + memcpy(ptr, pLocalTxPD, sizeof(struct TxPD)); + + ptr += sizeof(struct TxPD); + + HEXDUMP("Tx Data", (u8 *) p802x_hdr, pLocalTxPD->TxPacketLength); + memcpy(ptr, p802x_hdr, pLocalTxPD->TxPacketLength); + ret = libertas_sbi_host_to_card(priv, MVMS_DAT, + priv->adapter->TmpTxBuf, + pLocalTxPD->TxPacketLength + + sizeof(struct TxPD)); + + if (ret) { + PRINTM(INFO, "Tx Error: libertas_sbi_host_to_card failed: 0x%X\n", ret); + goto done; + } + + PRINTM(INFO, "SendSinglePacket succeeds\n"); + + done: + if (!ret) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + } + + if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { + /* Keep the skb to echo it back once Tx feedback is + received from FW */ + skb_orphan(skb); + /* stop processing outgoing pkts */ + netif_stop_queue(priv->wlan_dev.netdev); + /* freeze any packets already in our queues */ + priv->adapter->TxLockFlag = 1; + } else { + dev_kfree_skb_any(skb); + priv->adapter->CurrentTxSkb = NULL; + } + + LEAVE(); + return ret; +} + + +void libertas_tx_runqueue(wlan_private *priv) +{ + wlan_adapter *adapter = priv->adapter; + int i; + + spin_lock(&adapter->txqueue_lock); + for (i = 0; i < adapter->tx_queue_idx; i++) { + struct sk_buff *skb = adapter->tx_queue_ps[i]; + spin_unlock(&adapter->txqueue_lock); + SendSinglePacket(priv, skb); + spin_lock(&adapter->txqueue_lock); + } + adapter->tx_queue_idx = 0; + spin_unlock(&adapter->txqueue_lock); +} + +static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) +{ + wlan_adapter *adapter = priv->adapter; + + spin_lock(&adapter->txqueue_lock); + + WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE); + adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; + if (adapter->tx_queue_idx == NR_TX_QUEUE) + netif_stop_queue(priv->wlan_dev.netdev); + else + netif_start_queue(priv->wlan_dev.netdev); + + spin_unlock(&adapter->txqueue_lock); +} + +/** + * @brief This function checks the conditions and sends packet to IF + * layer if everything is ok. + * + * @param priv A pointer to wlan_private structure + * @return n/a + */ +int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) +{ + int ret = WLAN_STATUS_FAILURE; + + ENTER(); + + HEXDUMP("TX Data", skb->data, min_t(unsigned int, skb->len, 100)); + + if (priv->wlan_dev.dnld_sent) { + PRINTM(MSG, "TX Error: dnld_sent = %d, not sending\n", + priv->wlan_dev.dnld_sent); + goto done; + } + + if ((priv->adapter->PSState == PS_STATE_SLEEP) || + (priv->adapter->PSState == PS_STATE_PRE_SLEEP)) { + wlan_tx_queue(priv, skb); + return ret; + } + + priv->adapter->CurrentTxSkb = skb; + + ret = SendSinglePacket(priv, skb); +done: + LEAVE(); + return ret; +} + +/** + * @brief This function tells firmware to send a NULL data packet. + * + * @param priv A pointer to wlan_private structure + * @param pwr_mgmt indicate if power management bit should be 0 or 1 + * @return n/a + */ +int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt) +{ + wlan_adapter *Adapter = priv->adapter; + struct TxPD txpd; + int ret = WLAN_STATUS_SUCCESS; + u8 *ptr = priv->adapter->TmpTxBuf; + + ENTER(); + + if (priv->adapter->SurpriseRemoved) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + if (priv->adapter->MediaConnectStatus == WlanMediaStateDisconnected) { + ret = WLAN_STATUS_FAILURE; + goto done; + } + + memset(&txpd, 0, sizeof(struct TxPD)); + + txpd.TxControl = Adapter->PktTxCtrl; + txpd.PowerMgmt = pwr_mgmt; + txpd.TxPacketLocation = sizeof(struct TxPD); + + memcpy(ptr, &txpd, sizeof(struct TxPD)); + + ret = libertas_sbi_host_to_card(priv, MVMS_DAT, + priv->adapter->TmpTxBuf, sizeof(struct TxPD)); + + if (ret != 0) { + PRINTM(INFO, "TX Error: libertas_send_null_packet failed!\n"); + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function check if we need send last packet indication. + * + * @param priv A pointer to wlan_private structure + * + * @return TRUE or FALSE + */ +u8 libertas_check_last_packet_indication(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + u8 ret = 0; + if (Adapter->sleep_period.period == 0) + goto done; + done: + return ret; +} + +/** + * @brief This function sends to the host the last transmitted packet, + * filling the radiotap headers with transmission information. + * + * @param priv A pointer to wlan_private structure + * @param status A 32 bit value containing transmission status. + * + * @returns void + */ +void libertas_send_tx_feedback(wlan_private * priv) +{ + wlan_adapter *Adapter = priv->adapter; + struct TxRadiotapHdr *radiotap_hdr; + u32 status = Adapter->EventCause; + int txfail; + int try_count; + + if (Adapter->radiomode != WLAN_RADIOMODE_RADIOTAP || + Adapter->CurrentTxSkb == NULL) + return; + + radiotap_hdr = (struct TxRadiotapHdr *)Adapter->CurrentTxSkb->data; + + if ((Adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) + HEXDUMP("TX feedback: ", (u8 *) radiotap_hdr, + min_t(unsigned int, Adapter->CurrentTxSkb->len, 100)); + + txfail = (status >> 24); + +#if 0 + /* The version of roofnet that we've tested does not use this yet + * But it may be used in the future. + */ + if (txfail) + radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL; +#endif + try_count = (status >> 16) & 0xff; + radiotap_hdr->data_retries = (try_count) ? + (1 + Adapter->TxRetryCount - try_count) : 0; + libertas_upload_rx_packet(priv, Adapter->CurrentTxSkb); + Adapter->CurrentTxSkb = NULL; + priv->adapter->TxLockFlag = 0; + if (priv->adapter->MediaConnectStatus == WlanMediaStateConnected) + netif_wake_queue(priv->wlan_dev.netdev); +} diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_types.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_types.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_types.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_types.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,349 @@ +/** @file wlan_types.h + * @brief This header file contains definition for global types + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change log: + 10/11/05: add Doxygen format comments + 01/11/06: Add IEEE Association response type. Add TSF TLV information. + 01/31/06: Add support to selectively enabe the FW Scan channel filter + 04/10/06: Add power_adapt_cfg_ext command + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API +************************************************************/ + +#ifndef _WLAN_TYPES_ +#define _WLAN_TYPES_ + +#include <linux/if_ether.h> + +/** IEEE Type definitions */ +enum IEEEtypes_ElementId { + SSID = 0, + SUPPORTED_RATES, + FH_PARAM_SET, + DS_PARAM_SET, + CF_PARAM_SET, + TIM, + IBSS_PARAM_SET, + COUNTRY_INFO = 7, + + CHALLENGE_TEXT = 16, + + EXTENDED_SUPPORTED_RATES = 50, + + VENDOR_SPECIFIC_221 = 221, + + WPA_IE = 221, + WPA2_IE = 48, + + EXTRA_IE = 133, +} __attribute__ ((packed)); + +#define CAPINFO_MASK (~( W_BIT_15 | W_BIT_14 | \ + W_BIT_12 | W_BIT_11 | W_BIT_9) ) + +struct IEEEtypes_CapInfo { + u8 Ess:1; + u8 Ibss:1; + u8 CfPollable:1; + u8 CfPollRqst:1; + u8 Privacy:1; + u8 ShortPreamble:1; + u8 Pbcc:1; + u8 ChanAgility:1; + u8 SpectrumMgmt:1; + u8 Rsrvd3:1; + u8 ShortSlotTime:1; + u8 Apsd:1; + u8 Rsvrd2:1; + u8 DSSSOFDM:1; + u8 Rsrvd1:2; +} __attribute__ ((packed)); + +/** IEEEtypes_CfParamSet */ +struct IEEEtypes_CfParamSet { + u8 ElementId; + u8 Len; + u8 CfpCnt; + u8 CfpPeriod; + u16 CfpMaxDuration; + u16 CfpDurationRemaining; +} __attribute__ ((packed)); + +struct IEEEtypes_IbssParamSet { + u8 ElementId; + u8 Len; + u16 AtimWindow; +} __attribute__ ((packed)); + +/** IEEEtypes_SsParamSet */ +union IEEEtypes_SsParamSet { + struct IEEEtypes_CfParamSet CfParamSet; + struct IEEEtypes_IbssParamSet IbssParamSet; +} __attribute__ ((packed)); + +/** IEEEtypes_FhParamSet */ +struct IEEEtypes_FhParamSet { + u8 ElementId; + u8 Len; + u16 DwellTime; + u8 HopSet; + u8 HopPattern; + u8 HopIndex; +} __attribute__ ((packed)); + +struct IEEEtypes_DsParamSet { + u8 ElementId; + u8 Len; + u8 CurrentChan; +} __attribute__ ((packed)); + +/** IEEEtypes_DsParamSet */ +union IEEEtypes_PhyParamSet { + struct IEEEtypes_FhParamSet FhParamSet; + struct IEEEtypes_DsParamSet DsParamSet; +} __attribute__ ((packed)); + +struct IEEEtypes_AssocRsp { + struct IEEEtypes_CapInfo Capability; + u16 StatusCode; + u16 AId; + u8 IEBuffer[1]; +} __attribute__ ((packed)); + +/** TLV type ID definition */ +#define PROPRIETARY_TLV_BASE_ID 0x0100 + +/* Terminating TLV Type */ +#define MRVL_TERMINATE_TLV_ID 0xffff + +#define TLV_TYPE_SSID 0x0000 +#define TLV_TYPE_RATES 0x0001 +#define TLV_TYPE_PHY_FH 0x0002 +#define TLV_TYPE_PHY_DS 0x0003 +#define TLV_TYPE_CF 0x0004 +#define TLV_TYPE_IBSS 0x0006 + +#define TLV_TYPE_DOMAIN 0x0007 + +#define TLV_TYPE_POWER_CAPABILITY 0x0021 + +#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) +#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) +#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) +#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) +#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5) +#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6) +#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7) +#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8) +#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9) +#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) +#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11) +#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12) +#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13) +#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14) +#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15) +#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) +#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17) +#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) +#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) +#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) +#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) + +/** TLV related data structures*/ +/** MrvlIEtypesHeader */ +struct MrvlIEtypesHeader { + u16 Type; + u16 Len; +} __attribute__ ((packed)); + +/** MrvlIEtypes_Data */ +struct MrvlIEtypes_Data { + struct MrvlIEtypesHeader Header; + u8 Data[1]; +} __attribute__ ((packed)); + +/** MrvlIEtypes_RatesParamSet */ +struct MrvlIEtypes_RatesParamSet { + struct MrvlIEtypesHeader Header; + u8 Rates[1]; +} __attribute__ ((packed)); + +/** MrvlIEtypes_SsIdParamSet */ +struct MrvlIEtypes_SsIdParamSet { + struct MrvlIEtypesHeader Header; + u8 SsId[1]; +} __attribute__ ((packed)); + +/** MrvlIEtypes_WildCardSsIdParamSet */ +struct MrvlIEtypes_WildCardSsIdParamSet { + struct MrvlIEtypesHeader Header; + u8 MaxSsidLength; + u8 SsId[1]; +} __attribute__ ((packed)); + +/** ChanScanMode */ +struct ChanScanMode { + u8 PassiveScan:1; + u8 DisableChanFilt:1; + u8 Reserved_2_7:6; +} __attribute__ ((packed)); + +/** ChanScanParamSet */ +struct ChanScanParamSet { + u8 RadioType; + u8 ChanNumber; + struct ChanScanMode ChanScanMode; + u16 MinScanTime; + u16 MaxScanTime; +} __attribute__ ((packed)); + +/** MrvlIEtypes_ChanListParamSet */ +struct MrvlIEtypes_ChanListParamSet { + struct MrvlIEtypesHeader Header; + struct ChanScanParamSet ChanScanParam[1]; +} __attribute__ ((packed)); + +/** CfParamSet */ +struct CfParamSet { + u8 CfpCnt; + u8 CfpPeriod; + u16 CfpMaxDuration; + u16 CfpDurationRemaining; +} __attribute__ ((packed)); + +/** IbssParamSet */ +struct IbssParamSet { + u16 AtimWindow; +} __attribute__ ((packed)); + +/** MrvlIEtypes_SsParamSet */ +struct MrvlIEtypes_SsParamSet { + struct MrvlIEtypesHeader Header; + union { + struct CfParamSet CfParamSet[1]; + struct IbssParamSet IbssParamSet[1]; + } cf_ibss; +} __attribute__ ((packed)); + +/** FhParamSet */ +struct FhParamSet { + u16 DwellTime; + u8 HopSet; + u8 HopPattern; + u8 HopIndex; +} __attribute__ ((packed)); + +/** DsParamSet */ +struct DsParamSet { + u8 CurrentChan; +} __attribute__ ((packed)); + +/** MrvlIEtypes_PhyParamSet */ +struct MrvlIEtypes_PhyParamSet { + struct MrvlIEtypesHeader Header; + union { + struct FhParamSet FhParamSet[1]; + struct DsParamSet DsParamSet[1]; + } fh_ds; +} __attribute__ ((packed)); + +/** MrvlIEtypes_RsnParamSet */ +struct MrvlIEtypes_RsnParamSet { + struct MrvlIEtypesHeader Header; + u8 RsnIE[1]; +} __attribute__ ((packed)); + +struct MrvlIEtypes_TsfTimestamp { + struct MrvlIEtypesHeader Header; + u64 tsfTable[1]; +} __attribute__ ((packed)); + +/** Local Power Capability */ +struct MrvlIEtypes_PowerCapability { + struct MrvlIEtypesHeader Header; + s8 MinPower; + s8 MaxPower; +} __attribute__ ((packed)); + +/** MrvlIEtypes_RssiParamSet */ +struct MrvlIEtypes_RssiThreshold { + struct MrvlIEtypesHeader Header; + u8 RSSIValue; + u8 RSSIFreq; +} __attribute__ ((packed)); + +/** MrvlIEtypes_SnrThreshold */ +struct MrvlIEtypes_SnrThreshold { + struct MrvlIEtypesHeader Header; + u8 SNRValue; + u8 SNRFreq; +} __attribute__ ((packed)); + +/** MrvlIEtypes_FailureCountt */ +struct MrvlIEtypes_FailureCount { + struct MrvlIEtypesHeader Header; + u8 FailValue; + u8 FailFreq; +} __attribute__ ((packed)); + +/** MrvlIEtypes_BeaconsMissed */ +struct _rvlIEtypes_BeaconsMissed { + struct MrvlIEtypesHeader Header; + u8 BeaconMissed; + u8 Reserved; +} __attribute__ ((packed)); + +/** MrvlIEtypes_NumProbes */ +struct MrvlIEtypes_NumProbes { + struct MrvlIEtypesHeader Header; + u16 NumProbes; +} __attribute__ ((packed)); + +/** MrvlIEtypes_BcastProbe */ +struct MrvlIEtypes_BcastProbe { + struct MrvlIEtypesHeader Header; + u16 BcastProbe; +} __attribute__ ((packed)); + +/** MrvlIEtypes_NumSSIDProbe */ +struct MrvlIEtypes_NumSSIDProbe { + struct MrvlIEtypesHeader Header; + u16 NumSSIDProbe; +} __attribute__ ((packed)); + +struct Led_Pin { + u8 Led; + u8 Pin; +} __attribute__ ((packed)); + +/* MrvlIEtypes_LedGpio */ +struct MrvlIEtypes_LedGpio { + struct MrvlIEtypesHeader Header; + struct Led_Pin LedPin[1]; +} __attribute__ ((packed)); + +struct EthII_Hdr { + u8 dest_addr[ETH_ALEN]; + u8 src_addr[ETH_ALEN]; + u16 ethertype; +} __attribute__ ((packed)); + +#endif /* _WLAN_TYPES_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_version.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_version.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_version.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_version.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,36 @@ +/** @file wlan_version.h + * @brief This file contains wlan driver version number. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/04/05: Add Doxygen format comments + +********************************************************/ + +#define KERVER "26" +#define DRIVER_RELEASE_VERSION KERVER"318.p4" + +#define FPNUM "14" + +const char libertas_driver_version[] = "COMM-USB8388-%s-" DRIVER_RELEASE_VERSION +#ifdef DEBUG_LEVEL2 + "-dbg" +#endif + " "; diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_wext.c linux-2.6-libertas/drivers/net/wireless/libertas/wlan_wext.c --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_wext.c 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_wext.c 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,2745 @@ +/** @file wlan_wext.c + * @brief This file contains ioctl functions + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/10/05: Add Doxygen format comments + 12/23/05: Modify libertas_find_BSSID_in_list to search entire table for + duplicate BSSIDs when earlier matches are not compatible + 12/26/05: Remove errant memcpy in libertas_idle_off; overwriting stack space + 01/05/06: Add kernel 2.6.x support + 01/11/06: Change compile flag BULVERDE_SDIO to SD to support Monahans/Zylonite + 01/11/06: Conditionalize new scan/join functions. + Update statics/externs. Move forward decl. from wlan_decl.h + 04/06/06: Add TSPEC, queue metrics, and MSDU expiry support + 04/10/06: Add hostcmd generic API + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API +********************************************************/ + +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/wireless.h> + +#include <net/iw_handler.h> + +#include "host.h" +#include "radiotap.h" +#include "wlan_decl.h" +#include "wlan_defs.h" +#include "wlan_dev.h" +#include "wlan_join.h" +#include "wlan_version.h" +#include "wlan_wext.h" + + +/** + * @brief Convert mw value to dbm value + * + * @param mw the value of mw + * @return the value of dbm + */ +static int mw_to_dbm(int mw) +{ + if (mw < 2) + return 0; + else if (mw < 3) + return 3; + else if (mw < 4) + return 5; + else if (mw < 6) + return 7; + else if (mw < 7) + return 8; + else if (mw < 8) + return 9; + else if (mw < 10) + return 10; + else if (mw < 13) + return 11; + else if (mw < 16) + return 12; + else if (mw < 20) + return 13; + else if (mw < 25) + return 14; + else if (mw < 32) + return 15; + else if (mw < 40) + return 16; + else if (mw < 50) + return 17; + else if (mw < 63) + return 18; + else if (mw < 79) + return 19; + else if (mw < 100) + return 20; + else + return 21; +} + +/** + * @brief Find the channel frequency power info with specific channel + * + * @param adapter A pointer to wlan_adapter structure + * @param band it can be BAND_A, BAND_G or BAND_B + * @param channel the channel for looking + * @return A pointer to struct chan_freq_power structure or NULL if not find. + */ +struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter, + u8 band, u16 channel) +{ + struct chan_freq_power *cfp = NULL; + struct region_channel *rc; + int count = sizeof(adapter->region_channel) / + sizeof(adapter->region_channel[0]); + int i, j; + + for (j = 0; !cfp && (j < count); j++) { + rc = &adapter->region_channel[j]; + + if (adapter->State11D.Enable11D == ENABLE_11D) { + rc = &adapter->universal_channel[j]; + } + if (!rc->Valid || !rc->CFP) + continue; + if (rc->Band != band) + continue; + for (i = 0; i < rc->NrCFP; i++) { + if (rc->CFP[i].Channel == channel) { + cfp = &rc->CFP[i]; + break; + } + } + } + + if (!cfp && channel) + PRINTM(INFO, "libertas_find_cfp_by_band_and_channel(): cannot find " + "cfp by band %d & channel %d\n", band, channel); + + return cfp; +} + +/** + * @brief Find the channel frequency power info with specific frequency + * + * @param adapter A pointer to wlan_adapter structure + * @param band it can be BAND_A, BAND_G or BAND_B + * @param freq the frequency for looking + * @return A pointer to struct chan_freq_power structure or NULL if not find. + */ +static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, + u8 band, u32 freq) +{ + struct chan_freq_power *cfp = NULL; + struct region_channel *rc; + int count = sizeof(adapter->region_channel) / + sizeof(adapter->region_channel[0]); + int i, j; + + for (j = 0; !cfp && (j < count); j++) { + rc = &adapter->region_channel[j]; + + if (adapter->State11D.Enable11D == ENABLE_11D) { + rc = &adapter->universal_channel[j]; + } + + if (!rc->Valid || !rc->CFP) + continue; + if (rc->Band != band) + continue; + for (i = 0; i < rc->NrCFP; i++) { + if (rc->CFP[i].Freq == freq) { + cfp = &rc->CFP[i]; + break; + } + } + } + + if (!cfp && freq) + PRINTM(INFO, "find_cfp_by_band_and_freql(): cannot find cfp by " + "band %d & freq %d\n", band, freq); + + return cfp; +} + +/** + * @brief Update Current Channel + * + * @param priv A pointer to wlan_private structure + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +static int UpdateCurrentChannel(wlan_private * priv) +{ + int ret; + + /* + ** the channel in f/w could be out of sync, get the current channel + */ + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RF_CHANNEL, + HostCmd_OPT_802_11_RF_CHANNEL_GET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + PRINTM(INFO, "Current Channel = %d\n", + priv->adapter->CurBssParams.channel); + + return ret; +} + +/** + * @brief Set Current Channel + * + * @param priv A pointer to wlan_private structure + * @param channel The channel to be set. + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +static int SetCurrentChannel(wlan_private * priv, int channel) +{ + PRINTM(INFO, "Set Channel = %d\n", channel); + + /* + ** Current channel is not set to AdhocChannel requested, set channel + */ + return (libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_RF_CHANNEL, + HostCmd_OPT_802_11_RF_CHANNEL_SET, + HostCmd_OPTION_WAITFORRSP, 0, &channel)); +} + +/** + * @brief Change Adhoc Channel + * + * @param priv A pointer to wlan_private structure + * @param channel The channel to be set. + * @return WLAN_STATUS_SUCCESS--success, WLAN_STATUS_FAILURE--fail + */ +static int ChangeAdhocChannel(wlan_private * priv, int channel) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_adapter *Adapter = priv->adapter; + + Adapter->AdhocChannel = channel; + + UpdateCurrentChannel(priv); + + if (Adapter->CurBssParams.channel == Adapter->AdhocChannel) { + /* AdhocChannel is set to the current Channel already */ + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + PRINTM(INFO, "Updating Channel from %d to %d\n", + Adapter->CurBssParams.channel, Adapter->AdhocChannel); + + SetCurrentChannel(priv, Adapter->AdhocChannel); + + UpdateCurrentChannel(priv); + + if (Adapter->CurBssParams.channel != Adapter->AdhocChannel) { + PRINTM(INFO, "Failed to updated Channel to %d, channel = %d\n", + Adapter->AdhocChannel, Adapter->CurBssParams.channel); + LEAVE(); + return WLAN_STATUS_FAILURE; + } + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + int i; + struct WLAN_802_11_SSID curAdhocSsid; + + PRINTM(INFO, "Channel Changed while in an IBSS\n"); + + /* Copy the current ssid */ + memcpy(&curAdhocSsid, &Adapter->CurBssParams.ssid, + sizeof(struct WLAN_802_11_SSID)); + + /* Exit Adhoc mode */ + PRINTM(INFO, "In ChangeAdhocChannel(): Sending Adhoc Stop\n"); + ret = libertas_stop_adhoc_network(priv); + + if (ret) { + LEAVE(); + return ret; + } + /* Scan for the network, do not save previous results. Stale + * scan data will cause us to join a non-existant adhoc network + */ + libertas_send_specific_SSID_scan(priv, &curAdhocSsid, 0); + + // find out the BSSID that matches the current SSID + i = libertas_find_SSID_in_list(Adapter, &curAdhocSsid, NULL, + Wlan802_11IBSS); + + if (i >= 0) { + PRINTM(INFO, "SSID found at %d in List," + "so join\n", i); + libertas_join_adhoc_network(priv, &Adapter->ScanTable[i]); + } else { + // else send START command + PRINTM(INFO, "SSID not found in list, " + "so creating adhoc with ssid = %s\n", + curAdhocSsid.Ssid); + libertas_start_adhoc_network(priv, &curAdhocSsid); + } // end of else (START command) + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set WPA key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_encode_wpa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + struct WLAN_802_11_KEY *pKey; + + ENTER(); + + pKey = (struct WLAN_802_11_KEY *)extra; + + HEXDUMP("Key buffer: ", extra, dwrq->length); + + HEXDUMP("KeyMaterial: ", (u8 *) pKey->KeyMaterial, pKey->KeyLength); + + // current driver only supports key length of up to 32 bytes + if (pKey->KeyLength > MRVL_MAX_WPA_KEY_LENGTH) { + PRINTM(INFO, " Error in key length \n"); + return WLAN_STATUS_FAILURE; + } + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_KEY_MATERIAL, + HostCmd_ACT_SET, + HostCmd_OPTION_WAITFORRSP, + KEY_INFO_ENABLED, pKey); + if (ret) { + LEAVE(); + return ret; + } + + LEAVE(); + return ret; +} + +/* + * iwconfig ethX key on: WEPEnabled; + * iwconfig ethX key off: WEPDisabled; + * iwconfig ethX key [x]: CurrentWepKeyIndex = x; WEPEnabled; + * iwconfig ethX key [x] kstr: WepKey[x] = kstr; + * iwconfig ethX key kstr: WepKey[CurrentWepKeyIndex] = kstr; + * + * all: Send command SET_WEP; + libertas_set_mac_packet_filter; + */ + +/** + * @brief Set WEP key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_encode_nonwpa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + struct MRVL_WEP_KEY *pWep; + struct WLAN_802_11_SSID ssid; + int index, PrevAuthMode; + + ENTER(); + + pWep = &Adapter->WepKey[Adapter->CurrentWepKeyIndex]; + PrevAuthMode = Adapter->SecInfo.AuthenticationMode; + + index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (index >= 4) { + PRINTM(INFO, "Key index #%d out of range.\n", index + 1); + return -EINVAL; + } + + PRINTM(INFO, "Flags=0x%x, Length=%d Index=%d CurrentWepKeyIndex=%d\n", + dwrq->flags, dwrq->length, index, Adapter->CurrentWepKeyIndex); + + if (dwrq->length > 0) { + /* iwconfig ethX key [n] xxxxxxxxxxx + * Key has been provided by the user + */ + + /* + * Check the size of the key + */ + + if (dwrq->length > MAX_WEP_KEY_SIZE) { + return -EINVAL; + } + + /* + * Check the index (none -> use current) + */ + + if (index < 0 || index > 3) //invalid index or no index + index = Adapter->CurrentWepKeyIndex; + else //index is given & valid + pWep = &Adapter->WepKey[index]; + + /* + * Check if the key is not marked as invalid + */ + if (!(dwrq->flags & IW_ENCODE_NOKEY)) { + /* Cleanup */ + memset(pWep, 0, sizeof(struct MRVL_WEP_KEY)); + + /* Copy the key in the driver */ + memcpy(pWep->KeyMaterial, extra, dwrq->length); + + /* Set the length */ + if (dwrq->length > MIN_WEP_KEY_SIZE) { + pWep->KeyLength = MAX_WEP_KEY_SIZE; + } else { + if (dwrq->length > 0) { + pWep->KeyLength = MIN_WEP_KEY_SIZE; + } else { + /* Disable the key */ + pWep->KeyLength = 0; + } + } + pWep->KeyIndex = index; + + if (Adapter->SecInfo.WEPStatus != Wlan802_11WEPEnabled) { + /* + * The status is set as Key Absent + * so as to make sure we display the + * keys when iwlist ethX key is + * used - MPS + */ + + Adapter->SecInfo.WEPStatus = + Wlan802_11WEPKeyAbsent; + } + + PRINTM(INFO, "KeyIndex=%u KeyLength=%u\n", + pWep->KeyIndex, pWep->KeyLength); + HEXDUMP("WepKey", (u8 *) pWep->KeyMaterial, + pWep->KeyLength); + } + } else { + /* + * No key provided so it is either enable key, + * on or off */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + PRINTM(INFO, + "******** iwconfig ethX key off **********\n"); + + Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled; + if (Adapter->SecInfo.AuthenticationMode == + Wlan802_11AuthModeShared) + Adapter->SecInfo.AuthenticationMode = + Wlan802_11AuthModeOpen; + } else { + /* iwconfig ethX key [n] + * iwconfig ethX key on + * Do we want to just set the transmit key index ? + */ + + if (index < 0 || index > 3) { + PRINTM(INFO, + "******** iwconfig ethX key on **********\n"); + index = Adapter->CurrentWepKeyIndex; + } else { + PRINTM(INFO, + "******** iwconfig ethX key [x=%d] **********\n", + index); + Adapter->CurrentWepKeyIndex = index; + } + + /* Copy the required key as the current key */ + pWep = &Adapter->WepKey[index]; + + if (!pWep->KeyLength) { + PRINTM(INFO, + "Key not set,so cannot enable it\n"); + return -EPERM; + } + + Adapter->SecInfo.WEPStatus = Wlan802_11WEPEnabled; + + HEXDUMP("KeyMaterial", (u8 *) pWep->KeyMaterial, + pWep->KeyLength); + } + } + + if (pWep->KeyLength) { + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SET_WEP, + 0, HostCmd_OPTION_WAITFORRSP, + OID_802_11_ADD_WEP, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } + + if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) { + Adapter->CurrentPacketFilter |= HostCmd_ACT_MAC_WEP_ENABLE; + } else { + Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + } + + libertas_set_mac_packet_filter(priv); + + if (dwrq->flags & IW_ENCODE_RESTRICTED) { + /* iwconfig ethX restricted key [1] */ + Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeShared; + PRINTM(INFO, "Authentication mode restricted!\n"); + } else if (dwrq->flags & IW_ENCODE_OPEN) { + /* iwconfig ethX key [2] open */ + Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen; + PRINTM(INFO, "Authentication mode open!\n"); + } + + /* + * If authentication mode changed - de-authenticate, set authentication + * method and re-associate if we were previously associated. + */ + if (Adapter->SecInfo.AuthenticationMode != PrevAuthMode) { + if (Adapter->MediaConnectStatus == WlanMediaStateConnected && + Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + + /* keep a copy of the ssid associated with */ + memcpy(&ssid, &Adapter->CurBssParams.ssid, + sizeof(ssid)); + + /* + * De-authenticate from AP + */ + + ret = libertas_send_deauthentication(priv); + + if (ret) { + LEAVE(); + return ret; + } + + } else { + /* reset ssid */ + memset(&ssid, 0, sizeof(ssid)); + } + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Radio On/OFF + * + * @param priv A pointer to wlan_private structure + * @option Radio Option + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_radio_ioctl(wlan_private * priv, u8 option) +{ + int ret = 0; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (Adapter->RadioOn != option) { + PRINTM(INFO, "Switching %s the Radio\n", option ? "On" : "Off"); + Adapter->RadioOn = option; + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RADIO_CONTROL, + HostCmd_ACT_GEN_SET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + } + + LEAVE(); + return ret; +} + +/** + * @brief Copy Rates + * + * @param dest A pointer to Dest Buf + * @param src A pointer to Src Buf + * @param len The len of Src Buf + * @return Number of Rates copyed + */ +static inline int CopyRates(u8 * dest, int pos, u8 * src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + + return pos; +} + +/** + * @brief Get active data rates + * + * @param Adapter A pointer to wlan_adapter structure + * @param rate The buf to return the active rates + * @return The number of Rates + */ +static int get_active_data_rates(wlan_adapter * Adapter, + u8* rates) +{ + int k = 0; + + ENTER(); + + if (Adapter->MediaConnectStatus != WlanMediaStateConnected) { + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + //Infra. mode + PRINTM(INFO, "Infra\n"); + k = CopyRates(rates, k, libertas_supported_rates, + sizeof(libertas_supported_rates)); + } else { + //ad-hoc mode + PRINTM(INFO, "Adhoc G\n"); + k = CopyRates(rates, k, libertas_adhoc_rates_g, + sizeof(libertas_adhoc_rates_g)); + } + } else { + k = CopyRates(rates, 0, Adapter->CurBssParams.DataRates, + Adapter->CurBssParams.NumOfRates); + } + + LEAVE(); + + return k; +} + +/** + * @brief Commit handler: called after a bunch of SET operations + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_config_commit(struct net_device *dev, + struct iw_request_info *info, + char *cwrq, char *extra) +{ + ENTER(); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get protocol name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + const char *cp; + char comm[6] = { "COMM-" }; + char mrvl[6] = { "MRVL-" }; + int cnt; + + ENTER(); + + strcpy(cwrq, mrvl); + + cp = strstr(libertas_driver_version, comm); + if (cp == libertas_driver_version) //skip leading "COMM-" + cp = libertas_driver_version + strlen(comm); + else + cp = libertas_driver_version; + + cnt = strlen(mrvl); + cwrq += cnt; + while (cnt < 16 && (*cp != '-')) { + *cwrq++ = toupper(*cp++); + cnt++; + } + *cwrq = '\0'; + + LEAVE(); + + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get frequency + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param fwrq A pointer to iw_freq structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + struct chan_freq_power *cfp; + + ENTER(); + + cfp = libertas_find_cfp_by_band_and_channel(Adapter, 0, + Adapter->CurBssParams.channel); + + if (!cfp) { + if (Adapter->CurBssParams.channel) + PRINTM(INFO, "Invalid channel=%d\n", + Adapter->CurBssParams.channel); + return -EINVAL; + } + + fwrq->m = (long)cfp->Freq * 100000; + fwrq->e = 1; + + PRINTM(INFO, "freq=%u\n", fwrq->m); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get current BSSID + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + memcpy(awrq->sa_data, Adapter->CurBssParams.bssid, ETH_ALEN); + } else { + memset(awrq->sa_data, 0, ETH_ALEN); + } + awrq->sa_family = ARPHRD_ETHER; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Adapter Node Name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* + * Check the size of the string + */ + + if (dwrq->length > 16) { + return -E2BIG; + } + + memset(Adapter->nodeName, 0, sizeof(Adapter->nodeName)); + memcpy(Adapter->nodeName, extra, dwrq->length); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Adapter Node Name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* + * Get the Nick Name saved + */ + + strncpy(extra, Adapter->nodeName, 16); + + extra[16] = '\0'; + + /* + * If none, we may want to get the one that was set + */ + + /* + * Push it out ! + */ + dwrq->length = strlen(extra) + 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set RTS threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int rthr = vwrq->value; + + ENTER(); + + if (vwrq->disabled) { + Adapter->RTSThsd = rthr = MRVDRV_RTS_MAX_VALUE; + } else { + if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) + return -EINVAL; + Adapter->RTSThsd = rthr; + } + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP, + OID_802_11_RTS_THRESHOLD, &rthr); + + LEAVE(); + return ret; +} + +/** + * @brief Get RTS threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + Adapter->RTSThsd = 0; + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP, + OID_802_11_RTS_THRESHOLD, NULL); + if (ret) { + LEAVE(); + return ret; + } + + vwrq->value = Adapter->RTSThsd; + vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) + || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); + vwrq->fixed = 1; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Fragment threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + int fthr = vwrq->value; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (vwrq->disabled) { + Adapter->FragThsd = fthr = MRVDRV_FRAG_MAX_VALUE; + } else { + if (fthr < MRVDRV_FRAG_MIN_VALUE + || fthr > MRVDRV_FRAG_MAX_VALUE) + return -EINVAL; + Adapter->FragThsd = fthr; + } + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_SET, HostCmd_OPTION_WAITFORRSP, + OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); + LEAVE(); + return ret; +} + +/** + * @brief Get Fragment threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + Adapter->FragThsd = 0; + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP, + OID_802_11_FRAGMENTATION_THRESHOLD, NULL); + if (ret) { + LEAVE(); + return ret; + } + + vwrq->value = Adapter->FragThsd; + vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) + || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); + vwrq->fixed = 1; + + LEAVE(); + return ret; +} + +/** + * @brief Get Wlan Mode + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + switch (adapter->InfrastructureMode) { + case Wlan802_11IBSS: + *uwrq = IW_MODE_ADHOC; + break; + + case Wlan802_11Infrastructure: + *uwrq = IW_MODE_INFRA; + break; + + default: + case Wlan802_11AutoUnknown: + *uwrq = IW_MODE_AUTO; + break; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, u8 * extra) +{ + + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + int index = (dwrq->flags & IW_ENCODE_INDEX); + + ENTER(); + + PRINTM(INFO, "flags=0x%x index=%d length=%d CurrentWepKeyIndex=%d\n", + dwrq->flags, index, dwrq->length, adapter->CurrentWepKeyIndex); + + dwrq->flags = 0; + + /* + * Check encryption mode + */ + + switch (adapter->SecInfo.AuthenticationMode) { + case Wlan802_11AuthModeOpen: + dwrq->flags = IW_ENCODE_OPEN; + break; + + case Wlan802_11AuthModeShared: + case Wlan802_11AuthModeNetworkEAP: + dwrq->flags = IW_ENCODE_RESTRICTED; + break; + default: + dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; + break; + } + + if ((adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) + || (adapter->SecInfo.WEPStatus == Wlan802_11WEPKeyAbsent) + || adapter->SecInfo.WPAEnabled || adapter->SecInfo.WPA2Enabled) { + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + memset(extra, 0, 16); + + if (!index) { + /* Handle current key request */ + if ((adapter->WepKey[adapter->CurrentWepKeyIndex].KeyLength) && + (adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled)) { + index = + adapter->WepKey[adapter->CurrentWepKeyIndex]. + KeyIndex; + memcpy(extra, adapter->WepKey[index].KeyMaterial, + adapter->WepKey[index].KeyLength); + dwrq->length = adapter->WepKey[index].KeyLength; + /* return current key */ + dwrq->flags |= (index + 1); + /* return WEP enabled */ + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else if ((adapter->SecInfo.WPAEnabled) + || (adapter->SecInfo.WPA2Enabled) + ) { + /* return WPA enabled */ + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + } else { + /* Handle specific key requests */ + index--; + if (adapter->WepKey[index].KeyLength) { + memcpy(extra, adapter->WepKey[index].KeyMaterial, + adapter->WepKey[index].KeyLength); + dwrq->length = adapter->WepKey[index].KeyLength; + /* return current key */ + dwrq->flags |= (index + 1); + /* return WEP enabled */ + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else if ((adapter->SecInfo.WPAEnabled) + || (adapter->SecInfo.WPA2Enabled) + ) { + /* return WPA enabled */ + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + } + + dwrq->flags |= IW_ENCODE_NOKEY; + + PRINTM(INFO, "Key:%02x:%02x:%02x:%02x:%02x:%02x KeyLen=%d\n", + extra[0], extra[1], extra[2], + extra[3], extra[4], extra[5], dwrq->length); + + if (adapter->EncryptionStatus == Wlan802_11Encryption2Enabled + && !dwrq->length) { + dwrq->length = MAX_WEP_KEY_SIZE; + } + + PRINTM(INFO, "Return flags=0x%x\n", dwrq->flags); + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get TX Power + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_txpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RF_TX_POWER, + HostCmd_ACT_TX_POWER_OPT_GET, + HostCmd_OPTION_WAITFORRSP, 0, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + PRINTM(INFO, "TXPOWER GET %d dbm.\n", Adapter->TxPowerLevel); + vwrq->value = Adapter->TxPowerLevel; + vwrq->fixed = 1; + if (Adapter->RadioOn) { + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; + } else { + vwrq->disabled = 1; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set TX Retry Count + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *adapter = priv->adapter; + + ENTER(); + + if (vwrq->flags == IW_RETRY_LIMIT) { + /* The MAC has a 4-bit Total_Tx_Count register + Total_Tx_Count = 1 + Tx_Retry_Count */ +#define TX_RETRY_MIN 0 +#define TX_RETRY_MAX 14 + if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) + return -EINVAL; + + /* Adding 1 to convert retry count to try count */ + adapter->TxRetryCount = vwrq->value + 1; + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_SET, + HostCmd_OPTION_WAITFORRSP, + OID_802_11_TX_RETRYCOUNT, NULL); + + if (ret) { + LEAVE(); + return ret; + } + } else { + return -EOPNOTSUPP; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get TX Retry Count + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + + ENTER(); + Adapter->TxRetryCount = 0; + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GET, HostCmd_OPTION_WAITFORRSP, + OID_802_11_TX_RETRYCOUNT, NULL); + if (ret) { + LEAVE(); + return ret; + } + vwrq->disabled = 0; + if (!vwrq->flags) { + vwrq->flags = IW_RETRY_LIMIT; + /* Subtract 1 to convert try count to retry count */ + vwrq->value = Adapter->TxRetryCount - 1; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Sort Channels + * + * @param freq A pointer to iw_freq structure + * @param num number of Channels + * @return NA + */ +static inline void sort_channels(struct iw_freq *freq, int num) +{ + int i, j; + struct iw_freq temp; + + for (i = 0; i < num; i++) + for (j = i + 1; j < num; j++) + if (freq[i].i > freq[j].i) { + temp.i = freq[i].i; + temp.m = freq[i].m; + + freq[i].i = freq[j].i; + freq[i].m = freq[j].m; + + freq[j].i = temp.i; + freq[j].m = temp.m; + } +} + +/* data rate listing + MULTI_BANDS: + abg a b b/g + Infra G(12) A(8) B(4) G(12) + Adhoc A+B(12) A(8) B(4) B(4) + + non-MULTI_BANDS: + b b/g + Infra B(4) G(12) + Adhoc B(4) B(4) + */ +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int i, j; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + struct iw_range *range = (struct iw_range *)extra; + struct chan_freq_power *cfp; + u8 rates[WLAN_SUPPORTED_RATES]; + + u8 flag = 0; + + ENTER(); + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + memset(rates, 0, sizeof(rates)); + range->num_bitrates = get_active_data_rates(Adapter, rates); + + for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; + i++) { + range->bitrate[i] = (rates[i] & 0x7f) * 500000; + } + range->num_bitrates = i; + PRINTM(INFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES, + range->num_bitrates); + + range->num_frequency = 0; + if (libertas_get_state_11d(priv) == ENABLE_11D && + Adapter->MediaConnectStatus == WlanMediaStateConnected) { + u8 chan_no; + u8 band; + + struct parsed_region_chan_11d *parsed_region_chan = + &Adapter->parsed_region_chan; + + if (parsed_region_chan == NULL) { + PRINTM(INFO, "11D:parsed_region_chan is NULL\n"); + LEAVE(); + return 0; + } + band = parsed_region_chan->band; + PRINTM(INFO, "band=%d NoOfChan=%d\n", band, + parsed_region_chan->NoOfChan); + + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (i < parsed_region_chan->NoOfChan); i++) { + chan_no = parsed_region_chan->chanPwr[i].chan; + PRINTM(INFO, "chan_no=%d\n", chan_no); + range->freq[range->num_frequency].i = (long)chan_no; + range->freq[range->num_frequency].m = + (long)libertas_chan_2_freq(chan_no, band) * 100000; + range->freq[range->num_frequency].e = 1; + range->num_frequency++; + } + flag = 1; + } + if (!flag) { + for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (j < sizeof(Adapter->region_channel) + / sizeof(Adapter->region_channel[0])); j++) { + cfp = Adapter->region_channel[j].CFP; + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && Adapter->region_channel[j].Valid + && cfp + && (i < Adapter->region_channel[j].NrCFP); i++) { + range->freq[range->num_frequency].i = + (long)cfp->Channel; + range->freq[range->num_frequency].m = + (long)cfp->Freq * 100000; + range->freq[range->num_frequency].e = 1; + cfp++; + range->num_frequency++; + } + } + } + + PRINTM(INFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n", + IW_MAX_FREQUENCIES, range->num_frequency); + + range->num_channels = range->num_frequency; + + sort_channels(&range->freq[0], range->num_frequency); + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + if (i > 2) + range->throughput = 5000 * 1000; + else + range->throughput = 1500 * 1000; + + range->min_rts = MRVDRV_RTS_MIN_VALUE; + range->max_rts = MRVDRV_RTS_MAX_VALUE; + range->min_frag = MRVDRV_FRAG_MIN_VALUE; + range->max_frag = MRVDRV_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + range->min_pmp = 1000000; + range->max_pmp = 120000000; + range->min_pmt = 1000; + range->max_pmt = 1000000; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = TX_RETRY_MIN; + range->max_retry = TX_RETRY_MAX; + + /* + * Set the qual, level and noise range values + */ + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->avg_qual.qual = 70; + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->sensitivity = 0; + + /* + * Setup the supported power level ranges + */ + memset(range->txpower, 0, sizeof(range->txpower)); + range->txpower[0] = 5; + range->txpower[1] = 7; + range->txpower[2] = 9; + range->txpower[3] = 11; + range->txpower[4] = 13; + range->txpower[5] = 15; + range->txpower[6] = 17; + range->txpower[7] = 19; + + range->num_txpower = 8; + range->txpower_capa = IW_TXPOW_DBM; + range->txpower_capa |= IW_TXPOW_RANGE; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set power management + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + /* PS is currently supported only in Infrastructure Mode + * Remove this check if it is to be supported in IBSS mode also + */ + + if (vwrq->disabled) { + Adapter->PSMode = Wlan802_11PowerModeCAM; + if (Adapter->PSState != PS_STATE_FULL_POWER) { + libertas_ps_wakeup(priv, HostCmd_OPTION_WAITFORRSP); + } + + return 0; + } + + if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + PRINTM(INFO, + "Setting power timeout command is not supported\n"); + return -EINVAL; + } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { + PRINTM(INFO, "Setting power period command is not supported\n"); + return -EINVAL; + } + + if (Adapter->PSMode != Wlan802_11PowerModeCAM) { + return WLAN_STATUS_SUCCESS; + } + + Adapter->PSMode = Wlan802_11PowerModeMAX_PSP; + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + libertas_ps_sleep(priv, HostCmd_OPTION_WAITFORRSP); + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get power management + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int mode; + + ENTER(); + + mode = Adapter->PSMode; + + if ((vwrq->disabled = (mode == Wlan802_11PowerModeCAM)) + || Adapter->MediaConnectStatus == WlanMediaStateDisconnected) { + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + vwrq->value = 0; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set sensitivity threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int wlan_set_sens(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ENTER(); + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get sensitivity threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_FAILURE + */ +static int wlan_get_sens(struct net_device *dev, + struct iw_request_info *info, struct iw_param *vwrq, + char *extra) +{ + ENTER(); + LEAVE(); + return WLAN_STATUS_FAILURE; +} + +/* + * iwpriv settable callbacks + */ + +static const iw_handler wlan_private_handler[] = { + NULL, /* SIOCIWFIRSTPRIV */ +}; + +static const struct iw_priv_args wlan_private_args[] = { + /* + * { cmd, set_args, get_args, name } + */ + { + WLANEXTSCAN, + IW_PRIV_TYPE_INT, + IW_PRIV_TYPE_CHAR | 2, + "extscan"}, + + { + WLANCISDUMP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_BYTE | 512, + "getcis"}, + + { + WLANSCAN_TYPE, + IW_PRIV_TYPE_CHAR | 8, + IW_PRIV_TYPE_CHAR | 8, + "scantype"}, + + { + WLAN_SETINT_GETINT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + { + WLANNF, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getNF"}, + { + WLANRSSI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getRSSI"}, + { + WLANENABLE11D, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "enable11d"}, + { + WLANADHOCGRATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "adhocgrate"}, + + { + WLAN_SUBCMD_SET_PRESCAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "prescan"}, + { + WLAN_SETONEINT_GETONEINT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + ""}, + { + WLAN_BEACON_INTERVAL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "bcninterval"}, + { + WLAN_LISTENINTRVL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "lolisteninter"}, + { + WLAN_TXCONTROL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "txcontrol"}, + { + WLAN_NULLPKTINTERVAL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "psnullinterval"}, + /* Using iwpriv sub-command feature */ + { + WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */ + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + ""}, + + { + WLAN_SUBCMD_SETRXANTENNA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setrxant"}, + { + WLAN_SUBCMD_SETTXANTENNA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "settxant"}, + { + WLANSETAUTHALG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "authalgs", + }, + { + WLANSET8021XAUTHALG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "8021xauthalgs", + }, + { + WLANSETENCRYPTIONMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "encryptionmode", + }, + { + WLANSETREGION, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setregioncode"}, + { + WLAN_SET_LISTEN_INTERVAL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setlisteninter"}, + { + WLAN_SET_MULTIPLE_DTIM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setmultipledtim"}, + { + WLAN_SET_ATIM_WINDOW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "atimwindow"}, + { + WLANSETBCNAVG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setbcnavg"}, + { + WLANSETDATAAVG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "setdataavg"}, + { + WLAN_SET_LINKMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "linkmode"}, + { + WLAN_SET_RADIOMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "radiomode"}, + { + WLAN_SET_DEBUGMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_NONE, + "debugmode"}, + { + WLAN_SETNONE_GETONEINT, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + { + WLANGETREGION, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getregioncode"}, + { + WLAN_GET_LISTEN_INTERVAL, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getlisteninter"}, + { + WLAN_GET_MULTIPLE_DTIM, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getmultipledtim"}, + { + WLAN_GET_TX_RATE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "gettxrate"}, + { + WLANGETBCNAVG, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getbcnavg"}, + { + WLAN_GET_LINKMODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_linkmode"}, + { + WLAN_GET_RADIOMODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_radiomode"}, + { + WLAN_GET_DEBUGMODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_debugmode"}, + { + WLAN_SETNONE_GETTWELVE_CHAR, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + ""}, + { + WLAN_SUBCMD_GETRXANTENNA, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "getrxant"}, + { + WLAN_SUBCMD_GETTXANTENNA, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "gettxant"}, + { + WLAN_GET_TSF, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "gettsf"}, + { + WLAN_SETNONE_GETNONE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + ""}, + { + WLANDEAUTH, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "deauth"}, + { + WLANADHOCSTOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "adhocstop"}, + { + WLANRADIOON, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "radioon"}, + { + WLANRADIOOFF, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "radiooff"}, +#ifdef REASSOCIATION + { + WLANREASSOCIATIONAUTO, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "reasso-on"}, + { + WLANREASSOCIATIONUSER, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "reasso-off"}, +#endif /* REASSOCIATION */ + { + WLANWLANIDLEON, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "wlanidle-on"}, + { + WLANWLANIDLEOFF, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "wlanidle-off"}, + { + WLAN_SUBCMD_DFT_RESET, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "dft_reset"}, + { + WLAN_SUBCMD_BT_RESET, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "bt_reset"}, + { + WLAN_SET64CHAR_GET64CHAR, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + ""}, + { + WLANSLEEPPARAMS, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "sleepparams"}, + /* DFT Management */ + { + WLAN_SUBCMD_DFT_ADD, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "dft_add"}, + { + WLAN_SUBCMD_DFT_DEL, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "dft_del"}, + { + WLAN_SUBCMD_DFT_LIST, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "dft_list"}, + /* BT Management */ + { + WLAN_SUBCMD_BT_ADD, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "bt_add"}, + { + WLAN_SUBCMD_BT_DEL, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "bt_del"}, + { + WLAN_SUBCMD_BT_LIST, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "bt_list"}, + { + WLANSCAN_MODE, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "scanmode"}, + { + WLAN_GET_ADHOC_STATUS, + IW_PRIV_TYPE_CHAR | 64, + IW_PRIV_TYPE_CHAR | 64, + "getadhocstatus"}, + { + WLAN_SETWORDCHAR_GETNONE, + IW_PRIV_TYPE_CHAR | 32, + IW_PRIV_TYPE_NONE, + ""}, + { + WLAN_SETNONE_GETWORDCHAR, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 128, + ""}, + { + WLANVERSION, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 128, + "version"}, + { + WLANSETWPAIE, + IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24, + IW_PRIV_TYPE_NONE, + "setwpaie"}, + { + WLAN_SETTENCHAR_GETNONE, + IW_PRIV_TYPE_CHAR | 10, + IW_PRIV_TYPE_NONE, + ""}, + { + WLAN_SETNONE_GETTENCHAR, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 10, + ""}, + { + WLANGETLOG, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE, + "getlog"}, + { + WLAN_SET_GET_SIXTEEN_INT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + ""}, + { + WLAN_TPCCFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "tpccfg"}, + { + WLAN_POWERCFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "powercfg"}, + { + WLAN_AUTO_FREQ_SET, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "setafc"}, + { + WLAN_AUTO_FREQ_GET, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getafc"}, + { + WLAN_SCANPROBES, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "scanprobes"}, + { + WLAN_LED_GPIO_CTRL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "ledgpio"}, + { + WLAN_SLEEP_PERIOD, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "sleeppd"}, + { + WLAN_ADAPT_RATESET, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "rateadapt"}, + + { + WLAN_INACTIVITY_TIMEOUT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "inactivityto"}, + { + WLANSNR, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getSNR"}, + { + WLAN_GET_RATE, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getrate"}, + { + WLAN_GET_RXINFO, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getrxinfo"}, + + { + WLAN_SET_GET_2K, /* IOCTL : 14 */ + IW_PRIV_TYPE_BYTE | 2000, + IW_PRIV_TYPE_BYTE | 2000, + ""}, + + { + WLAN_SET_USER_SCAN, + IW_PRIV_TYPE_BYTE | 2000, + IW_PRIV_TYPE_BYTE | 2000, + "setuserscan"}, + { + WLAN_GET_SCAN_TABLE, + IW_PRIV_TYPE_BYTE | 2000, + IW_PRIV_TYPE_BYTE | 2000, + "getscantable"}, +}; + +/** + * @brief Get wireless statistics + * + * @param dev A pointer to net_device structure + * @return A pointer to iw_statistics buf + */ +static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) +{ + enum { + POOR = 30, + FAIR = 60, + GOOD = 80, + VERY_GOOD = 90, + EXCELLENT = 95, + PERFECT = 100 + }; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int ret = WLAN_STATUS_SUCCESS; + u32 rssi_qual; + u32 tx_qual; + u32 quality = 0; + int stats_valid = 0; + u8 rssi; + + ENTER(); + + priv->wstats.status = Adapter->InfrastructureMode; + + /* If we're not associated, all quality values are meaningless */ + if (Adapter->MediaConnectStatus != WlanMediaStateConnected) + goto out; + + /* send RSSI command to get beacon RSSI/NF, valid only if associated */ + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RSSI, + 0, HostCmd_OPTION_WAITFORRSP, 0, NULL); + if (ret) + goto out; + + /* Quality by RSSI */ + priv->wstats.qual.level = + CAL_RSSI(Adapter->SNR[TYPE_BEACON][TYPE_NOAVG], + Adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + + if (Adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; + } else { + priv->wstats.qual.noise = + CAL_NF(Adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + } + + PRINTM(INFO, "Signal Level = %#x\n", priv->wstats.qual.level); + PRINTM(INFO, "Noise = %#x\n", priv->wstats.qual.noise); + + rssi = priv->wstats.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; + if (rssi < 15) + rssi_qual = rssi * POOR / 10; + else if (rssi < 20) + rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR; + else if (rssi < 30) + rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR; + else if (rssi < 40) + rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / + 10 + GOOD; + else + rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / + 10 + VERY_GOOD; + quality = rssi_qual; + + /* Quality by TX errors */ + priv->wstats.discard.retries = priv->stats.tx_errors; + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_GET_LOG, + 0, HostCmd_OPTION_WAITFORRSP, 0, NULL); + if (!ret) { + u32 tx_retries = Adapter->LogMsg.retry; + + if (tx_retries > 75) + tx_qual = (90 - tx_retries) * POOR / 15; + else if (tx_retries > 70) + tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; + else if (tx_retries > 65) + tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; + else if (tx_retries > 50) + tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / + 15 + GOOD; + else + tx_qual = (50 - tx_retries) * + (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; + quality = min(quality, tx_qual); + + priv->wstats.discard.code = Adapter->LogMsg.wepundecryptable; + priv->wstats.discard.fragment = Adapter->LogMsg.fcserror; + priv->wstats.discard.retries = tx_retries; + priv->wstats.discard.misc = Adapter->LogMsg.ackfailure; + } + + /* Calculate quality */ + priv->wstats.qual.qual = max(quality, (u32)100); + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; + stats_valid = 1; + +out: + if (!stats_valid) { + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; + priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + } + + LEAVE (); + return &priv->wstats; + + +} + +/** + * @brief Set frequency + * + * @param priv A pointer to wlan_private structure + * @param info A pointer to iw_request_info structure + * @param fwrq A pointer to iw_freq structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS--success, otherwise--fail + */ +int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + int rc = -EINPROGRESS; /* Call commit handler */ + struct chan_freq_power *cfp; + + ENTER(); + + /* + * If setting by frequency, convert to a channel + */ + if (fwrq->e == 1) { + + long f = fwrq->m / 100000; + int c = 0; + + cfp = find_cfp_by_band_and_freq(Adapter, 0, f); + if (!cfp) { + PRINTM(INFO, "Invalid freq=%ld\n", f); + return -EINVAL; + } + + c = (int)cfp->Channel; + + if (c < 0) + return -EINVAL; + + fwrq->e = 0; + fwrq->m = c; + } + + /* + * Setting by channel number + */ + if (fwrq->m > 1000 || fwrq->e > 0) { + rc = -EOPNOTSUPP; + } else { + int channel = fwrq->m; + + cfp = libertas_find_cfp_by_band_and_channel(Adapter, 0, channel); + if (!cfp) { + rc = -EINVAL; + } else { + if (Adapter->InfrastructureMode == Wlan802_11IBSS) { + rc = ChangeAdhocChannel(priv, channel); + /* If station is WEP enabled, send the + * command to set WEP in firmware + */ + if (Adapter->SecInfo.WEPStatus == + Wlan802_11WEPEnabled) { + PRINTM(INFO, "set_freq: WEP Enabled\n"); + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SET_WEP, + 0, + HostCmd_OPTION_WAITFORRSP, + OID_802_11_ADD_WEP, + NULL); + + if (ret) { + LEAVE(); + return ret; + } + + Adapter->CurrentPacketFilter |= + HostCmd_ACT_MAC_WEP_ENABLE; + + libertas_set_mac_packet_filter(priv); + } + } else { + rc = -EOPNOTSUPP; + } + } + } + + LEAVE(); + return rc; +} + +/** + * @brief use index to get the data rate + * + * @param index The index of data rate + * @return data rate or 0 + */ +u32 libertas_index_to_data_rate(u8 index) +{ + if (index >= sizeof(libertas_wlan_data_rates)) + index = 0; + + return libertas_wlan_data_rates[index]; +} + +/** + * @brief use rate to get the index + * + * @param rate data rate + * @return index or 0 + */ +u8 libertas_data_rate_to_index(u32 rate) +{ + u8 *ptr; + + if (rate) + if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate, + sizeof(libertas_wlan_data_rates)))) + return (ptr - libertas_wlan_data_rates); + + return 0; +} + +/** + * @brief set data rate + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + u32 data_rate; + u16 action; + int ret = WLAN_STATUS_SUCCESS; + u8 rates[WLAN_SUPPORTED_RATES]; + u8 *rate; + + ENTER(); + + PRINTM(INFO, "Vwrq->value = %d\n", vwrq->value); + + if (vwrq->value == -1) { + action = HostCmd_ACT_SET_TX_AUTO; // Auto + Adapter->Is_DataRate_Auto = 1; + Adapter->DataRate = 0; + } else { + if (vwrq->value % 100000) { + return -EINVAL; + } + + data_rate = vwrq->value / 500000; + + memset(rates, 0, sizeof(rates)); + get_active_data_rates(Adapter, rates); + rate = rates; + while (*rate) { + PRINTM(INFO, "Rate=0x%X Wanted=0x%X\n", *rate, + data_rate); + if ((*rate & 0x7f) == (data_rate & 0x7f)) + break; + rate++; + } + if (!*rate) { + PRINTM(MSG, "The fixed data rate 0x%X is out " + "of range.\n", data_rate); + return -EINVAL; + } + + Adapter->DataRate = data_rate; + action = HostCmd_ACT_SET_TX_FIX_RATE; + Adapter->Is_DataRate_Auto = 0; + } + + ret = libertas_prepare_and_send_command(priv, HostCmd_CMD_802_11_DATA_RATE, + action, HostCmd_OPTION_WAITFORRSP, 0, NULL); + + LEAVE(); + return ret; +} + +/** + * @brief get data rate + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + + if (Adapter->Is_DataRate_Auto) { + vwrq->fixed = 0; + } else { + vwrq->fixed = 1; + } + + vwrq->value = Adapter->DataRate * 500000; + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief set wireless mode + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_set_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + enum WLAN_802_11_NETWORK_INFRASTRUCTURE WantedMode; + + ENTER(); + + switch (*uwrq) { + case IW_MODE_ADHOC: + PRINTM(INFO, "Wanted Mode is ad-hoc: current DataRate=%#x\n", + Adapter->DataRate); + WantedMode = Wlan802_11IBSS; + Adapter->AdhocChannel = DEFAULT_AD_HOC_CHANNEL; + break; + + case IW_MODE_INFRA: + PRINTM(INFO, "Wanted Mode is Infrastructure\n"); + WantedMode = Wlan802_11Infrastructure; + break; + + case IW_MODE_AUTO: + PRINTM(INFO, "Wanted Mode is Auto\n"); + WantedMode = Wlan802_11AutoUnknown; + break; + + default: + PRINTM(INFO, "Wanted Mode is Unknown: 0x%x\n", *uwrq); + return -EINVAL; + } + + if (Adapter->InfrastructureMode == WantedMode || + WantedMode == Wlan802_11AutoUnknown) { + PRINTM(INFO, "Already set to required mode! No change!\n"); + + Adapter->InfrastructureMode = WantedMode; + + LEAVE(); + return WLAN_STATUS_SUCCESS; + } + + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + if (Adapter->PSState != PS_STATE_FULL_POWER) { + libertas_ps_wakeup(priv, HostCmd_OPTION_WAITFORRSP); + } + Adapter->PSMode = Wlan802_11PowerModeCAM; + } + + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + if (Adapter->InfrastructureMode == Wlan802_11Infrastructure) { + ret = libertas_send_deauthentication(priv); + + if (ret) { + LEAVE(); + return ret; + } + } else if (Adapter->InfrastructureMode == Wlan802_11IBSS) { + /* If current mode is Adhoc, clean stale information */ + ret = libertas_stop_adhoc_network(priv); + + if (ret) { + LEAVE(); + return ret; + } + } + } + + if (Adapter->SecInfo.WEPStatus == Wlan802_11WEPEnabled) { + /* If there is a key with the specified SSID, + * send REMOVE WEP command, to make sure we clean up + * the WEP keys in firmware + */ + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SET_WEP, + 0, HostCmd_OPTION_WAITFORRSP, + OID_802_11_REMOVE_WEP, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + Adapter->CurrentPacketFilter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + libertas_set_mac_packet_filter(priv); + } + + Adapter->SecInfo.WEPStatus = Wlan802_11WEPDisabled; + Adapter->SecInfo.AuthenticationMode = Wlan802_11AuthModeOpen; + + Adapter->InfrastructureMode = WantedMode; + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_SNMP_MIB, + 0, HostCmd_OPTION_WAITFORRSP, + OID_802_11_INFRASTRUCTURE_MODE, NULL); + + if (ret) { + LEAVE(); + return ret; + } + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Set Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + + struct WLAN_802_11_KEY *pKey = NULL; + + ENTER(); + + if (dwrq->length > MAX_WEP_KEY_SIZE) { + pKey = (struct WLAN_802_11_KEY *)extra; + + if (pKey->KeyLength <= MAX_WEP_KEY_SIZE) { + //dynamic WEP + dwrq->length = pKey->KeyLength; + dwrq->flags = pKey->KeyIndex + 1; + return wlan_set_encode_nonwpa(dev, info, dwrq, + pKey->KeyMaterial); + } else { + //WPA + return wlan_set_encode_wpa(dev, info, dwrq, extra); + } + } else { + //static WEP + PRINTM(INFO, "Setting WEP\n"); + return wlan_set_encode_nonwpa(dev, info, dwrq, extra); + } + + return -EINVAL; +} + +/** + * @brief set tx power + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = WLAN_STATUS_SUCCESS; + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + u16 dbm; + + ENTER(); + + if (vwrq->disabled) { + wlan_radio_ioctl(priv, RADIO_OFF); + return WLAN_STATUS_SUCCESS; + } + + Adapter->Preamble = HostCmd_TYPE_AUTO_PREAMBLE; + + wlan_radio_ioctl(priv, RADIO_ON); + + if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { + dbm = (u16) mw_to_dbm(vwrq->value); + } else + dbm = (u16) vwrq->value; + + /* auto tx power control */ + + if (vwrq->fixed == 0) + dbm = 0xffff; + + PRINTM(INFO, "<1>TXPOWER SET %d dbm.\n", dbm); + + ret = libertas_prepare_and_send_command(priv, + HostCmd_CMD_802_11_RF_TX_POWER, + HostCmd_ACT_TX_POWER_OPT_SET_LOW, + HostCmd_OPTION_WAITFORRSP, 0, (void *)&dbm); + + LEAVE(); + return ret; +} + +/** + * @brief Get current essid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return WLAN_STATUS_SUCCESS --success, otherwise fail + */ +int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = dev->priv; + wlan_adapter *Adapter = priv->adapter; + + ENTER(); + /* + * Note : if dwrq->flags != 0, we should get the relevant SSID from + * the SSID list... + */ + + /* + * Get the current SSID + */ + if (Adapter->MediaConnectStatus == WlanMediaStateConnected) { + memcpy(extra, Adapter->CurBssParams.ssid.Ssid, + Adapter->CurBssParams.ssid.SsidLength); + extra[Adapter->CurBssParams.ssid.SsidLength] = '\0'; + } else { + memset(extra, 0, 32); + extra[Adapter->CurBssParams.ssid.SsidLength] = '\0'; + } + /* + * If none, we may want to get the one that was set + */ + + /* To make the driver backward compatible with WPA supplicant v0.2.4 */ + if (dwrq->length == 32) /* check with WPA supplicant buffer size */ + dwrq->length = min_t(size_t, Adapter->CurBssParams.ssid.SsidLength, + IW_ESSID_MAX_SIZE); + else + dwrq->length = Adapter->CurBssParams.ssid.SsidLength + 1; + + dwrq->flags = 1; /* active */ + + LEAVE(); + return WLAN_STATUS_SUCCESS; +} + +/** + * @brief Get version + * + * @param adapter A pointer to wlan_adapter structure + * @param version A pointer to version buffer + * @param maxlen max length of version buffer + * @return NA + */ +void libertas_get_version(wlan_adapter * adapter, char *version, int maxlen) +{ + union { + u32 l; + u8 c[4]; + } ver; + char fwver[32]; + + ver.l = adapter->FWReleaseNumber; + if (ver.c[3] == 0) + sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]); + else + sprintf(fwver, "%u.%u.%u.p%u", + ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(version, maxlen, libertas_driver_version, fwver); +} + + +/* + * iwconfig settable callbacks + */ +static const iw_handler wlan_handler[] = { + (iw_handler) wlan_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ + (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ + (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ + (iw_handler) wlan_set_sens, /* SIOCSIWSENS */ + (iw_handler) wlan_get_sens, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) libertas_set_wap, /* SIOCSIWAP */ + (iw_handler) wlan_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + //(iw_handler) wlan_get_aplist, /* SIOCGIWAPLIST */ + NULL, /* SIOCGIWAPLIST */ + (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */ + (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */ + (iw_handler) libertas_set_essid, /* SIOCSIWESSID */ + (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ + (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ + (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ + (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ + (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ + (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ + (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ + (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ + (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ + (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ + (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ + (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ + (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ + (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ +}; + +struct iw_handler_def libertas_handler_def = { + .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), + .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler), + .num_private_args = sizeof(wlan_private_args) / + sizeof(struct iw_priv_args), + .standard = (iw_handler *) wlan_handler, + .private = (iw_handler *) wlan_private_handler, + .private_args = (struct iw_priv_args *)wlan_private_args, + .get_wireless_stats = wlan_get_wireless_stats, +}; diff -Nur -p linux-2.6-orig/drivers/net/wireless/libertas/wlan_wext.h linux-2.6-libertas/drivers/net/wireless/libertas/wlan_wext.h --- linux-2.6-orig/drivers/net/wireless/libertas/wlan_wext.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/libertas/wlan_wext.h 2006-08-22 01:37:03.000000000 -0300 @@ -0,0 +1,281 @@ +/** @file wlan_wext.h + * @brief This file contains definition for IOCTL call. + * + * (c) Copyright © 2003-2006, Marvell International Ltd. + * All Rights Reserved + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available along with the File in the license.txt file or by writing to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/******************************************************** +Change log: + 10/11/05: Add Doxygen format comments + 12/19/05: Correct a typo in structure _wlan_ioctl_wmm_tspec + 01/11/06: Change compile flag BULVERDE_SDIO to SD to support Monahans/Zylonite + 01/11/06: Conditionalize new scan/join ioctls + 04/10/06: Add hostcmd generic API + 04/18/06: Remove old Subscrive Event and add new Subscribe Event + implementation through generic hostcmd API +********************************************************/ + +#ifndef _WLAN_WEXT_H_ +#define _WLAN_WEXT_H_ + +#define SUBCMD_OFFSET 4 +/** PRIVATE CMD ID */ +#define WLANIOCTL SIOCIWFIRSTPRIV + +#define WLANSETWPAIE (WLANIOCTL + 0) +#define WLANCISDUMP (WLANIOCTL + 1) +#define WLANREGRDWR (WLANIOCTL + 3) +#define MAX_EEPROM_DATA 256 +#define WLANHOSTCMD (WLANIOCTL + 4) + +#define WLAN_SETINT_GETINT (WLANIOCTL + 7) +#define WLANNF 1 +#define WLANRSSI 2 +#define WLANENABLE11D 5 +#define WLANADHOCGRATE 6 +#define WLAN_SUBCMD_SET_PRESCAN 11 + +#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8) +#define WLANDEAUTH 1 +#define WLANRADIOON 2 +#define WLANRADIOOFF 3 +#define WLANREMOVEADHOCAES 4 +#define WLANADHOCSTOP 5 +#define WLANCIPHERTEST 6 +#define WLANCRYPTOTEST 7 +#ifdef REASSOCIATION +#define WLANREASSOCIATIONAUTO 8 +#define WLANREASSOCIATIONUSER 9 +#endif /* REASSOCIATION */ + +#define WLANWLANIDLEON 10 +#define WLANWLANIDLEOFF 11 +#define WLAN_SUBCMD_DFT_RESET 12 +#define WLAN_SUBCMD_BT_RESET 13 + +#define WLANGETLOG (WLANIOCTL + 9) +#define WLAN_SETCONF_GETCONF (WLANIOCTL + 10) + +#define GETLOG_BUFSIZE 300 + +#define WLANSCAN_TYPE (WLANIOCTL + 11) + +#define WLAN_SET_GET_2K (WLANIOCTL + 13) +#define WLAN_SET_USER_SCAN 1 +#define WLAN_GET_SCAN_TABLE 2 + +#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15) +#define WLANGETREGION 1 +#define WLAN_GET_LISTEN_INTERVAL 2 +#define WLAN_GET_MULTIPLE_DTIM 3 +#define WLAN_GET_TX_RATE 4 +#define WLANGETBCNAVG 5 + +#define WLAN_GET_LINKMODE 6 +#define WLAN_GET_RADIOMODE 7 +#define WLAN_GET_DEBUGMODE 8 + +#define WLAN_SETTENCHAR_GETNONE (WLANIOCTL + 16) + +#define WLAN_SETNONE_GETTENCHAR (WLANIOCTL + 17) + +#define WLANREGCFRDWR (WLANIOCTL + 18) + +#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19) +#define WLAN_SUBCMD_GETRXANTENNA 1 +#define WLAN_SUBCMD_GETTXANTENNA 2 +#define WLAN_GET_TSF 3 + +#define WLAN_SETWORDCHAR_GETNONE (WLANIOCTL + 20) +#define WLANSETADHOCAES 1 + +#define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21) +#define WLANGETADHOCAES 1 +#define WLANVERSION 2 + +#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23) +#define WLAN_BEACON_INTERVAL 1 +#define WLAN_LISTENINTRVL 4 + +#define WLAN_TXCONTROL 6 +#define WLAN_NULLPKTINTERVAL 7 + +#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24) +#define WLAN_SUBCMD_SETRXANTENNA 1 +#define WLAN_SUBCMD_SETTXANTENNA 2 +#define WLANSETAUTHALG 5 +#define WLANSET8021XAUTHALG 6 +#define WLANSETENCRYPTIONMODE 7 +#define WLANSETREGION 8 +#define WLAN_SET_LISTEN_INTERVAL 9 + +#define WLAN_SET_MULTIPLE_DTIM 10 +#define WLAN_SET_ATIM_WINDOW 11 +#define WLANSETBCNAVG 13 +#define WLANSETDATAAVG 14 +#define WLAN_SET_LINKMODE 15 +#define WLAN_SET_RADIOMODE 16 +#define WLAN_SET_DEBUGMODE 17 + +#define WLAN_SET64CHAR_GET64CHAR (WLANIOCTL + 25) +#define WLANSLEEPPARAMS 2 +#define WLANSCAN_MODE 6 + +#define WLAN_GET_ADHOC_STATUS 9 + +#define WLAN_SUBCMD_DFT_ADD 15 +#define WLAN_SUBCMD_DFT_DEL 16 +#define WLAN_SUBCMD_DFT_LIST 17 +#define WLAN_SUBCMD_BT_ADD 18 +#define WLAN_SUBCMD_BT_DEL 19 +#define WLAN_SUBCMD_BT_LIST 20 + +#define WLANEXTSCAN (WLANIOCTL + 26) + +#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29) +#define WLAN_TPCCFG 1 +#define WLAN_POWERCFG 2 + +#define WLAN_AUTO_FREQ_SET 3 +#define WLAN_AUTO_FREQ_GET 4 +#define WLAN_LED_GPIO_CTRL 5 +#define WLAN_SCANPROBES 6 +#define WLAN_SLEEP_PERIOD 7 +#define WLAN_ADAPT_RATESET 8 +#define WLAN_INACTIVITY_TIMEOUT 9 +#define WLANSNR 10 +#define WLAN_GET_RATE 11 +#define WLAN_GET_RXINFO 12 + +#define WLANCMD52RDWR (WLANIOCTL + 30) +#define WLANCMD53RDWR (WLANIOCTL + 31) +#define CMD53BUFLEN 32 + +#define REG_MAC 0x19 +#define REG_BBP 0x1a +#define REG_RF 0x1b +#define REG_EEPROM 0x59 +#define WLAN_LINKMODE_802_3 0 +#define WLAN_LINKMODE_802_11 2 +#define WLAN_RADIOMODE_NONE 0 +#define WLAN_RADIOMODE_RADIOTAP 2 + +#define CMD_DISABLED 0 +#define CMD_ENABLED 1 +#define CMD_GET 2 +#define SKIP_CMDNUM 4 +#define SKIP_TYPE 1 +#define SKIP_SIZE 2 +#define SKIP_ACTION 2 +#define SKIP_TYPE_SIZE (SKIP_TYPE + SKIP_SIZE) +#define SKIP_TYPE_ACTION (SKIP_TYPE + SKIP_ACTION) + +/** wlan_ioctl */ +typedef struct _wlan_ioctl { + /** Command ID */ + u16 command; + /** data length */ + u16 len; + /** data pointer */ + u8 *data; +} wlan_ioctl; + +/** wlan_ioctl_rfantenna */ +typedef struct _wlan_ioctl_rfantenna { + u16 Action; + u16 AntennaMode; +} wlan_ioctl_rfantenna; + +/** wlan_ioctl_regrdwr */ +typedef struct _wlan_ioctl_regrdwr { + /** Which register to access */ + u16 WhichReg; + /** Read or Write */ + u16 Action; + u32 Offset; + u16 NOB; + u32 Value; +} wlan_ioctl_regrdwr; + +/** wlan_ioctl_cfregrdwr */ +typedef struct _wlan_ioctl_cfregrdwr { + /** Read or Write */ + u8 Action; + /** register address */ + u16 Offset; + /** register value */ + u16 Value; +} wlan_ioctl_cfregrdwr; + +/** wlan_ioctl_rdeeprom */ +typedef struct _wlan_ioctl_rdeeprom { + u16 WhichReg; + u16 Action; + u16 Offset; + u16 NOB; + u8 Value; +} wlan_ioctl_rdeeprom; + +/** wlan_ioctl_adhoc_key_info */ +typedef struct _wlan_ioctl_adhoc_key_info { + u16 action; + u8 key[16]; + u8 tkiptxmickey[16]; + u8 tkiprxmickey[16]; +} wlan_ioctl_adhoc_key_info; + +#ifdef __KERNEL__ +extern struct iw_handler_def libertas_handler_def; +int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i); +int wlan_radio_ioctl(wlan_private * priv, u8 option); +/* this one should not be needed in do_ioctl */ +int wlan_set_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra); +#endif + +/** sleep_params */ +typedef struct _wlan_ioctl_sleep_params_config { + u16 Action; + u16 Error; + u16 Offset; + u16 StableTime; + u8 CalControl; + u8 ExtSleepClk; + u16 Reserved; +} __attribute__ ((packed)) wlan_ioctl_sleep_params_config, + *pwlan_ioctl_sleep_params_config; + +/** BCA TIME SHARE */ +typedef struct _wlan_ioctl_bca_timeshare_config { + /** ACT_GET/ACT_SET */ + u16 Action; + /** Type: WLAN, BT */ + u16 TrafficType; + /** Interval: 20msec - 60000msec */ + u32 TimeShareInterval; + /** PTA arbiter time in msec */ + u32 BTTime; +} __attribute__ ((packed)) wlan_ioctl_bca_timeshare_config, + *pwlan_ioctl_bca_timeshare_config; + +typedef struct _wlan_ioctl_reassociation_info { + u8 CurrentBSSID[6]; + u8 DesiredBSSID[6]; + char DesiredSSID[IW_ESSID_MAX_SIZE + 1]; +} __attribute__ ((packed)) wlan_ioctl_reassociation_info; + +#endif /* _WLAN_WEXT_H_ */ diff -Nur -p linux-2.6-orig/drivers/net/wireless/Makefile linux-2.6-libertas/drivers/net/wireless/Makefile --- linux-2.6-orig/drivers/net/wireless/Makefile 2006-08-06 15:20:11.000000000 -0300 +++ linux-2.6-libertas/drivers/net/wireless/Makefile 2006-08-22 01:37:03.000000000 -0300 @@ -36,7 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_BCM43XX) += bcm43xx/ -obj-$(CONFIG_ZD1211RW) += zd1211rw/ +obj-$(CONFIG_LIBERTAS_USB) += libertas/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o diff -Nur -p linux-2.6-orig/include/net/ieee80211_radiotap.h linux-2.6-libertas/include/net/ieee80211_radiotap.h --- linux-2.6-orig/include/net/ieee80211_radiotap.h 2006-08-06 15:20:11.000000000 -0300 +++ linux-2.6-libertas/include/net/ieee80211_radiotap.h 2006-08-22 01:37:03.000000000 -0300 @@ -168,6 +168,23 @@ struct ieee80211_radiotap_header { * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * + * IEEE80211_RADIOTAP_RX_FLAGS u_int16_t bitmap + * + * Properties of received frames. See flags defined below. + * + * IEEE80211_RADIOTAP_TX_FLAGS u_int16_t bitmap + * + * Properties of transmitted frames. See flags defined below. + * + * IEEE80211_RADIOTAP_RTS_RETRIES u_int8_t data + * + * Number of rts retries a transmitted frame used. + * + * IEEE80211_RADIOTAP_DATA_RETRIES u_int8_t data + * + * Number of unicast retries a transmitted frame used. + * + * * IEEE80211_RADIOTAP_FCS u32 data * * FCS from frame in network byte order. @@ -187,7 +204,11 @@ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, - IEEE80211_RADIOTAP_EXT = 31, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + IEEE80211_RADIOTAP_EXT = 31 }; /* Channel flags. */