#ifndef _IF_80211
#define _IF_80211

#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/list.h>

#ifndef ETH_P_802_11
#define ETH_P_802_11	0x0020		/* 802.11 mgmt frames		*/
#endif

/* Modified from Jean's drivers/net/wireless/ieee802_11.h */

struct ieee802_11_hdr {
	u16 frame_ctl;
	u16 duration_id;
	u8 addr1[ETH_ALEN];
	u8 addr2[ETH_ALEN];
	u8 addr3[ETH_ALEN];
	u16 seq_ctl;
};

struct ieee802_11_hdr4 {
	u16 frame_ctl;
	u16 duration_id;
	u8 addr1[ETH_ALEN];
	u8 addr2[ETH_ALEN];
	u8 addr3[ETH_ALEN];
	u16 seq_ctl;
	u8 addr4[ETH_ALEN];
};

/* Address field usage based upon setting of FROMDS/TODS bits:
 *
 * FROMDS	TODS	addr1	addr2	addr3	addr4
 * ---------------------------------------------------
 * 0		0	DA	SA	BSSID	unused
 * 0		1	DA	BSSID	SA	unused
 * 1		0	BSSID	SA	DA	unused
 * 1		1	RA	TA	DA	SA
 */

/* Frame control field constants */
#define IEEE802_11_FCTL_VERS_0		0x0000
#define IEEE802_11_FCTL_VERS_MASK	0x0003
#define IEEE802_11_FCTL_FTYPE		0x000c
#define IEEE802_11_FCTL_STYPE		0x00f0
#define IEEE802_11_FCTL_NODS		0x0000
#define IEEE802_11_FCTL_TODS		0x0100
#define IEEE802_11_FCTL_FROMDS		0x0200
#define IEEE802_11_FCTL_DSTODS		0x0300
#define IEEE802_11_FCTL_DIRMASK		0x0300
#define IEEE802_11_FCTL_MOREFRAGS	0x0400
#define IEEE802_11_FCTL_RETRY		0x0800
#define IEEE802_11_FCTL_PM		0x1000
#define IEEE802_11_FCTL_MOREDATA	0x2000
#define IEEE802_11_FCTL_WEP		0x4000
#define IEEE802_11_FCTL_ORDER		0x8000

#define IEEE802_11_FTYPE_SHIFT	2
#define IEEE802_11_STYPE_SHIFT	4

#define IEEE802_11_FTYPE_MGMT		0x0000
#define IEEE802_11_FTYPE_CTL		0x0004
#define IEEE802_11_FTYPE_DATA		0x0008
#define IEEE802_11_FTYPE_INVALID	0x000C

/* management */
#define IEEE802_11_STYPE_ASSOC_REQ	0x0000
#define IEEE802_11_STYPE_ASSOC_RESP 	0x0010
#define IEEE802_11_STYPE_REASSOC_REQ	0x0020
#define IEEE802_11_STYPE_REASSOC_RESP	0x0030
#define IEEE802_11_STYPE_PROBE_REQ	0x0040
#define IEEE802_11_STYPE_PROBE_RESP	0x0050
#define IEEE802_11_STYPE_BEACON		0x0080
#define IEEE802_11_STYPE_ATIM		0x0090
#define IEEE802_11_STYPE_DISASSOC	0x00A0
#define IEEE802_11_STYPE_AUTH		0x00B0
#define IEEE802_11_STYPE_DEAUTH		0x00C0

/* control */
#define IEEE802_11_STYPE_PSPOLL		0x00A0
#define IEEE802_11_STYPE_RTS		0x00B0
#define IEEE802_11_STYPE_CTS		0x00C0
#define IEEE802_11_STYPE_ACK		0x00D0
#define IEEE802_11_STYPE_CFEND		0x00E0
#define IEEE802_11_STYPE_CFENDACK	0x00F0

/* data */
#define IEEE802_11_STYPE_DATA		0x0000
#define IEEE802_11_STYPE_DATA_CFACK	0x0010
#define IEEE802_11_STYPE_DATA_CFPOLL	0x0020
#define IEEE802_11_STYPE_DATA_CFACKPOLL	0x0030
#define IEEE802_11_STYPE_NULLFUNC	0x0040
#define IEEE802_11_STYPE_CFACK		0x0050
#define IEEE802_11_STYPE_CFPOLL		0x0060
#define IEEE802_11_STYPE_CFACKPOLL	0x0070

#define IEEE802_11_SCTL_FRAG		0x000F
#define IEEE802_11_SCTL_SEQ		0xFFF0
#define IEEE802_11_SCTL_SEQ_SHIFT	4

struct ieee802_11_snap {
	u8	dsap;
	u8	ssap;
	u8	control;
	u8	oui[3];
	u16	ethertype;
};

#define IEEE802_11_TLV_SIZE		2

