net: wireless: bcmdhd: Update to Version 5.90.195.19
authorDmitry Shmidt <dimitrysh@google.com>
Tue, 24 Jan 2012 21:47:47 +0000 (13:47 -0800)
committerDmitry Shmidt <dimitrysh@google.com>
Fri, 27 Jan 2012 23:32:33 +0000 (15:32 -0800)
- Add WFD changes
- Add extra locking for internal ioctl operations

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
24 files changed:
drivers/net/wireless/bcmdhd/Makefile
drivers/net/wireless/bcmdhd/bcmsdh_linux.c
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
drivers/net/wireless/bcmdhd/dhd.h
drivers/net/wireless/bcmdhd/dhd_cdc.c
drivers/net/wireless/bcmdhd/dhd_cfg80211.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/dhd_cfg80211.h [new file with mode: 0644]
drivers/net/wireless/bcmdhd/dhd_common.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/dhd_linux_mon.c [deleted file]
drivers/net/wireless/bcmdhd/dhd_sdio.c
drivers/net/wireless/bcmdhd/include/dhdioctl.h
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/include/proto/802.11.h
drivers/net/wireless/bcmdhd/include/wlioctl.h
drivers/net/wireless/bcmdhd/wl_android.c
drivers/net/wireless/bcmdhd/wl_android.h
drivers/net/wireless/bcmdhd/wl_cfg80211.c
drivers/net/wireless/bcmdhd/wl_cfg80211.h
drivers/net/wireless/bcmdhd/wl_cfgp2p.c
drivers/net/wireless/bcmdhd/wl_cfgp2p.h
drivers/net/wireless/bcmdhd/wl_linux_mon.c [new file with mode: 0644]
drivers/net/wireless/bcmdhd/wldev_common.c
drivers/net/wireless/bcmdhd/wldev_common.h

index e82c9856f006216e865d5d3ea874a1cc36526a71..17f07ca3a3073d547a04074866d1137d2ebcdd06 100644 (file)
@@ -13,7 +13,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER                     \
 DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o   \
        dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o  \
        bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o            \
-       bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o
+       bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o dhd_cfg80211.o
 
 obj-$(CONFIG_BCMDHD) += bcmdhd.o
 bcmdhd-objs += $(DHDOFILES)
@@ -22,7 +22,7 @@ bcmdhd-objs += wl_iw.o
 DHDCFLAGS += -DSOFTAP
 endif
 ifneq ($(CONFIG_CFG80211),)
-bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o
+bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o
 DHDCFLAGS += -DWL_CFG80211
 endif
 EXTRA_CFLAGS = $(DHDCFLAGS)
index 04c43a3225cfedaeeaba87968a1323c13840e973..5abfecc2cf1ec992e3392d5dd722bd264fa91cef 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_linux.c,v 1.72.6.5 2010-12-23 01:13:15 Exp $
+ * $Id: bcmsdh_linux.c 294990 2011-11-09 00:13:10Z $
  */
 
 /**
@@ -238,9 +238,9 @@ int bcmsdh_probe(struct device *dev)
        /* chain SDIO Host Controller info together */
        sdhc->next = sdhcinfo;
        sdhcinfo = sdhc;
+
        /* Read the vendor/device ID from the CIS */
        vendevid = bcmsdh_query_device(sdh);
-
        /* try to attach to the target device */
        if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
                                         (vendevid & 0xFFFF), 0, 0, 0, 0,
@@ -274,6 +274,7 @@ int bcmsdh_remove(struct device *dev)
        sdhc = sdhcinfo;
        drvinfo.detach(sdhc->ch);
        bcmsdh_detach(sdhc->osh, sdhc->sdh);
+
        /* find the SDIO Host Controller state for this pdev and take it out from the list */
        for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
                if (sdhc->dev == (void *)dev) {
@@ -290,7 +291,6 @@ int bcmsdh_remove(struct device *dev)
                return 0;
        }
 
-
        /* release SDIO Host Controller info */
        osh = sdhc->osh;
        MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
@@ -611,13 +611,6 @@ static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-void *bcmsdh_get_drvdata(void)
-{
-       if (!sdhcinfo)
-               return NULL;
-       return dev_get_drvdata(sdhcinfo->dev);
-}
-
 int bcmsdh_register_oob_intr(void * dhdp)
 {
        int error = 0;
@@ -645,6 +638,13 @@ int bcmsdh_register_oob_intr(void * dhdp)
        return 0;
 }
 
+void *bcmsdh_get_drvdata(void)
+{
+       if (!sdhcinfo)
+               return NULL;
+       return dev_get_drvdata(sdhcinfo->dev);
+}
+
 void bcmsdh_set_irq(int flag)
 {
        if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) {
@@ -671,6 +671,7 @@ void bcmsdh_unregister_oob_intr(void)
        }
 }
 #endif /* defined(OOB_INTR_ONLY) */
+
 /* Module parameters specific to each host-controller driver */
 
 extern uint sd_msglevel;       /* Debug message level */
@@ -694,6 +695,10 @@ module_param(sd_hiok, uint, 0);
 extern uint sd_f2_blocksize;
 module_param(sd_f2_blocksize, int, 0);
 
+#ifdef BCMSDIOH_STD
+extern int sd_uhsimode;
+module_param(sd_uhsimode, int, 0);
+#endif
 
 #ifdef BCMSDH_MODULE
 EXPORT_SYMBOL(bcmsdh_attach);
index aedb508c594a82b8e1033429cd43cfa3e9ca9c8c..6a8ff9431e9248fb9523a494afa54bcd7c2ed11b 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: bcmsdh_sdmmc.c 282820 2011-09-09 15:40:35Z $
+ * $Id: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $
  */
 #include <typedefs.h>
 
@@ -448,6 +448,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
                bcopy(params, &int_val, sizeof(int_val));
 
        bool_val = (int_val != 0) ? TRUE : FALSE;
+       BCM_REFERENCE(bool_val);
 
        actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
        switch (actionid) {
@@ -1179,6 +1180,7 @@ static void IRQHandlerF2(struct sdio_func *func)
        sd = gInstance->sd;
 
        ASSERT(sd != NULL);
+       BCM_REFERENCE(sd);
 }
 #endif /* !defined(OOB_INTR_ONLY) */
 
index 4335d0d6a8ac58c7a41b7b82ede812d7bdd66b99..25e74f44a532f093d0ba8f0af1a2439f6e823bf6 100644 (file)
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd.h 301794 2011-12-08 20:41:35Z $
+ * $Id: dhd.h 306879 2012-01-09 21:33:03Z $
  */
 
 /****************
@@ -419,6 +419,7 @@ extern int dhd_custom_get_mac_address(unsigned char *buf);
 extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
 extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
 extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
+extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
 
 #ifdef PNO_SUPPORT
 extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
@@ -433,8 +434,6 @@ extern int dhd_dev_pno_enable(struct net_device *dev,  int pfn_enabled);
 extern int dhd_dev_get_pno_status(struct net_device *dev);
 #endif /* PNO_SUPPORT */
 
-extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
-
 #define DHD_UNICAST_FILTER_NUM         0
 #define DHD_BROADCAST_FILTER_NUM       1
 #define DHD_MULTICAST4_FILTER_NUM      2
@@ -443,7 +442,7 @@ extern int net_os_set_packet_filter(struct net_device *dev, int val);
 extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
 
 extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
-extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
+extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
 
 #ifdef DHD_DEBUG
 extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
@@ -466,7 +465,7 @@ extern int dhd_timeout_expired(dhd_timeout_t *tmo);
 
 extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
 extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net);
-extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx);
+extern struct net_device * dhd_idx2net(void *pub, int ifidx);
 extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata,
                          wl_event_msg_t *, void **data_ptr);
 extern void wl_event_to_host_order(wl_event_msg_t * evt);
@@ -478,6 +477,7 @@ extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uin
 extern struct dhd_cmn *dhd_common_init(osl_t *osh);
 extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn);
 
+extern int dhd_do_driver_init(struct net_device *net);
 extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle,
        char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx);
 extern void dhd_del_if(struct dhd_info *dhd, int ifidx);
index 50e275a4ae231121434bfd17f7cec3fb7d2d077f..d01853c71a2e7845da941324dbe6c7015a61dc77 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_cdc.c 301794 2011-12-08 20:41:35Z $
+ * $Id: dhd_cdc.c 303389 2011-12-16 09:30:48Z $
  *
  * BDC is like CDC, except it includes a header for data packets to convey
  * packet priority over the bus, and flags (e.g. to indicate checksum status
@@ -2515,9 +2515,10 @@ dhd_prot_init(dhd_pub_t *dhd)
        ret = dhd_wlfc_init(dhd);
 #endif
 
-#if !defined(WL_CFG80211)
+#if defined(WL_CFG80211)
+       if (dhd_download_fw_on_driverload)
+#endif /* defined(WL_CFG80211) */
        ret = dhd_preinit_ioctls(dhd);
-#endif /* WL_CFG80211 */
 
        /* Always assumes wl for now */
        dhd->iswl = TRUE;
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
new file mode 100644 (file)
index 0000000..058749d
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ * 
+ *         Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_cfg80211.h>
+extern struct wl_priv *wlcfg_drv_priv;
+static int dhd_dongle_up = FALSE;
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up);
+static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
+static s32 wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align);
+static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,        u32 bcn_timeout);
+static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time);
+static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol);
+static s32 wl_pattern_atoh(s8 *src, s8 *dst);
+static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
+
+/**
+ * Function implementations
+ */
+
+s32 dhd_cfg80211_init(struct wl_priv *wl)
+{
+       dhd_dongle_up = FALSE;
+       return 0;
+}
+
+s32 dhd_cfg80211_deinit(struct wl_priv *wl)
+{
+       dhd_dongle_up = FALSE;
+       return 0;
+}
+
+s32 dhd_cfg80211_down(struct wl_priv *wl)
+{
+       dhd_dongle_up = FALSE;
+       return 0;
+}
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up)
+{
+       s32 err = 0;
+
+       err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
+       if (unlikely(err)) {
+               WL_ERR(("WLC_UP error (%d)\n", err));
+       }
+       return err;
+}
+
+static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
+{
+       s32 err = 0;
+
+       WL_TRACE(("In\n"));
+       err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
+       if (unlikely(err)) {
+               WL_ERR(("WLC_SET_PM error (%d)\n", err));
+       }
+       return err;
+}
+
+static s32
+wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
+{
+       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+       s32 err = 0;
+
+       /* Match Host and Dongle rx alignment */
+       bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
+               sizeof(iovbuf));
+       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+       if (unlikely(err)) {
+               WL_ERR(("txglomalign error (%d)\n", err));
+               goto dongle_glom_out;
+       }
+       /* disable glom option per default */
+       bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+       if (unlikely(err)) {
+               WL_ERR(("txglom error (%d)\n", err));
+               goto dongle_glom_out;
+       }
+dongle_glom_out:
+       return err;
+}
+
+static s32
+wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
+{
+       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+       s32 err = 0;
+
+       /* Setup timeout if Beacons are lost and roam is off to report link down */
+       if (roamvar) {
+               bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
+                       sizeof(iovbuf));
+               err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+               if (unlikely(err)) {
+                       WL_ERR(("bcn_timeout error (%d)\n", err));
+                       goto dongle_rom_out;
+               }
+       }
+       /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
+       bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+       if (unlikely(err)) {
+               WL_ERR(("roam_off error (%d)\n", err));
+               goto dongle_rom_out;
+       }
+dongle_rom_out:
+       return err;
+}
+
+static s32
+wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
+       s32 scan_unassoc_time)
+{
+       s32 err = 0;
+
+       err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
+               sizeof(scan_assoc_time), true);
+       if (err) {
+               if (err == -EOPNOTSUPP) {
+                       WL_INFO(("Scan assoc time is not supported\n"));
+               } else {
+                       WL_ERR(("Scan assoc time error (%d)\n", err));
+               }
+               goto dongle_scantime_out;
+       }
+       err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
+               sizeof(scan_unassoc_time), true);
+       if (err) {
+               if (err == -EOPNOTSUPP) {
+                       WL_INFO(("Scan unassoc time is not supported\n"));
+               } else {
+                       WL_ERR(("Scan unassoc time error (%d)\n", err));
+               }
+               goto dongle_scantime_out;
+       }
+
+dongle_scantime_out:
+       return err;
+}
+
+static s32
+wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
+{
+       /* Room for "event_msgs" + '\0' + bitvec */
+       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+       s32 err = 0;
+
+       /* Set ARP offload */
+       bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
+       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+       if (err) {
+               if (err == -EOPNOTSUPP)
+                       WL_INFO(("arpoe is not supported\n"));
+               else
+                       WL_ERR(("arpoe error (%d)\n", err));
+
+               goto dongle_offload_out;
+       }
+       bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
+       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+       if (err) {
+               if (err == -EOPNOTSUPP)
+                       WL_INFO(("arp_ol is not supported\n"));
+               else
+                       WL_ERR(("arp_ol error (%d)\n", err));
+
+               goto dongle_offload_out;
+       }
+
+dongle_offload_out:
+       return err;
+}
+
+static s32 wl_pattern_atoh(s8 *src, s8 *dst)
+{
+       int i;
+       if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
+               WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
+               return -1;
+       }
+       src = src + 2;          /* Skip past 0x */
+       if (strlen(src) % 2 != 0) {
+               WL_ERR(("Mask invalid format. Needs to be of even length\n"));
+               return -1;
+       }
+       for (i = 0; *src != '\0'; i++) {
+               char num[3];
+               strncpy(num, src, 2);
+               num[2] = '\0';
+               dst[i] = (u8) simple_strtoul(num, NULL, 16);
+               src += 2;
+       }
+       return i;
+}
+
+static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
+{
+       /* Room for "event_msgs" + '\0' + bitvec */
+       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+       const s8 *str;
+       struct wl_pkt_filter pkt_filter;
+       struct wl_pkt_filter *pkt_filterp;
+       s32 buf_len;
+       s32 str_len;
+       u32 mask_size;
+       u32 pattern_size;
+       s8 buf[256];
+       s32 err = 0;
+
+       /* add a default packet filter pattern */
+       str = "pkt_filter_add";
+       str_len = strlen(str);
+       strncpy(buf, str, str_len);
+       buf[str_len] = '\0';
+       buf_len = str_len + 1;
+
+       pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
+
+       /* Parse packet filter id. */
+       pkt_filter.id = htod32(100);
+
+       /* Parse filter polarity. */
+       pkt_filter.negate_match = htod32(0);
+
+       /* Parse filter type. */
+       pkt_filter.type = htod32(0);
+
+       /* Parse pattern filter offset. */
+       pkt_filter.u.pattern.offset = htod32(0);
+
+       /* Parse pattern filter mask. */
+       mask_size = htod32(wl_pattern_atoh("0xff",
+               (char *)pkt_filterp->u.pattern.
+                   mask_and_pattern));
+
+       /* Parse pattern filter pattern. */
+       pattern_size = htod32(wl_pattern_atoh("0x00",
+               (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
+
+       if (mask_size != pattern_size) {
+               WL_ERR(("Mask and pattern not the same size\n"));
+               err = -EINVAL;
+               goto dongle_filter_out;
+       }
+
+       pkt_filter.u.pattern.size_bytes = mask_size;
+       buf_len += WL_PKT_FILTER_FIXED_LEN;
+       buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
+
+       /* Keep-alive attributes are set in local
+        * variable (keep_alive_pkt), and
+        * then memcpy'ed into buffer (keep_alive_pktp) since there is no
+        * guarantee that the buffer is properly aligned.
+        */
+       memcpy((char *)pkt_filterp, &pkt_filter,
+               WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
+
+       err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
+       if (err) {
+               if (err == -EOPNOTSUPP) {
+                       WL_INFO(("filter not supported\n"));
+               } else {
+                       WL_ERR(("filter (%d)\n", err));
+               }
+               goto dongle_filter_out;
+       }
+
+       /* set mode to allow pattern */
+       bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
+               sizeof(iovbuf));
+       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+       if (err) {
+               if (err == -EOPNOTSUPP) {
+                       WL_INFO(("filter_mode not supported\n"));
+               } else {
+                       WL_ERR(("filter_mode (%d)\n", err));
+               }
+               goto dongle_filter_out;
+       }
+
+dongle_filter_out:
+       return err;
+}
+
+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock)
+{
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN    32
+#endif
+       struct net_device *ndev;
+       s32 err = 0;
+
+       WL_TRACE(("In\n"));
+       if (dhd_dongle_up) {
+               WL_ERR(("Dongle is already up\n"));
+               return err;
+       }
+
+       ndev = wl_to_prmry_ndev(wl);
+
+       if (need_lock)
+               rtnl_lock();
+
+       err = wl_dongle_up(ndev, 0);
+       if (unlikely(err)) {
+               WL_ERR(("wl_dongle_up failed\n"));
+               goto default_conf_out;
+       }
+       err = wl_dongle_power(ndev, PM_FAST);
+       if (unlikely(err)) {
+               WL_ERR(("wl_dongle_power failed\n"));
+               goto default_conf_out;
+       }
+       err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
+       if (unlikely(err)) {
+               WL_ERR(("wl_dongle_glom failed\n"));
+               goto default_conf_out;
+       }
+       err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
+       if (unlikely(err)) {
+               WL_ERR(("wl_dongle_roam failed\n"));
+               goto default_conf_out;
+       }
+       wl_dongle_scantime(ndev, 40, 80);
+       wl_dongle_offload(ndev, 1, 0xf);
+       wl_dongle_filter(ndev, 1);
+       dhd_dongle_up = true;
+
+default_conf_out:
+       if (need_lock)
+               rtnl_unlock();
+       return err;
+
+}
+
+
+/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
+#define COEX_DHCP
+
+#if defined(COEX_DHCP)
+
+/* use New SCO/eSCO smart YG suppression */
+#define BT_DHCP_eSCO_FIX
+/* this flag boost wifi pkt priority to max, caution: -not fair to sco */
+#define BT_DHCP_USE_FLAGS
+/* T1 start SCO/ESCo priority suppression */
+#define BT_DHCP_OPPR_WIN_TIME  2500
+/* T2 turn off SCO/SCO supperesion is (timeout) */
+#define BT_DHCP_FLAG_FORCE_TIME 5500
+
+enum wl_cfg80211_btcoex_status {
+       BT_DHCP_IDLE,
+       BT_DHCP_START,
+       BT_DHCP_OPPR_WIN,
+       BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+       uint reg, int *retval)
+{
+       union {
+               char buf[WLC_IOCTL_SMLEN];
+               int val;
+       } var;
+       int error;
+
+       bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
+               (char *)(&var), sizeof(var.buf));
+       error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+       *retval = dtoh32(var.val);
+       return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
+       char ioctlbuf_local[1024];
+#else
+       static char ioctlbuf_local[1024];
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
+
+       bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
+
+       return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+       char reg_addr[8];
+
+       memset(reg_addr, 0, sizeof(reg_addr));
+       memcpy((char *)&reg_addr[0], (char *)addr, 4);
+       memcpy((char *)&reg_addr[4], (char *)val, 4);
+
+       return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+       int ioc_res = 0;
+       bool res = FALSE;
+       int sco_id_cnt = 0;
+       int param27;
+       int i;
+
+       for (i = 0; i < 12; i++) {
+
+               ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
+
+               WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
+                       __FUNCTION__, i, param27));
+
+               if (ioc_res < 0) {
+                       WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
+                       break;
+               }
+
+               if ((param27 & 0x6) == 2) { /* count both sco & esco  */
+                       sco_id_cnt++;
+               }
+
+               if (sco_id_cnt > 2) {
+                       WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d  samples:%d\n",
+                               __FUNCTION__, sco_id_cnt, i));
+                       res = TRUE;
+                       break;
+               }
+
+               msleep(5);
+       }
+
+       return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+       static bool saved_status = FALSE;
+
+       char buf_reg50va_dhcp_on[8] =
+               { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+       char buf_reg51va_dhcp_on[8] =
+               { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       char buf_reg64va_dhcp_on[8] =
+               { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       char buf_reg65va_dhcp_on[8] =
+               { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       char buf_reg71va_dhcp_on[8] =
+               { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+       uint32 regaddr;
+       static uint32 saved_reg50;
+       static uint32 saved_reg51;
+       static uint32 saved_reg64;
+       static uint32 saved_reg65;
+       static uint32 saved_reg71;
+
+       if (trump_sco) {
+               /* this should reduce eSCO agressive retransmit
+                * w/o breaking it
+                */
+
+               /* 1st save current */
+               WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+                         "override}\n"));
+               if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+                       saved_status = TRUE;
+                       WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
+                                 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                                 __FUNCTION__, saved_reg50, saved_reg51,
+                                 saved_reg64, saved_reg65, saved_reg71));
+               } else {
+                       WL_ERR((":%s: save btc_params failed\n",
+                               __FUNCTION__));
+                       saved_status = FALSE;
+                       return -1;
+               }
+
+               WL_TRACE(("override with [50,51,64,65,71]:"
+                         "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                         *(u32 *)(buf_reg50va_dhcp_on+4),
+                         *(u32 *)(buf_reg51va_dhcp_on+4),
+                         *(u32 *)(buf_reg64va_dhcp_on+4),
+                         *(u32 *)(buf_reg65va_dhcp_on+4),
+                         *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg50va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg51va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg64va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg65va_dhcp_on[0], 8);
+               dev_wlc_bufvar_set(dev, "btc_params",
+                       (char *)&buf_reg71va_dhcp_on[0], 8);
+
+               saved_status = TRUE;
+       } else if (saved_status) {
+               /* restore previously saved bt params */
+               WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+                         "override}\n"));
+
+               regaddr = 50;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg50);
+               regaddr = 51;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg51);
+               regaddr = 64;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg64);
+               regaddr = 65;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg65);
+               regaddr = 71;
+               dev_wlc_intvar_set_reg(dev, "btc_params",
+                       (char *)&regaddr, (char *)&saved_reg71);
+
+               WL_TRACE(("restore bt_params[50,51,64,65,71]:"
+                       "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                       saved_reg50, saved_reg51, saved_reg64,
+                       saved_reg65, saved_reg71));
+
+               saved_status = FALSE;
+       } else {
+               WL_ERR((":%s att to restore not saved BTCOEX params\n",
+                       __FUNCTION__));
+               return -1;
+       }
+       return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+       char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+       char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+
+#if defined(BT_DHCP_eSCO_FIX)
+       /* set = 1, save & turn on  0 - off & restore prev settings */
+       set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+       WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+       if (set == TRUE)
+               /* Forcing bt_flag7  */
+               dev_wlc_bufvar_set(dev, "btc_flags",
+                       (char *)&buf_flag7_dhcp_on[0],
+                       sizeof(buf_flag7_dhcp_on));
+       else
+               /* Restoring default bt flag7 */
+               dev_wlc_bufvar_set(dev, "btc_flags",
+                       (char *)&buf_flag7_default[0],
+                       sizeof(buf_flag7_default));
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+       struct btcoex_info *bt_local = (struct btcoex_info *)data;
+       WL_TRACE(("%s\n", __FUNCTION__));
+       bt_local->timer_on = 0;
+       schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+       struct btcoex_info *btcx_inf;
+
+       btcx_inf = container_of(work, struct btcoex_info, work);
+
+       if (btcx_inf->timer_on) {
+               btcx_inf->timer_on = 0;
+               del_timer_sync(&btcx_inf->timer);
+       }
+
+       switch (btcx_inf->bt_state) {
+               case BT_DHCP_START:
+                       /* DHCP started
+                        * provide OPPORTUNITY window to get DHCP address
+                        */
+                       WL_TRACE(("%s bt_dhcp stm: started \n",
+                               __FUNCTION__));
+                       btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+                       mod_timer(&btcx_inf->timer,
+                               jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
+                       btcx_inf->timer_on = 1;
+                       break;
+
+               case BT_DHCP_OPPR_WIN:
+                       if (btcx_inf->dhcp_done) {
+                               WL_TRACE(("%s DHCP Done before T1 expiration\n",
+                                       __FUNCTION__));
+                               goto btc_coex_idle;
+                       }
+
+                       /* DHCP is not over yet, start lowering BT priority
+                        * enforce btc_params + flags if necessary
+                        */
+                       WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
+                               BT_DHCP_OPPR_WIN_TIME));
+                       if (btcx_inf->dev)
+                               wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+                       btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+                       mod_timer(&btcx_inf->timer,
+                               jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
+                       btcx_inf->timer_on = 1;
+                       break;
+
+               case BT_DHCP_FLAG_FORCE_TIMEOUT:
+                       if (btcx_inf->dhcp_done) {
+                               WL_TRACE(("%s DHCP Done before T2 expiration\n",
+                                       __FUNCTION__));
+                       } else {
+                               /* Noo dhcp during T1+T2, restore BT priority */
+                               WL_TRACE(("%s DHCP wait interval T2:%d"
+                                         "msec expired\n", __FUNCTION__,
+                                         BT_DHCP_FLAG_FORCE_TIME));
+                       }
+
+                       /* Restoring default bt priority */
+                       if (btcx_inf->dev)
+                               wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+                       btcx_inf->bt_state = BT_DHCP_IDLE;
+                       btcx_inf->timer_on = 0;
+                       break;
+
+               default:
+                       WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
+                               btcx_inf->bt_state));
+                       if (btcx_inf->dev)
+                               wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+                       btcx_inf->bt_state = BT_DHCP_IDLE;
+                       btcx_inf->timer_on = 0;
+                       break;
+       }
+
+       net_os_wake_unlock(btcx_inf->dev);
+}
+
+int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+{
+       struct btcoex_info *btco_inf = NULL;
+
+       btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+       if (!btco_inf)
+               return -ENOMEM;
+
+       btco_inf->bt_state = BT_DHCP_IDLE;
+       btco_inf->ts_dhcp_start = 0;
+       btco_inf->ts_dhcp_ok = 0;
+       /* Set up timer for BT  */
+       btco_inf->timer_ms = 10;
+       init_timer(&btco_inf->timer);
+       btco_inf->timer.data = (ulong)btco_inf;
+       btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+       btco_inf->dev = wl->wdev->netdev;
+
+       INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+       wl->btcoex_info = btco_inf;
+       return 0;
+}
+
+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
+{
+       if (!wl->btcoex_info)
+               return;
+
+       if (!wl->btcoex_info->timer_on) {
+               wl->btcoex_info->timer_on = 0;
+               del_timer_sync(&wl->btcoex_info->timer);
+       }
+
+       cancel_work_sync(&wl->btcoex_info->work);
+
+       kfree(wl->btcoex_info);
+       wl->btcoex_info = NULL;
+}
+#endif 
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
+{
+
+       struct wl_priv *wl = wlcfg_drv_priv;
+       char powermode_val = 0;
+       char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+       char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+       char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+       uint32 regaddr;
+       static uint32 saved_reg66;
+       static uint32 saved_reg41;
+       static uint32 saved_reg68;
+       static bool saved_status = FALSE;
+
+#ifdef COEX_DHCP
+       char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+       struct btcoex_info *btco_inf = wl->btcoex_info;
+#endif /* COEX_DHCP */
+
+       /* Figure out powermode 1 or o command */
+       strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+       if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+
+               WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
+
+               /* Retrieve and saved orig regs value */
+               if ((saved_status == FALSE) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
+                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
+                               saved_status = TRUE;
+                               WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
+                                       saved_reg66, saved_reg41, saved_reg68));
+
+                               /* Disable PM mode during dhpc session */
+
+                               /* Disable PM mode during dhpc session */
+#ifdef COEX_DHCP
+                               /* Start  BT timer only for SCO connection */
+                               if (btcoex_is_sco_active(dev)) {
+                                       /* btc_params 66 */
+                                       dev_wlc_bufvar_set(dev, "btc_params",
+                                               (char *)&buf_reg66va_dhcp_on[0],
+                                               sizeof(buf_reg66va_dhcp_on));
+                                       /* btc_params 41 0x33 */
+                                       dev_wlc_bufvar_set(dev, "btc_params",
+                                               (char *)&buf_reg41va_dhcp_on[0],
+                                               sizeof(buf_reg41va_dhcp_on));
+                                       /* btc_params 68 0x190 */
+                                       dev_wlc_bufvar_set(dev, "btc_params",
+                                               (char *)&buf_reg68va_dhcp_on[0],
+                                               sizeof(buf_reg68va_dhcp_on));
+                                       saved_status = TRUE;
+
+                                       btco_inf->bt_state = BT_DHCP_START;
+                                       btco_inf->timer_on = 1;
+                                       mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+                                       WL_TRACE(("%s enable BT DHCP Timer\n",
+                                       __FUNCTION__));
+                               }
+#endif /* COEX_DHCP */
+               }
+               else if (saved_status == TRUE) {
+                       WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
+               }
+       }
+       else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+               /* Restoring PM mode */
+
+#ifdef COEX_DHCP
+               /* Stop any bt timer because DHCP session is done */
+               WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
+               if (btco_inf->timer_on) {
+                       btco_inf->timer_on = 0;
+                       del_timer_sync(&btco_inf->timer);
+
+                       if (btco_inf->bt_state != BT_DHCP_IDLE) {
+                       /* need to restore original btc flags & extra btc params */
+                               WL_TRACE(("%s bt->bt_state:%d\n",
+                                       __FUNCTION__, btco_inf->bt_state));
+                               /* wake up btcoex thread to restore btlags+params  */
+                               schedule_work(&btco_inf->work);
+                       }
+               }
+
+               /* Restoring btc_flag paramter anyway */
+               if (saved_status == TRUE)
+                       dev_wlc_bufvar_set(dev, "btc_flags",
+                               (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+#endif /* COEX_DHCP */
+
+               /* Restore original values */
+               if (saved_status == TRUE) {
+                       regaddr = 66;
+                       dev_wlc_intvar_set_reg(dev, "btc_params",
+                               (char *)&regaddr, (char *)&saved_reg66);
+                       regaddr = 41;
+                       dev_wlc_intvar_set_reg(dev, "btc_params",
+                               (char *)&regaddr, (char *)&saved_reg41);
+                       regaddr = 68;
+                       dev_wlc_intvar_set_reg(dev, "btc_params",
+                               (char *)&regaddr, (char *)&saved_reg68);
+
+                       WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+                               saved_reg66, saved_reg41, saved_reg68));
+               }
+               saved_status = FALSE;
+
+       }
+       else {
+               WL_ERR(("%s Unkwown yet power setting, ignored\n",
+                       __FUNCTION__));
+       }
+
+       snprintf(command, 3, "OK");
+
+       return (strlen("OK"));
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
new file mode 100644 (file)
index 0000000..8dab652
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ * 
+ *         Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+
+#ifndef __DHD_CFG80211__
+#define __DHD_CFG80211__
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+
+s32 dhd_cfg80211_init(struct wl_priv *wl);
+s32 dhd_cfg80211_deinit(struct wl_priv *wl);
+s32 dhd_cfg80211_down(struct wl_priv *wl);
+s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock);
+
+int wl_cfg80211_btcoex_init(struct wl_priv *wl);
+void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
+
+#endif /* __DHD_CFG80211__ */
index 6376546c62c023bf4d412ddb9579ccfc85a9b774..a54c39152e4722d76c2c4bcb181a09b2e583fd22 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_common.c 297563 2011-11-20 15:38:29Z $
+ * $Id: dhd_common.c 307573 2012-01-12 00:04:39Z $
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -336,6 +336,11 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 
        case IOV_SVAL(IOV_MSGLEVEL):
                dhd_msg_level = int_val;
