/*
* VoodooWirelessDevice.h
* VoodooWireless
*
* Created by Prashant Vaibhav on 12/06/09.
* Copyright 2009 Prashant Vaibhav. All rights reserved.
*
*/

#ifndef _H_VOODOOWIRELESSDEVICE_H
#define _H_VOODOOWIRELESSDEVICE_H

#include <sys/types.h>
#include <sys/kpi_mbuf.h>

#include <IOKit/IOService.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOWorkLoop.h>

#include <IOKit/apple80211/IO80211Controller.h>
#include <IOKit/apple80211/IO80211Interface.h>
#include <IOKit/apple80211/IO80211WorkLoop.h>
#include <IOKit/network/IOOutputQueue.h>

#include "VoodooWirelessFamily.h"
#include "VoodooIEEE80211.h"
#include "VoodooWirelessDevice_Types.h"

using namespace org_voodoo_wireless;

class VoodooWirelessDevice : public IO80211Controller
{
public:
/* NOTE: None of the public functions need to be implemented by subclasses. Proper implementations
* is already provided by this superclass */

/* Basic IOKit functions */
virtual bool start ( IOService* provider );
virtual void stop ( IOService* provider );
IOReturn registerWithPolicyMaker ( IOService* policyMaker );

/* Network driver and apple80211 functions */
SInt32 apple80211Request ( UInt32 request_type, int request_number,
IO80211Interface* interface, void* data );
IOReturn enable ( IONetworkInterface* aNetif );
IOReturn disable ( IONetworkInterface* aNetif );
IOOutputQueue* createOutputQueue ( );

UInt32 outputPacket ( mbuf_t m, void* param );

IOReturn getMaxPacketSize ( UInt32 *maxSize ) const;
const OSString* newVendorString ( ) const;
const OSString* newModelString ( ) const;
const OSString* newRevisionString ( ) const;
IOReturn getHardwareAddress ( IOEthernetAddress* addr );
virtual IOReturn setPromiscuousMode ( IOEnetPromiscuousMode mode );
virtual IOReturn setMulticastMode ( IOEnetMulticastMode mode );
virtual IOReturn setMulticastList ( IOEthernetAddress* addr, UInt32 len );
virtual SInt32 monitorModeSetEnabled ( IO80211Interface * interface, bool enabled, UInt32 dlt );

protected:
struct ExpansionData {}; // reserved, for internal use only
ExpansionData* reserved; // reserved, for internal use only

/* Functions to init / shutdown the HW */
virtual IOReturn allocateResources ( ); // Allocate hw rings, memory etc. needed for power up
virtual void freeResources ( ); // Undo all allocations done in allocateResources()
virtual IOReturn turnPowerOn ( ); // Make the card ready for action
virtual IOReturn turnPowerOff ( ); // Turn the card off

/* Functions for establishing connections, scanning etc. */
virtual IOReturn startScan ( const ScanParameters* params,
const IEEE::ChannelList* channels );

virtual void abortScan ( );
virtual IOReturn associate ( const AssociationParameters* params );
virtual IOReturn disasssociate ( );

/* Various configuration functions */
virtual void getHardwareInfo ( HardwareInfo* info );
virtual IOReturn getConfiguration ( HardwareConfigType type, void* param );
virtual IOReturn setConfiguration ( HardwareConfigType type, void* param );

/* The following function should be called by subclasses to report events. */
void report ( DeviceResponseMessage msg, void* arg );

/* This is to be called by subclasses when it receives any frames from HW.
* "data" should be raw 802.11 frame.
* During scanning, beacon or probe response frames should be passed via this function
*/
void inputFrame ( RxFrameHeader hdr, mbuf_t data );

/* This function must be implemented by the subclass to output a raw 802.11 frame.
* Note that the mbuf_t could either be a single mbuf or a chain of 2 or more mbufs.
* The passed mbuf_t becomes property of the driver which should free it when it is no longer needed.
*/
virtual IOReturn outputFrame ( TxFrameHeader hdr, mbuf_t data );

private:
HardwareInfo _hwInfo;
uint32_t _flags;
IOSimpleLock* _simpleLock;

/* The following are reserved slots for future expansion */
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 0);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 1);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 2);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 3);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 4);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 5);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 6);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 7);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 8);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 9);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 10);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 11);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 12);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 13);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 14);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 15);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 16);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 17);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 18);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 19);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 20);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 21);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 22);
OSMetaClassDeclareReservedUnused(VoodooWirelessDevice, 23);
};

#endif//_H_VOODOOWIRELESSDEVICE_H

