Report abuse

/*
 *  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