+#ifdef WL_CFG80211
+               /* Enable DHD and WL logs in oneshot */
+               if (dhd_msg_level & DHD_WL_VAL)
+                       wl_cfg80211_enable_trace(dhd_msg_level);
+#endif
                break;
        case IOV_GVAL(IOV_BCMERRORSTR):
                bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
index 48c970a6b5b35a9fee1d0848f1670d76f1c7b110..07d8430ea1876669621847d2944a4799270a5d8f 100644 (file)
@@ -22,7 +22,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_linux.c 301794 2011-12-08 20:41:35Z $
+ * $Id: dhd_linux.c 307603 2012-01-12 01:32:01Z $
  */
 
 #include <typedefs.h>
@@ -286,6 +286,8 @@ typedef struct dhd_info {
 char firmware_path[MOD_PARAM_PATHLEN];
 char nvram_path[MOD_PARAM_PATHLEN];
 
+int op_mode = 0;
+module_param(op_mode, int, 0644);
 extern int wl_control_wl_start(struct net_device *dev);
 extern int net_os_send_hang_message(struct net_device *dev);
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -441,6 +443,9 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
 ;
 static void dhd_net_if_lock_local(dhd_info_t *dhd);
 static void dhd_net_if_unlock_local(dhd_info_t *dhd);
+#if !defined(AP) && defined(WLP2P)
+static u32 dhd_concurrent_fw(dhd_pub_t *dhd);
+#endif 
 
 #ifdef WLMEDIA_HTSF
 void htsf_update(dhd_info_t *dhd, void *data);
@@ -698,8 +703,9 @@ dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
        return DHD_BAD_IF;
 }
 
-struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx)
+struct net_device * dhd_idx2net(void *pub, int ifidx)
 {
+       struct dhd_pub *dhd_pub = (struct dhd_pub *)pub;
        struct dhd_info *dhd_info;
 
        if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
@@ -927,6 +933,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
                DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
        } else {
                memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
+               memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN);
        }
 
        return ret;
@@ -983,7 +990,7 @@ dhd_op_if(dhd_if_t *ifp)
 #ifdef WL_CFG80211
                        if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
                                if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
-                                       dhd_net_attach)) {
+                                       (void*)dhd_net_attach)) {
                                        ifp->state = DHD_IF_NONE;
                                        return;
                                }
@@ -1425,7 +1432,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
                        PKTFREE(dhdp->osh, pktbuf, TRUE);
                        continue;
                }
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
                /* Dropping packets before registering net device to avoid kernel panic */
                if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
                        !dhd->pub.up) {
@@ -1434,6 +1441,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
                        PKTFREE(dhdp->osh, pktbuf, TRUE);
                        continue;
                }
+#endif
 
                pnext = PKTNEXT(dhdp->osh, pktbuf);
                PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
@@ -2279,7 +2287,7 @@ dhd_stop(struct net_device *net)
        int ifidx;
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
        DHD_OS_WAKE_LOCK(&dhd->pub);
-       DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+       DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
        if (dhd->pub.up == 0) {
                goto exit;
        }
@@ -2287,7 +2295,7 @@ dhd_stop(struct net_device *net)
 
 #ifdef WL_CFG80211
        if (ifidx == 0) {
-               wl_cfg80211_down();
+               wl_cfg80211_down(NULL);
 
                /*
                 * For CFG80211: Clean up all the left over virtual interfaces
@@ -2399,7 +2407,7 @@ dhd_open(struct net_device *net)
 #endif /* TOE */
 
 #if defined(WL_CFG80211)
-               if (unlikely(wl_cfg80211_up())) {
+               if (unlikely(wl_cfg80211_up(NULL))) {
                        DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
                        ret = -1;
                        goto exit;
@@ -2421,6 +2429,32 @@ exit:
        return ret;
 }
 
+int dhd_do_driver_init(struct net_device *net)
+{
+       dhd_info_t *dhd = NULL;
+
+       if (!net) {
+               DHD_ERROR(("Primary Interface not initialized \n"));
+               return -EINVAL;
+       }
+
+       dhd = *(dhd_info_t **)netdev_priv(net);
+
+       /* If driver is already initialized, do nothing
+        */
+       if (dhd->pub.busstate == DHD_BUS_DATA) {
+               DHD_TRACE(("Driver already Inititalized. Nothing to do"));
+               return 0;
+       }
+
+       if (dhd_open(net) < 0) {
+               DHD_ERROR(("Driver Init Failed \n"));
+               return -1;
+       }
+
+       return 0;
+}
+
 osl_t *
 dhd_osl_attach(void *pdev, uint bustype)
 {
@@ -2855,6 +2889,37 @@ dhd_bus_start(dhd_pub_t *dhdp)
        return 0;
 }
 
+#if !defined(AP) && defined(WLP2P)
+/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware
+ * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA
+ * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware
+ * would still be named as fw_bcmdhd_apsta.
+ */
+static u32
+dhd_concurrent_fw(dhd_pub_t *dhd)
+{
+       int ret = 0;
+       char buf[WLC_IOCTL_SMLEN];
+
+       if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) &&
+               (strstr(fw_path, "_apsta") == NULL)) {
+               /* Given path is for the STA firmware. Check whether P2P support is present in
+                * the firmware. If so, set mode as P2P (concurrent support).
+                */
+               memset(buf, 0, sizeof(buf));
+               bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+               if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+                       FALSE, 0)) < 0) {
+                       DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
+               } else if (buf[0] == 1) {
+                       DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__));
+                       return 1;
+               }
+       }
+       return 0;
+}
+#endif 
+
 int
 dhd_preinit_ioctls(dhd_pub_t *dhd)
 {
@@ -2920,7 +2985,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif /* GET_CUSTOM_MAC_ENABLE */
 
 #ifdef SET_RANDOM_MAC_SOFTAP
-       if (strstr(fw_path, "_apsta") != NULL) {
+       if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) {
                uint rand_mac;
 
                srandom32((uint)jiffies);
@@ -2944,7 +3009,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        DHD_TRACE(("Firmware = %s\n", fw_path));
 #if !defined(AP) && defined(WLP2P)
        /* Check if firmware with WFD support used */
-       if (strstr(fw_path, "_p2p") != NULL) {
+       if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) ||
+               (dhd_concurrent_fw(dhd))) {
                bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
                if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
                        iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
@@ -2961,7 +3027,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 
 #if !defined(AP) && defined(WL_CFG80211)
        /* Check if firmware with HostAPD support used */
-       if (strstr(fw_path, "_apsta") != NULL) {
+       if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) {
                        /* Turn off MPC in AP mode */
                        bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
                        if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
@@ -3591,7 +3657,7 @@ void dhd_detach(dhd_pub_t *dhdp)
 
 #ifdef WL_CFG80211
        if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
-               wl_cfg80211_detach();
+               wl_cfg80211_detach(NULL);
                dhd_monitor_uninit();
        }
 #endif
@@ -3638,7 +3704,6 @@ dhd_module_cleanup(void)
        dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
 }
 
-
 static int __init
 dhd_module_init(void)
 {
@@ -3697,7 +3762,7 @@ dhd_module_init(void)
                }
 #endif
 #if defined(WL_CFG80211)
-       error = wl_android_post_init();
+       wl_android_post_init();
 #endif
 
        return error;
@@ -3716,7 +3781,11 @@ fail_1:
        return error;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
 late_initcall(dhd_module_init);
+#else
+module_init(dhd_module_init);
+#endif
 module_exit(dhd_module_cleanup);
 
 /*
@@ -4017,7 +4086,13 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
 #endif /* defined(CONFIG_WIRELESS_EXT)  */
 
 #ifdef WL_CFG80211
-
+       if ((ntoh32(event->event_type) == WLC_E_IF) &&
+               (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD))
+               /* If ADD_IF has been called directly by wl utility then we
+                * should not report this. In case if ADD_IF was called from
+                * CFG stack, then too this event need not be reported back
+                */
+               return (BCME_OK);
        if ((wl_cfg80211_is_progress_ifchange() ||
                wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
                /*
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
deleted file mode 100644 (file)
index d4dca26..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
- *
- * Copyright (C) 1999-2011, Broadcom Corporation
- * 
- *         Unless you and Broadcom execute a separate written software license
- * agreement governing use of this software, this software is licensed to you
- * under the terms of the GNU General Public License version 2 (the "GPL"),
- * available at http://www.broadcom.com/licenses/GPLv2.php, with the
- * following added to such license:
- * 
- *      As a special exception, the copyright holders of this software give you
- * permission to link this software with independent modules, and to copy and
- * distribute the resulting executable under terms of your choice, provided that
- * you also meet, for each linked independent module, the terms and conditions of
- * the license of that module.  An independent module is a module which is not
- * derived from this software.  The special exception does not apply to any
- * modifications of the software.
- * 
- *      Notwithstanding the above, under no circumstances may you combine this
- * software in any way with any other Broadcom software provided under a license
- * other than the GPL, without Broadcom's express prior written consent.
- *
- * $Id: dhd_linux_mon.c 297563 2011-11-20 15:38:29Z $
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/ieee80211.h>
-#include <linux/rtnetlink.h>
-#include <net/ieee80211_radiotap.h>
-
-#include <wlioctl.h>
-#include <bcmutils.h>
-#include <linux_osl.h>
-#include <dhd_dbg.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-
-typedef enum monitor_states
-{
-       MONITOR_STATE_DEINIT = 0x0,
-       MONITOR_STATE_INIT = 0x1,
-       MONITOR_STATE_INTERFACE_ADDED = 0x2,
-       MONITOR_STATE_INTERFACE_DELETED = 0x4
-} monitor_states_t;
-extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
-
-/**
- * Local declarations and defintions (not exposed)
- */
-#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
-#define MON_TRACE MON_PRINT
-
-typedef struct monitor_interface {
-       int radiotap_enabled;
-       struct net_device* real_ndev;   /* The real interface that the monitor is on */
-       struct net_device* mon_ndev;
-} monitor_interface;
-
-typedef struct dhd_linux_monitor {
-       void *dhd_pub;
-       monitor_states_t monitor_state;
-       monitor_interface mon_if[DHD_MAX_IFS];
-       struct mutex lock;              /* lock to protect mon_if */
-} dhd_linux_monitor_t;
-
-static dhd_linux_monitor_t g_monitor;
-
-static struct net_device* lookup_real_netdev(char *name);
-static monitor_interface* ndev_to_monif(struct net_device *ndev);
-static int dhd_mon_if_open(struct net_device *ndev);
-static int dhd_mon_if_stop(struct net_device *ndev);
-static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
-static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
-static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
-
-static const struct net_device_ops dhd_mon_if_ops = {
-       .ndo_open               = dhd_mon_if_open,
-       .ndo_stop               = dhd_mon_if_stop,
-       .ndo_start_xmit         = dhd_mon_if_subif_start_xmit,
-       .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
-       .ndo_set_mac_address    = dhd_mon_if_change_mac,
-};
-
-/**
- * Local static function defintions
- */
-
-/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
- * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
- */
-static struct net_device* lookup_real_netdev(char *name)
-{
-       int i;
-       int len = 0;
-       int last_name_len = 0;
-       struct net_device *ndev;
-       struct net_device *ndev_found = NULL;
-
-       /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
-        * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
-        * iface would be mon-p2p0-0.
-        */
-       for (i = 0; i < DHD_MAX_IFS; i++) {
-               ndev = dhd_idx2net(g_monitor.dhd_pub, i);
-
-               /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
-                * it matches, then this netdev is the corresponding real_netdev.
-                */
-               if (ndev && strstr(ndev->name, "p2p-p2p0")) {
-                       len = strlen("p2p");
-               } else {
-               /* if p2p- is not present, then the IFNAMSIZ have reached and name
-                * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
-                */
-                       len = 0;
-               }
-               if (ndev && strstr(name, (ndev->name + len))) {
-                       if (strlen(ndev->name) > last_name_len) {
-                               ndev_found = ndev;
-                               last_name_len = strlen(ndev->name);
-                       }
-               }
-       }
-
-       return ndev_found;
-}
-
-static monitor_interface* ndev_to_monif(struct net_device *ndev)
-{
-       int i;
-
-       for (i = 0; i < DHD_MAX_IFS; i++) {
-               if (g_monitor.mon_if[i].mon_ndev == ndev)
-                       return &g_monitor.mon_if[i];
-       }
-
-       return NULL;
-}
-
-static int dhd_mon_if_open(struct net_device *ndev)
-{
-       int ret = 0;
-
-       MON_PRINT("enter\n");
-       return ret;
-}
-
-static int dhd_mon_if_stop(struct net_device *ndev)
-{
-       int ret = 0;
-
-       MON_PRINT("enter\n");
-       return ret;
-}
-
-static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
-       int ret = 0;
-       int rtap_len;
-       int qos_len = 0;
-       int dot11_hdr_len = 24;
-       int snap_len = 6;
-       unsigned char *pdata;
-       unsigned short frame_ctl;
-       unsigned char src_mac_addr[6];
-       unsigned char dst_mac_addr[6];
-       struct ieee80211_hdr *dot11_hdr;
-       struct ieee80211_radiotap_header *rtap_hdr;
-       monitor_interface* mon_if;
-
-       MON_PRINT("enter\n");
-
-       mon_if = ndev_to_monif(ndev);
-       if (mon_if == NULL || mon_if->real_ndev == NULL) {
-               MON_PRINT(" cannot find matched net dev, skip the packet\n");
-               goto fail;
-       }
-
-       if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
-               goto fail;
-
-       rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
-       if (unlikely(rtap_hdr->it_version))
-               goto fail;
-
-       rtap_len = ieee80211_get_radiotap_len(skb->data);
-       if (unlikely(skb->len < rtap_len))
-               goto fail;
-
-       MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
-
-       /* Skip the ratio tap header */
-       skb_pull(skb, rtap_len);
-
-       dot11_hdr = (struct ieee80211_hdr *)skb->data;
-       frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
-       /* Check if the QoS bit is set */
-       if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
-               /* Check if this ia a Wireless Distribution System (WDS) frame
-                * which has 4 MAC addresses
-                */
-               if (dot11_hdr->frame_control & 0x0080)
-                       qos_len = 2;
-               if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
-                       dot11_hdr_len += 6;
-
-               memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
-               memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
-
-               /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
-                * for two MAC addresses
-                */
-               skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
-               pdata = (unsigned char*)skb->data;
-               memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
-               memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
-
-               MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
-
-               /* Use the real net device to transmit the packet */
-               ret = dhd_start_xmit(skb, mon_if->real_ndev);
-
-               return ret;
-       }
-fail:
-       dev_kfree_skb(skb);
-       return 0;
-}
-
-static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
-{
-       monitor_interface* mon_if;
-
-       mon_if = ndev_to_monif(ndev);
-       if (mon_if == NULL || mon_if->real_ndev == NULL) {
-               MON_PRINT(" cannot find matched net dev, skip the packet\n");
-       } else {
-               MON_PRINT("enter, if name: %s, matched if name %s\n",
-               ndev->name, mon_if->real_ndev->name);
-       }
-}
-
-static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
-{
-       int ret = 0;
-       monitor_interface* mon_if;
-
-       mon_if = ndev_to_monif(ndev);
-       if (mon_if == NULL || mon_if->real_ndev == NULL) {
-               MON_PRINT(" cannot find matched net dev, skip the packet\n");
-       } else {
-               MON_PRINT("enter, if name: %s, matched if name %s\n",
-               ndev->name, mon_if->real_ndev->name);
-       }
-       return ret;
-}
-
-/**
- * Global function definitions (declared in dhd_linux_mon.h)
- */
-
-int dhd_add_monitor(char *name, struct net_device **new_ndev)
-{
-       int i;
-       int idx = -1;
-       int ret = 0;
-       struct net_device* ndev = NULL;
-       dhd_linux_monitor_t **dhd_mon;
-
-       mutex_lock(&g_monitor.lock);
-
-       MON_TRACE("enter, if name: %s\n", name);
-       if (!name || !new_ndev) {
-               MON_PRINT("invalid parameters\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
-       /*
-        * Find a vacancy
-        */
-       for (i = 0; i < DHD_MAX_IFS; i++)
-               if (g_monitor.mon_if[i].mon_ndev == NULL) {
-                       idx = i;
-                       break;
-               }
-       if (idx == -1) {
-               MON_PRINT("exceeds maximum interfaces\n");
-               ret = -EFAULT;
-               goto out;
-       }
-
-       ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
-       if (!ndev) {
-               MON_PRINT("failed to allocate memory\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       ndev->type = ARPHRD_IEEE80211_RADIOTAP;
-       strncpy(ndev->name, name, IFNAMSIZ);
-       ndev->name[IFNAMSIZ - 1] = 0;
-       ndev->netdev_ops = &dhd_mon_if_ops;
-
-       ret = register_netdevice(ndev);
-       if (ret) {
-               MON_PRINT(" register_netdevice failed (%d)\n", ret);
-               goto out;
-       }
-
-       *new_ndev = ndev;
-       g_monitor.mon_if[idx].radiotap_enabled = TRUE;
-       g_monitor.mon_if[idx].mon_ndev = ndev;
-       g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
-       dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
-       *dhd_mon = &g_monitor;
-       g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
-       MON_PRINT("net device returned: 0x%p\n", ndev);
-       MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
-
-out:
-       if (ret && ndev)
-               free_netdev(ndev);
-
-       mutex_unlock(&g_monitor.lock);
-       return ret;
-
-}
-
-int dhd_del_monitor(struct net_device *ndev)
-{
-       int i;
-       bool rollback_lock = false;
-       if (!ndev)
-               return -EINVAL;
-       mutex_lock(&g_monitor.lock);
-       for (i = 0; i < DHD_MAX_IFS; i++) {
-               if (g_monitor.mon_if[i].mon_ndev == ndev ||
-                       g_monitor.mon_if[i].real_ndev == ndev) {
-                       g_monitor.mon_if[i].real_ndev = NULL;
-                       if (rtnl_is_locked()) {
-                               rtnl_unlock();
-                               rollback_lock = true;
-                       }
-                       unregister_netdev(g_monitor.mon_if[i].mon_ndev);
-                       free_netdev(g_monitor.mon_if[i].mon_ndev);
-                       g_monitor.mon_if[i].mon_ndev = NULL;
-                       g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
-                       break;
-               }
-       }
-       if (rollback_lock) {
-               rtnl_lock();
-               rollback_lock = false;
-       }
-
-       if (g_monitor.monitor_state !=
-       MONITOR_STATE_INTERFACE_DELETED)
-               MON_PRINT("interface not found in monitor IF array, is this a monitor IF? 0x%p\n",
-                       ndev);
-       mutex_unlock(&g_monitor.lock);
-
-       return 0;
-}
-
-int dhd_monitor_init(void *dhd_pub)
-{
-       if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
-               g_monitor.dhd_pub = dhd_pub;
-               mutex_init(&g_monitor.lock);
-               g_monitor.monitor_state = MONITOR_STATE_INIT;
-       }
-       return 0;
-}
-
-int dhd_monitor_uninit(void)
-{
-       int i;
-       struct net_device *ndev;
-       bool rollback_lock = false;
-       mutex_lock(&g_monitor.lock);
-       if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
-               for (i = 0; i < DHD_MAX_IFS; i++) {
-                       ndev = g_monitor.mon_if[i].mon_ndev;
-                       if (ndev) {
-                               if (rtnl_is_locked()) {
-                                       rtnl_unlock();
-                                       rollback_lock = true;
-                               }
-                               unregister_netdev(ndev);
-                               free_netdev(ndev);
-                               g_monitor.mon_if[i].real_ndev = NULL;
-                               g_monitor.mon_if[i].mon_ndev = NULL;
-                               if (rollback_lock) {
-                                       rtnl_lock();
-                                       rollback_lock = false;
-                               }
-                       }
-               }
-               g_monitor.monitor_state = MONITOR_STATE_DEINIT;
-       }
-       mutex_unlock(&g_monitor.lock);
-       return 0;
-}
index 7866eb771d586afffd067178458d167da26b68f4..e19ec6b9c7e47255d5196e70ad44992b8cbb38c5 100644 (file)
@@ -21,7 +21,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhd_sdio.c 301794 2011-12-08 20:41:35Z $
+ * $Id: dhd_sdio.c 303389 2011-12-16 09:30:48Z $
  */
 
 #include <typedefs.h>
@@ -1518,7 +1518,7 @@ enum {
 #ifdef DHD_DEBUG
        IOV_CHECKDIED,
        IOV_SERIALCONS,
-#endif
+#endif /* DHD_DEBUG */
        IOV_DOWNLOAD,
        IOV_SOCRAM_STATE,
        IOV_FORCEEVEN,
index 3f3755b53b09e3db6b16227cda131f2c31405b64..0312d2206013600a5e95fe2e18533795d792ff4e 100644 (file)
@@ -25,7 +25,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: dhdioctl.h 277737 2011-08-16 17:54:59Z $
+ * $Id: dhdioctl.h 307573 2012-01-12 00:04:39Z $
  */
 
 #ifndef _dhdioctl_h_
@@ -87,6 +87,7 @@ enum {
 #define DHD_BTA_VAL    0x1000
 #define DHD_ISCAN_VAL  0x2000
 #define DHD_ARPOE_VAL  0x4000
+#define DHD_WL_VAL     0x8000
 
 #ifdef SDTEST
 /* For pktgen iovar */
index 41a078c42a033ea440dd253da98738b80646672f..a0e9ed12b88e73c85b54b097135bf6e6c6b8b065 100644 (file)
 
 #define        EPI_RC_NUMBER           195
 
-#define        EPI_INCREMENTAL_NUMBER  15
+#define        EPI_INCREMENTAL_NUMBER  19
 
 #define        EPI_BUILD_NUMBER        0
 
-#define        EPI_VERSION             5, 90, 195, 15
+#define        EPI_VERSION             5, 90, 195, 19
 
-#define        EPI_VERSION_NUM         0x055ac30f
+#define        EPI_VERSION_NUM         0x055ac313
 
 #define EPI_VERSION_DEV                5.90.195
 
 
-#define        EPI_VERSION_STR         "5.90.195.15"
+#define        EPI_VERSION_STR         "5.90.195.19"
 
 #endif 
index 8850b2ded2360aad8de11e47fd344ed61ea9b2e8..fd69aac413098f497bebac8d5d247f25bb98982b 100644 (file)
@@ -21,7 +21,7 @@
  *
  * Fundamental types and constants relating to 802.11
  *
- * $Id: 802.11.h 289520 2011-10-13 04:44:55Z $
+ * $Id: 802.11.h 304058 2011-12-21 00:39:12Z $
  */
 
 
@@ -1394,6 +1394,14 @@ typedef struct dot11_ext_cap_ie dot11_ext_cap_ie_t;
 
 #define DOT11_OP_CLASS_NONE                    255
 
+BWL_PRE_PACKED_STRUCT struct do11_ap_chrep {
+       uint8 id;
+       uint8 len;
+       uint8 reg;
+       uint8 chanlist[1];
+} BWL_POST_PACKED_STRUCT;
+typedef struct do11_ap_chrep dot11_ap_chrep_t;
+
 
 #define DOT11_RM_ACTION_RM_REQ      0   
 #define DOT11_RM_ACTION_RM_REP      1   
@@ -1484,7 +1492,7 @@ typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t;
 #define DOT11_RMREQ_BCN_REPINFO_ID  1
 #define DOT11_RMREQ_BCN_REPDET_ID   2
 #define DOT11_RMREQ_BCN_REQUEST_ID  10
-#define DOT11_RMREQ_BCN_APCHREP_ID  51
+#define DOT11_RMREQ_BCN_APCHREP_ID  DOT11_MNG_AP_CHREP_ID
 
 
 #define DOT11_RMREQ_BCN_REPDET_FIXED    0   
index 676068c0b387532c4e13a543197a8c1a972a2fe6..e31bfa94c006afcb9ce4a77c02bd6b9ceaf3423f 100644 (file)
@@ -24,7 +24,7 @@
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wlioctl.h 302303 2011-12-10 07:51:07Z $
+ * $Id: wlioctl.h 307468 2012-01-11 18:29:27Z $
  */
 
 
@@ -821,8 +821,14 @@ typedef struct wlc_iov_trx_s {
 #define WLC_IOCTL_MEDLEN        1536    
 #ifdef WLC_HIGH_ONLY
 #define WLC_SAMPLECOLLECT_MAXLEN    1024    
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40  1024
 #else
-#define WLC_SAMPLECOLLECT_MAXLEN    10240   
+#if defined(LCNCONF) || defined(LCN40CONF)
+#define WLC_SAMPLECOLLECT_MAXLEN       8192    
+#else
+#define WLC_SAMPLECOLLECT_MAXLEN       10240   
+#endif
+#define WLC_SAMPLECOLLECT_MAXLEN_LCN40  8192
 #endif 
 
 
@@ -1411,7 +1417,7 @@ typedef struct wl_aci_args {
 #define TRIGGER_BADPLCP             0x10
 #define TRIGGER_CRSGLITCH           0x20
 #define WL_ACI_ARGS_LEGACY_LENGTH   16  
-#define WL_SAMPLECOLLECT_T_VERSION  1   
+#define        WL_SAMPLECOLLECT_T_VERSION      2       
 typedef struct wl_samplecollect_args {
        
        uint8 coll_us;
@@ -1419,7 +1425,7 @@ typedef struct wl_samplecollect_args {
        
        uint16 version;     
        uint16 length;      
-       uint8 trigger;
+       int8 trigger;
        uint16 timeout;
        uint16 mode;
        uint32 pre_dur;
@@ -1429,6 +1435,11 @@ typedef struct wl_samplecollect_args {
        bool be_deaf;
        bool agc;       
        bool filter;        
+       
+       uint8 trigger_state;
+       uint8 module_sel1;
+       uint8 module_sel2;
+       uint16 nsamps;
 } wl_samplecollect_args_t;
 
 #define WL_SAMPLEDATA_HEADER_TYPE   1
index dc32f17a91facd549cae3f1df9461931ad3bd0d5..2cbe333b0dd622864921d54932a841c0c3bf272d 100644 (file)
@@ -73,7 +73,6 @@
 #define CMD_GETBAND                            "GETBAND"
 #define CMD_COUNTRY                            "COUNTRY"
 #define CMD_P2P_SET_NOA                        "P2P_SET_NOA"
-#define CMD_P2P_GET_NOA                        "P2P_GET_NOA"
 #define CMD_P2P_SET_PS                 "P2P_SET_PS"
 #define CMD_SET_AP_WPS_P2P_IE  "SET_AP_WPS_P2P_IE"
 
@@ -537,9 +536,6 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
                bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
                        priv_cmd.total_len - skip);
        }
-       else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
-               bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
-       }
        else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
                int skip = strlen(CMD_P2P_SET_PS) + 1;
                bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
@@ -611,30 +607,14 @@ int wl_android_exit(void)
        return ret;
 }
 
-int wl_android_post_init(void)
+void wl_android_post_init(void)
 {
-       struct net_device *ndev;
-       int ret = 0;
-       char buf[IFNAMSIZ];
        if (!dhd_download_fw_on_driverload) {
                /* Call customer gpio to turn off power with WL_REG_ON signal */
                dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
                g_wifi_on = 0;
-       } else {
-               memset(buf, 0, IFNAMSIZ);
-#ifdef CUSTOMER_HW2
-               snprintf(buf, IFNAMSIZ, "%s%d", iface_name, 0);
-#else
-               snprintf(buf, IFNAMSIZ, "%s%d", "eth", 0);
-#endif
-               if ((ndev = dev_get_by_name (&init_net, buf)) != NULL) {
-                       dhd_dev_init_ioctl(ndev);
-                       dev_put(ndev);
-               }
        }
-       return ret;
 }
-
 /**
  * Functions for Android WiFi card detection
  */
index 17373b7f6d5bbdf259aa854c22ac8ba1e2d4f84d..3983306cfe38e643f714cb1a602b9e899b54393d 100644 (file)
@@ -40,7 +40,7 @@
  */
 int wl_android_init(void);
 int wl_android_exit(void);
-int wl_android_post_init(void);
+void wl_android_post_init(void);
 int wl_android_wifi_on(struct net_device *dev);
 int wl_android_wifi_off(struct net_device *dev);
 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
index 93fa447c16ba120632d292404814e3c2b20a6b82..2312e0d2443243944cc68d36bf16285eeef75eb9 100644 (file)
 #include <dhd.h>
 #include <dhdioctl.h>
 #include <wlioctl.h>
+#include <dhd_cfg80211.h>
 
 #include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/netdevice.h>
 #include <linux/ieee80211.h>
 #include <linux/wait.h>
 #include <net/cfg80211.h>
-
 #include <net/rtnetlink.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/firmware.h>
-#include <bcmsdbus.h>
 
 #include <wlioctl.h>
 #include <wldev_common.h>
 #include <wl_cfgp2p.h>
 
 static struct device *cfg80211_parent_dev = NULL;
-static struct wl_priv *wlcfg_drv_priv = NULL;
+static int vsdb_supported = 0;
+struct wl_priv *wlcfg_drv_priv = NULL;
 
 u32 wl_dbg_level = WL_DBG_ERR;
 
-#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
-#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 #define MAX_WAIT_TIME 1500
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
+#define WL_SCAN_ACTIVE_TIME     40
+#define WL_SCAN_PASSIVE_TIME   130
 
+#define DNGL_FUNC(func, parameters) func parameters;
 #define COEX_DHCP
 
-#if defined(COEX_DHCP)
-#define BT_DHCP_eSCO_FIX               /* use New SCO/eSCO smart YG
-                                        * suppression
-                                        */
-#define BT_DHCP_USE_FLAGS              /* this flag boost wifi pkt priority
-                                        * to max, caution: -not fair to sco
-                                        */
-#define BT_DHCP_OPPR_WIN_TIME  2500    /* T1 start SCO/ESCo priority
-                                        * suppression
-                                        */
-#define BT_DHCP_FLAG_FORCE_TIME 5500   /* T2 turn off SCO/SCO supperesion
-                                        * is (timeout)
-                                        */
-enum wl_cfg80211_btcoex_status {
-       BT_DHCP_IDLE,
-       BT_DHCP_START,
-       BT_DHCP_OPPR_WIN,
-       BT_DHCP_FLAG_FORCE_TIMEOUT
-};
-
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
-static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
-#endif
 
 /* Set this to 1 to use a seperate interface (p2p0)
  *  for p2p operations.
@@ -247,6 +220,8 @@ static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type,
        const wl_event_msg_t *msg, void *data);
 static void wl_put_event(struct wl_event_q *e);
 static void wl_wakeup_event(struct wl_priv *wl);
+static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
+       const wl_event_msg_t *e, void *data);
 static s32 wl_notify_connect_status(struct wl_priv *wl,
        struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
@@ -264,21 +239,10 @@ static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
 static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data);
 /*
- * register/deregister sdio function
+ * register/deregister parent device
  */
 static void wl_cfg80211_clear_parent_dev(void);
 
-/*
- * ioctl utilites
- */
-static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
-       s32 buf_len);
-static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
-       s8 *buf, s32 len);
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
-static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
-       s32 *retval);
-
 /*
  * cfg80211 set_wiphy_params utilities
  */
@@ -321,7 +285,7 @@ static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
 static u32 wl_get_ielen(struct wl_priv *wl);
 
 
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev);
 static void wl_free_wdev(struct wl_priv *wl);
 
 static s32 wl_inform_bss(struct wl_priv *wl);
@@ -353,42 +317,19 @@ static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev);
 static __used bool wl_is_ibssstarter(struct wl_priv *wl);
 
 /*
- * dongle up/down , default configuration utilities
+ * link up/down , default configuration utilities
  */