/*
* VoodooWirelessDevice_Types.h
* VoodooWireless
*
* Created by Prashant Vaibhav on 16/06/09.
* Copyright 2009 Prashant Vaibhav. All rights reserved.
*
*/

#ifndef _H_VOODOOWIRELESSDEVICE_TYPES_H
#define _H_VOODOOWIRELESSDEVICE_TYPES_H

#include <libkern/c++/OSSymbol.h>
#include <libkern/c++/OSString.h>
#include "VoodooWirelessFamily.h"
#include "VoodooIEEE80211.h"

namespace org_voodoo_wireless {

struct ScanParameters {
enum ScanType { scanTypeActive, scanTypePassive, scanTypeBackground };
ScanType scanType; // Type of scan (active/passive..)
IEEE::PHYModes scanPhyMode; // 11a,b,g or n on which to scan
IEEE::MACAddress bssid; // BSSID to which scan is directed
OSSymbol* ssid; // SSID (network name) to which scan is directed
uint32_t dwellTime; // Time to stay on each channel (ms)
uint32_t restTime; // Time to wait between channels (ms)
};

struct ScanResult {
IEEE::Channel channel; // channel on which this AP is operating
IEEE::Capability capability; // AP capability flags
IEEE::MACAddress bssid; // BSSID of access point
OSSymbol* ssid; // Network name
int noiseLevel; // background noise
int signalLevel; // signal strength
IEEE::RateSet supportedRates; // rates that the AP supports
uint32_t beaconInterval; // in ms
uint32_t age; // how old is this result (in ms)
IEList* extraIEs; // extra information elements sent in the probe response
};

struct AssociationParameters {
OSSymbol* ssid; // not needed usually, but providing anyway
IEEE::MACAddress bssid;
IEEE::Channel channel;
IEEE::Capability capability;
IEEE::RateSet supportedRates; // That the AP supports
uint32_t beaconInterval;
enum APMode { apModeAny, apModeAdHoc, apModeInfrastructure };
APMode connectionMode;
enum AuthType {
/* LSB signifies lower auth mode (to be OR'd with upper auth mode if needed) */
authTypeNone = 0, // Open authentication
authTypeShared = 1, // WEP key shared authentication
/* Upper auth modes (even number only as LSB is taken) */
authTypeWPA = 2,
authTypeWPAPSK = 4,
authTypeWPA2 = 6,
authTypeWPA2PSK = 8,
authtypeLEAP = 10,
authType8021X = 12,
authTypeWPS = 14
};
AuthType authType;
IEEE::WEPKey wepKey; // if key is zero length, then no WEP
IEList* extraIEs; // info elements used with RSN (WPA etc.)
bool closedNetwork; // indicates assoc request is for directed scanned network
};

struct RxFrameHeader {
/* information about an incoming frame */
IEEE::Channel channel;
IEEE::DataRate rate;
int signalLevel; // signal strength
bool decrypted; // whether HW has already decrypted this frame
};

struct TxFrameHeader {
IEEE::DataRate rate; // desired Tx rate (can be ignored by HW)
bool encrypted; // whether this frame is already encrypted
};

struct HardwareCapabilities {
/* Which features does the hardware support */
bool WEP :1; // the cipher. if 0, will fall back to software cipher
bool TKIP :1; // the cipher. if 0, will fall back to software cipher
bool TKIP_MIC :1; // hardware TKIP MIC support. if 0, fall back to full software TKIP
bool AES_CCMP :1; // the cipher. if 0, will fall back to software cipher
bool WPA1 :1; // connecting to WPA1. if 0, WPA1 will not be available at all
bool WPA2 :1; // connecting to WPA2. if 0, WPA2 will not be available at all

bool AdHocMode :1;
bool HostAPMode :1;
bool MonitorMode :1;

bool PowerManagement :1; // active 802.11 power management, not IOKit power management
bool TxPowerManagement:1; // transmit power can be set
bool WakeOneWireless :1;

bool ShortSlot :1;
bool ShortPreamble :1;
bool FrameBursting :1;
bool WMEQoS :1;
bool ShortGuardInterval20MHz :1;
bool ShortGuardInterval40MHz :1;

bool hardwareRoaming :1; // hardware can migrate to different APs on its own
};

enum PowerSavingModes {
powerSaveAlwaysOn = 1,
powerSaveNormal = 2, // middle-level power saving
powerSaveMaximum = 4 // maximum power savings
};

enum HardwareConfigType {
/* Which kind of config to get/set, when get/setConfig is called. Any of this can be ignored */
configTxPower, // param = int txPower
configRTSThreshold, // param = uint32_t threshInBytes
configFragmentationThreshold, // param = uint32_t threshInBytes
configShortRetryLimit, // param = uint32_t numRetries
configLongRetryLimit, // param = uint32_t numRetries
configCurrentTxRate, // param = IEEE::DataRate
configRateSet, // param = IEEE::RateSet [working rates, not HW supported rates]
configInterferenceMitigation, // param = bool turnOn [HW dependent, usually bluetooth interference]
config11GProtection // param = bool turnOn [used in mixed 11bg networks]
};

struct HardwareInfo {
/* Note: strings should not have been allocated already, they will be allocated
by the driver itself. Ownership is then passed to the superclass who must
release the strings. In other words, this struct should be zero filled
before being passed to subclass. */
OSString* manufacturer;
OSString* model;
OSString* hardwareRevision;
OSString* driverVersion;
OSString* firmwareVersion;
IEEE::MACAddress hardwareAddress;
IEEE::PHYModes supportedModes; // OR'd bits if it's multi-mode PHY
IEEE::ChannelList supportedChannels; // independent of locale
IEEE::RateSet supportedRates; // that hardware supports, not what it's using now
unsigned int maxTxPower; // in dBm, independent of locale
enum SNRUnit { unit_dBm, unit_Percent, unit_mW, unit_Other_Linear, unit_Other_Logarithmic };
SNRUnit snrUnit; // which units are noise/signal levels reported in
PowerSavingModes powerSavingModes; // which modes does hardware support
HardwareCapabilities capabilities;
uint32_t maxPacketSize; // largest packet size which this HW can transmit
uint32_t txQueueSize; // how many packets can be sent to HW's tx queue
};

enum DeviceResponseMessage {
msgNull = iokit_vendor_specific_msg(1), // XXX: not used

msgPowerOff, // HW power was turned off without being requested
msgPowerOn, // HW power was turned on without being requested
msgRadioOff, // PHY was turned off by user or power saving
msgRadioOn, // PHY was turned on by user or power saving

msgScanAborted, // scan was aborted (by HW, not as response to client request)
msgScanCompleted, // scanning all specified chanels is completed
msgChannelScanned, // scanning a specific channel is completed (arg=Channel*)

msgAuthenticationFailed, // authentication step failed
msgAuthenticationDone, // authentication step was done
msgAssociationFailed, // association with AP failed, arg=IEEE::ReasonCode*
msgAssociationDone, // association was finished successfully
msgDeassociationFailed, // deassoc request failed, arg=IEEE::ReasonCode*
msgDeassociationDone, // deassociated from AP, arg=IEEE::ReasonCode*
msgDeauthenticated, // deauthenticated from AP, arg=IEEE::ReasonCode*

msgNoiseLevelReport, // reporting noise level, arg=int* noiseLevel
msgSignalStrengthReport, // reporting signal strength, arg=int* signalStrength
msgChannelSwitch, // reporting AP channel switch, arg=Channel* newChan
msgLinkQualityReport, // reporting link quality, arg=int* qualityLevel
msgBeaconMissed, // reporting missed beacon, arg=uint32_t* howManyMissed
msgConfigChanged, // reporting a change in HW config (without being requested)
// arg=HardwareConfigType* type, client may call getConfig after this

msgMaxMessageNumber // XXX: used to check if msg num was out of bound
};
};

