[PATCH] Marvell Libertas 8388 802.11b/g USB driver

Add the Marvell Libertas 8388 802.11 USB driver.

Signed-off-by: Marcelo Tosatti <marcelo@kvack.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 4426841..c4b3dc2 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -265,6 +265,19 @@
 
 	  If you are not sure, say N here.
 
+config LIBERTAS_USB
+	tristate "Marvell Libertas 8388 802.11a/b/g cards"
+	depends on NET_RADIO && USB
+	select FW_LOADER
+	---help---
+	  A driver for Marvell Libertas 8388 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 ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c613af1..d212460 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -43,3 +43,4 @@
 obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
+obj-$(CONFIG_LIBERTAS_USB)     += libertas/
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
new file mode 100644
index 0000000..e0ecc4d
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.c
@@ -0,0 +1,754 @@
+/**
+  * This file contains functions for 802.11D.
+  */
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/wireless.h>
+
+#include "host.h"
+#include "decl.h"
+#include "11d.h"
+#include "dev.h"
+#include "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}
+};
+
+static u8 wlan_region_2_code(u8 * 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);
+}
+
+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 nrchan-th chan after the firstchan
+ *  @param band       band
+ *  @param firstchan  first channel number
+ *  @param nrchan   number of channels
+ *  @return 	      the nrchan-th chan number
+*/
+static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
+/*find the nrchan-th chan after the firstchan*/
+{
+	u8 i;
+	struct chan_freq_power *cfp;
+	u8 cfp_no;
+
+	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) {
+			lbs_pr_debug(1, "firstchan found\n");
+			break;
+		}
+	}
+
+	if (i < cfp_no) {
+		/*if beyond the boundary */
+		if (i + nrchan < cfp_no) {
+			*chan = (cfp + i + nrchan)->channel;
+			return 1;
+		}
+	}
+
+	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 nr_chan = parsed_region_chan->nr_chan;
+	u8 i = 0;
+
+	lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+		sizeof(struct chan_power_11d) * nr_chan);
+
+	for (i = 0; i < nr_chan; i++) {
+		if (chan == chanpwr[i].chan) {
+			lbs_pr_debug(1, "11D: Found Chan:%d\n", chan);
+			return 1;
+		}
+	}
+
+	lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan);
+	return 0;
+}
+
+u32 libertas_chan_2_freq(u8 chan, u8 band)
+{
+	struct chan_freq_power *cf;
+	u16 cnt;
+	u16 i;
+	u32 freq = 0;
+
+	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;
+	}
+
+	return freq;
+}
+
+static int generate_domain_info_11d(struct parsed_region_chan_11d
+				  *parsed_region_chan,
+				  struct wlan_802_11d_domain_reg * domaininfo)
+{
+	u8 nr_subband = 0;
+
+	u8 nr_chan = parsed_region_chan->nr_chan;
+	u8 nr_parsedchan = 0;
+
+	u8 firstchan = 0, nextchan = 0, maxpwr = 0;
+
+	u8 i, flag = 0;
+
+	memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
+	       COUNTRY_CODE_LEN);
+
+	lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
+	lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+		sizeof(struct parsed_region_chan_11d));
+
+	for (i = 0; i < nr_chan; i++) {
+		if (!flag) {
+			flag = 1;
+			nextchan = firstchan =
+			    parsed_region_chan->chanpwr[i].chan;
+			maxpwr = parsed_region_chan->chanpwr[i].pwr;
+			nr_parsedchan = 1;
+			continue;
+		}
+
+		if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
+		    parsed_region_chan->chanpwr[i].pwr == maxpwr) {
+			nextchan++;
+			nr_parsedchan++;
+		} else {
+			domaininfo->subband[nr_subband].firstchan = firstchan;
+			domaininfo->subband[nr_subband].nrchan =
+			    nr_parsedchan;
+			domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+			nr_subband++;
+			nextchan = firstchan =
+			    parsed_region_chan->chanpwr[i].chan;
+			maxpwr = parsed_region_chan->chanpwr[i].pwr;
+		}
+	}
+
+	if (flag) {
+		domaininfo->subband[nr_subband].firstchan = firstchan;
+		domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
+		domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+		nr_subband++;
+	}
+	domaininfo->nr_subband = nr_subband;
+
+	lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
+	lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+		COUNTRY_CODE_LEN + 1 +
+		sizeof(struct ieeetypes_subbandset) * nr_subband);
+	return 0;
+}
+
+/**
+ *  @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;
+
+	if (region_chan == NULL) {
+		lbs_pr_debug(1, "11D: region_chan is NULL\n");
+		return;
+	}
+
+	cfp = region_chan->CFP;
+	if (cfp == NULL) {
+		lbs_pr_debug(1, "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);
+
+	lbs_pr_debug(1, "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;
+		lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n",
+		       parsed_region_chan->chanpwr[i].chan,
+		       parsed_region_chan->chanpwr[i].pwr);
+	}
+	parsed_region_chan->nr_chan = region_chan->nrcfp;
+
+	lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+
+	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();
+
+	cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+	if (cfp == 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 	                0
+*/
+static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
+				 countryinfo,
+				 u8 band,
+				 struct parsed_region_chan_11d *
+				 parsed_region_chan)
+{
+	u8 nr_subband, nrchan;
+	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
+	 */
+
+	lbs_dbg_hex("CountryInfo:", (u8 *) 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 0;
+	}
+
+	/*Step1: check region_code */
+	parsed_region_chan->region = region =
+	    wlan_region_2_code(countryinfo->countrycode);
+
+	lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
+	lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+		COUNTRY_CODE_LEN);
+
+	parsed_region_chan->band = band;
+
+	memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
+	       COUNTRY_CODE_LEN);
+
+	nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
+	    sizeof(struct ieeetypes_subbandset);
+
+	for (j = 0, lastchan = 0; j < nr_subband; j++) {
+
+		if (countryinfo->subband[j].firstchan <= lastchan) {
+			/*Step2&3. Check First Chan Num increment and no overlap */
+			lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
+			       countryinfo->subband[j].firstchan, lastchan);
+			continue;
+		}
+
+		firstchan = countryinfo->subband[j].firstchan;
+		nrchan = countryinfo->subband[j].nrchan;
+
+		for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
+			/*step4: channel is supported? */
+
+			if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
+				/* Chan is not found in UN table */
+				lbs_pr_debug(1, "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 */
+				lbs_pr_debug(1,
+				       "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->nr_chan = idx;
+
+	lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
+	lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+		2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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 = cmd_scan_type_passive;
+
+	ENTER();
+
+	if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+		lbs_pr_debug(1, "11D: Found and do Active Scan\n");
+		scan_type = cmd_scan_type_active;
+	} else {
+		lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
+	}
+
+	LEAVE();
+	return scan_type;
+
+}
+
+void libertas_init_11d(wlan_private * priv)
+{
+	priv->adapter->enable11d = 0;
+	memset(&(priv->adapter->parsed_region_chan), 0,
+	       sizeof(struct parsed_region_chan_11d));
+	return;
+}
+
+static int wlan_enable_11d(wlan_private * priv, u8 flag)
+{
+	int ret;
+
+	priv->adapter->enable11d = flag;
+
+	/* send cmd to FW to enable/disable 11D function in FW */
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    cmd_act_set,
+				    cmd_option_waitforrsp,
+				    OID_802_11D_ENABLE,
+				    &priv->adapter->enable11d);
+	if (ret)
+		lbs_pr_debug(1, "11D: Fail to enable 11D \n");
+
+	return 0;
+}
+
+/**
+ *  @brief This function sets DOMAIN INFO to FW
+ *  @param priv       pointer to wlan_private
+ *  @return 	      0; -1
+*/
+static int set_domain_info_11d(wlan_private * priv)
+{
+	int ret;
+
+	if (!priv->adapter->enable11d) {
+		lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
+		return 0;
+	}
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
+				    cmd_act_set,
+				    cmd_option_waitforrsp, 0, NULL);
+	if (ret)
+		lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
+
+	return ret;
+}
+
+/**
+ *  @brief This function setups scan channels
+ *  @param priv       pointer to wlan_private
+ *  @param band       band
+ *  @return 	      0
+*/
+int libertas_set_universaltable(wlan_private * priv, u8 band)
+{
+	wlan_adapter *adapter = priv->adapter;
+	u16 size = sizeof(struct chan_freq_power);
+	u16 i = 0;
+
+	memset(adapter->universal_channel, 0,
+	       sizeof(adapter->universal_channel));
+
+	adapter->universal_channel[i].nrcfp =
+	    sizeof(channel_freq_power_UN_BG) / size;
+	lbs_pr_debug(1, "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++;
+
+	return 0;
+}
+
+/**
+ *  @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 	      0
+*/
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_ds_command *cmd, u16 cmdno,
+				 u16 cmdoption)
+{
+	struct cmd_ds_802_11d_domain_info *pdomaininfo =
+	    &cmd->params.domaininfo;
+	struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+	wlan_adapter *adapter = priv->adapter;
+	u8 nr_subband = adapter->domainreg.nr_subband;
+
+	ENTER();
+
+	lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
+
+	cmd->command = cpu_to_le16(cmdno);
+	pdomaininfo->action = cpu_to_le16(cmdoption);
+	if (cmdoption == cmd_act_get) {
+		cmd->size =
+		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+		lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+			(int)(cmd->size));
+		LEAVE();
+		return 0;
+	}
+
+	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+	memcpy(domain->countrycode, adapter->domainreg.countrycode,
+	       sizeof(domain->countrycode));
+
+	domain->header.len =
+	    cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
+			     sizeof(domain->countrycode));
+
+	if (nr_subband) {
+		memcpy(domain->subband, adapter->domainreg.subband,
+		       nr_subband * sizeof(struct ieeetypes_subbandset));
+
+		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+					     domain->header.len +
+					     sizeof(struct mrvlietypesheader) +
+					     S_DS_GEN);
+	} else {
+		cmd->size =
+		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+	}
+
+	lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
+
+	LEAVE();
+
+	return 0;
+}
+
+/**
+ *  @brief This function implements private cmd: enable/disable 11D
+ *  @param priv    pointer to wlan_private
+ *  @param wrq     pointer to user data
+ *  @return 	   0 or -1
+ */
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+	int data = 0;
+	int *val;
+
+	ENTER();
+	data = SUBCMD_DATA(wrq);
+
+	lbs_pr_debug(1, "enable 11D: %s\n",
+	       (data == 1) ? "enable" : "Disable");
+
+	wlan_enable_11d(priv, data);
+	val = (int *)wrq->u.name;
+	*val = priv->adapter->enable11d;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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 	   0; -1
+ */
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11d_domain_info
+	*domaininfo = &resp->params.domaininforesp;
+	struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
+	u16 action = le16_to_cpu(domaininfo->action);
+	s16 ret = 0;
+	u8 nr_subband = 0;
+
+	ENTER();
+
+	lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+		(int)le16_to_cpu(resp->size));
+
+	nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
+	/* countrycode 3 bytes */
+
+	lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+
+	if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
+		lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
+		return -1;
+	}
+
+	switch (action) {
+	case cmd_act_set:	/*Proc Set action */
+		break;
+
+	case cmd_act_get:
+		break;
+	default:
+		lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
+		ret = -1;
+		break;
+	}
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function parses countryinfo from AP and download country info to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   0; -1
+ */
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+	int ret;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+	if (priv->adapter->enable11d) {
+		memset(&adapter->parsed_region_chan, 0,
+		       sizeof(struct parsed_region_chan_11d));
+		ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
+					       countryinfo, 0,
+					       &adapter->parsed_region_chan);
+
+		if (ret == -1) {
+			lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
+			LEAVE();
+			return ret;
+		}
+
+		memset(&adapter->domainreg, 0,
+		       sizeof(struct wlan_802_11d_domain_reg));
+		generate_domain_info_11d(&adapter->parsed_region_chan,
+				      &adapter->domainreg);
+
+		ret = set_domain_info_11d(priv);
+
+		if (ret) {
+			lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+			LEAVE();
+			return ret;
+		}
+	}
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function generates 11D info from user specified regioncode and download to FW
+ *  @param priv    pointer to wlan_private
+ *  @return 	   0; -1
+ */
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
+{
+	int ret;
+	wlan_adapter *adapter = priv->adapter;
+	struct region_channel *region_chan;
+	u8 j;
+
+	ENTER();
+	lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+
+	if (priv->adapter->enable11d) {
+		/* 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];
+
+			lbs_pr_debug(1, "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])) {
+			lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
+			       adapter->curbssparams.band);
+			LEAVE();
+			return -1;
+		}
+
+		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));
+		generate_domain_info_11d(&adapter->parsed_region_chan,
+					 &adapter->domainreg);
+
+		ret = set_domain_info_11d(priv);
+
+		if (ret) {
+			lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+			LEAVE();
+			return ret;
+		}
+
+	}
+
+	LEAVE();
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
new file mode 100644
index 0000000..db2ebea9
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.h
@@ -0,0 +1,105 @@
+/**
+  * This header file contains data structures and
+  * function declarations of 802.11d
+  */
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+#include "types.h"
+#include "defs.h"
+
+#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 cmd_ds_command;
+
+/** Data structure for Country IE*/
+struct ieeetypes_subbandset {
+	u8 firstchan;
+	u8 nrchan;
+	u8 maxtxpwr;
+} __attribute__ ((packed));
+
+struct ieeetypes_countryinfoset {
+	u8 element_id;
+	u8 len;
+	u8 countrycode[COUNTRY_CODE_LEN];
+	struct ieeetypes_subbandset subband[1];
+};
+
+struct ieeetypes_countryinfofullset {
+	u8 element_id;
+	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));
+
+struct cmd_ds_802_11d_domain_info {
+	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 nr_subband;
+	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 nr_chan;
+} __attribute__ ((packed));
+
+struct region_code_mapping {
+	u8 region[COUNTRY_CODE_LEN];
+	u8 code;
+};
+
+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 cmd_ds_command *cmd, u16 cmdno,
+				 u16 cmdOption);
+
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+				 struct cmd_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 --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
new file mode 100644
index 0000000..8862742
--- /dev/null
+++ b/drivers/net/wireless/libertas/LICENSE
@@ -0,0 +1,16 @@
+  Copyright (c) 2003-2006, Marvell International Ltd.
+  All Rights Reserved
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
new file mode 100644
index 0000000..19c9350
--- /dev/null
+++ b/drivers/net/wireless/libertas/Makefile
@@ -0,0 +1,21 @@
+# EXTRA_CFLAGS += -Wpacked
+
+usb8xxx-objs := main.o fw.o wext.o \
+		rx.o tx.o cmd.o 	  \
+		cmdresp.o scan.o	  \
+		join.o 11d.o 		  \
+		ioctl.o debugfs.o	  \
+		ethtool.o assoc.o
+
+ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y)
+EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG
+endif
+
+
+# This is needed to support the newer boot2 bootloader (v >= 3104)
+EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND
+usb8xxx-objs += if_bootcmd.o
+usb8xxx-objs += if_usb.o
+
+obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
new file mode 100644
index 0000000..688da4c
--- /dev/null
+++ b/drivers/net/wireless/libertas/README
@@ -0,0 +1,1044 @@
+================================================================================
+			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.
+================================================================================
+
+=====================
+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]
+
+=====================
+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
+
+BT Commands:
+	The blinding table (BT) contains a list of mac addresses that should be
+	ignored by the firmware.  It is primarily used for debugging and
+	testing networks.  It can be edited and inspected with the following
+	commands:
+
+	iwpriv ethX bt_reset
+	iwpriv ethX bt_add <mac_address>
+	iwpriv ethX bt_del <mac_address>
+	iwpriv ethX bt_list <id>
+
+FWT Commands:
+	The forwarding table (FWT) is a feature used to manage mesh network
+	routing in the firmware.  The FWT is essentially a routing table that
+	associates a destination mac address (da) with a next hop receiver
+	address (ra).  The FWT can be inspected and edited with the following
+	iwpriv commands, which are described in greater detail below.
+	Eventually, the table will be automatically maintained by a custom
+	routing protocol.
+
+	NOTE: FWT commands replace the previous DFT commands.  What were the DFT
+	commands?, you might ask.  They were an earlier API to the firmware that
+	implemented a simple MAC-layer forwarding mechanism.  In the unlikely
+	event that you were using these commands, you must migrate to the new
+	FWT commands which can be used to achieve the same functionality.
+
+	iwpriv ethX fwt_add [parameters]
+	iwpriv ethX fwt_del [parameters]
+	iwpriv ethX fwt_lookup [parameters]
+	iwpriv ethX fwt_list [parameters]
+	iwpriv ethX fwt_list_route [parameters]
+	iwpriv ethX fwt_list_neigh [parameters]
+	iwpriv ethX fwt_reset [parameters]
+	iwpriv ethX fwt_cleanup
+	iwpriv ethX fwt_time
+
+MESH Commands:
+
+	The MESH commands are used to configure various features of the mesh
+	routing protocol.  The following commands are supported:
+
+	iwpriv ethX mesh_get_ttl
+	iwpriv ethX mesh_set_ttl ttl
+
+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.
+
+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.
+
+
+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)
+
+fwt_add
+	This command is used to insert an entry into the FWT table. The list of
+	parameters must follow the following structure:
+
+	iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr]
+
+	The parameters between brackets are optional, but they must appear in
+	the order specified.  For example, if you want to specify the metric,
+	you must also specify the dir, ssn, and dsn but you need not specify the
+	hopcount, expiration, sleepmode, or snr.  Any unspecified parameters
+	will be assigned the defaults specified below.
+
+	The different parameters are:-
+		da		-- DA MAC address in the form 00:11:22:33:44:55
+		ra		-- RA MAC address in the form 00:11:22:33:44:55
+		metric		-- route metric (cost: smaller-metric routes are
+				   preferred, default is 0)
+		dir		-- direction (1 for direct, 0 for reverse,
+				   default is 1)
+		ssn		-- Source Sequence Number (time at the RA for
+				   reverse routes.  Default is 0)
+		dsn		-- Destination Sequence Number (time at the DA
+				   for direct routes.  Default is 0)
+		hopcount	-- hop count (currently unused, default is 0)
+		ttl		-- TTL (Only used in reverse entries)
+		expiration	-- entry expiration (in ticks, where a tick is
+				   1024us, or ~ 1ms. Use 0 for an indefinite
+				   entry, default is 0)
+		sleepmode	-- RA's sleep mode (currently unused, default is
+				   0)
+		snr		-- SNR in the link to RA (currently unused,
+				   default is 0)
+
+	The command does not return anything.
+
+fwt_del
+	This command is used to remove an entry to the FWT table. The list of
+	parameters must follow the following structure:
+
+		iwpriv ethX fwt_del da ra [dir]
+
+	where the different parameters are:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+		ra		-- RA MAC address (in the form "00:11:22:33:44:55")
+		dir		-- direction (1 for direct, 0 for reverse,
+				   default is 1)
+
+	The command does not return anything.
+
+fwt_lookup
+	This command is used to get the best route in the FWT table to a given
+	host. The only parameter is the MAC address of the host that is being
+	looked for.
+
+		iwpriv ethX fwt_lookup da
+
+	where:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+
+	The command returns an output string identical to the one returned by
+	fwt_list described below.
+
+
+fwt_list
+	This command is used to list a route from the FWT table. The only
+	parameter is the index into the table. If you want to list all the
+	routes in a table, start with index=0, and keep listing until you get a
+	"(null)" string.  Note that the indicies may change as the fwt is
+	updated.  It is expected that most users will not use fwt_list directly,
+	but that a utility similar to the traditional route command will be used
+	to invoke fwt_list over and over.
+
+		iwpriv ethX fwt_list index
+
+	The output is a string of the following form:
+
+		da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr
+
+	where the different fields are:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+		ra		-- RA MAC address (in the form "00:11:22:33:44:55")
+		metric		-- route metric (cost: smaller-metric routes are preferred)
+		dir		-- direction (1 for direct, 0 for reverse)
+		ssn		-- Source Sequence Number (time at the RA for reverse routes)
+		dsn		-- Destination Sequence Number (time at the DA for direct routes)
+		hopcount	-- hop count (currently unused)
+		ttl		-- TTL (only used in reverse entries)
+		expiration	-- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+		sleepmode	-- RA's sleep mode (currently unused)
+		snr		-- SNR in the link to RA (currently unused)
+
+fwt_list_route
+	This command is used to list a route from the FWT table. The only
+	parameter is the route ID. If you want to list all the routes in a
+	table, start with rid=0, and keep incrementing rid until you get a
+	"(null)" string. This function is similar to fwt_list. The only
+	difference is the output format.  Also note that this command is meant
+	for debugging.  It is expected that users will use fwt_lookup and
+	fwt_list.  One important reason for this is that the route id may change
+	as the route table is altered.
+
+		iwpriv ethX fwt_list_route rid
+
+	The output is a string of the following form:
+
+		da metric dir nid ssn dsn hopcount ttl expiration
+
+	where the different fields are:-
+		da		-- DA MAC address (in the form "00:11:22:33:44:55")
+		metric		-- route metric (cost: smaller-metric routes are preferred)
+		dir		-- direction (1 for direct, 0 for reverse)
+		nid		-- Next-hop (neighbor) host ID (nid)
+		ssn		-- Source Sequence Number (time at the RA for reverse routes)
+		dsn		-- Destination Sequence Number (time at the DA for direct routes)
+		hopcount	-- hop count (currently unused)
+		ttl		-- TTL count (only used in reverse entries)
+		expiration	-- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+
+fwt_list_neigh
+	This command is used to list a neighbor from the FWT table. The only
+	parameter is the neighbor ID. If you want to list all the neighbors in a
+	table, start with nid=0, and keep incrementing nid until you get a
+	"(null)" string.  Note that the nid from a fwt_list_route command can be
+	used as an input to this command.  Also note that this command is meant
+	mostly for debugging.  It is expected that users will use fwt_lookup.
+	One important reason for this is that the neighbor id may change as the
+	neighbor table is altered.
+
+		iwpriv ethX fwt_list_neigh nid
+
+	The output is a string of the following form:
+
+		ra sleepmode snr references
+
+	where the different fields are:-
+		ra		-- RA MAC address (in the form "00:11:22:33:44:55")
+		sleepmode	-- RA's sleep mode (currently unused)
+		snr		-- SNR in the link to RA (currently unused)
+		references	-- RA's reference counter
+
+fwt_reset
+	This command is used to reset the FWT table, getting rid of all the
+	entries. There are no input parameters.
+
+		iwpriv ethX fwt_reset
+
+	The command does not return anything.
+
+fwt_cleanup
+	This command is used to perform user-based garbage recollection. The
+	FWT table is checked, and all the entries that are expired or invalid
+	are cleaned. Note that this is exported to the driver for debugging
+	purposes, as garbage collection is also fired by the firmware when in
+	space problems. There are no input parameters.
+
+		iwpriv ethX fwt_cleanup
+
+	The command does returns the number of invalid/expired routes deleted.
+
+fwt_time
+	This command returns a card's internal time representation.  It is this
+	time that is used to represent the expiration times of FWT entries.  The
+	number is not consistent from card to card; it is simply a timer count.
+	The fwt_time command is used to inspect the timer so that expiration
+	times reported by fwt_list can be properly interpreted.
+
+		iwpriv ethX fwt_time
+
+mesh_get_ttl
+
+	The mesh ttl is the number of hops a mesh packet can traverse before it
+	is dropped.  This parameter is used to prevent infinite loops in the
+	mesh network.  The value returned by this function is the ttl assigned
+	to all mesh packets.  Currently there is no way to control the ttl on a
+	per packet or per socket basis.
+
+	iwpriv ethX mesh_get_ttl
+
+mesh_set_ttl ttl
+
+	Set the ttl.  The argument must be between 0 and 255.
+
+	iwpriv ethX mesh_set_ttl <ttl>
+
+=========================
+ETHTOOL
+=========================
+
+
+Use the -i option to retrieve version information from the driver.
+
+# ethtool -i eth0
+driver: libertas
+version: COMM-USB8388-318.p4
+firmware-version: 5.110.7
+bus-info:
+
+Use the -e option to read the EEPROM contents of the card.
+
+	Usage:
+	ethtool -e ethX [raw on|off] [offset N] [length N]
+
+       -e     retrieves and prints an EEPROM dump for the  specified  ethernet
+              device.   When raw is enabled, then it dumps the raw EEPROM data
+              to stdout. The length and offset parameters allow  dumping  cer-
+              tain portions of the EEPROM.  Default is to dump the entire EEP-
+              ROM.
+
+# ethtool -e eth0 offset 0 length 16
+Offset          Values
+------          ------
+0x0000          38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
+
+========================
+DEBUGFS COMMANDS
+========================
+
+those commands are used via debugfs interface
+
+===========
+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 must be specified in
+	hexadecimal (its possible to preceed preceding the number with a "0x").
+
+	Path: /debugfs/libertas_wireless/ethX/registers/
+
+	Usage:
+		echo "0xa123" > rdmac ; cat rdmac
+		echo "0xa123" > rdbbp ; cat rdbbp
+		echo "0xa123" > rdrf ; cat rdrf
+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 must
+	be specified in hexadecimal (its possible to preceed the number
+	with a "0x").
+
+	Usage:
+		echo "0xa123 0xaa" > wrmac
+		echo "0xa123 0xaa" > wrbbp
+		echo "0xa123 0xaa" > wrrf
+
+sleepparams
+	This command is used to set the sleepclock configurations
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+	Usage:
+		cat sleepparams: reads the current sleepclock configuration
+
+		echo "p1 p2 p3 p4 p5 p6" > sleepparams: 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)
+
+subscribed_events
+
+	The subscribed_events directory contains the interface for the
+	subscribed events API.
+
+	Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+
+	Each event is represented by a filename. Each filename consists of the
+	following three fields:
+	Value Frequency Subscribed
+
+	To read the current values for a given event, do:
+		cat event
+	To set the current values, do:
+		echo "60 2 1" > event
+
+	Frequency field specifies the reporting frequency for this event.
+	If it is set to 0, then the event is reported only once, and then
+	automatically unsubscribed. If it is set to 1, then the event is
+	reported every time it occurs. If it is set to N, then the event is
+	reported every Nth time it occurs.
+
+	beacon_missed
+	Value field specifies the number of consecutive missing beacons which
+	triggers the LINK_LOSS event. This event is generated only once after
+	which the firmware resets its state. At initialization, the LINK_LOSS
+	event is subscribed by default. The default value of MissedBeacons is
+	60.
+
+	failure_count
+	Value field specifies the consecutive failure count threshold which
+	triggers the generation of the MAX_FAIL event. Once this event is
+	generated, the consecutive failure count is reset to 0.
+	At initialization, the MAX_FAIL event is NOT subscribed by
+	default.
+
+	high_rssi
+	This event is generated when the average received RSSI in beacons goes
+	above a threshold, specified by Value.
+
+	low_rssi
+	This event is generated when the average received RSSI in beacons goes
+	below a threshold, specified by Value.
+
+	high_snr
+	This event is generated when the average received SNR in beacons goes
+	above a threshold, specified by Value.
+
+	low_snr
+	This event is generated when the average received SNR in beacons goes
+	below a threshold, specified by Value.
+
+extscan
+	This command is used to do a specific scan.
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+	Usage: echo "SSID" > extscan
+
+	Example:
+		echo "LINKSYS-AP" > extscan
+
+	To see the results of use getscantable command.
+
+getscantable
+
+	Display the current contents of the driver scan table (ie. get the
+	scan results).
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+	Usage:
+		cat getscantable
+
+setuserscan
+	Initiate a customized scan and retrieve the results
+
+
+	Path: /debugfs/libertas_wireless/ethX/
+
+    Usage:
+       echo "[ARGS]" > setuserscan
+
+         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:
+            echo "chan=1g,6g,11g" > setuserscan
+
+    2) Perform a passive scan on channel 11 for 20 ms:
+            echo "chan=11gp dur=20" > setuserscan
+
+    3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+       channel 36 in the 'a' band:
+
+            echo "chan=1g,6g,11g,36ap" > setuserscan
+
+    4) Perform an active scan on channel 6 and 36 for a specific SSID:
+            echo "chan=6g,36a ssid="TestAP"" > setuserscan
+
+    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:
+            echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+    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:
+            echo "chan=6g type=1 probes=2 keep=1" > setuserscan
+
+    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.
+
+==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
new file mode 100644
index 0000000..b55c7f5
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -0,0 +1,588 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#include <linux/bitops.h>
+#include <net/ieee80211.h>
+
+#include "assoc.h"
+#include "join.h"
+#include "decl.h"
+#include "hostcmd.h"
+#include "host.h"
+
+
+static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static int assoc_helper_essid(wlan_private *priv,
+                              struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	int i;
+
+	ENTER();
+
+	lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid);
+	if (assoc_req->mode == wlan802_11infrastructure) {
+		if (adapter->prescan) {
+			libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
+		}
+
+		i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
+				NULL, wlan802_11infrastructure);
+		if (i >= 0) {
+			lbs_pr_debug(1,
+			       "SSID found in scan list ... associating...\n");
+
+			ret = wlan_associate(priv, &adapter->scantable[i]);
+			if (ret == 0) {
+				memcpy(&assoc_req->bssid,
+				       &adapter->scantable[i].macaddress,
+				       ETH_ALEN);
+			}
+		} else {
+			lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n",
+				assoc_req->ssid.ssid);
+		}
+	} else if (assoc_req->mode == wlan802_11ibss) {
+		/* 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, &assoc_req->ssid, 0);
+
+		/* Search for the requested SSID in the scan table */
+		i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
+				wlan802_11ibss);
+		if (i >= 0) {
+			lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret);
+			libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+		} else {
+			/* else send START command */
+			lbs_pr_debug(1, "SSID not found in list, so creating adhoc"
+				" with SSID '%s'\n", assoc_req->ssid.ssid);
+			libertas_start_adhoc_network(priv, &assoc_req->ssid);
+		}
+		memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
+	}
+
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_bssid(wlan_private *priv,
+                              struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i, ret = 0;
+
+	ENTER();
+
+	lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n",
+		MAC_ARG(assoc_req->bssid));
+
+	/* Search for index position in list for requested MAC */
+	i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
+			    assoc_req->mode);
+	if (i < 0) {
+		lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, "
+			"cannot associate.\n", MAC_ARG(assoc_req->bssid));
+		goto out;
+	}
+
+	if (assoc_req->mode == wlan802_11infrastructure) {
+		ret = wlan_associate(priv, &adapter->scantable[i]);
+		lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret);
+	} else if (assoc_req->mode == wlan802_11ibss) {
+		libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+	}
+	memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
+		sizeof(struct WLAN_802_11_SSID));
+
+out:
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_associate(wlan_private *priv,
+                                  struct assoc_request * assoc_req)
+{
+	int ret = 0, done = 0;
+
+	/* If we're given and 'any' BSSID, try associating based on SSID */
+
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
+		    && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
+			ret = assoc_helper_bssid(priv, assoc_req);
+			done = 1;
+			if (ret) {
+				lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+			}
+		}
+	}
+
+	if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		ret = assoc_helper_essid(priv, assoc_req);
+		if (ret) {
+			lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+		}
+	}
+
+	return ret;
+}
+
+
+static int assoc_helper_mode(wlan_private *priv,
+                             struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	if (assoc_req->mode == adapter->inframode) {
+		LEAVE();
+		return 0;
+	}
+
+	if (assoc_req->mode == wlan802_11infrastructure) {
+		if (adapter->psstate != PS_STATE_FULL_POWER)
+			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+		adapter->psmode = wlan802_11powermodecam;
+	}
+
+	adapter->inframode = assoc_req->mode;
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    0, cmd_option_waitforrsp,
+				    OID_802_11_INFRASTRUCTURE_MODE,
+				    (void *) assoc_req->mode);
+
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_wep_keys(wlan_private *priv,
+                                 struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int i;
+	int ret = 0;
+
+	ENTER();
+
+	/* Set or remove WEP keys */
+	if (   assoc_req->wep_keys[0].len
+	    || assoc_req->wep_keys[1].len
+	    || assoc_req->wep_keys[2].len
+	    || assoc_req->wep_keys[3].len) {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_set_wep,
+					    cmd_act_add,
+					    cmd_option_waitforrsp,
+					    0, assoc_req);
+	} else {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_set_wep,
+					    cmd_act_remove,
+					    cmd_option_waitforrsp,
+					    0, NULL);
+	}
+
+	if (ret)
+		goto out;
+
+	/* enable/disable the MAC's WEP packet filter */
+	if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled)
+		adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+	else
+		adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+	ret = libertas_set_mac_packet_filter(priv);
+	if (ret)
+		goto out;
+
+	mutex_lock(&adapter->lock);
+
+	/* Copy WEP keys into adapter wep key fields */
+	for (i = 0; i < 4; i++) {
+		memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
+			sizeof(struct WLAN_802_11_KEY));
+	}
+	adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+
+	mutex_unlock(&adapter->lock);
+
+out:
+	LEAVE();
+	return ret;
+}
+
+static int assoc_helper_secinfo(wlan_private *priv,
+                                struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	memcpy(&adapter->secinfo, &assoc_req->secinfo,
+		sizeof(struct wlan_802_11_security));
+
+	ret = libertas_set_mac_packet_filter(priv);
+
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_wpa_keys(wlan_private *priv,
+                                 struct assoc_request * assoc_req)
+{
+	int ret = 0;
+
+	ENTER();
+
+	/* enable/Disable RSN */
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_enable_rsn,
+				    cmd_act_set,
+				    cmd_option_waitforrsp,
+				    0, assoc_req);
+	if (ret)
+		goto out;
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_key_material,
+				    cmd_act_set,
+				    cmd_option_waitforrsp,
+				    0, assoc_req);
+
+out:
+	LEAVE();
+	return ret;
+}
+
+
+static int assoc_helper_wpa_ie(wlan_private *priv,
+                               struct assoc_request * assoc_req)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+		memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+		adapter->wpa_ie_len = assoc_req->wpa_ie_len;
+	} else {
+		memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
+		adapter->wpa_ie_len = 0;
+	}
+
+	LEAVE();
+	return ret;
+}
+
+
+static int should_deauth_infrastructure(wlan_adapter *adapter,
+                                        struct assoc_request * assoc_req)
+{
+	if (adapter->connect_status != libertas_connected)
+		return 0;
+
+	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		lbs_pr_debug(1, "Deauthenticating due to new SSID in "
+			" configuration request.\n");
+		return 1;
+	}
+
+	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+		if (adapter->secinfo.authmode !=
+		    assoc_req->secinfo.authmode) {
+			lbs_pr_debug(1, "Deauthenticating due to updated security "
+				"info in configuration request.\n");
+			return 1;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		lbs_pr_debug(1, "Deauthenticating due to new BSSID in "
+			" configuration request.\n");
+		return 1;
+	}
+
+	/* FIXME: deal with 'auto' mode somehow */
+	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+		if (assoc_req->mode != wlan802_11infrastructure)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int should_stop_adhoc(wlan_adapter *adapter,
+                             struct assoc_request * assoc_req)
+{
+	if (adapter->connect_status != libertas_connected)
+		return 0;
+
+	if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
+		return 1;
+	if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
+			sizeof(struct WLAN_802_11_SSID)))
+		return 1;
+
+	/* FIXME: deal with 'auto' mode somehow */
+	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+		if (assoc_req->mode != wlan802_11ibss)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+void wlan_association_worker(struct work_struct *work)
+{
+	wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req = NULL;
+	int ret = 0;
+	int find_any_ssid = 0;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = adapter->assoc_req;
+	adapter->assoc_req = NULL;
+	mutex_unlock(&adapter->lock);
+
+	if (!assoc_req) {
+		LEAVE();
+		return;
+	}
+
+	lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n",
+		assoc_req->flags);
+
+	/* If 'any' SSID was specified, find an SSID to associate with */
+	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
+	    && !assoc_req->ssid.ssidlength)
+		find_any_ssid = 1;
+
+	/* But don't use 'any' SSID if there's a valid locked BSSID to use */
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
+		    && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
+			find_any_ssid = 0;
+	}
+
+	if (find_any_ssid) {
+		enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+		ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
+				assoc_req->mode, &new_mode);
+		if (ret) {
+			lbs_pr_debug(1, "Could not find best network\n");
+			ret = -ENETUNREACH;
+			goto out;
+		}
+
+		/* Ensure we switch to the mode of the AP */
+		if (assoc_req->mode == wlan802_11autounknown) {
+			set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+			assoc_req->mode = new_mode;
+		}
+	}
+
+	/*
+	 * Check if the attributes being changing require deauthentication
+	 * from the currently associated infrastructure access point.
+	 */
+	if (adapter->inframode == wlan802_11infrastructure) {
+		if (should_deauth_infrastructure(adapter, assoc_req)) {
+			ret = libertas_send_deauthentication(priv);
+			if (ret) {
+				lbs_pr_debug(1, "Deauthentication due to new "
+					"configuration request failed: %d\n",
+					ret);
+			}
+		}
+	} else if (adapter->inframode == wlan802_11ibss) {
+		if (should_stop_adhoc(adapter, assoc_req)) {
+			ret = libertas_stop_adhoc_network(priv);
+			if (ret) {
+				lbs_pr_debug(1, "Teardown of AdHoc network due to "
+					"new configuration request failed: %d\n",
+					ret);
+			}
+
+		}
+	}
+
+	/* Send the various configuration bits to the firmware */
+	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+		ret = assoc_helper_mode(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
+	    || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+		ret = assoc_helper_wep_keys(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+		ret = assoc_helper_secinfo(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+		ret = assoc_helper_wpa_ie(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
+	    || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+		ret = assoc_helper_wpa_keys(priv, assoc_req);
+		if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+			goto out;
+		}
+	}
+
+	/* SSID/BSSID should be the _last_ config option set, because they
+	 * trigger the association attempt.
+	 */
+	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
+	    || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		int success = 1;
+
+		ret = assoc_helper_associate(priv, assoc_req);
+		if (ret) {
+			lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n",
+				ret);
+			success = 0;
+		}
+
+		if (adapter->connect_status != libertas_connected) {
+			lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, "
+				"not connected.\n");
+			success = 0;
+		}
+
+		if (success) {
+			lbs_pr_debug(1, "ASSOC: association attempt successful. "
+				"Associated to '%s' (" MAC_FMT ")\n",
+				assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
+			libertas_prepare_and_send_command(priv,
+				cmd_802_11_rssi,
+				0, cmd_option_waitforrsp, 0, NULL);
+
+			libertas_prepare_and_send_command(priv,
+				cmd_802_11_get_log,
+				0, cmd_option_waitforrsp, 0, NULL);
+		} else {
+
+			ret = -1;
+		}
+	}
+
+out:
+	if (ret) {
+		lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n",
+			ret);
+	}
+	kfree(assoc_req);
+	LEAVE();
+}
+
+
+/*
+ * Caller MUST hold any necessary locks
+ */
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+{
+	struct assoc_request * assoc_req;
+
+	if (!adapter->assoc_req) {
+		adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
+		if (!adapter->assoc_req) {
+			lbs_pr_info("Not enough memory to allocate association"
+				" request!\n");
+			return NULL;
+		}
+	}
+
+	/* Copy current configuration attributes to the association request,
+	 * but don't overwrite any that are already set.
+	 */
+	assoc_req = adapter->assoc_req;
+	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+		memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
+			adapter->curbssparams.ssid.ssidlength);
+	}
+
+	if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+		assoc_req->channel = adapter->curbssparams.channel;
+
+	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
+		assoc_req->mode = adapter->inframode;
+
+	if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+		memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
+			ETH_ALEN);
+	}
+
+	if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
+		int i;
+		for (i = 0; i < 4; i++) {
+			memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+				sizeof(struct WLAN_802_11_KEY));
+		}
+	}
+
+	if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
+		assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
+
+	if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+		memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+			sizeof(struct WLAN_802_11_KEY));
+	}
+
+	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+			sizeof(struct WLAN_802_11_KEY));
+	}
+
+	if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+		memcpy(&assoc_req->secinfo, &adapter->secinfo,
+			sizeof(struct wlan_802_11_security));
+	}
+
+	if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+		memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
+			MAX_WPA_IE_LEN);
+		assoc_req->wpa_ie_len = adapter->wpa_ie_len;
+	}
+
+	return assoc_req;
+}
+
+
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
new file mode 100644
index 0000000..2ffd82d
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#ifndef _WLAN_ASSOC_H_
+#define _WLAN_ASSOC_H_
+
+#include "dev.h"
+
+void wlan_association_worker(struct work_struct *work);
+
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
+
+#define ASSOC_DELAY (HZ / 2)
+static inline void wlan_postpone_association_work(wlan_private *priv)
+{
+	if (priv->adapter->surpriseremoved)
+		return;
+	cancel_delayed_work(&priv->assoc_work);
+	queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+}
+
+static inline void wlan_cancel_association_work(wlan_private *priv)
+{
+	cancel_delayed_work(&priv->assoc_work);
+	if (priv->adapter->assoc_req) {
+		kfree(priv->adapter->assoc_req);
+		priv->adapter->assoc_req = NULL;
+	}
+}
+
+#endif /* _WLAN_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
new file mode 100644
index 0000000..bfdac58
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -0,0 +1,1958 @@
+/**
+  * This file contains the handling of command.
+  * It prepares command and sends it to firmware when it is ready.
+  */
+
+#include <net/iw_handler.h>
+#include "host.h"
+#include "hostcmd.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
+
+static u16 commands_allowed_in_ps[] = {
+	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 == cpu_to_le16(commands_allowed_in_ps[i]))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
+{
+	struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_get_hw_spec);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
+	memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
+				   struct cmd_ds_command *cmd,
+				   u16 cmd_action)
+{
+	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+	u16 action = cmd_action;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
+			     S_DS_GEN);
+	psm->action = cpu_to_le16(cmd_action);
+	psm->multipledtim = 0;
+	switch (action) {
+	case cmd_subcmd_enter_ps:
+		lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n");
+		lbs_pr_debug(1, "locallisteninterval = %d\n",
+		       adapter->locallisteninterval);
+
+		psm->locallisteninterval =
+		    cpu_to_le16(adapter->locallisteninterval);
+		psm->nullpktinterval =
+		    cpu_to_le16(adapter->nullpktinterval);
+		psm->multipledtim =
+		    cpu_to_le16(priv->adapter->multipledtim);
+		break;
+
+	case cmd_subcmd_exit_ps:
+		lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n");
+		break;
+
+	case cmd_subcmd_sleep_confirmed:
+		lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n");
+		break;
+
+	default:
+		break;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+					      struct cmd_ds_command *cmd,
+					      u16 cmd_action, void *pdata_buf)
+{
+	u16 *timeout = pdata_buf;
+
+	cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+			     + S_DS_GEN);
+
+	cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
+
+	if (cmd_action)
+		cmd->params.inactivity_timeout.timeout =
+		    cpu_to_le16(*timeout);
+	else
+		cmd->params.inactivity_timeout.timeout = 0;
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					u16 cmd_action)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+
+	if (cmd_action == cmd_act_get) {
+		memset(&adapter->sp, 0, sizeof(struct sleep_params));
+		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
+		sp->action = cpu_to_le16(cmd_action);
+	} else if (cmd_action == cmd_act_set) {
+		sp->action = cpu_to_le16(cmd_action);
+		sp->error = cpu_to_le16(adapter->sp.sp_error);
+		sp->offset = cpu_to_le16(adapter->sp.sp_offset);
+		sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
+		sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
+		sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
+		sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_set_wep(wlan_private * priv,
+                                   struct cmd_ds_command *cmd,
+                                   u32 cmd_act,
+                                   void * pdata_buf)
+{
+	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct assoc_request * assoc_req = pdata_buf;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep))
+	                             + S_DS_GEN);
+
+	if (cmd_act == cmd_act_add) {
+		int i;
+
+		if (!assoc_req) {
+			lbs_pr_debug(1, "Invalid association request!");
+			ret = -1;
+			goto done;
+		}
+
+		wep->action = cpu_to_le16(cmd_act_add);
+
+		/* default tx key index */
+		wep->keyindex = cpu_to_le16((u16)
+				                 (assoc_req->wep_tx_keyidx &
+				                 (u32)cmd_WEP_KEY_INDEX_MASK));
+
+		lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex);
+
+		/* Copy key types and material to host command structure */
+		for (i = 0; i < 4; i++) {
+			struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+
+			switch (pkey->len) {
+			case KEY_LEN_WEP_40:
+				wep->keytype[i] = cmd_type_wep_40_bit;
+				memmove(&wep->keymaterial[i], pkey->key,
+				        pkey->len);
+				break;
+			case KEY_LEN_WEP_104:
+				wep->keytype[i] = cmd_type_wep_104_bit;
+				memmove(&wep->keymaterial[i], pkey->key,
+				        pkey->len);
+				break;
+			case 0:
+				break;
+			default:
+				lbs_pr_debug(1, "Invalid WEP key %d length of %d\n",
+				       i, pkey->len);
+				ret = -1;
+				goto done;
+				break;
+			}
+		}
+	} else if (cmd_act == cmd_act_remove) {
+		/* ACT_REMOVE clears _all_ WEP keys */
+		wep->action = cpu_to_le16(cmd_act_remove);
+
+		/* default tx key index */
+		wep->keyindex = cpu_to_le16((u16)
+				                 (adapter->wep_tx_keyidx &
+				                 (u32)cmd_WEP_KEY_INDEX_MASK));
+	}
+
+	ret = 0;
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      u16 cmd_action)
+{
+	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
+			     S_DS_GEN);
+	penableRSN->action = cpu_to_le16(cmd_action);
+	if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+		penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+	} else {
+		penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+	}
+
+	return 0;
+}
+
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
+                            struct WLAN_802_11_KEY * pkey)
+{
+	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+
+	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
+		pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
+	} else {
+		pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
+	}
+
+	if (pkey->flags & KEY_INFO_WPA_UNICAST) {
+		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+	} else if (pkey->flags & KEY_INFO_WPA_MCAST) {
+		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+	}
+
+	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+	pkeyparamset->keylen = cpu_to_le16(pkey->len);
+	memcpy(pkeyparamset->key, pkey->key, pkey->len);
+	pkeyparamset->length = cpu_to_le16(  sizeof(pkeyparamset->keytypeid)
+	                                        + sizeof(pkeyparamset->keyinfo)
+	                                        + sizeof(pkeyparamset->keylen)
+	                                        + sizeof(pkeyparamset->key));
+}
+
+static int wlan_cmd_802_11_key_material(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					u16 cmd_action,
+					u32 cmd_oid, void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_key_material *pkeymaterial =
+	    &cmd->params.keymaterial;
+	int ret = 0;
+	int index = 0;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_key_material);
+	pkeymaterial->action = cpu_to_le16(cmd_action);
+
+	if (cmd_action == cmd_act_get) {
+		cmd->size = cpu_to_le16(  S_DS_GEN
+		                             + sizeof (pkeymaterial->action));
+		ret = 0;
+		goto done;
+	}
+
+	memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+
+	if (adapter->wpa_unicast_key.len) {
+		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+		                &adapter->wpa_unicast_key);
+		index++;
+	}
+
+	if (adapter->wpa_mcast_key.len) {
+		set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+		                &adapter->wpa_mcast_key);
+		index++;
+	}
+
+	cmd->size = cpu_to_le16(  S_DS_GEN
+	                             + sizeof (pkeymaterial->action)
+	                             + index * sizeof(struct MrvlIEtype_keyParamSet));
+
+	ret = 0;
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_cmd_802_11_reset(wlan_private * priv,
+				 struct cmd_ds_command *cmd, int cmd_action)
+{
+	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+
+	cmd->command = cpu_to_le16(cmd_802_11_reset);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+	reset->action = cpu_to_le16(cmd_action);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_get_log(wlan_private * priv,
+				   struct cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(cmd_802_11_get_log);
+	cmd->size =
+		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_get_stat(wlan_private * priv,
+				    struct cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) +
+			     S_DS_GEN);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+				    struct cmd_ds_command *cmd,
+				    int cmd_action,
+				    int cmd_oid, void *pdata_buf)
+{
+	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
+	wlan_adapter *adapter = priv->adapter;
+	u8 ucTemp;
+
+	ENTER();
+
+	lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+	cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) +
+			     S_DS_GEN);
+
+	switch (cmd_oid) {
+	case OID_802_11_INFRASTRUCTURE_MODE:
+	{
+		enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode =
+			(enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf;
+		pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+		pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+		pSNMPMIB->bufsize = sizeof(u8);
+		if (mode == 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 = cpu_to_le16((u16) dot11d_i);
+
+			if (cmd_action == cmd_act_set) {
+				pSNMPMIB->querytype = cmd_act_set;
+				pSNMPMIB->bufsize = sizeof(u16);
+				ulTemp = *(u32 *)pdata_buf;
+				*((unsigned short *)(pSNMPMIB->value)) =
+				    cpu_to_le16((u16) ulTemp);
+			}
+			break;
+		}
+
+	case OID_802_11_FRAGMENTATION_THRESHOLD:
+		{
+			u32 ulTemp;
+
+			pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+
+			if (cmd_action == cmd_act_get) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_get);
+			} else if (cmd_action == cmd_act_set) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_set);
+				pSNMPMIB->bufsize =
+				    cpu_to_le16(sizeof(u16));
+				ulTemp = *((u32 *) pdata_buf);
+				*((unsigned short *)(pSNMPMIB->value)) =
+				    cpu_to_le16((u16) ulTemp);
+
+			}
+
+			break;
+		}
+
+	case OID_802_11_RTS_THRESHOLD:
+		{
+
+			u32 ulTemp;
+			pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+
+			if (cmd_action == cmd_act_get) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_get);
+			} else if (cmd_action == cmd_act_set) {
+				pSNMPMIB->querytype =
+				    cpu_to_le16(cmd_act_set);
+				pSNMPMIB->bufsize =
+				    cpu_to_le16(sizeof(u16));
+				ulTemp = *((u32 *)
+					   pdata_buf);
+				*(unsigned short *)(pSNMPMIB->value) =
+				    cpu_to_le16((u16) ulTemp);
+
+			}
+			break;
+		}
+	case OID_802_11_TX_RETRYCOUNT:
+		pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+
+		if (cmd_action == cmd_act_get) {
+			pSNMPMIB->querytype =
+			    cpu_to_le16(cmd_act_get);
+		} else if (cmd_action == cmd_act_set) {
+			pSNMPMIB->querytype =
+			    cpu_to_le16(cmd_act_set);
+			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+			*((unsigned short *)(pSNMPMIB->value)) =
+			    cpu_to_le16((u16) adapter->txretrycount);
+		}
+
+		break;
+	default:
+		break;
+	}
+
+	lbs_pr_debug(1,
+	       "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
+	       cmd->command, cmd->size, cmd->seqnum, cmd->result);
+
+	lbs_pr_debug(1,
+	       "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 0;
+}
+
+static int wlan_cmd_802_11_radio_control(wlan_private * priv,
+					 struct cmd_ds_command *cmd,
+					 int cmd_action)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_radio_control *pradiocontrol =
+	    &cmd->params.radio;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+
+	pradiocontrol->action = cpu_to_le16(cmd_action);
+
+	switch (adapter->preamble) {
+	case cmd_type_short_preamble:
+		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
+		break;
+
+	case cmd_type_long_preamble:
+		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
+		break;
+
+	case cmd_type_auto_preamble:
+	default:
+		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
+		break;
+	}
+
+	if (adapter->radioon)
+		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
+	else
+		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+				       struct cmd_ds_command *cmd,
+				       u16 cmd_action, void *pdata_buf)
+{
+
+	struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+	prtp->action = cmd_action;
+
+	lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size,
+	       cmd->command, prtp->action);
+
+	switch (cmd_action) {
+	case cmd_act_tx_power_opt_get:
+		prtp->action = cpu_to_le16(cmd_act_get);
+		prtp->currentlevel = 0;
+		break;
+
+	case cmd_act_tx_power_opt_set_high:
+		prtp->action = cpu_to_le16(cmd_act_set);
+		prtp->currentlevel =
+		    cpu_to_le16(cmd_act_tx_power_index_high);
+		break;
+
+	case cmd_act_tx_power_opt_set_mid:
+		prtp->action = cpu_to_le16(cmd_act_set);
+		prtp->currentlevel =
+		    cpu_to_le16(cmd_act_tx_power_index_mid);
+		break;
+
+	case cmd_act_tx_power_opt_set_low:
+		prtp->action = cpu_to_le16(cmd_act_set);
+		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+		break;
+	}
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+
+	cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
+			     S_DS_GEN);
+
+	rant->action = cpu_to_le16(cmd_action);
+	if ((cmd_action == cmd_act_set_rx) ||
+	    (cmd_action == cmd_act_set_tx)) {
+		rant->antennamode =
+		    cpu_to_le16((u16) (*(u32 *) pdata_buf));
+	}
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+					      struct cmd_ds_command *cmd,
+					      u16 cmd_action)
+{
+	struct cmd_ds_802_11_rate_adapt_rateset
+	*rateadapt = &cmd->params.rateset;
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+			     + S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
+
+	ENTER();
+
+	rateadapt->action = cmd_action;
+	rateadapt->enablehwauto = adapter->enablehwauto;
+	rateadapt->bitmap = adapter->ratebitmap;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_data_rate(wlan_private * priv,
+				     struct cmd_ds_command *cmd,
+				     u16 cmd_action)
+{
+	struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = cmd_action;
+
+	ENTER();
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
+			     S_DS_GEN);
+
+	cmd->command = cpu_to_le16(cmd_802_11_data_rate);
+
+	memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
+
+	pdatarate->action = cpu_to_le16(cmd_action);
+
+	if (action == cmd_act_set_tx_fix_rate) {
+		pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
+		lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n",
+		       adapter->datarate);
+	} else if (action == cmd_act_set_tx_auto) {
+		lbs_pr_debug(1, "Setting FW for AUTO rate\n");
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      u16 cmd_action)
+{
+	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
+			     S_DS_GEN);
+	cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+
+	pMCastAdr->action = cpu_to_le16(cmd_action);
+	pMCastAdr->nr_of_adrs =
+	    cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
+	memcpy(pMCastAdr->maclist, adapter->multicastlist,
+	       adapter->nr_of_multicastmacaddr * ETH_ALEN);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
+				      struct cmd_ds_command *cmd,
+				      int option, void *pdata_buf)
+{
+	struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+
+	cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel)
+				     + S_DS_GEN);
+
+	if (option == cmd_opt_802_11_rf_channel_set) {
+		rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
+	}
+
+	rfchan->action = cpu_to_le16(option);
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_rssi(wlan_private * priv,
+				struct cmd_ds_command *cmd)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->command = cpu_to_le16(cmd_802_11_rssi);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_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 0;
+}
+
+static int wlan_cmd_reg_access(wlan_private * priv,
+			       struct cmd_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 cmd_mac_reg_access:
+		{
+			struct cmd_ds_mac_reg_access *macreg;
+
+			cmdptr->size =
+			    cpu_to_le16(sizeof
+					     (struct cmd_ds_mac_reg_access)
+					     + S_DS_GEN);
+			macreg =
+			    (struct cmd_ds_mac_reg_access *)&cmdptr->params.
+			    macreg;
+
+			macreg->action = cpu_to_le16(cmd_action);
+			macreg->offset = cpu_to_le16((u16) offval->offset);
+			macreg->value = cpu_to_le32(offval->value);
+
+			break;
+		}
+
+	case cmd_bbp_reg_access:
+		{
+			struct cmd_ds_bbp_reg_access *bbpreg;
+
+			cmdptr->size =
+			    cpu_to_le16(sizeof
+					     (struct cmd_ds_bbp_reg_access)
+					     + S_DS_GEN);
+			bbpreg =
+			    (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
+			    bbpreg;
+
+			bbpreg->action = cpu_to_le16(cmd_action);
+			bbpreg->offset = cpu_to_le16((u16) offval->offset);
+			bbpreg->value = (u8) offval->value;
+
+			break;
+		}
+
+	case cmd_rf_reg_access:
+		{
+			struct cmd_ds_rf_reg_access *rfreg;
+
+			cmdptr->size =
+			    cpu_to_le16(sizeof
+					     (struct cmd_ds_rf_reg_access) +
+					     S_DS_GEN);
+			rfreg =
+			    (struct cmd_ds_rf_reg_access *)&cmdptr->params.
+			    rfreg;
+
+			rfreg->action = cpu_to_le16(cmd_action);
+			rfreg->offset = cpu_to_le16((u16) offval->offset);
+			rfreg->value = (u8) offval->value;
+
+			break;
+		}
+
+	default:
+		break;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_cmd_802_11_mac_address(wlan_private * priv,
+				       struct cmd_ds_command *cmd,
+				       u16 cmd_action)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
+			     S_DS_GEN);
+	cmd->result = 0;
+
+	cmd->params.macadd.action = cpu_to_le16(cmd_action);
+
+	if (cmd_action == cmd_act_set) {
+		memcpy(cmd->params.macadd.macadd,
+		       adapter->current_addr, ETH_ALEN);
+		lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+	}
+
+	return 0;
+}
+
+static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+					 struct cmd_ds_command *cmd,
+					 int cmd_action, void *pdata_buf)
+{
+	struct wlan_ioctl_regrdwr *ea = pdata_buf;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
+			     S_DS_GEN);
+	cmd->result = 0;
+
+	cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
+	cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
+	cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
+	cmd->params.rdeeprom.value = 0;
+
+	return 0;
+}
+
+static int wlan_cmd_bt_access(wlan_private * priv,
+			       struct cmd_ds_command *cmd,
+			       u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+	lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action);
+
+	cmd->command = cpu_to_le16(cmd_bt_access);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access)
+				     + S_DS_GEN);
+	cmd->result = 0;
+	bt_access->action = cpu_to_le16(cmd_action);
+
+	switch (cmd_action) {
+	case cmd_act_bt_access_add:
+		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+		lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+		break;
+	case cmd_act_bt_access_del:
+		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+		lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+		break;
+	case cmd_act_bt_access_list:
+		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+		break;
+	case cmd_act_bt_access_reset:
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int wlan_cmd_fwt_access(wlan_private * priv,
+			       struct cmd_ds_command *cmd,
+			       u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+	lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+	cmd->command = cpu_to_le16(cmd_fwt_access);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)
+				     + S_DS_GEN);
+	cmd->result = 0;
+
+	if (pdata_buf)
+		memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
+	else
+		memset(fwt_access, 0, sizeof(*fwt_access));
+
+	fwt_access->action = cpu_to_le16(cmd_action);
+
+	return 0;
+}
+
+static int wlan_cmd_mesh_access(wlan_private * priv,
+				struct cmd_ds_command *cmd,
+				u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+	lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+	cmd->command = cpu_to_le16(cmd_mesh_access);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access)
+				     + S_DS_GEN);
+	cmd->result = 0;
+
+	if (pdata_buf)
+		memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
+	else
+		memset(mesh_access, 0, sizeof(*mesh_access));
+
+	mesh_access->action = cpu_to_le16(cmd_action);
+
+	return 0;
+}
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
+{
+	unsigned long flags;
+	struct cmd_ds_command *cmdptr;
+
+	ENTER();
+
+	if (!cmdnode) {
+		lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n");
+		goto done;
+	}
+
+	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+	if (!cmdptr) {
+		lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n");
+		goto done;
+	}
+
+	/* Exit_PS command needs to be queued in the header always. */
+	if (cmdptr->command == cmd_802_11_ps_mode) {
+		struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+		if (psm->action == cmd_subcmd_exit_ps) {
+			if (adapter->psstate != PS_STATE_FULL_POWER)
+				addtail = 0;
+		}
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, 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->driver_lock, flags);
+
+	lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n",
+	       (u32) cmdnode,
+	       ((struct cmd_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
+ */
+static int DownloadcommandToStation(wlan_private * priv,
+				    struct cmd_ctrl_node *cmdnode)
+{
+	unsigned long flags;
+	struct cmd_ds_command *cmdptr;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	u16 cmdsize;
+	u16 command;
+
+	ENTER();
+
+	if (!adapter || !cmdnode) {
+		lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n",
+		       (int)adapter, (int)cmdnode);
+		if (cmdnode) {
+			spin_lock_irqsave(&adapter->driver_lock, flags);
+			__libertas_cleanup_and_insert_cmd(priv, cmdnode);
+			spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		}
+		ret = -1;
+		goto done;
+	}
+
+	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (!cmdptr || !cmdptr->size) {
+		lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, "
+		       "Not sending\n");
+		__libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	adapter->cur_cmd = cmdnode;
+	adapter->cur_cmd_retcode = 0;
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n",
+	       cmdptr->size);
+
+	cmdsize = cmdptr->size;
+
+	command = cpu_to_le16(cmdptr->command);
+
+	cmdnode->cmdwaitqwoken = 0;
+	cmdsize = cpu_to_le16(cmdsize);
+
+	ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
+
+	if (ret != 0) {
+		lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n");
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
+	lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+
+	/* Setup the timer after transmit command */
+	if (command == cmd_802_11_scan
+	    || command == cmd_802_11_authenticate
+	    || command == cmd_802_11_associate)
+		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
+	else
+		mod_timer(&adapter->command_timer, jiffies + (5*HZ));
+
+	ret = 0;
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_cmd_mac_control(wlan_private * priv,
+				struct cmd_ds_command *cmd)
+{
+	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_mac_control);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
+	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
+
+	lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n",
+	       mac->action, cmd->size);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  This function inserts command node to cmdfreeq
+ *  after cleans it. Requires adapter->driver_lock held.
+ */
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	if (!ptempcmd)
+		goto done;
+
+	cleanup_cmdnode(ptempcmd);
+	list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+done:
+	return;
+}
+
+void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+	__libertas_cleanup_and_insert_cmd(priv, ptempcmd);
+	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+int libertas_set_radio_control(wlan_private * priv)
+{
+	int ret = 0;
+
+	ENTER();
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_radio_control,
+				    cmd_act_set,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+	       priv->adapter->radioon, priv->adapter->preamble);
+
+	LEAVE();
+	return ret;
+}
+
+int libertas_set_mac_packet_filter(wlan_private * priv)
+{
+	int ret = 0;
+
+	ENTER();
+
+	lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n",
+	       priv->adapter->currentpacketfilter);
+
+	/* Send MAC control command to station */
+	ret = libertas_prepare_and_send_command(priv,
+				    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 		0 or -1
+ */
+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 = 0;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmdnode;
+	struct cmd_ds_command *cmdptr;
+	unsigned long flags;
+
+	ENTER();
+
+	if (!adapter) {
+		lbs_pr_debug(1, "PREP_CMD: adapter is Null\n");
+		ret = -1;
+		goto done;
+	}
+
+	if (adapter->surpriseremoved) {
+		lbs_pr_debug(1, "PREP_CMD: Card is Removed\n");
+		ret = -1;
+		goto done;
+	}
+
+	cmdnode = libertas_get_free_cmd_ctrl_node(priv);
+
+	if (cmdnode == NULL) {
+		lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n");
+
+		/* Wake up main thread to execute next command */
+		wake_up_interruptible(&priv->mainthread.waitq);
+		ret = -1;
+		goto done;
+	}
+
+	libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
+
+	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+	lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n",
+	       (u32) cmdptr, cmd_no);
+
+	if (!cmdptr) {
+		lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+		libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		ret = -1;
+		goto done;
+	}
+
+	/* Set sequence number, command and INT option */
+	adapter->seqnum++;
+	cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
+
+	cmdptr->command = cmd_no;
+	cmdptr->result = 0;
+
+	switch (cmd_no) {
+	case cmd_get_hw_spec:
+		ret = wlan_cmd_hw_spec(priv, cmdptr);
+		break;
+	case cmd_802_11_ps_mode:
+		ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_scan:
+		ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_mac_control:
+		ret = wlan_cmd_mac_control(priv, cmdptr);
+		break;
+
+	case cmd_802_11_associate:
+	case cmd_802_11_reassociate:
+		ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_802_11_deauthenticate:
+		ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
+		break;
+
+	case cmd_802_11_set_wep:
+		ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_ad_hoc_start:
+		ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+		break;
+	case cmd_code_dnld:
+		break;
+
+	case cmd_802_11_reset:
+		ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_get_log:
+		ret = wlan_cmd_802_11_get_log(priv, cmdptr);
+		break;
+
+	case cmd_802_11_authenticate:
+		ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_802_11_get_stat:
+		ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
+		break;
+
+	case cmd_802_11_snmp_mib:
+		ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
+					       cmd_action, cmd_oid, pdata_buf);
+		break;
+
+	case cmd_mac_reg_access:
+	case cmd_bbp_reg_access:
+	case cmd_rf_reg_access:
+		ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_rf_channel:
+		ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
+						 cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_rf_tx_power:
+		ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
+						  cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_radio_control:
+		ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_rf_antenna:
+		ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
+						 cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_data_rate:
+		ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
+		break;
+	case cmd_802_11_rate_adapt_rateset:
+		ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
+							 cmdptr, cmd_action);
+		break;
+
+	case cmd_mac_multicast_adr:
+		ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_ad_hoc_join:
+		ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+		break;
+
+	case cmd_802_11_rssi:
+		ret = wlan_cmd_802_11_rssi(priv, cmdptr);
+		break;
+
+	case cmd_802_11_ad_hoc_stop:
+		ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
+		break;
+
+	case cmd_802_11_enable_rsn:
+		ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_key_material:
+		ret = wlan_cmd_802_11_key_material(priv, cmdptr,
+						   cmd_action, cmd_oid,
+						   pdata_buf);
+		break;
+
+	case cmd_802_11_pairwise_tsc:
+		break;
+	case cmd_802_11_group_tsc:
+		break;
+
+	case cmd_802_11_mac_address:
+		ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+		break;
+
+	case cmd_802_11_eeprom_access:
+		ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
+						    cmd_action, pdata_buf);
+		break;
+
+	case cmd_802_11_set_afc:
+	case cmd_802_11_get_afc:
+
+		cmdptr->command = cpu_to_le16(cmd_no);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
+				     S_DS_GEN);
+
+		memmove(&cmdptr->params.afc,
+			pdata_buf, sizeof(struct cmd_ds_802_11_afc));
+
+		ret = 0;
+		goto done;
+
+	case cmd_802_11d_domain_info:
+		ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
+						   cmd_no, cmd_action);
+		break;
+
+	case cmd_802_11_sleep_params:
+		ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
+		break;
+	case 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 cmd_802_11_tpc_cfg:
+		cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
+				     S_DS_GEN);
+
+		memmove(&cmdptr->params.tpccfg,
+			pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
+
+		ret = 0;
+		break;
+	case 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 cmd_ds_802_11_led_ctrl));
+
+			cmdptr->command =
+			    cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+			cmdptr->size =
+			    cpu_to_le16(gpio->header.len + S_DS_GEN +
+					     ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+			gpio->header.len = cpu_to_le16(gpio->header.len);
+
+			ret = 0;
+			break;
+		}
+	case cmd_802_11_pwr_cfg:
+		cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
+				     S_DS_GEN);
+		memmove(&cmdptr->params.pwrcfg, pdata_buf,
+			sizeof(struct cmd_ds_802_11_pwr_cfg));
+
+		ret = 0;
+		break;
+	case cmd_bt_access:
+		ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_fwt_access:
+		ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_mesh_access:
+		ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case cmd_get_tsf:
+		cmdptr->command = cpu_to_le16(cmd_get_tsf);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_ds_get_tsf)
+				     + S_DS_GEN);
+		ret = 0;
+		break;
+	case cmd_802_11_tx_rate_query:
+		cmdptr->command =
+		    cpu_to_le16(cmd_802_11_tx_rate_query);
+		cmdptr->size =
+		    cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+				     S_DS_GEN);
+		adapter->txrate = 0;
+		ret = 0;
+		break;
+	default:
+		lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no);
+		ret = -1;
+		break;
+	}
+
+	/* return error, since the command preparation failed */
+	if (ret != 0) {
+		lbs_pr_debug(1, "PREP_CMD: command preparation failed\n");
+		libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		ret = -1;
+		goto done;
+	}
+
+	cmdnode->cmdwaitqwoken = 0;
+
+	libertas_queue_cmd(adapter, cmdnode, 1);
+	adapter->nr_cmd_pending++;
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	if (wait_option & cmd_option_waitforrsp) {
+		lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n");
+		might_sleep();
+		wait_event_interruptible(cmdnode->cmdwait_q,
+					 cmdnode->cmdwaitqwoken);
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->cur_cmd_retcode) {
+		lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n",
+		       adapter->cur_cmd_retcode);
+		adapter->cur_cmd_retcode = 0;
+		ret = -1;
+	}
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+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 		0 or -1
+ */
+int libertas_allocate_cmd_buffer(wlan_private * priv)
+{
+	int ret = 0;
+	u32 ulbufsize;
+	u32 i;
+	struct cmd_ctrl_node *tempcmd_array;
+	u8 *ptempvirtualaddr;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* Allocate and initialize cmdCtrlNode */
+	ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+	if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) {
+		lbs_pr_debug(1,
+		       "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+		ret = -1;
+		goto done;
+	}
+
+	adapter->cmd_array = tempcmd_array;
+	memset(adapter->cmd_array, 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))) {
+			lbs_pr_debug(1,
+			       "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+			ret = -1;
+			goto done;
+		}
+
+		memset(ptempvirtualaddr, 0, ulbufsize);
+
+		/* Update command buffer virtual */
+		tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
+	}
+
+	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+		init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
+		libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
+	}
+
+	ret = 0;
+      done:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief This function frees the command buffer.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @return 		0 or -1
+ */
+int libertas_free_cmd_buffer(wlan_private * priv)
+{
+	u32 ulbufsize;
+	unsigned int i;
+	struct cmd_ctrl_node *tempcmd_array;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* need to check if cmd array is allocated or not */
+	if (adapter->cmd_array == NULL) {
+		lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n");
+		goto done;
+	}
+
+	tempcmd_array = adapter->cmd_array;
+
+	/* Release shared memory buffers */
+	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+		if (tempcmd_array[i].bufvirtualaddr) {
+			lbs_pr_debug(1, "Free all the array\n");
+			kfree(tempcmd_array[i].bufvirtualaddr);
+			tempcmd_array[i].bufvirtualaddr = NULL;
+		}
+	}
+
+	/* Release cmd_ctrl_node */
+	if (adapter->cmd_array) {
+		lbs_pr_debug(1, "Free cmd_array\n");
+		kfree(adapter->cmd_array);
+		adapter->cmd_array = NULL;
+	}
+
+done:
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function gets a free command node if available in
+ *  command free queue.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ */
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
+{
+	struct cmd_ctrl_node *tempnode;
+	wlan_adapter *adapter = priv->adapter;
+	unsigned long flags;
+
+	if (!adapter)
+		return NULL;
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (!list_empty(&adapter->cmdfreeq)) {
+		tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
+		list_del((struct list_head *)tempnode);
+	} else {
+		lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+		tempnode = NULL;
+	}
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (tempnode) {
+		lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
+		lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
+		       tempnode);
+		cleanup_cmdnode(tempnode);
+	}
+
+	return tempnode;
+}
+
+/**
+ *  @brief This function cleans command node.
+ *
+ *  @param ptempnode	A pointer to cmdCtrlNode structure
+ *  @return 		n/a
+ */
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
+{
+	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);
+	return;
+}
+
+/**
+ *  @brief This function initializes the command node.
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param ptempnode	A pointer to cmd_ctrl_node 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 		0 or -1
+ */
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+		    struct cmd_ctrl_node *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 	   0 or -1
+ */
+int libertas_execute_next_command(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmdnode = NULL;
+	struct cmd_ds_command *cmdptr;
+	unsigned long flags;
+	int ret = 0;
+
+	lbs_pr_debug(1, "libertas_execute_next_command\n");
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (adapter->cur_cmd) {
+		lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	if (!list_empty(&adapter->cmdpendingq)) {
+		cmdnode = (struct cmd_ctrl_node *)
+		    adapter->cmdpendingq.next;
+	}
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (cmdnode) {
+		lbs_pr_debug(1,
+		       "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
+		cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+		if (is_command_allowed_in_ps(cmdptr->command)) {
+			if ((adapter->psstate == PS_STATE_SLEEP)
+			    || (adapter->psstate == PS_STATE_PRE_SLEEP)
+			    ) {
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+				       cmdptr->command, adapter->psstate);
+				ret = -1;
+				goto done;
+			}
+			lbs_pr_debug(1, "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 !=
+			    cpu_to_le16(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 = 0;
+				goto done;
+			} else {
+				/*
+				 * PS command. Ignore it if it is not Exit_PS.
+				 * otherwise send it down immediately.
+				 */
+				struct cmd_ds_802_11_ps_mode *psm =
+				    &cmdptr->params.psmode;
+
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+				       psm->action);
+				if (psm->action !=
+				    cpu_to_le16(cmd_subcmd_exit_ps)) {
+					lbs_pr_debug(1,
+					       "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+					list_del((struct list_head *)cmdnode);
+					libertas_cleanup_and_insert_cmd(priv, cmdnode);
+
+					ret = 0;
+					goto done;
+				}
+
+				if ((adapter->psstate == PS_STATE_SLEEP)
+				    || (adapter->psstate == PS_STATE_PRE_SLEEP)
+				    ) {
+					lbs_pr_debug(1,
+					       "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 = 0;
+					goto done;
+				}
+
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+			}
+		}
+		list_del((struct list_head *)cmdnode);
+		lbs_pr_debug(1, "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->connect_status == libertas_connected)) {
+			if (adapter->secinfo.WPAenabled
+			    || adapter->secinfo.WPA2enabled) {
+				/* check for valid WPA group keys */
+				if (adapter->wpa_mcast_key.len
+				    || adapter->wpa_unicast_key.len) {
+					lbs_pr_debug(1,
+					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+					       " go back to PS_SLEEP");
+					libertas_ps_sleep(priv, 0);
+				}
+			} else {
+				lbs_pr_debug(1,
+				       "EXEC_NEXT_CMD: command PendQ is empty,"
+				       " go back to PS_SLEEP");
+				libertas_ps_sleep(priv, 0);
+			}
+		}
+	}
+
+	ret = 0;
+done:
+	return ret;
+}
+
+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.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+	/* Send Event to upper layer */
+	lbs_pr_debug(1, "Event Indication string = %s\n",
+	       (char *)buf);
+	lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length);
+
+	lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str);
+	wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+
+	LEAVE();
+	return;
+}
+
+static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
+{
+	unsigned long flags;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+	       size);
+
+	lbs_dbg_hex("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;
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->intcounter || adapter->currenttxskb)
+		lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+		       adapter->intcounter, adapter->currenttxskb);
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (ret) {
+		lbs_pr_alert(
+		       "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
+	} else {
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		if (!adapter->intcounter) {
+			adapter->psstate = PS_STATE_SLEEP;
+		} else {
+			lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+			       adapter->intcounter);
+		}
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
+		lbs_pr_debug(1, "+");
+	}
+
+	LEAVE();
+	return ret;
+}
+
+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, cmd_802_11_ps_mode,
+			      cmd_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;
+
+	lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode);
+
+	libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+			      cmd_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)
+{
+	unsigned long flags =0;
+	wlan_adapter *adapter = priv->adapter;
+	u8 allowed = 1;
+
+	ENTER();
+
+	if (priv->wlan_dev.dnld_sent) {
+		allowed = 0;
+		lbs_pr_debug(1, "D");
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->cur_cmd) {
+		allowed = 0;
+		lbs_pr_debug(1, "C");
+	}
+	if (adapter->intcounter > 0) {
+		allowed = 0;
+		lbs_pr_debug(1, "I%d", adapter->intcounter);
+	}
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	if (allowed) {
+		lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n");
+		sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
+				 sizeof(struct PS_CMD_ConfirmSleep));
+	} else {
+		lbs_pr_debug(1, "Sleep Confirm has been delayed\n");
+	}
+
+	LEAVE();
+}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
new file mode 100644
index 0000000..cdb012c
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -0,0 +1,1031 @@
+/**
+  * This file contains the handling of command
+  * responses as well as events generated by firmware.
+  */
+#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 "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "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;
+
+	if (adapter->connect_status != libertas_connected)
+		return;
+
+	lbs_pr_debug(1, "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->rxpd_rate = 0;
+	lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
+	       adapter->curbssparams.ssid.ssid,
+	       adapter->curbssparams.ssid.ssidlength);
+	lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
+	       adapter->previousssid.ssid, adapter->previousssid.ssidlength);
+
+	/* reset internal flags */
+	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->connect_status = libertas_disconnected;
+
+	/*
+	 * 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 = NULL;
+	memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+	if (adapter->psstate != PS_STATE_FULL_POWER) {
+		/* make firmware to exit PS mode */
+		lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
+		libertas_ps_wakeup(priv, 0);
+	}
+}
+
+/**
+ *  @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 handle_mic_failureevent(wlan_private * priv, u32 event)
+{
+	char buf[50];
+
+	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);
+}
+
+static int wlan_ret_reg_access(wlan_private * priv,
+			       u16 type, struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	switch (type) {
+	case cmd_ret_mac_reg_access:
+		{
+			struct cmd_ds_mac_reg_access *reg;
+
+			reg =
+			    (struct cmd_ds_mac_reg_access *)&resp->params.
+			    macreg;
+
+			adapter->offsetvalue.offset = reg->offset;
+			adapter->offsetvalue.value = reg->value;
+			break;
+		}
+
+	case cmd_ret_bbp_reg_access:
+		{
+			struct cmd_ds_bbp_reg_access *reg;
+			reg =
+			    (struct cmd_ds_bbp_reg_access *)&resp->params.
+			    bbpreg;
+
+			adapter->offsetvalue.offset = reg->offset;
+			adapter->offsetvalue.value = reg->value;
+			break;
+		}
+
+	case cmd_ret_rf_reg_access:
+		{
+			struct cmd_ds_rf_reg_access *reg;
+			reg =
+			    (struct cmd_ds_rf_reg_access *)&resp->params.
+			    rfreg;
+
+			adapter->offsetvalue.offset = reg->offset;
+			adapter->offsetvalue.value = reg->value;
+			break;
+		}
+
+	default:
+		LEAVE();
+		return -1;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_get_hw_spec(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+	u32 i;
+	struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	ENTER();
+
+	adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
+
+	adapter->fwreleasenumber = hwspec->fwreleasenumber;
+
+	lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+	       adapter->fwreleasenumber);
+	lbs_pr_debug(1, "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]);
+	lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X  version=0x%X\n",
+	       hwspec->hwifversion, hwspec->version);
+
+	adapter->regioncode = 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;
+		lbs_pr_info(
+		       "unidentified region code, use the default (USA)\n");
+	}
+
+	if (adapter->current_addr[0] == 0xff) {
+		memmove(adapter->current_addr, hwspec->permanentaddr,
+			ETH_ALEN);
+	}
+
+	memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
+	memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+	if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (libertas_set_universaltable(priv, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+static int wlan_ret_802_11_sleep_params(wlan_private * priv,
+					struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	lbs_pr_debug(1, "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 = le16_to_cpu(sp->error);
+	adapter->sp.sp_offset = le16_to_cpu(sp->offset);
+	adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
+	adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
+	adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
+	adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_stat(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+/*	currently adapter->wlan802_11Stat is unused
+
+	struct cmd_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 cmd_ds_802_11_get_stat));
+*/
+	return 0;
+}
+
+static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
+				    struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+	u16 oid = le16_to_cpu(smib->oid);
+	u16 querytype = le16_to_cpu(smib->querytype);
+
+	ENTER();
+
+	lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+	       querytype);
+	lbs_pr_debug(1, "SNMP_RESP: Buf size  = %x\n",
+	       le16_to_cpu(smib->bufsize));
+
+	if (querytype == cmd_act_get) {
+		switch (oid) {
+		case fragthresh_i:
+			priv->adapter->fragthsd =
+			    le16_to_cpu(*
+					     ((unsigned short *)(smib->value)));
+			lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
+			       priv->adapter->fragthsd);
+			break;
+		case rtsthresh_i:
+			priv->adapter->rtsthsd =
+			    le16_to_cpu(*
+					     ((unsigned short *)(smib->value)));
+			lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
+			       priv->adapter->rtsthsd);
+			break;
+		case short_retrylim_i:
+			priv->adapter->txretrycount =
+			    le16_to_cpu(*
+					     ((unsigned short *)(smib->value)));
+			lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
+			       priv->adapter->rtsthsd);
+			break;
+		default:
+			break;
+		}
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_key_material(wlan_private * priv,
+					struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_key_material *pkeymaterial =
+	    &resp->params.keymaterial;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = le16_to_cpu(pkeymaterial->action);
+
+	ENTER();
+
+	/* Copy the returned key to driver private data */
+	if (action == cmd_act_get) {
+		u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
+		u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
+
+		while (buf_ptr < resp_end) {
+			struct MrvlIEtype_keyParamSet * pkeyparamset =
+			    (struct MrvlIEtype_keyParamSet *) buf_ptr;
+			struct WLAN_802_11_KEY * pkey;
+			u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+			u16 param_set_len = le16_to_cpu(pkeyparamset->length);
+			u8 * end;
+			u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+
+			end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+			                          + sizeof (pkeyparamset->length)
+			                          + param_set_len;
+			/* Make sure we don't access past the end of the IEs */
+			if (end > resp_end)
+				break;
+
+			if (key_info & KEY_INFO_WPA_UNICAST)
+				pkey = &adapter->wpa_unicast_key;
+			else if (key_info & KEY_INFO_WPA_MCAST)
+				pkey = &adapter->wpa_mcast_key;
+			else
+				break;
+
+			/* Copy returned key into driver */
+			memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+			if (key_len > sizeof(pkey->key))
+				break;
+			pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
+			pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
+			pkey->len = le16_to_cpu(pkeyparamset->keylen);
+			memcpy(pkey->key, pkeyparamset->key, pkey->len);
+
+			buf_ptr = end + 1;
+		}
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_mac_address(wlan_private * priv,
+				       struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
+				       struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+
+	lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
+				      struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = le16_to_cpu(pAntenna->action);
+
+	if (action == cmd_act_get_rx)
+		adapter->rxantennamode =
+		    le16_to_cpu(pAntenna->antennamode);
+
+	if (action == cmd_act_get_tx)
+		adapter->txantennamode =
+		    le16_to_cpu(pAntenna->antennamode);
+
+	lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
+	       action, le16_to_cpu(pAntenna->antennamode));
+
+	return 0;
+}
+
+static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+					      struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rate_adapt_rateset *rates =
+	    &resp->params.rateset;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if (rates->action == cmd_act_get) {
+		adapter->enablehwauto = rates->enablehwauto;
+		adapter->ratebitmap = rates->bitmap;
+	}
+
+	LEAVE();
+
+	return 0;
+}
+
+static int wlan_ret_802_11_data_rate(wlan_private * priv,
+				     struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
+	wlan_adapter *adapter = priv->adapter;
+	u8 dot11datarate;
+
+	ENTER();
+
+	lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
+		(u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+
+	dot11datarate = pdatarate->datarate[0];
+	if (pdatarate->action == cmd_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 0;
+}
+
+static int wlan_ret_802_11_rf_channel(wlan_private * priv,
+				      struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_rf_channel *rfchannel =
+	    &resp->params.rfchannel;
+	wlan_adapter *adapter = priv->adapter;
+	u16 action = le16_to_cpu(rfchannel->action);
+	u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
+
+	ENTER();
+
+	if (action == cmd_opt_802_11_rf_channel_get
+	    && adapter->curbssparams.channel != newchannel) {
+		lbs_pr_debug(1, "channel Switch: %d to %d\n",
+		       adapter->curbssparams.channel, newchannel);
+
+		/* Update the channel again */
+		adapter->curbssparams.channel = newchannel;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_ret_802_11_rssi(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+	struct cmd_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] = le16_to_cpu(rssirsp->SNR);
+	adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+	    le16_to_cpu(rssirsp->noisefloor);
+
+	adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+	adapter->NF[TYPE_BEACON][TYPE_AVG] =
+	    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);
+
+	lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
+	       adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+	return 0;
+}
+
+static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
+				  struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_ioctl_regrdwr *pbuf;
+	pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
+
+	lbs_pr_debug(1, "eeprom read len=%x\n",
+	       le16_to_cpu(resp->params.rdeeprom.bytecount));
+	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
+		pbuf->NOB = 0;
+		lbs_pr_debug(1, "eeprom read return length is too big\n");
+		return -1;
+	}
+	pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
+	if (pbuf->NOB > 0) {
+
+		memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
+		       le16_to_cpu(resp->params.rdeeprom.bytecount));
+		lbs_dbg_hex("adapter", (char *)&pbuf->value,
+			le16_to_cpu(resp->params.rdeeprom.bytecount));
+	}
+	return 0;
+}
+
+static int wlan_ret_get_log(wlan_private * priv,
+			    struct cmd_ds_command *resp)
+{
+	struct cmd_ds_802_11_get_log *logmessage =
+	    (struct cmd_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 cmd_ds_802_11_get_log));
+
+	LEAVE();
+	return 0;
+}
+
+static inline int handle_cmd_response(u16 respcmd,
+				      struct cmd_ds_command *resp,
+				      wlan_private *priv)
+{
+	int ret = 0;
+	unsigned long flags;
+	wlan_adapter *adapter = priv->adapter;
+
+	switch (respcmd) {
+	case cmd_ret_mac_reg_access:
+	case cmd_ret_bbp_reg_access:
+	case cmd_ret_rf_reg_access:
+		ret = wlan_ret_reg_access(priv, respcmd, resp);
+		break;
+
+	case cmd_ret_hw_spec_info:
+		ret = wlan_ret_get_hw_spec(priv, resp);
+		break;
+
+	case cmd_ret_802_11_scan:
+		ret = libertas_ret_80211_scan(priv, resp);
+		break;
+
+	case cmd_ret_802_11_get_log:
+		ret = wlan_ret_get_log(priv, resp);
+		break;
+
+	case cmd_ret_802_11_associate:
+	case cmd_ret_802_11_reassociate:
+		ret = libertas_ret_80211_associate(priv, resp);
+		break;
+
+	case cmd_ret_802_11_disassociate:
+	case cmd_ret_802_11_deauthenticate:
+		ret = libertas_ret_80211_disassociate(priv, resp);
+		break;
+
+	case cmd_ret_802_11_ad_hoc_start:
+	case cmd_ret_802_11_ad_hoc_join:
+		ret = libertas_ret_80211_ad_hoc_start(priv, resp);
+		break;
+
+	case cmd_ret_802_11_stat:
+		ret = wlan_ret_802_11_stat(priv, resp);
+		break;
+
+	case cmd_ret_802_11_snmp_mib:
+		ret = wlan_ret_802_11_snmp_mib(priv, resp);
+		break;
+
+	case cmd_ret_802_11_rf_tx_power:
+		ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+		break;
+
+	case cmd_ret_802_11_set_afc:
+	case cmd_ret_802_11_get_afc:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.afc,
+			sizeof(struct cmd_ds_802_11_afc));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		break;
+	case cmd_ret_802_11_rf_antenna:
+		ret = wlan_ret_802_11_rf_antenna(priv, resp);
+		break;
+
+	case cmd_ret_mac_multicast_adr:
+	case cmd_ret_mac_control:
+	case cmd_ret_802_11_set_wep:
+	case cmd_ret_802_11_reset:
+	case cmd_ret_802_11_authenticate:
+	case cmd_ret_802_11_radio_control:
+	case cmd_ret_802_11_beacon_stop:
+	case cmd_ret_802_11_enable_rsn:
+		break;
+
+	case cmd_ret_802_11_data_rate:
+		ret = wlan_ret_802_11_data_rate(priv, resp);
+		break;
+	case cmd_ret_802_11_rate_adapt_rateset:
+		ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+		break;
+	case cmd_ret_802_11_rf_channel:
+		ret = wlan_ret_802_11_rf_channel(priv, resp);
+		break;
+
+	case cmd_ret_802_11_rssi:
+		ret = wlan_ret_802_11_rssi(priv, resp);
+		break;
+
+	case cmd_ret_802_11_mac_address:
+		ret = wlan_ret_802_11_mac_address(priv, resp);
+		break;
+
+	case cmd_ret_802_11_ad_hoc_stop:
+		ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
+		break;
+
+	case cmd_ret_802_11_key_material:
+		lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
+		ret = wlan_ret_802_11_key_material(priv, resp);
+		break;
+
+	case cmd_ret_802_11_eeprom_access:
+		ret = wlan_ret_802_11_eeprom_access(priv, resp);
+		break;
+
+	case cmd_ret_802_11d_domain_info:
+		ret = libertas_ret_802_11d_domain_info(priv, resp);
+		break;
+
+	case cmd_ret_802_11_sleep_params:
+		ret = wlan_ret_802_11_sleep_params(priv, resp);
+		break;
+	case cmd_ret_802_11_inactivity_timeout:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		*((u16 *) adapter->cur_cmd->pdata_buf) =
+		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+
+	case cmd_ret_802_11_tpc_cfg:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.tpccfg,
+			sizeof(struct cmd_ds_802_11_tpc_cfg));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_802_11_led_gpio_ctrl:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.ledgpio,
+			sizeof(struct cmd_ds_802_11_led_ctrl));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_802_11_pwr_cfg:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memmove(adapter->cur_cmd->pdata_buf,
+			&resp->params.pwrcfg,
+			sizeof(struct cmd_ds_802_11_pwr_cfg));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		break;
+
+	case cmd_ret_get_tsf:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		memcpy(priv->adapter->cur_cmd->pdata_buf,
+		       &resp->params.gettsf.tsfvalue, sizeof(u64));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_bt_access:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		if (adapter->cur_cmd->pdata_buf)
+			memcpy(adapter->cur_cmd->pdata_buf,
+			       &resp->params.bt.addr1, 2 * ETH_ALEN);
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_fwt_access:
+		spin_lock_irqsave(&adapter->driver_lock, flags);
+		if (adapter->cur_cmd->pdata_buf)
+			memcpy(adapter->cur_cmd->pdata_buf,
+			       &resp->params.fwt,
+				sizeof(resp->params.fwt));
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		break;
+	case cmd_ret_mesh_access:
+		if (adapter->cur_cmd->pdata_buf)
+			memcpy(adapter->cur_cmd->pdata_buf,
+			       &resp->params.mesh,
+			       sizeof(resp->params.mesh));
+		break;
+	case cmd_rte_802_11_tx_rate_query:
+		priv->adapter->txrate = resp->params.txrate.txrate;
+		break;
+	default:
+		lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
+		       resp->command);
+		break;
+	}
+	return ret;
+}
+
+int libertas_process_rx_command(wlan_private * priv)
+{
+	u16 respcmd;
+	struct cmd_ds_command *resp;
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	ulong flags;
+	u16 result;
+
+	ENTER();
+
+	lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
+
+	/* Now we got response from FW, cancel the command timer */
+	del_timer(&adapter->command_timer);
+
+	mutex_lock(&adapter->lock);
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+
+	if (!adapter->cur_cmd) {
+		lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+		ret = -1;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		goto done;
+	}
+	resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+	lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
+		priv->wlan_dev.upld_len);
+
+	respcmd = le16_to_cpu(resp->command);
+
+	result = le16_to_cpu(resp->result);
+
+	lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
+	       result, priv->wlan_dev.upld_len);
+
+	if (!(respcmd & 0x8000)) {
+		lbs_pr_debug(1, "Invalid response to command!");
+		adapter->cur_cmd_retcode = -1;
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	/* Store the response code to cur_cmd_retcode. */
+	adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
+
+	if (respcmd == cmd_ret_802_11_ps_mode) {
+		struct cmd_ds_802_11_ps_mode *psmode;
+
+		psmode = &resp->params.psmode;
+		lbs_pr_debug(1,
+		       "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+		       resp->result, psmode->action);
+		psmode->action = cpu_to_le16(psmode->action);
+
+		if (result) {
+			lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
+			       resp->result);
+			if (adapter->inframode == 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 == cmd_subcmd_enter_ps)
+					adapter->psmode =
+					    wlan802_11powermodecam;
+			}
+		} else if (psmode->action == cmd_subcmd_enter_ps) {
+			adapter->needtowakeup = 0;
+			adapter->psstate = PS_STATE_AWAKE;
+
+			lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
+			if (adapter->connect_status != libertas_connected) {
+				/*
+				 * When Deauth Event received before Enter_PS command
+				 * response, We need to wake up the firmware.
+				 */
+				lbs_pr_debug(1,
+				       "Disconnected, Going to invoke libertas_ps_wakeup\n");
+
+				mutex_unlock(&adapter->lock);
+				spin_unlock_irqrestore(&adapter->driver_lock, flags);
+				libertas_ps_wakeup(priv, 0);
+				mutex_lock(&adapter->lock);
+				spin_lock_irqsave(&adapter->driver_lock, flags);
+			}
+		} else if (psmode->action == cmd_subcmd_exit_ps) {
+			adapter->needtowakeup = 0;
+			adapter->psstate = PS_STATE_FULL_POWER;
+			lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
+		} else {
+			lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
+			       psmode->action);
+		}
+
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		ret = 0;
+		goto done;
+	}
+
+	if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
+		/* Copy the response back to response buffer */
+		memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
+
+		adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
+	}
+
+	/* If the command is not successful, cleanup and return failure */
+	if ((result != 0 || !(respcmd & 0x8000))) {
+		lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
+		       resp->command, resp->result);
+		/*
+		 * Handling errors here
+		 */
+		switch (respcmd) {
+		case cmd_ret_hw_spec_info:
+		case cmd_ret_802_11_reset:
+			lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
+			break;
+
+		}
+
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		adapter->cur_cmd = NULL;
+		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+		ret = -1;
+		goto done;
+	}
+
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	ret = handle_cmd_response(respcmd, resp, priv);
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	if (adapter->cur_cmd) {
+		/* Clean up and Put current command back to cmdfreeq */
+		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
+		WARN_ON(adapter->nr_cmd_pending > 128);
+		adapter->cur_cmd = NULL;
+	}
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+	mutex_unlock(&adapter->lock);
+	LEAVE();
+	return ret;
+}
+
+int libertas_process_event(wlan_private * priv)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	u32 eventcause;
+
+	spin_lock_irq(&adapter->driver_lock);
+	eventcause = adapter->eventcause;
+	spin_unlock_irq(&adapter->driver_lock);
+
+	ENTER();
+
+	lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
+
+	switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
+	case MACREG_INT_CODE_LINK_SENSED:
+		lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+		break;
+
+	case MACREG_INT_CODE_DEAUTHENTICATED:
+		lbs_pr_debug(1, "EVENT: Deauthenticated\n");
+		libertas_mac_event_disconnected(priv);
+		break;
+
+	case MACREG_INT_CODE_DISASSOCIATED:
+		lbs_pr_debug(1, "EVENT: Disassociated\n");
+		libertas_mac_event_disconnected(priv);
+		break;
+
+	case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+		lbs_pr_debug(1, "EVENT: Link lost\n");
+		libertas_mac_event_disconnected(priv);
+		break;
+
+	case MACREG_INT_CODE_PS_SLEEP:
+		lbs_pr_debug(1, "EVENT: SLEEP\n");
+		lbs_pr_debug(1, "_");
+
+		/* handle unexpected PS SLEEP event */
+		if (adapter->psstate == PS_STATE_FULL_POWER) {
+			lbs_pr_debug(1,
+			       "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:
+		lbs_pr_debug(1, "EVENT: AWAKE \n");
+		lbs_pr_debug(1, "|");
+
+		/* handle unexpected PS AWAKE event */
+		if (adapter->psstate == PS_STATE_FULL_POWER) {
+			lbs_pr_debug(1,
+			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+			break;
+		}
+
+		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()
+			 */
+			lbs_pr_debug(1, "Waking up...\n");
+			libertas_ps_wakeup(priv, 0);
+		}
+		break;
+
+	case MACREG_INT_CODE_MIC_ERR_UNICAST:
+		lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
+		handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+		break;
+
+	case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+		lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
+		handle_mic_failureevent(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:
+		lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
+		break;
+
+	case MACREG_INT_CODE_RSSI_LOW:
+		lbs_pr_alert( "EVENT: RSSI_LOW\n");
+		break;
+	case MACREG_INT_CODE_SNR_LOW:
+		lbs_pr_alert( "EVENT: SNR_LOW\n");
+		break;
+	case MACREG_INT_CODE_MAX_FAIL:
+		lbs_pr_alert( "EVENT: MAX_FAIL\n");
+		break;
+	case MACREG_INT_CODE_RSSI_HIGH:
+		lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+		break;
+	case MACREG_INT_CODE_SNR_HIGH:
+		lbs_pr_alert( "EVENT: SNR_HIGH\n");
+		break;
+
+	default:
+		lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+		       eventcause >> SBI_EVENT_CAUSE_SHIFT);
+		break;
+	}
+
+	spin_lock_irq(&adapter->driver_lock);
+	adapter->eventcause = 0;
+	spin_unlock_irq(&adapter->driver_lock);
+	LEAVE();
+	return ret;
+}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
new file mode 100644
index 0000000..3ad1e03
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -0,0 +1,1968 @@
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <net/iw_handler.h>
+#include "dev.h"
+#include "decl.h"
+#include "host.h"
+
+static struct dentry *libertas_dir = NULL;
+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 const size_t len = PAGE_SIZE;
+
+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;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+	ssize_t res;
+
+	pos += snprintf(buf+pos, len-pos, "state = %s\n",
+				szStates[priv->adapter->connect_status]);
+	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+				(u32) priv->adapter->regioncode);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+	free_page(addr);
+	return res;
+}
+
+
+static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	size_t pos = 0;
+	int numscansdone = 0, res;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	pos += snprintf(buf+pos, len-pos,
+			"---------------------------------------");
+	pos += snprintf(buf+pos, len-pos,
+			"---------------------------------------\n");
+	pos += snprintf(buf+pos, len-pos,
+		"# | ch  | ss  |       bssid       |   cap    |    TSF   | Qual | SSID \n");
+	pos += snprintf(buf+pos, len-pos,
+		"---------------------------------------");
+	pos += snprintf(buf+pos, len-pos,
+		"---------------------------------------\n");
+
+	while (numscansdone < priv->adapter->numinscantable) {
+		struct bss_descriptor *pbssinfo;
+		u16 cap;
+
+		pbssinfo = &priv->adapter->scantable[numscansdone];
+		memcpy(&cap, &pbssinfo->cap, sizeof(cap));
+		pos += snprintf(buf+pos, len-pos,
+			"%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
+			numscansdone, pbssinfo->channel, pbssinfo->rssi,
+			pbssinfo->macaddress[0], pbssinfo->macaddress[1],
+			pbssinfo->macaddress[2], pbssinfo->macaddress[3],
+			pbssinfo->macaddress[4], pbssinfo->macaddress[5]);
+		pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+		pos += snprintf(buf+pos, len-pos, "%c%c%c |",
+				pbssinfo->cap.ibss ? 'A' : 'I',
+				pbssinfo->cap.privacy ? 'P' : ' ',
+				pbssinfo->cap.spectrummgmt ? 'S' : ' ');
+		pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf);
+		pos += snprintf(buf+pos, len-pos, " %d |",
+			SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi));
+
+		pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
+
+		numscansdone++;
+	}
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_sleepparams_write(struct file *file,
+				const char __user *user_buf, size_t count,
+				loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t buf_size, res;
+	int p1, p2, p3, p4, p5, p6;
+	struct sleep_params sp;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, user_buf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+	if (res != 6) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	sp.sp_error = p1;
+	sp.sp_offset = p2;
+	sp.sp_stabletime = p3;
+	sp.sp_calcontrol = p4;
+	sp.sp_extsleepclk = p5;
+	sp.sp_reserved = p6;
+
+	memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params));
+
+        res = libertas_prepare_and_send_command(priv,
+				cmd_802_11_sleep_params,
+				cmd_act_set,
+				cmd_option_waitforrsp, 0, NULL);
+
+	if (!res)
+		res = count;
+	else
+		res = -EINVAL;
+
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res;
+	size_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+        res = libertas_prepare_and_send_command(priv,
+				cmd_802_11_sleep_params,
+				cmd_act_get,
+				cmd_option_waitforrsp, 0, NULL);
+	if (res) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
+			adapter->sp.sp_offset, adapter->sp.sp_stabletime,
+			adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
+			adapter->sp.sp_reserved);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	struct WLAN_802_11_SSID extscan_ssid;
+	union iwreq_data wrqu;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
+	extscan_ssid.ssidlength = strlen(buf)-1;
+
+	libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1);
+
+	memset(&wrqu, 0, sizeof(union iwreq_data));
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+	free_page(addr);
+	return count;
+}
+
+static int libertas_parse_chan(char *buf, size_t count,
+			struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
+{
+	char *start, *end, *hold, *str;
+	int i = 0;
+
+	start = strstr(buf, "chan=");
+	if (!start)
+		return -EINVAL;
+	start += 5;
+	end = strstr(start, " ");
+	if (!end)
+		end = buf + count;
+	hold = kzalloc((end - start)+1, GFP_KERNEL);
+	if (!hold)
+		return -ENOMEM;
+	strncpy(hold, start, end - start);
+	hold[(end-start)+1] = '\0';
+	while(hold && (str = strsep(&hold, ","))) {
+		int chan;
+		char band, passive = 0;
+		sscanf(str, "%d%c%c", &chan, &band, &passive);
+		scan_cfg->chanlist[i].channumber = chan;
+		scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
+		if (band == 'b' || band == 'g')
+			scan_cfg->chanlist[i].radiotype = 0;
+		else if (band == 'a')
+			scan_cfg->chanlist[i].radiotype = 1;
+
+		scan_cfg->chanlist[i].scantime = dur;
+		i++;
+	}
+
+	kfree(hold);
+	return i;
+}
+
+static void libertas_parse_bssid(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	unsigned int mac[ETH_ALEN];
+	int i;
+
+	hold = strstr(buf, "bssid=");
+	if (!hold)
+		return;
+	hold += 6;
+	sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
+			mac+4, mac+5);
+	for(i=0;i<ETH_ALEN;i++)
+		scan_cfg->specificBSSID[i] = mac[i];
+}
+
+static void libertas_parse_ssid(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold, *end;
+	ssize_t size;
+
+	hold = strstr(buf, "ssid=");
+	if (!hold)
+		return;
+	hold += 5;
+	end = strstr(hold, " ");
+	if (!end)
+		end = buf + count - 1;
+
+	size = min(IW_ESSID_MAX_SIZE, end - hold);
+	strncpy(scan_cfg->specificSSID, hold, size);
+
+	return;
+}
+
+static void libertas_parse_keep(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "keep=");
+	if (!hold)
+		return;
+	hold += 5;
+	sscanf(hold, "%d", &val);
+
+	if (val != 0)
+		val = 1;
+
+	scan_cfg->keeppreviousscan = val;
+	return;
+}
+
+static int libertas_parse_dur(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "dur=");
+	if (!hold)
+		return 0;
+	hold += 4;
+	sscanf(hold, "%d", &val);
+
+	return val;
+}
+
+static void libertas_parse_probes(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "probes=");
+	if (!hold)
+		return;
+	hold += 7;
+	sscanf(hold, "%d", &val);
+
+	scan_cfg->numprobes = val;
+
+	return;
+}
+
+static void libertas_parse_type(char *buf, size_t count,
+                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+	char *hold;
+	int val;
+
+	hold = strstr(buf, "type=");
+	if (!hold)
+		return;
+	hold += 5;
+	sscanf(hold, "%d", &val);
+
+	/* type=1,2 or 3 */
+	if (val < 1 || val > 3)
+		return;
+
+	scan_cfg->bsstype = val;
+
+	return;
+}
+
+static ssize_t libertas_setuserscan(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	struct wlan_ioctl_user_scan_cfg *scan_cfg;
+	union iwreq_data wrqu;
+	int dur;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
+	if (!scan_cfg)
+		return -ENOMEM;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
+
+	dur = libertas_parse_dur(buf, count, scan_cfg);
+	libertas_parse_chan(buf, count, scan_cfg, dur);
+	libertas_parse_bssid(buf, count, scan_cfg);
+	libertas_parse_ssid(buf, count, scan_cfg);
+	libertas_parse_keep(buf, count, scan_cfg);
+	libertas_parse_probes(buf, count, scan_cfg);
+	libertas_parse_type(buf, count, scan_cfg);
+
+	wlan_scan_networks(priv, scan_cfg);
+	wait_event_interruptible(priv->adapter->cmd_pending,
+				 !priv->adapter->nr_cmd_pending);
+
+	memset(&wrqu, 0x00, sizeof(union iwreq_data));
+	wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+	free_page(addr);
+	kfree(scan_cfg);
+	return count;
+}
+
+static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
+			struct cmd_ctrl_node **cmdnode,
+			struct cmd_ds_command **cmd)
+{
+	u16 wait_option = cmd_option_waitforrsp;
+
+	if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
+		lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n");
+		return -ENOMEM;
+	}
+	if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
+		lbs_pr_debug(1, "failed to allocate response buffer!\n");
+		return -ENOMEM;
+	}
+	libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
+	init_waitqueue_head(&(*cmdnode)->cmdwait_q);
+	(*cmdnode)->pdata_buf = *response_buf;
+	(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
+	(*cmdnode)->cmdwaitqwoken = 0;
+	*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
+	(*cmd)->command = cmd_802_11_subscribe_event;
+	(*cmd)->seqnum = ++priv->adapter->seqnum;
+	(*cmd)->result = 0;
+	return 0;
+}
+
+static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_rssithreshold  *Lowrssi;
+		case TLV_TYPE_RSSI_LOW:
+		Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				Lowrssi->rssivalue,
+				Lowrssi->rssifreq,
+				(event->events & 0x0001)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static u16 libertas_get_events_bitmap(wlan_private *priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res;
+	u16 event_bitmap;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		return res;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		return 0;
+	}
+
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	event_bitmap = event->events;
+	kfree(response_buf);
+	return event_bitmap;
+}
+
+static ssize_t libertas_lowrssi_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_rssithreshold *rssi_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_rssithreshold));
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+	rssi_threshold->header.type = cpu_to_le16(0x0104);
+	rssi_threshold->header.len = 2;
+	rssi_threshold->rssivalue = cpu_to_le16(value);
+	rssi_threshold->rssifreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0001 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_snrthreshold *LowSnr;
+		case TLV_TYPE_SNR_LOW:
+		LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				LowSnr->snrvalue,
+				LowSnr->snrfreq,
+				(event->events & 0x0002)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_lowsnr_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_snrthreshold *snr_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_snrthreshold));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
+	snr_threshold->header.len = 2;
+	snr_threshold->snrvalue = cpu_to_le16(value);
+	snr_threshold->snrfreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0002 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_failurecount *failcount;
+		case TLV_TYPE_FAILCOUNT:
+		failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				failcount->failvalue,
+				failcount->Failfreq,
+				(event->events & 0x0004)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_failurecount);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_failcount_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_failurecount *failcount;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_failurecount));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	failcount = (struct mrvlietypes_failurecount *)(ptr);
+	failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
+	failcount->header.len = 2;
+	failcount->failvalue = cpu_to_le16(value);
+	failcount->Failfreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0004 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = (struct cmd_ds_command *)response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		free_page(addr);
+		kfree(response_buf);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		free_page(addr);
+		kfree(response_buf);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_beaconsmissed *bcnmiss;
+		case TLV_TYPE_BCNMISS:
+		bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
+				bcnmiss->beaconmissed,
+				(event->events & 0x0008)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_bcnmiss_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_beaconsmissed *bcnmiss;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_beaconsmissed));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
+	bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
+	bcnmiss->header.len = 2;
+	bcnmiss->beaconmissed = cpu_to_le16(value);
+	event_bitmap |= subscribed ? 0x0008 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		free_page(addr);
+		kfree(response_buf);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_rssithreshold  *Highrssi;
+		case TLV_TYPE_RSSI_HIGH:
+		Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				Highrssi->rssivalue,
+				Highrssi->rssifreq,
+				(event->events & 0x0010)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highrssi_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_rssithreshold *rssi_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_rssithreshold));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+	rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+	rssi_threshold->header.len = 2;
+	rssi_threshold->rssivalue = cpu_to_le16(value);
+	rssi_threshold->rssifreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0010 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	void *response_buf;
+	int res, cmd_len;
+	ssize_t pos = 0;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0) {
+		free_page(addr);
+		return res;
+	}
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_get;
+	pcmdptr->size =
+	cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+	while (cmd_len < pcmdptr->size) {
+		struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+		switch(header->type) {
+		struct mrvlietypes_snrthreshold *HighSnr;
+		case TLV_TYPE_SNR_HIGH:
+		HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+		pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+				HighSnr->snrvalue,
+				HighSnr->snrfreq,
+				(event->events & 0x0020)?1:0);
+		default:
+			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+			break;
+		}
+	}
+
+	kfree(response_buf);
+
+	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_highsnr_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	ssize_t res, buf_size;
+	int value, freq, subscribed, cmd_len;
+	struct cmd_ctrl_node *pcmdnode;
+	struct cmd_ds_command *pcmdptr;
+	struct cmd_ds_802_11_subscribe_event *event;
+	struct mrvlietypes_snrthreshold *snr_threshold;
+	void *response_buf;
+	u16 event_bitmap;
+	u8 *ptr;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+	if (res != 3) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	event_bitmap = libertas_get_events_bitmap(priv);
+
+	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+	if (res < 0)
+		goto out_unlock;
+
+	event = &pcmdptr->params.subscribe_event;
+	event->action = cmd_act_set;
+	pcmdptr->size = cpu_to_le16(S_DS_GEN +
+		sizeof(struct cmd_ds_802_11_subscribe_event) +
+		sizeof(struct mrvlietypes_snrthreshold));
+	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+	ptr = (u8*) pcmdptr+cmd_len;
+	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
+	snr_threshold->header.len = 2;
+	snr_threshold->snrvalue = cpu_to_le16(value);
+	snr_threshold->snrfreq = cpu_to_le16(freq);
+	event_bitmap |= subscribed ? 0x0020 : 0x0;
+	event->events = event_bitmap;
+
+	libertas_queue_cmd(adapter, pcmdnode, 1);
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	/* Sleep until response is generated by FW */
+	wait_event_interruptible(pcmdnode->cmdwait_q,
+				pcmdnode->cmdwaitqwoken);
+
+	pcmdptr = response_buf;
+
+	if (pcmdptr->result) {
+		lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+			pcmdptr->result);
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+		lbs_pr_err("command response incorrect!\n");
+		kfree(response_buf);
+		free_page(addr);
+		return 0;
+	}
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_offset_value offval;
+	ssize_t pos = 0;
+	int ret;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	offval.offset = priv->mac_offset;
+	offval.value = 0;
+
+	ret = libertas_prepare_and_send_command(priv,
+				cmd_mac_reg_access, 0,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+				priv->mac_offset, adapter->offsetvalue.value);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+	return ret;
+}
+
+static ssize_t libertas_rdmac_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_wrmac_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	u32 offset, value;
+	struct wlan_offset_value offval;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%x %x", &offset, &value);
+	if (res != 2) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	offval.offset = offset;
+	offval.value = value;
+	res = libertas_prepare_and_send_command(priv,
+				cmd_mac_reg_access, 1,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_offset_value offval;
+	ssize_t pos = 0;
+	int ret;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	offval.offset = priv->bbp_offset;
+	offval.value = 0;
+
+	ret = libertas_prepare_and_send_command(priv,
+				cmd_bbp_reg_access, 0,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+				priv->bbp_offset, adapter->offsetvalue.value);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+
+	return ret;
+}
+
+static ssize_t libertas_rdbbp_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_wrbbp_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	u32 offset, value;
+	struct wlan_offset_value offval;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%x %x", &offset, &value);
+	if (res != 2) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	offval.offset = offset;
+	offval.value = value;
+	res = libertas_prepare_and_send_command(priv,
+				cmd_bbp_reg_access, 1,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
+				  size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_offset_value offval;
+	ssize_t pos = 0;
+	int ret;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	offval.offset = priv->rf_offset;
+	offval.value = 0;
+
+	ret = libertas_prepare_and_send_command(priv,
+				cmd_rf_reg_access, 0,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+				priv->rf_offset, adapter->offsetvalue.value);
+
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	free_page(addr);
+
+	return ret;
+}
+
+static ssize_t libertas_rdrf_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+static ssize_t libertas_wrrf_write(struct file *file,
+				    const char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+
+	wlan_private *priv = file->private_data;
+	ssize_t res, buf_size;
+	u32 offset, value;
+	struct wlan_offset_value offval;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	buf_size = min(count, len - 1);
+	if (copy_from_user(buf, userbuf, buf_size)) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+	res = sscanf(buf, "%x %x", &offset, &value);
+	if (res != 2) {
+		res = -EFAULT;
+		goto out_unlock;
+	}
+
+	offval.offset = offset;
+	offval.value = value;
+	res = libertas_prepare_and_send_command(priv,
+				cmd_rf_reg_access, 1,
+				cmd_option_waitforrsp, 0, &offval);
+	mdelay(10);
+
+	res = count;
+out_unlock:
+	free_page(addr);
+	return res;
+}
+
+#define FOPS(fread, fwrite) { \
+	.owner = THIS_MODULE, \
+	.open = open_file_generic, \
+	.read = (fread), \
+	.write = (fwrite), \
+}
+
+struct libertas_debugfs_files {
+	char *name;
+	int perm;
+	struct file_operations fops;
+};
+
+struct libertas_debugfs_files debugfs_files[] = {
+	{ "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
+	{ "getscantable", 0444, FOPS(libertas_getscantable,
+					write_file_dummy), },
+	{ "sleepparams", 0644, FOPS(libertas_sleepparams_read,
+				libertas_sleepparams_write), },
+	{ "extscan", 0600, FOPS(NULL, libertas_extscan), },
+	{ "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
+};
+
+struct libertas_debugfs_files debugfs_events_files[] = {
+	{"low_rssi", 0644, FOPS(libertas_lowrssi_read,
+				libertas_lowrssi_write), },
+	{"low_snr", 0644, FOPS(libertas_lowsnr_read,
+				libertas_lowsnr_write), },
+	{"failure_count", 0644, FOPS(libertas_failcount_read,
+				libertas_failcount_write), },
+	{"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
+				libertas_bcnmiss_write), },
+	{"high_rssi", 0644, FOPS(libertas_highrssi_read,
+				libertas_highrssi_write), },
+	{"high_snr", 0644, FOPS(libertas_highsnr_read,
+				libertas_highsnr_write), },
+};
+
+struct libertas_debugfs_files debugfs_regs_files[] = {
+	{"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
+	{"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
+	{"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
+	{"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
+	{"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
+	{"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
+};
+
+void libertas_debugfs_init(void)
+{
+	if (!libertas_dir)
+		libertas_dir = debugfs_create_dir("libertas_wireless", 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)
+{
+	int i;
+	struct libertas_debugfs_files *files;
+	if (!libertas_dir)
+		goto exit;
+
+	priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
+	if (!priv->debugfs_dir)
+		goto exit;
+
+	for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+		files = &debugfs_files[i];
+		priv->debugfs_files[i] = debugfs_create_file(files->name,
+							     files->perm,
+							     priv->debugfs_dir,
+							     priv,
+							     &files->fops);
+	}
+
+	priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
+	if (!priv->events_dir)
+		goto exit;
+
+	for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
+		files = &debugfs_events_files[i];
+		priv->debugfs_events_files[i] = debugfs_create_file(files->name,
+							     files->perm,
+							     priv->events_dir,
+							     priv,
+							     &files->fops);
+	}
+
+	priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
+	if (!priv->regs_dir)
+		goto exit;
+
+	for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
+		files = &debugfs_regs_files[i];
+		priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
+							     files->perm,
+							     priv->regs_dir,
+							     priv,
+							     &files->fops);
+	}
+
+#ifdef PROC_DEBUG
+	libertas_debug_init(priv, dev);
+#endif
+exit:
+	return;
+}
+
+void libertas_debugfs_remove_one(wlan_private *priv)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
+		debugfs_remove(priv->debugfs_regs_files[i]);
+
+	debugfs_remove(priv->regs_dir);
+
+	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+		debugfs_remove(priv->debugfs_events_files[i]);
+
+	debugfs_remove(priv->events_dir);
+#ifdef PROC_DEBUG
+	debugfs_remove(priv->debugfs_debug);
+#endif
+	for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+		debugfs_remove(priv->debugfs_files[i]);
+}
+
+/* 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;
+	unsigned long addr = get_zeroed_page(GFP_KERNEL);
+	char *buf = (char *)addr;
+
+	p = buf;
+
+	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);
+
+	free_page(addr);
+	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)) {
+		lbs_pr_debug(1, "Copy from user failed\n");
+		kfree(pdata);
+		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 --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
new file mode 100644
index 0000000..880a11b
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.h
@@ -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 --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
new file mode 100644
index 0000000..606bdd0
--- /dev/null
+++ b/drivers/net/wireless/libertas/decl.h
@@ -0,0 +1,83 @@
+/**
+  *  This file contains declaration referring to
+  *  functions defined in other source files
+  */
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+#include "defs.h"
+
+/** Function Prototype Declaration */
+struct wlan_private;
+struct sk_buff;
+struct net_device;
+
+extern char *libertas_fw_name;
+
+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 cmd_ctrl_node;
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
+
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+		    struct cmd_ctrl_node *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 cmd_ctrl_node *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_fwversion(wlan_adapter * adapter, char *fwversion, 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 cmd_ctrl_node *ptempcmd);
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
+					struct cmd_ctrl_node *ptempcmd);
+
+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);
+
+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);
+
+int reset_device(wlan_private *priv);
+/* main.c */
+extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
+						             int *cfp_no);
+wlan_private *wlan_add_card(void *card);
+int wlan_remove_card(void *card);
+
+#endif				/* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
new file mode 100644
index 0000000..fb1478c
--- /dev/null
+++ b/drivers/net/wireless/libertas/defs.h
@@ -0,0 +1,369 @@
+/**
+  * This header file contains global constant/enum definitions,
+  * global variable declaration.
+  */
+#ifndef _WLAN_DEFS_H_
+#define _WLAN_DEFS_H_
+
+#include <linux/spinlock.h>
+
+extern unsigned int libertas_debug;
+
+#define DRV_NAME		"usb8xxx"
+
+#define lbs_pr_info(format, args...) \
+	printk(KERN_INFO DRV_NAME": " format, ## args)
+#define lbs_pr_err(format, args...) \
+	printk(KERN_ERR DRV_NAME": " format, ## args)
+#define lbs_pr_alert(format, args...) \
+	printk(KERN_ALERT DRV_NAME": " format, ## args)
+
+#ifdef DEBUG
+#define lbs_pr_debug(level, format, args...) \
+	do { if (libertas_debug >= level) \
+	printk(KERN_INFO DRV_NAME": " format, ##args); } while (0)
+#define lbs_dev_dbg(level, device, format, args...) \
+        lbs_pr_debug(level, "%s: " format, \
+        (device)->bus_id , ## args)
+
+static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+{
+	int i = 0;
+
+	if (!libertas_debug)
+		return;
+
+	printk(KERN_DEBUG "%s: ", prompt);
+	for (i = 1; i <= len; i++) {
+		printk(KERN_DEBUG "%02x ", (u8) * buf);
+		buf++;
+	}
+	printk("\n");
+}
+#else
+#define lbs_pr_debug(level, format, args...)		do {} while (0)
+#define lbs_dev_dbg(level, device, format, args...)	do {} while (0)
+#define lbs_dbg_hex(x,y,z)				do {} while (0)
+#endif
+
+#define	ENTER()			lbs_pr_debug(1, "Enter: %s, %s:%i\n", \
+					__FUNCTION__, __FILE__, __LINE__)
+#define	LEAVE()			lbs_pr_debug(1, "Leave: %s, %s:%i\n", \
+					__FUNCTION__, __FILE__, __LINE__)
+
+/** 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_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_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_CHANNELS_PER_SCAN		4
+#define	MRVDRV_MAX_CHANNELS_PER_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 mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define TxPD_CONTROL_WDS_FRAME (1<<17)
+#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+
+/** RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK                0x0001
+
+/** RxPD status - Received packet types */
+/** Rx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define RxPD_CONTROL_WDS_FRAME (0x40)
+#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
+
+/** 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
+
+/* 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)
+#define FW_CAPINFO_WPA  	(1 << 0)
+
+/** WPA key LENGTH*/
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH     32
+
+#define KEY_LEN_WPA_AES			16
+#define KEY_LEN_WPA_TKIP		32
+#define KEY_LEN_WEP_104			13
+#define KEY_LEN_WEP_40			5
+
+#define RF_ANTENNA_1		0x1
+#define RF_ANTENNA_2		0x2
+#define RF_ANTENNA_AUTO		0xFFFF
+
+#define	BAND_B			(0x01)
+#define	BAND_G			(0x02)
+#define ALL_802_11_BANDS	(BAND_B | BAND_G)
+
+/** 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 B_SUPPORTED_RATES		8
+#define G_SUPPORTED_RATES		14
+
+#define	WLAN_SUPPORTED_RATES		14
+
+#define	MAX_LEDS			8
+
+#define IS_MESH_FRAME(x) (x->cb[6])
+#define SET_MESH_FRAME(x) (x->cb[6]=1)
+#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
+
+/** Global Variable Declaration */
+typedef struct _wlan_private wlan_private;
+typedef struct _wlan_adapter wlan_adapter;
+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_11powemodemax
+};
+
+/** 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 {
+	libertas_connected,
+	libertas_disconnected
+};
+
+/** 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
+};
+
+/** 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,
+};
+
+/** SNMP_MIB_INDEX_e */
+enum SNMP_MIB_INDEX_e {
+	desired_bsstype_i = 0,
+	op_rateset_i,
+	bcnperiod_i,
+	dtimperiod_i,
+	assocrsp_timeout_i,
+	rtsthresh_i,
+	short_retrylim_i,
+	long_retrylim_i,
+	fragthresh_i,
+	dot11d_i,
+	dot11h_i,
+	manufid_i,
+	prodID_i,
+	manuf_oui_i,
+	manuf_name_i,
+	manuf_prodname_i,
+	manuf_prodver_i,
+};
+
+/** KEY_TYPE_ID */
+enum KEY_TYPE_ID {
+	KEY_TYPE_ID_WEP = 0,
+	KEY_TYPE_ID_TKIP,
+	KEY_TYPE_ID_AES
+};
+
+/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+enum KEY_INFO_WPA {
+	KEY_INFO_WPA_MCAST = 0x01,
+	KEY_INFO_WPA_UNICAST = 0x02,
+	KEY_INFO_WPA_ENABLED = 0x04
+};
+
+/** SNMP_MIB_VALUE_e */
+enum SNMP_MIB_VALUE_e {
+	SNMP_MIB_VALUE_INFRA = 1,
+	SNMP_MIB_VALUE_ADHOC
+};
+
+/* Default values for fwt commands. */
+#define FWT_DEFAULT_METRIC 0
+#define FWT_DEFAULT_DIR 1
+#define FWT_DEFAULT_SSN 0xffffffff
+#define FWT_DEFAULT_DSN 0
+#define FWT_DEFAULT_HOPCOUNT 0
+#define FWT_DEFAULT_TTL 0
+#define FWT_DEFAULT_EXPIRATION 0
+#define FWT_DEFAULT_SLEEPMODE 0
+#define FWT_DEFAULT_SNR 0
+
+#endif				/* _WLAN_DEFS_H_ */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
new file mode 100644
index 0000000..b1f876f
--- /dev/null
+++ b/drivers/net/wireless/libertas/dev.h
@@ -0,0 +1,403 @@
+/**
+  * This file contains definitions and data structures specific
+  * to Marvell 802.11 NIC. It contains the Device Information
+  * structure wlan_adapter.
+  */
+#ifndef _WLAN_DEV_H_
+#define _WLAN_DEV_H_
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ethtool.h>
+#include <linux/debugfs.h>
+
+#include "defs.h"
+#include "scan.h"
+#include "thread.h"
+
+extern struct ethtool_ops libertas_ethtool_ops;
+
+#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
+
+#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 authmode;
+	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;
+};
+
+/** 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;
+
+/* Mesh statistics */
+struct wlan_mesh_stats {
+	u32	fwd_bcast_cnt;		/* Fwd: Broadcast counter */
+	u32	fwd_unicast_cnt;	/* Fwd: Unicast counter */
+	u32	fwd_drop_ttl;		/* Fwd: TTL zero */
+	u32	fwd_drop_rbt;		/* Fwd: Recently Broadcasted */
+	u32	fwd_drop_noroute; 	/* Fwd: No route to Destination */
+	u32	fwd_drop_nobuf;		/* Fwd: Run out of internal buffers */
+	u32	drop_blind;		/* Rx:  Dropped by blinding table */
+};
+
+/** Private structure for the MV device */
+struct _wlan_private {
+	int open;
+	int mesh_open;
+	int infra_open;
+
+	wlan_adapter *adapter;
+	wlan_dev_t wlan_dev;
+
+	struct net_device_stats stats;
+	struct net_device *mesh_dev ; /* Virtual device */
+
+	struct iw_statistics wstats;
+	struct wlan_mesh_stats mstats;
+	struct dentry *debugfs_dir;
+	struct dentry *debugfs_debug;
+	struct dentry *debugfs_files[6];
+
+	struct dentry *events_dir;
+	struct dentry *debugfs_events_files[6];
+
+	struct dentry *regs_dir;
+	struct dentry *debugfs_regs_files[6];
+
+	u32 mac_offset;
+	u32 bbp_offset;
+	u32 rf_offset;
+
+	const struct firmware *firmware;
+	struct device *hotplug_device;
+
+	/** thread to service interrupts */
+	struct wlan_thread mainthread;
+
+	struct delayed_work assoc_work;
+	struct workqueue_struct *assoc_thread;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID			1
+#define ASSOC_FLAG_CHANNEL		2
+#define ASSOC_FLAG_MODE			3
+#define ASSOC_FLAG_BSSID		4
+#define ASSOC_FLAG_WEP_KEYS		5
+#define ASSOC_FLAG_WEP_TX_KEYIDX	6
+#define ASSOC_FLAG_WPA_MCAST_KEY	7
+#define ASSOC_FLAG_WPA_UCAST_KEY	8
+#define ASSOC_FLAG_SECINFO		9
+#define ASSOC_FLAG_WPA_IE		10
+	unsigned long flags;
+
+	struct WLAN_802_11_SSID ssid;
+	u8 channel;
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode;
+	u8 bssid[ETH_ALEN];
+
+	/** WEP keys */
+	struct WLAN_802_11_KEY wep_keys[4];
+	u16 wep_tx_keyidx;
+
+	/** WPA keys */
+	struct WLAN_802_11_KEY wpa_mcast_key;
+	struct WLAN_802_11_KEY wpa_unicast_key;
+
+	struct wlan_802_11_security secinfo;
+
+	/** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	u8 wpa_ie_len;
+};
+
+/** Wlan adapter data structure*/
+struct _wlan_adapter {
+	/** STATUS variables */
+	u32 fwreleasenumber;
+	u32 fwcapinfo;
+	/* protected with big lock */
+
+	struct mutex lock;
+
+	u8 tmptxbuf[WLAN_UPLD_SIZE];
+	/* protected by hard_start_xmit serialization */
+
+	/** command-related variables */
+	u16 seqnum;
+	/* protected by big lock */
+
+	struct cmd_ctrl_node *cmd_array;
+	/** Current command */
+	struct cmd_ctrl_node *cur_cmd;
+	int cur_cmd_retcode;
+	/** command Queues */
+	/** Free command buffers */
+	struct list_head cmdfreeq;
+	/** Pending command buffers */
+	struct list_head cmdpendingq;
+
+	wait_queue_head_t cmd_pending;
+	u8 nr_cmd_pending;
+	/* command related variables protected by adapter->driver_lock */
+
+	/** Async and Sync Event variables */
+	u32 intcounter;
+	u32 eventcause;
+	u8 nodename[16];	/* nickname */
+
+	/** spin locks */
+	spinlock_t driver_lock;
+
+	/** Timers */
+	struct timer_list command_timer;
+
+	/* TX queue used in PS mode */
+	spinlock_t txqueue_lock;
+	struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
+	unsigned int tx_queue_idx;
+
+	u8 hisregcpy;
+
+	/** current ssid/bssid related parameters*/
+	struct current_bss_params curbssparams;
+
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+
+	struct bss_descriptor *pattemptedbssdesc;
+
+	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;
+
+	/** MAC address information */
+	u8 current_addr[ETH_ALEN];
+	u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+	u32 nr_of_multicastmacaddr;
+
+	/** 802.11 statistics */
+//	struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+
+	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;
+
+	u16 listeninterval;
+	u16 prescan;
+	u8 txretrycount;
+
+	/** Tx-related variables (for single packet tx) */
+	struct sk_buff *currenttxskb;
+	u16 TxLockFlag;
+
+	/** NIC Operation characteristics */
+	u16 currentpacketfilter;
+	u32 connect_status;
+	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;
+
+	struct assoc_request * assoc_req;
+
+	/** Encryption parameter */
+	struct wlan_802_11_security secinfo;
+
+	/** WEP keys */
+	struct WLAN_802_11_KEY wep_keys[4];
+	u16 wep_tx_keyidx;
+
+	/** WPA keys */
+	struct WLAN_802_11_KEY wpa_mcast_key;
+	struct WLAN_802_11_KEY wpa_unicast_key;
+
+	/** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	u8 wpa_ie_len;
+
+	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;
+	u16 rxpd_rate;
+
+	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;
+
+	/** 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 */
+	u32 enable11d;
+
+	/**	MISCELLANEOUS */
+	u8 *prdeeprom;
+	struct wlan_offset_value offsetvalue;
+
+	struct cmd_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 --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
new file mode 100644
index 0000000..0064de5
--- /dev/null
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -0,0 +1,184 @@
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+static const char * mesh_stat_strings[]= {
+			"drop_duplicate_bcast",
+			"drop_ttl_zero",
+			"drop_no_fwd_route",
+			"drop_no_buffers",
+			"fwded_unicast_cnt",
+			"fwded_bcast_cnt",
+			"drop_blind_table"
+};
+
+static void libertas_ethtool_get_drvinfo(struct net_device *dev,
+					 struct ethtool_drvinfo *info)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+	char fwver[32];
+
+	libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
+
+	strcpy(info->driver, "libertas");
+	strcpy(info->version, libertas_driver_version);
+	strcpy(info->fw_version, fwver);
+}
+
+/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+#define LIBERTAS_EEPROM_LEN 16384
+
+static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
+{
+	return LIBERTAS_EEPROM_LEN;
+}
+
+static int libertas_ethtool_get_eeprom(struct net_device *dev,
+                                  struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct wlan_ioctl_regrdwr regctrl;
+	char *ptr;
+	int ret;
+
+	regctrl.action = 0;
+	regctrl.offset = eeprom->offset;
+	regctrl.NOB = eeprom->len;
+
+	if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
+		return -EINVAL;
+
+//      mutex_lock(&priv->mutex);
+
+	adapter->prdeeprom =
+		    (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+	if (!adapter->prdeeprom)
+		return -ENOMEM;
+	memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
+
+	/* +14 is for action, offset, and NOB in
+	 * response */
+	lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n",
+	       regctrl.action, regctrl.offset, regctrl.NOB);
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_eeprom_access,
+				    regctrl.action,
+				    cmd_option_waitforrsp, 0,
+				    &regctrl);
+
+	if (ret) {
+		if (adapter->prdeeprom)
+			kfree(adapter->prdeeprom);
+		LEAVE();
+			return ret;
+	}
+
+	mdelay(10);
+
+	ptr = (char *)adapter->prdeeprom;
+
+	/* skip the command header, but include the "value" u32 variable */
+	ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
+
+	/*
+	 * Return the result back to the user
+	 */
+	memcpy(bytes, ptr, eeprom->len);
+
+	if (adapter->prdeeprom)
+		kfree(adapter->prdeeprom);
+//	mutex_unlock(&priv->mutex);
+
+        return 0;
+}
+
+static void libertas_ethtool_get_stats(struct net_device * dev,
+				struct ethtool_stats * stats, u64 * data)
+{
+	wlan_private *priv = dev->priv;
+
+	ENTER();
+
+	stats->cmd = ETHTOOL_GSTATS;
+	BUG_ON(stats->n_stats != MESH_STATS_NUM);
+
+        data[0] = priv->mstats.fwd_drop_rbt;
+        data[1] = priv->mstats.fwd_drop_ttl;
+        data[2] = priv->mstats.fwd_drop_noroute;
+        data[3] = priv->mstats.fwd_drop_nobuf;
+        data[4] = priv->mstats.fwd_unicast_cnt;
+        data[5] = priv->mstats.fwd_bcast_cnt;
+        data[6] = priv->mstats.drop_blind;
+
+	LEAVE();
+}
+
+static int libertas_ethtool_get_stats_count(struct net_device * dev)
+{
+	int ret;
+	wlan_private *priv = dev->priv;
+	struct cmd_ds_mesh_access mesh_access;
+
+	ENTER();
+	/* Get Mesh Statistics */
+	ret = libertas_prepare_and_send_command(priv,
+			cmd_mesh_access, cmd_act_mesh_get_stats,
+			cmd_option_waitforrsp, 0, &mesh_access);
+
+	if (ret) {
+		LEAVE();
+		return 0;
+	}
+
+        priv->mstats.fwd_drop_rbt = mesh_access.data[0];
+        priv->mstats.fwd_drop_ttl = mesh_access.data[1];
+        priv->mstats.fwd_drop_noroute = mesh_access.data[2];
+        priv->mstats.fwd_drop_nobuf = mesh_access.data[3];
+        priv->mstats.fwd_unicast_cnt = mesh_access.data[4];
+        priv->mstats.fwd_bcast_cnt = mesh_access.data[5];
+        priv->mstats.drop_blind = mesh_access.data[6];
+
+	LEAVE();
+	return MESH_STATS_NUM;
+}
+
+static void libertas_ethtool_get_strings (struct net_device * dev,
+					  u32 stringset,
+					  u8 * s)
+{
+	int i;
+
+	ENTER();
+	switch (stringset) {
+        case ETH_SS_STATS:
+		for (i=0; i < MESH_STATS_NUM; i++) {
+			memcpy(s + i * ETH_GSTRING_LEN,
+					mesh_stat_strings[i],
+					ETH_GSTRING_LEN);
+		}
+		break;
+        }
+	LEAVE();
+}
+
+struct ethtool_ops libertas_ethtool_ops = {
+	.get_drvinfo = libertas_ethtool_get_drvinfo,
+	.get_eeprom =  libertas_ethtool_get_eeprom,
+	.get_eeprom_len = libertas_ethtool_get_eeprom_len,
+	.get_stats_count = libertas_ethtool_get_stats_count,
+	.get_ethtool_stats = libertas_ethtool_get_stats,
+	.get_strings = libertas_ethtool_get_strings,
+};
+
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
new file mode 100644
index 0000000..b194a45
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.c
@@ -0,0 +1,361 @@
+/**
+  * This file contains the initialization for FW and HW
+  */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "defs.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "if_usb.h"
+
+char *libertas_fw_name = NULL;
+module_param_named(fw_name, libertas_fw_name, charp, 0644);
+
+unsigned int libertas_debug = 0;
+module_param(libertas_debug, int, 0);
+
+/**
+ *  @brief This function checks the validity of Boot2/FW image.
+ *
+ *  @param data              pointer to image
+ *         len               image length
+ *  @return     0 or -1
+ */
+static int check_fwfile_format(u8 *data, u32 totlen)
+{
+	u8  bincmd, exit;
+	u32 blksize, offset, len;
+	int ret;
+
+	ret = 1;
+	exit = len = 0;
+
+	do {
+		bincmd = *data;
+		blksize = *(u32*)(data + offsetof(struct fwheader, datalength));
+		switch (bincmd) {
+		case FW_HAS_DATA_TO_RECV:
+			offset = sizeof(struct fwheader) + blksize;
+			data += offset;
+			len += offset;
+			if (len >= totlen)
+				exit = 1;
+			break;
+		case FW_HAS_LAST_BLOCK:
+			exit = 1;
+			ret = 0;
+			break;
+		default:
+			exit = 1;
+			break;
+		}
+	} while (!exit);
+
+	if (ret)
+		lbs_pr_err("bin file format check FAIL...\n");
+	else
+		lbs_pr_debug(1, "bin file format check PASS...\n");
+
+	return ret;
+}
+
+/**
+ *  @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 	   0 or -1
+ */
+static int wlan_setup_station_hw(wlan_private * priv)
+{
+	int ret = -1;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
+				    priv->hotplug_device)) < 0) {
+		lbs_pr_err("request_firmware() failed, error code = %#x\n",
+		       ret);
+		lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name);
+		goto done;
+	}
+
+	if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
+		release_firmware(priv->firmware);
+		goto done;
+	}
+
+	ret = libertas_sbi_prog_firmware(priv);
+
+	release_firmware(priv->firmware);
+
+	if (ret) {
+		lbs_pr_debug(1, "Bootloader in invalid state!\n");
+		ret = -1;
+		goto done;
+	}
+
+	/*
+	 * Read MAC address from HW
+	 */
+	memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
+				    0, cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	libertas_set_mac_packet_filter(priv);
+
+	/* Get the supported Data rates */
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+				    cmd_act_get_tx_rate,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	ret = 0;
+done:
+	LEAVE();
+
+	return (ret);
+}
+
+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 -1;
+	}
+
+	adapter->scantable = ptempscantable;
+	memset(adapter->scantable, 0, ulbufsize);
+
+	/* 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 = cpu_to_le16(++adapter->seqnum);
+	adapter->libertas_ps_confirm_sleep.command =
+	    cpu_to_le16(cmd_802_11_ps_mode);
+	adapter->libertas_ps_confirm_sleep.size =
+	    cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+	adapter->libertas_ps_confirm_sleep.result = 0;
+	adapter->libertas_ps_confirm_sleep.action =
+	    cpu_to_le16(cmd_subcmd_sleep_confirmed);
+
+	return 0;
+}
+
+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->connect_status = libertas_disconnected;
+	memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+	/* scan type */
+	adapter->scantype = cmd_scan_type_active;
+
+	/* scan mode */
+	adapter->scanmode = cmd_bss_type_any;
+
+	/* 802.11 specific */
+	adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+	for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+	     i++)
+		memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
+	adapter->wep_tx_keyidx = 0;
+	adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+	adapter->secinfo.authmode = wlan802_11authmodeopen;
+	adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+	adapter->secinfo.Encryptionmode = CIPHER_NONE;
+	adapter->inframode = wlan802_11infrastructure;
+
+	adapter->assoc_req = NULL;
+
+	adapter->numinscantable = 0;
+	adapter->pattemptedbssdesc = NULL;
+	mutex_init(&adapter->lock);
+
+	adapter->prescan = 1;
+
+	memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+	/* PnP and power profile */
+	adapter->surpriseremoved = 0;
+
+	adapter->currentpacketfilter =
+	    cmd_act_mac_rx_on | cmd_act_mac_tx_on;
+
+	adapter->radioon = RADIO_ON;
+	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 = 0;
+
+	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);
+
+int libertas_init_fw(wlan_private * priv)
+{
+	int ret = -1;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	/* Allocate adapter structure */
+	if ((ret = wlan_allocate_adapter(priv)) != 0)
+		goto done;
+
+	/* init adapter structure */
+	wlan_init_adapter(priv);
+
+	/* init timer etc. */
+	setup_timer(&adapter->command_timer, command_timer_fn,
+			(unsigned long)priv);
+
+	/* download fimrware etc. */
+	if ((ret = wlan_setup_station_hw(priv)) != 0) {
+		del_timer_sync(&adapter->command_timer);
+		goto done;
+	}
+
+	/* init 802.11d */
+	libertas_init_11d(priv);
+
+	ret = 0;
+done:
+	LEAVE();
+	return ret;
+}
+
+void libertas_free_adapter(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	if (!adapter) {
+		lbs_pr_debug(1, "Why double free adapter?:)\n");
+		return;
+	}
+
+	lbs_pr_debug(1, "Free command buffer\n");
+	libertas_free_cmd_buffer(priv);
+
+	lbs_pr_debug(1, "Free commandTimer\n");
+	del_timer(&adapter->command_timer);
+
+	lbs_pr_debug(1, "Free scantable\n");
+	if (adapter->scantable) {
+		kfree(adapter->scantable);
+		adapter->scantable = NULL;
+	}
+
+	lbs_pr_debug(1, "Free adapter\n");
+
+	/* Free the adapter object itself */
+	kfree(adapter);
+	priv->adapter = NULL;
+}
+
+/**
+ *  This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+	wlan_private *priv = (wlan_private *)data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *ptempnode;
+	struct cmd_ds_command *cmd;
+	unsigned long flags;
+
+	ptempnode = adapter->cur_cmd;
+	cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+
+	lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command);
+
+	if (!adapter->fw_ready)
+		return;
+
+	if (ptempnode == NULL) {
+		lbs_pr_debug(1, "PTempnode Empty\n");
+		return;
+	}
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	adapter->cur_cmd = NULL;
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	lbs_pr_debug(1, "Re-sending same command as it timeout...!\n");
+	libertas_queue_cmd(adapter, ptempnode, 0);
+
+	wake_up_interruptible(&priv->mainthread.waitq);
+
+	return;
+}
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h
new file mode 100644
index 0000000..1f9ae26
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.h
@@ -0,0 +1,13 @@
+/**
+  * This header file contains FW interface related definitions.
+  */
+#ifndef _WLAN_FW_H_
+#define _WLAN_FW_H_
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN            32
+#endif
+
+int libertas_init_fw(wlan_private * priv);
+
+#endif				/* _WLAN_FW_H_ */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
new file mode 100644
index 0000000..c0faaec
--- /dev/null
+++ b/drivers/net/wireless/libertas/host.h
@@ -0,0 +1,338 @@
+/**
+  * This file contains definitions of WLAN commands.
+  */
+
+#ifndef _HOST_H_
+#define _HOST_H_
+
+/** PUBLIC DEFINITIONS */
+#define DEFAULT_AD_HOC_CHANNEL       6
+#define DEFAULT_AD_HOC_CHANNEL_A    36
+
+/** IEEE 802.11 oids */
+#define OID_802_11_SSID                       0x00008002
+#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_TX_ANTENNA_SELECTED        0x0000800D
+#define OID_802_11_SUPPORTED_RATES            0x0000800E
+#define OID_802_11_STATISTICS                 0x00008012
+#define OID_802_11_TX_RETRYCOUNT              0x0000801D
+#define OID_802_11D_ENABLE                    0x00008020
+
+#define cmd_option_waitforrsp             0x0002
+
+/** Host command ID */
+#define cmd_code_dnld                 0x0002
+#define cmd_get_hw_spec               0x0003
+#define cmd_eeprom_update             0x0004
+#define cmd_802_11_reset              0x0005
+#define cmd_802_11_scan               0x0006
+#define cmd_802_11_get_log            0x000b
+#define cmd_mac_multicast_adr         0x0010
+#define cmd_802_11_authenticate       0x0011
+#define cmd_802_11_eeprom_access      0x0059
+#define cmd_802_11_associate          0x0050
+#define cmd_802_11_set_wep            0x0013
+#define cmd_802_11_get_stat           0x0014
+#define cmd_802_3_get_stat            0x0015
+#define cmd_802_11_snmp_mib           0x0016
+#define cmd_mac_reg_map               0x0017
+#define cmd_bbp_reg_map               0x0018
+#define cmd_mac_reg_access            0x0019
+#define cmd_bbp_reg_access            0x001a
+#define cmd_rf_reg_access             0x001b
+#define cmd_802_11_radio_control      0x001c
+#define cmd_802_11_rf_channel         0x001d
+#define cmd_802_11_rf_tx_power        0x001e
+#define cmd_802_11_rssi               0x001f
+#define cmd_802_11_rf_antenna         0x0020
+
+#define cmd_802_11_ps_mode	      0x0021
+
+#define cmd_802_11_data_rate          0x0022
+#define cmd_rf_reg_map                0x0023
+#define cmd_802_11_deauthenticate     0x0024
+#define cmd_802_11_reassociate        0x0025
+#define cmd_802_11_disassociate       0x0026
+#define cmd_mac_control               0x0028
+#define cmd_802_11_ad_hoc_start       0x002b
+#define cmd_802_11_ad_hoc_join        0x002c
+
+#define cmd_802_11_query_tkip_reply_cntrs  0x002e
+#define cmd_802_11_enable_rsn              0x002f
+#define cmd_802_11_pairwise_tsc       0x0036
+#define cmd_802_11_group_tsc          0x0037
+#define cmd_802_11_key_material       0x005e
+
+#define cmd_802_11_set_afc            0x003c
+#define cmd_802_11_get_afc            0x003d
+
+#define cmd_802_11_ad_hoc_stop        0x0040
+
+#define cmd_802_11_beacon_stop        0x0049
+
+#define cmd_802_11_mac_address        0x004D
+#define cmd_802_11_eeprom_access      0x0059
+
+#define cmd_802_11_band_config        0x0058
+
+#define cmd_802_11d_domain_info       0x005b
+
+#define cmd_802_11_sleep_params          0x0066
+
+#define cmd_802_11_inactivity_timeout    0x0067
+
+#define cmd_802_11_tpc_cfg               0x0072
+#define cmd_802_11_pwr_cfg               0x0073
+
+#define cmd_802_11_led_gpio_ctrl         0x004e
+
+#define cmd_802_11_subscribe_event       0x0075
+
+#define cmd_802_11_rate_adapt_rateset    0x0076
+
+#define cmd_802_11_tx_rate_query	0x007f
+
+#define cmd_get_tsf                      0x0080
+
+#define cmd_bt_access                 0x0087
+#define cmd_ret_bt_access                 0x8087
+
+#define cmd_fwt_access                0x0088
+#define cmd_ret_fwt_access                0x8088
+
+#define cmd_mesh_access               0x0090
+#define cmd_ret_mesh_access               0x8090
+
+/* For the IEEE Power Save */
+#define cmd_subcmd_enter_ps               0x0030
+#define cmd_subcmd_exit_ps                0x0031
+#define cmd_subcmd_sleep_confirmed        0x0034
+#define cmd_subcmd_full_powerdown         0x0035
+#define cmd_subcmd_full_powerup           0x0036
+
+/* command RET code, MSB is set to 1 */
+#define cmd_ret_hw_spec_info              0x8003
+#define cmd_ret_eeprom_update             0x8004
+#define cmd_ret_802_11_reset              0x8005
+#define cmd_ret_802_11_scan               0x8006
+#define cmd_ret_802_11_get_log            0x800b
+#define cmd_ret_mac_control               0x8028
+#define cmd_ret_mac_multicast_adr         0x8010
+#define cmd_ret_802_11_authenticate       0x8011
+#define cmd_ret_802_11_deauthenticate     0x8024
+#define cmd_ret_802_11_associate          0x8012
+#define cmd_ret_802_11_reassociate        0x8025
+#define cmd_ret_802_11_disassociate       0x8026
+#define cmd_ret_802_11_set_wep            0x8013
+#define cmd_ret_802_11_stat               0x8014
+#define cmd_ret_802_3_stat                0x8015
+#define cmd_ret_802_11_snmp_mib           0x8016
+#define cmd_ret_mac_reg_map               0x8017
+#define cmd_ret_bbp_reg_map               0x8018
+#define cmd_ret_rf_reg_map                0x8023
+#define cmd_ret_mac_reg_access            0x8019
+#define cmd_ret_bbp_reg_access            0x801a
+#define cmd_ret_rf_reg_access             0x801b
+#define cmd_ret_802_11_radio_control      0x801c
+#define cmd_ret_802_11_rf_channel         0x801d
+#define cmd_ret_802_11_rssi               0x801f
+#define cmd_ret_802_11_rf_tx_power        0x801e
+#define cmd_ret_802_11_rf_antenna         0x8020
+#define cmd_ret_802_11_ps_mode            0x8021
+#define cmd_ret_802_11_data_rate          0x8022
+
+#define cmd_ret_802_11_ad_hoc_start       0x802B
+#define cmd_ret_802_11_ad_hoc_join        0x802C
+
+#define cmd_ret_802_11_query_tkip_reply_cntrs  0x802e
+#define cmd_ret_802_11_enable_rsn              0x802f
+#define cmd_ret_802_11_pairwise_tsc       0x8036
+#define cmd_ret_802_11_group_tsc          0x8037
+#define cmd_ret_802_11_key_material       0x805e
+
+#define cmd_enable_rsn                    0x0001
+#define cmd_disable_rsn                   0x0000
+
+#define cmd_act_set                       0x0001
+#define cmd_act_get                       0x0000
+
+#define cmd_act_get_AES                   (cmd_act_get + 2)
+#define cmd_act_set_AES                   (cmd_act_set + 2)
+#define cmd_act_remove_aes                (cmd_act_set + 3)
+
+#define cmd_ret_802_11_set_afc            0x803c
+#define cmd_ret_802_11_get_afc            0x803d
+
+#define cmd_ret_802_11_ad_hoc_stop        0x8040
+
+#define cmd_ret_802_11_beacon_stop        0x8049
+
+#define cmd_ret_802_11_mac_address        0x804D
+#define cmd_ret_802_11_eeprom_access      0x8059
+
+#define cmd_ret_802_11_band_config        0x8058
+
+#define cmd_ret_802_11_sleep_params          0x8066
+
+#define cmd_ret_802_11_inactivity_timeout    0x8067
+
+#define cmd_ret_802_11d_domain_info      (0x8000 |                  \
+                                              cmd_802_11d_domain_info)
+
+#define cmd_ret_802_11_tpc_cfg        (cmd_802_11_tpc_cfg | 0x8000)
+#define cmd_ret_802_11_pwr_cfg        (cmd_802_11_pwr_cfg | 0x8000)
+
+#define cmd_ret_802_11_led_gpio_ctrl     0x804e
+
+#define cmd_ret_802_11_subscribe_event	(cmd_802_11_subscribe_event | 0x8000)
+
+#define cmd_ret_802_11_rate_adapt_rateset	(cmd_802_11_rate_adapt_rateset | 0x8000)
+
+#define cmd_rte_802_11_tx_rate_query 	(cmd_802_11_tx_rate_query | 0x8000)
+
+#define cmd_ret_get_tsf             0x8080
+
+/* Define action or option for cmd_802_11_set_wep */
+#define cmd_act_add                         0x0002
+#define cmd_act_remove                      0x0004
+#define cmd_act_use_default                 0x0008
+
+#define cmd_type_wep_40_bit                 0x0001
+#define cmd_type_wep_104_bit                0x0002
+
+#define cmd_NUM_OF_WEP_KEYS                 4
+
+#define cmd_WEP_KEY_INDEX_MASK              0x3fff
+
+/* Define action or option for cmd_802_11_reset */
+#define cmd_act_halt                        0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_bss_type_bss                    0x0001
+#define cmd_bss_type_ibss                   0x0002
+#define cmd_bss_type_any                    0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_scan_type_active                0x0000
+#define cmd_scan_type_passive               0x0001
+
+#define cmd_scan_radio_type_bg		0
+
+#define cmd_scan_probe_delay_time           0
+
+/* Define action or option for cmd_mac_control */
+#define cmd_act_mac_rx_on                   0x0001
+#define cmd_act_mac_tx_on                   0x0002
+#define cmd_act_mac_loopback_on             0x0004
+#define cmd_act_mac_wep_enable              0x0008
+#define cmd_act_mac_int_enable              0x0010
+#define cmd_act_mac_multicast_enable        0x0020
+#define cmd_act_mac_broadcast_enable        0x0040
+#define cmd_act_mac_promiscuous_enable      0x0080
+#define cmd_act_mac_all_multicast_enable    0x0100
+#define cmd_act_mac_strict_protection_enable  0x0400
+
+/* Define action or option for cmd_802_11_radio_control */
+#define cmd_type_auto_preamble              0x0001
+#define cmd_type_short_preamble             0x0002
+#define cmd_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 cmd_opt_802_11_rf_channel_get       0x00
+#define cmd_opt_802_11_rf_channel_set       0x01
+
+/* Define action or option for cmd_802_11_rf_tx_power */
+#define cmd_act_tx_power_opt_get            0x0000
+#define cmd_act_tx_power_opt_set_high       0x8007
+#define cmd_act_tx_power_opt_set_mid        0x8004
+#define cmd_act_tx_power_opt_set_low        0x8000
+
+#define cmd_act_tx_power_index_high         0x0007
+#define cmd_act_tx_power_index_mid          0x0004
+#define cmd_act_tx_power_index_low          0x0000
+
+/* Define action or option for cmd_802_11_data_rate */
+#define cmd_act_set_tx_auto                 0x0000
+#define cmd_act_set_tx_fix_rate             0x0001
+#define cmd_act_get_tx_rate                 0x0002
+
+#define cmd_act_set_rx                      0x0001
+#define cmd_act_set_tx                      0x0002
+#define cmd_act_set_both                    0x0003
+#define cmd_act_get_rx                      0x0004
+#define cmd_act_get_tx                      0x0008
+#define cmd_act_get_both                    0x000c
+
+/* Define action or option for cmd_802_11_ps_mode */
+#define cmd_type_cam                        0x0000
+#define cmd_type_max_psp                    0x0001
+#define cmd_type_fast_psp                   0x0002
+
+/* Define action or option for cmd_bt_access */
+enum cmd_bt_access_opts {
+	/* The bt commands start at 5 instead of 1 because the old dft commands
+	 * are mapped to 1-4.  These old commands are no longer maintained and
+	 * should not be called.
+	 */
+	cmd_act_bt_access_add = 5,
+	cmd_act_bt_access_del,
+	cmd_act_bt_access_list,
+	cmd_act_bt_access_reset
+};
+
+/* Define action or option for cmd_fwt_access */
+enum cmd_fwt_access_opts {
+	cmd_act_fwt_access_add = 1,
+	cmd_act_fwt_access_del,
+	cmd_act_fwt_access_lookup,
+	cmd_act_fwt_access_list,
+	cmd_act_fwt_access_list_route,
+	cmd_act_fwt_access_list_neighbor,
+	cmd_act_fwt_access_reset,
+	cmd_act_fwt_access_cleanup,
+	cmd_act_fwt_access_time,
+};
+
+/* Define action or option for cmd_mesh_access */
+enum cmd_mesh_access_opts {
+	cmd_act_mesh_get_ttl = 1,
+	cmd_act_mesh_set_ttl,
+	cmd_act_mesh_get_stats,
+	cmd_act_mesh_get_mpp,
+	cmd_act_mesh_set_mpp,
+};
+
+/** 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 --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
new file mode 100644
index 0000000..f239e5d
--- /dev/null
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -0,0 +1,693 @@
+/*
+ * This file contains the function prototypes, data structure
+ * and defines for all the host/station commands
+ */
+#ifndef __HOSTCMD__H
+#define __HOSTCMD__H
+
+#include <linux/wireless.h>
+#include "11d.h"
+#include "types.h"
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+	/* Current Tx packet status */
+	u32 tx_status;
+	/* Tx control */
+	u32 tx_control;
+	u32 tx_packet_location;
+	/* Tx packet length */
+	u16 tx_packet_length;
+	/* First 2 byte of destination MAC address */
+	u8 tx_dest_addr_high[2];
+	/* Last 4 byte of destination MAC address */
+	u8 tx_dest_addr_low[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 rx_control;
+
+	/* Pkt length */
+	u16 pkt_len;
+
+	/* Noise Floor */
+	u8 nf;
+
+	/* Rx Packet Rate */
+	u8 rx_rate;
+
+	/* Pkt addr */
+	u32 pkt_ptr;
+
+	/* Next Rx RxPD addr */
+	u32 next_rxpd_ptr;
+
+	/* Pkt Priority */
+	u8 priority;
+	u8 reserved[3];
+};
+
+struct cmd_ctrl_node {
+	/* 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;
+};
+
+/* WLAN_802_11_KEY
+ *
+ * Generic structure to hold all key types.  key type (WEP40, WEP104, TKIP, AES)
+ * is determined from the keylength field.
+ */
+struct WLAN_802_11_KEY {
+	u32 len;
+	u32 flags;  /* KEY_INFO_* from wlan_defs.h */
+	u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+	u16 type; /* KEY_TYPE_* from wlan_defs.h */
+};
+
+struct IE_WPA {
+	u8 elementid;
+	u8 len;
+	u8 oui[4];
+	u16 version;
+};
+
+struct WLAN_802_11_SSID {
+	/* SSID length */
+	u32 ssidlength;
+
+	/* SSID information field */
+	u8 ssid[IW_ESSID_MAX_SIZE];
+};
+
+struct WPA_SUPPLICANT {
+	u8 wpa_ie[256];
+	u8 wpa_ie_len;
+};
+
+/* wlan_offset_value */
+struct wlan_offset_value {
+	u32 offset;
+	u32 value;
+};
+
+struct WLAN_802_11_FIXED_IEs {
+	u8 timestamp[8];
+	u16 beaconinterval;
+	u16 capabilities;
+};
+
+struct WLAN_802_11_VARIABLE_IEs {
+	u8 elementid;
+	u8 length;
+	u8 data[1];
+};
+
+/* Define general data structure */
+/* cmd_DS_GEN */
+struct cmd_ds_gen {
+	u16 command;
+	u16 size;
+	u16 seqnum;
+	u16 result;
+};
+
+#define S_DS_GEN sizeof(struct cmd_ds_gen)
+/*
+ * Define data structure for cmd_get_hw_spec
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+	/* HW Interface version number */
+	u16 hwifversion;
+	/* HW version number */
+	u16 version;
+	/* Max number of TxPD FW can handle */
+	u16 nr_txpd;
+	/* Max no of Multicast address */
+	u16 nr_mcast_adr;
+	/* MAC address */
+	u8 permanentaddr[6];
+
+	/* region Code */
+	u16 regioncode;
+
+	/* Number of antenna used */
+	u16 nr_antenna;
+
+	/* FW release number, example 0x1234=1.2.3.4 */
+	u32 fwreleasenumber;
+
+	/* Base Address of TxPD queue */
+	u32 wcb_base;
+	/* Read Pointer of RxPd queue */
+	u32 rxpd_rdptr;
+
+	/* Write Pointer of RxPd queue */
+	u32 rxpd_wrptr;
+
+	/*FW/HW capability */
+	u32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_reset {
+	u16 action;
+};
+
+struct cmd_ds_802_11_subscribe_event {
+	u16 action;
+	u16 events;
+};
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for cmd_802_11_scan
+ */
+struct cmd_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 cmd_ds_802_11_scan_rsp {
+	u16 bssdescriptsize;
+	u8 nr_sets;
+	u8 bssdesc_and_tlvbuffer[1];
+};
+
+struct cmd_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;
+};
+
+struct cmd_ds_mac_control {
+	u16 action;
+	u16 reserved;
+};
+
+struct cmd_ds_mac_multicast_adr {
+	u16 action;
+	u16 nr_of_adrs;
+	u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+};
+
+struct cmd_ds_802_11_authenticate {
+	u8 macaddr[ETH_ALEN];
+	u8 authtype;
+	u8 reserved[10];
+};
+
+struct cmd_ds_802_11_deauthenticate {
+	u8 macaddr[6];
+	u16 reasoncode;
+};
+
+struct cmd_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));
+
+struct cmd_ds_802_11_disassociate {
+	u8 destmacaddr[6];
+	u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate_rsp {
+	struct ieeetypes_assocrsp assocRsp;
+};
+
+struct cmd_ds_802_11_ad_hoc_result {
+	u8 PAD[3];
+	u8 BSSID[ETH_ALEN];
+};
+
+struct cmd_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 keytype[4];
+	u8 keymaterial[4][16];
+};
+
+struct cmd_ds_802_3_get_stat {
+	u32 xmitok;
+	u32 rcvok;
+	u32 xmiterror;
+	u32 rcverror;
+	u32 rcvnobuffer;
+	u32 rcvcrcerror;
+};
+
+struct cmd_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;
+};
+
+struct cmd_ds_802_11_snmp_mib {
+	u16 querytype;
+	u16 oid;
+	u16 bufsize;
+	u8 value[128];
+};
+
+struct cmd_ds_mac_reg_map {
+	u16 buffersize;
+	u8 regmap[128];
+	u16 reserved;
+};
+
+struct cmd_ds_bbp_reg_map {
+	u16 buffersize;
+	u8 regmap[128];
+	u16 reserved;
+};
+
+struct cmd_ds_rf_reg_map {
+	u16 buffersize;
+	u8 regmap[64];
+	u16 reserved;
+};
+
+struct cmd_ds_mac_reg_access {
+	u16 action;
+	u16 offset;
+	u32 value;
+};
+
+struct cmd_ds_bbp_reg_access {
+	u16 action;
+	u16 offset;
+	u8 value;
+	u8 reserved[3];
+};
+
+struct cmd_ds_rf_reg_access {
+	u16 action;
+	u16 offset;
+	u8 value;
+	u8 reserved[3];
+};
+
+struct cmd_ds_802_11_radio_control {
+	u16 action;
+	u16 control;
+};
+
+struct cmd_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;
+};
+
+struct cmd_ds_802_11_inactivity_timeout {
+	/* ACT_GET/ACT_SET */
+	u16 action;
+
+	/* Inactivity timeout in msec */
+	u16 timeout;
+};
+
+struct cmd_ds_802_11_rf_channel {
+	u16 action;
+	u16 currentchannel;
+	u16 rftype;
+	u16 reserved;
+	u8 channellist[32];
+};
+
+struct cmd_ds_802_11_rssi {
+	/* weighting factor */
+	u16 N;
+
+	u16 reserved_0;
+	u16 reserved_1;
+	u16 reserved_2;
+};
+
+struct cmd_ds_802_11_rssi_rsp {
+	u16 SNR;
+	u16 noisefloor;
+	u16 avgSNR;
+	u16 avgnoisefloor;
+};
+
+struct cmd_ds_802_11_mac_address {
+	u16 action;
+	u8 macadd[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_rf_tx_power {
+	u16 action;
+	u16 currentlevel;
+};
+
+struct cmd_ds_802_11_rf_antenna {
+	u16 action;
+
+	/* Number of antennas or 0xffff(diversity) */
+	u16 antennamode;
+
+};
+
+struct cmd_ds_802_11_ps_mode {
+	u16 action;
+	u16 nullpktinterval;
+	u16 multipledtim;
+	u16 reserved;
+	u16 locallisteninterval;
+};
+
+struct PS_CMD_ConfirmSleep {
+	u16 command;
+	u16 size;
+	u16 seqnum;
+	u16 result;
+
+	u16 action;
+	u16 reserved1;
+	u16 multipledtim;
+	u16 reserved;
+	u16 locallisteninterval;
+};
+
+struct cmd_ds_802_11_data_rate {
+	u16 action;
+	u16 reserverd;
+	u8 datarate[G_SUPPORTED_RATES];
+};
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+	u16 action;
+	u16 enablehwauto;
+	u16 bitmap;
+};
+
+struct cmd_ds_802_11_ad_hoc_start {
+	u8 SSID[IW_ESSID_MAX_SIZE];
+	u8 bsstype;
+	u16 beaconperiod;
+	u8 dtimperiod;
+	union IEEEtypes_ssparamset ssparamset;
+	union ieeetypes_phyparamset phyparamset;
+	u16 probedelay;
+	struct ieeetypes_capinfo cap;
+	u8 datarate[G_SUPPORTED_RATES];
+	u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+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[G_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));
+
+struct cmd_ds_802_11_ad_hoc_join {
+	struct adhoc_bssdesc bssdescriptor;
+	u16 failtimeout;
+	u16 probedelay;
+
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+	u16 action;
+	u16 enable;
+};
+
+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];
+};
+
+struct cmd_ds_802_11_key_material {
+	u16 action;
+	struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+	u16 action;
+
+	/* multiple 4 */
+	u16 offset;
+	u16 bytecount;
+	u8 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+	u16 action;
+	u8 enable;
+	s8 P0;
+	s8 P1;
+	s8 P2;
+	u8 usesnr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_led_ctrl {
+	u16 action;
+	u16 numled;
+	u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_pwr_cfg {
+	u16 action;
+	u8 enable;
+	s8 PA_P0;
+	s8 PA_P1;
+	s8 PA_P2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+	u16 afc_auto;
+	union {
+		struct {
+			u16 threshold;
+			u16 period;
+		};
+		struct {
+			s16 timing_offset;
+			s16 carrier_offset;
+		};
+	};
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+	u16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+	__le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+	u16 action;
+	u32 id;
+	u8 addr1[ETH_ALEN];
+	u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+	u16 action;
+	u32 id;
+	u8 da[ETH_ALEN];
+	u8 dir;
+	u8 ra[ETH_ALEN];
+	u32 ssn;
+	u32 dsn;
+	u32 metric;
+	u8 hopcount;
+	u8 ttl;
+	u32 expiration;
+	u8 sleepmode;
+	u32 snr;
+	u32 references;
+} __attribute__ ((packed));
+
+#define MESH_STATS_NUM 7
+struct cmd_ds_mesh_access {
+	u16 action;
+	u32 data[MESH_STATS_NUM + 1];	/* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_command {
+	/* command header */
+	u16 command;
+	u16 size;
+	u16 seqnum;
+	u16 result;
+
+	/* command Body */
+	union {
+		struct cmd_ds_get_hw_spec hwspec;
+		struct cmd_ds_802_11_ps_mode psmode;
+		struct cmd_ds_802_11_scan scan;
+		struct cmd_ds_802_11_scan_rsp scanresp;
+		struct cmd_ds_mac_control macctrl;
+		struct cmd_ds_802_11_associate associate;
+		struct cmd_ds_802_11_deauthenticate deauth;
+		struct cmd_ds_802_11_set_wep wep;
+		struct cmd_ds_802_11_ad_hoc_start ads;
+		struct cmd_ds_802_11_reset reset;
+		struct cmd_ds_802_11_ad_hoc_result result;
+		struct cmd_ds_802_11_get_log glog;
+		struct cmd_ds_802_11_authenticate auth;
+		struct cmd_ds_802_11_get_stat gstat;
+		struct cmd_ds_802_3_get_stat gstat_8023;
+		struct cmd_ds_802_11_snmp_mib smib;
+		struct cmd_ds_802_11_rf_tx_power txp;
+		struct cmd_ds_802_11_rf_antenna rant;
+		struct cmd_ds_802_11_data_rate drate;
+		struct cmd_ds_802_11_rate_adapt_rateset rateset;
+		struct cmd_ds_mac_multicast_adr madr;
+		struct cmd_ds_802_11_ad_hoc_join adj;
+		struct cmd_ds_802_11_radio_control radio;
+		struct cmd_ds_802_11_rf_channel rfchannel;
+		struct cmd_ds_802_11_rssi rssi;
+		struct cmd_ds_802_11_rssi_rsp rssirsp;
+		struct cmd_ds_802_11_disassociate dassociate;
+		struct cmd_ds_802_11_mac_address macadd;
+		struct cmd_ds_802_11_enable_rsn enbrsn;
+		struct cmd_ds_802_11_key_material keymaterial;
+		struct cmd_ds_mac_reg_access macreg;
+		struct cmd_ds_bbp_reg_access bbpreg;
+		struct cmd_ds_rf_reg_access rfreg;
+		struct cmd_ds_802_11_eeprom_access rdeeprom;
+
+		struct cmd_ds_802_11d_domain_info domaininfo;
+		struct cmd_ds_802_11d_domain_info domaininforesp;
+
+		struct cmd_ds_802_11_sleep_params sleep_params;
+		struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
+		struct cmd_ds_802_11_tpc_cfg tpccfg;
+		struct cmd_ds_802_11_pwr_cfg pwrcfg;
+		struct cmd_ds_802_11_afc afc;
+		struct cmd_ds_802_11_led_ctrl ledgpio;
+
+		struct cmd_tx_rate_query txrate;
+		struct cmd_ds_bt_access bt;
+		struct cmd_ds_fwt_access fwt;
+		struct cmd_ds_mesh_access mesh;
+		struct cmd_ds_get_tsf gettsf;
+		struct cmd_ds_802_11_subscribe_event subscribe_event;
+	} params;
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
new file mode 100644
index 0000000..567000c
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_bootcmd.c
@@ -0,0 +1,38 @@
+/**
+  * This file contains functions used in USB Boot command
+  * and Boot2/FW update
+  */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+/**
+ *  @brief This function issues Boot command to the Boot2 code
+ *  @param ivalue   1:Boot from FW by USB-Download
+ *                  2:Boot from FW in EEPROM
+ *  @return 	   	0
+ */
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+{
+	struct usb_card_rec	*cardp = priv->wlan_dev.card;
+	struct bootcmdstr	sbootcmd;
+	int i;
+
+	/* Prepare command */
+	sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER;
+	sbootcmd.u8cmd_tag = ivalue;
+	for (i=0; i<11; i++)
+		sbootcmd.au8dumy[i]=0x00;
+	memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+
+	/* Issue command */
+	usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
new file mode 100644
index 0000000..695fb6a
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -0,0 +1,952 @@
+/**
+  * This file contains functions used in USB interface module.
+  */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+#define MESSAGE_HEADER_LEN	4
+
+static const char usbdriver_name[] = "usb8xxx";
+
+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 */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+
+/**
+ *  @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)
+{
+	wlan_private *priv = (wlan_private *) (urb->context);
+	wlan_adapter *adapter = priv->adapter;
+	struct net_device *dev = priv->wlan_dev.netdev;
+
+	/* handle the transmission complete validations */
+
+	if (urb->status != 0) {
+		/* print the failure status number for debug */
+		lbs_pr_info("URB in failure status\n");
+	} else {
+		lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n");
+		lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n",
+		       urb->actual_length);
+		priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+		/* Wake main thread if commands are pending */
+		if (!adapter->cur_cmd)
+			wake_up_interruptible(&priv->mainthread.waitq);
+		if ((adapter->connect_status == libertas_connected))
+			netif_wake_queue(dev);
+	}
+
+	return;
+}
+
+/**
+ *  @brief  free tx/rx urb, skb and rx buffer
+ *  @param cardp	pointer usb_card_rec
+ *  @return 	   	N/A
+ */
+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;
+
+	udev = interface_to_usbdev(intf);
+
+	usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+	if (!usb_cardp) {
+		lbs_pr_err("Out of memory allocating private data.\n");
+		goto error;
+	}
+
+	usb_cardp->udev = udev;
+	iface_desc = intf->cur_altsetting;
+
+	lbs_dev_dbg(1, &udev->dev, "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 & USB_ENDPOINT_DIR_MASK)
+		    && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_BULK)) {
+			/* we found a bulk in endpoint */
+			lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n",
+			       endpoint->wMaxPacketSize);
+			if (!
+			    (usb_cardp->rx_urb =
+			     usb_alloc_urb(0, GFP_KERNEL))) {
+				lbs_dev_dbg(1, &udev->dev,
+				       "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 & USB_ENDPOINT_NUMBER_MASK);
+			lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n",
+			       endpoint->bEndpointAddress);
+		}
+
+		if (((endpoint->
+		      bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+		     USB_DIR_OUT)
+		    && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_BULK)) {
+			/* We found bulk out endpoint */
+			if (!
+			    (usb_cardp->tx_urb =
+			     usb_alloc_urb(0, GFP_KERNEL))) {
+				lbs_dev_dbg(1,&udev->dev,
+				       "Tx URB allocation failed\n");
+				goto dealloc;
+			}
+
+			usb_cardp->bulk_out_size =
+			    endpoint->wMaxPacketSize;
+			lbs_dev_dbg(1, &udev->dev,
+				    "Bulk out size is %d\n",
+				    endpoint->wMaxPacketSize);
+			usb_cardp->bulk_out_endpointAddr =
+			    endpoint->bEndpointAddress;
+			lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n",
+				    endpoint->bEndpointAddress);
+			usb_cardp->bulk_out_buffer =
+			    kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+				    GFP_KERNEL);
+
+			if (!usb_cardp->bulk_out_buffer) {
+				lbs_dev_dbg(1, &udev->dev,
+				       "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 = wlan_add_card(usb_cardp)))
+		goto dealloc;
+
+	usb_get_dev(udev);
+	usb_set_intfdata(intf, usb_cardp);
+
+	/*
+	 * 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:
+	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 = NULL;
+
+	adapter = priv->adapter;
+
+	/*
+	 * Update Surprise removed to TRUE
+	 */
+	adapter->surpriseremoved = 1;
+
+	/* card is removed and we can call wlan_remove_card */
+	lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n");
+	wlan_remove_card(cardp);
+
+	/* Unlink and free urb */
+	if_usb_free(cardp);
+
+	usb_set_intfdata(intf, NULL);
+	usb_put_dev(interface_to_usbdev(intf));
+
+	return;
+}
+
+/**
+ *  @brief  This function download FW
+ *  @param priv		pointer to wlan_private
+ *  @return 	   	0
+ */
+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;
+
+	fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
+
+	if (!fwdata)
+		return -1;
+
+	fwheader = &fwdata->fwheader;
+
+	if (!cardp->CRC_OK) {
+		cardp->totalbytes = cardp->fwlastblksent;
+		cardp->fwseqnum = cardp->lastseqnum - 1;
+	}
+
+	lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n",
+		    cardp->totalbytes);
+
+	memcpy(fwheader, &firmware[cardp->totalbytes],
+	       sizeof(struct fwheader));
+
+	cardp->fwlastblksent = cardp->totalbytes;
+	cardp->totalbytes += sizeof(struct fwheader);
+
+	lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n");
+	memcpy(fwdata->data, &firmware[cardp->totalbytes],
+	       fwdata->fwheader.datalength);
+
+	lbs_dev_dbg(2, &cardp->udev->dev,
+		    "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) {
+		lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n");
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "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) {
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "Host has finished FW downloading\n");
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "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;
+	}
+
+	lbs_dev_dbg(2, &cardp->udev->dev,
+		    "The firmware download is done size is %d\n",
+		    cardp->totalbytes);
+
+	kfree(fwdata);
+
+	return 0;
+}
+
+static int libertas_do_reset(wlan_private *priv)
+{
+	int ret;
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+	ret = usb_reset_device(cardp->udev);
+	if (!ret) {
+		msleep(10);
+		reset_device(priv);
+		msleep(10);
+	}
+	return ret;
+}
+
+/**
+ *  @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 	   	0 or -1
+ */
+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 = -1;
+
+	/* check if device is removed */
+	if (priv->adapter->surpriseremoved) {
+		lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n");
+		goto tx_ret;
+	}
+
+	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 */
+		lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n");
+		ret = -1;
+	} else {
+		lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n");
+		ret = 0;
+	}
+
+tx_ret:
+	return ret;
+}
+
+static int __if_usb_submit_rx_urb(wlan_private * priv,
+				  void (*callbackfn)
+				  (struct urb *urb))
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	struct sk_buff *skb;
+	struct read_cb_info *rinfo = &cardp->rinfo;
+	int ret = -1;
+
+	if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+		lbs_pr_err("No free skb\n");
+		goto rx_ret;
+	}
+
+	rinfo->skb = skb;
+
+	/* 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;
+
+	lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+	if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+		/* handle failure conditions */
+		lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n");
+		ret = -1;
+	} else {
+		lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n");
+		ret = 0;
+	}
+
+rx_ret:
+	return ret;
+}
+
+static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+{
+	return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+}
+
+static inline int if_usb_submit_rx_urb(wlan_private * priv)
+{
+	return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+	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;
+	struct bootcmdrespStr bootcmdresp;
+
+	if (urb->status) {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "URB status is failed during fw load\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	if (cardp->bootcmdresp == 0) {
+		memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+			sizeof(bootcmdresp));
+		if (cardp->udev->descriptor.bcdDevice < 0x3106) {
+			kfree_skb(skb);
+			if_usb_submit_rx_urb_fwload(priv);
+			cardp->bootcmdresp = 1;
+			lbs_dev_dbg(1, &cardp->udev->dev,
+				    "Received valid boot command response\n");
+			return;
+		}
+		if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) {
+			lbs_pr_info(
+				"boot cmd response wrong magic number (0x%x)\n",
+				bootcmdresp.u32magicnumber);
+		} else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
+			lbs_pr_info(
+				"boot cmd response cmd_tag error (%d)\n",
+				bootcmdresp.u8cmd_tag);
+		} else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
+			lbs_pr_info(
+				"boot cmd response result error (%d)\n",
+				bootcmdresp.u8result);
+		} else {
+			cardp->bootcmdresp = 1;
+			lbs_dev_dbg(1, &cardp->udev->dev,
+				    "Received valid boot command response\n");
+		}
+		kfree_skb(skb);
+		if_usb_submit_rx_urb_fwload(priv);
+		return;
+	}
+
+	syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+	if (!syncfwheader) {
+		lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
+			sizeof(struct fwsyncheader));
+
+	if (!syncfwheader->cmd) {
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "FW received Blk with correct CRC\n");
+		lbs_dev_dbg(2, &cardp->udev->dev,
+			    "FW received Blk seqnum = %d\n",
+		       syncfwheader->seqnum);
+		cardp->CRC_OK = 1;
+	} else {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "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;
+
+}
+
+#define MRVDRV_MIN_PKT_LEN	30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+				       struct usb_card_rec *cardp,
+				       wlan_private *priv)
+{
+	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
+	    MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Packet length is Invalid\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	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);
+}
+
+static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
+				      struct sk_buff *skb,
+				      struct usb_card_rec *cardp,
+				      wlan_private *priv)
+{
+	u8 *cmdbuf;
+	if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "The receive buffer is too large\n");
+		kfree_skb(skb);
+		return;
+	}
+
+	if (!in_interrupt())
+		BUG();
+
+	spin_lock(&priv->adapter->driver_lock);
+	/* take care of cur_cmd = NULL case by reading the
+	 * data to clear the interrupt */
+	if (!priv->adapter->cur_cmd) {
+		cmdbuf = priv->wlan_dev.upld_buf;
+		priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+	} else
+		cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+
+	cardp->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);
+	libertas_interrupt(priv->wlan_dev.netdev);
+	spin_unlock(&priv->adapter->driver_lock);
+
+	lbs_dev_dbg(1, &cardp->udev->dev,
+		    "Wake up main thread to handle cmd response\n");
+
+	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 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;
+
+	ENTER();
+
+	if (recvlength) {
+		if (urb->status) {
+			lbs_dev_dbg(1, &cardp->udev->dev,
+				    "URB status is failed\n");
+			kfree_skb(skb);
+			goto setup_for_next;
+		}
+
+		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+		memcpy(&recvtype, recvbuff, sizeof(u32));
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Recv length = 0x%x\n", recvlength);
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Receive type = 0x%X\n", recvtype);
+		recvtype = le32_to_cpu(recvtype);
+		lbs_dev_dbg(1, &cardp->udev->dev,
+			    "Receive type after = 0x%X\n", recvtype);
+	} else if (urb->status)
+		goto rx_exit;
+
+
+	switch (recvtype) {
+	case CMD_TYPE_DATA:
+		process_cmdtypedata(recvlength, skb, cardp, priv);
+		break;
+
+	case CMD_TYPE_REQUEST:
+		process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+		break;
+
+	case CMD_TYPE_INDICATION:
+		/* Event cause handling */
+		spin_lock(&priv->adapter->driver_lock);
+		cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN);
+		lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n",
+			    cardp->usb_event_cause);
+		if (cardp->usb_event_cause & 0xffff0000) {
+			libertas_send_tx_feedback(priv);
+			break;
+		}
+		cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3;
+		cardp->usb_int_cause |= his_cardevent;
+		kfree_skb(skb);
+		libertas_interrupt(priv->wlan_dev.netdev);
+		spin_unlock(&priv->adapter->driver_lock);
+		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 	   	0 or -1
+ */
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+	int ret = -1;
+	u32 tmp;
+	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+	lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type);
+	lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb);
+
+	if (type == MVMS_CMD) {
+		tmp = 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 = 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;
+}
+
+/* called with adapter->driver_lock held */
+int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+	*ireg = cardp->usb_int_cause;
+	cardp->usb_int_cause = 0;
+
+	lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
+
+	return 0;
+}
+
+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 0;
+}
+
+int reset_device(wlan_private *priv)
+{
+	int ret;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
+				    cmd_act_halt, 0, 0, NULL);
+	msleep_interruptible(10);
+
+	return ret;
+}
+
+int libertas_sbi_unregister_dev(wlan_private * priv)
+{
+	int ret = 0;
+
+	/* 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 register usb device and initialize parameter
+ *  @param		priv pointer to wlan_private
+ *  @return		0 or -1
+ */
+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));
+
+	lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n",
+		    cardp->udev);
+
+	LEAVE();
+	return 0;
+}
+
+
+
+int libertas_sbi_prog_firmware(wlan_private * priv)
+{
+	struct usb_card_rec *cardp = priv->wlan_dev.card;
+	int i = 0;
+	static int reset_count = 10;
+
+	ENTER();
+
+	cardp->rinfo.priv = priv;
+
+restart:
+	if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+		lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n");
+		LEAVE();
+		return -1;
+	}
+
+#ifdef SUPPORT_BOOT_COMMAND
+	cardp->bootcmdresp = 0;
+	do {
+		int j = 0;
+		i++;
+		/* Issue Boot command = 1, Boot from Download-FW */
+		if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+		/* wait for command response */
+		do {
+			j++;
+			msleep_interruptible(100);
+		} while (cardp->bootcmdresp == 0 && j < 10);
+	} while (cardp->bootcmdresp == 0 && i < 5);
+
+	if (cardp->bootcmdresp == 0) {
+		if (--reset_count >= 0) {
+			libertas_do_reset(priv);
+			goto restart;
+		}
+		return -1;
+	}
+#endif
+
+	i = 0;
+	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 {
+		lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n");
+		i++;
+		msleep_interruptible(100);
+		if (priv->adapter->surpriseremoved || i >= 20)
+			break;
+	} while (!cardp->fwdnldover);
+
+	if (!cardp->fwdnldover) {
+		lbs_pr_info("failed to load fw, resetting device!\n");
+		if (--reset_count >= 0) {
+			libertas_do_reset(priv);
+			goto restart;
+		}
+
+		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+		LEAVE();
+		return -1;
+	}
+
+	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 0;
+}
+
+/**
+ *  @brief Given a usb_card_rec return its wlan_private
+ *  @param card		pointer to a usb_card_rec
+ *  @return 	   	pointer to wlan_private
+ */
+wlan_private *libertas_sbi_get_priv(void *card)
+{
+	struct usb_card_rec *cardp = card;
+	return cardp->priv;
+}
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private * priv)
+{
+	return 0;
+}
+
+int libertas_sbi_resume(wlan_private * priv)
+{
+	return 0;
+}
+#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;
+}
+#else
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+#endif
+
+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,
+};
+
+/**
+ *  @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(void)
+{
+	/*
+	 * API registers the Marvell USB driver
+	 * to the USB system
+	 */
+	usb_register(&if_usb_driver);
+
+	/* Return success to wlan layer */
+	return 0;
+}
+
+/**
+ *  @brief This function removes usb driver.
+ *  @return 	   	N/A
+ */
+void libertas_sbi_unregister(void)
+{
+	/* API unregisters the driver from USB subsystem */
+	usb_deregister(&if_usb_driver);
+	return;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
new file mode 100644
index 0000000..7851167
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -0,0 +1,109 @@
+/**
+  * This file contains definition for USB interface.
+  */
+#define CMD_TYPE_REQUEST                0xF00DFACE
+#define CMD_TYPE_DATA                   0xBEADC0DE
+#define CMD_TYPE_INDICATION             0xBEEFFACE
+
+#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
+
+#ifdef SUPPORT_BOOT_COMMAND
+#define BOOT_CMD_FW_BY_USB     0x01
+#define BOOT_CMD_FW_IN_EEPROM  0x02
+#define BOOT_CMD_UPDATE_BOOT2  0x03
+#define BOOT_CMD_UPDATE_FW     0x04
+#define BOOT_CMD_MAGIC_NUMBER  0x4C56524D   /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
+
+struct bootcmdstr
+{
+	u32 u32magicnumber;
+	u8  u8cmd_tag;
+	u8  au8dumy[11];
+};
+
+#define BOOT_CMD_RESP_OK     0x0001
+#define BOOT_CMD_RESP_FAIL   0x0000
+
+struct bootcmdrespStr
+{
+	u32 u32magicnumber;
+	u8  u8cmd_tag;
+	u8  u8result;
+	u8  au8dumy[2];
+};
+#endif /* SUPPORT_BOOT_COMMAND */
+
+/* read callback private data */
+struct read_cb_info {
+        wlan_private *priv;
+        struct sk_buff *skb;
+};
+
+/** USB card description structure*/
+struct usb_card_rec {
+	struct net_device *eth_dev;
+	struct usb_device *udev;
+	struct urb *rx_urb, *tx_urb;
+	void *priv;
+	struct read_cb_info rinfo;
+
+	int bulk_in_size;
+	u8 bulk_in_endpointAddr;
+
+	u8 *bulk_out_buffer;
+	int bulk_out_size;
+	u8 bulk_out_endpointAddr;
+
+	u8 CRC_OK;
+	u32 fwseqnum;
+	u32 lastseqnum;
+	u32 totalbytes;
+	u32 fwlastblksent;
+	u8 fwdnldover;
+	u8 fwfinalblk;
+
+	u32 usb_event_cause;
+	u8 usb_int_cause;
+
+	u8 rx_urb_recall;
+
+	u8 bootcmdresp;
+};
+
+/** 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 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)
+
+int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+void if_usb_free(struct usb_card_rec *cardp);
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
+
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c
new file mode 100644
index 0000000..82b3964
--- /dev/null
+++ b/drivers/net/wireless/libertas/ioctl.c
@@ -0,0 +1,2500 @@
+/**
+  * This file contains ioctl functions
+  */
+
+#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 <net/ieee80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+#define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
+				IW_ESSID_MAX_SIZE + \
+				IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+				IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
+				IW_EV_PARAM_LEN + 40)	/* 40 for WPAIE */
+
+#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
+
+static int setrxantenna(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->rxantennamode = mode;
+
+	lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+				    cmd_act_set_rx,
+				    cmd_option_waitforrsp, 0,
+				    &adapter->rxantennamode);
+	return ret;
+}
+
+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;
+
+	lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+				    cmd_act_set_tx,
+				    cmd_option_waitforrsp, 0,
+				    &adapter->txantennamode);
+
+	return ret;
+}
+
+static int getrxantenna(wlan_private * priv, char *buf)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	// 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, cmd_802_11_rf_antenna,
+				    cmd_act_get_rx,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode);
+
+	return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1;
+}
+
+static int gettxantenna(wlan_private * priv, char *buf)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	// 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, cmd_802_11_rf_antenna,
+				    cmd_act_get_tx,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode);
+
+	return sprintf(buf, "0x%04x", adapter->txantennamode) + 1;
+}
+
+static int wlan_set_region(wlan_private * priv, u16 region_code)
+{
+	int i;
+
+	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) {
+		lbs_pr_debug(1, "region Code not identified\n");
+		LEAVE();
+		return -1;
+	}
+
+	if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
+		LEAVE();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ *  @brief Get/Set Firmware wakeup method
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	0--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))) {
+			lbs_pr_alert("copy_to_user failed!\n");
+			return -EFAULT;
+		}
+	} else {
+		if ((int)wrq->u.data.length > 1) {
+			lbs_pr_alert("ioctl too many args!\n");
+			return -EFAULT;
+		}
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_alert("Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		adapter->pkttxctrl = (u32) data;
+	}
+
+	wrq->u.data.length = 1;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Get/Set NULL Package generation interval
+ *
+ *  @param priv		A pointer to wlan_private structure
+ *  @param wrq	   	A pointer to user data
+ *  @return 	   	0--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))) {
+			lbs_pr_alert( "copy_to_user failed!\n");
+			return -EFAULT;
+		}
+	} else {
+		if ((int)wrq->u.data.length > 1) {
+			lbs_pr_alert( "ioctl too many args!\n");
+			return -EFAULT;
+		}
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		adapter->nullpktinterval = data;
+	}
+
+	wrq->u.data.length = 1;
+
+	LEAVE();
+	return 0;
+}
+
+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->rxpd_rate;
+	if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+		lbs_pr_debug(1, "Copy to user failed\n");
+		return -EFAULT;
+	}
+	wrq->u.data.length = 2;
+	LEAVE();
+	return 0;
+}
+
+static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret = 0;
+	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)))
+			return -EFAULT;
+	}
+	if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+		if (adapter->connect_status == libertas_connected) {
+			ret = libertas_prepare_and_send_command(priv,
+						    cmd_802_11_rssi,
+						    0,
+						    cmd_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))
+			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)))
+			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)))
+			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)))
+			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)))
+			return -EFAULT;
+		wrq->u.data.length = 1;
+	} else
+		return -ENOTSUPP;
+
+	LEAVE();
+	return 0;
+}
+
+static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+	int data;
+	wlan_adapter *adapter = priv->adapter;
+
+	if (wrq->u.data.length > 0) {
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int)))
+			return -EFAULT;
+
+		lbs_pr_debug(1, "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)))
+		return -EFAULT;
+
+	wrq->u.data.length = 1;
+
+	return 0;
+}
+
+static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	int temp;
+	int data = 0;
+	int *val;
+
+	ENTER();
+	data = SUBCMD_DATA(wrq);
+	if ((data == 0) || (data == 1)) {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rssi,
+					    0, cmd_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 0;
+}
+
+static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret = 0;
+	wlan_adapter *adapter = priv->adapter;
+	int temp;
+	int data = 0;
+	int *val;
+
+	data = SUBCMD_DATA(wrq);
+	if ((data == 0) || (data == 1)) {
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rssi,
+					    0, cmd_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);
+
+	lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp);
+	val = (int *)wrq->u.name;
+	*val = temp;
+	return 0;
+}
+
+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 = 0;
+	adapter->txrate = 0;
+	lbs_pr_debug(1, "wlan_get_txrate_ioctl\n");
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query,
+				    cmd_act_get, cmd_option_waitforrsp,
+				    0, NULL);
+	if (ret)
+		return ret;
+
+	pdata = (int *)wrq->u.name;
+	*pdata = (int)adapter->txrate;
+	return 0;
+}
+
+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->inframode) {
+	case wlan802_11ibss:
+		if (adapter->connect_status == libertas_connected) {
+			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;
+	}
+
+	lbs_pr_debug(1, "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 0;
+}
+
+/**
+ *  @brief Set/Get WPA IE
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --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 = 0;
+
+	ENTER();
+
+	if (wrq->u.data.length) {
+		if (wrq->u.data.length > sizeof(adapter->wpa_ie)) {
+			lbs_pr_debug(1, "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)) {
+			lbs_pr_debug(1, "failed to copy WPA IE \n");
+			return -EFAULT;
+		}
+		adapter->wpa_ie_len = wrq->u.data.length;
+		lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len,
+		       adapter->wpa_ie[0]);
+		lbs_dbg_hex("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;
+		lbs_pr_debug(1, "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, cmd_802_11_enable_rsn,
+				    cmd_act_set, cmd_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 	   		0 --success, otherwise fail
+ */
+static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	int data;
+	wlan_adapter *adapter = priv->adapter;
+	int *val;
+
+	data = SUBCMD_DATA(wrq);
+	lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data);
+	adapter->prescan = data;
+
+	val = (int *)wrq->u.name;
+	*val = data;
+	return 0;
+}
+
+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 = SUBCMD_DATA(wrq);
+	mdtim = (u32) idata;
+	if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM)
+	     && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+	    || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+		priv->adapter->multipledtim = mdtim;
+		ret = 0;
+	}
+	if (ret)
+		lbs_pr_debug(1, "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 	   		0 --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;
+
+	if (wrq->u.data.flags == 0) {
+		//from iwpriv subcmd
+		alg = SUBCMD_DATA(wrq);
+	} else {
+		//from wpa_supplicant subcmd
+		if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+	}
+
+	lbs_pr_debug(1, "auth alg is %#x\n", alg);
+
+	switch (alg) {
+	case AUTH_ALG_SHARED_KEY:
+		adapter->secinfo.authmode = wlan802_11authmodeshared;
+		break;
+	case AUTH_ALG_NETWORK_EAP:
+		adapter->secinfo.authmode =
+		    wlan802_11authmodenetworkEAP;
+		break;
+	case AUTH_ALG_OPEN_SYSTEM:
+	default:
+		adapter->secinfo.authmode = wlan802_11authmodeopen;
+		break;
+	}
+	return 0;
+}
+
+/**
+ *  @brief Set 802.1x authentication mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int alg;
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	if (wrq->u.data.flags == 0) {
+		//from iwpriv subcmd
+		alg = SUBCMD_DATA(wrq);
+	} else {
+		//from wpa_supplicant subcmd
+		if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+	}
+	lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg);
+	priv->adapter->secinfo.auth1xalg = alg;
+	return 0;
+}
+
+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 = SUBCMD_DATA(wrq);
+	} else {
+		//from wpa_supplicant subcmd
+		if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+	}
+	lbs_pr_debug(1, "encryption mode is %#x\n", mode);
+	priv->adapter->secinfo.Encryptionmode = mode;
+
+	LEAVE();
+	return 0;
+}
+
+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_4addr);
+
+	if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP)
+		mtu_increment += max(sizeof(struct tx_radiotap_hdr),
+				     sizeof(struct rx_radiotap_hdr));
+	priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN
+	    - sizeof(struct ethhdr)
+	    + mtu_increment;
+}
+
+/**
+ *  @brief Set Link-Layer Layer mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int mode;
+
+	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:
+		lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n",
+		       mode);
+		return -EINVAL;
+		break;
+	}
+	lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode);
+
+	adjust_mtu(priv);
+
+	return 0;
+}
+
+/**
+ *  @brief Set Radio header mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	int mode;
+
+	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:
+		lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n",
+		       mode);
+		return -EINVAL;
+	}
+	lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode);
+
+	adjust_mtu(priv);
+	return 0;
+}
+
+/**
+ *  @brief Set Debug header mode
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param req			A pointer to ifreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	priv->adapter->debugmode = (int)((struct ifreq *)
+					 ((u8 *) req + 4))->ifr_data;
+	return 0;
+}
+
+static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv,
+					  struct ifreq *req)
+{
+	int len;
+	char buf[8];
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	lbs_pr_debug(1, "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)) {
+			lbs_pr_debug(1, "CopyToUser failed\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv,
+					  struct ifreq *req)
+{
+	int len;
+	char buf[8];
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	lbs_pr_debug(1, "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)) {
+			lbs_pr_debug(1, "CopyToUser failed\n");
+			return -EFAULT;
+		}
+	}
+	return 0;
+}
+
+/**
+ *  @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;
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_get_tsf,
+				    0, cmd_option_waitforrsp, 0, &tsfval);
+
+	lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval);
+
+	if (ret != 0) {
+		lbs_pr_debug(1, "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) {
+
+			lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n");
+			ret = -EFAULT;
+		} else {
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+/**
+ *  @brief Get/Set adapt rate
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret;
+	wlan_adapter *adapter = priv->adapter;
+	int data[2];
+
+	memset(data, 0, sizeof(data));
+	if (!wrq->u.data.length) {
+		lbs_pr_debug(1, "Get ADAPT RATE SET\n");
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rate_adapt_rateset,
+					    cmd_act_get,
+					    cmd_option_waitforrsp, 0, NULL);
+		data[0] = adapter->enablehwauto;
+		data[1] = adapter->ratebitmap;
+		if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			return -EFAULT;
+		}
+#define GET_TWO_INT	2
+		wrq->u.data.length = GET_TWO_INT;
+	} else {
+		lbs_pr_debug(1, "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)) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		adapter->enablehwauto = data[0];
+		adapter->ratebitmap = data[1];
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_rate_adapt_rateset,
+					    cmd_act_set,
+					    cmd_option_waitforrsp, 0, NULL);
+	}
+	return ret;
+}
+
+/**
+ *  @brief Get/Set inactivity timeout
+ *  @param priv                 A pointer to wlan_private structure
+ *  @param wrq			A pointer to iwreq structure
+ *  @return 	   		0 --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,
+					    cmd_802_11_inactivity_timeout,
+					    cmd_act_get,
+					    cmd_option_waitforrsp, 0,
+					    &timeout);
+		data = timeout;
+		if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			return -EFAULT;
+		}
+	} else {
+		/* Set */
+		if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+			lbs_pr_debug(1, "Copy from user failed\n");
+			return -EFAULT;
+		}
+
+		timeout = data;
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_inactivity_timeout,
+					    cmd_act_set,
+					    cmd_option_waitforrsp, 0,
+					    &timeout);
+	}
+
+	wrq->u.data.length = 1;
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+	int ret;
+	char buf[GETLOG_BUFSIZE - 1];
+	wlan_adapter *adapter = priv->adapter;
+
+	lbs_pr_debug(1, " GET STATS\n");
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log,
+				    0, cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		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)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+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 = 0;
+	wlan_adapter *adapter = priv->adapter;
+
+	if (priv->adapter->enable11d) {
+		lbs_pr_debug(1, "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)))
+		return -EFAULT;
+
+	lbs_pr_debug(1, "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 = cmd_scan_type_active;
+		break;
+	case 1:
+		adapter->scantype = cmd_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)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			ret = -EFAULT;
+		}
+
+		break;
+	default:
+		lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n");
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+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 = 0;
+
+	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))) {
+		lbs_pr_debug(1, "Copy from user failed\n");
+		return -EFAULT;
+	}
+
+	lbs_pr_debug(1, "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 = cmd_bss_type_bss;
+		break;
+	case 1:
+		adapter->scanmode = cmd_bss_type_ibss;
+		break;
+	case 2:
+		adapter->scanmode = cmd_bss_type_any;
+		break;
+	case 3:
+
+		wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1;
+
+		lbs_pr_debug(1, "Get Scan mode Option = %s\n",
+		       option[adapter->scanmode - 1]);
+
+		lbs_pr_debug(1, "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)) {
+			lbs_pr_debug(1, "Copy to user failed\n");
+			ret = -EFAULT;
+		}
+		lbs_pr_debug(1, "GET Scan type Option after copy = %s\n",
+		       (char *)wrq->u.data.pointer);
+
+		break;
+
+	default:
+		lbs_pr_debug(1, "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 	   	0--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 = SUBCMD_DATA(wrq);
+	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 0;
+}
+
+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 BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --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) {
+		lbs_pr_info("BT_ADD: Invalid MAC address\n");
+		return -EINVAL;
+	}
+
+	lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
+	LEAVE();
+	return (libertas_prepare_and_send_command(priv, cmd_bt_access,
+				      cmd_act_bt_access_add,
+				      cmd_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         0 --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) {
+		lbs_pr_info("Invalid MAC address\n");
+		return -EINVAL;
+	}
+
+	lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
+
+	return (libertas_prepare_and_send_command(priv,
+				      cmd_bt_access,
+				      cmd_act_bt_access_del,
+				      cmd_option_waitforrsp, 0, ethaddr));
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_bt_reset_ioctl(wlan_private * priv)
+{
+	ENTER();
+
+	lbs_pr_alert( "BT: resetting\n");
+
+	return (libertas_prepare_and_send_command(priv,
+				      cmd_bt_access,
+				      cmd_act_bt_access_reset,
+				      cmd_option_waitforrsp, 0, NULL));
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          List an entry from the BT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --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))) {
+		lbs_pr_debug(1, "Copy from user failed\n");
+		return -1;
+	}
+	param.id = simple_strtoul(outstr, NULL, 10);
+	pos = sprintf(pbuf, "%d: ", param.id);
+	pbuf += pos;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
+				    cmd_act_bt_access_list,
+				    cmd_option_waitforrsp, 0,
+				    (char *)&param);
+
+	if (ret == 0) {
+		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)) {
+		lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Find the next parameter in an input string
+ *  @param ptr      A pointer to the input parameter string
+ *  @return         A pointer to the next parameter, or 0 if no parameters left.
+ */
+static char * next_param(char * ptr)
+{
+	if (!ptr) return NULL;
+	while (*ptr == ' ' || *ptr == '\t') ++ptr;
+	return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ *  @brief          Add an entry to the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[128];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+		lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+		lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.metric =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.metric = FWT_DEFAULT_METRIC;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.dir = FWT_DEFAULT_DIR;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.ssn =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.ssn = FWT_DEFAULT_SSN;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.dsn =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.dsn = FWT_DEFAULT_DSN;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.ttl = FWT_DEFAULT_TTL;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.expiration =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.snr =
+			cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+	else
+		fwt_access.snr = FWT_DEFAULT_SNR;
+
+#ifdef DEBUG
+	{
+		char ethaddr1_str[18], ethaddr2_str[18];
+		eth_addr2str(fwt_access.da, ethaddr1_str);
+		eth_addr2str(fwt_access.ra, ethaddr2_str);
+		lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
+		       fwt_access.dir, ethaddr2_str);
+		lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
+		       fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
+		       fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
+		       fwt_access.sleepmode, fwt_access.snr);
+	}
+#endif
+
+	LEAVE();
+	return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
+						  cmd_act_fwt_access_add,
+						  cmd_option_waitforrsp, 0,
+						  (void *)&fwt_access));
+}
+
+/**
+ *  @brief          Delete an entry from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[64];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+		lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+		lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
+		return -EINVAL;
+	}
+
+	if ((ptr = next_param(ptr)))
+		fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+	else
+		fwt_access.dir = FWT_DEFAULT_DIR;
+
+#ifdef DEBUG
+	{
+		char ethaddr1_str[18], ethaddr2_str[18];
+		lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
+		eth_addr2str(fwt_access.da, ethaddr1_str);
+		eth_addr2str(fwt_access.ra, ethaddr2_str);
+		lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
+		       ethaddr2_str, fwt_access.dir);
+	}
+#endif
+
+	LEAVE();
+	return (libertas_prepare_and_send_command(priv,
+						  cmd_fwt_access,
+						  cmd_act_fwt_access_del,
+						  cmd_option_waitforrsp, 0,
+						  (void *)&fwt_access));
+}
+
+
+/**
+ *  @brief             Print route parameters
+ *  @param fwt_access  struct cmd_ds_fwt_access with route info
+ *  @param buf         destination buffer for route info
+ */
+static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
+{
+	buf += sprintf(buf, " ");
+	buf += eth_addr2str(fwt_access.da, buf);
+	buf += sprintf(buf, " ");
+	buf += eth_addr2str(fwt_access.ra, buf);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
+	buf += sprintf(buf, " %u", fwt_access.dir);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
+	buf += sprintf(buf, " %u", fwt_access.hopcount);
+	buf += sprintf(buf, " %u", fwt_access.ttl);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
+	buf += sprintf(buf, " %u", fwt_access.sleepmode);
+	buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
+}
+
+/**
+ *  @brief          Lookup an entry in the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[64];
+	char *ptr;
+	static struct cmd_ds_fwt_access fwt_access;
+	static char out_str[128];
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+		lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
+		return -EINVAL;
+	}
+
+#ifdef DEBUG
+	{
+		char ethaddr1_str[18];
+		lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
+		eth_addr2str(fwt_access.da, ethaddr1_str);
+		lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv,
+						cmd_fwt_access,
+						cmd_act_fwt_access_lookup,
+						cmd_option_waitforrsp, 0,
+						(void *)&fwt_access);
+
+	if (ret == 0)
+		print_route(fwt_access, out_str);
+	else
+		sprintf(out_str, "(null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Reset all entries from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_reset_ioctl(wlan_private * priv)
+{
+	lbs_pr_debug(1, "FWT: resetting\n");
+
+	return (libertas_prepare_and_send_command(priv,
+				      cmd_fwt_access,
+				      cmd_act_fwt_access_reset,
+				      cmd_option_waitforrsp, 0, NULL));
+}
+
+/**
+ *  @brief          List an entry from the FWT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[8];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr = in_str;
+	static char out_str[128];
+	char *pbuf = out_str;
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+	{
+		lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
+		lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_list,
+				    cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+	if (ret == 0)
+		print_route(fwt_access, pbuf);
+	else
+		pbuf += sprintf(pbuf, " (null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          List an entry from the FRT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[64];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr = in_str;
+	static char out_str[128];
+	char *pbuf = out_str;
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+	{
+		lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
+		lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_list_route,
+				    cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+	if (ret == 0) {
+		pbuf += sprintf(pbuf, " ");
+		pbuf += eth_addr2str(fwt_access.da, pbuf);
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
+		pbuf += sprintf(pbuf, " %u", fwt_access.dir);
+		/* note that the firmware returns the nid in the id field */
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
+		pbuf += sprintf(pbuf, "  hop %u", fwt_access.hopcount);
+		pbuf += sprintf(pbuf, "  ttl %u", fwt_access.ttl);
+		pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
+	} else
+		pbuf += sprintf(pbuf, " (null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          List an entry from the FNT table
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct iwreq *wrq = (struct iwreq *)req;
+	char in_str[8];
+	static struct cmd_ds_fwt_access fwt_access;
+	char *ptr = in_str;
+	static char out_str[128];
+	char *pbuf = out_str;
+	int ret;
+
+	ENTER();
+	if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+		return -EFAULT;
+
+	memset(&fwt_access, 0, sizeof(fwt_access));
+	fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+	{
+		lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
+		lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
+	}
+#endif
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_list_neighbor,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&fwt_access);
+
+	if (ret == 0) {
+		pbuf += sprintf(pbuf, " ra ");
+		pbuf += eth_addr2str(fwt_access.ra, pbuf);
+		pbuf += sprintf(pbuf, "  slp %u", fwt_access.sleepmode);
+		pbuf += sprintf(pbuf, "  snr %u", le32_to_cpu(fwt_access.snr));
+		pbuf += sprintf(pbuf, "  ref %u", le32_to_cpu(fwt_access.references));
+	} else
+		pbuf += sprintf(pbuf, " (null)");
+
+	wrq->u.data.length = strlen(out_str);
+	if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+			 wrq->u.data.length)) {
+		lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
+		return -EFAULT;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Cleans up the route (FRT) and neighbor (FNT) tables
+ *                  (Garbage Collection)
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	static struct cmd_ds_fwt_access fwt_access;
+	int ret;
+
+	ENTER();
+
+	lbs_pr_debug(1, "FWT: cleaning up\n");
+
+	memset(&fwt_access, 0, sizeof(fwt_access));
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_cleanup,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&fwt_access);
+
+	if (ret == 0)
+		req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+	else
+		return -EFAULT;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Gets firmware internal time (debug purposes)
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	static struct cmd_ds_fwt_access fwt_access;
+	int ret;
+
+	ENTER();
+
+	lbs_pr_debug(1, "FWT: getting time\n");
+
+	memset(&fwt_access, 0, sizeof(fwt_access));
+
+	ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+				    cmd_act_fwt_access_time,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&fwt_access);
+
+	if (ret == 0)
+		req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+	else
+		return -EFAULT;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Gets mesh ttl from firmware
+ *  @param priv     A pointer to wlan_private structure
+ *  @param req      A pointer to ifreq structure
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
+{
+	struct cmd_ds_mesh_access mesh_access;
+	int ret;
+
+	ENTER();
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+
+	ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+				    cmd_act_mesh_get_ttl,
+				    cmd_option_waitforrsp, 0,
+				    (void *)&mesh_access);
+
+	if (ret == 0) {
+		req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0]));
+	}
+	else
+		return -EFAULT;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief          Gets mesh ttl from firmware
+ *  @param priv     A pointer to wlan_private structure
+ *  @param ttl      New ttl value
+ *  @return         0 --success, otherwise fail
+ */
+static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
+{
+	struct cmd_ds_mesh_access mesh_access;
+	int ret;
+
+	ENTER();
+
+	if( (ttl > 0xff) || (ttl < 0) )
+		return -EINVAL;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	mesh_access.data[0] = ttl;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+						cmd_act_mesh_set_ttl,
+						cmd_option_waitforrsp, 0,
+						(void *)&mesh_access);
+
+	if (ret != 0)
+		ret = -EFAULT;
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief ioctl function - entry point
+ *
+ *  @param dev		A pointer to net_device structure
+ *  @param req	   	A pointer to ifreq structure
+ *  @param cmd 		command
+ *  @return 	   	0--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 = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iwreq *wrq = (struct iwreq *)req;
+
+	ENTER();
+
+	lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+	switch (cmd) {
+	case WLANSCAN_TYPE:
+		lbs_pr_debug(1, "Scan type Ioctl\n");
+		ret = wlan_scan_type_ioctl(priv, wrq);
+		break;
+
+	case WLAN_SETNONE_GETNONE:	/* set WPA mode on/off ioctl #20 */
+		switch (wrq->u.data.flags) {
+		case WLANDEAUTH:
+			lbs_pr_debug(1, "Deauth\n");
+			libertas_send_deauth(priv);
+			break;
+
+		case WLANADHOCSTOP:
+			lbs_pr_debug(1, "Adhoc stop\n");
+			ret = libertas_do_adhocstop_ioctl(priv);
+			break;
+
+		case WLANRADIOON:
+			wlan_radio_ioctl(priv, 1);
+			break;
+
+		case WLANRADIOOFF:
+			wlan_radio_ioctl(priv, 0);
+			break;
+		case WLANWLANIDLEON:
+			libertas_idle_on(priv);
+			break;
+		case WLANWLANIDLEOFF:
+			libertas_idle_off(priv);
+			break;
+		case WLAN_SUBCMD_BT_RESET:	/* bt_reset */
+			wlan_bt_reset_ioctl(priv);
+			break;
+		case WLAN_SUBCMD_FWT_RESET:	/* fwt_reset */
+			wlan_fwt_reset_ioctl(priv);
+			break;
+		}		/* End of switch */
+		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;
+				lbs_pr_debug(1, "Get locallisteninterval value\n");
+#define GET_ONE_INT	1
+				data = adapter->locallisteninterval;
+				if (copy_to_user(wrq->u.data.pointer,
+						 &data, sizeof(int))) {
+					lbs_pr_debug(1, "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))) {
+					lbs_pr_debug(1, "Copy from user failed\n");
+					return -EFAULT;
+				}
+
+				lbs_pr_debug(1, "Set locallisteninterval = %d\n",
+				       data);
+#define MAX_U16_VAL	65535
+				if (data > MAX_U16_VAL) {
+					lbs_pr_debug(1, "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 = SUBCMD_DATA(wrq);
+			ret = setrxantenna(priv, idata);
+			break;
+		case WLAN_SUBCMD_SETTXANTENNA:	/* SETTXANTENNA */
+			idata = SUBCMD_DATA(wrq);
+			ret = settxantenna(priv, idata);
+			break;
+		case WLAN_SET_ATIM_WINDOW:
+			adapter->atimwindow = SUBCMD_DATA(wrq);
+			adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50);
+			break;
+		case WLANSETBCNAVG:
+			adapter->bcn_avg_factor = SUBCMD_DATA(wrq);
+			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 = SUBCMD_DATA(wrq);
+			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 = SUBCMD_DATA(wrq);
+			ret = wlan_set_region(priv, (u16) idata);
+			break;
+
+		case WLAN_SET_LISTEN_INTERVAL:
+			idata = SUBCMD_DATA(wrq);
+			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;
+
+		case WLAN_SUBCMD_MESH_SET_TTL:
+			idata = SUBCMD_DATA(wrq);
+			ret = wlan_mesh_set_ttl_ioctl(priv, idata);
+			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_SET128CHAR_GET128CHAR:
+		switch ((int)wrq->u.data.flags) {
+
+		case WLANSCAN_MODE:
+			lbs_pr_debug(1, "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_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;
+		case WLAN_SUBCMD_FWT_ADD:
+			ret = wlan_fwt_add_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_DEL:
+			ret = wlan_fwt_del_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LOOKUP:
+			ret = wlan_fwt_lookup_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
+			ret = wlan_fwt_list_neighbor_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LIST:
+			ret = wlan_fwt_list_ioctl(priv, req);
+			break;
+		case WLAN_SUBCMD_FWT_LIST_ROUTE:
+			ret = wlan_fwt_list_route_ioctl(priv, req);
+			break;
+		}
+		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;
+		case WLAN_SUBCMD_FWT_CLEANUP:	/* fwt_cleanup */
+			ret = wlan_fwt_cleanup_ioctl(priv, req);
+			break;
+
+		case WLAN_SUBCMD_FWT_TIME:	/* fwt_time */
+			ret = wlan_fwt_time_ioctl(priv, req);
+			break;
+
+		case WLAN_SUBCMD_MESH_GET_TTL:
+			ret = wlan_mesh_get_ttl_ioctl(priv, req);
+			break;
+
+		default:
+			ret = -EOPNOTSUPP;
+
+		}
+
+		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 cmd_ds_802_11_tpc_cfg cfg;
+				memset(&cfg, 0, sizeof(cfg));
+				if ((wrq->u.data.length > 1)
+				    && (wrq->u.data.length != 5))
+					return -1;
+
+				if (wrq->u.data.length == 0) {
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_get);
+				} else {
+					if (copy_from_user
+					    (data, wrq->u.data.pointer,
+					     sizeof(int) * 5)) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_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,
+							  cmd_802_11_tpc_cfg,
+							  0,
+							  cmd_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)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = 5;
+			}
+			break;
+
+		case WLAN_POWERCFG:
+			{
+				int data[4];
+				struct cmd_ds_802_11_pwr_cfg cfg;
+				memset(&cfg, 0, sizeof(cfg));
+				if ((wrq->u.data.length > 1)
+				    && (wrq->u.data.length != 4))
+					return -1;
+				if (wrq->u.data.length == 0) {
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_get);
+				} else {
+					if (copy_from_user
+					    (data, wrq->u.data.pointer,
+					     sizeof(int) * 4)) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					cfg.action =
+					    cpu_to_le16
+					    (cmd_act_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,
+							  cmd_802_11_pwr_cfg,
+							  0,
+							  cmd_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)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = 4;
+			}
+			break;
+		case WLAN_AUTO_FREQ_SET:
+			{
+				int data[3];
+				struct cmd_ds_802_11_afc afc;
+				memset(&afc, 0, sizeof(afc));
+				if (wrq->u.data.length != 3)
+					return -1;
+				if (copy_from_user
+				    (data, wrq->u.data.pointer,
+				     sizeof(int) * 3)) {
+					lbs_pr_debug(1, "Copy from user failed\n");
+					return -EFAULT;
+				}
+				afc.afc_auto = data[0];
+
+				if (afc.afc_auto != 0) {
+					afc.threshold = data[1];
+					afc.period = data[2];
+				} else {
+					afc.timing_offset = data[1];
+					afc.carrier_offset = data[2];
+				}
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_set_afc,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&afc);
+			}
+			break;
+		case WLAN_AUTO_FREQ_GET:
+			{
+				int data[3];
+				struct cmd_ds_802_11_afc afc;
+				memset(&afc, 0, sizeof(afc));
+				ret =
+				    libertas_prepare_and_send_command(priv,
+							  cmd_802_11_get_afc,
+							  0,
+							  cmd_option_waitforrsp,
+							  0, (void *)&afc);
+				data[0] = afc.afc_auto;
+				data[1] = afc.timing_offset;
+				data[2] = afc.carrier_offset;
+				if (copy_to_user
+				    (wrq->u.data.pointer, data,
+				     sizeof(int) * 3)) {
+					lbs_pr_debug(1, "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))) {
+						lbs_pr_debug(1,
+						       "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))) {
+						lbs_pr_debug(1,
+						       "Copy to user failed\n");
+						return -EFAULT;
+					}
+				}
+				wrq->u.data.length = 1;
+			}
+			break;
+		case WLAN_LED_GPIO_CTRL:
+			{
+				int i;
+				int data[16];
+
+				struct cmd_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 =
+					    cpu_to_le16
+					    (cmd_act_get);
+				} else {
+					if (copy_from_user
+					    (data, wrq->u.data.pointer,
+					     sizeof(int) *
+					     wrq->u.data.length)) {
+						lbs_pr_debug(1,
+						       "Copy from user failed\n");
+						return -EFAULT;
+					}
+
+					ctrl.action =
+					    cpu_to_le16
+					    (cmd_act_set);
+					ctrl.numled = cpu_to_le16(0);
+					gpio->header.type =
+					    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,
+							  cmd_802_11_led_gpio_ctrl,
+							  0,
+							  cmd_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)) {
+					lbs_pr_debug(1, "Copy to user failed\n");
+					return -EFAULT;
+				}
+
+				wrq->u.data.length = gpio->header.len;
+			}
+			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;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	LEAVE();
+	return ret;
+}
+
+
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
new file mode 100644
index 0000000..11682cb
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.c
@@ -0,0 +1,1055 @@
+/**
+  *  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.
+  */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "join.h"
+#include "dev.h"
+
+/**
+ *  @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            0 or -1
+ */
+static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
+			    int rate1_size, u8 * rate2, int rate2_size)
+{
+	u8 *ptr = rate1;
+	int ret = 0;
+	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];
+		}
+	}
+
+	lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
+	lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
+	lbs_dbg_hex("Common rates:", ptr, rate1_size);
+	lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate);
+
+	if (!adapter->is_datarate_auto) {
+		while (*ptr) {
+			if ((*ptr & 0x7f) == adapter->datarate) {
+				ret = 0;
+				goto done;
+			}
+			ptr++;
+		}
+		lbs_pr_alert( "Previously set fixed data rate %#x isn't "
+		       "compatible with the network.\n", adapter->datarate);
+
+		ret = -1;
+		goto done;
+	}
+
+	ret = 0;
+done:
+	return ret;
+}
+
+int libertas_send_deauth(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	if (adapter->inframode == wlan802_11infrastructure &&
+	    adapter->connect_status == libertas_connected)
+		ret = libertas_send_deauthentication(priv);
+	else
+		ret = -ENOTSUPP;
+
+	return ret;
+}
+
+int libertas_do_adhocstop_ioctl(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	if (adapter->inframode == wlan802_11ibss &&
+	    adapter->connect_status == libertas_connected)
+		ret = libertas_stop_adhoc_network(priv);
+	else
+		ret = -ENOTSUPP;
+
+	return ret;
+}
+
+/**
+ *  @brief Associate 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          0-success, otherwise fail
+ */
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret;
+
+	ENTER();
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
+				    0, cmd_option_waitforrsp,
+				    0, pbssdesc->macaddress);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	/* set preamble to firmware */
+	if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble)
+		adapter->preamble = cmd_type_short_preamble;
+	else
+		adapter->preamble = cmd_type_long_preamble;
+
+	libertas_set_radio_control(priv);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
+				    0, cmd_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             0--success, -1--fail
+ */
+int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	adapter->adhoccreate = 1;
+
+	if (!adapter->capinfo.shortpreamble) {
+		lbs_pr_debug(1, "AdhocStart: Long preamble\n");
+		adapter->preamble = cmd_type_long_preamble;
+	} else {
+		lbs_pr_debug(1, "AdhocStart: Short preamble\n");
+		adapter->preamble = cmd_type_short_preamble;
+	}
+
+	libertas_set_radio_control(priv);
+
+	lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel);
+	lbs_pr_debug(1, "curbssparams.channel = %d\n",
+	       adapter->curbssparams.channel);
+	lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
+				    0, cmd_option_waitforrsp, 0, adhocssid);
+
+	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             0--success, -1--fail
+ */
+int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n",
+	       adapter->curbssparams.ssid.ssid);
+	lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n",
+	       adapter->curbssparams.ssid.ssidlength);
+	lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid);
+	lbs_pr_debug(1, "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.inframode ==
+		wlan802_11ibss)) {
+
+        lbs_pr_debug(1,
+		       "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+		       "not attempting to re-join");
+
+		return -1;
+	}
+
+	/*Use shortpreamble only when both creator and card supports
+	   short preamble */
+	if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+		lbs_pr_debug(1, "AdhocJoin: Long preamble\n");
+		adapter->preamble = cmd_type_long_preamble;
+	} else {
+		lbs_pr_debug(1, "AdhocJoin: Short preamble\n");
+		adapter->preamble = cmd_type_short_preamble;
+	}
+
+	libertas_set_radio_control(priv);
+
+	lbs_pr_debug(1, "curbssparams.channel = %d\n",
+	       adapter->curbssparams.channel);
+	lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band);
+
+	adapter->adhoccreate = 0;
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
+				    0, cmd_option_waitforrsp,
+				    OID_802_11_SSID, pbssdesc);
+
+	return ret;
+}
+
+int libertas_stop_adhoc_network(wlan_private * priv)
+{
+	return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
+				     0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ *  @brief Send Deauthentication Request
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @return          0--success, -1--fail
+ */
+int libertas_send_deauthentication(wlan_private * priv)
+{
+	return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
+				     0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ *  @brief Set Idle Off
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_idle_off(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 };
+	int i;
+
+	ENTER();
+
+	if (adapter->connect_status == libertas_disconnected) {
+		if (adapter->inframode == wlan802_11infrastructure) {
+			if (memcmp(adapter->previousbssid, zeromac,
+				   sizeof(zeromac)) != 0) {
+
+				lbs_pr_debug(1, "Previous SSID = %s\n",
+				       adapter->previousssid.ssid);
+				lbs_pr_debug(1, "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->inframode);
+
+				if (i < 0) {
+					libertas_send_specific_BSSID_scan(priv,
+							      adapter->
+							      previousbssid,
+							      1);
+					i = libertas_find_SSID_in_list(adapter,
+							   &adapter->
+							   previousssid,
+							   adapter->
+							   previousbssid,
+							   adapter->
+							   inframode);
+				}
+
+				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->
+							   inframode);
+				}
+
+				if (i < 0) {
+					libertas_send_specific_SSID_scan(priv,
+							     &adapter->
+							     previousssid,
+							     1);
+					i = libertas_find_SSID_in_list(adapter,
+							   &adapter->
+							   previousssid, NULL,
+							   adapter->
+							   inframode);
+				}
+
+				if (i >= 0) {
+					ret =
+					    wlan_associate(priv,
+							   &adapter->
+							   scantable[i]);
+				}
+			}
+		} else if (adapter->inframode == wlan802_11ibss) {
+			ret = libertas_prepare_and_send_command(priv,
+						    cmd_802_11_ad_hoc_start,
+						    0,
+						    cmd_option_waitforrsp,
+						    0, &adapter->previousssid);
+		}
+	}
+	/* else it is connected */
+
+	lbs_pr_debug(1, "\nwlanidle is off");
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Set Idle On
+ *
+ *  @param priv         A pointer to wlan_private structure
+ *  @return             0 --success, otherwise fail
+ */
+int libertas_idle_on(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	if (adapter->connect_status == libertas_connected) {
+		if (adapter->inframode == wlan802_11infrastructure) {
+			lbs_pr_debug(1, "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->inframode == wlan802_11ibss) {
+			ret = libertas_stop_adhoc_network(priv);
+		}
+
+	}
+
+	lbs_pr_debug(1, "\nwlanidle is on");
+
+	return ret;
+}
+
+/**
+ *  @brief This function prepares command of authenticate.
+ *
+ *  @param priv      A pointer to wlan_private structure
+ *  @param cmd       A pointer to cmd_ds_command structure
+ *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ *  @return         0 or -1
+ */
+int libertas_cmd_80211_authenticate(wlan_private * priv,
+				 struct cmd_ds_command *cmd,
+				 void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_authenticate *pauthenticate =
+	    &cmd->params.auth;
+	u8 *bssid = pdata_buf;
+
+	cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+			     + S_DS_GEN);
+
+	pauthenticate->authtype = adapter->secinfo.authmode;
+	memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+	lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
+	       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+
+	return 0;
+}
+
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+				   struct cmd_ds_command *cmd)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+	ENTER();
+
+	cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_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 = cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+	LEAVE();
+	return 0;
+}
+
+int libertas_cmd_80211_associate(wlan_private * priv,
+			      struct cmd_ds_command *cmd, void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+	int ret = 0;
+	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 = pdata_buf;
+	pos = (u8 *) passo;
+
+	if (!adapter) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->command = cpu_to_le16(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 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 = 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 = cpu_to_le16(ssid->header.len);
+
+	phy = (struct mrvlietypes_phyparamset *) pos;
+	phy->header.type = 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 = cpu_to_le16(phy->header.len);
+
+	ss = (struct mrvlietypes_ssparamset *) pos;
+	ss->header.type = cpu_to_le16(TLV_TYPE_CF);
+	ss->header.len = sizeof(ss->cf_ibss.cfparamset);
+	pos += sizeof(ss->header) + ss->header.len;
+	ss->header.len = cpu_to_le16(ss->header.len);
+
+	rates = (struct mrvlietypes_ratesparamset *) pos;
+	rates->header.type = 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 = -1;
+		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 = 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 = cpu_to_le16(rsn->header.type);
+		rsn->header.len = (u16) adapter->wpa_ie[1];
+		memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
+		lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+			sizeof(rsn->header) + rsn->header.len);
+		pos += sizeof(rsn->header) + rsn->header.len;
+		rsn->header.len = 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));
+
+	lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
+
+	/* set IBSS field */
+	if (pbssdesc->inframode == wlan802_11infrastructure) {
+#define CAPINFO_ESS_MODE 1
+		passo->capinfo.ess = CAPINFO_ESS_MODE;
+	}
+
+	if (libertas_parse_dnld_countryinfo_11d(priv)) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->size = 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;
+	lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+	       tmpcap, CAPINFO_MASK);
+	tmpcap = cpu_to_le16(tmpcap);
+	memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+				 struct cmd_ds_command *cmd, void *pssid)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+	int ret = 0;
+	int cmdappendsize = 0;
+	int i;
+	u16 tmpcap;
+	struct bss_descriptor *pbssdesc;
+	struct WLAN_802_11_SSID *ssid = pssid;
+
+	ENTER();
+
+	if (!adapter) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+
+	pbssdesc = &adapter->curbssparams.bssdescriptor;
+	adapter->pattemptedbssdesc = pbssdesc;
+
+	/*
+	 * Fill in the parameters for 2 data structures:
+	 *   1. cmd_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, IW_ESSID_MAX_SIZE);
+
+	memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+	memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
+	memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
+
+	pbssdesc->ssid.ssidlength = ssid->ssidlength;
+
+	/* set the BSS type */
+	adhs->bsstype = cmd_bss_type_ibss;
+	pbssdesc->inframode = 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;
+
+	WARN_ON(!adapter->adhocchannel);
+
+	lbs_pr_debug(1, "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));
+
+	/* 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 = cpu_to_le16(cmd_scan_probe_delay_time);
+
+	/* set up privacy in adapter->scantable[i] */
+	if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+		lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
+		pbssdesc->privacy = wlan802_11privfilter8021xWEP;
+		adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+	} else {
+		lbs_pr_debug(1, "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);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+	       adhs->datarate[0], adhs->datarate[1],
+	       adhs->datarate[2], adhs->datarate[3]);
+
+	lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+	if (libertas_create_dnld_countryinfo_11d(priv)) {
+		lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+		ret = -1;
+		goto done;
+	}
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
+			     + S_DS_GEN + cmdappendsize);
+
+	memcpy(&tmpcap, &adhs->cap, sizeof(u16));
+	tmpcap = cpu_to_le16(tmpcap);
+	memcpy(&adhs->cap, &tmpcap, sizeof(u16));
+
+	ret = 0;
+done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+				struct cmd_ds_command *cmd)
+{
+	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+	cmd->size = cpu_to_le16(S_DS_GEN);
+
+	return 0;
+}
+
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+				struct cmd_ds_command *cmd, void *pdata_buf)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+	struct bss_descriptor *pbssdesc = pdata_buf;
+	int cmdappendsize = 0;
+	int ret = 0;
+	u8 *card_rates;
+	int card_rates_size;
+	u16 tmpcap;
+	int i;
+
+	ENTER();
+
+	adapter->pattemptedbssdesc = pbssdesc;
+
+	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+
+	padhocjoin->bssdescriptor.bsstype = cmd_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;
+
+	lbs_pr_debug(1, "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 */
+    lbs_pr_debug(1,
+	       "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);
+
+	lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
+	       (u32) padhocjoin->bssdescriptor.datarates);
+
+	/* failtimeout */
+	padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+	/* probedelay */
+	padhocjoin->probedelay =
+	    cpu_to_le16(cmd_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)) {
+		lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
+		ret = -1;
+		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 =
+	    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,
+					    cmd_802_11_ps_mode,
+					    cmd_act_set,
+					    0, 0, &Localpsmode);
+
+		if (ret) {
+			ret = -1;
+			goto done;
+		}
+	}
+
+	if (libertas_parse_dnld_countryinfo_11d(priv)) {
+		ret = -1;
+		goto done;
+	}
+
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
+			     + S_DS_GEN + cmdappendsize);
+
+	memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
+	       sizeof(struct ieeetypes_capinfo));
+	tmpcap = cpu_to_le16(tmpcap);
+
+	memcpy(&padhocjoin->bssdescriptor.cap,
+	       &tmpcap, sizeof(struct ieeetypes_capinfo));
+
+      done:
+	LEAVE();
+	return ret;
+}
+
+int libertas_ret_80211_associate(wlan_private * priv,
+			      struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	union iwreq_data wrqu;
+	struct ieeetypes_assocrsp *passocrsp;
+	struct bss_descriptor *pbssdesc;
+
+	ENTER();
+
+	passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
+
+	if (passocrsp->statuscode) {
+
+		libertas_mac_event_disconnected(priv);
+
+        lbs_pr_debug(1,
+		       "ASSOC_RESP: Association failed, status code = %d\n",
+		       passocrsp->statuscode);
+
+		ret = -1;
+		goto done;
+	}
+
+	lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+		le16_to_cpu(resp->size) - S_DS_GEN);
+
+	/* Send a Media Connected event, according to the Spec */
+	adapter->connect_status = libertas_connected;
+
+	/* Set the attempted BSSID Index to current */
+	pbssdesc = adapter->pattemptedbssdesc;
+
+	lbs_pr_debug(1, "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));
+
+	lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
+	       adapter->currentpacketfilter);
+
+	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);
+
+	lbs_pr_debug(1, "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;
+}
+
+int libertas_ret_80211_disassociate(wlan_private * priv,
+				 struct cmd_ds_command *resp)
+{
+	ENTER();
+
+	libertas_mac_event_disconnected(priv);
+
+	LEAVE();
+	return 0;
+}
+
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+				 struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	u16 command = le16_to_cpu(resp->command);
+	u16 result = le16_to_cpu(resp->result);
+	struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+	union iwreq_data wrqu;
+	struct bss_descriptor *pbssdesc;
+
+	ENTER();
+
+	padhocresult = &resp->params.result;
+
+	lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
+	lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
+	lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
+
+	pbssdesc = adapter->pattemptedbssdesc;
+
+	/*
+	 * Join result code 0 --> SUCCESS
+	 */
+	if (result) {
+		lbs_pr_debug(1, "ADHOC_RESP failed\n");
+		if (adapter->connect_status == libertas_connected) {
+			libertas_mac_event_disconnected(priv);
+		}
+
+		memset(&adapter->curbssparams.bssdescriptor,
+		       0x00, sizeof(adapter->curbssparams.bssdescriptor));
+
+		LEAVE();
+		return -1;
+	}
+
+	/*
+	 * Now the join cmd should be successful
+	 * If BSSID has changed use SSID to compare instead of BSSID
+	 */
+	lbs_pr_debug(1, "ADHOC_J_RESP  %s\n", pbssdesc->ssid.ssid);
+
+	/* Send a Media Connected event, according to the Spec */
+	adapter->connect_status = libertas_connected;
+
+	if (command == cmd_ret_802_11_ad_hoc_start) {
+		/* 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);
+
+	lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
+	lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
+	lbs_pr_debug(1, "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;
+}
+
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+				struct cmd_ds_command *resp)
+{
+	ENTER();
+
+	libertas_mac_event_disconnected(priv);
+
+	LEAVE();
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
new file mode 100644
index 0000000..8efa245
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * 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
+  */
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+#include "defs.h"
+
+struct cmd_ds_command;
+extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+				       struct cmd_ds_command *cmd,
+				       void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+				       struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+					struct cmd_ds_command *cmd,
+					void *pssid);
+extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+					  struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_associate(wlan_private * priv,
+				     struct cmd_ds_command *cmd,
+				     void *pdata_buf);
+
+extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+					struct cmd_ds_command *resp);
+extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+				       struct cmd_ds_command *resp);
+extern int libertas_ret_80211_disassociate(wlan_private * priv,
+					struct cmd_ds_command *resp);
+extern int libertas_ret_80211_associate(wlan_private * priv,
+				     struct cmd_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);
+
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc);
+
+#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
new file mode 100644
index 0000000..4970465
--- /dev/null
+++ b/drivers/net/wireless/libertas/main.c
@@ -0,0 +1,1258 @@
+/**
+  * This file contains the major functions in WLAN
+  * driver. It includes init, exit, open, close and main
+  * thread etc..
+  */
+
+#include <linux/delay.h>
+#include <linux/freezer.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 "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "assoc.h"
+
+#ifdef ENABLE_PM
+static struct pm_dev *wlan_pm_dev = NULL;
+#endif
+
+#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;
+
+#define MAX_DEVS 5
+static struct net_device *libertas_devs[MAX_DEVS];
+static int libertas_found = 0;
+
+/**
+ * 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";
+
+/**
+ * Attributes exported through sysfs
+ */
+#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+
+/**
+ * @brief Get function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_get(struct class_device * dev, char * buf) {
+	struct cmd_ds_mesh_access mesh_access;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+			cmd_mesh_access,
+			cmd_act_mesh_get_mpp,
+			cmd_option_waitforrsp, 0, (void *)&mesh_access);
+
+	return snprintf(buf, 3, "%d\n", mesh_access.data[0]);
+}
+
+/**
+ * @brief Set function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_set(struct class_device * dev, const char * buf,
+		size_t count) {
+	struct cmd_ds_mesh_access mesh_access;
+
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	sscanf(buf, "%d", &(mesh_access.data[0]));
+	libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+			cmd_mesh_access,
+			cmd_act_mesh_set_mpp,
+			cmd_option_waitforrsp, 0, (void *)&mesh_access);
+	return strlen(buf);
+}
+
+/**
+ * libertas_mpp attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-mpp)
+ */
+static CLASS_DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get,
+		libertas_mpp_set );
+
+/**
+ *  @brief Check if the device can be open and wait if necessary.
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ *
+ * 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.
+ *
+ */
+static int pre_open_check(struct net_device *dev) {
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	int i = 0;
+
+	while (!adapter->fw_ready && i < 20) {
+		i++;
+		msleep_interruptible(100);
+	}
+	if (!adapter->fw_ready) {
+		lbs_pr_info("FW not ready, pre_open_check() return failure\n");
+		LEAVE();
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ *  @brief This function opens the device
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int wlan_dev_open(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+
+	priv->open = 1;
+
+	if (adapter->connect_status == libertas_connected) {
+		netif_carrier_on(priv->wlan_dev.netdev);
+	} else
+		netif_carrier_off(priv->wlan_dev.netdev);
+
+	LEAVE();
+	return 0;
+}
+/**
+ *  @brief This function opens the mshX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int mesh_open(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv ;
+
+	if(pre_open_check(dev) == -1)
+		return -1;
+	priv->mesh_open = 1 ;
+	netif_start_queue(priv->mesh_dev);
+	if (priv->infra_open == 0)
+		return wlan_dev_open(priv->wlan_dev.netdev) ;
+	return 0;
+}
+
+/**
+ *  @brief This function opens the ethX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int wlan_open(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv ;
+
+	if(pre_open_check(dev) == -1)
+		return -1;
+	priv->infra_open = 1 ;
+	netif_wake_queue(priv->wlan_dev.netdev);
+	if (priv->open == 0)
+		return wlan_dev_open(priv->wlan_dev.netdev) ;
+	return 0;
+}
+
+static int wlan_dev_close(struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+
+	ENTER();
+
+	netif_carrier_off(priv->wlan_dev.netdev);
+	priv->open = 0;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief This function closes the mshX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int mesh_close(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) (dev->priv);
+
+	priv->mesh_open = 0;
+	netif_stop_queue(priv->mesh_dev);
+	if (priv->infra_open == 0)
+		return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+	else
+		return 0;
+}
+
+/**
+ *  @brief This function closes the ethX interface
+ *
+ *  @param dev     A pointer to net_device structure
+ *  @return 	   0
+ */
+static int wlan_close(struct net_device *dev) {
+	wlan_private *priv = (wlan_private *) dev->priv;
+
+	netif_stop_queue(priv->wlan_dev.netdev);
+	priv->infra_open = 0;
+	if (priv->mesh_open == 0)
+		return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+	else
+		return 0;
+}
+
+
+#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 	   0 or -1
+ */
+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;
+
+	lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq);
+
+	switch (pmreq) {
+	case PM_SUSPEND:
+		lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n");
+
+		/* in associated mode */
+		if (adapter->connect_status == libertas_connected) {
+			if ((adapter->psstate != PS_STATE_SLEEP)
+			    ) {
+				lbs_pr_debug(1,
+				       "wlan_pm_callback: can't enter sleep mode\n");
+				return -1;
+			} else {
+
+				/*
+				 * Detach the network interface
+				 * if the network is running
+				 */
+				if (netif_running(dev)) {
+					netif_device_detach(dev);
+					lbs_pr_debug(1,
+					       "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->connect_status == libertas_connected) {
+			{
+				/*
+				 * 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);
+					lbs_pr_debug(1,
+					       "after netif_device_attach().\n");
+				}
+				lbs_pr_debug(1,
+				       "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);
+
+		lbs_pr_debug(1, "after netif attach, in NON associated mode.\n");
+		break;
+	}
+
+	return 0;
+}
+#endif				/* ENABLE_PM */
+
+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 Mark mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+	ENTER();
+	SET_MESH_FRAME(skb);
+	LEAVE();
+
+	return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev);
+}
+
+/**
+ * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	ENTER();
+	UNSET_MESH_FRAME(skb);
+	LEAVE();
+	return wlan_hard_start_xmit(skb, dev);
+}
+
+static void wlan_tx_timeout(struct net_device *dev)
+{
+	wlan_private *priv = (wlan_private *) dev->priv;
+
+	ENTER();
+
+	lbs_pr_err("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->connect_status == libertas_connected)
+		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;
+}
+
+static int wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+	int ret = 0;
+	wlan_private *priv = (wlan_private *) dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct sockaddr *phwaddr = addr;
+
+	ENTER();
+
+	memset(adapter->current_addr, 0, ETH_ALEN);
+
+	/* dev->dev_addr is 8 bytes */
+	lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+	lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+	memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
+				    cmd_act_set,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		lbs_pr_debug(1, "set mac address failed.\n");
+		ret = -1;
+		goto done;
+	}
+
+	lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+	memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
+	memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, 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;
+
+}
+
+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) {
+		lbs_pr_debug(1, "enable Promiscuous mode\n");
+		adapter->currentpacketfilter |=
+		    cmd_act_mac_promiscuous_enable;
+		adapter->currentpacketfilter &=
+		    ~(cmd_act_mac_all_multicast_enable |
+		      cmd_act_mac_multicast_enable);
+	} else {
+		/* Multicast */
+		adapter->currentpacketfilter &=
+		    ~cmd_act_mac_promiscuous_enable;
+
+		if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+		    MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+			lbs_pr_debug(1, "Enabling All Multicast!\n");
+			adapter->currentpacketfilter |=
+			    cmd_act_mac_all_multicast_enable;
+			adapter->currentpacketfilter &=
+			    ~cmd_act_mac_multicast_enable;
+		} else {
+			adapter->currentpacketfilter &=
+			    ~cmd_act_mac_all_multicast_enable;
+
+			if (!dev->mc_count) {
+				lbs_pr_debug(1, "No multicast addresses - "
+				       "disabling multicast!\n");
+				adapter->currentpacketfilter &=
+				    ~cmd_act_mac_multicast_enable;
+			} else {
+				int i;
+
+				adapter->currentpacketfilter |=
+				    cmd_act_mac_multicast_enable;
+
+				adapter->nr_of_multicastmacaddr =
+				    wlan_copy_multicast_address(adapter, dev);
+
+				lbs_pr_debug(1, "Multicast addresses: %d\n",
+				       dev->mc_count);
+
+				for (i = 0; i < dev->mc_count; i++) {
+					lbs_pr_debug(1, "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,
+						      cmd_mac_multicast_adr,
+						      cmd_act_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 	   0
+ */
+static int wlan_service_main_thread(void *data)
+{
+	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 (;;) {
+		lbs_pr_debug(1, "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);
+		spin_lock_irq(&adapter->driver_lock);
+		if ((adapter->psstate == PS_STATE_SLEEP) ||
+		    (!adapter->intcounter
+		     && (priv->wlan_dev.dnld_sent || adapter->cur_cmd ||
+			 list_empty(&adapter->cmdpendingq)))) {
+			lbs_pr_debug(1,
+			       "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+			       adapter->connect_status, adapter->intcounter,
+			       adapter->psmode, adapter->psstate);
+			spin_unlock_irq(&adapter->driver_lock);
+			schedule();
+		} else
+			spin_unlock_irq(&adapter->driver_lock);
+
+
+		lbs_pr_debug(1,
+		       "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();
+
+		lbs_pr_debug(1, "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) {
+			lbs_pr_debug(1,
+			       "main-thread: break from main thread: surpriseremoved=0x%x\n",
+			       adapter->surpriseremoved);
+			break;
+		}
+
+
+		spin_lock_irq(&adapter->driver_lock);
+		if (adapter->intcounter) {
+			u8 int_status;
+			adapter->intcounter = 0;
+			int_status = libertas_sbi_get_int_status(priv, &ireg);
+
+			if (int_status) {
+				lbs_pr_debug(1,
+				       "main-thread: reading HOST_INT_STATUS_REG failed\n");
+				spin_unlock_irq(&adapter->driver_lock);
+				continue;
+			}
+			adapter->hisregcpy |= ireg;
+		}
+
+		lbs_pr_debug(1, "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) {
+			lbs_pr_debug(1, "main-thread: cmd response ready.\n");
+
+			adapter->hisregcpy &= ~his_cmdupldrdy;
+			spin_unlock_irq(&adapter->driver_lock);
+			libertas_process_rx_command(priv);
+			spin_lock_irq(&adapter->driver_lock);
+		}
+
+		/* Any Card Event */
+		if (adapter->hisregcpy & his_cardevent) {
+			lbs_pr_debug(1, "main-thread: Card Event Activity.\n");
+
+			adapter->hisregcpy &= ~his_cardevent;
+
+			if (libertas_sbi_read_event_cause(priv)) {
+				lbs_pr_alert(
+				       "main-thread: libertas_sbi_read_event_cause failed.\n");
+				spin_unlock_irq(&adapter->driver_lock);
+				continue;
+			}
+			spin_unlock_irq(&adapter->driver_lock);
+			libertas_process_event(priv);
+		} else
+			spin_unlock_irq(&adapter->driver_lock);
+
+		/* Check if we need to confirm Sleep Request received previously */
+		if (adapter->psstate == PS_STATE_PRE_SLEEP) {
+			if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) {
+				if (adapter->connect_status ==
+				    libertas_connected) {
+					lbs_pr_debug(1,
+					       "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
+					       "dnld_sent=%d cur_cmd=%p, confirm now\n",
+					       adapter->intcounter,
+					       adapter->currenttxskb,
+					       priv->wlan_dev.dnld_sent,
+					       adapter->cur_cmd);
+
+					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;
+					lbs_pr_alert(
+					       "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 && !priv->adapter->cur_cmd)
+			libertas_execute_next_command(priv);
+
+		/* Wake-up command waiters which can't sleep in
+		 * libertas_prepare_and_send_command
+		 */
+		if (!adapter->nr_cmd_pending)
+			wake_up_all(&adapter->cmd_pending);
+
+		libertas_tx_runqueue(priv);
+	}
+
+	del_timer(&adapter->command_timer);
+	adapter->nr_cmd_pending = 0;
+	wake_up_all(&adapter->cmd_pending);
+	wlan_deactivate_thread(thread);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ * @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
+ */
+wlan_private *wlan_add_card(void *card)
+{
+	struct net_device *dev = NULL;
+	struct net_device *mesh_dev = NULL;
+	wlan_private *priv = NULL;
+
+	ENTER();
+
+	/* Allocate an Ethernet device and register it */
+	if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+		lbs_pr_alert( "Init ethernet device failed!\n");
+		return NULL;
+	}
+
+	priv = dev->priv;
+
+	/* allocate buffer for wlan_adapter */
+	if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+		lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n");
+		goto err_kmalloc;
+	}
+
+	/* Allocate a virtual mesh device */
+	if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
+		lbs_pr_debug(1, "Init ethernet device failed!\n");
+		return NULL;
+	}
+
+	/* Both intervaces share the priv structure */
+	mesh_dev->priv = priv;
+
+	/* init wlan_adapter */
+	memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+	priv->wlan_dev.netdev = dev;
+	priv->wlan_dev.card = card;
+	priv->mesh_open = 0;
+	priv->infra_open = 0;
+	priv->mesh_dev = mesh_dev;
+	wlanpriv = priv;
+
+	SET_MODULE_OWNER(dev);
+	SET_MODULE_OWNER(mesh_dev);
+
+	/* Setup the OS Interface to our functions */
+	dev->open = wlan_open;
+	dev->hard_start_xmit = wlan_pre_start_xmit;
+	dev->stop = wlan_close;
+	dev->do_ioctl = libertas_do_ioctl;
+	dev->set_mac_address = wlan_set_mac_address;
+	mesh_dev->open = mesh_open;
+	mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
+	mesh_dev->stop = mesh_close;
+	mesh_dev->do_ioctl = libertas_do_ioctl;
+	memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr,
+			sizeof(wlanpriv->wlan_dev.netdev->dev_addr));
+
+#define	WLAN_WATCHDOG_TIMEOUT	(5 * HZ)
+
+	dev->tx_timeout = wlan_tx_timeout;
+	dev->get_stats = wlan_get_stats;
+	dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT;
+	dev->ethtool_ops = &libertas_ethtool_ops;
+	mesh_dev->get_stats = wlan_get_stats;
+	mesh_dev->ethtool_ops = &libertas_ethtool_ops;
+
+#ifdef	WIRELESS_EXT
+	dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+	mesh_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_LIST_HEAD(&priv->adapter->cmdfreeq);
+	INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+
+	spin_lock_init(&priv->adapter->driver_lock);
+	init_waitqueue_head(&priv->adapter->cmd_pending);
+	priv->adapter->nr_cmd_pending = 0;
+
+	lbs_pr_debug(1, "Starting kthread...\n");
+	priv->mainthread.priv = priv;
+	wlan_create_thread(wlan_service_main_thread,
+			   &priv->mainthread, "wlan_main_service");
+
+	priv->assoc_thread =
+		create_singlethread_workqueue("libertas_assoc");
+	INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker);
+
+	/*
+	 * 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) {
+		lbs_pr_info("failed to register wlan device!\n");
+		goto err_registerdev;
+	}
+
+	/* init FW and HW */
+	if (libertas_init_fw(priv)) {
+		lbs_pr_debug(1, "Firmware Init failed\n");
+		goto err_registerdev;
+	}
+
+	if (register_netdev(dev)) {
+		lbs_pr_err("Cannot register network device!\n");
+		goto err_init_fw;
+	}
+
+	/* Register virtual mesh interface */
+	if (register_netdev(mesh_dev)) {
+		lbs_pr_info("Cannot register mesh virtual interface!\n");
+		goto err_init_fw;
+	}
+
+	lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name);
+
+	libertas_debugfs_init_one(priv, dev);
+
+	if (libertas_found == MAX_DEVS)
+		goto err_init_fw;
+	libertas_devs[libertas_found] = dev;
+	libertas_found++;
+#ifdef ENABLE_PM
+	if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback)))
+		lbs_pr_alert( "failed to register PM callback\n");
+#endif
+	if (class_device_create_file(&(mesh_dev->class_dev), &class_device_attr_libertas_mpp))
+		goto err_create_file;
+
+	LEAVE();
+	return priv;
+
+err_create_file:
+	class_device_remove_file(&(mesh_dev->class_dev), &class_device_attr_libertas_mpp);
+err_init_fw:
+	libertas_sbi_unregister_dev(priv);
+err_registerdev:
+	destroy_workqueue(priv->assoc_thread);
+	/* Stop the thread servicing the interrupts */
+	wake_up_interruptible(&priv->mainthread.waitq);
+	wlan_terminate_thread(&priv->mainthread);
+	kfree(priv->adapter);
+err_kmalloc:
+	free_netdev(dev);
+	free_netdev(mesh_dev);
+	wlanpriv = NULL;
+
+	LEAVE();
+	return NULL;
+}
+
+static void wake_pending_cmdnodes(wlan_private *priv)
+{
+	struct cmd_ctrl_node *cmdnode;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+	list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+		cmdnode->cmdwaitqwoken = 1;
+		wake_up_interruptible(&cmdnode->cmdwait_q);
+	}
+	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+
+int wlan_remove_card(void *card)
+{
+	wlan_private *priv = libertas_sbi_get_priv(card);
+	wlan_adapter *adapter;
+	struct net_device *dev;
+	struct net_device *mesh_dev;
+	union iwreq_data wrqu;
+	int i;
+
+	ENTER();
+
+	if (!priv) {
+		LEAVE();
+		return 0;
+	}
+
+	adapter = priv->adapter;
+
+	if (!adapter) {
+		LEAVE();
+		return 0;
+	}
+
+	dev = priv->wlan_dev.netdev;
+	mesh_dev = priv->mesh_dev;
+
+	netif_stop_queue(mesh_dev);
+	netif_stop_queue(priv->wlan_dev.netdev);
+	netif_carrier_off(priv->wlan_dev.netdev);
+
+	wake_pending_cmdnodes(priv);
+
+	class_device_remove_file(&(mesh_dev->class_dev), &class_device_attr_libertas_mpp);
+	unregister_netdev(mesh_dev);
+	unregister_netdev(dev);
+
+	cancel_delayed_work(&priv->assoc_work);
+	destroy_workqueue(priv->assoc_thread);
+
+	if (adapter->psmode == wlan802_11powermodemax_psp) {
+		adapter->psmode = wlan802_11powermodecam;
+		libertas_ps_wakeup(priv, cmd_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);
+
+#ifdef ENABLE_PM
+	pm_unregister(wlan_pm_dev);
+#endif
+
+	adapter->surpriseremoved = 1;
+
+	/* Stop the thread servicing the interrupts */
+	wlan_terminate_thread(&priv->mainthread);
+
+	libertas_debugfs_remove_one(priv);
+
+	lbs_pr_debug(1, "Free adapter\n");
+	libertas_free_adapter(priv);
+
+	for (i = 0; i<libertas_found; i++) {
+		if (libertas_devs[i]==priv->wlan_dev.netdev) {
+			libertas_devs[i] = libertas_devs[--libertas_found];
+			libertas_devs[libertas_found] = NULL ;
+			break ;
+		}
+	}
+
+	lbs_pr_debug(1, "Unregister finish\n");
+
+	priv->wlan_dev.netdev = NULL;
+	priv->mesh_dev = NULL ;
+	free_netdev(mesh_dev);
+	free_netdev(dev);
+	wlanpriv = NULL;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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++) {
+		lbs_pr_debug(1, "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;
+}
+
+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 {
+			lbs_pr_debug(1, "wrong region code %#x in band B-G\n",
+			       region);
+			return -1;
+		}
+		adapter->region_channel[i].valid = 1;
+		adapter->region_channel[i].region = region;
+		adapter->region_channel[i].band = band;
+		i++;
+	}
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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();
+
+	lbs_pr_debug(1, "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();
+}
+
+static int wlan_init_module(void)
+{
+	int ret = 0;
+
+	ENTER();
+
+	if (libertas_fw_name == NULL) {
+		libertas_fw_name = default_fw_name;
+	}
+
+	libertas_debugfs_init();
+
+	if (libertas_sbi_register()) {
+		ret = -1;
+		libertas_debugfs_remove();
+		goto done;
+	}
+
+done:
+	LEAVE();
+	return ret;
+}
+
+static void wlan_cleanup_module(void)
+{
+	int i;
+
+	ENTER();
+
+	for (i = 0; i<libertas_found; i++) {
+		wlan_private *priv = libertas_devs[i]->priv;
+		reset_device(priv);
+	}
+
+	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 --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
new file mode 100644
index 0000000..5d118f4
--- /dev/null
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -0,0 +1,57 @@
+#include <net/ieee80211_radiotap.h>
+
+struct tx_radiotap_hdr {
+	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 rx_radiotap_hdr {
+	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 --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644
index 0000000..7e3f78f
--- /dev/null
+++ b/drivers/net/wireless/libertas/rx.c
@@ -0,0 +1,459 @@
+/**
+  * This file contains the handling of RX in wlan driver.
+  */
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "dev.h"
+#include "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 process_rxed_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 *p_rx_pd)
+{
+	wlan_adapter *adapter = priv->adapter;
+	if (adapter->numSNRNF < adapter->data_avg_factor)
+		adapter->numSNRNF++;
+	adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
+	adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->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 *p_rx_pd)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
+	lbs_pr_debug(1, "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] = p_rx_pd->snr;
+	adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+	wlan_save_rawSNRNF(priv, p_rx_pd);
+
+	adapter->rxpd_rate = p_rx_pd->rx_rate;
+
+	adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
+	adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
+	lbs_pr_debug(1, "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();
+}
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+	lbs_pr_debug(1, "skb->data=%p\n", skb->data);
+
+	if(IS_MESH_FRAME(skb))
+		skb->dev = priv->mesh_dev;
+	else
+		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 	   0 or -1
+ */
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	struct rxpackethdr *p_rx_pkt;
+	struct rxpd *p_rx_pd;
+
+	int hdrchop;
+	struct ethhdr *p_ethhdr;
+
+	const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+	ENTER();
+
+	if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
+		lbs_dbg_hex("RX packet: ", skb->data,
+			 min_t(unsigned int, skb->len, 100));
+
+	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+		return process_rxed_802_11_packet(priv, skb);
+
+	p_rx_pkt = (struct rxpackethdr *) skb->data;
+	p_rx_pd = &p_rx_pkt->rx_pd;
+	if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+		SET_MESH_FRAME(skb);
+	else
+		UNSET_MESH_FRAME(skb);
+
+	lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+		 min_t(unsigned int, skb->len, 100));
+
+	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+		lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+		priv->stats.rx_length_errors++;
+		ret = 0;
+		goto done;
+	}
+
+	/*
+	 * Check rxpd status and update 802.3 stat,
+	 */
+	if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
+		lbs_pr_debug(1, "RX error: frame received with bad status\n");
+		lbs_pr_alert("rxpd Not OK\n");
+		priv->stats.rx_errors++;
+		ret = 0;
+		goto done;
+	}
+
+	lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+	       skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+	lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+		sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+	lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+		sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+	if (memcmp(&p_rx_pkt->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.
+		 */
+		p_ethhdr = (struct ethhdr *)
+		    ((u8 *) & p_rx_pkt->eth803_hdr
+		     + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
+		     - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
+		     - sizeof(p_rx_pkt->eth803_hdr.src_addr)
+		     - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
+
+		memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
+		       sizeof(p_ethhdr->h_source));
+		memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
+		       sizeof(p_ethhdr->h_dest));
+
+		/* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
+		 *   that was removed
+		 */
+		hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+	} else {
+		lbs_dbg_hex("RX Data: LLC/SNAP",
+			(u8 *) & p_rx_pkt->rfc1042_hdr,
+			sizeof(p_rx_pkt->rfc1042_hdr));
+
+		/* Chop off the rxpd */
+		hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
+	}
+
+	/* 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(p_rx_pd->rx_rate);
+
+	wlan_compute_rssi(priv, p_rx_pd);
+
+	lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+	if (libertas_upload_rx_packet(priv, skb)) {
+		lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
+		       " returns failure\n");
+		ret = -1;
+		goto done;
+	}
+	priv->stats.rx_bytes += skb->len;
+	priv->stats.rx_packets++;
+
+	ret = 0;
+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;
+	}
+	lbs_pr_alert( "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 	   0 or -1
+ */
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+
+	struct rx80211packethdr *p_rx_pkt;
+	struct rxpd *prxpd;
+	struct rx_radiotap_hdr radiotap_hdr;
+	struct rx_radiotap_hdr *pradiotap_hdr;
+
+	ENTER();
+
+	p_rx_pkt = (struct rx80211packethdr *) skb->data;
+	prxpd = &p_rx_pkt->rx_pd;
+
+	// lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+
+	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+		lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+		priv->stats.rx_length_errors++;
+		ret = 0;
+		goto done;
+	}
+
+	/*
+	 * Check rxpd status and update 802.3 stat,
+	 */
+	if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
+		//lbs_pr_debug(1, "RX error: frame received with bad status\n");
+		priv->stats.rx_errors++;
+	}
+
+	lbs_pr_debug(1, "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 rx_radiotap_hdr);
+		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->rx_rate);
+		/* 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);
+
+		// lbs_dbg_hex1("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 rx_radiotap_hdr)) &&
+		    pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
+				     GFP_ATOMIC)) {
+			lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
+			       __func__);
+		}
+
+		pradiotap_hdr =
+		    (struct rx_radiotap_hdr *)skb_push(skb,
+						     sizeof(struct
+							    rx_radiotap_hdr));
+		memcpy(pradiotap_hdr, &radiotap_hdr,
+		       sizeof(struct rx_radiotap_hdr));
+		//lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
+		break;
+
+	default:
+		/* unknown header */
+		lbs_pr_alert( "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->rx_rate);
+	}
+
+	wlan_compute_rssi(priv, prxpd);
+
+	lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+
+	if (libertas_upload_rx_packet(priv, skb)) {
+		lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
+			"returns failure\n");
+		ret = -1;
+		goto done;
+	}
+
+	priv->stats.rx_bytes += skb->len;
+	priv->stats.rx_packets++;
+
+	ret = 0;
+done:
+	LEAVE();
+
+	skb->protocol = __constant_htons(0x0019);	/* ETH_P_80211_RAW */
+
+	return (ret);
+}
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h
new file mode 100644
index 0000000..59d3a59c
--- /dev/null
+++ b/drivers/net/wireless/libertas/sbi.h
@@ -0,0 +1,40 @@
+/**
+  * This file contains IF layer definitions.
+  */
+
+#ifndef	_SBI_H_
+#define	_SBI_H_
+
+#include <linux/interrupt.h>
+
+#include "defs.h"
+
+/** INT status Bit Definition*/
+#define his_cmddnldrdy			0x01
+#define his_cardevent			0x02
+#define his_cmdupldrdy			0x04
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN			32
+#endif
+
+#define SBI_EVENT_CAUSE_SHIFT		3
+
+/* Probe and Check if the card is present*/
+int libertas_sbi_register_dev(wlan_private * priv);
+int libertas_sbi_unregister_dev(wlan_private *);
+int libertas_sbi_get_int_status(wlan_private * priv, u8 *);
+int libertas_sbi_register(void);
+void libertas_sbi_unregister(void);
+int libertas_sbi_prog_firmware(wlan_private *);
+
+int libertas_sbi_read_event_cause(wlan_private *);
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+wlan_private *libertas_sbi_get_priv(void *card);
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private *);
+int libertas_sbi_resume(wlan_private *);
+#endif
+
+#endif				/* _SBI_H */
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
new file mode 100644
index 0000000..e187062
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.c
@@ -0,0 +1,2044 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * 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.
+  */
+#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 "decl.h"
+#include "dev.h"
+#include "scan.h"
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
+                             + IW_ESSID_MAX_SIZE        \
+                             + IW_EV_UINT_LEN           \
+                             + IW_EV_FREQ_LEN           \
+                             + IW_EV_QUAL_LEN           \
+                             + IW_ESSID_MAX_SIZE        \
+                             + 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 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 is_network_compatible(wlan_adapter * adapter, int index, int mode)
+{
+	ENTER();
+
+	if (adapter->scantable[index].inframode == 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 */
+            lbs_pr_debug(1,
+			       "is_network_compatible() 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 */
+            lbs_pr_debug(1,
+			       "is_network_compatible() 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 */
+            lbs_pr_debug(1,
+			       "is_network_compatible() 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 */
+        lbs_pr_debug(1,
+		       "is_network_compatible() 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->connect_status == libertas_connected) {
+		/* 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++) {
+		lbs_pr_debug(1, "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 < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
+		if (priv->adapter->enable11d &&
+		    adapter->connect_status != libertas_connected) {
+			/* 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 (priv->adapter->enable11d) {
+				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 =
+				    cmd_scan_radio_type_bg;
+				break;
+			}
+
+			if (scantype == cmd_scan_type_passive) {
+				scanchanlist[chanidx].maxscantime =
+				    cpu_to_le16
+				    (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+				scanchanlist[chanidx].chanscanmode.passivescan =
+				    1;
+			} else {
+				scanchanlist[chanidx].maxscantime =
+				    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 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                 resulting scan configuration
+ */
+static struct wlan_scan_cmd_config *
+wlan_scan_setup_scan_config(wlan_private * priv,
+			    const struct wlan_ioctl_user_scan_cfg * puserscanin,
+			    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;
+	struct wlan_scan_cmd_config * pscancfgout = NULL;
+	u8 *ptlvpos;
+	u16 numprobes;
+	u16 ssidlen;
+	int chanidx;
+	int scantype;
+	int scandur;
+	int channel;
+	int radiotype;
+
+	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+	if (pscancfgout == NULL)
+		goto out;
+
+	/* 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 = cpu_to_le16(TLV_TYPE_SSID);
+			pssidtlv->header.len = 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 =
+		    cpu_to_le16(TLV_TYPE_NUMPROBES);
+		pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
+		pnumprobestlv->numprobes = cpu_to_le16(numprobes);
+
+		ptlvpos +=
+		    sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
+
+		pnumprobestlv->header.len =
+		    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) {
+
+		lbs_pr_debug(1, "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 == cmd_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 == cmd_scan_type_passive) {
+					scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+				} else {
+					scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+				}
+			}
+
+			(pscanchanlist + chanidx)->minscantime =
+			    cpu_to_le16(scandur);
+			(pscanchanlist + chanidx)->maxscantime =
+			    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;
+			lbs_pr_debug(1, "Scan: Scanning current channel only");
+		}
+
+	} else {
+		lbs_pr_debug(1, "Scan: Creating full region channel list\n");
+		wlan_scan_create_channel_list(priv, pscanchanlist,
+					      *pfilteredscan);
+	}
+
+out:
+	return pscancfgout;
+}
+
+/**
+ *  @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                0 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 = 0;
+
+	ENTER();
+
+	if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
+		lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
+		       pscancfgout, pchantlvout, pscanchanlist);
+		return -1;
+	}
+
+	pchantlvout->header.type = 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) {
+
+            lbs_pr_debug(1,
+                    "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, cmd_802_11_scan, 0,
+					    0, 0, pscancfgout);
+	}
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @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              0 or < 0 if error
+ */
+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 * scan_chan_list = NULL;
+	struct wlan_scan_cmd_config * scan_cfg = NULL;
+	u8 keeppreviousscan;
+	u8 filteredscan;
+	u8 scancurrentchanonly;
+	int maxchanperscan;
+	int ret;
+
+	ENTER();
+
+	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
+				WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+	if (scan_chan_list == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	scan_cfg = wlan_scan_setup_scan_config(priv,
+					       puserscanin,
+					       &pchantlvout,
+					       scan_chan_list,
+					       &maxchanperscan,
+					       &filteredscan,
+					       &scancurrentchanonly);
+	if (scan_cfg == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	keeppreviousscan = 0;
+
+	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,
+				     scan_cfg,
+				     pchantlvout,
+				     scan_chan_list);
+
+	/*  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->connect_status == libertas_connected) {
+		netif_carrier_on(priv->wlan_dev.netdev);
+		netif_wake_queue(priv->wlan_dev.netdev);
+	}
+
+out:
+	if (scan_cfg)
+		kfree(scan_cfg);
+
+	if (scan_chan_list)
+		kfree(scan_chan_list);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @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;
+
+	lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
+	lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
+
+	while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
+		tlvtype = le16_to_cpu(pcurrenttlv->header.type);
+		tlvlen = le16_to_cpu(pcurrenttlv->header.len);
+
+		switch (tlvtype) {
+		case TLV_TYPE_TSFTIMESTAMP:
+			*ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
+			break;
+
+		default:
+			lbs_pr_debug(1, "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             0 or -1
+ */
+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 = le16_to_cpu(beaconsize);
+		*bytesleft -= sizeof(beaconsize);
+		*pbeaconinfo += sizeof(beaconsize);
+	}
+
+	if (beaconsize == 0 || beaconsize > *bytesleft) {
+
+		*pbeaconinfo += *bytesleft;
+		*bytesleft = 0;
+
+		return -1;
+	}
+
+	/* 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);
+	lbs_pr_debug(1, "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) {
+		lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
+		return -1;
+	}
+
+	/*
+	 * next 4 fields are RSSI, time stamp, beacon interval,
+	 *   and capability information
+	 */
+
+	/* RSSI is 1 byte long */
+	pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
+	lbs_pr_debug(1, "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 = le16_to_cpu(fixedie.beaconinterval);
+	pcurrentptr += 2;
+	bytesleftforcurrentbeacon -= 2;
+
+	/* capability information is 2 bytes long */
+	memcpy(&fixedie.capabilities, pcurrentptr, 2);
+	lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
+	       fixedie.capabilities);
+	fixedie.capabilities = 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 */
+	lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
+	       bytesleftforcurrentbeacon);
+
+	lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
+		bytesleftforcurrentbeacon);
+
+	if (pcap->privacy) {
+		lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
+		pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
+	} else {
+		pBSSEntry->privacy = wlan802_11privfilteracceptall;
+	}
+
+	if (pcap->ibss == 1) {
+		pBSSEntry->inframode = wlan802_11ibss;
+	} else {
+		pBSSEntry->inframode = wlan802_11infrastructure;
+	}
+
+	/* process variable IE */
+	while (bytesleftforcurrentbeacon >= 2) {
+		elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
+		elemlen = *((u8 *) pcurrentptr + 1);
+
+		if (bytesleftforcurrentbeacon < elemlen) {
+			lbs_pr_debug(1, "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);
+			lbs_pr_debug(1, "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:
+			lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
+			pBSSEntry->extra_ie = 1;
+			break;
+
+		case FH_PARAM_SET:
+			pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+			memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
+				sizeof(struct ieeetypes_fhparamset));
+			pBSSEntry->phyparamset.fhparamset.dwelltime
+			    =
+			    le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
+					     dwelltime);
+			break;
+
+		case DS_PARAM_SET:
+			pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+
+			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 =
+			    le32_to_cpu(pibss->atimwindow);
+
+			memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
+				sizeof(struct ieeetypes_ibssparamset));
+
+			pBSSEntry->ssparamset.ibssparamset.atimwindow
+			    =
+			    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) {
+				lbs_pr_debug(1, "InterpretIE: 11D- Err "
+				       "CountryInfo len =%d min=%d max=254\n",
+				       pcountryinfo->len,
+				       sizeof(pcountryinfo->countrycode));
+				LEAVE();
+				return -1;
+			}
+
+			memcpy(&pBSSEntry->countryinfo,
+			       pcountryinfo, pcountryinfo->len + 2);
+			lbs_dbg_hex("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);
+				lbs_dbg_hex("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);
+
+			lbs_dbg_hex("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 0;
+}
+
+/**
+ *  @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;
+
+	lbs_pr_debug(1, "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 = is_network_compatible(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;
+
+	lbs_pr_debug(1, "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 = is_network_compatible(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,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
+{
+	int bestnet = -ENETUNREACH;
+	u8 bestrssi = 0;
+	int i;
+
+	ENTER();
+
+	lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
+
+	for (i = 0; i < adapter->numinscantable; i++) {
+		switch (mode) {
+		case wlan802_11infrastructure:
+		case wlan802_11ibss:
+			if (is_network_compatible(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             0--success, otherwise--fail
+ */
+int libertas_find_best_network_SSID(wlan_private * priv,
+                                    struct WLAN_802_11_SSID *pSSID,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+                                    enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct bss_descriptor *preqbssid;
+	int i;
+
+	ENTER();
+
+	memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
+
+	wlan_scan_networks(priv, NULL);
+	if (adapter->surpriseremoved)
+		return -1;
+	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+	i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
+	if (i < 0) {
+		ret = -1;
+		goto out;
+	}
+
+	preqbssid = &adapter->scantable[i];
+	memcpy(pSSID, &preqbssid->ssid,
+	       sizeof(struct WLAN_802_11_SSID));
+	*out_mode = preqbssid->inframode;
+
+	if (!pSSID->ssidlength) {
+		ret = -1;
+	}
+
+out:
+	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             0 --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();
+
+	if (!wlan_scan_networks(priv, NULL)) {
+		memset(&wrqu, 0, sizeof(union iwreq_data));
+		wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+				    NULL);
+	}
+
+	if (adapter->surpriseremoved)
+		return -1;
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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                0-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 -1;
+	}
+
+	memset(&scancfg, 0x00, sizeof(scancfg));
+
+	memcpy(scancfg.specificSSID, prequestedssid->ssid,
+	       prequestedssid->ssidlength);
+	scancfg.keeppreviousscan = keeppreviousscan;
+
+	wlan_scan_networks(priv, &scancfg);
+	if (adapter->surpriseremoved)
+		return -1;
+	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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          0-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 -1;
+	}
+
+	memset(&scancfg, 0x00, sizeof(scancfg));
+	memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
+	scancfg.keeppreviousscan = keeppreviousscan;
+
+	wlan_scan_networks(priv, &scancfg);
+	if (priv->adapter->surpriseremoved)
+		return -1;
+	wait_event_interruptible(priv->adapter->cmd_pending,
+		!priv->adapter->nr_cmd_pending);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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             0 --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 = 0;
+	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 there's either commands in the queue or one being
+	 * processed return -EAGAIN for iwlist to retry later.
+	 */
+    if (adapter->nr_cmd_pending)
+		return -EAGAIN;
+
+	if (adapter->connect_status == libertas_connected)
+		lbs_pr_debug(1, "Current ssid: %32s\n",
+		       adapter->curbssparams.ssid.ssid);
+
+	lbs_pr_debug(1, "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) {
+			lbs_pr_debug(1, "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];
+
+		lbs_pr_debug(1, "i=%d  ssid: %32s\n", i, pscantable->ssid.ssid);
+
+		cfp =
+		    libertas_find_cfp_by_band_and_channel(adapter, 0,
+						 pscantable->channel);
+		if (!cfp) {
+			lbs_pr_debug(1, "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].inframode + 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->inframode == wlan802_11ibss) &&
+		    !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+			     &adapter->scantable[i].ssid)
+		    && adapter->adhoccreate) {
+			ret = libertas_prepare_and_send_command(priv,
+						    cmd_802_11_rssi,
+						    0,
+						    cmd_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].inframode == 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);
+
+			lbs_pr_debug(1, "iwe.u.data.length %d\n",
+			       iwe.u.data.length);
+			lbs_pr_debug(1, "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 0;
+}
+
+/**
+ *  @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 cmd_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 cmd_ds_command structure to be sent to
+ *                    firmware with the cmd_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           0 or -1
+ *
+ *  @sa wlan_scan_create_channel_list
+ */
+int libertas_cmd_80211_scan(wlan_private * priv,
+			 struct cmd_ds_command *cmd, void *pdata_buf)
+{
+	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
+	struct wlan_scan_cmd_config *pscancfg;
+
+	ENTER();
+
+	pscancfg = 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 = cpu_to_le16(cmd_802_11_scan);
+
+	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
+	cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
+				     + sizeof(pscan->BSSID)
+				     + pscancfg->tlvbufferlen + S_DS_GEN);
+
+	lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+	       cmd->command, cmd->size, cmd->seqnum);
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @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 cmd_ds_command
+ *
+ *  @return        0 or -1
+ */
+int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_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->nr_sets > MRVDRV_MAX_BSSID_LIST) {
+        lbs_pr_debug(1,
+		       "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+		       pscan->nr_sets);
+		LEAVE();
+		return -1;
+	}
+
+	bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+	lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
+
+	scanrespsize = le16_to_cpu(resp->size);
+	lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
+	       pscan->nr_sets);
+
+	numintable = adapter->numinscantable;
+	pbssinfo = pscan->bssdesc_and_tlvbuffer;
+
+	/* 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->nr_sets)
+				     + S_DS_GEN);
+
+	ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + 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->nr_sets).  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->nr_sets && 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) ==
+		     0)
+		    && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
+
+            lbs_pr_debug(1,
+			       "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)) {
+                        lbs_pr_debug(1,
+						       "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 = 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 */
+			lbs_pr_debug(1, "SCAN_RESP: "
+			       "InterpretBSSDescriptionWithIE returned ERROR\n");
+		}
+	}
+
+	lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+	       pscan->nr_sets, numintable - adapter->numinscantable,
+	       numintable);
+
+	/* Update the total number of BSSIDs in the scan table */
+	adapter->numinscantable = numintable;
+
+	LEAVE();
+	return 0;
+}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
new file mode 100644
index 0000000..d93aa7f
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.h
@@ -0,0 +1,216 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+  * Interface for the wlan network scan routines
+  *
+  * Driver interface functions and type declarations for the scan module
+  *   implemented in wlan_scan.c.
+  */
+#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[IW_ESSID_MAX_SIZE + 1];
+
+    /**
+     *  @brief Variable number (fixed maximum) of channels to scan up
+     */
+	struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+};
+
+/**
+ *  @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_INFRASTRUCTURE inframode;
+	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];
+
+	__le64 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);
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode);
+extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode);
+
+int libertas_find_best_network_SSID(wlan_private * priv,
+			struct WLAN_802_11_SSID *pSSID,
+			enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+			enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode);
+
+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_cmd_80211_scan(wlan_private * priv,
+				struct cmd_ds_command *cmd,
+				void *pdata_buf);
+
+extern int libertas_ret_80211_scan(wlan_private * priv,
+				struct cmd_ds_command *resp);
+
+int wlan_scan_networks(wlan_private * priv,
+                const struct wlan_ioctl_user_scan_cfg * puserscanin);
+
+struct ifreq;
+
+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				/* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
new file mode 100644
index 0000000..207b8a6
--- /dev/null
+++ b/drivers/net/wireless/libertas/thread.h
@@ -0,0 +1,52 @@
+#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();
+
+	thr->pid = 0;
+
+	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) {
+		printk(KERN_ERR "Thread does not exist\n");
+		return -1;
+	}
+	kthread_stop(thr->task);
+
+	LEAVE();
+	return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
new file mode 100644
index 0000000..82d0622
--- /dev/null
+++ b/drivers/net/wireless/libertas/tx.c
@@ -0,0 +1,285 @@
+/**
+  * This file contains the handling of TX in wlan driver.
+  */
+#include <linux/netdevice.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "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 	   0 or -1
+ */
+static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+{
+	wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	struct txpd localtxpd;
+	struct txpd *plocaltxpd = &localtxpd;
+	u8 *p802x_hdr;
+	struct tx_radiotap_hdr *pradiotap_hdr;
+	u32 new_rate;
+	u8 *ptr = priv->adapter->tmptxbuf;
+
+	ENTER();
+
+	if (priv->adapter->surpriseremoved)
+		return -1;
+
+	if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+		lbs_dbg_hex("TX packet: ", skb->data,
+			 min_t(unsigned int, skb->len, 100));
+
+	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+		lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n",
+		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+		ret = -1;
+		goto done;
+	}
+
+	memset(plocaltxpd, 0, sizeof(struct txpd));
+
+	plocaltxpd->tx_packet_length = skb->len;
+
+	/* offset of actual data */
+	plocaltxpd->tx_packet_location = sizeof(struct txpd);
+
+	/* TxCtrl set by user or default */
+	plocaltxpd->tx_control = adapter->pkttxctrl;
+
+	p802x_hdr = skb->data;
+	if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+
+		/* locate radiotap header */
+		pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+
+		/* set txpd fields from the radiotap header */
+		new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+		if (new_rate != 0) {
+			/* erase tx_control[4:0] */
+			plocaltxpd->tx_control &= ~0x1f;
+			/* write new tx_control[4:0] */
+			plocaltxpd->tx_control |= new_rate;
+		}
+
+		/* skip the radiotap header */
+		p802x_hdr += sizeof(struct tx_radiotap_hdr);
+		plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr);
+
+	}
+	/* copy destination address from 802.3 or 802.11 header */
+	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+	else
+		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+
+	lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+
+	if (IS_MESH_FRAME(skb)) {
+		plocaltxpd->tx_control |= TxPD_MESH_FRAME;
+	}
+
+	memcpy(ptr, plocaltxpd, sizeof(struct txpd));
+
+	ptr += sizeof(struct txpd);
+
+	lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length);
+	memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length);
+	ret = libertas_sbi_host_to_card(priv, MVMS_DAT,
+			       priv->adapter->tmptxbuf,
+			       plocaltxpd->tx_packet_length +
+			       sizeof(struct txpd));
+
+	if (ret) {
+		lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret);
+		goto done;
+	}
+
+	lbs_pr_debug(1, "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 = -1;
+
+	ENTER();
+
+	lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+	if (priv->wlan_dev.dnld_sent) {
+		lbs_pr_alert( "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 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 tx_radiotap_hdr *radiotap_hdr;
+	u32 status = adapter->eventcause;
+	int txfail;
+	int try_count;
+
+	if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+	    adapter->currenttxskb == NULL)
+		return;
+
+	radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+
+	if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+		lbs_dbg_hex("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->connect_status == libertas_connected)
+		netif_wake_queue(priv->wlan_dev.netdev);
+}
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
new file mode 100644
index 0000000..09d62f8
--- /dev/null
+++ b/drivers/net/wireless/libertas/types.h
@@ -0,0 +1,289 @@
+/**
+  * This header file contains definition for global types
+  */
+#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	(~(0xda00))
+
+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));
+
+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));
+
+union IEEEtypes_ssparamset {
+	struct ieeetypes_cfparamset cfparamset;
+	struct ieeetypes_ibssparamset ibssparamset;
+} __attribute__ ((packed));
+
+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));
+
+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*/
+struct mrvlietypesheader {
+	u16 type;
+	u16 len;
+} __attribute__ ((packed));
+
+struct mrvlietypes_data {
+	struct mrvlietypesheader header;
+	u8 Data[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ratesparamset {
+	struct mrvlietypesheader header;
+	u8 rates[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssidparamset {
+	struct mrvlietypesheader header;
+	u8 ssid[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_wildcardssidparamset {
+	struct mrvlietypesheader header;
+	u8 MaxSsidlength;
+	u8 ssid[1];
+} __attribute__ ((packed));
+
+struct chanscanmode {
+	u8 passivescan:1;
+	u8 disablechanfilt:1;
+	u8 reserved_2_7:6;
+} __attribute__ ((packed));
+
+struct chanscanparamset {
+	u8 radiotype;
+	u8 channumber;
+	struct chanscanmode chanscanmode;
+	u16 minscantime;
+	u16 maxscantime;
+} __attribute__ ((packed));
+
+struct mrvlietypes_chanlistparamset {
+	struct mrvlietypesheader header;
+	struct chanscanparamset chanscanparam[1];
+} __attribute__ ((packed));
+
+struct cfparamset {
+	u8 cfpcnt;
+	u8 cfpperiod;
+	u16 cfpmaxduration;
+	u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+struct ibssparamset {
+	u16 atimwindow;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssparamset {
+	struct mrvlietypesheader header;
+	union {
+		struct cfparamset cfparamset[1];
+		struct ibssparamset ibssparamset[1];
+	} cf_ibss;
+} __attribute__ ((packed));
+
+struct fhparamset {
+	u16 dwelltime;
+	u8 hopset;
+	u8 hoppattern;
+	u8 hopindex;
+} __attribute__ ((packed));
+
+struct dsparamset {
+	u8 currentchan;
+} __attribute__ ((packed));
+
+struct mrvlietypes_phyparamset {
+	struct mrvlietypesheader header;
+	union {
+		struct fhparamset fhparamset[1];
+		struct dsparamset dsparamset[1];
+	} fh_ds;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rsnparamset {
+	struct mrvlietypesheader header;
+	u8 rsnie[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_tsftimestamp {
+	struct mrvlietypesheader header;
+	__le64 tsftable[1];
+} __attribute__ ((packed));
+
+/**  Local Power capability */
+struct mrvlietypes_powercapability {
+	struct mrvlietypesheader header;
+	s8 minpower;
+	s8 maxpower;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rssithreshold {
+	struct mrvlietypesheader header;
+	u8 rssivalue;
+	u8 rssifreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_snrthreshold {
+	struct mrvlietypesheader header;
+	u8 snrvalue;
+	u8 snrfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_failurecount {
+	struct mrvlietypesheader header;
+	u8 failvalue;
+	u8 Failfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_beaconsmissed {
+	struct mrvlietypesheader header;
+	u8 beaconmissed;
+	u8 reserved;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numprobes {
+	struct mrvlietypesheader header;
+	u16 numprobes;
+} __attribute__ ((packed));
+
+struct mrvlietypes_bcastprobe {
+	struct mrvlietypesheader header;
+	u16 bcastprobe;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numssidprobe {
+	struct mrvlietypesheader header;
+	u16 numssidprobe;
+} __attribute__ ((packed));
+
+struct led_pin {
+	u8 led;
+	u8 pin;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ledgpio {
+	struct mrvlietypesheader header;
+	struct led_pin ledpin[1];
+} __attribute__ ((packed));
+
+#endif				/* _WLAN_TYPES_ */
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
new file mode 100644
index 0000000..e86f65ae
--- /dev/null
+++ b/drivers/net/wireless/libertas/version.h
@@ -0,0 +1,8 @@
+#define DRIVER_RELEASE_VERSION "320.p0"
+const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef  DEBUG
+    "-dbg"
+#endif
+    "";
+
+
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
new file mode 100644
index 0000000..4a52336
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.c
@@ -0,0 +1,2769 @@
+/**
+  * This file contains ioctl functions
+  */
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitops.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "version.h"
+#include "wext.h"
+#include "assoc.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->enable11d)
+			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)
+		lbs_pr_debug(1, "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->enable11d)
+			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)
+		lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
+		       "band %d & freq %d\n", band, freq);
+
+	return cfp;
+}
+
+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, cmd_802_11_rf_channel,
+				    cmd_opt_802_11_rf_channel_get,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	lbs_pr_debug(1, "Current channel = %d\n",
+	       priv->adapter->curbssparams.channel);
+
+	return ret;
+}
+
+static int setcurrentchannel(wlan_private * priv, int channel)
+{
+	lbs_pr_debug(1, "Set channel = %d\n", channel);
+
+	/*
+	 **  Current channel is not set to adhocchannel requested, set channel
+	 */
+	return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+				      cmd_opt_802_11_rf_channel_set,
+				      cmd_option_waitforrsp, 0, &channel));
+}
+
+static int changeadhocchannel(wlan_private * priv, int channel)
+{
+	int ret = 0;
+	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 0;
+	}
+
+	lbs_pr_debug(1, "Updating channel from %d to %d\n",
+	       adapter->curbssparams.channel, adapter->adhocchannel);
+
+	setcurrentchannel(priv, adapter->adhocchannel);
+
+	updatecurrentchannel(priv);
+
+	if (adapter->curbssparams.channel != adapter->adhocchannel) {
+		lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
+		       adapter->adhocchannel, adapter->curbssparams.channel);
+		LEAVE();
+		return -1;
+	}
+
+	if (adapter->connect_status == libertas_connected) {
+		int i;
+		struct WLAN_802_11_SSID curadhocssid;
+
+		lbs_pr_debug(1, "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 */
+		lbs_pr_debug(1, "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) {
+			lbs_pr_debug(1, "SSID found at %d in List,"
+			       "so join\n", i);
+			libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+		} else {
+			// else send START command
+			lbs_pr_debug(1, "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 0;
+}
+
+/**
+ *  @brief Set Radio On/OFF
+ *
+ *  @param priv                 A pointer to wlan_private structure
+ *  @option 			Radio Option
+ *  @return 	   		0 --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) {
+		lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
+		adapter->radioon = option;
+
+		ret = libertas_prepare_and_send_command(priv,
+					    cmd_802_11_radio_control,
+					    cmd_act_set,
+					    cmd_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->connect_status != libertas_connected) {
+		if (adapter->inframode == wlan802_11infrastructure) {
+			//Infra. mode
+			lbs_pr_debug(1, "Infra\n");
+			k = copyrates(rates, k, libertas_supported_rates,
+				      sizeof(libertas_supported_rates));
+		} else {
+			//ad-hoc mode
+			lbs_pr_debug(1, "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;
+}
+
+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 0;
+}
+
+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)
+			lbs_pr_debug(1, "Invalid channel=%d\n",
+			       adapter->curbssparams.channel);
+		return -EINVAL;
+	}
+
+	fwrq->m = (long)cfp->freq * 100000;
+	fwrq->e = 1;
+
+	lbs_pr_debug(1, "freq=%u\n", fwrq->m);
+
+	LEAVE();
+	return 0;
+}
+
+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->connect_status == libertas_connected) {
+		memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	} else {
+		memset(awrq->sa_data, 0, ETH_ALEN);
+	}
+	awrq->sa_family = ARPHRD_ETHER;
+
+	LEAVE();
+	return 0;
+}
+
+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;
+	}
+
+	mutex_lock(&adapter->lock);
+	memset(adapter->nodename, 0, sizeof(adapter->nodename));
+	memcpy(adapter->nodename, extra, dwrq->length);
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return 0;
+}
+
+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
+	 */
+
+	mutex_lock(&adapter->lock);
+	strncpy(extra, adapter->nodename, 16);
+	mutex_unlock(&adapter->lock);
+
+	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 0;
+}
+
+static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+			struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	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, cmd_802_11_snmp_mib,
+				    cmd_act_set, cmd_option_waitforrsp,
+				    OID_802_11_RTS_THRESHOLD, &rthr);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+			struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	adapter->rtsthsd = 0;
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+				    cmd_act_get, cmd_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 0;
+}
+
+static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	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, cmd_802_11_snmp_mib,
+				    cmd_act_set, cmd_option_waitforrsp,
+				    OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+			 struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	adapter->fragthsd = 0;
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    cmd_act_get, cmd_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;
+}
+
+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->inframode) {
+	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 0;
+}
+
+static int wlan_get_txpow(struct net_device *dev,
+			  struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_rf_tx_power,
+				    cmd_act_tx_power_opt_get,
+				    cmd_option_waitforrsp, 0, NULL);
+
+	if (ret) {
+		LEAVE();
+		return ret;
+	}
+
+	lbs_pr_debug(1, "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 0;
+}
+
+static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+			  struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	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, cmd_802_11_snmp_mib,
+					    cmd_act_set,
+					    cmd_option_waitforrsp,
+					    OID_802_11_TX_RETRYCOUNT, NULL);
+
+		if (ret) {
+			LEAVE();
+			return ret;
+		}
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+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 = 0;
+
+	ENTER();
+	adapter->txretrycount = 0;
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_snmp_mib,
+				    cmd_act_get, cmd_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 0;
+}
+
+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 	   		0 --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;
+	lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+	       range->num_bitrates);
+
+	range->num_frequency = 0;
+	if (priv->adapter->enable11d &&
+	    adapter->connect_status == libertas_connected) {
+		u8 chan_no;
+		u8 band;
+
+		struct parsed_region_chan_11d *parsed_region_chan =
+		    &adapter->parsed_region_chan;
+
+		if (parsed_region_chan == NULL) {
+			lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
+			LEAVE();
+			return 0;
+		}
+		band = parsed_region_chan->band;
+		lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
+		       parsed_region_chan->nr_chan);
+
+		for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+		     && (i < parsed_region_chan->nr_chan); i++) {
+			chan_no = parsed_region_chan->chanpwr[i].chan;
+			lbs_pr_debug(1, "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++;
+			}
+		}
+	}
+
+	lbs_pr_debug(1, "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;
+
+	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+				IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+				IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
+	if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
+		range->enc_capa =   IW_ENC_CAPA_WPA
+		                  | IW_ENC_CAPA_WPA2
+		                  | IW_ENC_CAPA_CIPHER_TKIP
+		                  | IW_ENC_CAPA_CIPHER_CCMP;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+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, cmd_option_waitforrsp);
+		}
+
+		return 0;
+	}
+
+	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		lbs_pr_debug(1,
+		       "Setting power timeout command is not supported\n");
+		return -EINVAL;
+	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+		lbs_pr_debug(1, "Setting power period command is not supported\n");
+		return -EINVAL;
+	}
+
+	if (adapter->psmode != wlan802_11powermodecam) {
+		return 0;
+	}
+
+	adapter->psmode = wlan802_11powermodemax_psp;
+
+	if (adapter->connect_status == libertas_connected) {
+		libertas_ps_sleep(priv, cmd_option_waitforrsp);
+	}
+
+	LEAVE();
+	return 0;
+}
+
+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->connect_status == libertas_disconnected) {
+		LEAVE();
+		return 0;
+	}
+
+	vwrq->value = 0;
+
+	LEAVE();
+	return 0;
+}
+
+/*
+ * 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 }
+	 */
+	{
+	 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_SUBCMD_MESH_SET_TTL,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 IW_PRIV_TYPE_NONE,
+	 "mesh_set_ttl"},
+	{
+	 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_SUBCMD_FWT_CLEANUP,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "fwt_cleanup"},
+	{
+	 WLAN_SUBCMD_FWT_TIME,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "fwt_time"},
+	{
+	 WLAN_SUBCMD_MESH_GET_TTL,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 "mesh_get_ttl"},
+	{
+	 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"},
+	{
+	 WLANWLANIDLEON,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "wlanidle-on"},
+	{
+	 WLANWLANIDLEOFF,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "wlanidle-off"},
+	{
+	 WLAN_SUBCMD_FWT_RESET,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "fwt_reset"},
+	{
+	 WLAN_SUBCMD_BT_RESET,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_NONE,
+	 "bt_reset"},
+	{
+	 WLAN_SET128CHAR_GET128CHAR,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 ""},
+	/* BT Management */
+	{
+	 WLAN_SUBCMD_BT_ADD,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "bt_add"},
+	{
+	 WLAN_SUBCMD_BT_DEL,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "bt_del"},
+	{
+	 WLAN_SUBCMD_BT_LIST,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "bt_list"},
+	/* FWT Management */
+	{
+	 WLAN_SUBCMD_FWT_ADD,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_add"},
+	{
+	 WLAN_SUBCMD_FWT_DEL,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_del"},
+	{
+	 WLAN_SUBCMD_FWT_LOOKUP,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_lookup"},
+	{
+	 WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_list_neigh"},
+	{
+	 WLAN_SUBCMD_FWT_LIST,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_list"},
+	{
+	 WLAN_SUBCMD_FWT_LIST_ROUTE,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "fwt_list_route"},
+	{
+	 WLANSCAN_MODE,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "scanmode"},
+	{
+	 WLAN_GET_ADHOC_STATUS,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 "getadhocstatus"},
+	{
+	 WLAN_SETNONE_GETWORDCHAR,
+	 IW_PRIV_TYPE_NONE,
+	 IW_PRIV_TYPE_CHAR | 128,
+	 ""},
+	{
+	 WLANSETWPAIE,
+	 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+	 IW_PRIV_TYPE_NONE,
+	 "setwpaie"},
+	{
+	 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_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"},
+};
+
+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;
+	u32 rssi_qual;
+	u32 tx_qual;
+	u32 quality = 0;
+	int stats_valid = 0;
+	u8 rssi;
+	u32 tx_retries;
+
+	ENTER();
+
+	priv->wstats.status = adapter->inframode;
+
+	/* If we're not associated, all quality values are meaningless */
+	if (adapter->connect_status != libertas_connected)
+		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]);
+	}
+
+	lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
+	lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
+
+	rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
+	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;
+
+	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 | IW_QUAL_DBM;
+	stats_valid = 1;
+
+	/* update stats asynchronously for future calls */
+	libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+					0, 0, NULL);
+	libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+					0, 0, NULL);
+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;
+
+
+}
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_freq *fwrq, char *extra)
+{
+	int ret = 0;
+	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) {
+			lbs_pr_debug(1, "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->inframode == 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) {
+					lbs_pr_debug(1, "set_freq: WEP enabled\n");
+					ret = libertas_prepare_and_send_command(priv,
+								    cmd_802_11_set_wep,
+								    cmd_act_add,
+								    cmd_option_waitforrsp,
+								    0,
+								    NULL);
+
+					if (ret) {
+						LEAVE();
+						return ret;
+					}
+
+					adapter->currentpacketfilter |=
+					    cmd_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;
+}
+
+static 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 = 0;
+	u8 rates[WLAN_SUPPORTED_RATES];
+	u8 *rate;
+
+	ENTER();
+
+	lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
+
+	if (vwrq->value == -1) {
+		action = cmd_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) {
+			lbs_pr_debug(1, "Rate=0x%X  Wanted=0x%X\n", *rate,
+			       data_rate);
+			if ((*rate & 0x7f) == (data_rate & 0x7f))
+				break;
+			rate++;
+		}
+		if (!*rate) {
+			lbs_pr_alert( "The fixed data rate 0x%X is out "
+			       "of range.\n", data_rate);
+			return -EINVAL;
+		}
+
+		adapter->datarate = data_rate;
+		action = cmd_act_set_tx_fix_rate;
+		adapter->is_datarate_auto = 0;
+	}
+
+	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+				    action, cmd_option_waitforrsp, 0, NULL);
+
+	LEAVE();
+	return ret;
+}
+
+static 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 0;
+}
+
+static int wlan_set_mode(struct net_device *dev,
+		  struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+	ENTER();
+
+	switch (*uwrq) {
+	case IW_MODE_ADHOC:
+		lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n",
+		       adapter->datarate);
+		new_mode = wlan802_11ibss;
+		adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+		break;
+
+	case IW_MODE_INFRA:
+		lbs_pr_debug(1, "Wanted mode is Infrastructure\n");
+		new_mode = wlan802_11infrastructure;
+		break;
+
+	case IW_MODE_AUTO:
+		lbs_pr_debug(1, "Wanted mode is Auto\n");
+		new_mode = wlan802_11autounknown;
+		break;
+
+	default:
+		lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq);
+		return -EINVAL;
+	}
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+	} else {
+		assoc_req->mode = new_mode;
+	}
+
+	if (ret == 0) {
+		set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+
+/**
+ *  @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 	   		0 --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) - 1;
+
+	ENTER();
+
+	lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
+	       dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
+
+	dwrq->flags = 0;
+
+	/* Authentication method */
+	switch (adapter->secinfo.authmode) {
+	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.WPAenabled || adapter->secinfo.WPA2enabled) {
+		dwrq->flags &= ~IW_ENCODE_DISABLED;
+	} else {
+		dwrq->flags |= IW_ENCODE_DISABLED;
+	}
+
+	memset(extra, 0, 16);
+
+	mutex_lock(&adapter->lock);
+
+	/* Default to returning current transmit key */
+	if (index < 0)
+		index = adapter->wep_tx_keyidx;
+
+	if ((adapter->wep_keys[index].len) &&
+	    (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) {
+		memcpy(extra, adapter->wep_keys[index].key,
+		       adapter->wep_keys[index].len);
+		dwrq->length = adapter->wep_keys[index].len;
+
+		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;
+	}
+
+	mutex_unlock(&adapter->lock);
+
+	dwrq->flags |= IW_ENCODE_NOKEY;
+
+	lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
+	       extra[0], extra[1], extra[2],
+	       extra[3], extra[4], extra[5], dwrq->length);
+
+	lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
+
+	LEAVE();
+	return 0;
+}
+
+/**
+ *  @brief Set Encryption key (internal)
+ *
+ *  @param priv			A pointer to private card structure
+ *  @param key_material		A pointer to key material
+ *  @param key_length		length of key material
+ *  @param index		key index to set
+ *  @param set_tx_key		Force set TX key (1 = yes, 0 = no)
+ *  @return 	   		0 --success, otherwise fail
+ */
+static int wlan_set_wep_key(struct assoc_request *assoc_req,
+			    const char *key_material,
+			    u16 key_length,
+			    u16 index,
+			    int set_tx_key)
+{
+	struct WLAN_802_11_KEY *pkey;
+
+	ENTER();
+
+	/* Paranoid validation of key index */
+	if (index > 3) {
+		LEAVE();
+		return -EINVAL;
+	}
+
+	/* validate max key length */
+	if (key_length > KEY_LEN_WEP_104) {
+		LEAVE();
+		return -EINVAL;
+	}
+
+	pkey = &assoc_req->wep_keys[index];
+
+	if (key_length > 0) {
+		memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+		pkey->type = KEY_TYPE_ID_WEP;
+
+		/* Standardize the key length */
+		pkey->len = (key_length > KEY_LEN_WEP_40) ?
+		                KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
+		memcpy(pkey->key, key_material, key_length);
+	}
+
+	if (set_tx_key) {
+		/* Ensure the chosen key is valid */
+		if (!pkey->len) {
+			lbs_pr_debug(1, "key not set, so cannot enable it\n");
+			LEAVE();
+			return -EINVAL;
+		}
+		assoc_req->wep_tx_keyidx = index;
+	}
+
+	assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled;
+
+	LEAVE();
+	return 0;
+}
+
+static int validate_key_index(u16 def_index, u16 raw_index,
+			      u16 *out_index, u16 *is_default)
+{
+	if (!out_index || !is_default)
+		return -EINVAL;
+
+	/* Verify index if present, otherwise use default TX key index */
+	if (raw_index > 0) {
+		if (raw_index > 4)
+			return -EINVAL;
+		*out_index = raw_index - 1;
+	} else {
+		*out_index = def_index;
+		*is_default = 1;
+	}
+	return 0;
+}
+
+static void disable_wep(struct assoc_request *assoc_req)
+{
+	int i;
+
+	/* Set Open System auth mode */
+	assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+
+	/* Clear WEP keys and mark WEP as disabled */
+	assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+	for (i = 0; i < 4; i++)
+		assoc_req->wep_keys[i].len = 0;
+
+	set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+	set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+}
+
+/**
+ *  @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 	   		0 --success, otherwise fail
+ */
+static int wlan_set_encode(struct net_device *dev,
+		    struct iw_request_info *info,
+		    struct iw_point *dwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	u16 is_default = 0, index = 0, set_tx_key = 0;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (dwrq->flags & IW_ENCODE_DISABLED) {
+		disable_wep (assoc_req);
+		goto out;
+	}
+
+	ret = validate_key_index(assoc_req->wep_tx_keyidx,
+	                         (dwrq->flags & IW_ENCODE_INDEX),
+	                         &index, &is_default);
+	if (ret) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* If WEP isn't enabled, or if there is no key data but a valid
+	 * index, set the TX key.
+	 */
+	if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+	    || (dwrq->length == 0 && !is_default))
+		set_tx_key = 1;
+
+	ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+	if (ret)
+		goto out;
+
+	if (dwrq->length)
+		set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+	if (set_tx_key)
+		set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+	if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+		assoc_req->secinfo.authmode = wlan802_11authmodeshared;
+	} else if (dwrq->flags & IW_ENCODE_OPEN) {
+		assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+	}
+
+out:
+	if (ret == 0) {
+		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Get Extended Encryption key (WPA/802.1x and WEP)
+ *
+ *  @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 	   		0 on success, otherwise failure
+ */
+static int wlan_get_encodeext(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *dwrq,
+			      char *extra)
+{
+	int ret = -EINVAL;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int index, max_key_len;
+
+	ENTER();
+
+	max_key_len = dwrq->length - sizeof(*ext);
+	if (max_key_len < 0)
+		goto out;
+
+	index = dwrq->flags & IW_ENCODE_INDEX;
+	if (index) {
+		if (index < 1 || index > 4)
+			goto out;
+		index--;
+	} else {
+		index = adapter->wep_tx_keyidx;
+	}
+
+	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+	    ext->alg != IW_ENCODE_ALG_WEP) {
+		if (index != 0 || adapter->inframode != wlan802_11infrastructure)
+			goto out;
+	}
+
+	dwrq->flags = index + 1;
+	memset(ext, 0, sizeof(*ext));
+
+	if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled)
+	    && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) {
+		ext->alg = IW_ENCODE_ALG_NONE;
+		ext->key_len = 0;
+		dwrq->flags |= IW_ENCODE_DISABLED;
+	} else {
+		u8 *key = NULL;
+
+		if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+		    && !adapter->secinfo.WPAenabled
+		    && !adapter->secinfo.WPA2enabled) {
+			ext->alg = IW_ENCODE_ALG_WEP;
+			ext->key_len = adapter->wep_keys[index].len;
+			key = &adapter->wep_keys[index].key[0];
+		} else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) &&
+		           (adapter->secinfo.WPAenabled ||
+		            adapter->secinfo.WPA2enabled)) {
+			/* WPA */
+			ext->alg = IW_ENCODE_ALG_TKIP;
+			ext->key_len = 0;
+		} else {
+			goto out;
+		}
+
+		if (ext->key_len > max_key_len) {
+			ret = -E2BIG;
+			goto out;
+		}
+
+		if (ext->key_len)
+			memcpy(ext->key, key, ext->key_len);
+		else
+			dwrq->flags |= IW_ENCODE_NOKEY;
+		dwrq->flags |= IW_ENCODE_ENABLED;
+	}
+	ret = 0;
+
+out:
+	LEAVE();
+	return ret;
+}
+
+/**
+ *  @brief Set Encryption key Extended (WPA/802.1x and WEP)
+ *
+ *  @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 	   		0 --success, otherwise fail
+ */
+static int wlan_set_encodeext(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *dwrq,
+			      char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+	int alg = ext->alg;
+	struct assoc_request * assoc_req;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
+		disable_wep (assoc_req);
+	} else if (alg == IW_ENCODE_ALG_WEP) {
+		u16 is_default = 0, index, set_tx_key = 0;
+
+		ret = validate_key_index(assoc_req->wep_tx_keyidx,
+		                         (dwrq->flags & IW_ENCODE_INDEX),
+		                         &index, &is_default);
+		if (ret)
+			goto out;
+
+		/* If WEP isn't enabled, or if there is no key data but a valid
+		 * index, or if the set-TX-key flag was passed, set the TX key.
+		 */
+		if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+		    || (dwrq->length == 0 && !is_default)
+		    || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
+			set_tx_key = 1;
+
+		/* Copy key to driver */
+		ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
+					set_tx_key);
+		if (ret)
+			goto out;
+
+		if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeshared;
+		} else if (dwrq->flags & IW_ENCODE_OPEN) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		}
+
+		/* Mark the various WEP bits as modified */
+		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		if (dwrq->length)
+			set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+		if (set_tx_key)
+			set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+	} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+		struct WLAN_802_11_KEY * pkey;
+
+		/* validate key length */
+		if (((alg == IW_ENCODE_ALG_TKIP)
+			&& (ext->key_len != KEY_LEN_WPA_TKIP))
+		    || ((alg == IW_ENCODE_ALG_CCMP)
+		        && (ext->key_len != KEY_LEN_WPA_AES))) {
+				lbs_pr_debug(1, "Invalid size %d for key of alg"
+				       "type %d.\n",
+				       ext->key_len,
+				       alg);
+				ret = -EINVAL;
+				goto out;
+		}
+
+		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+			pkey = &assoc_req->wpa_mcast_key;
+		else
+			pkey = &assoc_req->wpa_unicast_key;
+
+		memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+		memcpy(pkey->key, ext->key, ext->key_len);
+		pkey->len = ext->key_len;
+		pkey->flags = KEY_INFO_WPA_ENABLED;
+
+		if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+			pkey->flags |= KEY_INFO_WPA_MCAST;
+			set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+		} else {
+			pkey->flags |= KEY_INFO_WPA_UNICAST;
+			set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+		}
+
+		if (alg == IW_ENCODE_ALG_TKIP)
+			pkey->type = KEY_TYPE_ID_TKIP;
+		else if (alg == IW_ENCODE_ALG_CCMP)
+			pkey->type = KEY_TYPE_ID_AES;
+
+		/* If WPA isn't enabled yet, do that now */
+		if (   assoc_req->secinfo.WPAenabled == 0
+		    && assoc_req->secinfo.WPA2enabled == 0) {
+			assoc_req->secinfo.WPAenabled = 1;
+			assoc_req->secinfo.WPA2enabled = 1;
+			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		}
+
+		disable_wep (assoc_req);
+	}
+
+out:
+	if (ret == 0) {
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+
+static int wlan_set_genie(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 = 0;
+	struct assoc_request * assoc_req;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (dwrq->length > MAX_WPA_IE_LEN ||
+	    (dwrq->length && extra == NULL)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (dwrq->length) {
+		memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
+		assoc_req->wpa_ie_len = dwrq->length;
+	} else {
+		memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
+		assoc_req->wpa_ie_len = 0;
+	}
+
+out:
+	if (ret == 0) {
+		set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_genie(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();
+
+	if (adapter->wpa_ie_len == 0) {
+		dwrq->length = 0;
+		LEAVE();
+		return 0;
+	}
+
+	if (dwrq->length < adapter->wpa_ie_len) {
+		LEAVE();
+		return -E2BIG;
+	}
+
+	dwrq->length = adapter->wpa_ie_len;
+	memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
+
+	LEAVE();
+	return 0;
+}
+
+
+static int wlan_set_auth(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *dwrq,
+			 char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+	struct assoc_request * assoc_req;
+	int ret = 0;
+	int updated = 0;
+
+	ENTER();
+
+	mutex_lock(&adapter->lock);
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	switch (dwrq->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_TKIP_COUNTERMEASURES:
+	case IW_AUTH_CIPHER_PAIRWISE:
+	case IW_AUTH_CIPHER_GROUP:
+	case IW_AUTH_KEY_MGMT:
+		/*
+		 * libertas does not use these parameters
+		 */
+		break;
+
+	case IW_AUTH_WPA_VERSION:
+		if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
+			assoc_req->secinfo.WPAenabled = 0;
+			assoc_req->secinfo.WPA2enabled = 0;
+		}
+		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
+			assoc_req->secinfo.WPAenabled = 1;
+			assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		}
+		if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
+			assoc_req->secinfo.WPA2enabled = 1;
+			assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		}
+		updated = 1;
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		if (dwrq->value) {
+			adapter->currentpacketfilter |=
+			    cmd_act_mac_strict_protection_enable;
+		} else {
+			adapter->currentpacketfilter &=
+			    ~cmd_act_mac_strict_protection_enable;
+		}
+		updated = 1;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeshared;
+		} else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodeopen;
+		} else if (dwrq->value & IW_AUTH_ALG_LEAP) {
+			assoc_req->secinfo.authmode =
+			    wlan802_11authmodenetworkEAP;
+		} else {
+			ret = -EINVAL;
+		}
+		updated = 1;
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		if (dwrq->value) {
+			if (!assoc_req->secinfo.WPAenabled &&
+			    !assoc_req->secinfo.WPA2enabled) {
+				assoc_req->secinfo.WPAenabled = 1;
+				assoc_req->secinfo.WPA2enabled = 1;
+				assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+				assoc_req->secinfo.authmode =
+				    wlan802_11authmodeopen;
+			}
+		} else {
+			assoc_req->secinfo.WPAenabled = 0;
+			assoc_req->secinfo.WPA2enabled = 0;
+		}
+		updated = 1;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+out:
+	if (ret == 0) {
+		if (updated)
+			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	} else if (ret != -EOPNOTSUPP) {
+		wlan_cancel_association_work(priv);
+	}
+	mutex_unlock(&adapter->lock);
+
+	LEAVE();
+	return ret;
+}
+
+static int wlan_get_auth(struct net_device *dev,
+			 struct iw_request_info *info,
+			 struct iw_param *dwrq,
+			 char *extra)
+{
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	ENTER();
+
+	switch (dwrq->flags & IW_AUTH_INDEX) {
+	case IW_AUTH_WPA_VERSION:
+		dwrq->value = 0;
+		if (adapter->secinfo.WPAenabled)
+			dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
+		if (adapter->secinfo.WPA2enabled)
+			dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
+		if (!dwrq->value)
+			dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
+		break;
+
+	case IW_AUTH_DROP_UNENCRYPTED:
+		dwrq->value = 0;
+		if (adapter->currentpacketfilter &
+		    cmd_act_mac_strict_protection_enable)
+			dwrq->value = 1;
+		break;
+
+	case IW_AUTH_80211_AUTH_ALG:
+		switch (adapter->secinfo.authmode) {
+		case wlan802_11authmodeshared:
+			dwrq->value = IW_AUTH_ALG_SHARED_KEY;
+			break;
+		case wlan802_11authmodeopen:
+			dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+			break;
+		case wlan802_11authmodenetworkEAP:
+			dwrq->value = IW_AUTH_ALG_LEAP;
+			break;
+		default:
+			break;
+		}
+		break;
+
+	case IW_AUTH_WPA_ENABLED:
+		if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
+			dwrq->value = 1;
+		break;
+
+	default:
+		LEAVE();
+		return -EOPNOTSUPP;
+	}
+
+	LEAVE();
+	return 0;
+}
+
+
+static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+		   struct iw_param *vwrq, char *extra)
+{
+	int ret = 0;
+	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	u16 dbm;
+
+	ENTER();
+
+	if (vwrq->disabled) {
+		wlan_radio_ioctl(priv, RADIO_OFF);
+		return 0;
+	}
+
+	adapter->preamble = cmd_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;
+
+	lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+	ret = libertas_prepare_and_send_command(priv,
+				    cmd_802_11_rf_tx_power,
+				    cmd_act_tx_power_opt_set_low,
+				    cmd_option_waitforrsp, 0, (void *)&dbm);
+
+	LEAVE();
+	return ret;
+}
+
+static 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->connect_status == libertas_connected) {
+		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 0;
+}
+
+static int wlan_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 = 0;
+	struct WLAN_802_11_SSID ssid;
+	struct assoc_request * assoc_req;
+	int ssid_len = dwrq->length;
+
+	ENTER();
+
+	/*
+	 * WE-20 and earlier NULL pad the end of the SSID and increment
+	 * SSID length so it can be used like a string.  WE-21 and later don't,
+	 * but some userspace tools aren't able to cope with the change.
+	 */
+	if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
+		ssid_len--;
+
+	/* Check the size of the string */
+	if (ssid_len > IW_ESSID_MAX_SIZE) {
+		ret = -E2BIG;
+		goto out;
+	}
+
+	memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
+
+	if (!dwrq->flags || !ssid_len) {
+		/* "any" SSID requested; leave SSID blank */
+	} else {
+		/* Specific SSID requested */
+		memcpy(&ssid.ssid, extra, ssid_len);
+		ssid.ssidlength = ssid_len;
+	}
+
+	lbs_pr_debug(1, "Requested new SSID = %s\n",
+	       (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
+
+out:
+	mutex_lock(&adapter->lock);
+	if (ret == 0) {
+		/* Get or create the current association request */
+		assoc_req = wlan_get_association_request(adapter);
+		if (!assoc_req) {
+			ret = -ENOMEM;
+		} else {
+			/* Copy the SSID to the association request */
+			memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
+			set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+			wlan_postpone_association_work(priv);
+		}
+	}
+
+	/* Cancel the association request if there was an error */
+	if (ret != 0) {
+		wlan_cancel_association_work(priv);
+	}
+
+	mutex_unlock(&adapter->lock);
+
+	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             0 --success, otherwise fail
+ */
+static int wlan_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;
+	struct assoc_request * assoc_req;
+	int ret = 0;
+
+	ENTER();
+
+	if (awrq->sa_family != ARPHRD_ETHER)
+		return -EINVAL;
+
+	lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+
+	mutex_lock(&adapter->lock);
+
+	/* Get or create the current association request */
+	assoc_req = wlan_get_association_request(adapter);
+	if (!assoc_req) {
+		wlan_cancel_association_work(priv);
+		ret = -ENOMEM;
+	} else {
+		/* Copy the BSSID to the association request */
+		memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
+		set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
+		wlan_postpone_association_work(priv);
+	}
+
+	mutex_unlock(&adapter->lock);
+
+	return ret;
+}
+
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
+{
+	union {
+		u32 l;
+		u8 c[4];
+	} ver;
+	char fwver[32];
+
+	mutex_lock(&adapter->lock);
+	ver.l = adapter->fwreleasenumber;
+	mutex_unlock(&adapter->lock);
+
+	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(fwversion, maxlen, fwver);
+}
+
+
+/*
+ * iwconfig settable callbacks
+ */
+static const iw_handler wlan_handler[] = {
+	(iw_handler) NULL,	/* 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) NULL,	/* SIOCSIWSENS */
+	(iw_handler) NULL,	/* 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) wlan_set_wap,	/* SIOCSIWAP */
+	(iw_handler) wlan_get_wap,	/* SIOCGIWAP */
+	(iw_handler) NULL,	/* SIOCSIWMLME */
+	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
+	(iw_handler) libertas_set_scan,	/* SIOCSIWSCAN */
+	(iw_handler) libertas_get_scan,	/* SIOCGIWSCAN */
+	(iw_handler) wlan_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) wlan_set_genie,	/* SIOCSIWGENIE */
+	(iw_handler) wlan_get_genie,	/* SIOCGIWGENIE */
+	(iw_handler) wlan_set_auth,	/* SIOCSIWAUTH */
+	(iw_handler) wlan_get_auth,	/* SIOCGIWAUTH */
+	(iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+	(iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+	(iw_handler) NULL,		/* SIOCSIWPMKSA */
+};
+
+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 --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
new file mode 100644
index 0000000..39f367c3
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.h
@@ -0,0 +1,147 @@
+/**
+  * This file contains definition for IOCTL call.
+  */
+#ifndef	_WLAN_WEXT_H_
+#define	_WLAN_WEXT_H_
+
+#define SUBCMD_OFFSET			4
+#define SUBCMD_DATA(x)			*((int *)(x->u.name + SUBCMD_OFFSET))
+
+/** PRIVATE CMD ID */
+#define	WLANIOCTL			SIOCIWFIRSTPRIV
+
+#define WLANSETWPAIE			(WLANIOCTL + 0)
+
+#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
+
+#define WLANWLANIDLEON				10
+#define WLANWLANIDLEOFF				11
+#define WLAN_SUBCMD_BT_RESET			13
+#define WLAN_SUBCMD_FWT_RESET			14
+
+#define WLANGETLOG                  	(WLANIOCTL + 9)
+#define GETLOG_BUFSIZE  300
+
+#define WLANSCAN_TYPE			(WLANIOCTL + 11)
+
+#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_SUBCMD_FWT_CLEANUP			15
+#define WLAN_SUBCMD_FWT_TIME			16
+#define WLAN_SUBCMD_MESH_GET_TTL		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_SETNONE_GETWORDCHAR	(WLANIOCTL + 21)
+#define WLANGETADHOCAES				1
+
+#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_SUBCMD_MESH_SET_TTL		18
+
+#define WLAN_SET128CHAR_GET128CHAR	(WLANIOCTL + 25)
+#define WLANSCAN_MODE				6
+
+#define WLAN_GET_ADHOC_STATUS			9
+
+#define WLAN_SUBCMD_BT_ADD			18
+#define WLAN_SUBCMD_BT_DEL   			19
+#define WLAN_SUBCMD_BT_LIST			20
+#define WLAN_SUBCMD_FWT_ADD				21
+#define WLAN_SUBCMD_FWT_DEL   		22
+#define WLAN_SUBCMD_FWT_LOOKUP		23
+#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR			24
+#define WLAN_SUBCMD_FWT_LIST			25
+#define WLAN_SUBCMD_FWT_LIST_ROUTE			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_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
+
+/** wlan_ioctl_regrdwr */
+struct wlan_ioctl_regrdwr {
+	/** Which register to access */
+	u16 whichreg;
+	/** Read or Write */
+	u16 action;
+	u32 offset;
+	u16 NOB;
+	u32 value;
+};
+
+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);
+
+#endif				/* _WLAN_WEXT_H_ */
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index 429b738..c6e0d81 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -168,6 +168,23 @@
  *      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 @@
 	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. */
@@ -219,6 +240,14 @@
 						 * 802.11 header and payload
 						 * (to 32-bit boundary)
 						 */
+/* 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 */
 
 /* Ugly macro to convert literal channel numbers into their mhz equivalents
  * There are certianly some conditions that will break this (like feeding it '30')