+static s32 __wl_cfg80211_up(struct wl_priv *wl);
+static s32 __wl_cfg80211_down(struct wl_priv *wl);
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
 static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
 static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev);
 static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
 static void wl_link_up(struct wl_priv *wl);
 static void wl_link_down(struct wl_priv *wl);
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
-static s32 __wl_cfg80211_up(struct wl_priv *wl);
-static s32 __wl_cfg80211_down(struct wl_priv *wl);
-static s32 wl_dongle_probecap(struct wl_priv *wl);
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
 static void wl_init_conf(struct wl_conf *conf);
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
-
-/*
- * dongle configuration utilities
- */
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
-static s32 wl_dongle_up(struct net_device *ndev, u32 up);
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
-static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
-       u32 dongle_align);
-static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
-       u32 bcn_timeout);
-static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
-       s32 scan_unassoc_time);
-static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
-       s32 arp_ol);
-static s32 wl_pattern_atoh(s8 *src, s8 *dst);
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
 static s32 wl_update_wiphybands(struct wl_priv *wl);
-#endif                         /* !EMBEDDED_PLATFORM */
-static __used void wl_dongle_poweron(struct wl_priv *wl);
-static __used void wl_dongle_poweroff(struct wl_priv *wl);
-static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
 
 /*
  * iscan handler
@@ -411,34 +352,21 @@ static s32 wl_iscan_pending(struct wl_priv *wl);
 static s32 wl_iscan_inprogress(struct wl_priv *wl);
 static s32 wl_iscan_aborted(struct wl_priv *wl);
 
-/*
- * fw/nvram downloading handler
- */
-static void wl_init_fw(struct wl_fw_ctrl *fw);
-
 /*
  * find most significant bit set
  */
 static __used u32 wl_find_msb(u16 bit16);
 
-/*
- * update pmklist to dongle
- */
-static __used s32 wl_update_pmklist(struct net_device *dev,
-       struct wl_pmk_list *pmk_list, s32 err);
-
-/*
- * debufs support
- */
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl, struct net_device *ndev);
-static void wl_debugfs_remove_netdev(struct wl_priv *wl);
-
 /*
  * rfkill support
  */
 static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
 static int wl_rfkill_set(void *data, bool blocked);
 
+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel,
+       int nprobes, int *out_params_size);
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac);
+
 /*
  * Some external functions, TODO: move them to dhd_linux.h
  */
@@ -579,7 +507,22 @@ static struct ieee80211_supported_band __wl_band_2ghz = {
        .channels = __wl_2ghz_channels,
        .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
        .bitrates = wl_g_rates,
-       .n_bitrates = wl_g_rates_size
+       .n_bitrates = wl_g_rates_size,
+#if ENABLE_P2P_INTERFACE
+       /* wpa_supplicant sets wmm_enabled based on whether ht_cap
+        * is present or not. The wmm_enabled is inturn used to
+        * set the replay counters in the RSN IE. Without this
+        * the 4way handshake will fail complaining that IE in beacon
+        * doesn't match with the IE present in the 3/4 EAPOL msg.
+        */
+       .ht_cap = {
+                               IEEE80211_HT_CAP_SGI_20 |
+                               IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
+                               .ht_supported = TRUE,
+                               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+                               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
+       }
+#endif
 };
 
 static struct ieee80211_supported_band __wl_band_5ghz_a = {
@@ -748,36 +691,39 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc)
 
 static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
 {
-       chanspec_t chspec;
-       int err = 0;
-       struct wl_priv *wl = wiphy_priv(wiphy);
-       struct net_device *dev = wl_to_prmry_ndev(wl);
-       struct ether_addr bssid;
-       struct wl_bss_info *bss = NULL;
-
-       if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
-               /* STA interface is not associated. So start the new interface on a temp
-                * channel . Later proper channel will be applied by the above framework
-                * via set_channel (cfg80211 API).
-                */
-               WL_DBG(("Not associated. Return a temp channel. \n"));
+       if (vsdb_supported) {
                return wf_chspec_aton(WL_P2P_TEMP_CHAN);
        }
+       else {
+               chanspec_t chspec;
+               int err = 0;
+               struct wl_priv *wl = wiphy_priv(wiphy);
+               struct net_device *dev = wl_to_prmry_ndev(wl);
+               struct ether_addr bssid;
+               struct wl_bss_info *bss = NULL;
+               if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
+                       /* STA interface is not associated. So start the new interface on a temp
+                        * channel . Later proper channel will be applied by the above framework
+                        * via set_channel (cfg80211 API).
+                        */
+                       WL_DBG(("Not associated. Return a temp channel. \n"));
+                       return wf_chspec_aton(WL_P2P_TEMP_CHAN);
+               }
 
 
-       *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
-       if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
-               sizeof(WL_EXTRA_BUF_MAX), false))) {
-                       WL_ERR(("Failed to get associated bss info, use temp channel \n"));
-                       chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
-       }
-       else {
-                       bss = (struct wl_bss_info *) (wl->extra_buf + 4);
-                       chspec =  bss->chanspec;
-                       WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec));
+               *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+               if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
+                       sizeof(WL_EXTRA_BUF_MAX), false))) {
+                               WL_ERR(("Failed to get associated bss info, use temp channel \n"));
+                               chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+               }
+               else {
+                               bss = (struct wl_bss_info *) (wl->extra_buf + 4);
+                               chspec =  bss->chanspec;
+                               WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec));
+               }
+               return chspec;
        }
-
-       return chspec;
 }
 
 static struct net_device* wl_cfg80211_add_monitor_if(char *name)
@@ -802,9 +748,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
        chanspec_t chspec;
        struct wl_priv *wl = wiphy_priv(wiphy);
        struct net_device *_ndev;
-       dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
-       int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
+       struct ether_addr primary_mac;
+       int (*net_attach)(void *dhdp, int ifidx);
        bool rollback_lock = false;
+
        /* Use primary I/F for sending cmds down to firmware */
        _ndev = wl_to_prmry_ndev(wl);
 
@@ -852,7 +799,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                        }
                        WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
                                __func__));
-                       timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+                       timeout = wait_event_interruptible_timeout(wl->netif_change_event,
                                (wl_get_p2p_status(wl, IF_DELETING) == false),
                                msecs_to_jiffies(MAX_WAIT_TIME));
 
@@ -874,9 +821,11 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                        wl_cfgp2p_set_firm_p2p(wl);
                        wl_cfgp2p_init_discovery(wl);
                }
+
                memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
                strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
-               wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+               get_primary_mac(wl, &primary_mac);
+               wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
 
                /* In concurrency case, STA may be already associated in a particular channel.
                 * so retrieve the current channel of primary interface and then start the virtual
@@ -895,7 +844,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                        return ERR_PTR(-ENOMEM);
                }
 
-               timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+               timeout = wait_event_interruptible_timeout(wl->netif_change_event,
                        (wl_get_p2p_status(wl, IF_ADD) == false),
                        msecs_to_jiffies(MAX_WAIT_TIME));
                if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
@@ -922,7 +871,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
                                rtnl_unlock();
                                rollback_lock = true;
                        }
-                       if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
+                       if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) {
                                wl_alloc_netinfo(wl, _ndev, vwdev, mode);
                                WL_DBG((" virtual interface(%s) is "
                                        "created net attach done\n", wl->p2p->vir_ifname));
@@ -973,21 +922,22 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
                        wldev_iovar_setint(dev, "mpc", 1);
                        wl_set_p2p_status(wl, IF_DELETING);
                        ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
-                       if (ret) {
                        /* Firmware could not delete the interface so we will not get WLC_E_IF
                        * event for cleaning the dhd virtual nw interace
                        * So lets do it here. Failures from fw will ensure the application to do
                        * ifconfig <inter> down and up sequnce, which will reload the fw
                        * however we should cleanup the linux network virtual interfaces
                        */
-                               dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
-                               WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
-                               WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
-                               dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
+                       /* Request framework to RESET and clean up */
+                       if (ret) {
+                               struct net_device *ndev = wl_to_prmry_ndev(wl);
+                               WL_ERR(("Firmware returned an error (%d) from p2p_ifdel"
+                                       "HANG Notification sent to %s\n", ret, ndev->name));
+                               wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED);
                        }
 
                        /* Wait for any pending scan req to get aborted from the sysioc context */
-                       timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+                       timeout = wait_event_interruptible_timeout(wl->netif_change_event,
                                (wl_get_p2p_status(wl, IF_DELETING) == false),
                                msecs_to_jiffies(MAX_WAIT_TIME));
                        if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
@@ -1014,6 +964,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
        s32 mode = 0;
        chanspec_t chspec;
        struct wl_priv *wl = wiphy_priv(wiphy);
+
        WL_DBG(("Enter \n"));
        switch (type) {
        case NL80211_IFTYPE_MONITOR:
@@ -1046,7 +997,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                if (wl->p2p_supported && wl->p2p->vif_created) {
                        WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
                        p2p_on(wl)));
-
+                       wldev_iovar_setint(ndev, "mpc", 0);
                        /* In concurrency case, STA may be already associated in a particular
                         * channel. so retrieve the current channel of primary interface and
                         * then start the virtual interface on that.
@@ -1059,7 +1010,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                        wl_set_p2p_status(wl, IF_CHANGING);
                        wl_clr_p2p_status(wl, IF_CHANGED);
                        err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
-                       timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+                       timeout = wait_event_interruptible_timeout(wl->netif_change_event,
                                (wl_get_p2p_status(wl, IF_CHANGED) == true),
                                msecs_to_jiffies(MAX_WAIT_TIME));
                        wl_set_mode_by_netdev(wl, ndev, mode);
@@ -1085,10 +1036,11 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
 
 s32
 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
+       void* _net_attach)
 {
        struct wl_priv *wl = wlcfg_drv_priv;
        s32 ret = BCME_OK;
+       WL_DBG(("Enter"));
        if (!ndev) {
                WL_ERR(("net is NULL\n"));
                return 0;
@@ -1104,7 +1056,7 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
                ndev->ifindex = idx;
                wl_clr_p2p_status(wl, IF_ADD);
 
-               wake_up_interruptible(&wl->dongle_event_wait);
+               wake_up_interruptible(&wl->netif_change_event);
        } else {
                ret = BCME_NOTREADY;
        }
@@ -1153,7 +1105,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev)
 
        }
        /* Wake up any waiting thread */
-       wake_up_interruptible(&wl->dongle_event_wait);
+       wake_up_interruptible(&wl->netif_change_event);
 
        return 0;
 }
@@ -1185,7 +1137,7 @@ wl_cfg80211_notify_ifchange(void)
        struct wl_priv *wl = wlcfg_drv_priv;
        if (wl_get_p2p_status(wl, IF_CHANGING)) {
                wl_set_p2p_status(wl, IF_CHANGED);
-               wake_up_interruptible(&wl->dongle_event_wait);
+               wake_up_interruptible(&wl->netif_change_event);
        }
        return 0;
 }
@@ -1222,6 +1174,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
        params->passive_time = htod32(params->passive_time);
        params->home_time = htod32(params->home_time);
 
+       /* if request is null just exit so it will be all channel broadcast scan */
        if (!request)
                return;
 
@@ -1328,7 +1281,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
                goto done;
        }
        err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
-               iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
+               iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
        if (unlikely(err)) {
                if (err == -EBUSY) {
                        WL_ERR(("system busy : iscan canceled\n"));
@@ -1418,7 +1371,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
                        goto exit;
                }
                err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
-                       wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
+                       wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
                if (unlikely(err))
                        WL_ERR((" Escan set error (%d)\n", err));
                kfree(params);
@@ -1516,8 +1469,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        u32 wpsie_len = 0;
        u8 wpsie[IE_MAX_LEN];
 
-       /* If scan req comes for p2p0, send it over primary I/F as there
-        * there is no firmware interface corresponding to p2p0.
+       /* If scan req comes for p2p0, send it over primary I/F
         * Scan results will be delivered corresponding to cfg80211_scan_request
         */
        if (ndev == wl->p2p_net) {
@@ -1534,7 +1486,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                return -EAGAIN;
        }
        if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
-               WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+               WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
                return -EOPNOTSUPP;
        }
 
@@ -1700,52 +1652,11 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
        return err;
 }
 
-static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
-{
-       s8 buf[WLC_IOCTL_SMLEN];
-       u32 len;
-       s32 err = 0;
-
-       val = htod32(val);
-       len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
-       BUG_ON(unlikely(!len));
-
-       err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
-       if (unlikely(err)) {
-               WL_ERR(("error (%d)\n", err));
-       }
-
-       return err;
-}
-
-static s32
-wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
-{
-       union {
-               s8 buf[WLC_IOCTL_SMLEN];
-               s32 val;
-       } var;
-       u32 len;
-       u32 data_null;
-       s32 err = 0;
-
-       len = bcm_mkiovar(name, (char *)(&data_null), 0,
-               (char *)(&var), sizeof(var.buf));
-       BUG_ON(unlikely(!len));
-       err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
-       if (unlikely(err)) {
-               WL_ERR(("error (%d)\n", err));
-       }
-       *retval = dtoh32(var.val);
-
-       return err;
-}
-
 static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
 {
        s32 err = 0;
 
-       err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
+       err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
        if (unlikely(err)) {
                WL_ERR(("Error (%d)\n", err));
                return err;
@@ -1757,7 +1668,7 @@ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
 {
        s32 err = 0;
 
-       err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
+       err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
        if (unlikely(err)) {
                WL_ERR(("Error (%d)\n", err));
                return err;
@@ -1786,6 +1697,7 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        s32 err = 0;
 
        CHECK_SYS_UP(wl);
+       WL_DBG(("Enter\n"));
        if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
                (wl->conf->rts_threshold != wiphy->rts_threshold)) {
                wl->conf->rts_threshold = wiphy->rts_threshold;
@@ -1815,7 +1727,6 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
                        return err;
                }
        }
-
        return err;
 }
 
@@ -2060,7 +1971,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
        s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
 
        if (sme->crypto.n_akm_suites) {
-               err = wl_dev_intvar_get(dev, "wpa_auth", &val);
+               err = wldev_iovar_getint(dev, "wpa_auth", &val);
                if (unlikely(err)) {
                        WL_ERR(("could not get wpa_auth (%d)\n", err));
                        return err;
@@ -2125,7 +2036,8 @@ wl_set_set_sharedkey(struct net_device *dev,
                if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
                        NL80211_WPA_VERSION_2)) &&
                        (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
-                       WLAN_CIPHER_SUITE_WEP104))) {
+               WLAN_CIPHER_SUITE_WEP104)))
+               {
                        memset(&key, 0, sizeof(key));
                        key.len = (u32) sme->key_len;
                        key.index = (u32) sme->key_idx;
@@ -2153,7 +2065,7 @@ wl_set_set_sharedkey(struct net_device *dev,
                        WL_DBG(("key \"%s\"\n", key.data));
                        swap_key_from_BE(&key);
                        err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
-                               ioctlbuf, sizeof(ioctlbuf), bssidx);
+                               wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
                        if (unlikely(err)) {
                                WL_ERR(("WLC_SET_KEY error (%d)\n", err));
                                return err;
@@ -2247,10 +2159,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                                wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
                                wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
                                wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
-                               ioctlbuf, sizeof(ioctlbuf));
+                                       wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
                        } else {
                                wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
-                               ioctlbuf, sizeof(ioctlbuf));
+                                       wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
                        }
 
                        /* find the WPSIE */