#endif


/*
* VoodooIEEE80211_Types.h
* VoodooWireless
*
* Created by Prashant Vaibhav on 16/06/09.
* Copyright 2009 Prashant Vaibhav. All rights reserved.
*
*/


#ifndef _H_VOODOOIEEE80211_TYPES_H
#define _H_VOODOOIEEE80211_TYPES_H

#include "VoodooWirelessFamily.h"

namespace org_voodoo_wireless {
namespace IEEE {
struct MACAddress {
/* Defining this again here because families should not have to use another
family's headers, and IOEthernetAddress is defined in IOEthernetFamily */
uint8_t bytes[6];
};

struct WEPKey {
uint8_t index; // 0 to 3
OSString* key; // 40 or 104 bits (5 or 13 bytes)
};

enum PHYModes {
dot11A = 1, // 5GHz OFDM
dot11B = 2, // 2.4GHz CCK
dot11G = 4, // 2.4GHz OFDM
dot11N = 8, // 2.4GHz or 5GHz MIMO
};

const size_t MAX_CHANNELS = 64;
const size_t MAX_RATES = 32;

struct Channel {
uint8_t number; // Channel number
uint16_t flags; // Channel type flags
enum Flags {
supportsActiveScanning = 0x1,
band2GHz = 0x2,
band5GHz = 0x4,
width10MHz = 0x8,
width20MHz = 0x10,
width40MHz = 0x20,
requiresDFS = 0x40, // dynamic frequency selection for 11a
supportsHostAPMode = 0x80,
supportsAdHocMode = 0x100,
extensionChannelIsAbove = 0x200 // in 11n mode, if ext. ch is above this ch. (otherwise below)
};
};

struct ChannelList {
size_t numItems;
Channel channel[MAX_CHANNELS];
};

enum DataRate {
rateIsBasic = 128, // basic rates should be OR'd with this value (ie. bit 7 = 1)
/* Rates are just uint32_t, in 0.5 Mbps units */
rate1Mbps = 2, // 1 Mbps CCK
rate2Mbps = 4, // 2 Mbps CCK
rate5Mbps = 10, // 5.5 Mbps CCK
rate6Mbps = 12, // 6 Mbps OFDM
rate9Mbps = 18, // 9 Mbps OFDM
rate11Mbps = 22, // 11 Mbps CCK
rate12Mbps = 24, // 12 Mbps OFDM
rate18Mbps = 36, // 18 Mbps OFDM
rate24Mbps = 48, // 24 Mbps OFDM
rate36Mbps = 72, // 36 Mbps OFDM
rate48Mbps = 96, // 48 Mbps OFDM
rate54Mbps = 108, // 54 Mbps OFDM
/* 11n MIMO rates to be added later */
};

struct RateSet {
size_t numItems;
DataRate rate[MAX_RATES];
};

enum ReasonCode {
// § 7.3.1.7 Table 7-22
reasonUnspecified = 1,
reasonPreviousAuthExpired = 2,
reasonDeauthBecauseSTALeft = 3,
reasonDisassocDueToInactivity = 4,
reasonAPFull = 5,
reasonClass2FrameRxWithoutAuth = 6,
reasonClass3FrameRxWithoutAssoc = 7,
reasonDisassocBecauseSTALeft = 8,
reasonNotAuthorized = 9,
reasonPowerCapsUnacceptable = 10,
reasonSupportedChannelsUnacceptable = 11,
reasonInvalidIE = 13, /* 12 is reserved */
reasonMICFailure = 14,
reason4WayHandshakeTimeout = 15,
reasonGroupKeyHandshakeTimeout = 16,
reasonIEMismatch = 17,
reasonInvalidGroupCipher = 18,
reasonInvalidPairwiseCipher = 19,
reasonInvalidAKMP = 20,
reasonUnsupportedRSNIE = 21,
reasonInvalidRSNIECaps = 22,
reason8021XAuthFailed = 23,
reasonCipherSuiteRejected = 24,
reasonQoS = 32, /* 25-31 reserved */
reasonQoSBandwidthUnavailable = 33,
reasonTooManyACKs = 34,
reasonTXOPsOutsideLimits = 35,
reasonPeerSTALeaving = 36,
reasonPeerSTAMechanismRejected = 37,
reasonPeerSTAMechanismNeedsSetup= 38,
reasonPeerSTATimeout = 39,
reasonPeerSTACipherUnsupported = 45, /* 40-44 reserved */
reasonPrivateUnspecified = 0xffff /* our own unspecified failure code */
};

struct IE {
enum ID {
/* § 7.3.2 Table 7-26 */
ieSSID = 0, ieSupportedRates = 1,
ieFHParamSet = 2, ieDSParamSet = 3,
ieCFParamSet = 4, ieTIM = 5,
ieIBSSParamSet = 6, ieCountry = 7,
ieHoppingPatternParams = 8, ieHoppingPatternTable = 9,
ieRequest = 10, ieBSSLoad = 11,
ieEDCAParamSet = 12, ieTSPEC = 13,
ieTCLAS = 14, ieSchedule = 15,
ieChallengeText = 16, /* 17-31 reserved */
iePowerConstraint = 32, iePowerCapability = 33,
ieTPCRequest = 34, ieTPCReport = 35,
ieSupportedChannels = 36, ieChannelSwitchAnnounce = 37,
ieMeasurementRequest = 38, ieMeasurementReport = 39,
ieQuiet = 40, ieIBSSDFS = 41,
ieERPInformation = 42, ieTSDelay = 43,
ieTCLASProcessing = 44, /* 45 reserved */
ieQoSCapability = 46, /* 47 reserved */
ieRSN = 48, /* 49 reserved */
ieExtendedSupportedRates= 50, /* 51-125 reserved */
/* 126 reserved */ ieExtendedCapabilities = 127,
/* 128-220 reserved */ ieVendorSpecific = 221,
/* 222-255 reserved */
};
uint8_t id; // type codes specified in enum ID
uint8_t length; // length in bytes of data that follows
uint8_t data[0]; // variable length up to 255 bytes
} __packed;

union Capability {
struct {
/* § 7.3.1.4 */
bool ESS :1;
bool IBSS :1; // indicates Ad-hoc mode
bool CFPollable :1;
bool CFPollRequest :1;
bool Privacy :1; // indicates WEP on/off
bool ShortPreamble :1;
bool PBCC :1;
bool ChannelAgility :1;
bool SpectrumMgmt :1;
bool QoS :1;
bool ShortSlotTime :1;
bool APSD :1;
bool Reserved :1;
bool DSSSOFDM :1; // indicates 11g mode on/off
bool DelayedBlockAck :1;
bool ImmediateBlockAck:1;
} bits __packed;
uint16_t value;
} __packed;


/* Following is the structure of a MAC header present in ALL frames. The remaining
* contents of the frame depend on the type/subtype etc. § 7.2 onwards
*/
struct WiFiFrameHeader
{
enum FrameType {
ManagementFrame = 0,
ControlFrame = 1,
DataFrame = 2,
ReservedFrame = 3
};

enum FrameSubtype {
/* Subtype for Management frames: */
AssocRequest = 0, AssocResponse = 1,
ReassocRequest = 2, ReassocResponse = 3,
ProbeRequest = 4, ProbeResponse = 5,
/* 6-7 are reserved */
Beacon = 8, ATIM = 9,
Disassoc = 10, Authentication = 11,
DeAuthentication= 12, Action = 13,
/* 14-15 are reserved */

/* Subtypes for Control frames: */
/* 0-7 are reserved */
BlockAckReq = 8, BlockAck = 9,
PSPoll = 10, RTS = 11,
CTS = 12, ACK = 13,
CFEnd = 14, CFEndPoll = 15,

/* Subtypes for Data frames: */
Data = 0, DataCFAck = 1,
DataCFPoll = 2, DataCFAckPoll = 3,
Null = 4, CFAck = 5,
CFPoll = 6, CFAckPoll = 7,
QoSData = 8, QoSDataCFAck = 9,
QoSDataCFPoll = 10, QoSDataCFAckPoll = 11,
QoSNull = 12, /* 13 is reserved */
QoSCFPoll = 14, QoSCFAckCFPoll = 15
};

uint8_t protocolVersion :2;
FrameType type :2;
FrameSubtype subtype :4;
bool toDS :1;
bool fromDS :1;
bool moreFrag :1;
bool retry :1;
bool powerSaveMode :1; // Called PwrMgt in spec
bool moreData :1;
bool protectedFrame :1;
bool order :1;

uint16_t durationID :16;

/* The following is also present in all MAC headers, but we won't
* put in here because its meaning depends on the particular frame type
IOEthernetAddress addr1;
*/
} __packed;

struct SequenceControl {
uint8_t fragmentNumber :4;
uint16_t sequenceNumber :12;
} __packed;

struct ManagementFrameHeader
{
WiFiFrameHeader hdr;
uint8_t da[6];
uint8_t sa[6];
uint8_t bssid[6];
SequenceControl sequenceControl;
} __packed;

struct ProbeResponseFrameHeader {
ManagementFrameHeader mgmt;
uint64_t timestamp;
uint16_t beaconInterval;
uint16_t capability;
/* Then follows a variable number of information elements */
uint8_t ieData[0];
} __packed;

struct TxDataFrameHeader {
WiFiFrameHeader hdr;
uint8_t bssid[6];
uint8_t sa[6]; // source MAC addr
uint8_t da[6]; // dest MAC addr
uint16_t seq;
uint8_t data[0]; // variable length
} __packed;

struct TxQoSDataFrameHeader {
WiFiFrameHeader hdr;
uint8_t bssid[6];
uint8_t sa[6]; // source MAC addr
uint8_t da[6]; // dest MAC addr
uint16_t seq;
uint16_t qos;
uint8_t data[0]; // variable length
} __packed;

struct EthernetFrameHeader {
uint8_t da[6];
uint8_t sa[6];
uint8_t frameType[2]; // always = 0x80 0x00
uint8_t data[0]; // variable length
} __packed;

}
}

#endif