#define IEEE802_11_TLV_TYPE_SSID	0
#define IEEE802_11_TLV_TYPE_RATES	1
#define IEEE802_11_TLV_TYPE_FHPARMS	2
#define IEEE802_11_TLV_TYPE_DSPARMS	3
#define IEEE802_11_TLV_TYPE_CFPARMS	4
#define IEEE802_11_TLV_TYPE_TIM		5
#define IEEE802_11_TLV_TYPE_IBSSPARMS	6
#define IEEE802_11_TLV_TYPE_COUNTRY	7
#define IEEE802_11_TLV_TYPE_XRATES	50

#define IEEE802_11_MAX_RATES	8

#define WIRELESS_MAX_RATES	31
struct wireless_rtdesc {
	u8	num;
	u8	rates[WIRELESS_MAX_RATES];
};

struct wireless_node {
	struct list_head	list;

	u8			mac[ETH_ALEN];
	u8			bssid[ETH_ALEN];
};
#define wireless_node_entry(_entry) \
	list_entry(entry, struct wireless_node, list)

struct wireless_ops;

struct wireless_info {
	struct list_head	all_info;

	struct list_head	nodes;
	spinlock_t		node_lock;

	atomic_t		refcnt;
	spinlock_t		state_lock;

	u16			cur_seq;
	u8			mode;
#define WIRELESS_MODE_UNKNOWN	0x01
#define WIRELESS_MODE_STATION	0x02
#define WIRELESS_MODE_AP	0x03
#define WIRELESS_MODE_IBSS	0x04

	/* Figure 8 in IEEE 802.11 1999 */
	u8			state;
#define WIRELESS_STATE_DOWN	0x01 /* Un{authenticaed,associated},pre-scan */
#define WIRELESS_STATE_SEARCH	0x02 /* Determining available stations. */
#define WIRELESS_STATE_AUTH	0x03 /* Scan done, trying to auth */
#define WIRELESS_STATE_ASSOC	0x04 /* Authenticated, trying to associate. */
#define WIRELESS_STATE_UP	0x05 /* Authenticated, associated.  */

	u8			phy_type;
#define WIRELESS_PHY_TYPE_INV	0x01

	u8			phy_cur;
#define WIRELESS_PHY_CUR_INV	0x01
#define WIRELESS_PHY_CUR_A	0x02
#define WIRELESS_PHY_CUR_B	0x03
#define WIRELESS_PHY_CUR_G	0x04
#define WIRELESS_PHY_CUR_TURBO	0x05
#define WIRELESS_PHY_CUR_AUTO	0x06
#define WIRELESS_PHY_CUR_MAX	(WIRELESS_PHY_CUR_AUTO+1)

	u16			__pad;

	struct wireless_rtdesc	rate_caps[WIRELESS_PHY_CUR_MAX];

	struct wireless_node	self;

#define WIRELESS_SSID_MAX	32
	u8			ssid[WIRELESS_SSID_MAX];
	u8			ssid_len;

	/* While we are scanning the network looking for an
	 * attachment point, we queue non-802.11 mgmt packets here.
	 */
	struct sk_buff_head	resolution_queue;
	int			resolution_queue_maxlen;

	struct net_device	*dev;
	struct wireless_ops	*ops;
};
#define wireless_entry(_entry) \
	list_entry(entry, struct wireless_info, all_info)

struct wireless_ops {
};

extern struct wireless_info *p80211_open(struct net_device *,
					 struct wireless_ops *);
extern void p80211_close(struct net_device *, struct wireless_info *);
extern int p80211_set_mode(struct wireless_info *, u8);
extern int p80211_start_scan(struct wireless_info *);

/* MUST be invoked only from driver's ->hard_start_xmit() method.
 * Therefore, no locking needed.
 */
static inline void wireless_xmit_seq(struct wireless_info *wp, u16 *hdr)
{
	u16 tmp = *hdr & le16_to_cpu(IEEE802_11_SCTL_FRAG);
	u16 seq = wp->cur_seq++ & (4096 - 1);

	*hdr = (tmp |
		cpu_to_le16(seq << IEEE802_11_SCTL_SEQ_SHIFT));
}

/* Return 0 if it is OK for the driver to transmit the packet.
 * If non-zero is returned, the wireless layer has queued the
 * packet or freed it, so the driver should inform the upper
 * layers that it took the packet.
 */
static inline int wireless_xmit_check(struct wireless_info *wp,
				      struct sk_buff *skb)
{
	/* Queue anything other than management/control
	 * frames until we have fully authenticated with an AP.
	 */
	if (skb->protocol != __constant_htons(ETH_P_802_11) &&
	    wp->state != WIRELESS_STATE_UP) {
		if (wp->resolution_queue.qlen <
		    wp->resolution_queue_maxlen)
			skb_queue_tail(&wp->resolution_queue, skb);
		else
			kfree_skb(skb);
		return -1;
	}
	return 0;
}

#endif /* !(_IF_80211) */