@@ -2331,8 +2243,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        /* increate dwell time to receive probe response or detect Beacon
        * from target AP at a noisy air only during connect command
        */
-       ext_join_params->scan.active_time = DHD_SCAN_ACTIVE_TIME*3;
-       ext_join_params->scan.passive_time = DHD_SCAN_PASSIVE_TIME*3;
+       ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3;
+       ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3;
        ext_join_params->scan.home_time = -1;
 
        if (sme->bssid)
@@ -2360,8 +2272,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                        ext_join_params->ssid.SSID_len));
        }
        wl_set_drv_status(wl, CONNECTING, dev);
-       err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
-               sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
+       err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync);
        kfree(ext_join_params);
        if (err) {
                wl_clr_drv_status(wl, CONNECTING, dev);
@@ -2480,7 +2392,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
                txpwrmw = 0xffff;
        else
                txpwrmw = (u16) dbm;
-       err = wl_dev_intvar_set(ndev, "qtxpower",
+       err = wldev_iovar_setint(ndev, "qtxpower",
                (s32) (bcm_mw_to_qdbm(txpwrmw)));
        if (unlikely(err)) {
                WL_ERR(("qtxpower error (%d)\n", err));
@@ -2500,7 +2412,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
        s32 err = 0;
 
        CHECK_SYS_UP(wl);
-       err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
+       err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm);
        if (unlikely(err)) {
                WL_ERR(("error (%d)\n", err));
                return err;
@@ -2561,8 +2473,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
        if (key.len == 0) {
                /* key delete */
                swap_key_from_BE(&key);
-               wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-                       sizeof(ioctlbuf), bssidx);
+               wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+                       wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
                if (unlikely(err)) {
                        WL_ERR(("key delete error (%d)\n", err));
                        return err;
@@ -2620,11 +2532,11 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
                        return -EINVAL;
                }
                swap_key_from_BE(&key);
-#ifdef CONFIG_WIRELESS_EXT
+#if defined(CONFIG_WIRELESS_EXT)
                dhd_wait_pend8021x(dev);
 #endif
-               wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-                       sizeof(ioctlbuf), bssidx);
+               wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+                       wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
                if (unlikely(err)) {
                        WL_ERR(("WLC_SET_KEY error (%d)\n", err));
                        return err;
@@ -2706,8 +2618,8 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 
        /* Set the new key/index */
        swap_key_from_BE(&key);
-       err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-               sizeof(ioctlbuf), bssidx);
+       err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+               WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
        if (unlikely(err)) {
                WL_ERR(("WLC_SET_KEY error (%d)\n", err));
                return err;
@@ -2750,8 +2662,8 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
        WL_DBG(("key index (%d)\n", key_idx));
        /* Set the new key/index */
        swap_key_from_BE(&key);
-       wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
-               sizeof(ioctlbuf), bssidx);
+       wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf,
+               WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
        if (unlikely(err)) {
                if (err == -EINVAL) {
                        if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
@@ -2847,13 +2759,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
        CHECK_SYS_UP(wl);
        if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
                err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
-                       ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
+                       ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
                if (err < 0) {
                        WL_ERR(("GET STA INFO failed, %d\n", err));
                        return err;
                }
                sinfo->filled = STATION_INFO_INACTIVE_TIME;
-               sta = (sta_info_t *)ioctlbuf;
+               sta = (sta_info_t *)wl->ioctl_buf;
                sta->len = dtoh16(sta->len);
                sta->cap = dtoh16(sta->cap);
                sta->flags = dtoh32(sta->flags);
@@ -2931,9 +2843,6 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        CHECK_SYS_UP(wl);
 
        if (wl->p2p_net == dev) {
-               /* Since p2p0 is a hidden interface in firmware, power
-                * mgmt doesn't apply.
-                */
                return err;
        }
 
@@ -3019,7 +2928,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
        for_each_ndev(wl, iter, next)
                wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
        wl_term_iscan(wl);
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        if (wl->scan_request) {
                cfg80211_scan_done(wl->scan_request, true);
                wl->scan_request = NULL;
@@ -3028,7 +2937,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
                wl_clr_drv_status(wl, SCANNING, iter->ndev);
                wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev);
        }
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        for_each_ndev(wl, iter, next) {
                if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) {
                        wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false);
@@ -3038,7 +2947,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
        return 0;
 }
 
-static __used s32
+static s32
 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
        s32 err)
 {
@@ -3046,9 +2955,12 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
        struct wl_priv *wl = wlcfg_drv_priv;
        struct net_device *primary_dev = wl_to_prmry_ndev(wl);
 
-       /* Firmware is supporting pmk list only for STA interface i.e. primary interface
+       if (!pmk_list) {
+               printk("pmk_list is NULL\n");
+               return -EINVAL;
+       }
+       /* pmk list is supported only for STA interface i.e. primary interface
          * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
-         * Do we really need to support PMK cache in P2P in firmware?
        */
        if (primary_dev != dev) {
                WL_INFO(("Not supporting Flushing pmklist on virtual"
@@ -3065,8 +2977,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
                }
        }
        if (likely(!err)) {
-               err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
-                       sizeof(*pmk_list));
+               err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
+                       sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
        }
 
        return err;
@@ -3167,7 +3079,7 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
 
 }
 
-wl_scan_params_t *
+static wl_scan_params_t *
 wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
 {
        wl_scan_params_t *params;
@@ -3228,13 +3140,13 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
                }
        }
        del_timer_sync(&wl->scan_timeout);
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        if (wl->scan_request) {
                cfg80211_scan_done(wl->scan_request, true);
                wl->scan_request = NULL;
        }
        wl_clr_drv_status(wl, SCANNING, ndev);
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        if (params)
                kfree(params);
        return err;
@@ -3248,23 +3160,21 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
 {
        s32 target_channel;
        u32 id;
+       struct ether_addr primary_mac;
        struct net_device *ndev = NULL;
+
        s32 err = BCME_OK;
        struct wl_priv *wl = wiphy_priv(wiphy);
-       dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
        WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
 
        if (wl->p2p_net == dev) {
-               /* Since there is no ifidx corresponding to p2p0, cmds to
-                * firmware should be routed through primary I/F
-                */
                ndev = wl_to_prmry_ndev(wl);
        } else {
                ndev = dev;
        }
 
-       if (wl_get_drv_status(wl, SCANNING, dev)) {
-               wl_cfg80211_scan_abort(wl, dev);
+       if (wl_get_drv_status(wl, SCANNING, ndev)) {
+               wl_cfg80211_scan_abort(wl, ndev);
        }
 
        target_channel = ieee80211_frequency_to_channel(channel->center_freq);
@@ -3277,14 +3187,15 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
        cfg80211_ready_on_channel(dev, *cookie, channel,
                channel_type, duration, GFP_KERNEL);
        if (!p2p_is_on(wl)) {
-               wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+               get_primary_mac(wl, &primary_mac);
+               wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
 
                /* In case of p2p_listen command, supplicant send remain_on_channel
                 * without turning on P2P
                 */
 
                p2p_on(wl) = true;
-               err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
+               err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0);
 
                if (unlikely(err)) {
                        goto exit;
@@ -3307,6 +3218,93 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev
        return err;
 }
 
+static s32
+wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl)
+{
+       wl_af_params_t *tx_act_frm;
+       struct net_device *dev = wl->afx_hdl->dev;
+       if (!p2p_is_on(wl))
+               return -1;
+
+       if (dev == wl->p2p_net) {
+               dev = wl_to_prmry_ndev(wl);
+       }
+
+       tx_act_frm = wl->afx_hdl->pending_tx_act_frm;
+       WL_DBG(("Sending the action frame\n"));
+       wl->afx_hdl->pending_tx_act_frm = NULL;
+       if (tx_act_frm != NULL) {
+               /* Suspend P2P discovery's search-listen to prevent it from
+                * starting a scan or changing the channel.
+                */
+               wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev);
+               wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+               wl_cfg80211_scan_abort(wl, dev);
+               wl_cfgp2p_discover_enable_search(wl, false);
+               tx_act_frm->channel = wl->afx_hdl->peer_chan;
+               wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev,
+                       tx_act_frm, wl->afx_hdl->bssidx)) ? false : true;
+       }
+       return 0;
+}
+static void
+wl_cfg80211_afx_handler(struct work_struct *work)
+{
+
+       struct afx_hdl *afx_instance;
+       struct wl_priv *wl = wlcfg_drv_priv;
+       afx_instance = container_of(work, struct afx_hdl, work);
+       if (afx_instance != NULL) {
+               wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev,
+                       wl->afx_hdl->bssidx, 0);
+       }
+}
+
+static bool
+wl_cfg80211_send_at_common_channel(struct wl_priv *wl,
+       struct net_device *dev,
+       wl_af_params_t *af_params)
+{
+       WL_DBG((" enter ) \n"));
+       /* initialize afx_hdl */
+       wl->afx_hdl->pending_tx_act_frm = af_params;
+       wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev);
+       wl->afx_hdl->dev = dev;
+       wl->afx_hdl->retry = 0;
+       wl->afx_hdl->peer_chan = WL_INVALID;
+       wl->afx_hdl->ack_recv = false;
+       memcpy(wl->afx_hdl->pending_tx_dst_addr.octet,
+               af_params->action_frame.da.octet,
+               sizeof(wl->afx_hdl->pending_tx_dst_addr.octet));
+       /* Loop to wait until we have sent the pending tx action frame or the
+        * pending action frame tx is cancelled.
+        */
+       while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) &&
+               (wl->afx_hdl->peer_chan == WL_INVALID)) {
+               wl_set_drv_status(wl, SENDING_ACT_FRM, dev);
+               wl_set_drv_status(wl, SCANNING, dev);
+               WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
+                       wl->afx_hdl->retry));
+               /* Do find_peer_for_action */
+               schedule_work(&wl->afx_hdl->work);
+               wait_for_completion(&wl->act_frm_scan);
+               wl->afx_hdl->retry++;
+       }
+       if (wl->afx_hdl->peer_chan != WL_INVALID)
+               wl_cfg80211_send_pending_tx_act_frm(wl);
+       else {
+               WL_ERR(("Couldn't find the peer after %d retries\n",
+                       wl->afx_hdl->retry));
+       }
+       wl->afx_hdl->dev = NULL;
+       wl->afx_hdl->bssidx = WL_INVALID;
+       wl_clr_drv_status(wl, SENDING_ACT_FRM, dev);
+       if (wl->afx_hdl->ack_recv)
+               return true; /* ACK */
+       else
+               return false; /* NO ACK */
+}
+
 static s32
 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        struct ieee80211_channel *channel, bool offchan,
@@ -3314,29 +3312,28 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        bool channel_type_valid, unsigned int wait,
        const u8* buf, size_t len, u64 *cookie)
 {
+       struct ether_addr primary_mac;
        wl_action_frame_t *action_frame;
        wl_af_params_t *af_params;
        wifi_p2p_ie_t *p2p_ie;
        wpa_ie_fixed_t *wps_ie;
+       scb_val_t scb_val;
        const struct ieee80211_mgmt *mgmt;
        struct wl_priv *wl = wiphy_priv(wiphy);
        struct net_device *dev = NULL;
-       dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
        s32 err = BCME_OK;
        s32 bssidx = 0;
        u32 p2pie_len = 0;
        u32 wpsie_len = 0;
-       u16 fc;
+       u32 id;
+       u32 retry = 0;
        bool ack = false;
        wifi_p2p_pub_act_frame_t *act_frm;
+       s8 eabuf[ETHER_ADDR_STR_LEN];
 
        WL_DBG(("Enter \n"));
 
        if (ndev == wl->p2p_net) {
-               /* Firmware doesn't have an ifidx corresponding to p2p0 interface.
-                * so divert commands received on p2p0 to wlan0. Note that the TX status
-                * will be sent back to the interface(ndev) on which request is received
-                */
                dev = wl_to_prmry_ndev(wl);
        } else {
                /* If TX req is for any valid ifidx. Use as is */
@@ -3345,16 +3342,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
 
        /* find bssidx based on ndev */
        bssidx = wl_cfgp2p_find_idx(wl, dev);
-       /* cookie generation */
-       *cookie = (unsigned long) buf;
-
        if (bssidx == -1) {
 
                WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
                return -ENODEV;
        }
        if (p2p_is_on(wl)) {
-               wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
+               get_primary_mac(wl, &primary_mac);
+               wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
                /* Suspend P2P discovery search-listen to prevent it from changing the
                 * channel.
                 */
@@ -3363,11 +3358,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                        return -EFAULT;
                }
        }
-
-       mgmt = (const struct ieee80211_mgmt *) buf;
-       fc = mgmt->frame_control;
-       if (fc != IEEE80211_STYPE_ACTION) {
-               if (fc == IEEE80211_STYPE_PROBE_RESP) {
+       *cookie = 0;
+       id = wl->send_action_id++;
+       if (id == 0)
+               id = wl->send_action_id++;
+       *cookie = id;
+       mgmt = (const struct ieee80211_mgmt *)buf;
+       if (ieee80211_is_mgmt(mgmt->frame_control)) {
+               if (ieee80211_is_probe_resp(mgmt->frame_control)) {
                        s32 ie_offset =  DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
                        s32 ie_len = len - ie_offset;
                        if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
@@ -3380,7 +3378,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                                /* Order of Vendor IE is 1) WPS IE +
                                 * 2) P2P IE created by supplicant
                                 *  So, it is ok to find start address of WPS IE
-                                *  to save IEs to firmware
+                                *  to save IEs
                                 */
                                wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
                                        sizeof(wps_ie->tag);
@@ -3388,18 +3386,35 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
                                        VNDR_IE_PRBRSP_FLAG,
                                        (u8 *)wps_ie, wpsie_len + p2pie_len);
                        }
+                       cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+                       goto exit;
+               } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
+                       ieee80211_is_deauth(mgmt->frame_control)) {
+                       memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
+                       scb_val.val = mgmt->u.disassoc.reason_code;
+                       wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+                               sizeof(scb_val_t), true);
+                       WL_DBG(("Disconnect STA : %s\n",
+                               bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf)));
+                       cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
+                       goto exit;
+
+               } else if (ieee80211_is_action(mgmt->frame_control)) {
+                       /* Abort the dwell time of any previous off-channel action frame that may
+                       * be still in effect.  Sending off-channel action frames relies on the
+                       * driver's scan engine.  If a previous off-channel action frame tx is
+                       * still in progress (including the dwell time), then this new action
+                       * frame will not be sent out.
+                       */
+                       wl_cfg80211_scan_abort(wl, dev);
+
                }
-               cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
-               goto exit;
+
        } else {
-           /* Abort the dwell time of any previous off-channel action frame that may
-            * be still in effect.  Sending off-channel action frames relies on the
-            * driver's scan engine.  If a previous off-channel action frame tx is
-            * still in progress (including the dwell time), then this new action
-            * frame will not be sent out.
-            */
-               wl_cfg80211_scan_abort(wl, dev);
+               WL_ERR(("Driver only allows MGMT packet type\n"));
+               goto exit;
        }
+
        af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
 
        if (af_params == NULL)
@@ -3411,7 +3426,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        action_frame = &af_params->action_frame;
 
        /* Add the packet Id */
-       action_frame->packetId = (u32) action_frame;
+       action_frame->packetId = *cookie;
        WL_DBG(("action frame %d\n", action_frame->packetId));
        /* Add BSSID */
        memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
@@ -3445,23 +3460,47 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
        WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
                action_frame->len, af_params->channel,
                act_frm->category, act_frm->subtype));
-       if (wl->p2p->vif_created) {
-               /*
-                * To make sure to send successfully action frame, we have to turn off mpc
-                */
-               if ((act_frm->subtype == P2P_PAF_GON_REQ)||
-                 (act_frm->subtype == P2P_PAF_GON_RSP)) {
-                       wldev_iovar_setint(dev, "mpc", 0);
-               } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
-                       wldev_iovar_setint(dev, "mpc", 1);
-               } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
+       /*
+        * To make sure to send successfully action frame, we have to turn off mpc
+        */
+       if ((IS_PUB_ACT_FRAME(act_frm->category)) &&
+        ((act_frm->subtype == P2P_PAF_GON_REQ) ||
+         (act_frm->subtype == P2P_PAF_GON_RSP) ||
+         (act_frm->subtype == P2P_PAF_GON_CONF) ||
+         (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
+               wldev_iovar_setint(dev, "mpc", 0);
+       }
+
+       if (IS_PUB_ACT_FRAME(act_frm->category)) {
+               if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
                        af_params->dwell_time = WL_LONG_DWELL_TIME;
+               } else if ((act_frm->subtype == P2P_PAF_PROVDIS_REQ) ||
+                       (act_frm->subtype == P2P_PAF_PROVDIS_RSP)) {
+                       af_params->dwell_time = WL_MED_DWELL_TIME;
+               }
+       }
+       if (IS_P2P_SOCIAL(af_params->channel) &&
+               (IS_P2P_ACT_REQ(act_frm->category, act_frm->subtype) ||
+               IS_GAS_REQ(act_frm->category, act_frm->action)) &&
+               wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
+               /* channel offload require P2P IE for Probe request
+                * otherwise, we will use wl_cfgp2p_tx_action_frame directly.
+                * channel offload for action request frame
+               */
+               ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params);
+       } else {
+               for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) {
+                       ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ?
+                               false : true;
+                       if (ack)
+                               break;
                }
        }
-
-       ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
        cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL);
-
+       if (IS_PUB_ACT_FRAME(act_frm->category) &&
+               (act_frm->subtype == P2P_PAF_GON_CONF)) {
+               wldev_iovar_setint(dev, "mpc", 1);
+       }
        kfree(af_params);
 exit:
        return err;
@@ -3518,9 +3557,6 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
        struct wl_priv *wl = wiphy_priv(wiphy);
 
        if (wl->p2p_net == dev) {
-               /* Since there is no ifidx corresponding to p2p0, cmds to
-                * firmware should be routed through primary I/F
-                */
                dev = wl_to_prmry_ndev(wl);
        }
        channel = ieee80211_frequency_to_channel(chan->center_freq);
@@ -3539,7 +3575,6 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
        s32 len = 0;
        s32 err = BCME_OK;
        u16 auth = 0; /* d11 open authentication */
-       u16 count;
        u32 wsec;
        u32 pval = 0;
        u32 gval = 0;
@@ -3577,7 +3612,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
        len -= WPA_SUITE_LEN;
        /* check the unicast cipher */
        ucast = (wpa_suite_ucast_t *)&mcast[1];
-       count = ltoh16_ua(&ucast->count);
+       ltoh16_ua(&ucast->count);
        tmp = ucast->list[0].oui;
        switch (tmp[DOT11_OUI_LEN]) {
                case WPA_CIPHER_NONE:
@@ -3600,7 +3635,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
        wsec = (pval | gval | SES_OW_ENABLED);
        /* check the AKM */
        mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1];
-       count = ltoh16_ua(&mgmt->count);
+       ltoh16_ua(&mgmt->count);
        tmp = (u8 *)&mgmt->list[0];
        switch (tmp[DOT11_OUI_LEN]) {
                case RSN_AKM_NONE:
@@ -3811,9 +3846,6 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                info->interval, info->dtim_period, info->head_len, info->tail_len));
 
        if (wl->p2p_net == dev) {
-               /* Since there is no ifidx corresponding to p2p0, cmds to
-                * firmware should be routed through primary I/F
-                */
                dev = wl_to_prmry_ndev(wl);
        }
 
@@ -3862,7 +3894,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                        WL_ERR(("No P2PIE in beacon \n"));
                }
                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-               wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+               wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
                        beacon_ie, wpsie_len + p2pie_len);
 
@@ -3885,12 +3917,13 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                goto exit;
                        }
                        err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
-                               sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
+                               sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+                               bssidx, &wl->ioctl_buf_sync);
                        if (err < 0) {
                                WL_ERR(("GO SSID setting error %d\n", err));
                                goto exit;
                        }
-                       if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
+                       if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) {
                                WL_ERR(("GO Bring up error %d\n", err));
                                goto exit;
                        }
@@ -3970,7 +4003,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                beacon_ie, wpsie_len);
                                wl->ap_info->wps_ie = kmemdup(wps_ie,   wpsie_len, GFP_KERNEL);
                                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-                               wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+                               wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                        } else {
                                WL_DBG(("No WPSIE in beacon \n"));
                        }
@@ -4023,12 +4056,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                kfree(wl->ap_info->wps_ie);
                                wl->ap_info->wps_ie = kmemdup(wps_ie,   wpsie_len, GFP_KERNEL);
                                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-                               wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+                               wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                        } else if (wl->ap_info->wps_ie == NULL) {
                                WL_DBG((" WPS IE is added\n"));
                                wl->ap_info->wps_ie = kmemdup(wps_ie,   wpsie_len, GFP_KERNEL);
                                /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
-                               wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
+                               wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
                        }
                        /* find the RSN_IE */
                        if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -4094,12 +4127,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                                }
                                if (update_bss) {
                                        wl->ap_info->security_mode = true;
-                                       wl_cfgp2p_bss(dev, bssidx, 0);
+                                       wl_cfgp2p_bss(wl, dev, bssidx, 0);
                                        if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx)  < 0 ||
                                                wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
                                                return BCME_ERROR;
                                        }
-                                       wl_cfgp2p_bss(dev, bssidx, 1);
+                                       wl_cfgp2p_bss(wl, dev, bssidx, 1);
                                }
                        }
                } else {
@@ -4164,21 +4197,15 @@ s32 wl_mode_to_nl80211_iftype(s32 mode)
        return err;
 }
 
-static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev)
 {
-       struct wireless_dev *wdev;
        s32 err = 0;
-       wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
-       if (unlikely(!wdev)) {
-               WL_ERR(("Could not allocate wireless device\n"));
-               return ERR_PTR(-ENOMEM);
-       }
        wdev->wiphy =
            wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
        if (unlikely(!wdev->wiphy)) {
                WL_ERR(("Couldn not allocate wiphy device\n"));
                err = -ENOMEM;
-               goto wiphy_new_out;
+               return err;
        }
        set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
        wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
@@ -4217,30 +4244,28 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
        err = wiphy_register(wdev->wiphy);
        if (unlikely(err < 0)) {
                WL_ERR(("Couldn not register wiphy device (%d)\n", err));
-               goto wiphy_register_out;
+               wiphy_free(wdev->wiphy);
        }
-       return wdev;
-
-wiphy_register_out:
-       wiphy_free(wdev->wiphy);
-
-wiphy_new_out:
-       kfree(wdev);
-
-       return ERR_PTR(err);
+       return err;
 }
 
 static void wl_free_wdev(struct wl_priv *wl)
 {
        struct wireless_dev *wdev = wl->wdev;
+       struct wiphy *wiphy;
        if (!wdev) {
                WL_ERR(("wdev is invalid\n"));
                return;
        }
+       wiphy = wdev->wiphy;
        wiphy_unregister(wdev->wiphy);
        wdev->wiphy->dev.parent = NULL;
-       wiphy_free(wdev->wiphy);
+
        wl_delete_all_netinfo(wl);
+       wiphy_free(wiphy);
+       /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl",
+        * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
+        */
 }
 
 static s32 wl_inform_bss(struct wl_priv *wl)
@@ -4329,6 +4354,21 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
 
        signal = notif_bss_info->rssi * 100;
 
+#if defined(WLP2P) && ENABLE_P2P_INTERFACE
+       if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) {
+#else
+       if (p2p_is_on(wl) && p2p_scan(wl)) {
+#endif
+               /* find the P2PIE, if we do not find it, we will discard this frame */
+               wifi_p2p_ie_t * p2p_ie;
+               if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable,
+                       wl_get_ielen(wl))) == NULL) {
+                       WL_ERR(("Couldn't find P2PIE in probe response/beacon\n"));
+                       kfree(notif_bss_info);
+                       return err;
+               }
+       }
+
        cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
                le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL);
        if (unlikely(!cbss)) {
@@ -4395,89 +4435,136 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
        return false;
 }
 
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
+ * to AP/P2P GO via events. If this change is backported to kernel for which
+ * this driver is being built, set CFG80211_STA_EVENT_AVAILABLE to 1. You
+ * should use this new/del sta event mechanism for BRCM supplicant from BRANCH
+ * HOSTAP_BRANCH_0_15 (ver >= 15_1).
+ */
+#define CFG80211_STA_EVENT_AVAILABLE   0
 static s32
-wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev,
        const wl_event_msg_t *e, void *data)
 {
-       bool act;
-       bool isfree = false;
        s32 err = 0;
-       s32 freq;
-       s32 channel;
-       u8 body[200];
        u32 event = ntoh32(e->event_type);
        u32 reason = ntoh32(e->reason);
        u32 len = ntoh32(e->datalen);
-       u16 fc = 0;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE
+       bool isfree = false;
        u8 *mgmt_frame;
        u8 bsscfgidx = e->bsscfgidx;
+       s32 freq;
+       s32 channel;
+       u8 body[200];
+       u16 fc = 0;
        struct ieee80211_supported_band *band;
        struct ether_addr da;
        struct ether_addr bssid;
        struct wiphy *wiphy = wl_to_wiphy(wl);
        channel_info_t ci;
+#else
+       struct station_info sinfo;
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE */
 
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE
        memset(body, 0, sizeof(body));
        memset(&bssid, 0, ETHER_ADDR_LEN);
        WL_DBG(("Enter \n"));
        if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID)
                return WL_INVALID;
 
-       if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
-               memcpy(body, data, len);
-               wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
-               NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
-               memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
-               err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
-               switch (event) {
-                       case WLC_E_ASSOC_IND:
-                               fc = FC_ASSOC_REQ;
-                               break;
-                       case WLC_E_REASSOC_IND:
-                               fc = FC_REASSOC_REQ;
-                               break;
-                       case WLC_E_DISASSOC_IND:
-                               fc = FC_DISASSOC;
-                               break;
-                       case WLC_E_DEAUTH_IND:
-                               fc = FC_DISASSOC;
-                               break;
-                       case WLC_E_DEAUTH:
-                               fc = FC_DISASSOC;
-                               break;
-                       default:
-                               fc = 0;
-                               goto exit;
-               }
-               if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
-                       return err;
+       memcpy(body, data, len);
+       wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+               NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
+       memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
+       err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+       switch (event) {
+               case WLC_E_ASSOC_IND:
+                       fc = FC_ASSOC_REQ;
+                       break;
+               case WLC_E_REASSOC_IND:
+                       fc = FC_REASSOC_REQ;
+                       break;
+               case WLC_E_DISASSOC_IND:
+                       fc = FC_DISASSOC;
+                       break;
+               case WLC_E_DEAUTH_IND:
+                       fc = FC_DISASSOC;
+                       break;
+               case WLC_E_DEAUTH:
+                       fc = FC_DISASSOC;
+                       break;
+               default:
+                       fc = 0;
+                       goto exit;
+       }
+       if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
+               return err;
 
-               channel = dtoh32(ci.hw_channel);
-               if (channel <= CH_MAX_2G_CHANNEL)
-                       band = wiphy->bands[IEEE80211_BAND_2GHZ];
-               else
-                       band = wiphy->bands[IEEE80211_BAND_5GHZ];
+       channel = dtoh32(ci.hw_channel);
+       if (channel <= CH_MAX_2G_CHANNEL)
+               band = wiphy->bands[IEEE80211_BAND_2GHZ];
+       else
+               band = wiphy->bands[IEEE80211_BAND_5GHZ];
 
 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
-               freq = ieee80211_channel_to_frequency(channel);
+       freq = ieee80211_channel_to_frequency(channel);
 #else
-               freq = ieee80211_channel_to_frequency(channel, band->band);
+       freq = ieee80211_channel_to_frequency(channel, band->band);
 #endif
 
-               err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
+       err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
                &mgmt_frame, &len, body);
-               if (err < 0)
-                               goto exit;
-               isfree = true;
+       if (err < 0)
+               goto exit;
+       isfree = true;
 
-               if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
-                       cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
-               } else if (event == WLC_E_DISASSOC_IND) {
-                       cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
-               } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
-                       cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+       if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
+               cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+       } else if (event == WLC_E_DISASSOC_IND) {
+               cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+       } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+               cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+       }
+
+exit:
+       if (isfree)
+               kfree(mgmt_frame);
+       return err;
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */
+       sinfo.filled = 0;
+       if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
+               reason == DOT11_SC_SUCCESS) {
+               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+               if (!data) {
+                       WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
+                       return -EINVAL;
                }
+               sinfo.assoc_req_ies = data;
+               sinfo.assoc_req_ies_len = len;
+               cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
+       } else if (event == WLC_E_DISASSOC_IND) {
+               cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+       } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+               cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+       }
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */
+       return err;
+}
+
+static s32
+wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+       const wl_event_msg_t *e, void *data)
+{
+       bool act;
+       s32 err = 0;
+       u32 event = ntoh32(e->event_type);
 
+       if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
+               wl_notify_connect_status_ap(wl, ndev, e, data);
        } else {
                WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
                ntoh32(e->event_type), ntoh32(e->status)));
@@ -4549,9 +4636,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
                        printk("%s nothing\n", __FUNCTION__);
                }
        }
-exit:
-       if (isfree)
-               kfree(mgmt_frame);
        return err;
 }
 
@@ -4576,48 +4660,15 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
        return err;
 }
 
-static __used s32
-wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
-{
-       struct wl_priv *wl = wlcfg_drv_priv;
-       u32 buflen;
-
-       buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
-       BUG_ON(unlikely(!buflen));
-
-       return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
-}
-
-static s32
-wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
-       s32 buf_len)
+static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
 {
-       struct wl_priv *wl = wlcfg_drv_priv;
-       u32 len;
-       s32 err = 0;
-
-       len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
-       BUG_ON(unlikely(!len));
-       err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
-               WL_IOCTL_LEN_MAX, false);
-       if (unlikely(err)) {
-               WL_ERR(("error (%d)\n", err));
-               return err;
-       }
-       memcpy(buf, wl->ioctl_buf, buf_len);
-
-       return err;
-}
-
-static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
-{
-       wl_assoc_info_t assoc_info;
-       struct wl_connect_info *conn_info = wl_to_conn(wl);
+       wl_assoc_info_t assoc_info;
+       struct wl_connect_info *conn_info = wl_to_conn(wl);
        s32 err = 0;
 
        WL_DBG(("Enter \n"));
-       err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
-               WL_ASSOC_INFO_MAX);
+       err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf,
+               WL_ASSOC_INFO_MAX, NULL);
        if (unlikely(err)) {
                WL_ERR(("could not get assoc info (%d)\n", err));
                return err;
@@ -4635,8 +4686,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
                bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
        }
        if (assoc_info.req_len) {
-               err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
-                       WL_ASSOC_INFO_MAX);
+               err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf,
+                       WL_ASSOC_INFO_MAX, NULL);
                if (unlikely(err)) {
                        WL_ERR(("could not get assoc req (%d)\n", err));
                        return err;
@@ -4656,8 +4707,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
                conn_info->req_ie_len = 0;
        }
        if (assoc_info.resp_len) {
-               err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
-                       WL_ASSOC_INFO_MAX);
+               err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf,
+                       WL_ASSOC_INFO_MAX, NULL);
                if (unlikely(err)) {
                        WL_ERR(("could not get assoc resp (%d)\n", err));
                        return err;
@@ -4719,8 +4770,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
        struct wl_bss_info *bi;
        struct wlc_ssid *ssid;
        struct bcm_tlv *tim;
-       u16 beacon_interval;
-       u8 dtim_period;
+       s32 beacon_interval;
+       s32 dtim_period;
        size_t ie_len;
        u8 *ie;
        u8 *curbssid;
@@ -4774,7 +4825,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
                /*
                * active scan was done so we could not get dtim
                * information out of probe response.
-               * so we speficially query dtim information to dongle.
+               * so we speficially query dtim information.
                */
                err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
                        &dtim_period, sizeof(dtim_period), false);
@@ -4826,6 +4877,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
        struct wl_connect_info *conn_info = wl_to_conn(wl);
        s32 err = 0;
        u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
+
        WL_DBG((" enter\n"));
        if (wl->scan_request) {
                wl_cfg80211_scan_abort(wl, ndev);
@@ -4939,13 +4991,13 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
 
 scan_done_out:
        del_timer_sync(&wl->scan_timeout);
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        if (wl->scan_request) {
                WL_DBG(("cfg80211_scan_done\n"));
                cfg80211_scan_done(wl->scan_request, false);
                wl->scan_request = NULL;
        }
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        mutex_unlock(&wl->usr_sync);
        return err;
 }
@@ -5014,9 +5066,6 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
        memset(&bssid, 0, ETHER_ADDR_LEN);
 
        if (wl->p2p_net == ndev) {
-               /* Since there is no ifidx corresponding to p2p0, cmds to
-                * firmware should be routed through primary I/F
-                */
                dev = wl_to_prmry_ndev(wl);
        } else {
                dev = ndev;
@@ -5034,10 +5083,10 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
 #endif
        if (event == WLC_E_ACTION_FRAME_RX) {
                wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr",
-               NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
+                       NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync);
 
                wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
-               memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
+               memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN);
                err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
                        &mgmt_frame, &mgmt_frame_len,
                        (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
@@ -5052,9 +5101,18 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
                /*
                 * After complete GO Negotiation, roll back to mpc mode
                 */
-                if (act_frm->subtype == P2P_PAF_GON_CONF) {
+               if (IS_PUB_ACT_FRAME(act_frm->category) &&
+                       ((act_frm->subtype == P2P_PAF_GON_CONF)||
+                       (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
                        wldev_iovar_setint(dev, "mpc", 1);
                }
+
+               if (IS_P2P_ACT_FRAME(act_frm->category) &&
+                       (act_frm->subtype == P2P_AF_PRESENCE_REQ)) {
+                       /* TODO Do not submit these frames to supplicant,
+                        * we will handle it in the driver
+                       */
+               }
        } else {
                mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
        }
@@ -5084,9 +5142,10 @@ static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev)
 {
        unsigned long flags;
        struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        memset(profile, 0, sizeof(struct wl_profile));
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 }
 
 static void wl_init_event_handler(struct wl_priv *wl)
@@ -5131,7 +5190,7 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
                WL_ERR(("Scan req alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+       wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
        if (unlikely(!wl->ioctl_buf)) {
                WL_ERR(("Ioctl buf alloc failed\n"));
                goto init_priv_mem_out;
@@ -5151,11 +5210,6 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
                WL_ERR(("Iscan buf alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
-       if (unlikely(!wl->fw)) {
-               WL_ERR(("fw object alloc failed\n"));
-               goto init_priv_mem_out;
-       }
        wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
        if (unlikely(!wl->pmk_list)) {
                WL_ERR(("pmk list alloc failed\n"));
@@ -5166,6 +5220,14 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
                WL_ERR(("sta info  alloc failed\n"));
                goto init_priv_mem_out;
        }
+       wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL);
+       if (unlikely(!wl->afx_hdl)) {
+               WL_ERR(("afx hdl  alloc failed\n"));
+               goto init_priv_mem_out;
+       } else {
+               init_completion(&wl->act_frm_scan);
+               INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler);
+       }
        return 0;
 
 init_priv_mem_out:
@@ -5190,12 +5252,16 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
        wl->extra_buf = NULL;
        kfree(wl->iscan);
        wl->iscan = NULL;
-       kfree(wl->fw);
-       wl->fw = NULL;
        kfree(wl->pmk_list);
        wl->pmk_list = NULL;
        kfree(wl->sta_info);
        wl->sta_info = NULL;
+       if (wl->afx_hdl) {
+               cancel_work_sync(&wl->afx_hdl->work);
+               kfree(wl->afx_hdl);
+               wl->afx_hdl = NULL;
+       }
+
        if (wl->ap_info) {
                kfree(wl->ap_info->wpa_ie);
                kfree(wl->ap_info->rsn_ie);
@@ -5210,7 +5276,8 @@ static s32 wl_create_event_handler(struct wl_priv *wl)
        int ret = 0;
        WL_DBG(("Enter \n"));
 
-       wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
+       /* Do not use DHD in cfg driver */
+       wl->event_tsk.thr_pid = -1;
        PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
        if (wl->event_tsk.thr_pid < 0)
                ret = -ENOMEM;
@@ -5249,13 +5316,13 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
                WL_ERR(("Scan complete while device not scanning\n"));
                return;
        }
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        wl_clr_drv_status(wl, SCANNING, ndev);
        if (likely(wl->scan_request)) {
                cfg80211_scan_done(wl->scan_request, aborted);
                wl->scan_request = NULL;
        }
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        wl->iscan_kickstart = false;
 }
 
@@ -5291,7 +5358,7 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
        list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
        err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list,
                WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
-               WL_ISCAN_BUF_MAX);
+               WL_ISCAN_BUF_MAX, NULL);
        if (unlikely(err)) {
                WL_ERR(("error (%d)\n", err));
                return err;
@@ -5364,13 +5431,11 @@ static s32 wl_iscan_aborted(struct wl_priv *wl)
 
 static s32 wl_iscan_thread(void *data)
 {
-       struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
        struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
        struct wl_priv *wl = iscan_to_wl(iscan);
        u32 status;
        int err = 0;
 
-       sched_setscheduler(current, SCHED_FIFO, &param);
        allow_signal(SIGTERM);
        status = WL_SCAN_RESULTS_PARTIAL;
        while (likely(!down_interruptible(&iscan->sync))) {
@@ -5486,12 +5551,12 @@ static void wl_notify_escan_complete(struct wl_priv *wl,
        if (p2p_is_on(wl))
                wl_clr_p2p_status(wl, SCANNING);
 
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        if (likely(wl->scan_request)) {
                cfg80211_scan_done(wl->scan_request, aborted);
                wl->scan_request = NULL;
        }
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 }
 
 static s32 wl_escan_handler(struct wl_priv *wl,
@@ -5506,14 +5571,22 @@ static s32 wl_escan_handler(struct wl_priv *wl,
        wl_scan_results_t *list;
        u32 bi_length;
        u32 i;
+       u8 *p2p_dev_addr = NULL;
+
        WL_DBG((" enter event type : %d, status : %d \n",
                ntoh32(e->event_type), ntoh32(e->status)));
        /* P2P SCAN is coming from primary interface */
-       if (wl_get_p2p_status(wl, SCANNING))
-               ndev = wl->escan_info.ndev;
+       if (wl_get_p2p_status(wl, SCANNING)) {
+               if (wl_get_drv_status_all(wl, SENDING_ACT_FRM))
+                       ndev = wl->afx_hdl->dev;
+               else
+                       ndev = wl->escan_info.ndev;
+
+       }
        if (!ndev || !wl->escan_on ||
                !wl_get_drv_status(wl, SCANNING, ndev)) {
-               WL_ERR(("escan is not ready \n"));
+               WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n",
+                       ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev)));
                return err;
        }
 
@@ -5538,47 +5611,69 @@ static s32 wl_escan_handler(struct wl_priv *wl,
                        WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
                        goto exit;
                }
-               list = (wl_scan_results_t *)wl->escan_info.escan_buf;
-               if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
-                       WL_ERR(("Buffer is too small: ignoring\n"));
-                       goto exit;
-               }
-#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
-               for (i = 0; i < list->count; i++) {
-                       bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
-                               : list->bss_info;
-
-                       if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
-                               CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
-                               bi->SSID_len == bss->SSID_len &&
-                               !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
-                               if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
-                                       (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
-                                       /* preserve max RSSI if the measurements are
-                                        * both on-channel or both off-channel
-                                        */
-                                       bss->RSSI = MAX(bss->RSSI, bi->RSSI);
-                               } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
-                                       (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
-                                       /* preserve the on-channel rssi measurement
-                                        * if the new measurement is off channel
-                                        */
-                                       bss->RSSI = bi->RSSI;
-                                       bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
-                               }
 
+               if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+                       p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
+                       if (p2p_dev_addr && !memcmp(p2p_dev_addr,
+                               wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) {
+                               s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
+                               WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel));
+                               wl_clr_p2p_status(wl, SCANNING);
+                               wl->afx_hdl->peer_chan = channel;
+                               complete(&wl->act_frm_scan);
                                goto exit;
                        }
+
+               } else {
+                       list = (wl_scan_results_t *)wl->escan_info.escan_buf;
+                       if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+                               WL_ERR(("Buffer is too small: ignoring\n"));
+                               goto exit;
+                       }
+#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
+                       for (i = 0; i < list->count; i++) {
+                               bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+                                       : list->bss_info;
+
+                               if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+                                       CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
+                                       bi->SSID_len == bss->SSID_len &&
+                                       !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
+                                       if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
+                                               (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
+                                               /* preserve max RSSI if the measurements are
+                                               * both on-channel or both off-channel
+                                               */
+                                               bss->RSSI = MAX(bss->RSSI, bi->RSSI);
+                                       } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
+                                               (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
+                                               /* preserve the on-channel rssi measurement
+                                               * if the new measurement is off channel
+                                               */
+                                               bss->RSSI = bi->RSSI;
+                                               bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
+                                       }
+
+                                       goto exit;
+                               }
+                       }
+                       memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
+                       list->version = dtoh32(bi->version);
+                       list->buflen += bi_length;
+                       list->count++;
+
                }
-               memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
-               list->version = dtoh32(bi->version);
-               list->buflen += bi_length;
-               list->count++;
 
        }
        else if (status == WLC_E_STATUS_SUCCESS) {
                wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-               if (likely(wl->scan_request)) {
+               if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+                       WL_INFO(("ACTION FRAME SCAN DONE\n"));
+                       wl_clr_p2p_status(wl, SCANNING);
+                       wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+                       if (wl->afx_hdl->peer_chan == WL_INVALID)
+                               complete(&wl->act_frm_scan);
+               } else if (likely(wl->scan_request)) {
                        mutex_lock(&wl->usr_sync);
                        del_timer_sync(&wl->scan_timeout);
                        WL_INFO(("ESCAN COMPLETED\n"));
@@ -5590,7 +5685,13 @@ static s32 wl_escan_handler(struct wl_priv *wl,
        }
        else if (status == WLC_E_STATUS_ABORT) {
                wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-               if (likely(wl->scan_request)) {
+               if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+                       WL_INFO(("ACTION FRAME SCAN DONE\n"));
+                       wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+                       wl_clr_p2p_status(wl, SCANNING);
+                       if (wl->afx_hdl->peer_chan == WL_INVALID)
+                               complete(&wl->act_frm_scan);
+               } else if (likely(wl->scan_request)) {
                        mutex_lock(&wl->usr_sync);
                        del_timer_sync(&wl->scan_timeout);
                        WL_INFO(("ESCAN ABORTED\n"));
@@ -5603,7 +5704,13 @@ static s32 wl_escan_handler(struct wl_priv *wl,
        else {
                WL_ERR(("unexpected Escan Event %d : abort\n", status));
                wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-               if (likely(wl->scan_request)) {
+               if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
+                       WL_INFO(("ACTION FRAME SCAN DONE\n"));
+                       wl_clr_p2p_status(wl, SCANNING);
+                       wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
+                       if (wl->afx_hdl->peer_chan == WL_INVALID)
+                               complete(&wl->act_frm_scan);
+               } else if (likely(wl->scan_request)) {
                        mutex_lock(&wl->usr_sync);
                        del_timer_sync(&wl->scan_timeout);
                        wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
@@ -5649,16 +5756,12 @@ static s32 wl_init_scan(struct wl_priv *wl)
        return err;
 }
 
-static void wl_init_fw(struct wl_fw_ctrl *fw)
-{
-       fw->status = 0;
-}
-
 static s32 wl_init_priv(struct wl_priv *wl)
 {
        struct wiphy *wiphy = wl_to_wiphy(wl);
        struct net_device *ndev = wl_to_prmry_ndev(wl);
        s32 err = 0;
+
        wl->scan_request = NULL;
        wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
        wl->iscan_on = false;
@@ -5666,10 +5769,10 @@ static s32 wl_init_priv(struct wl_priv *wl)
        wl->roam_on = false;
        wl->iscan_kickstart = false;
        wl->active_scan = true;
-       wl->dongle_up = false;
        wl->rf_blocked = false;
-
-       init_waitqueue_head(&wl->dongle_event_wait);
+       spin_lock_init(&wl->cfgdrv_lock);
+       mutex_init(&wl->ioctl_buf_sync);
+       init_waitqueue_head(&wl->netif_change_event);
        wl_init_eq(wl);
        err = wl_init_priv_mem(wl);
        if (err)
@@ -5681,18 +5784,18 @@ static s32 wl_init_priv(struct wl_priv *wl)
        err = wl_init_scan(wl);
        if (err)
                return err;
-       wl_init_fw(wl->fw);
        wl_init_conf(wl->conf);
        wl_init_prof(wl, ndev);
        wl_link_down(wl);
+       DNGL_FUNC(dhd_cfg80211_init, (wl));
 
        return err;
 }
 
 static void wl_deinit_priv(struct wl_priv *wl)
 {
+       DNGL_FUNC(dhd_cfg80211_deinit, (wl));
        wl_destroy_event_handler(wl);
-       wl->dongle_up = false;  /* dongle down */
        wl_flush_eq(wl);
        wl_link_down(wl);
        del_timer_sync(&wl->scan_timeout);
@@ -5721,7 +5824,7 @@ static s32  wl_cfg80211_detach_p2p(void)
        struct wl_priv *wl = wlcfg_drv_priv;
        struct wireless_dev *wdev = wl->p2p_wdev;
 
-       WL_TRACE(("Enter \n"));
+       WL_DBG(("Enter \n"));
        if (!wdev || !wl) {
                WL_ERR(("Invalid Ptr\n"));
                return -EINVAL;
@@ -5731,7 +5834,7 @@ static s32  wl_cfg80211_detach_p2p(void)
 
        wl->p2p_wdev = NULL;
        wl->p2p_net = NULL;
-
+       WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev));
        kfree(wdev);
 
        return 0;
@@ -5751,9 +5854,11 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev)
        if (wl && !wl_get_drv_status(wl, READY, ndev)) {
                        if (wl->wdev &&
                                wl_cfgp2p_supported(wl, ndev)) {
+#if !ENABLE_P2P_INTERFACE
                                wl->wdev->wiphy->interface_modes |=
                                        (BIT(NL80211_IFTYPE_P2P_CLIENT)|
                                        BIT(NL80211_IFTYPE_P2P_GO));
+#endif
                                if ((err = wl_cfgp2p_init_priv(wl)) != 0)
                                        goto fail;
 
@@ -5794,10 +5899,17 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
        }
        WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
        dev = wl_cfg80211_get_parent_dev();
-       wdev = wl_alloc_wdev(dev);
-       if (IS_ERR(wdev))
-               return -ENOMEM;
 
+       wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+       if (unlikely(!wdev)) {
+               WL_ERR(("Could not allocate wireless device\n"));
+               return -ENOMEM;
+       }
+       err = wl_setup_wiphy(wdev, dev);
+       if (unlikely(err)) {
+               kfree(wdev);
+               return -ENOMEM;
+       }
        wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
        wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
        wl->wdev = wdev;
@@ -5830,7 +5942,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
 #if defined(COEX_DHCP)
        if (wl_cfg80211_btcoex_init(wl))
                goto cfg80211_attach_out;
-#endif /* COEX_DHCP */
+#endif 
 
        wlcfg_drv_priv = wl;
 
@@ -5848,7 +5960,7 @@ cfg80211_attach_out:
        return err;
 }
 
-void wl_cfg80211_detach(void)
+void wl_cfg80211_detach(void *para)
 {
        struct wl_priv *wl;
 
@@ -5858,7 +5970,7 @@ void wl_cfg80211_detach(void)
 
 #if defined(COEX_DHCP)
        wl_cfg80211_btcoex_deinit(wl);
-#endif /* COEX_DHCP */
+#endif 
 
 #if defined(WLP2P) && ENABLE_P2P_INTERFACE
        wl_cfg80211_detach_p2p();
@@ -5870,6 +5982,9 @@ void wl_cfg80211_detach(void)
        wlcfg_drv_priv = NULL;
        wl_cfg80211_clear_parent_dev();
        wl_free_wdev(wl);
+        /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl",
+         * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!!
+         */
 }
 
 static void wl_wakeup_event(struct wl_priv *wl)
@@ -5932,20 +6047,17 @@ static s32 wl_event_handler(void *data)
                        break;
                while ((e = wl_deq_event(wl))) {
                        WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
-
                        /* All P2P device address related events comes on primary interface since
-                        * there is no corresponding interface in the firmware. Map it to p2p0
+                        * there is no corresponding bsscfg for P2P interface. Map it to p2p0
                         * interface.
                         */
                        if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) {
                                netdev = wl->p2p_net;
                        } else {
                                netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
-                               if (!netdev) {
-                                       netdev = wl_to_prmry_ndev(wl);
-                               }
                        }
-
+                       if (!netdev)
+                               netdev = wl_to_prmry_ndev(wl);
                        if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
                                wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
                        } else {
@@ -6056,7 +6168,7 @@ static void wl_put_event(struct wl_event_q *e)
        kfree(e);
 }
 
-static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
+static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
 {
        s32 infra = 0;
        s32 err = 0;
@@ -6097,7 +6209,8 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp
 
        return 0;
 }
-static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+
+static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
 {
        s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
 
@@ -6110,7 +6223,7 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo
        err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
        if (unlikely(err)) {
                WL_ERR(("Get event_msgs error (%d)\n", err));
-               goto dongle_eventmsg_out;
+               goto eventmsg_out;
        }
        memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
        if (add) {
@@ -6123,350 +6236,15 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo
        err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
        if (unlikely(err)) {
                WL_ERR(("Set event_msgs error (%d)\n", err));
-               goto dongle_eventmsg_out;
-       }
-
-dongle_eventmsg_out:
-       return err;
-
-}
-
-
-#ifndef EMBEDDED_PLATFORM
-static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
-{
-
-       s32 err = 0;
-
-       return err;
-}
-
-static s32 wl_dongle_up(struct net_device *ndev, u32 up)
-{
-       s32 err = 0;
-
-       err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
-       if (unlikely(err)) {
-               WL_ERR(("WLC_UP error (%d)\n", err));
-       }
-       return err;
-}
-
-static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
-{
-       s32 err = 0;
-
-       WL_TRACE(("In\n"));
-       err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
-       if (unlikely(err)) {
-               WL_ERR(("WLC_SET_PM error (%d)\n", err));
-       }
-       return err;
-}
-
-static s32
-wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
-{
-       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-       s32 err = 0;
-
-       /* Match Host and Dongle rx alignment */
-       bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
-               sizeof(iovbuf));
-       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-       if (unlikely(err)) {
-               WL_ERR(("txglomalign error (%d)\n", err));
-               goto dongle_glom_out;
-       }
-       /* disable glom option per default */
-       bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
-       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-       if (unlikely(err)) {
-               WL_ERR(("txglom error (%d)\n", err));
-               goto dongle_glom_out;
-       }
-dongle_glom_out:
-       return err;
-}
-
-static s32
-wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
-{
-       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-       s32 err = 0;
-
-       /* Setup timeout if Beacons are lost and roam is off to report link down */
-       if (roamvar) {
-               bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
-                       sizeof(iovbuf));
-               err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-               if (unlikely(err)) {
-                       WL_ERR(("bcn_timeout error (%d)\n", err));
-                       goto dongle_rom_out;
-               }
-       }
-       /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
-       bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
-       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-       if (unlikely(err)) {
-               WL_ERR(("roam_off error (%d)\n", err));
-               goto dongle_rom_out;
-       }
-dongle_rom_out:
-       return err;
-}
-
-static s32
-wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
-       s32 scan_unassoc_time)
-{
-       s32 err = 0;
-
-       err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
-               sizeof(scan_assoc_time), true);
-       if (err) {
-               if (err == -EOPNOTSUPP) {
-                       WL_INFO(("Scan assoc time is not supported\n"));
-               } else {
-                       WL_ERR(("Scan assoc time error (%d)\n", err));
-               }
-               goto dongle_scantime_out;
+               goto eventmsg_out;
        }
-       err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
-               sizeof(scan_unassoc_time), true);
-       if (err) {
-               if (err == -EOPNOTSUPP) {
-                       WL_INFO(("Scan unassoc time is not supported\n"));
-               } else {
-                       WL_ERR(("Scan unassoc time error (%d)\n", err));
-               }
-               goto dongle_scantime_out;
-       }
-
-dongle_scantime_out:
-       return err;
-}
-
-static s32
-wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
-{
-       /* Room for "event_msgs" + '\0' + bitvec */
-       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-       s32 err = 0;
-
-       /* Set ARP offload */
-       bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
-       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       WL_INFO(("arpoe is not supported\n"));
-               else
-                       WL_ERR(("arpoe error (%d)\n", err));
-
-               goto dongle_offload_out;
-       }
-       bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
-       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       WL_INFO(("arp_ol is not supported\n"));
-               else
-                       WL_ERR(("arp_ol error (%d)\n", err));
-
-               goto dongle_offload_out;
-       }
-
-dongle_offload_out:
-       return err;
-}
-
-static s32 wl_pattern_atoh(s8 *src, s8 *dst)
-{
-       int i;
-       if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
-               WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
-               return -1;
-       }
-       src = src + 2;          /* Skip past 0x */
-       if (strlen(src) % 2 != 0) {
-               WL_ERR(("Mask invalid format. Needs to be of even length\n"));
-               return -1;
-       }
-       for (i = 0; *src != '\0'; i++) {
-               char num[3];
-               strncpy(num, src, 2);
-               num[2] = '\0';
-               dst[i] = (u8) simple_strtoul(num, NULL, 16);
-               src += 2;
-       }
-       return i;
-}
-
-static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
-{
-       /* Room for "event_msgs" + '\0' + bitvec */
-       s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
-
-       const s8 *str;
-       struct wl_pkt_filter pkt_filter;
-       struct wl_pkt_filter *pkt_filterp;
-       s32 buf_len;
-       s32 str_len;
-       u32 mask_size;
-       u32 pattern_size;
-       s8 buf[256];
-       s32 err = 0;
-
-       /* add a default packet filter pattern */
-       str = "pkt_filter_add";
-       str_len = strlen(str);
-       strncpy(buf, str, str_len);
-       buf[str_len] = '\0';
-       buf_len = str_len + 1;
-
-       pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
-
-       /* Parse packet filter id. */
-       pkt_filter.id = htod32(100);
-
-       /* Parse filter polarity. */
-       pkt_filter.negate_match = htod32(0);
-
-       /* Parse filter type. */
-       pkt_filter.type = htod32(0);
-
-       /* Parse pattern filter offset. */
-       pkt_filter.u.pattern.offset = htod32(0);
-
-       /* Parse pattern filter mask. */
-       mask_size = htod32(wl_pattern_atoh("0xff",
-               (char *)pkt_filterp->u.pattern.
-                   mask_and_pattern));
-
-       /* Parse pattern filter pattern. */
-       pattern_size = htod32(wl_pattern_atoh("0x00",
-               (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
-
-       if (mask_size != pattern_size) {
-               WL_ERR(("Mask and pattern not the same size\n"));
-               err = -EINVAL;
-               goto dongle_filter_out;
-       }
-
-       pkt_filter.u.pattern.size_bytes = mask_size;
-       buf_len += WL_PKT_FILTER_FIXED_LEN;
-       buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
-       /* Keep-alive attributes are set in local
-        * variable (keep_alive_pkt), and
-        * then memcpy'ed into buffer (keep_alive_pktp) since there is no
-        * guarantee that the buffer is properly aligned.
-        */
-       memcpy((char *)pkt_filterp, &pkt_filter,
-               WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
-
-       err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
-       if (err) {
-               if (err == -EOPNOTSUPP) {
-                       WL_INFO(("filter not supported\n"));
-               } else {
-                       WL_ERR(("filter (%d)\n", err));
-               }
-               goto dongle_filter_out;
-       }
-
-       /* set mode to allow pattern */
-       bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
-               sizeof(iovbuf));
-       err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
-       if (err) {
-               if (err == -EOPNOTSUPP) {
-                       WL_INFO(("filter_mode not supported\n"));
-               } else {
-                       WL_ERR(("filter_mode (%d)\n", err));
-               }
-               goto dongle_filter_out;
-       }
-
-dongle_filter_out:
-       return err;
-}
-#endif                         /* !EMBEDDED_PLATFORM */
-
-s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
-{
-#ifndef DHD_SDALIGN
-#define DHD_SDALIGN    32
-#endif
-       struct net_device *ndev;
-       struct wireless_dev *wdev;
-       s32 err = 0;
-
-       WL_TRACE(("In\n"));
-       if (wl->dongle_up) {
-               WL_ERR(("Dongle is already up\n"));
-               return err;
-       }
-
-       ndev = wl_to_prmry_ndev(wl);
-       wdev = ndev->ieee80211_ptr;
-       if (need_lock)
-               rtnl_lock();
-#ifndef EMBEDDED_PLATFORM
-       err = wl_dongle_up(ndev, 0);
-       if (unlikely(err)) {
-               WL_ERR(("wl_dongle_up failed\n"));
-               goto default_conf_out;
-       }
-       err = wl_dongle_country(ndev, 0);
-       if (unlikely(err)) {
-               WL_ERR(("wl_dongle_country failed\n"));
-               goto default_conf_out;
-       }
-       err = wl_dongle_power(ndev, PM_FAST);
-       if (unlikely(err)) {
-               WL_ERR(("wl_dongle_power failed\n"));
-               goto default_conf_out;
-       }
-       err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
-       if (unlikely(err)) {
-               WL_ERR(("wl_dongle_glom failed\n"));
-               goto default_conf_out;
-       }
-       err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
-       if (unlikely(err)) {
-               WL_ERR(("wl_dongle_roam failed\n"));
-               goto default_conf_out;
-       }
-       wl_dongle_scantime(ndev, 40, 80);
-       wl_dongle_offload(ndev, 1, 0xf);
-       wl_dongle_filter(ndev, 1);
-#endif                         /* !EMBEDDED_PLATFORM */
-
-       err = wl_dongle_mode(wl, ndev, wdev->iftype);
-       if (unlikely(err && err != -EINPROGRESS)) {
-               WL_ERR(("wl_dongle_mode failed\n"));
-               goto default_conf_out;
-       }
-       err = wl_dongle_probecap(wl);
-       if (unlikely(err)) {
-               WL_ERR(("wl_dongle_probecap failed\n"));
-               goto default_conf_out;
-       }
-
-       wl->dongle_up = true;
-default_conf_out:
-       if (need_lock)
-               rtnl_unlock();
 
+eventmsg_out:
        return err;
 
 }
 
-static s32 wl_update_wiphybands(struct wl_priv *wl)
+s32 wl_update_wiphybands(struct wl_priv *wl)
 {
        struct wiphy *wiphy;
        s8 phylist_buf[128];
@@ -6494,14 +6272,25 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl)
 {
        s32 err = 0;
        struct net_device *ndev = wl_to_prmry_ndev(wl);
+       struct wireless_dev *wdev = ndev->ieee80211_ptr;
+
        WL_TRACE(("In\n"));
-       wl_debugfs_add_netdev_params(wl, ndev);
 
-       err = wl_config_dongle(wl, false);
+       err = dhd_config_dongle(wl, false);
        if (unlikely(err))
                return err;
-       dhd_monitor_init(wl->pub);
-       wl_invoke_iscan(wl);
+
+       err = wl_config_ifmode(wl, ndev, wdev->iftype);
+       if (unlikely(err && err != -EINPROGRESS)) {
+               WL_ERR(("wl_config_ifmode failed\n"));
+       }
+       err = wl_update_wiphybands(wl);
+       if (unlikely(err)) {
+               WL_ERR(("wl_update_wiphybands failed\n"));
+       }
+
+       err = dhd_monitor_init(wl->pub);
+       err = wl_invoke_iscan(wl);
        wl_set_drv_status(wl, READY, ndev);
        return err;
 }
@@ -6512,6 +6301,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
        unsigned long flags;
        struct net_info *iter, *next;
        struct net_device *ndev = wl_to_prmry_ndev(wl);
+
        WL_TRACE(("In\n"));
        /* Check if cfg80211 interface is already down */
        if (!wl_get_drv_status(wl, READY, ndev))
@@ -6520,7 +6310,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
                wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev);
 
        wl_term_iscan(wl);
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        if (wl->scan_request) {
                cfg80211_scan_done(wl->scan_request, true);
                wl->scan_request = NULL;
@@ -6537,21 +6327,19 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
        }
        wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
                NL80211_IFTYPE_STATION;
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
 
-       wl->dongle_up = false;
+       DNGL_FUNC(dhd_cfg80211_down, (wl));
        wl_flush_eq(wl);
        wl_link_down(wl);
        if (wl->p2p_supported)
                wl_cfgp2p_down(wl);
        dhd_monitor_uninit();
 
-       wl_debugfs_remove_netdev(wl);
-
        return err;
 }
 
-s32 wl_cfg80211_up(void)
+s32 wl_cfg80211_up(void *para)
 {
        struct wl_priv *wl;
        s32 err = 0;
@@ -6564,17 +6352,16 @@ s32 wl_cfg80211_up(void)
        if (err)
                WL_ERR(("__wl_cfg80211_up failed\n"));
        mutex_unlock(&wl->usr_sync);
-
        return err;
 }
 
-/* Private Event  to Supplicant with indication that FW hangs */
+/* Private Event to Supplicant with indication that chip hangs */
 int wl_cfg80211_hang(struct net_device *dev, u16 reason)
 {
        struct wl_priv *wl;
        wl = wlcfg_drv_priv;
 
-       WL_ERR(("In : FW crash Eventing\n"));
+       WL_ERR(("In : chip crash eventing\n"));
        cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
        if (wl != NULL) {
                wl_link_down(wl);
@@ -6582,7 +6369,7 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason)
        return 0;
 }
 
-s32 wl_cfg80211_down(void)
+s32 wl_cfg80211_down(void *para)
 {
        struct wl_priv *wl;
        s32 err = 0;
@@ -6596,25 +6383,15 @@ s32 wl_cfg80211_down(void)
        return err;
 }
 
-static s32 wl_dongle_probecap(struct wl_priv *wl)
-{
-       s32 err = 0;
-
-       err = wl_update_wiphybands(wl);
-       if (unlikely(err))
-               return err;
-
-       return err;
-}
-
 static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item)
 {
        unsigned long flags;
        void *rptr = NULL;
        struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
+
        if (!profile)
                return NULL;
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        switch (item) {
        case WL_PROF_SEC:
                rptr = &profile->sec;
@@ -6629,7 +6406,7 @@ static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item)
                rptr = &profile->ssid;
                break;
        }
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        if (!rptr)
                WL_ERR(("invalid item (%d)\n", item));
        return rptr;
@@ -6643,9 +6420,10 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
        struct wlc_ssid *ssid;
        unsigned long flags;
        struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
+
        if (!profile)
                return WL_INVALID;
-       flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
+       spin_lock_irqsave(&wl->cfgdrv_lock, flags);
        switch (item) {
        case WL_PROF_SSID:
                ssid = (wlc_ssid_t *) data;
@@ -6677,7 +6455,7 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev,
                err = -EOPNOTSUPP;
                break;
        }
-       dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
+       spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
        return err;
 }
 
@@ -6805,114 +6583,22 @@ static void wl_delay(u32 ms)
        }
 }
 
-s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
-{
-       const struct firmware *fw_entry;
-       struct wl_priv *wl;
-
-       wl = wlcfg_drv_priv;
-
-       fw_entry = wl->fw->fw_entry;
-
-       if (fw_entry->size < wl->fw->ptr + size)
-               size = fw_entry->size - wl->fw->ptr;
-
-       memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
-       wl->fw->ptr += size;
-       return size;
-}
-
-void wl_cfg80211_release_fw(void)
-{
-       struct wl_priv *wl;
-
-       wl = wlcfg_drv_priv;
-       release_firmware(wl->fw->fw_entry);
-       wl->fw->ptr = 0;
-}
-
-void *wl_cfg80211_request_fw(s8 *file_name)
-{
-       struct wl_priv *wl;
-       const struct firmware *fw_entry = NULL;
-       s32 err = 0;
-
-       WL_TRACE(("In\n"));
-       WL_DBG(("file name : \"%s\"\n", file_name));
-       wl = wlcfg_drv_priv;
-
-       if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
-               err = request_firmware(&wl->fw->fw_entry, file_name,
-                       wl_cfg80211_get_parent_dev());
-               if (unlikely(err)) {
-                       WL_ERR(("Could not download fw (%d)\n", err));
-                       goto req_fw_out;
-               }
-               set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
-               fw_entry = wl->fw->fw_entry;
-               if (fw_entry) {
-                       WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
-                               fw_entry->data));
-               }
-       } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
-               err = request_firmware(&wl->fw->fw_entry, file_name,
-                       wl_cfg80211_get_parent_dev());
-               if (unlikely(err)) {
-                       WL_ERR(("Could not download nvram (%d)\n", err));
-                       goto req_fw_out;
-               }
-               set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
-               fw_entry = wl->fw->fw_entry;
-               if (fw_entry) {
-                       WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
-                               fw_entry->data));
-               }
-       } else {
-               WL_DBG(("Downloading already done. Nothing to do more\n"));
-               err = -EPERM;
-       }
-
-req_fw_out:
-       if (unlikely(err)) {
-               return NULL;
-       }
-       wl->fw->ptr = 0;
-       return (void *)fw_entry->data;
-}
-
-s8 *wl_cfg80211_get_fwname(void)
-{
-       struct wl_priv *wl;
-
-       wl = wlcfg_drv_priv;
-       strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
-       return wl->fw->fw_name;
-}
-
-s8 *wl_cfg80211_get_nvramname(void)
-{
-       struct wl_priv *wl;
-
-       wl = wlcfg_drv_priv;
-       strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
-       return wl->fw->nvram_name;
-}
-
 s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
 {
        struct wl_priv *wl;
-       dhd_pub_t *dhd_pub;
        struct ether_addr p2pif_addr;
+       struct ether_addr primary_mac;
 
        wl = wlcfg_drv_priv;
-       dhd_pub = (dhd_pub_t *)wl->pub;
-       wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
+       get_primary_mac(wl, &primary_mac);
+       wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr);
 
        return 0;
 }
 s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
 {
        struct wl_priv *wl;
+
        wl = wlcfg_drv_priv;
 
        return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
@@ -6970,70 +6656,6 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
        return ret;
 }
 
-static __used void wl_dongle_poweron(struct wl_priv *wl)
-{
-       WL_DBG(("Enter \n"));
-       dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
-
-#if defined(BCMLXSDMMC)
-       sdioh_start(NULL, 0);
-#endif
-#if defined(BCMLXSDMMC)
-       sdioh_start(NULL, 1);
-#endif
-       wl_cfg80211_resume(wl_to_wiphy(wl));
-}
-
-static __used void wl_dongle_poweroff(struct wl_priv *wl)
-{
-       WL_DBG(("Enter \n"));
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
-       wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
-#else
-       wl_cfg80211_suspend(wl_to_wiphy(wl));
-#endif
-
-#if defined(BCMLXSDMMC)
-       sdioh_stop(NULL);
-#endif
-       /* clean up dtim_skip setting */
-       dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
-}
-
-static int wl_debugfs_add_netdev_params(struct wl_priv *wl, struct net_device *ndev)
-{
-       char buf[10+IFNAMSIZ];
-       struct dentry *fd;
-       struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev);
-       s32 err = 0;
-
-       WL_TRACE(("In\n"));
-       sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name);
-       wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
-
-       fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
-               (u16 *)&profile->beacon_interval);
-       if (!fd) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-       fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
-               (u8 *)&profile->dtim_period);
-       if (!fd) {
-               err = -ENOMEM;
-               goto err_out;
-       }
-
-err_out:
-       return err;
-}
-
-static void wl_debugfs_remove_netdev(struct wl_priv *wl)
-{
-       WL_DBG(("Enter \n"));
-}
-
 static const struct rfkill_ops wl_rfkill_ops = {
        .set_block = wl_rfkill_set
 };
@@ -7088,486 +6710,42 @@ err_out:
        return err;
 }
 
-#if defined(COEX_DHCP)
-/*
- * get named driver variable to uint register value and return error indication
- * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
- */
-static int
-dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
-       uint reg, int *retval)
-{
-       union {
-               char buf[WLC_IOCTL_SMLEN];
-               int val;
-       } var;
-       int error;
-
-       bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
-               (char *)(&var), sizeof(var.buf));
-       error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
-
-       *retval = dtoh32(var.val);
-       return (error);
-}
-
-static int
-dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
-       char ioctlbuf[1024];
-#else
-       static char ioctlbuf[1024];
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
-
-       bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
-
-       return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
-}
-/*
-get named driver variable to uint register value and return error indication
-calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
-*/
-static int
-dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
-{
-       char reg_addr[8];
-
-       memset(reg_addr, 0, sizeof(reg_addr));
-       memcpy((char *)&reg_addr[0], (char *)addr, 4);
-       memcpy((char *)&reg_addr[4], (char *)val, 4);
-
-       return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
-}
-
-static bool btcoex_is_sco_active(struct net_device *dev)
-{
-       int ioc_res = 0;
-       bool res = FALSE;
-       int sco_id_cnt = 0;
-       int param27;
-       int i;
-
-       for (i = 0; i < 12; i++) {
-
-               ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
-
-               WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
-                       __FUNCTION__, i, param27));
-
-               if (ioc_res < 0) {
-                       WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
-                       break;
-               }
-
-               if ((param27 & 0x6) == 2) { /* count both sco & esco  */
-                       sco_id_cnt++;
-               }
-
-               if (sco_id_cnt > 2) {
-                       WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d  samples:%d\n",
-                               __FUNCTION__, sco_id_cnt, i));
-                       res = TRUE;
-                       break;
-               }
-
-               msleep(5);
-       }
-
-       return res;
-}
-
-#if defined(BT_DHCP_eSCO_FIX)
-/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
-static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+struct device *wl_cfg80211_get_parent_dev(void)
 {
-       static bool saved_status = FALSE;
-
-       char buf_reg50va_dhcp_on[8] =
-               { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
-       char buf_reg51va_dhcp_on[8] =
-               { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-       char buf_reg64va_dhcp_on[8] =
-               { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-       char buf_reg65va_dhcp_on[8] =
-               { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-       char buf_reg71va_dhcp_on[8] =
-               { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
-       uint32 regaddr;
-       static uint32 saved_reg50;
-       static uint32 saved_reg51;
-       static uint32 saved_reg64;
-       static uint32 saved_reg65;
-       static uint32 saved_reg71;
-
-       if (trump_sco) {
-               /* this should reduce eSCO agressive retransmit
-                * w/o breaking it
-                */
-
-               /* 1st save current */
-               WL_TRACE(("Do new SCO/eSCO coex algo {save &"
-                         "override}\n"));
-               if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
-                       saved_status = TRUE;
-                       WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
-                                 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
-                                 __FUNCTION__, saved_reg50, saved_reg51,
-                                 saved_reg64, saved_reg65, saved_reg71));
-               } else {
-                       WL_ERR((":%s: save btc_params failed\n",
-                               __FUNCTION__));
-                       saved_status = FALSE;
-                       return -1;
-               }
-
-               WL_TRACE(("override with [50,51,64,65,71]:"
-                         "0x%x 0x%x 0x%x 0x%x 0x%x\n",
-                         *(u32 *)(buf_reg50va_dhcp_on+4),
-                         *(u32 *)(buf_reg51va_dhcp_on+4),
-                         *(u32 *)(buf_reg64va_dhcp_on+4),
-                         *(u32 *)(buf_reg65va_dhcp_on+4),
-                         *(u32 *)(buf_reg71va_dhcp_on+4)));
-
-               dev_wlc_bufvar_set(dev, "btc_params",
-                       (char *)&buf_reg50va_dhcp_on[0], 8);
-               dev_wlc_bufvar_set(dev, "btc_params",
-                       (char *)&buf_reg51va_dhcp_on[0], 8);
-               dev_wlc_bufvar_set(dev, "btc_params",
-                       (char *)&buf_reg64va_dhcp_on[0], 8);
-               dev_wlc_bufvar_set(dev, "btc_params",
-                       (char *)&buf_reg65va_dhcp_on[0], 8);
-               dev_wlc_bufvar_set(dev, "btc_params",
-                       (char *)&buf_reg71va_dhcp_on[0], 8);
-
-               saved_status = TRUE;
-       } else if (saved_status) {
-               /* restore previously saved bt params */
-               WL_TRACE(("Do new SCO/eSCO coex algo {save &"
-                         "override}\n"));
-
-               regaddr = 50;
-               dev_wlc_intvar_set_reg(dev, "btc_params",
-                       (char *)&regaddr, (char *)&saved_reg50);
-               regaddr = 51;
-               dev_wlc_intvar_set_reg(dev, "btc_params",
-                       (char *)&regaddr, (char *)&saved_reg51);
-               regaddr = 64;
-               dev_wlc_intvar_set_reg(dev, "btc_params",
-                       (char *)&regaddr, (char *)&saved_reg64);
-               regaddr = 65;
-               dev_wlc_intvar_set_reg(dev, "btc_params",
-                       (char *)&regaddr, (char *)&saved_reg65);
-               regaddr = 71;
-               dev_wlc_intvar_set_reg(dev, "btc_params",
-                       (char *)&regaddr, (char *)&saved_reg71);
-
-               WL_TRACE(("restore bt_params[50,51,64,65,71]:"
-                       "0x%x 0x%x 0x%x 0x%x 0x%x\n",
-                       saved_reg50, saved_reg51, saved_reg64,
-                       saved_reg65, saved_reg71));
-
-               saved_status = FALSE;
-       } else {
-               WL_ERR((":%s att to restore not saved BTCOEX params\n",
-                       __FUNCTION__));
-               return -1;
-       }
-       return 0;
+       return cfg80211_parent_dev;
 }
-#endif /* BT_DHCP_eSCO_FIX */
 
-static void
-wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+void wl_cfg80211_set_parent_dev(void *dev)
 {
-#if defined(BT_DHCP_USE_FLAGS)
-       char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
-       char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
-#endif
-
-#if defined(BT_DHCP_eSCO_FIX)
-       /* set = 1, save & turn on  0 - off & restore prev settings */
-       set_btc_esco_params(dev, set);
-#endif
-
-#if defined(BT_DHCP_USE_FLAGS)
-       WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
-       if (set == TRUE)
-               /* Forcing bt_flag7  */
-               dev_wlc_bufvar_set(dev, "btc_flags",
-                       (char *)&buf_flag7_dhcp_on[0],
-                       sizeof(buf_flag7_dhcp_on));
-       else
-               /* Restoring default bt flag7 */
-               dev_wlc_bufvar_set(dev, "btc_flags",
-                       (char *)&buf_flag7_default[0],
-                       sizeof(buf_flag7_default));
-#endif
+       cfg80211_parent_dev = dev;
 }
 
-static void wl_cfg80211_bt_timerfunc(ulong data)
+static void wl_cfg80211_clear_parent_dev(void)
 {
-       struct btcoex_info *bt_local = (struct btcoex_info *)data;
-       WL_TRACE(("%s\n", __FUNCTION__));
-       bt_local->timer_on = 0;
-       schedule_work(&bt_local->work);
+       cfg80211_parent_dev = NULL;
 }
 
-static void wl_cfg80211_bt_handler(struct work_struct *work)
+static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac)
 {
-       struct btcoex_info *btcx_inf;
-
-       btcx_inf = container_of(work, struct btcoex_info, work);
-
-       if (btcx_inf->timer_on) {
-               btcx_inf->timer_on = 0;
-               del_timer_sync(&btcx_inf->timer);
-       }
-
-       switch (btcx_inf->bt_state) {
-               case BT_DHCP_START:
-                       /* DHCP started
-                        * provide OPPORTUNITY window to get DHCP address
-                        */
-                       WL_TRACE(("%s bt_dhcp stm: started \n",
-                               __FUNCTION__));
-                       btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
-                       mod_timer(&btcx_inf->timer,
-                               jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
-                       btcx_inf->timer_on = 1;
-                       break;
-
-               case BT_DHCP_OPPR_WIN:
-                       if (btcx_inf->dhcp_done) {
-                               WL_TRACE(("%s DHCP Done before T1 expiration\n",
-                                       __FUNCTION__));
-                               goto btc_coex_idle;
-                       }
-
-                       /* DHCP is not over yet, start lowering BT priority
-                        * enforce btc_params + flags if necessary
-                        */
-                       WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
-                               BT_DHCP_OPPR_WIN_TIME));
-                       if (btcx_inf->dev)
-                               wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
-                       btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
-                       mod_timer(&btcx_inf->timer,
-                               jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
-                       btcx_inf->timer_on = 1;
-                       break;
-
-               case BT_DHCP_FLAG_FORCE_TIMEOUT:
-                       if (btcx_inf->dhcp_done) {
-                               WL_TRACE(("%s DHCP Done before T2 expiration\n",
-                                       __FUNCTION__));
-                       } else {
-                               /* Noo dhcp during T1+T2, restore BT priority */
-                               WL_TRACE(("%s DHCP wait interval T2:%d"
-                                         "msec expired\n", __FUNCTION__,
-                                         BT_DHCP_FLAG_FORCE_TIME));
-                       }
-
-                       /* Restoring default bt priority */
-                       if (btcx_inf->dev)
-                               wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
-btc_coex_idle:
-                       btcx_inf->bt_state = BT_DHCP_IDLE;
-                       btcx_inf->timer_on = 0;
-                       break;
-
-               default:
-                       WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
-                               btcx_inf->bt_state));
-                       if (btcx_inf->dev)
-                               wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
-                       btcx_inf->bt_state = BT_DHCP_IDLE;
-                       btcx_inf->timer_on = 0;
-                       break;
-       }
-
-       net_os_wake_unlock(btcx_inf->dev);
+       wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL,
+               0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
+       memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN);
 }
 
-static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
+int wl_cfg80211_do_driver_init(struct net_device *net)
 {
-       struct btcoex_info *btco_inf = NULL;
-
-       btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
-       if (!btco_inf)
-               return -ENOMEM;
+       struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net);
 
-       btco_inf->bt_state = BT_DHCP_IDLE;
-       btco_inf->ts_dhcp_start = 0;
-       btco_inf->ts_dhcp_ok = 0;
-       /* Set up timer for BT  */
-       btco_inf->timer_ms = 10;
-       init_timer(&btco_inf->timer);
-       btco_inf->timer.data = (ulong)btco_inf;
-       btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
-
-       btco_inf->dev = wl->wdev->netdev;
+       if (!wl || !wl->wdev)
+               return -EINVAL;
 
-       INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+       if (dhd_do_driver_init(wl->wdev->netdev) < 0)
+               return -1;
 
-       wl->btcoex_info = btco_inf;
        return 0;
 }
 
-static void
-wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
-{
-       if (!wl->btcoex_info)
-               return;
-
-       if (!wl->btcoex_info->timer_on) {
-               wl->btcoex_info->timer_on = 0;
-               del_timer_sync(&wl->btcoex_info->timer);
-       }
-
-       cancel_work_sync(&wl->btcoex_info->work);
-
-       kfree(wl->btcoex_info);
-       wl->btcoex_info = NULL;
-}
-#endif         /* COEX_DHCP */
-
-int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
-{
-       char powermode_val = 0;
-       char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
-       char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
-       char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
-
-       uint32 regaddr;
-       static uint32 saved_reg66;
-       static uint32 saved_reg41;
-       static uint32 saved_reg68;
-       static bool saved_status = FALSE;
-
-#ifdef COEX_DHCP
-       char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
-       struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
-#endif /* COEX_DHCP */
-
-       /* Figure out powermode 1 or o command */
-       strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
-
-       if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
-
-               WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
-
-               /* Retrieve and saved orig regs value */
-               if ((saved_status == FALSE) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
-                       (!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
-                               saved_status = TRUE;
-                               WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
-                                       saved_reg66, saved_reg41, saved_reg68));
-
-                               /* Disable PM mode during dhpc session */
-
-                               /* Disable PM mode during dhpc session */
-#ifdef COEX_DHCP
-                               /* Start  BT timer only for SCO connection */
-                               if (btcoex_is_sco_active(dev)) {
-                                       /* btc_params 66 */
-                                       dev_wlc_bufvar_set(dev, "btc_params",
-                                               (char *)&buf_reg66va_dhcp_on[0],
-                                               sizeof(buf_reg66va_dhcp_on));
-                                       /* btc_params 41 0x33 */
-                                       dev_wlc_bufvar_set(dev, "btc_params",
-                                               (char *)&buf_reg41va_dhcp_on[0],
-                                               sizeof(buf_reg41va_dhcp_on));
-                                       /* btc_params 68 0x190 */
-                                       dev_wlc_bufvar_set(dev, "btc_params",
-                                               (char *)&buf_reg68va_dhcp_on[0],
-                                               sizeof(buf_reg68va_dhcp_on));
-                                       saved_status = TRUE;
-
-                                       btco_inf->bt_state = BT_DHCP_START;
-                                       btco_inf->timer_on = 1;
-                                       mod_timer(&btco_inf->timer, btco_inf->timer.expires);
-                                       WL_TRACE(("%s enable BT DHCP Timer\n",
-                                       __FUNCTION__));
-                               }
-#endif /* COEX_DHCP */
-               }
-               else if (saved_status == TRUE) {
-                       WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
-               }
-       }
-       else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
-
-
-               /* Restoring PM mode */
-
-#ifdef COEX_DHCP
-               /* Stop any bt timer because DHCP session is done */
-               WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
-               if (btco_inf->timer_on) {
-                       btco_inf->timer_on = 0;
-                       del_timer_sync(&btco_inf->timer);
-
-                       if (btco_inf->bt_state != BT_DHCP_IDLE) {
-                       /* need to restore original btc flags & extra btc params */
-                               WL_TRACE(("%s bt->bt_state:%d\n",
-                                       __FUNCTION__, btco_inf->bt_state));
-                               /* wake up btcoex thread to restore btlags+params  */
-                               schedule_work(&btco_inf->work);
-                       }
-               }
-
-               /* Restoring btc_flag paramter anyway */
-               if (saved_status == TRUE)
-                       dev_wlc_bufvar_set(dev, "btc_flags",
-                               (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
-#endif /* COEX_DHCP */
-
-               /* Restore original values */
-               if (saved_status == TRUE) {
-                       regaddr = 66;
-                       dev_wlc_intvar_set_reg(dev, "btc_params",
-                               (char *)&regaddr, (char *)&saved_reg66);
-                       regaddr = 41;
-                       dev_wlc_intvar_set_reg(dev, "btc_params",
-                               (char *)&regaddr, (char *)&saved_reg41);
-                       regaddr = 68;
-                       dev_wlc_intvar_set_reg(dev, "btc_params",
-                               (char *)&regaddr, (char *)&saved_reg68);
-
-                       WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
-                               saved_reg66, saved_reg41, saved_reg68));
-               }
-               saved_status = FALSE;
-
-       }
-       else {
-               WL_ERR(("%s Unkwown yet power setting, ignored\n",
-                       __FUNCTION__));
-       }
-
-       snprintf(command, 3, "OK");
-
-       return (strlen("OK"));
-}
-
-struct device *wl_cfg80211_get_parent_dev(void)
-{
-       return cfg80211_parent_dev;
-}
-
-void wl_cfg80211_set_parent_dev(void *dev)
+void wl_cfg80211_enable_trace(int level)
 {
-       cfg80211_parent_dev = dev;
-}
-
-static void wl_cfg80211_clear_parent_dev(void)
-{
-       cfg80211_parent_dev = NULL;
+       wl_dbg_level |= WL_DBG_DBG;
 }
index 18ff27680cb0f84d4639d6b3246c5108241b0ac6..2b8e66413f23a699b4f2d6c73637d5545b40363a 100644 (file)
@@ -68,6 +68,9 @@ do {                                                                          \
                        printk args;                                            \
                }                                                               \
 } while (0)
+#ifdef WL_INFO
+#undef WL_INFO
+#endif
 #define        WL_INFO(args)                                                                   \
 do {                                                                           \
        if (wl_dbg_level & WL_DBG_INFO) {                               \
@@ -75,6 +78,9 @@ do {                                                                          \
                        printk args;                                            \
                }                                                               \
 } while (0)
+#ifdef WL_SCAN
+#undef WL_SCAN
+#endif
 #define        WL_SCAN(args)                                                           \
 do {                                                                   \
        if (wl_dbg_level & WL_DBG_SCAN) {                       \
@@ -82,6 +88,9 @@ do {                                                                  \
                printk args;                                                    \
        }                                                                       \
 } while (0)
+#ifdef WL_TRACE
+#undef WL_TRACE
+#endif
 #define        WL_TRACE(args)                                                          \
 do {                                                                   \
        if (wl_dbg_level & WL_DBG_TRACE) {                      \
@@ -102,40 +111,30 @@ do {                                                                      \
 #endif                         /* (WL_DBG_LEVEL > 0) */
 
 
-#define WL_SCAN_RETRY_MAX      3       /* used for ibss scan */
-#define WL_NUM_PMKIDS_MAX      MAXPMKID        /* will be used
-                                                * for 2.6.33 kernel
-                                                * or later
-                                                */
-#define WL_SCAN_BUF_MAX                (1024 * 8)
-#define WL_TLV_INFO_MAX                1024
+#define WL_SCAN_RETRY_MAX      3
+#define WL_NUM_PMKIDS_MAX      MAXPMKID
+#define WL_SCAN_BUF_MAX        (1024 * 8)
+#define WL_TLV_INFO_MAX        1024
 #define WL_SCAN_IE_LEN_MAX      2048
-#define WL_BSS_INFO_MAX                        2048
-#define WL_ASSOC_INFO_MAX      512     /*
-                                * needs to grab assoc info from dongle to
-                                * report it to cfg80211 through "connect"
-                                * event
-                                */
+#define WL_BSS_INFO_MAX                2048
+#define WL_ASSOC_INFO_MAX      512
 #define WL_IOCTL_LEN_MAX       1024
 #define WL_EXTRA_BUF_MAX       2048
-#define WL_ISCAN_BUF_MAX       2048    /*
-                                * the buf lengh can be WLC_IOCTL_MAXLEN (8K)
-                                * to reduce iteration
-                                */
+#define WL_ISCAN_BUF_MAX       2048
 #define WL_ISCAN_TIMER_INTERVAL_MS     3000
 #define WL_SCAN_ERSULTS_LAST   (WL_SCAN_RESULTS_NO_MEM+1)
-#define WL_AP_MAX      256     /* virtually unlimitted as long
-                                * as kernel memory allows
-                                */
+#define WL_AP_MAX              256
 #define WL_FILE_NAME_MAX       256
-#define WL_DWELL_TIME          200
-#define WL_LONG_DWELL_TIME     1000
-#define IFACE_MAX_CNT 2
+#define WL_DWELL_TIME          200
+#define WL_MED_DWELL_TIME       400
+#define WL_LONG_DWELL_TIME     1000
+#define IFACE_MAX_CNT          2
 
 #define WL_SCAN_TIMER_INTERVAL_MS      8000 /* Scan timeout */
+#define WL_CHANNEL_SYNC_RETRY  5
+#define WL_INVALID             -1
 
-#define WL_INVALID -1
-/* dongle status */
+/* driver status */
 enum wl_status {
        WL_STATUS_READY = 0,
        WL_STATUS_SCANNING,
@@ -144,7 +143,8 @@ enum wl_status {
        WL_STATUS_CONNECTED,
        WL_STATUS_DISCONNECTING,
        WL_STATUS_AP_CREATING,
-       WL_STATUS_AP_CREATED
+       WL_STATUS_AP_CREATED,
+       WL_STATUS_SENDING_ACT_FRM
 };
 
 /* wi-fi mode */
@@ -154,7 +154,7 @@ enum wl_mode {
        WL_MODE_AP
 };
 
-/* dongle profile list */
+/* driver profile list */
 enum wl_prof_list {
        WL_PROF_MODE,
        WL_PROF_SSID,
@@ -167,7 +167,7 @@ enum wl_prof_list {
        WL_PROF_DTIMPERIOD
 };
 
-/* dongle iscan state */
+/* driver iscan state */
 enum wl_iscan_state {
        WL_ISCAN_STATE_IDLE,
        WL_ISCAN_STATE_SCANING
@@ -197,7 +197,7 @@ struct beacon_proberesp {
        u8 variable[0];
 } __attribute__ ((packed));
 
-/* dongle configuration */
+/* driver configuration */
 struct wl_conf {
        u32 frag_threshold;
        u32 rts_threshold;
@@ -256,7 +256,7 @@ struct wl_ibss {
        u8 channel;
 };
 
-/* dongle profile */
+/* wl driver profile */
 struct wl_profile {
        u32 mode;
        s32 band;
@@ -272,14 +272,14 @@ struct wl_profile {
 struct net_info {
        struct net_device *ndev;
        struct wireless_dev *wdev;
-       struct wl_profile profile;      /* holding dongle profile */
+       struct wl_profile profile;
        s32 mode;
        unsigned long sme_state;
        struct list_head list; /* list of all net_info structure */
 };
 typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl);
 
-/* dongle iscan controller */
+/* iscan controller */
 struct wl_iscan_ctrl {
        struct net_device *dev;
        struct timer_list timer;
@@ -366,20 +366,34 @@ struct sta_info {
        u32 probe_req_ie_len;
        u32 assoc_req_ie_len;
 };
-/* dongle private data of cfg80211 interface */
+
+struct afx_hdl {
+       wl_af_params_t *pending_tx_act_frm;
+       struct ether_addr       pending_tx_dst_addr;
+       struct net_device *dev;
+       struct work_struct work;
+       u32 bssidx;
+       u32 retry;
+       s32 peer_chan;
+       bool ack_recv;
+};
+
+/* private data of cfg80211 interface */
 struct wl_priv {
        struct wireless_dev *wdev;      /* representing wl cfg80211 device */
 
        struct wireless_dev *p2p_wdev;  /* representing wl cfg80211 device for P2P */
        struct net_device *p2p_net;    /* reference to p2p0 interface */
 
-       struct wl_conf *conf;   /* dongle configuration */
+       struct wl_conf *conf;
        struct cfg80211_scan_request *scan_request;     /* scan request object */
        EVENT_HANDLER evt_handler[WLC_E_LAST];
        struct list_head eq_list;       /* used for event queue */
        struct list_head net_list;     /* used for struct net_info */
        spinlock_t eq_lock;     /* for event queue synchronization */
-       struct mutex usr_sync;  /* maily for dongle up/down synchronization */
+       spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */
+       struct completion act_frm_scan;
+       struct mutex usr_sync;  /* maily for up/down synchronization */
        struct wl_scan_results *bss_list;
        struct wl_scan_results *scan_results;
 
@@ -392,8 +406,6 @@ struct wl_priv {
        /* association information container */
        struct wl_connect_info conn_info;
 
-       /* control firwmare and nvram paramter downloading */
-       struct wl_fw_ctrl *fw;
        struct wl_pmk_list *pmk_list;   /* wpa2 pmk list */
        tsk_ctl_t event_tsk;            /* task of main event handler thread */
        void *pub;
@@ -407,12 +419,12 @@ struct wl_priv {
        bool ibss_starter;      /* indicates this sta is ibss starter */
        bool link_up;           /* link/connection up flag */
 
-       /* indicate whether dongle to support power save mode */
+       /* indicate whether chip to support power save mode */
        bool pwr_save;
-       bool dongle_up;         /* indicate whether dongle up or not */
-       bool roam_on;           /* on/off switch for dongle self-roaming */
+       bool roam_on;           /* on/off switch for self-roaming */
        bool scan_tried;        /* indicates if first scan attempted */
-       u8 *ioctl_buf;  /* ioctl buffer */
+       u8 *ioctl_buf;          /* ioctl buffer */
+       struct mutex ioctl_buf_sync;
        u8 *escan_ioctl_buf;
        u8 *extra_buf;  /* maily to grab assoc information */
        struct dentry *debugfsdir;
@@ -420,8 +432,10 @@ struct wl_priv {
        bool rf_blocked;
        struct ieee80211_channel remain_on_chan;
        enum nl80211_channel_type remain_on_chan_type;
+       u64 send_action_id;
        u64 last_roc_id;
-       wait_queue_head_t dongle_event_wait;
+       wait_queue_head_t netif_change_event;
+       struct afx_hdl *afx_hdl;
        struct ap_info *ap_info;
        struct sta_info *sta_info;
        struct p2p_info *p2p;
@@ -474,6 +488,7 @@ wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev)
                }
        }
 }
+
 static inline void
 wl_delete_all_netinfo(struct wl_priv *wl)
 {
@@ -611,28 +626,24 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev)
         (!_sme->crypto.cipher_group))
 extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data);
 extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
-extern void wl_cfg80211_detach(void);
-/* event handler from dongle */
+extern void wl_cfg80211_detach(void *para);
+
 extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
             void *data);
 void wl_cfg80211_set_parent_dev(void *dev);
 struct device *wl_cfg80211_get_parent_dev(void);
 
-extern s32 wl_cfg80211_up(void);       /* dongle up */
-extern s32 wl_cfg80211_down(void);     /* dongle down */
-extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
-int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
+extern s32 wl_cfg80211_up(void *para);
+extern s32 wl_cfg80211_down(void *para);
+extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
+       void* _net_attach);
+extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
 extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev);
 extern s32 wl_cfg80211_is_progress_ifadd(void);
 extern s32 wl_cfg80211_is_progress_ifchange(void);
 extern s32 wl_cfg80211_is_progress_ifadd(void);
 extern s32 wl_cfg80211_notify_ifchange(void);
 extern void wl_cfg80211_dbg_level(u32 level);
-extern void *wl_cfg80211_request_fw(s8 *file_name);
-extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size);
-extern void wl_cfg80211_release_fw(void);
-extern s8 *wl_cfg80211_get_fwname(void);
-extern s8 *wl_cfg80211_get_nvramname(void);
 extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
 extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
 extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
@@ -641,11 +652,11 @@ extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len
 extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
 extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
 extern s32 wl_mode_to_nl80211_iftype(s32 mode);
+int wl_cfg80211_do_driver_init(struct net_device *net);
+void wl_cfg80211_enable_trace(int level);
 
 /* do scan abort */
-extern s32
-wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev);
+extern s32 wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev);
 
-extern s32
-wl_cfg80211_if_is_group_owner(void);
+extern s32 wl_cfg80211_if_is_group_owner(void);
 #endif                         /* _wl_cfg80211_h_ */
index 85c36101ab41f5ad54515fba7a2f3cb7a3ed8ce8..6991a9d785596700c85391525beb10bb6b31f24e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <bcmutils.h>
 #include <bcmendian.h>
 #include <proto/ethernet.h>
-#include <dngl_stats.h>
-#include <dhd.h>
-#include <dhdioctl.h>
-#include <wlioctl.h>
 
 #include <wl_cfg80211.h>
 #include <wl_cfgp2p.h>
 #include <wldev_common.h>
 #include <wl_android.h>
 
-static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
 static s8 scanparambuf[WLC_IOCTL_SMLEN];
-static s8 *smbuf = ioctlbuf;
 
 static bool
 wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
 
 static s32
-wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
             s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
 
 static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
@@ -123,6 +118,8 @@ wl_cfgp2p_init_priv(struct wl_priv *wl)
 void
 wl_cfgp2p_deinit_priv(struct wl_priv *wl)
 {
+       CFGP2P_DBG(("In\n"));
+
        if (wl->p2p) {
                kfree(wl->p2p);
                wl->p2p = NULL;
@@ -155,7 +152,7 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
         * firmware for P2P device address
         */
        ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
-                   sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0);
+               sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync);
        if (ret && ret != BCME_UNSUPPORTED) {
                CFGP2P_ERR(("failed to update device address\n"));
        }
@@ -181,14 +178,14 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
        ifreq.chspec = chspec;
        memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
 
-       CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
+       CFGP2P_DBG(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
            ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
                ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
                (if_type == WL_P2P_IF_GO) ? "go" : "client",
                (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
 
        err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
-               ioctlbuf, sizeof(ioctlbuf));
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
        return err;
 }
 
@@ -207,7 +204,7 @@ wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac)
            netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
            mac->octet[3], mac->octet[4], mac->octet[5]));
        ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
-               ioctlbuf, sizeof(ioctlbuf));
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
        if (unlikely(ret < 0)) {
                printk("'wl p2p_ifdel' error %d\n", ret);
        }
@@ -238,7 +235,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
                (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
 
        err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
-               ioctlbuf, sizeof(ioctlbuf));
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 
        if (unlikely(err < 0)) {
                printk("'wl p2p_ifupd' error %d\n", err);
@@ -264,8 +261,8 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
            mac->octet[0], mac->octet[1], mac->octet[2],
            mac->octet[3], mac->octet[4], mac->octet[5]));
 
-       ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac),
-                   getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY));
+       ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
+               sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL);
 
        if (ret == 0) {
                memcpy(index, getbuf, sizeof(index));
@@ -275,7 +272,7 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
        return ret;
 }
 
-s32
+static s32
 wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
 {
        s32 ret = BCME_OK;
@@ -324,13 +321,14 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms,
        discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
        discovery_mode.dwell = listen_ms;
        ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
-                   sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx);
+               sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+               bssidx, &wl->ioctl_buf_sync);
 
        return ret;
 }
 
 /* Get the index of the P2P Discovery BSS */
-s32
+static s32
 wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
 {
        s32 ret;
@@ -394,7 +392,7 @@ wl_cfgp2p_init_discovery(struct wl_priv *wl)
  * @wl        : wl_private data
  * Returns 0 if succes
  */
-s32
+static s32
 wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
 {
        s32 ret = BCME_OK;
@@ -432,7 +430,8 @@ wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
  * Returns 0 if success.
  */
 s32
-wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len)
+wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev,
+       const u8 *ie, u32 ie_len)
 {
        s32 ret = BCME_OK;
        if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
@@ -524,9 +523,9 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
        wl_escan_params_t *eparams;
        wlc_ssid_t ssid;
        /* Scan parameters */
-#define P2PAPI_SCAN_NPROBES 4
-#define P2PAPI_SCAN_DWELL_TIME_MS 80
-#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 50
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
 #define P2PAPI_SCAN_HOME_TIME_MS 10
        struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
        wl_set_p2p_status(wl, SCANNING);
@@ -543,7 +542,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
                return -1;
        }
        memset(memblk, 0, memsize);
-       memset(ioctlbuf, 0, sizeof(ioctlbuf));
+       memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
        if (search_state == WL_P2P_DISC_ST_SEARCH) {
                /*
                 * If we in SEARCH STATE, we don't need to set SSID explictly
@@ -608,9 +607,54 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
        CFGP2P_INFO(("\n"));
 
        ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
-                   memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
+               memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
+       return ret;
+}
+
+/* search function to reach at common channel to send action frame
+ * Parameters:
+ * @wl       : wl_private data
+ * @ndev     : net device for bssidx
+ * @bssidx   : bssidx for BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
+       s32 bssidx, s32 channel)
+{
+       s32 ret = 0;
+       u32 chan_cnt = 0;
+       u16 *default_chan_list = NULL;
+       if (!p2p_is_on(wl))
+               return -BCME_ERROR;
+       CFGP2P_ERR((" Enter\n"));
+       if (bssidx == P2PAPI_BSSCFG_PRIMARY)
+               bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+       if (channel)
+               chan_cnt = 1;
+       else
+               chan_cnt = SOCIAL_CHAN_CNT;
+       default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
+       if (default_chan_list == NULL) {
+               CFGP2P_ERR(("channel list allocation failed \n"));
+               ret = -ENOMEM;
+               goto exit;
+       }
+       if (channel) {
+               default_chan_list[0] = channel;
+       } else {
+               default_chan_list[0] = SOCIAL_CHAN_1;
+               default_chan_list[1] = SOCIAL_CHAN_2;
+               default_chan_list[2] = SOCIAL_CHAN_3;
+       }
+       ret = wl_cfgp2p_escan(wl, ndev, true, SOCIAL_CHAN_CNT,
+               default_chan_list, WL_P2P_DISC_ST_SEARCH,
+               WL_SCAN_ACTION_START, bssidx);
+       kfree(default_chan_list);
+exit:
        return ret;
 }
+
 /* Check whether pointed-to IE looks like WPA. */
 #define wl_cfgp2p_is_wpa_ie(ie, tlvs, len)     wl_cfgp2p_has_ie(ie, tlvs, len, \
                (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
@@ -648,7 +692,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
        u8 delete = 0;
 #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
 #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
-       if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
+       if (p2p_is_on(wl) && bssidx != -1) {
                if (bssidx == P2PAPI_BSSCFG_PRIMARY)
                        bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
                switch (pktflag) {
@@ -748,8 +792,9 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
                                        CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
                                                "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
                                                ie_buf[pos+1], ie_buf[pos+2]));
-                                       ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
-                                           VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+                                       ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
+                                               ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
+                                               ie_len-3, delete);
                                }
                                pos += ie_len;
                        }
@@ -773,8 +818,9 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss
                                        CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
                                                "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
                                                ie_buf[pos+1], ie_buf[pos+2]));
-                                       ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
-                                           VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
+                                       ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag,
+                                               ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3,
+                                               ie_len-3, delete);
                                }
                                pos += ie_len;
                        }
@@ -880,7 +926,7 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
 }
 
 static s32
-wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
+wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
             s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
 {
        s32 err = BCME_OK;
@@ -922,7 +968,7 @@ wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
        memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
        memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
        err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
-               ioctlbuf, sizeof(ioctlbuf), bssidx);
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 
        CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
        kfree(ie_setbuf);
@@ -1106,10 +1152,10 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
                        wl_set_p2p_status(wl, ACTION_TX_NOACK);
                        CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
                }
-               wake_up_interruptible(&wl->dongle_event_wait);
        } else {
                CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
                                        "status : %d\n", status));
+               wake_up_interruptible(&wl->netif_change_event);
        }
        return ret;
 }
@@ -1139,15 +1185,15 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
        if (bssidx == P2PAPI_BSSCFG_PRIMARY)
                bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
 
-       ret = wldev_iovar_setbuf_bsscfg(dev, "actframe",
-                  af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx);
+       ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
 
        if (ret < 0) {
 
                CFGP2P_ERR((" sending action frame is failed\n"));
                goto exit;
        }
-       timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+       timeout = wait_event_interruptible_timeout(wl->netif_change_event,
        (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
        msecs_to_jiffies(MAX_WAIT_TIME));
 
@@ -1256,7 +1302,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
        /* Check if the BSS is up */
        *(int*)getbuf = -1;
        result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
-                           sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0);
+               sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
        if (result != 0) {
                CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
                CFGP2P_ERR(("NOTE: this ioctl error is normal "
@@ -1273,7 +1319,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
 
 /* Bring up or down a BSS */
 s32
-wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up)
 {
        s32 ret = BCME_OK;
        s32 val = up ? 1 : 0;
@@ -1287,7 +1333,7 @@ wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
        bss_setbuf.val = htod32(val);
        CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
        ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
-               ioctlbuf, sizeof(ioctlbuf));
+               wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
 
        if (ret != 0) {
                CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
@@ -1343,7 +1389,7 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf
 
                sscanf(buf, "%d %d %d", &count, &start, &duration);
                CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
-                               count, start, duration));
+                       count, start, duration));
                if (count != -1)
                        wl->p2p->noa.desc[0].count = count;
 
@@ -1387,7 +1433,8 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf
                dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
 
                ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
-                       "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf));
+                       "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN,
+                       &wl->ioctl_buf_sync);
 
                if (ret < 0) {
                        CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
@@ -1459,7 +1506,7 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf,
                        wl->p2p->ops.ops = ps;
                        ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
                                "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
-                               ioctlbuf, sizeof(ioctlbuf));
+                               wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
                        if (ret < 0) {
                                CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
                        }
@@ -1481,6 +1528,96 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf,
        return ret;
 }
 
+u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
+{
+       wifi_p2p_ie_t *ie = NULL;
+       u16 len = 0;
+       u8 *subel;
+       u8 subelt_id;
+       u16 subelt_len;
+
+       if (!buf) {
+               WL_ERR(("P2P IE not present"));
+               return 0;
+       }
+
+       ie = (wifi_p2p_ie_t*) buf;
+       len = ie->len;
+
+       /* Point subel to the P2P IE's subelt field.
+        * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+        */
+       subel = ie->subelts;
+       len -= 4;       /* exclude OUI + OUI_TYPE */
+
+       while (len >= 3) {
+       /* attribute id */
+               subelt_id = *subel;
+               subel += 1;
+               len -= 1;
+
+               /* 2-byte little endian */
+               subelt_len = *subel++;
+               subelt_len |= *subel++ << 8;
+
+               len -= 2;
+               len -= subelt_len;      /* for the remaining subelt fields */
+
+               if (subelt_id == element_id) {
+                       /* This will point to start of subelement attrib after
+                        * attribute id & len
+                        */
+                       return subel;
+               }
+
+               /* Go to next subelement */
+               subel += subelt_len;
+       }
+
+       /* Not Found */
+       return NULL;
+}
+
+#define P2P_GROUP_CAPAB_GO_BIT 0x01
+u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
+{
+       wifi_p2p_ie_t * p2p_ie = NULL;
+       u8 *capability = NULL;
+       bool p2p_go     = 0;
+       u8 *ptr = NULL;
+
+       if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) {
+               WL_ERR(("P2P IE not found"));
+               return NULL;
+       }
+
+       if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) {
+               WL_ERR(("P2P Capability attribute not found"));
+               return NULL;
+       }
+
+       /* Check Group capability for Group Owner bit */
+       p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
+       if (!p2p_go) {
+               return bi->BSSID.octet;
+       }
+
+       /* In probe responses, DEVICE INFO attribute will be present */
+       if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) {
+               /* If DEVICE_INFO is not found, this might be a beacon frame.
+                * check for DEVICE_ID in the beacon frame.
+                */
+               ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID);
+       }
+
+       if (!ptr)
+               WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
+
+       return ptr;
+}
+
 s32
 wl_cfgp2p_register_ndev(struct wl_priv *wl)
 {
@@ -1613,12 +1750,34 @@ static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd
 
 static int wl_cfgp2p_if_open(struct net_device *net)
 {
-       CFGP2P_DBG(("Do Nothing \n"));
+       struct wireless_dev *wdev = net->ieee80211_ptr;
+
+       if (!wdev)
+               return -EINVAL;
+
+       /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
+        * do it here. This will make sure that in concurrent mode, supplicant
+        * is not dependent on a particular order of interface initialization.
+        * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
+        * -iwlan0.
+        */
+       wl_cfg80211_do_driver_init(net);
+
+       wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
+               | BIT(NL80211_IFTYPE_P2P_GO));
+
        return 0;
 }
 
 static int wl_cfgp2p_if_stop(struct net_device *net)
 {
-       CFGP2P_DBG(("Do Nothing \n"));
+       struct wireless_dev *wdev = net->ieee80211_ptr;
+
+       if (!wdev)
+               return -EINVAL;
+
+       wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
+                                       & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+                                       BIT(NL80211_IFTYPE_P2P_GO)));
        return 0;
 }
index 6934d8f1c9bea55898c8048cf312c2d94649597d..d50b00f8394c4b189f2ada4730372e04b250a8d5 100644 (file)
@@ -107,7 +107,7 @@ enum wl_cfgp2p_status {
                                                                        &(wl)->p2p->status))
 #define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \
                                                                        &(wl)->p2p->status))
-#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : change_bit(WLP2P_STATUS_ ## stat, \
+#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0: change_bit(WLP2P_STATUS_ ## stat, \
                                                                        &(wl)->p2p->status))
 #define p2p_on(wl) ((wl)->p2p->on)
 #define p2p_scan(wl) ((wl)->p2p->scan)
@@ -172,6 +172,10 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_
        u16 *channels,
        s32 search_state, u16 action, u32 bssidx);
 
+extern s32
+wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev,
+       s32 bssidx, s32 channel);
+
 extern wpa_ie_fixed_t *
 wl_cfgp2p_find_wpaie(u8 *parse, u32 len);
 
@@ -217,7 +221,7 @@ extern bool
 wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx);
 
 extern s32
-wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up);
+wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up);
 
 
 extern s32
@@ -235,6 +239,12 @@ wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, in
 extern s32
 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
 
+extern u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id);
+
+extern u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length);
+
 extern s32
 wl_cfgp2p_register_ndev(struct wl_priv *wl);
 
@@ -245,9 +255,22 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl);
 #define SOCIAL_CHAN_1 1
 #define SOCIAL_CHAN_2 6
 #define SOCIAL_CHAN_3 11
+#define SOCIAL_CHAN_CNT 3
 #define WL_P2P_WILDCARD_SSID "DIRECT-"
 #define WL_P2P_WILDCARD_SSID_LEN 7
 #define WL_P2P_INTERFACE_PREFIX "p2p"
 #define WL_P2P_TEMP_CHAN "11"
+#define IS_PUB_ACT_FRAME(category) ((category == P2P_PUB_AF_CATEGORY))
+#define IS_P2P_ACT_FRAME(category) ((category == P2P_AF_CATEGORY))
+
+#define IS_P2P_ACTION(categry, action) (IS_PUB_ACT_FRAME(category) && (action == P2P_PUB_AF_ACTION))
+#define IS_GAS_REQ(category, action) (IS_PUB_ACT_FRAME(category) && \
+                                       ((action == P2PSD_ACTION_ID_GAS_IREQ) || \
+                                       (action == P2PSD_ACTION_ID_GAS_CREQ)))
+#define IS_P2P_ACT_REQ(category, subtype) (IS_PUB_ACT_FRAME(category) && \
+                                               ((subtype == P2P_PAF_GON_REQ) || \
+                                               (subtype == P2P_PAF_INVITE_REQ) || \
+                                               (subtype == P2P_PAF_PROVDIS_REQ)))
+#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3))
 #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0)
 #endif                         /* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
new file mode 100644 (file)
index 0000000..f44b4b0
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ * 
+ *         Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ * 
+ *      As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module.  An independent module is a module which is not
+ * derived from this software.  The special exception does not apply to any
+ * modifications of the software.
+ * 
+ *      Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_linux_mon.c 303266 2011-12-16 00:15:23Z $
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
+#include <linux/rtnetlink.h>
+#include <net/ieee80211_radiotap.h>
+
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+typedef enum monitor_states
+{
+       MONITOR_STATE_DEINIT = 0x0,
+       MONITOR_STATE_INIT = 0x1,
+       MONITOR_STATE_INTERFACE_ADDED = 0x2,
+       MONITOR_STATE_INTERFACE_DELETED = 0x4
+} monitor_states_t;
+extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+
+/**
+ * Local declarations and defintions (not exposed)
+ */
+#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
+#define MON_TRACE MON_PRINT
+
+typedef struct monitor_interface {
+       int radiotap_enabled;
+       struct net_device* real_ndev;   /* The real interface that the monitor is on */
+       struct net_device* mon_ndev;
+} monitor_interface;
+
+typedef struct dhd_linux_monitor {
+       void *dhd_pub;
+       monitor_states_t monitor_state;
+       monitor_interface mon_if[DHD_MAX_IFS];
+       struct mutex lock;              /* lock to protect mon_if */
+} dhd_linux_monitor_t;
+
+static dhd_linux_monitor_t g_monitor;
+
+static struct net_device* lookup_real_netdev(char *name);
+static monitor_interface* ndev_to_monif(struct net_device *ndev);
+static int dhd_mon_if_open(struct net_device *ndev);
+static int dhd_mon_if_stop(struct net_device *ndev);
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
+
+static const struct net_device_ops dhd_mon_if_ops = {
+       .ndo_open               = dhd_mon_if_open,
+       .ndo_stop               = dhd_mon_if_stop,
+       .ndo_start_xmit         = dhd_mon_if_subif_start_xmit,
+       .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
+       .ndo_set_mac_address    = dhd_mon_if_change_mac,
+};
+
+/**
+ * Local static function defintions
+ */
+
+/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
+ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
+ */
+static struct net_device* lookup_real_netdev(char *name)
+{
+       int i;
+       int len = 0;
+       int last_name_len = 0;
+       struct net_device *ndev;
+       struct net_device *ndev_found = NULL;
+
+       /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
+        * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
+        * iface would be mon-p2p0-0.
+        */
+       for (i = 0; i < DHD_MAX_IFS; i++) {
+               ndev = dhd_idx2net(g_monitor.dhd_pub, i);
+
+               /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
+                * it matches, then this netdev is the corresponding real_netdev.
+                */
+               if (ndev && strstr(ndev->name, "p2p-p2p0")) {
+                       len = strlen("p2p");
+               } else {
+               /* if p2p- is not present, then the IFNAMSIZ have reached and name
+                * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
+                */
+                       len = 0;
+               }
+               if (ndev && strstr(name, (ndev->name + len))) {
+                       if (strlen(ndev->name) > last_name_len) {
+                               ndev_found = ndev;
+                               last_name_len = strlen(ndev->name);
+                       }
+               }
+       }
+
+       return ndev_found;
+}
+
+static monitor_interface* ndev_to_monif(struct net_device *ndev)
+{
+       int i;
+
+       for (i = 0; i < DHD_MAX_IFS; i++) {
+               if (g_monitor.mon_if[i].mon_ndev == ndev)
+                       return &g_monitor.mon_if[i];
+       }
+
+       return NULL;
+}
+
+static int dhd_mon_if_open(struct net_device *ndev)
+{
+       int ret = 0;
+
+       MON_PRINT("enter\n");
+       return ret;
+}
+
+static int dhd_mon_if_stop(struct net_device *ndev)
+{
+       int ret = 0;
+
+       MON_PRINT("enter\n");
+       return ret;
+}
+
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+       int ret = 0;
+       int rtap_len;
+       int qos_len = 0;
+       int dot11_hdr_len = 24;
+       int snap_len = 6;
+       unsigned char *pdata;
+       unsigned short frame_ctl;
+       unsigned char src_mac_addr[6];
+       unsigned char dst_mac_addr[6];
+       struct ieee80211_hdr *dot11_hdr;
+       struct ieee80211_radiotap_header *rtap_hdr;
+       monitor_interface* mon_if;
+
+       MON_PRINT("enter\n");
+
+       mon_if = ndev_to_monif(ndev);
+       if (mon_if == NULL || mon_if->real_ndev == NULL) {
+               MON_PRINT(" cannot find matched net dev, skip the packet\n");
+               goto fail;
+       }
+
+       if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+               goto fail;
+
+       rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+       if (unlikely(rtap_hdr->it_version))
+               goto fail;
+
+       rtap_len = ieee80211_get_radiotap_len(skb->data);
+       if (unlikely(skb->len < rtap_len))
+               goto fail;
+
+       MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
+
+       /* Skip the ratio tap header */
+       skb_pull(skb, rtap_len);
+
+       dot11_hdr = (struct ieee80211_hdr *)skb->data;
+       frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
+       /* Check if the QoS bit is set */
+       if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+               /* Check if this ia a Wireless Distribution System (WDS) frame
+                * which has 4 MAC addresses
+                */
+               if (dot11_hdr->frame_control & 0x0080)
+                       qos_len = 2;
+               if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+                       dot11_hdr_len += 6;
+
+               memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+               memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+               /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+                * for two MAC addresses
+                */
+               skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+               pdata = (unsigned char*)skb->data;
+               memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+               memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+
+               MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+
+               /* Use the real net device to transmit the packet */
+               ret = dhd_start_xmit(skb, mon_if->real_ndev);
+
+               return ret;
+       }
+fail:
+       dev_kfree_skb(skb);
+       return 0;
+}
+
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
+{
+       monitor_interface* mon_if;
+
+       mon_if = ndev_to_monif(ndev);
+       if (mon_if == NULL || mon_if->real_ndev == NULL) {
+               MON_PRINT(" cannot find matched net dev, skip the packet\n");
+       } else {
+               MON_PRINT("enter, if name: %s, matched if name %s\n",
+               ndev->name, mon_if->real_ndev->name);
+       }
+}
+
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
+{
+       int ret = 0;
+       monitor_interface* mon_if;
+
+       mon_if = ndev_to_monif(ndev);
+       if (mon_if == NULL || mon_if->real_ndev == NULL) {
+               MON_PRINT(" cannot find matched net dev, skip the packet\n");
+       } else {
+               MON_PRINT("enter, if name: %s, matched if name %s\n",
+               ndev->name, mon_if->real_ndev->name);
+       }
+       return ret;
+}
+
+/**
+ * Global function definitions (declared in dhd_linux_mon.h)
+ */
+
+int dhd_add_monitor(char *name, struct net_device **new_ndev)
+{
+       int i;
+       int idx = -1;
+       int ret = 0;
+       struct net_device* ndev = NULL;
+       dhd_linux_monitor_t **dhd_mon;
+
+       mutex_lock(&g_monitor.lock);
+
+       MON_TRACE("enter, if name: %s\n", name);
+       if (!name || !new_ndev) {
+               MON_PRINT("invalid parameters\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * Find a vacancy
+        */
+       for (i = 0; i < DHD_MAX_IFS; i++)
+               if (g_monitor.mon_if[i].mon_ndev == NULL) {
+                       idx = i;
+                       break;
+               }
+       if (idx == -1) {
+               MON_PRINT("exceeds maximum interfaces\n");
+               ret = -EFAULT;
+               goto out;
+       }
+
+       ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
+       if (!ndev) {
+               MON_PRINT("failed to allocate memory\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+       strncpy(ndev->name, name, IFNAMSIZ);
+       ndev->name[IFNAMSIZ - 1] = 0;
+       ndev->netdev_ops = &dhd_mon_if_ops;
+
+       ret = register_netdevice(ndev);
+       if (ret) {
+               MON_PRINT(" register_netdevice failed (%d)\n", ret);
+               goto out;
+       }
+
+       *new_ndev = ndev;
+       g_monitor.mon_if[idx].radiotap_enabled = TRUE;
+       g_monitor.mon_if[idx].mon_ndev = ndev;
+       g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
+       dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
+       *dhd_mon = &g_monitor;
+       g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
+       MON_PRINT("net device returned: 0x%p\n", ndev);
+       MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
+
+out:
+       if (ret && ndev)
+               free_netdev(ndev);
+
+       mutex_unlock(&g_monitor.lock);
+       return ret;
+
+}
+
+int dhd_del_monitor(struct net_device *ndev)
+{
+       int i;
+       bool rollback_lock = false;
+       if (!ndev)
+               return -EINVAL;
+       mutex_lock(&g_monitor.lock);
+       for (i = 0; i < DHD_MAX_IFS; i++) {
+               if (g_monitor.mon_if[i].mon_ndev == ndev ||
+                       g_monitor.mon_if[i].real_ndev == ndev) {
+                       g_monitor.mon_if[i].real_ndev = NULL;
+                       if (rtnl_is_locked()) {
+                               rtnl_unlock();
+                               rollback_lock = true;
+                       }
+                       unregister_netdev(g_monitor.mon_if[i].mon_ndev);
+                       free_netdev(g_monitor.mon_if[i].mon_ndev);
+                       g_monitor.mon_if[i].mon_ndev = NULL;
+                       g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
+                       break;
+               }
+       }
+       if (rollback_lock) {
+               rtnl_lock();
+               rollback_lock = false;
+       }
+
+       if (g_monitor.monitor_state !=
+       MONITOR_STATE_INTERFACE_DELETED)
+               MON_PRINT("interface not found in monitor IF array, is this a monitor IF? 0x%p\n",
+                       ndev);
+       mutex_unlock(&g_monitor.lock);
+
+       return 0;
+}
+
+int dhd_monitor_init(void *dhd_pub)
+{
+       if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
+               g_monitor.dhd_pub = dhd_pub;
+               mutex_init(&g_monitor.lock);
+               g_monitor.monitor_state = MONITOR_STATE_INIT;
+       }
+       return 0;
+}
+
+int dhd_monitor_uninit(void)
+{
+       int i;
+       struct net_device *ndev;
+       bool rollback_lock = false;
+       mutex_lock(&g_monitor.lock);
+       if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
+               for (i = 0; i < DHD_MAX_IFS; i++) {
+                       ndev = g_monitor.mon_if[i].mon_ndev;
+                       if (ndev) {
+                               if (rtnl_is_locked()) {
+                                       rtnl_unlock();
+                                       rollback_lock = true;
+                               }
+                               unregister_netdev(ndev);
+                               free_netdev(ndev);
+                               g_monitor.mon_if[i].real_ndev = NULL;
+                               g_monitor.mon_if[i].mon_ndev = NULL;
+                               if (rollback_lock) {
+                                       rtnl_lock();
+                                       rollback_lock = false;
+                               }
+                       }
+               }
+               g_monitor.monitor_state = MONITOR_STATE_DEINIT;
+       }
+       mutex_unlock(&g_monitor.lock);
+       return 0;
+}
index bb3eaea90d0f9b55d43896883b6c9d574a3aa782..d9a0b93d689fad66218cc26385122b2247354d2e 100644 (file)
  * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
  */
 
-#include <linux/module.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/netdevice.h>
 
 #include <wldev_common.h>
 #include <bcmutils.h>
-#include <dhd_dbg.h>
 
 #define htod32(i) i
 #define htod16(i) i
 #define dtoh16(i) i
 #define htodchanspec(i) i
 #define dtohchanspec(i) i
+
+#define        WLDEV_ERROR(args)                                               \
+       do {                                                                            \
+               printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__);        \
+               printk args;                                                    \
+       } while (0)
+
 extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
 
 s32 wldev_ioctl(
@@ -71,26 +79,34 @@ static s32 wldev_mkiovar(
 
 s32 wldev_iovar_getbuf(
        struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen)
+       void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
 {
        s32 ret = 0;
        s32 iovar_len = 0;
-
+       if (buf_sync) {
+               mutex_lock(buf_sync);
+       }
        iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
        ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+       if (buf_sync)
+               mutex_unlock(buf_sync);
        return ret;
 }
 
 
 s32 wldev_iovar_setbuf(
        struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen)
+       void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
 {
        s32 ret = 0;
        s32 iovar_len;
-
+       if (buf_sync) {
+               mutex_lock(buf_sync);
+       }
        iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
        ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+       if (buf_sync)
+               mutex_unlock(buf_sync);
        return ret;
 }
 
@@ -102,7 +118,7 @@ s32 wldev_iovar_setint(
        val = htod32(val);
        memset(iovar_buf, 0, sizeof(iovar_buf));
        return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
-               sizeof(iovar_buf));
+               sizeof(iovar_buf), NULL);
 }
 
 
@@ -114,7 +130,7 @@ s32 wldev_iovar_getint(
 
        memset(iovar_buf, 0, sizeof(iovar_buf));
        err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
-               sizeof(iovar_buf));
+               sizeof(iovar_buf), NULL);
        if (err == 0)
        {
                memcpy(pval, iovar_buf, sizeof(*pval));
@@ -148,7 +164,7 @@ s32 wldev_mkiovar_bsscfg(
 
        if (buflen < 0 || iolen > (u32)buflen)
        {
-               DHD_ERROR(("%s: buffer is too short\n", __FUNCTION__));
+               WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
                return BCME_BUFTOOSHORT;
        }
 
@@ -177,26 +193,37 @@ s32 wldev_mkiovar_bsscfg(
 
 s32 wldev_iovar_getbuf_bsscfg(
        struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
+       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
 {
        s32 ret = 0;
        s32 iovar_len = 0;
-
+       if (buf_sync) {
+               mutex_lock(buf_sync);
+       }
        iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
        ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+       if (buf_sync) {
+               mutex_unlock(buf_sync);
+       }
        return ret;
 
 }
 
 s32 wldev_iovar_setbuf_bsscfg(
        struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
+       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
 {
        s32 ret = 0;
        s32 iovar_len;
-
+       if (buf_sync) {
+               mutex_lock(buf_sync);
+       }
        iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+
        ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+       if (buf_sync) {
+               mutex_unlock(buf_sync);
+       }
        return ret;
 }
 
@@ -208,7 +235,7 @@ s32 wldev_iovar_setint_bsscfg(
        val = htod32(val);
        memset(iovar_buf, 0, sizeof(iovar_buf));
        return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
-               sizeof(iovar_buf), bssidx);
+               sizeof(iovar_buf), bssidx, NULL);
 }
 
 
@@ -220,7 +247,7 @@ s32 wldev_iovar_getint_bsscfg(
 
        memset(iovar_buf, 0, sizeof(iovar_buf));
        err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
-               sizeof(iovar_buf), bssidx);
+               sizeof(iovar_buf), bssidx, NULL);
        if (err == 0)
        {
                memcpy(pval, iovar_buf, sizeof(*pval));
@@ -309,16 +336,16 @@ int wldev_set_country(
                return error;
 
        error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec),
-               smbuf, sizeof(smbuf));
+               smbuf, sizeof(smbuf), NULL);
        if (error < 0)
-               DHD_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
+               WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
 
        if ((error < 0) ||
            (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) {
                bzero(&scbval, sizeof(scb_val_t));
                error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
                if (error < 0) {
-                       DHD_ERROR(("%s: set country failed due to Disassoc error %d\n",
+                       WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
                                __FUNCTION__, error));
                        return error;
                }
@@ -328,14 +355,14 @@ int wldev_set_country(
        memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
        get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
        error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
-               smbuf, sizeof(smbuf));
+               smbuf, sizeof(smbuf), NULL);
        if (error < 0) {
-               DHD_ERROR(("%s: set country for %s as %s rev %d failed\n",
+               WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
                        __FUNCTION__, country_code, cspec.ccode, cspec.rev));
                return error;
        }
        dhd_bus_country_set(dev, &cspec);
-       DHD_INFO(("%s: set country for %s as %s rev %d\n",
+       WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
                __FUNCTION__, country_code, cspec.ccode, cspec.rev));
        return 0;
 }
index 46326803e21639267e7ad57fceb9940ba67de0c3..6a1ba153360092d424a1ab1eb8cf6d1937658837 100644 (file)
  * software in any way with any other Broadcom software provided under a license
  * other than the GPL, without Broadcom's express prior written consent.
  *
- * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
+ * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
  */
 #ifndef __WLDEV_COMMON_H__
 #define __WLDEV_COMMON_H__
 
 #include <wlioctl.h>
 
-/** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or 
+/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
  *  netdev_ops->ndo_do_ioctl in new kernels)
  *  @dev: the net_device handle
  */
 s32 wldev_ioctl(
        struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set);
 
-/** Retrieve named IOVARs, this function calls wl_dev_ioctl with 
+/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
  *  WLC_GET_VAR IOCTL code
  */
 s32 wldev_iovar_getbuf(
        struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen);
+       void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
 
 /** Set named IOVARs, this function calls wl_dev_ioctl with
  *  WLC_SET_VAR IOCTL code
  */
 s32 wldev_iovar_setbuf(
        struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen);
+       void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
 
 s32 wldev_iovar_setint(
        struct net_device *dev, s8 *iovar, s32 val);
@@ -67,15 +67,15 @@ s32 wldev_mkiovar_bsscfg(
  *  WLC_GET_VAR IOCTL code
  */
 s32 wldev_iovar_getbuf_bsscfg(
-       struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
+       struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+       void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
 
 /** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
  *  WLC_SET_VAR IOCTL code
  */
 s32 wldev_iovar_setbuf_bsscfg(
-       struct net_device *dev, s8 *iovar_name,
-       void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
+       struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+       void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
 
 s32 wldev_iovar_getint_bsscfg(
        struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx);
@@ -94,7 +94,7 @@ extern int net_os_set_dtim_skip(struct net_device *dev, int val);
 extern int net_os_set_suspend_disable(struct net_device *dev, int val);
 extern int net_os_set_suspend(struct net_device *dev, int val);
 extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
-                                       int max, int *bytes_left);
+       int max, int *bytes_left);
 
 /* Get the link speed from dongle, speed is in kpbs */
 int wldev_get_link_speed(struct net_device *dev, int *plink_speed);