MLK-14688: bcmdhd: update to version 1.141.100.6
authorxlin <xlin@murata.com>
Thu, 23 Mar 2017 16:21:01 +0000 (11:21 -0500)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:22:02 +0000 (15:22 -0500)
Features:
- support for CYW43455 (Murata 1HK)
- support for simultaneous STA-AP operation
- Hostapd ACS support
- 4339 OOB enable based on DTS GPIO configuration
- 43340 packet filter timeout event

Bug Fixes:
- 4339 high current after wake up
- Vendor IE does not show up in SoftAP beacons
- mfgtest driver crash when wpa_supplicant is running
- Fix for PMF testcase 5.3.3.2 failing due to deauth packets not being sent

Known Issues:
 Kernel panic upon rmmod after insmod failure

Signed-off-by: xlin <xlin@murata.com>
Signed-off-by: Tiberiu Breana <andrei-tiberiu.breana@nxp.com>
39 files changed:
drivers/net/wireless/bcmdhd/Kconfig
drivers/net/wireless/bcmdhd/Makefile
drivers/net/wireless/bcmdhd/aiutils.c
drivers/net/wireless/bcmdhd/bcmevent.c
drivers/net/wireless/bcmdhd/bcmsdh_linux.c
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
drivers/net/wireless/bcmdhd/bcmspibrcm.c
drivers/net/wireless/bcmdhd/bcmutils.c
drivers/net/wireless/bcmdhd/dhd.h
drivers/net/wireless/bcmdhd/dhd_cdc.c
drivers/net/wireless/bcmdhd/dhd_cfg80211.c
drivers/net/wireless/bcmdhd/dhd_common.c
drivers/net/wireless/bcmdhd/dhd_linux.c
drivers/net/wireless/bcmdhd/dhd_linux.h
drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
drivers/net/wireless/bcmdhd/dhd_pcie.c
drivers/net/wireless/bcmdhd/dhd_pno.c
drivers/net/wireless/bcmdhd/dhd_sdio.c
drivers/net/wireless/bcmdhd/dhd_wlfc.c
drivers/net/wireless/bcmdhd/include/bcmsdh.h
drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h
drivers/net/wireless/bcmdhd/include/epivers.h
drivers/net/wireless/bcmdhd/include/linux_osl.h
drivers/net/wireless/bcmdhd/include/linuxver.h
drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
drivers/net/wireless/bcmdhd/include/sbchipc.h
drivers/net/wireless/bcmdhd/include/sdio.h
drivers/net/wireless/bcmdhd/include/siutils.h
drivers/net/wireless/bcmdhd/include/wlioctl.h
drivers/net/wireless/bcmdhd/linux_osl.c
drivers/net/wireless/bcmdhd/sbutils.c
drivers/net/wireless/bcmdhd/siutils.c
drivers/net/wireless/bcmdhd/wl_android.c
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/wldev_common.c

index 7234910..acc85e2 100644 (file)
@@ -8,7 +8,7 @@ config BCMDHD
          unsure.
 
 config BCMDHD_SDIO
-       tristate "SDIO bus interface support"
+       bool "SDIO bus interface support"
        depends on BCMDHD && MMC
 
 config BCMDHD_PCIE
index 6404f65..03c8618 100644 (file)
@@ -10,8 +10,7 @@ DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER            \
        -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT                             \
        -DEMBEDDED_PLATFORM -DPNO_SUPPORT                                     \
        -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT                           \
-       -DCUSTOMER_HW2 -DGET_CUSTOM_MAC_ENABLE  \
-       -DCONFIG_DTS -DCUSTOMER_IMX
+       -DCUSTOMER_HW2 -DGET_CUSTOM_MAC_ENABLE
 
 #################
 # Common feature
@@ -20,8 +19,6 @@ DHDCFLAGS += -DWL_CFG80211
 # Print out kernel panic point of file and line info when assertion happened
 DHDCFLAGS += -DBCMASSERT_LOG
 
-DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
-
 # keepalive
 DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
 
@@ -82,21 +79,40 @@ DHDCFLAGS += -DCONFIG_CONTROL_PM
 # idle count
 DHDCFLAGS += -DDHD_USE_IDLECOUNT
 
-# SKB TAILPAD to avoid out of boundary memory access
-DHDCFLAGS += -DDHDENABLE_TAILPAD
-
 # Wi-Fi Direct
 DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
 DHDCFLAGS += -DWL_CFG80211_STA_EVENT
 DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
 # DHDCFLAGS += -DWL_ENABLE_P2P_IF
 
+# For APSTA virtual interface
+DHDCFLAGS += -DWL_VIRTUAL_APSTA
+
+##########################
+# platform type
+# imx: NXP iMX platform
+##########################
+DHDPLATFORM ?= imx
+ifeq ($(DHDPLATFORM), imx)
+  DHDCFLAGS += -DCONFIG_DTS -DCUSTOMER_IMX
+else
+  # XXX Disable for NXP-iMX platforms 
+  # SKB TAILPAD to avoid out of boundary memory access
+  DHDCFLAGS += -DDHDENABLE_TAILPAD
+endif
+
 ##########################
 # driver type
 # m: module type driver
 # y: built-in type driver
 ##########################
-#DRIVER_TYPE ?= y
+DRIVER_TYPE ?= y
+
+ifeq ($(DRIVER_TYPE), y)
+  DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
+else
+  DHDCFLAGS += -DNO_SDIO_RESET
+endif
 
 #########################
 # Chip dependent feature
@@ -105,9 +121,9 @@ ifneq ($(CONFIG_BCM4354),)
   DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB
 
 # tput enhancement
-  DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
+  DHDTXGLOM ?= y
+  MAX_TXGLOM ?= 40
   DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
-  DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED
   DHDCFLAGS += -DDHDTCPACK_SUPPRESS
   DHDCFLAGS += -DUSE_WL_TXBF
   DHDCFLAGS += -DUSE_WL_FRAMEBURST
@@ -115,8 +131,7 @@ ifneq ($(CONFIG_BCM4354),)
   DHDCFLAGS += -DREPEAT_READFRAME
   DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
   DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
-  DHDCFLAGS += -DPROP_TXSTATUS_VSDB
-  DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40
+#  DHDCFLAGS += -DPROP_TXSTATUS_VSDB
   DHDCFLAGS += -DMAX_HDR_READ=128
   DHDCFLAGS += -DDHD_FIRSTREAD=128
   DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16
@@ -132,11 +147,8 @@ ifneq ($(CONFIG_BCM4339),)
   DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB
 
   # tput enhancement
-  DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
-  DHDCFLAGS += -DCUSTOM_RXCHAIN=1
-
+  DHDTXGLOM ?= y
   DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
-  DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED
   DHDCFLAGS += -DDHDTCPACK_SUPPRESS
   DHDCFLAGS += -DUSE_WL_TXBF
   DHDCFLAGS += -DUSE_WL_FRAMEBURST
@@ -144,7 +156,6 @@ ifneq ($(CONFIG_BCM4339),)
   DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
   DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
 #  DHDCFLAGS += -DPROP_TXSTATUS_VSDB
-   DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32
 
   # New Features
   DHDCFLAGS += -DWL11U
@@ -152,6 +163,19 @@ ifneq ($(CONFIG_BCM4339),)
   DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30
 endif
 
+##########################
+# SDIO TX glomming
+# y: enable
+# n: disable
+##########################
+DHDTXGLOM ?= n
+ifeq ($(DHDTXGLOM), y)
+  MAX_TXGLOM ?= 32
+  DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
+  DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED
+  DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=$(MAX_TXGLOM)
+endif
+
 # Murata: need the following define to handle BCM43340 edge interrupt (vs level interrupt on other chipsets).
 # Define is in imx_v7_defconfig.
 ifeq ($(CONFIG_BCM43340),)
@@ -167,10 +191,8 @@ ifneq ($(CONFIG_BCMDHD_PCIE),)
   DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1
 endif
 
-# Murata: Un-comment next line for Optimization
 #EXTRA_LDFLAGS += --strip-debug
 
-# Murata: swap these lines depending on optimization -- comment debug flag to make code execution faster.
 EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG
 EXTRA_CFLAGS += -DSRCBASE=\"$(src)\"
 EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/
@@ -192,7 +214,7 @@ ifneq ($(CONFIG_BCMDHD_PCIE),)
 endif
 
 bcmdhd-objs := $(DHDOFILES)
-obj-$(CONFIG_BCMDHD_SDIO)   += bcmdhd.o
+obj-$(DRIVER_TYPE)   += bcmdhd.o
 
 all:
        @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules"
index 085dc97..85c034b 100644 (file)
@@ -152,12 +152,10 @@ ai_scan(si_t *sih, void *regs, uint devid)
                eromptr = regs;
                break;
 
-#ifdef BCMSDIO
        case SPI_BUS:
        case SDIO_BUS:
                eromptr = (uint32 *)(uintptr)erombase;
                break;
-#endif /* BCMSDIO */
 
        case PCMCIA_BUS:
        default:
@@ -396,13 +394,11 @@ ai_setcoreidx(si_t *sih, uint coreidx)
                        OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap);
                break;
 
-#ifdef BCMSDIO
        case SPI_BUS:
        case SDIO_BUS:
                sii->curmap = regs = (void *)((uintptr)addr);
                sii->curwrap = (void *)((uintptr)wrap);
                break;
-#endif /* BCMSDIO */
 
        case PCMCIA_BUS:
        default:
index b2d1c24..d1f8abe 100644 (file)
  *      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: bcmevent.c 487870 2014-06-27 07:37:35Z $
+ * $Id: bcmevent.c 662961 2016-11-24 01:22:35Z $
  */
 
 #include <typedefs.h>
 #include <bcmutils.h>
+#include <bcmendian.h>
 #include <proto/ethernet.h>
 #include <proto/bcmeth.h>
 #include <proto/bcmevent.h>
+#include <proto/802.11.h>
+
+#if WLC_E_LAST != 165
+#error "You need to add an entry to bcmevent_names[] for the new event"
+#endif
 
 /* Use the actual name for event tracing */
 #define BCMEVENT_NAME(_event) {(_event), #_event}
@@ -146,6 +152,91 @@ const bcmevent_name_t bcmevent_names[] = {
 #endif
        BCMEVENT_NAME(WLC_E_TXFAIL_THRESH),
        BCMEVENT_NAME(WLC_E_RMC_EVENT),
+       BCMEVENT_NAME(WLC_E_PKT_FILTER),
 };
 
 const int bcmevent_names_size = ARRAYSIZE(bcmevent_names);
+
+/*
+ * Validate if the event is proper and if valid copy event header to event.
+ * If proper event pointer is passed, to just validate, pass NULL to event.
+ *
+ * Return values are
+ *     BCME_OK - It is a BRCM event or BRCM dongle event
+ *     BCME_NOTFOUND - Not BRCM, not an event, may be okay
+ *     BCME_BADLEN - Bad length, should not process, just drop
+ */
+int
+is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
+               wl_event_msg_t *out_event)
+{
+       uint16 len;
+       uint16 subtype;
+       uint16 usr_subtype;
+       bcm_event_t *bcm_event;
+       uint8 *pktend;
+       int err = BCME_OK;
+
+       pktend = (uint8 *)pktdata + pktlen;
+       bcm_event = (bcm_event_t *)pktdata;
+
+       /* only care about 16-bit subtype / length versions */
+       if ((uint8 *)&bcm_event->bcm_hdr < pktend) {
+               uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr;
+               if (!(short_subtype & 0x80)) {
+                       err = BCME_NOTFOUND;
+                       goto done;
+               }
+       }
+
+       /* must have both ether_header and bcmeth_hdr */
+       if (pktlen < OFFSETOF(bcm_event_t, event)) {
+               err = BCME_BADLEN;
+               goto done;
+       }
+
+       /* check length in bcmeth_hdr */
+       len = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
+
+       /* match on subtype, oui and usr subtype for BRCM events */
+       subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype);
+       if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) {
+               err = BCME_NOTFOUND;
+               goto done;
+       }
+
+       if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
+               err = BCME_NOTFOUND;
+               goto done;
+       }
+
+       /* if it is a bcm_event or bcm_dngl_event_t, validate it */
+       usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype);
+       if (usr_subtype == BCMILCP_BCM_SUBTYPE_EVENT) {
+               if (pktlen < sizeof(bcm_event_t)) {
+                       err = BCME_BADLEN;
+                       goto done;
+               }
+               len = (uint16)sizeof(bcm_event_t) +
+                       (uint16)ntoh32_ua((void *)&bcm_event->event.datalen);
+               if ((uint8 *)pktdata + len > pktend) {
+                       err = BCME_BADLEN;
+                       goto done;
+               }
+               if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) {
+                       err = BCME_NOTFOUND;
+                       goto done;
+               }
+               if (out_event) {
+                       /* ensure BRCM event pkt aligned */
+                       memcpy(out_event, &bcm_event->event, sizeof(wl_event_msg_t));
+               }
+       }
+       else {
+               err = BCME_NOTFOUND;
+               goto done;
+       }
+
+done:
+       return err;
+}
index 3eb4a48..87c00c2 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 634247 2016-04-27 05:53:55Z $
+ * $Id: bcmsdh_linux.c 662739 2016-11-08 09:20:31Z $
  */
 
 /**
@@ -84,10 +84,6 @@ typedef struct bcmsdh_os_info {
 /* debugging macros */
 #define SDLX_MSG(x)
 
-#if defined(OOB_PARAM)
-extern uint dhd_oob_disable;
-#endif /* OOB_PARAM */
-
 /**
  * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
  */
@@ -145,6 +141,9 @@ void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint
        bcmsdh_info_t *bcmsdh;
        uint32 vendevid;
        bcmsdh_os_info_t *bcmsdh_osinfo = NULL;
+#ifdef OOB_PARAM
+       wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)adapter_info;
+#endif /* OOB_PARAM */
 
        bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
        if (bcmsdh == NULL) {
@@ -168,7 +167,7 @@ void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint
 #endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
 
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(adapter->oob_disable)) {
                spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock);
                /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
                bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
index edaf1cf..bf94aaa 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 643045 2016-06-13 06:02:06Z $
+ * $Id: bcmsdh_sdmmc.c 662739 2016-11-08 09:20:31Z $
  */
 #include <typedefs.h>
 
@@ -54,15 +54,24 @@ extern int sdio_function_init(void);
 extern void sdio_function_cleanup(void);
 #endif /* BCMSDH_MODULE */
 
-#if defined(OOB_PARAM)
-extern uint dhd_oob_disable;
-#endif /* OOB_PARAM */
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
 static void IRQHandler(struct sdio_func *func);
 static void IRQHandlerF2(struct sdio_func *func);
 #endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
+
+#ifdef OOB_PARAM
+extern int sdioh_get_oob_disable(sdioh_info_t *sd);
+#endif /* OOB_PRARM */
+
+#if defined(NO_SDIO_RESET)
+static int sdio_reset_comm(struct mmc_card *card)
+{
+       return 0;
+}
+#else
 extern int sdio_reset_comm(struct mmc_card *card);
+#endif /* NO_SDIO_RESET */
 
 #define DEFAULT_SDIO_F2_BLKSIZE                512
 #ifndef CUSTOM_SDIO_F2_BLKSIZE
@@ -306,7 +315,7 @@ sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
                return SDIOH_API_RC_FAIL;
        }
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
-       OOB_PARAM_IF(dhd_oob_disable) {
+       OOB_PARAM_IF(dhd_get_oob_disable(argh)) {
                sd->intr_handler = fn;
                sd->intr_handler_arg = argh;
                sd->intr_handler_valid = TRUE;
@@ -340,7 +349,7 @@ sdioh_interrupt_deregister(sdioh_info_t *sd)
        sd_trace(("%s: Entering\n", __FUNCTION__));
 
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
-       OOB_PARAM_IF(dhd_oob_disable) {
+       OOB_PARAM_IF(sd->intr_handler_valid) {
                if (sd->func[1]) {
                        /* register and unmask irq */
                        sdio_claim_host(sd->func[1]);
@@ -1391,7 +1400,7 @@ sdioh_start(sdioh_info_t *sd, int stage)
                        }
                } else {
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
-                       OOB_PARAM_IF(dhd_oob_disable) {
+                       OOB_PARAM_IF(sdioh_get_oob_disable(sd)) {
                                sdio_claim_host(sd->func[0]);
                                if (sd->func[2])
                                        sdio_claim_irq(sd->func[2], IRQHandlerF2);
@@ -1407,7 +1416,7 @@ sdioh_start(sdioh_info_t *sd, int stage)
 #endif /* defined(HW_OOB) */
                                bcmsdh_oob_intr_set(sd->bcmsdh, TRUE);
                        }
-#endif /* !defined(OOB_INTR_ONLY) */
+#endif /* defined(OOB_INTR_ONLY) */
                }
        }
        else
@@ -1427,7 +1436,7 @@ sdioh_stop(sdioh_info_t *sd)
        */
        if (sd->func[0]) {
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
-               OOB_PARAM_IF(dhd_oob_disable) {
+               OOB_PARAM_IF(sdioh_get_oob_disable(sd)) {
                        sdio_claim_host(sd->func[0]);
                        if (sd->func[1])
                                sdio_release_irq(sd->func[1]);
index 03bb701..f4af5d7 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_linux.c 634247 2016-04-27 05:53:55Z $
+ * $Id: bcmsdh_sdmmc_linux.c 662758 2016-11-10 08:03:26Z $
  */
 
 #include <typedefs.h>
@@ -96,10 +96,6 @@ MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
 
 extern volatile bool dhd_mmc_suspend;
 
-#if defined(OOB_PARAM)
-extern uint dhd_oob_disable;
-#endif /* OOB_PARAM */
-
 static int sdioh_probe(struct sdio_func *func)
 {
        int host_idx = func->card->host->index;
@@ -220,6 +216,20 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
 
 MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
 
+#ifdef OOB_PARAM
+uint
+sdioh_get_oob_disable(sdioh_info_t *sd)
+{
+       int host_idx = sd->func[0]->card->host->index;
+       uint32 rca = sd->func[0]->card->rca;
+       wifi_adapter_info_t *adapter;
+
+       adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca);
+
+       return adapter->oob_disable;
+}
+#endif /* OOB_PARAM */
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
 static int bcmsdh_sdmmc_suspend(struct device *pdev)
 {
@@ -255,7 +265,7 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev)
                return err;
        }
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(sdioh_get_oob_disable(sdioh))) {
                bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE);
        }
 #endif 
@@ -275,11 +285,7 @@ static int bcmsdh_sdmmc_resume(struct device *pdev)
 
        sdioh = sdio_get_drvdata(func);
        dhd_mmc_suspend = FALSE;
-#if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
-               bcmsdh_resume(sdioh->bcmsdh);
-       }
-#endif 
+       bcmsdh_resume(sdioh->bcmsdh);
 
        smp_mb();
        return 0;
index c286a2b..c3ba9d8 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: bcmspibrcm.c 634247 2016-04-27 05:53:55Z $
+ * $Id: bcmspibrcm.c 662541 2016-10-28 03:22:57Z $
  */
 
 #define HSMODE
@@ -200,7 +200,7 @@ sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
 {
        sd_trace(("%s: Entering\n", __FUNCTION__));
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
-       OOB_PARAM_IF(dhd_oob_disable) {
+       OOB_PARAM_IF(dhd_get_oob_disable(argh)) {
                sd->intr_handler = fn;
                sd->intr_handler_arg = argh;
                sd->intr_handler_valid = TRUE;
@@ -214,7 +214,7 @@ sdioh_interrupt_deregister(sdioh_info_t *sd)
 {
        sd_trace(("%s: Entering\n", __FUNCTION__));
 #if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
-       OOB_PARAM_IF(dhd_oob_disable) {
+       OOB_PARAM_IF(sd->intr_handler_valid) {
                sd->intr_handler_valid = FALSE;
                sd->intr_handler = NULL;
                sd->intr_handler_arg = NULL;
index 13a4a93..1d5c6a0 100644 (file)
@@ -20,7 +20,7 @@
  *      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: bcmutils.c 599648 2015-11-16 09:33:00Z $
+ * $Id: bcmutils.c 658506 2016-09-08 06:44:19Z $
  */
 
 #include <bcm_cfg.h>
@@ -266,12 +266,11 @@ pktq_penq(struct pktq *pq, int prec, void *p)
        struct pktq_prec *q;
 
        ASSERT(prec >= 0 && prec < pq->num_prec);
-       /* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */
-       ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p)));
+       ASSERT(PKTLINK(p) == NULL);             /* queueing chains not allowed */
+
 
        ASSERT(!pktq_full(pq));
        ASSERT(!pktq_pfull(pq, prec));
-
        q = &pq->q[prec];
 
        if (q->head)
@@ -296,12 +295,11 @@ pktq_penq_head(struct pktq *pq, int prec, void *p)
        struct pktq_prec *q;
 
        ASSERT(prec >= 0 && prec < pq->num_prec);
-       /* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */
-       ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p)));
+       ASSERT(PKTLINK(p) == NULL);             /* queueing chains not allowed */
+
 
        ASSERT(!pktq_full(pq));
        ASSERT(!pktq_pfull(pq, prec));
-
        q = &pq->q[prec];
 
        if (q->head == NULL)
index fab855c..cb327a6 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 634247 2016-04-27 05:53:55Z $
+ * $Id: dhd.h 662786 2016-11-11 09:06:37Z $
  */
 
 /****************
@@ -348,6 +348,9 @@ typedef struct dhd_pub {
        struct task_struct * current_rxf;
        int chan_isvht80;
 #endif /* CUSTOM_SET_CPUCORE */
+#ifdef OOB_PARAM
+       uint    oob_disable;
+#endif /* OOB_PARAM */
 } dhd_pub_t;
 
 
@@ -637,6 +640,7 @@ extern int net_os_send_hang_message(struct net_device *dev);
 extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, uint16 pktlen,
                wl_event_msg_t *, void **data_ptr, void *raw_event);
 extern void wl_event_to_host_order(wl_event_msg_t * evt);
+extern int wl_host_event_get_data(void *pktdata, uint pktlen, wl_event_msg_t *evt);
 
 extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len);
 extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set,
@@ -649,11 +653,11 @@ extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifeven
 extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent,
        char *name, uint8 *mac);
 extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
-       uint8 *mac, uint8 bssidx, bool need_rtnl_lock);
+       uint8 *mac, uint8 bssidx, bool need_rtnl_lock, char *dngl_name);
 extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock);
 extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name);
 extern void dhd_vif_del(struct dhd_info *dhd, int ifidx);
-extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx);
+extern void dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx);
 extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len);
 
 /* Send packet to dongle via data channel */
@@ -673,12 +677,10 @@ extern int dhd_bus_suspend(dhd_pub_t *dhdpub);
 extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage);
 extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size);
 extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
-extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval);
-#if defined(BCMSDIO)
+extern bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval);
 extern uint dhd_bus_chip_id(dhd_pub_t *dhdp);
 extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp);
 extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp);
-#endif /* defined(BCMSDIO) */
 
 #if defined(KEEP_ALIVE)
 extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
@@ -922,4 +924,8 @@ void dhd_os_prefree(dhd_pub_t *dhdpub, int section, void *addr, uint size);
 #endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
 
 
+#ifdef OOB_PARAM
+extern uint dhd_get_oob_disable(struct dhd_bus* bus);
+#endif /* OOB_PARAM */
+
 #endif /* _dhd_h_ */
index 4e1bb8e..c776089 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 557252 2015-05-18 08:55:13Z $
+ * $Id: dhd_cdc.c 657232 2016-08-31 11:02:44Z $
  *
  * 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
@@ -340,6 +340,9 @@ dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
 void
 dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
 {
+       if (!dhdp || !dhdp->prot)
+               return;
+
        bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
 #ifdef PROP_TXSTATUS
        dhd_wlfc_dump(dhdp, strbuf);
index 8d47b21..17e6866 100644 (file)
@@ -111,9 +111,9 @@ s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg)
 }
 
 struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name,
-       uint8 *mac, uint8 bssidx)
+       uint8 *mac, uint8 bssidx, char *dngl_name)
 {
-       return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE);
+       return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name);
 }
 
 int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev)
index 83e2741..c45b1e1 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 643093 2016-06-13 08:43:46Z $
+ * $Id: dhd_common.c 662961 2016-11-24 01:22:35Z $
  */
 #include <typedefs.h>
 #include <osl.h>
@@ -220,6 +220,8 @@ dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
 
        struct bcmstrbuf b;
        struct bcmstrbuf *strbuf = &b;
+       if (!dhdp || !dhdp->prot || !buf)
+               return BCME_ERROR;
 
        bcm_binit(strbuf, buf, buflen);
 
@@ -540,9 +542,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
 #ifdef BCMDHDUSB
                int_val = BUS_TYPE_USB;
 #endif
-#ifdef BCMSDIO
                int_val = BUS_TYPE_SDIO;
-#endif
 #ifdef PCIE_FULL_DONGLE
                int_val = BUS_TYPE_PCIE;
 #endif
@@ -1411,7 +1411,6 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
                DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
                break;
 
-
        case WLC_E_CCA_CHAN_QUAL:
                if (datalen) {
                        buf = (uchar *) event_data;
@@ -1420,7 +1419,12 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
                                (int)reason, (int)auth_type, *(buf + 4)));
                }
                break;
-
+       case WLC_E_PKT_FILTER:
+               if (status == WLC_E_PKT_FILTER_TIMEOUT)
+                       DHD_EVENT(("MACEVENT: %s, Timeout(Pkt Filter Id=%d)\n", event_name, reason));
+               else
+                       DHD_EVENT(("MACEVENT: %s, status %d reason %d\n", event_name, status, reason));
+               break;
 
        default:
                DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
@@ -1440,6 +1444,21 @@ wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
 }
 #endif /* SHOW_EVENTS */
 
+/* Check whether packet is a BRCM event pkt. If it is, record event data. */
+int
+wl_host_event_get_data(void *pktdata, uint pktlen, wl_event_msg_t *evt)
+{
+       int ret;
+
+       ret = is_wlc_event_frame(pktdata, pktlen, 0, evt);
+       if (ret != BCME_OK) {
+               DHD_ERROR(("%s: Invalid event frame, err = %d\n",
+                       __FUNCTION__, ret));
+       }
+
+       return ret;
+}
+
 int
 wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint16 pktlen,
               wl_event_msg_t *event, void **data_ptr, void *raw_event)
@@ -1449,21 +1468,12 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint16 pktlen,
        uint8 *event_data;
        uint32 type, status, datalen;
        uint16 flags;
-       int evlen;
-
-       if (pktlen < sizeof(bcm_event_t))
-               return (BCME_ERROR);
+       uint evlen;
+       int ret;
 
-       if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
-               DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
-               return (BCME_ERROR);
-       }
-
-       /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
-       if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT ||
-               ntoh16_ua((void *)&pvt_data->bcm_hdr.subtype) != BCMILCP_SUBTYPE_VENDOR_LONG) {
-               DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
-               return (BCME_ERROR);
+       ret = wl_host_event_get_data(pktdata, pktlen, event);
+       if (ret != BCME_OK) {
+               return ret;
        }
 
        *data_ptr = &pvt_data[1];
@@ -2230,7 +2240,7 @@ dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
 /*
  * returns = TRUE if associated, FALSE if not associated
  */
-bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
+bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval)
 {
        char bssid[6], zbuf[6];
        int ret = -1;
@@ -2238,7 +2248,8 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
        bzero(bssid, 6);
        bzero(zbuf, 6);
 
-       ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
+       ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid,
+               ETHER_ADDR_LEN, FALSE, ifidx);
        DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
 
        if (ret == BCME_NOTASSOCIATED) {
@@ -2251,18 +2262,11 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
        if (ret < 0)
                return FALSE;
 
-       if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
-               /*  STA is assocoated BSSID is non zero */
-
-               if (bss_buf) {
-                       /* return bss if caller provided buf */
-                       memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
-               }
-               return TRUE;
-       } else {
+       if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) == 0)) {
                DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
                return FALSE;
        }
+       return TRUE;
 }
 
 
@@ -2276,7 +2280,7 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
        int ap_beacon = 0;
        int allowed_skip_dtim_cnt = 0;
        /* Check if associated */
-       if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
+       if (dhd_is_associated(dhd, 0, NULL) == FALSE) {
                DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
                goto exit;
        }
index 55ae538..caaa548 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 634247 2016-04-27 05:53:55Z $
+ * $Id: dhd_linux.c 663029 2016-11-30 03:37:26Z $
  */
 
 #include <typedefs.h>
@@ -177,11 +177,6 @@ volatile bool dhd_mmc_suspend = FALSE;
 DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
 
-#if defined(OOB_PARAM)
-uint dhd_oob_disable = FALSE;
-module_param(dhd_oob_disable, uint, 0);
-#endif /* OOB_PARAM */
-
 #if defined(OOB_INTR_ONLY)
 extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
 #endif 
@@ -282,6 +277,7 @@ typedef struct dhd_if {
        bool                    attached;               /* Delayed attachment when unset */
        bool                    txflowcontrol;  /* Per interface flow control indicator */
        char                    name[IFNAMSIZ+1]; /* linux interface name */
+       char                    dngl_name[IFNAMSIZ+1]; /* corresponding dongle interface name */
        uint8                   bssidx;                 /* bsscfg index for the interface */
        bool                    set_macaddress;
        bool                    set_multicast;
@@ -566,7 +562,6 @@ module_param(dhd_intr, uint, 0);
 uint dhd_sdiod_drive_strength = 6;
 module_param(dhd_sdiod_drive_strength, uint, 0);
 
-#ifdef BCMSDIO
 /* Tx/Rx bounds */
 extern uint dhd_txbound;
 extern uint dhd_rxbound;
@@ -582,7 +577,6 @@ extern void dhd_dbg_init(dhd_pub_t *dhdp);
 extern void dhd_dbg_remove(void);
 #endif /* BCMDBGFS */
 
-#endif /* BCMSDIO */
 
 
 #ifdef SDTEST
@@ -1154,7 +1148,7 @@ dhd_ifname2idx(dhd_info_t *dhd, char *name)
                return 0;
 
        while (--i > 0)
-               if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
+               if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->dngl_name, name, IFNAMSIZ))
                                break;
 
        DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
@@ -1216,7 +1210,10 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
        uint buflen;
        int ret;
 
-                       ASSERT(dhd && dhd->iflist[ifidx]);
+                       if (!dhd->iflist[ifidx]) {
+                               DHD_ERROR(("%s : dhd->iflist[%d] was NULL\n", __FUNCTION__, ifidx));
+                               return;
+                       }
                        dev = dhd->iflist[ifidx]->net;
                        if (!dev)
                                return;
@@ -1438,7 +1435,7 @@ dhd_ifadd_event_handler(void *handle, void *event_info, u8 event)
        DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
 
        ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name,
-               if_event->mac, bssidx, TRUE);
+               if_event->mac, bssidx, TRUE, if_event->name);
        if (!ndev) {
                DHD_ERROR(("%s: net device alloc failed  \n", __FUNCTION__));
                goto done;
@@ -1564,8 +1561,8 @@ static void
 dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
 {
        dhd_info_t *dhd = handle;
-       dhd_if_t *ifp = event_info;
-       int ifidx;
+       int ifidx = (int)((long int)event_info);
+       dhd_if_t *ifp = NULL;
 
 #ifdef SOFTAP
        bool in_ap = FALSE;
@@ -1583,6 +1580,7 @@ dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
        }
 
 #ifdef SOFTAP
+       ifp = dhd->iflist[ifidx];
        flags = dhd_os_spin_lock(&dhd->pub);
        in_ap = (ap_net_dev != NULL);
        dhd_os_spin_unlock(&dhd->pub, flags);
@@ -1598,6 +1596,9 @@ dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event)
        dhd_net_if_lock_local(dhd);
        DHD_OS_WAKE_LOCK(&dhd->pub);
 
+       /* Be sure to make corresponding (dhd_if_t*) pointer after lock() */
+       ifp = dhd->iflist[ifidx];
+
        if (ifp == NULL || !dhd->pub.up) {
                DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
                goto done;
@@ -1650,7 +1651,7 @@ dhd_set_multicast_list(struct net_device *dev)
                return;
 
        dhd->iflist[ifidx]->set_multicast = TRUE;
-       dhd_deferred_schedule_work((void *)dhd->iflist[ifidx], DHD_WQ_WORK_SET_MCAST_LIST,
+       dhd_deferred_schedule_work((void *)((long int)ifidx), DHD_WQ_WORK_SET_MCAST_LIST,
                dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
 }
 
@@ -2108,7 +2109,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 #else
                        skb->mac.raw,
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */
-                       len - ETHER_TYPE_LEN,
+                       len > ETHER_TYPE_LEN ? len - ETHER_TYPE_LEN : 0,
                        &event,
                        &data);
 
@@ -2186,7 +2187,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
 }
 
 void
-dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
+dhd_event(struct dhd_info *dhd, char *evpkt, uint evlen, int ifidx)
 {
        /* Linux version has nothing to do */
        return;
@@ -3475,7 +3476,7 @@ dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, ui
  */
 struct net_device*
 dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
-       uint8 *mac, uint8 bssidx, bool need_rtnl_lock)
+       uint8 *mac, uint8 bssidx, bool need_rtnl_lock, char *dngl_name)
 {
        dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info;
        dhd_if_t *ifp;
@@ -3538,6 +3539,13 @@ dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
        strncpy(ifp->name, ifp->net->name, IFNAMSIZ);
        ifp->name[IFNAMSIZ - 1] = '\0';
        dhdinfo->iflist[ifidx] = ifp;
+
+/* initialize the dongle provided if name */
+       if (dngl_name)
+               strncpy(ifp->dngl_name, dngl_name, IFNAMSIZ);
+       else
+               strncpy(ifp->dngl_name, name, IFNAMSIZ);
+
        return ifp->net;
 
 fail:
@@ -4023,9 +4031,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        DHD_TRACE(("%s: Enter\n", __FUNCTION__));
 
        /* will implement get_ids for DBUS later */
-#if defined(BCMSDIO)
        dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
-#endif 
        adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
 
        /* Allocate primary dhd_info */
@@ -4043,6 +4049,10 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        dhd->pub.osh = osh;
        dhd->adapter = adapter;
 
+#ifdef OOB_PARAM
+       dhd->pub.oob_disable = adapter->oob_disable;
+#endif /* OOB_PARAM */
+
 #ifdef GET_CUSTOM_MAC_ENABLE
        wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
 #endif /* GET_CUSTOM_MAC_ENABLE */
@@ -4085,7 +4095,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
                if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
                        strcat(if_name, "%d");
        }
-       net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE);
+       net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE, NULL);
        if (net == NULL)
                goto fail;
        dhd_state |= DHD_ATTACH_STATE_ADD_IF;
@@ -4186,6 +4196,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        if (dhd_watchdog_prio >= 0) {
                /* Initialize watchdog thread */
                PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread");
+               if (dhd->thr_wdt_ctl.thr_pid < 0) {
+                       goto fail;
+               }
 
        } else {
                dhd->thr_wdt_ctl.thr_pid = -1;
@@ -4199,6 +4212,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        if (dhd_dpc_prio >= 0) {
                /* Initialize DPC thread */
                PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc");
+               if (dhd->thr_dpc_ctl.thr_pid < 0) {
+                       goto fail;
+               }
        } else {
                /*  use tasklet for dpc */
                tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
@@ -4209,6 +4225,9 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
                bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND);
                /* Initialize RXF thread */
                PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf");
+               if (dhd->thr_rxf_ctl.thr_pid < 0) {
+                       goto fail;
+               }
        }
 
        dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
@@ -4261,11 +4280,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
        cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER);
 #endif
 #ifdef DHDTCPACK_SUPPRESS
-#ifdef BCMSDIO
        dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX);
-#else
-       dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
-#endif /* BCMSDIO */
 #endif /* DHDTCPACK_SUPPRESS */
 #ifdef DHD_DEBUG
        dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT;
@@ -4427,7 +4442,7 @@ dhd_bus_start(dhd_pub_t *dhdp)
                return ret;
        }
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(dhd->pub.oob_disable)) {
                /* Host registration for OOB interrupt */
                if (dhd_bus_oob_intr_register(dhdp)) {
                        /* deactivate timer and wait for the handler to finish */
@@ -4627,7 +4642,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        int ret = 0;
        char eventmask[WL_EVENTING_MASK_LEN];
        char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for "event_msgs" + '\0' + bitvec  */
+       uint8 msglen;
+       eventmsgs_ext_t *eventmask_msg;
+       char iov_buf[WLC_IOCTL_SMLEN];
        uint32 buf_key_b4_m4 = 1;
+       int ret2 = 0;
 #if defined(CUSTOM_AMPDU_BA_WSIZE)
        uint32 ampdu_ba_wsize = 0;
 #endif 
@@ -4635,24 +4654,19 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        uint32 ampdu_mpdu = 0;
 #endif
 
-#if defined(BCMSDIO)
 #ifdef PROP_TXSTATUS
        int wlfc_enable = TRUE;
 #ifndef DISABLE_11N
        uint32 hostreorder = 1;
-       int ret2 = 0;
 #endif /* DISABLE_11N */
 #endif /* PROP_TXSTATUS */
-#endif 
 
 #ifdef DHD_ENABLE_LPC
        uint32 lpc = 1;
 #endif /* DHD_ENABLE_LPC */
        uint power_mode = PM_FAST;
        uint32 dongle_align = DHD_SDALIGN;
-#if defined(BCMSDIO)
        uint32 glom = CUSTOM_GLOM_SETTING;
-#endif /* defined(BCMSDIO) */
 #if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
        uint32 credall = 1;
 #endif
@@ -4718,6 +4732,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #ifdef CUSTOM_PSPRETEND_THR
        uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
 #endif
+#ifdef DISABLE_AUTOCOUNTRY
+       uint32 autocountry = 0;
+#endif /* DISABLE_AUTOCOUNTRY */
+
 #ifdef PKT_FILTER_SUPPORT
        dhd_pkt_filter_enable = TRUE;
 #endif /* PKT_FILTER_SUPPORT */
@@ -4879,6 +4897,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
                        DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
        }
 
+#if defined(DISABLE_AUTOCOUNTRY)
+       /* disable setting country to AP's country */
+       bcm_mkiovar("autocountry", (char *)&autocountry, 4, iovbuf, sizeof(iovbuf));
+       if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+               DHD_ERROR(("%s disabling autocountry failed %d\n", __FUNCTION__, ret));
+#endif /* DISABLE_AUTOCOUNTRY */
+
 
        /* Set Listen Interval */
        bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
@@ -4955,13 +4980,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
        dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
 #endif
 
-#if defined(BCMSDIO)
        if (glom != DEFAULT_GLOM_VALUE) {
                DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
                bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
                dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
        }
-#endif /* defined(BCMSDIO) */
 
        /* Setup timeout if Beacons are lost and roam is off to report link down */
        bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
@@ -5135,6 +5158,47 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
                goto done;
        }
 
+    /* make up event mask ext message iovar for event larger than 128 */
+    msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE;
+    eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL);
+    if (eventmask_msg == NULL) {
+            DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen));
+            return BCME_NOMEM;
+    }
+    bzero(eventmask_msg, msglen);
+    eventmask_msg->ver = EVENTMSGS_VER;
+    eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
+
+    /* Read event_msgs_ext mask */
+    bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, sizeof(iov_buf));
+    ret2  = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, sizeof(iov_buf), FALSE, 0);
+    if (ret2 != BCME_UNSUPPORTED)
+            ret = ret2;
+    if (ret2 == 0) { /* event_msgs_ext must be supported */
+            bcopy(iov_buf, eventmask_msg, msglen);
+
+                       /* Enable required event mask */
+            setbit(eventmask_msg->mask, WLC_E_PKT_FILTER);
+
+            /* Write updated Event mask */
+            eventmask_msg->ver = EVENTMSGS_VER;
+            eventmask_msg->command = EVENTMSGS_SET_MASK;
+            eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
+            bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
+                    msglen, iov_buf, sizeof(iov_buf));
+            if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+                    iov_buf, sizeof(iov_buf), TRUE, 0)) < 0) {
+                    DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
+                    kfree(eventmask_msg);
+                    goto done;
+            }
+    } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
+            DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
+            kfree(eventmask_msg);
+            goto done;
+    } /* unsupported is ok */
+    kfree(eventmask_msg);
+
        dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
                sizeof(scan_assoc_time), TRUE, 0);
        dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
@@ -5196,16 +5260,11 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
                bcmstrtok(&ptr, "\n", 0);
                /* Print fw version info */
                DHD_ERROR(("Firmware version = %s\n", buf));
-#if defined(BCMSDIO)
                dhd_set_version_info(dhd, buf);
-#endif /* defined(BCMSDIO) */
        }
 
-#if defined(BCMSDIO)
        dhd_txglom_enable(dhd, TRUE);
-#endif /* defined(BCMSDIO) */
 
-#if defined(BCMSDIO)
 #ifdef PROP_TXSTATUS
        if (disable_proptx ||
 #ifdef PROP_TXSTATUS_VSDB
@@ -5251,7 +5310,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
 #endif /* DISABLE_11N */
 
 #endif /* PROP_TXSTATUS */
-#endif /* BCMSDIO || BCMBUS */
 #ifdef PNO_SUPPORT
        if (!dhd->pno_state) {
                dhd_pno_init(dhd);
@@ -5698,10 +5756,8 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
 #ifdef WL_CFG80211
                        wl_terminate_event_handler();
 #endif /* WL_CFG80211 */
-#ifdef BCMSDIO
                        dhd_net_bus_devreset(net, TRUE);
                        dhd_net_bus_suspend(net);
-#endif /* BCMSDIO */
                        wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY);
                }
        }
@@ -5741,7 +5797,7 @@ dhd_bus_detach(dhd_pub_t *dhdp)
                        }
 
 #if defined(OOB_INTR_ONLY)
-                       OOB_PARAM_IF(!dhd_oob_disable) {
+                       OOB_PARAM_IF(!(dhdp->oob_disable)) {
                                dhd_bus_oob_intr_unregister(dhdp);
                        }
 #endif 
@@ -6444,7 +6500,7 @@ dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len)
 
 void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
 {
-#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
        struct dhd_info *dhdinfo =  dhd->info;
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -6456,13 +6512,13 @@ void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
        dhd_os_sdunlock(dhd);
        wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout);
        dhd_os_sdlock(dhd);
-#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */
+#endif 
        return;
 }
 
 void dhd_wait_event_wakeup(dhd_pub_t *dhd)
 {
-#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
        struct dhd_info *dhdinfo =  dhd->info;
        if (waitqueue_active(&dhdinfo->ctrl_wait))
                wake_up(&dhdinfo->ctrl_wait);
@@ -6470,7 +6526,6 @@ void dhd_wait_event_wakeup(dhd_pub_t *dhd)
        return;
 }
 
-#ifdef BCMSDIO
 int
 dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
 {
@@ -6523,8 +6578,6 @@ dhd_net_bus_resume(struct net_device *dev, uint8 stage)
        return dhd_bus_resume(&dhdinfo->pub, stage);
 }
 
-#endif /* BCMSDIO */
-
 int net_os_set_suspend_disable(struct net_device *dev, int val)
 {
        dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
@@ -7173,7 +7226,7 @@ int dhd_os_wake_lock(dhd_pub_t *pub)
                if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
 #ifdef CONFIG_HAS_WAKELOCK
                        wake_lock(&dhd->wl_wifi);
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
                dhd_bus_dev_pm_stay_awake(pub);
 #endif
                }
@@ -7208,7 +7261,7 @@ int dhd_os_wake_unlock(dhd_pub_t *pub)
                        if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
 #ifdef CONFIG_HAS_WAKELOCK
                                wake_unlock(&dhd->wl_wifi);
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
                        dhd_bus_dev_pm_relax(pub);
 #endif
                        }
@@ -7221,8 +7274,7 @@ int dhd_os_wake_unlock(dhd_pub_t *pub)
 
 int dhd_os_check_wakelock(dhd_pub_t *pub)
 {
-#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \
-       KERNEL_VERSION(2, 6, 36)))
+#if defined(CONFIG_HAS_WAKELOCK) || (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
        dhd_info_t *dhd;
 
        if (!pub)
@@ -7235,7 +7287,7 @@ int dhd_os_check_wakelock(dhd_pub_t *pub)
        if (dhd && (wake_lock_active(&dhd->wl_wifi) ||
                (wake_lock_active(&dhd->wl_wdwake))))
                return 1;
-#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
        if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub))
                return 1;
 #endif
@@ -7359,7 +7411,6 @@ bool dhd_os_check_if_up(dhd_pub_t *pub)
        return pub->up;
 }
 
-#if defined(BCMSDIO)
 /* function to collect firmware, chip id and chip version info */
 void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
 {
@@ -7375,7 +7426,6 @@ void dhd_set_version_info(dhd_pub_t *dhdp, char *fw)
                "\n  Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
                dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
 }
-#endif /* defined(BCMSDIO) */
 int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
 {
        int ifidx;
@@ -7949,7 +7999,7 @@ void dhd_set_cpucore(dhd_pub_t *dhd, int set)
                } while (e_rxf < 0);
        }
 #ifdef DHD_OF_SUPPORT
-       interrupt_set_cpucore(set);
+       interrupt_set_cpucore(set, DPC_CPUCORE, PRIMARY_CPUCORE);
 #endif /* DHD_OF_SUPPORT */
        DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set));
 
index cb1766b..f5df9cb 100644 (file)
@@ -49,6 +49,9 @@ typedef struct wifi_adapter_info {
        uint            bus_type;
        uint            bus_num;
        uint            slot_num;
+#ifdef OOB_PARAM
+       uint            oob_disable;
+#endif /* OOB_PARAM */
 } wifi_adapter_info_t;
 
 typedef struct bcmdhd_wifi_platdata {
index f46c333..4720083 100644 (file)
@@ -70,10 +70,6 @@ struct wifi_platform_data {
 struct regulator *wifi_regulator = NULL;
 #endif /* CONFIG_DTS */
 
-#if defined(OOB_PARAM)
-extern uint dhd_oob_disable;
-#endif /* OOB_PARAM */
-
 bool cfg_multichip = FALSE;
 bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL;
 static int wifi_plat_dev_probe_ret = 0;
@@ -319,6 +315,10 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
                adapter->intr_flags = resource->flags;
        }
 
+#ifdef OOB_PARAM
+       adapter->oob_disable = FALSE;
+#endif /* OOB_PARAM */
+
 #ifdef CONFIG_DTS
        /* get firmware from dts */
        ret = of_property_read_string(pdev->dev.of_node, "bcmdhd_fw", &adapter->fw_path);
@@ -334,7 +334,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
                return -1;
        }
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(adapter->oob_disable)) {
                /* This is to get the irq for the OOB */
                gpio = of_get_gpio(pdev->dev.of_node, 0);
 
@@ -342,7 +342,7 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
                        DHD_ERROR(("%s no GPIO for OOB in device tree.\n", __FUNCTION__));
 #if defined(OOB_PARAM)
                        DHD_ERROR(("%s continue with non-OOB mode.\n", __FUNCTION__));
-                       dhd_oob_disable = TRUE;
+                       adapter->oob_disable = TRUE;
                        goto out;
 #else
                        return -1;
@@ -404,10 +404,14 @@ static int wifi_plat_dev_drv_remove(struct platform_device *pdev)
 
 static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state)
 {
+#ifdef OOB_PARAM
+       wifi_adapter_info_t *adapter;
+       adapter = &dhd_wifi_platdata->adapters[0];
+#endif /* OOB_PARAM */
+
        DHD_TRACE(("##> %s\n", __FUNCTION__));
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \
-       defined(BCMSDIO)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+       OOB_PARAM_IF(!(adapter->oob_disable)) {
                bcmsdh_oob_intr_set(0);
        }
 #endif /* (OOB_INTR_ONLY) */
@@ -416,10 +420,14 @@ static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t
 
 static int wifi_plat_dev_drv_resume(struct platform_device *pdev)
 {
+#ifdef OOB_PARAM
+       wifi_adapter_info_t *adapter;
+       adapter = &dhd_wifi_platdata->adapters[0];
+#endif /* OOB_PARAM */
+
        DHD_TRACE(("##> %s\n", __FUNCTION__));
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \
-       defined(BCMSDIO)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+       OOB_PARAM_IF(!(adapter->oob_disable)) {
                if (dhd_os_check_if_up(wl_cfg80211_get_dhdp()))
                        bcmsdh_oob_intr_set(1);
        }
@@ -672,7 +680,6 @@ extern uint dhd_deferred_tx;
 extern struct semaphore dhd_registration_sem;
 #endif 
 
-#ifdef BCMSDIO
 static int dhd_wifi_platform_load_sdio(void)
 {
        int i;
@@ -785,12 +792,6 @@ fail:
 
        return err;
 }
-#else /* BCMSDIO */
-static int dhd_wifi_platform_load_sdio(void)
-{
-       return 0;
-}
-#endif /* BCMSDIO */
 
 static int dhd_wifi_platform_load_usb(void)
 {
index 7ecb9e3..ca02e4e 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_pcie.c 475815 2014-05-07 00:27:31Z $
+ * $Id: dhd_pcie.c 662459 2016-10-24 04:35:43Z $
  */
 
 
@@ -407,7 +407,9 @@ dhdpcie_dongle_attach(dhd_bus_t *bus)
                        bus->dongle_ram_base = CR4_4360_RAM_BASE;
                        break;
                case BCM4345_CHIP_ID:
-                       bus->dongle_ram_base = CR4_4345_RAM_BASE;
+                       /* RAM base changed from 4345c0 (chiprev=6) onwards */
+                       bus->dongle_ram_base = (bus->sih->chiprev < 6)
+                               ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
                        break;
                case BCM43602_CHIP_ID:
                        bus->dongle_ram_base = CR4_43602_RAM_BASE;
index 353ec9f..e1d56e0 100644 (file)
@@ -162,7 +162,7 @@ _dhd_pno_enable(dhd_pub_t *dhd, int enable)
        }
        if (enable) {
                if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
-                       dhd_is_associated(dhd, NULL, NULL)) {
+                       dhd_is_associated(dhd, 0, NULL)) {
                        DHD_ERROR(("%s Legacy PNO mode cannot be enabled "
                                "in assoc mode , ignore it\n", __FUNCTION__));
                        err = BCME_BADOPTION;
index 55b7781..425fbba 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 634247 2016-04-27 05:53:55Z $
+ * $Id: dhd_sdio.c 663157 2016-12-08 12:19:27Z $
  */
 
 #include <typedefs.h>
@@ -294,7 +294,7 @@ typedef struct dhd_bus {
        bool            sleeping;               /* Is SDIO bus sleeping? */
 #if defined(SUPPORT_P2P_GO_PS)
        wait_queue_head_t bus_sleep;
-#endif /* LINUX && SUPPORT_P2P_GO_PS */
+#endif /* LINUX && (SUPPORT_P2P_GO_PS || !OEM_ANDROID) */
        uint            rxflow_mode;            /* Rx flow control mode */
        bool            rxflow;                 /* Is rx flow control on */
        uint            prev_rxlim_hit;         /* Is prev rx limit exceeded (per dpc schedule) */
@@ -384,10 +384,9 @@ typedef struct dhd_bus {
        bool            txglom_enable;  /* Flag to indicate whether tx glom is enabled/disabled */
        uint32          txglomsize;     /* Glom size limitation */
        void            *pad_pkt;
-#if defined(OOB_INTR_ONLY)
-       /* Murata -- fix for suspend/resume powersave issue on i.MX arch */
+#if defined(CUSTOMER_IMX)
        int             bus_wake_on_resume;
-#endif
+#endif /* CUSTOMER_IMX */
 } dhd_bus_t;
 
 /* clkstate */
@@ -425,10 +424,6 @@ uint dhd_dpcpoll = FALSE;
 module_param(dhd_doflow, uint, 0644);
 module_param(dhd_dpcpoll, uint, 0644);
 
-#if defined(OOB_PARAM)
-extern uint dhd_oob_disable;
-#endif /* OOB_PARAM */
-
 static bool dhd_alignctl;
 
 static bool sd1idle;
@@ -1194,7 +1189,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
                /* Go to pending and await interrupt if appropriate */
                if (1 &&
 #if defined(OOB_PARAM)
-                       dhd_oob_disable &&
+                       bus->dhd->oob_disable &&
 #endif /* OOB_PARAM */
                        !SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
                        /* Allow only clock-available interrupt */
@@ -1535,7 +1530,7 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
                bus->sleeping = TRUE;
 #if defined(SUPPORT_P2P_GO_PS)
                wake_up(&bus->bus_sleep);
-#endif /* LINUX && SUPPORT_P2P_GO_PS */
+#endif /* LINUX && (SUPPORT_P2P_GO_PS || !OEM_ANDROID) */
        } else {
                /* Waking up: bus power up is ok, set local state */
 
@@ -1921,10 +1916,6 @@ static int dhdsdio_txpkt_preprocess(dhd_bus_t *bus, void *pkt, int chan, int txs
                PKTALIGN(osh, tmp_pkt, PKTLEN(osh, pkt), DHD_SDALIGN);
                bcopy(PKTDATA(osh, pkt), PKTDATA(osh, tmp_pkt), PKTLEN(osh, pkt));
                *new_pkt = tmp_pkt;
-               /* pull back sdpcm_hdrlen length from old skb as new skb here
-                * is passed to postprocessing
-                */
-               PKTPULL(osh, pkt, sdpcm_hdrlen);
                pkt = tmp_pkt;
        }
 
@@ -2187,6 +2178,13 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
                num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map));
                for (i = 0; i < num_pkt; i++) {
                        pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out);
+                       if (!pkts[i]) {
+                               DHD_ERROR(("%s: pktg_mlen non-zero when no pkt\n",
+                                       __FUNCTION__));
+                               ASSERT(0);
+                               break;
+                       }
+                       PKTORPHAN(pkts[i]);
                        datalen += PKTLEN(osh, pkts[i]);
                }
                dhd_os_sdunlock_txq(bus->dhd);
@@ -6057,7 +6055,7 @@ clkwait:
                          __FUNCTION__, rxdone, framecnt));
                bus->intdis = FALSE;
 #if defined(OOB_INTR_ONLY)
-               OOB_PARAM_IF(!dhd_oob_disable) {
+               OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
                        bcmsdh_oob_intr_set(bus->sdh, TRUE);
                }
 #endif /* defined(OOB_INTR_ONLY) */
@@ -6065,7 +6063,7 @@ clkwait:
        }
 
 #if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
                /* In case of SW-OOB(using edge trigger),
                 * Check interrupt status in the dongle again after enable irq on the host.
                 * and rechedule dpc if interrupt is pended in the dongle.
@@ -6200,7 +6198,7 @@ dhdsdio_isr(void *arg)
        bus->intdis = TRUE;
 
 #if defined(SDIO_ISR_THREAD) || defined(OOB_PARAM)
-       OOB_PARAM_IF(dhd_oob_disable) {
+       OOB_PARAM_IF(bus->dhd->oob_disable) {
                DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
                DHD_OS_WAKE_LOCK(bus->dhd);
                dhdsdio_dpc(bus);
@@ -6525,7 +6523,7 @@ int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
        int err = 0;
 
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(dhdp->oob_disable)) {
                err = bcmsdh_oob_intr_register(dhdp->bus->sdh, dhdsdio_isr, dhdp->bus);
        }
 #endif
@@ -6535,7 +6533,7 @@ int dhd_bus_oob_intr_register(dhd_pub_t *dhdp)
 void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
 {
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(dhdp->oob_disable)) {
                bcmsdh_oob_intr_unregister(dhdp->bus->sdh);
        }
 #endif
@@ -6544,7 +6542,7 @@ void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp)
 void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable)
 {
 #if defined(OOB_INTR_ONLY)
-       OOB_PARAM_IF(!dhd_oob_disable) {
+       OOB_PARAM_IF(!(dhdp->oob_disable)) {
                bcmsdh_oob_intr_set(dhdp->bus->sdh, enable);
        }
 #endif
@@ -6577,14 +6575,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
 
        bus = dhdp->bus;
 
-/* Murata -- fix for suspend/resume powersave issue on i.MX architecture */
-#if defined(OOB_INTR_ONLY)
-       if (bus->bus_wake_on_resume) {
-               BUS_WAKE(bus);
-               bus->bus_wake_on_resume = 0;
-       }
-#endif
-
        if (bus->dhd->dongle_reset)
                return FALSE;
 
@@ -6600,6 +6590,15 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
        if (dhdp->busstate == DHD_BUS_DOWN)
                return FALSE;
 
+
+#if defined(CUSTOMER_IMX)
+       if (bus->bus_wake_on_resume) {
+               BUS_WAKE(bus);
+               bus->bus_wake_on_resume = 0;
+       }
+#endif /* CUSTOMER_IMX */
+
+
        /* Poll period: check device if appropriate. */
        if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) {
                uint32 intstatus = 0;
@@ -6954,7 +6953,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
 
 #if defined(SUPPORT_P2P_GO_PS)
        init_waitqueue_head(&bus->bus_sleep);
-#endif /* LINUX && SUPPORT_P2P_GO_PS */
+#endif /* LINUX && (SUPPORT_P2P_GO_PS || !OEM_ANDROID) */
 
        /* attempt to attach to the dongle */
        if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
@@ -7167,7 +7166,9 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
                                bus->dongle_ram_base = CR4_4360_RAM_BASE;
                                break;
                        case BCM4345_CHIP_ID:
-                               bus->dongle_ram_base = CR4_4345_RAM_BASE;
+                               /* RAM base changed from 4345c0 (chiprev=6) onwards */
+                               bus->dongle_ram_base = (bus->sih->chiprev < 6)
+                                       ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
                                break;
                        default:
                                bus->dongle_ram_base = 0;
@@ -7252,6 +7253,7 @@ dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
                /* release rxbuf which was already located as above */
                if (bus->rxbuf) {
                        DHD_OS_PREFREE(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxbuf, bus->rxblen);
+                       bus->rxbuf = NULL;
                }
                goto fail;
        }
@@ -7525,42 +7527,55 @@ dhdsdio_suspend(void *context)
        int ret = 0;
 
        dhd_bus_t *bus = (dhd_bus_t*)context;
-#ifdef SUPPORT_P2P_GO_PS
+#if defined(SUPPORT_P2P_GO_PS)
        int wait_time = 0;
 
        if (bus->idletime > 0) {
-               wait_time = msecs_to_jiffies(bus->idletime * dhd_watchdog_ms);
+               wait_time = 2 * (msecs_to_jiffies(bus->idletime * dhd_watchdog_ms));
        }
-#endif /* SUPPORT_P2P_GO_PS */
+#endif /* SUPPORT_P2P_GO_PS || !OEM_ANDROID */
        ret = dhd_os_check_wakelock(bus->dhd);
-#ifdef SUPPORT_P2P_GO_PS
+#if defined(SUPPORT_P2P_GO_PS)
+       /* Sometimes DHD enters into suspend state when bus is still awake due
+        * to absence of wake locks on Non-Android platforms, so perform bus
+        * sleep status check using bus_sleep event to prevent dhd entering
+        * into suspend state when bus is still awake.
+        */
        if ((!ret) && (bus->dhd->up) && (bus->dhd->op_mode != DHD_FLAG_HOSTAP_MODE)) {
                if (wait_event_timeout(bus->bus_sleep, bus->sleeping, wait_time) == 0) {
                        if (!bus->sleeping) {
-                               return 1;
+                               DHD_ERROR(("%s: cannot suspend because bus is awake\n",
+                                       __FUNCTION__));
+                               return -EBUSY;
                        }
                }
        }
-#endif /* SUPPORT_P2P_GO_PS */
+#endif /* SUPPORT_P2P_GO_PS || !OEM_ANDROID */
        return ret;
 }
 
 static int
 dhdsdio_resume(void *context)
 {
-#if defined(OOB_INTR_ONLY)
+
+#if defined(OOB_INTR_ONLY) || defined(CUSTOMER_IMX)
        dhd_bus_t *bus = (dhd_bus_t*)context;
+#endif /* defined(OOB_INTR_ONLY)||defined(BCMSPI_ANDROID)||
+       * defined(CUSTOMER_IMX) */
 
-       OOB_PARAM_IF(!dhd_oob_disable) {
+#if defined(OOB_INTR_ONLY)
+
+       OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
                if (dhd_os_check_if_up(bus->dhd))
                        bcmsdh_oob_intr_set(bus->sdh, TRUE);
        }
-       /* Murata -- fix for suspend/resume powersave issue on i.MX arch:
-        * add next two lines of code.
-        */
+#endif
+
+#if defined(CUSTOMER_IMX)
        bus->bus_wake_on_resume = 1;
        dhd_os_wd_timer(bus->dhd, 1000);
-#endif
+#endif /* CUSTOMER_IMX */
+
        return 0;
 }
 
@@ -8053,7 +8068,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                        dhd_bus_stop(bus, FALSE);
 
 #if defined(OOB_INTR_ONLY)
-                       OOB_PARAM_IF(!dhd_oob_disable) {
+                       OOB_PARAM_IF(!(dhdp->oob_disable)) {
                                /* Clean up any pending IRQ */
                                dhd_enable_oob_intr(bus, FALSE);
                                bcmsdh_oob_intr_set(bus->sdh, FALSE);
@@ -8096,7 +8111,7 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                        bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
                                        if (bcmerror == BCME_OK) {
 #if defined(OOB_INTR_ONLY)
-                                               OOB_PARAM_IF(!dhd_oob_disable) {
+                                               OOB_PARAM_IF(!(dhdp->oob_disable)) {
                                                        dhd_enable_oob_intr(bus, TRUE);
                                                        bcmsdh_oob_intr_register(bus->sdh,
                                                                dhdsdio_isr, bus);
@@ -8119,8 +8134,15 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
                                                dhdsdio_release_dongle(bus, bus->dhd->osh,
                                                        TRUE, FALSE);
                                        }
-                               } else
+                               } else {
+                                       DHD_ERROR(("%s Failed to download binary to the dongle\n",
+                                               __FUNCTION__));
+                                       if (bus->sih != NULL) {
+                                               si_detach(bus->sih);
+                                               bus->sih = NULL;
+                                       }
                                        bcmerror = BCME_SDIO_ERROR;
+                               }
                        } else
                                bcmerror = BCME_SDIO_ERROR;
 
@@ -8254,7 +8276,6 @@ dhd_bus_pktq_flush(dhd_pub_t *dhdp)
        }
 }
 
-#ifdef BCMSDIO
 int
 dhd_sr_config(dhd_pub_t *dhd, bool on)
 {
@@ -8276,7 +8297,6 @@ dhd_get_chipid(dhd_pub_t *dhd)
        else
                return 0;
 }
-#endif /* BCMSDIO */
 
 #ifdef DEBUGGER
 uint32 dhd_sdio_reg_read(void *h, uint32 addr)
@@ -8312,3 +8332,12 @@ void dhd_sdio_reg_write(void *h, uint32 addr, uint32 val)
        dhd_os_sdunlock(bus->dhd);
 }
 #endif /* DEBUGGER */
+
+
+#ifdef OOB_PARAM
+uint
+dhd_get_oob_disable(struct dhd_bus *bus)
+{
+       return bus->dhd->oob_disable;
+}
+#endif /* OOB_PARAM */
index 153a931..8c1436a 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_wlfc.c 599648 2015-11-16 09:33:00Z $
+ * $Id: dhd_wlfc.c 658506 2016-09-08 06:44:19Z $
  *
  */
 
@@ -93,8 +93,7 @@ _dhd_wlfc_prec_enque(struct pktq *pq, int prec, void* p, bool qHead,
                return;
 
        ASSERT(prec >= 0 && prec < pq->num_prec);
-       /* queueing chains not allowed and no segmented SKB (Kernel-3.18.y) */
-       ASSERT(!((PKTLINK(p) != NULL) && (PKTLINK(p) != p)));
+       ASSERT(PKTLINK(p) == NULL);             /* queueing chains not allowed */
 
        ASSERT(!pktq_full(pq));
        ASSERT(!pktq_pfull(pq, prec));
index 403b145..8062bf7 100644 (file)
@@ -23,7 +23,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.h 455573 2014-02-14 17:49:31Z $
+ * $Id: bcmsdh.h 662739 2016-11-08 09:20:31Z $
  */
 
 /**
@@ -40,8 +40,7 @@ extern const uint bcmsdh_msglevel;
 #define BCMSDH_ERROR(x)
 #define BCMSDH_INFO(x)
 
-#if defined(BCMSDIO) && (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || \
-       defined(BCMSDIOH_SPI))
+#if (defined(BCMSDIOH_STD) || defined(BCMSDIOH_BCM) || defined(BCMSDIOH_SPI))
 #define BCMSDH_ADAPTER
 #endif /* BCMSDIO && (BCMSDIOH_STD || BCMSDIOH_BCM || BCMSDIOH_SPI) */
 
index 24ea3d8..d85298b 100644 (file)
 /* number of bytes needed to define a proper bit mask for MAC event reporting */
 #define BCMIO_ROUNDUP(x, y)    ((((x) + ((y) - 1)) / (y)) * (y))
 #define BCMIO_NBBY             8
-#define WL_EVENTING_MASK_LEN   16
+/* number of bytes needed to define a mask for MAC event reporting */
+#define WL_EVENTING_MASK_LEN   (((WLC_E_LAST) / 8) + (((WLC_E_LAST % 8) > 0) ? 1 : 0))
 
 
 /* join preference types */
index 07fe014..31e5a91 100644 (file)
 
 #define        EPI_MINOR_VERSION       141
 
-#define        EPI_RC_NUMBER           92
+#define        EPI_RC_NUMBER           100
 
-#define        EPI_INCREMENTAL_NUMBER  0
+#define        EPI_INCREMENTAL_NUMBER  6
 
 #define        EPI_BUILD_NUMBER        0
 
-#define        EPI_VERSION             1, 141, 92, 0
+#define        EPI_VERSION             1, 141, 100, 6
 
-#define        EPI_VERSION_NUM         0x018d5c00
+#define        EPI_VERSION_NUM         0x018d6406
 
-#define EPI_VERSION_DEV                1.141.92
+#define EPI_VERSION_DEV                1.141.100
 
 /* Driver Version String, ASCII, 32 chars max */
-#define        EPI_VERSION_STR         "1.141.92 (r)"
+#define        EPI_VERSION_STR         "1.141.100.6 (r)"
 
 #endif /* _epivers_h_ */
index d9dd5fd..ba989be 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: linux_osl.h 623322 2016-03-07 12:58:14Z $
+ * $Id: linux_osl.h 657415 2016-09-01 05:45:34Z $
  */
 
 #ifndef _linux_osl_h_
@@ -179,23 +179,16 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction);
 #endif 
 
 /* register access macros */
-#if defined(BCMSDIO)
        #include <bcmsdh.h>
        #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(osl_get_bus_handle(osh), \
                (uintptr)(r), sizeof(*(r)), (v)))
        #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(osl_get_bus_handle(osh), \
                (uintptr)(r), sizeof(*(r))))
-#endif 
 
-#if defined(BCMSDIO)
        #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \
                mmap_op else bus_op
        #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \
                mmap_op : bus_op
-#else
-       #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;})
-       #define SELECT_BUS_READ(osh, mmap_op, bus_op) ({BCM_REFERENCE(osh); mmap_op;})
-#endif 
 
 #define OSL_ERROR(bcmerror)    osl_error(bcmerror)
 extern int osl_error(int bcmerror);
@@ -365,6 +358,11 @@ extern int osl_error(int bcmerror);
 #define PKTID(skb)              ({BCM_REFERENCE(skb); 0;})
 #define PKTSETID(skb, id)       ({BCM_REFERENCE(skb); BCM_REFERENCE(id);})
 #define PKTSHRINK(osh, m)              ({BCM_REFERENCE(osh); m;})
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+#define PKTORPHAN(skb)          skb_orphan(skb)
+#else
+#define PKTORPHAN(skb)          ({BCM_REFERENCE(skb); 0;})
+#endif /* LINUX VERSION >= 3.6 */
 
 #ifdef BCMDBG_CTRACE
 #define        DEL_CTRACE(zosh, zskb) { \
index 393cf14..15071c9 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: linuxver.h 431983 2013-10-25 06:53:27Z $
+ * $Id: linuxver.h 656961 2016-08-30 13:20:42Z $
  */
 
 #ifndef _linuxver_h_
@@ -604,10 +604,16 @@ static inline bool binary_sema_up(tsk_ctl_t *tsk)
        (tsk_ctl)->proc_name = name;  \
        (tsk_ctl)->terminated = FALSE; \
        (tsk_ctl)->p_task  = kthread_run(thread_func, tsk_ctl, (char*)name); \
-       (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \
-       spin_lock_init(&((tsk_ctl)->spinlock)); \
-       DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \
-               (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \
+       if (IS_ERR((tsk_ctl)->p_task)) { \
+               (tsk_ctl)->thr_pid = DHD_PID_KT_INVALID; \
+               DBG_THR(("%s(): thread:%s:%lx failed\n", __FUNCTION__, \
+                       (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \
+       } else { \
+               (tsk_ctl)->thr_pid = (tsk_ctl)->p_task->pid; \
+               spin_lock_init(&((tsk_ctl)->spinlock)); \
+               DBG_THR(("%s(): thread:%s:%lx started\n", __FUNCTION__, \
+                       (tsk_ctl)->proc_name, (tsk_ctl)->thr_pid)); \
+       } \
 }
 
 #define PROC_STOP(tsk_ctl) \
index 73fff8f..2791636 100644 (file)
@@ -23,7 +23,7 @@
  *
  * Dependencies: proto/bcmeth.h
  *
- * $Id: bcmevent.h 589976 2015-10-01 07:01:27Z $
+ * $Id: bcmevent.h 662961 2016-11-24 01:22:35Z $
  *
  */
 
@@ -223,9 +223,10 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
 #define WLC_E_TX_STAT_ERROR            126     /* tx error indication */
 #define WLC_E_BCMC_CREDIT_SUPPORT      127     /* credit check for BCMC supported */
 #define WLC_E_RMC_EVENT                        139     /* RMC event */
-#define WLC_E_LAST                     140     /* highest val + 1 for range checking */
+#define WLC_E_PKT_FILTER                       164 /* Packet filter event */
+#define WLC_E_LAST                     165     /* highest val + 1 for range checking */
 
-#if (WLC_E_LAST > 140)
+#if (WLC_E_LAST > 165)
 #error "WLC_E_LAST: Invalid value for last event; must be <= 140."
 #endif /* WLC_E_LAST */
 
@@ -239,6 +240,10 @@ typedef struct {
 extern const bcmevent_name_t   bcmevent_names[];
 extern const int               bcmevent_names_size;
 
+/* validate if the event is proper and if valid copy event header to event */
+extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
+       wl_event_msg_t *out_event);
+
 /* Event status codes */
 #define WLC_E_STATUS_SUCCESS           0       /* operation was successful */
 #define WLC_E_STATUS_FAIL              1       /* operation failed */
@@ -385,12 +390,16 @@ typedef struct wl_event_data_rssi {
 #define WLAN_TDLS_SET_SETUP_WFD_IE              12
 #endif
 
+
 /* reason codes for WLC_E_RMC_EVENT event */
 #define WLC_E_REASON_RMC_NONE          0
 #define WLC_E_REASON_RMC_AR_LOST               1
 #define WLC_E_REASON_RMC_AR_NO_ACK             2
 
 
+/* WLC_E_PKT_FILTER event codes */
+#define WLC_E_PKT_FILTER_TIMEOUT       1 /* Matching packet not received in last timeout seconds */
+
 /* GAS event data */
 typedef BWL_PRE_PACKED_STRUCT struct wl_event_gas {
        uint16  channel;                /* channel of GAS protocol */
index 5ef0522..f1549b6 100644 (file)
@@ -5,7 +5,7 @@
  * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
  * GPIO interface, extbus, and support for serial and parallel flashes.
  *
- * $Id: sbchipc.h 468568 2014-04-08 05:33:12Z $
+ * $Id: sbchipc.h 662459 2016-10-24 04:35:43Z $
  *
  * Copyright (C) 1999-2016, Broadcom Corporation
  * 
@@ -2669,7 +2669,8 @@ typedef volatile struct {
 
 #define PATCHTBL_SIZE                  (0x800)
 #define CR4_4335_RAM_BASE                    (0x180000)
-#define CR4_4345_RAM_BASE                    (0x1b0000)
+#define CR4_4345_LT_C0_RAM_BASE                (0x1b0000)
+#define CR4_4345_GE_C0_RAM_BASE                (0x198000)
 #define CR4_4349_RAM_BASE                    (0x180000)
 #define CR4_4350_RAM_BASE                    (0x180000)
 #define CR4_4360_RAM_BASE                    (0x0)
index b19c9df..2ada5ec 100644 (file)
@@ -28,7 +28,6 @@
 #ifndef        _SDIO_H
 #define        _SDIO_H
 
-#ifdef BCMSDIO
 
 /* CCCR structure for function 0 */
 typedef volatile struct {
@@ -617,6 +616,4 @@ typedef volatile struct {
 /* command issue options */
 #define CMD_OPTION_DEFAULT     0
 #define CMD_OPTION_TUNING      1
-
-#endif /* def BCMSDIO */
 #endif /* _SDIO_H */
index 73a8fda..c6dae89 100644 (file)
@@ -268,9 +268,7 @@ extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset);
 extern uint si_pcie_writereg(void *sih, uint addrtype, uint offset, uint val);
 
 
-#ifdef BCMSDIO
 extern void si_sdio_init(si_t *sih);
-#endif
 
 extern uint16 si_d11_devid(si_t *sih);
 extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice,
index 32590f4..cc2d667 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 575651 2015-07-30 13:49:47Z $
+ * $Id: wlioctl.h 662961 2016-11-24 01:22:35Z $
  */
 
 #ifndef _wlioctl_h_
@@ -2682,7 +2682,10 @@ typedef struct pm_wake_packet {
 typedef enum wl_pkt_filter_type {
        WL_PKT_FILTER_TYPE_PATTERN_MATCH=0,     /* Pattern matching filter */
        WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH=1, /* Magic packet match */
-       WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2 /* A pattern list (match all to match filter) */
+       WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH=2,        /* A pattern list (match all to match filter) */
+       WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH=3, /* SECURE WOWL magic / net pattern match */
+       WL_PKT_FILTER_TYPE_APF_MATCH=4, /* Android packet filter match */
+       WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT=5, /* Pattern matching filter with timeout event */
 } wl_pkt_filter_type_t;
 
 #define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
@@ -2691,7 +2694,10 @@ typedef enum wl_pkt_filter_type {
 #define WL_PKT_FILTER_TYPE_NAMES \
        { "PATTERN", WL_PKT_FILTER_TYPE_PATTERN_MATCH },       \
        { "MAGIC",   WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH }, \
-       { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH }
+       { "PATLIST", WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH }, \
+       { "SECURE WOWL", WL_PKT_FILTER_TYPE_ENCRYPTED_PATTERN_MATCH }, \
+       { "APF", WL_PKT_FILTER_TYPE_APF_MATCH }, \
+       { "PATTERN TIMEOUT", WL_PKT_FILTER_TYPE_PATTERN_MATCH_TIMEOUT }
 
 /* Pattern matching filter. Specifies an offset within received packets to
  * start matching, the pattern to match, the size of the pattern, and a bitmask
@@ -2723,6 +2729,19 @@ typedef struct wl_pkt_filter_pattern_list {
        wl_pkt_filter_pattern_listel_t patterns[1]; /* Variable number of list elements */
 } wl_pkt_filter_pattern_list_t;
 
+
+typedef struct wl_pkt_filter_pattern_timeout {
+       uint32  offset; /* Offset within received packet to start pattern matching.
+                                        * Offset '0' is the first byte of the ethernet header.
+                                        */
+       uint32  size_bytes;     /* Size of the pattern. Bitmask must be the same size. */
+       uint32  timeout;        /* Timeout(seconds) */
+       uint8   mask_and_pattern[1]; /* Variable length mask and pattern data.
+                                                                * mask starts at offset 0. Pattern
+                                                                * immediately follows mask.
+                                                               */
+} wl_pkt_filter_pattern_timeout_t;
+
 /* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
 typedef struct wl_pkt_filter {
        uint32  id;             /* Unique filter id, specified by app. */
@@ -2731,6 +2750,7 @@ typedef struct wl_pkt_filter {
        union {                 /* Filter definitions */
                wl_pkt_filter_pattern_t pattern;        /* Pattern matching filter */
                wl_pkt_filter_pattern_list_t patlist; /* List of patterns to match */
+               wl_pkt_filter_pattern_timeout_t pattern_timeout; /* Pattern timeout event filter */
        } u;
 } wl_pkt_filter_t;
 
@@ -2745,6 +2765,8 @@ typedef struct wl_tcp_keep_set {
 #define WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_list_t, patterns)
 #define WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN \
                        OFFSETOF(wl_pkt_filter_pattern_listel_t, mask_and_data)
+#define WL_PKT_FILTER_PATTERN_TIMEOUT_FIXED_LEN        \
+                       OFFSETOF(wl_pkt_filter_pattern_timeout_t, mask_and_pattern)
 
 /* IOVAR "pkt_filter_enable" parameter. */
 typedef struct wl_pkt_filter_enable {
@@ -4958,4 +4980,29 @@ typedef struct wl_bssload_static {
 } wl_bssload_static_t;
 
 
+
+typedef enum event_msgs_ext_command {
+       EVENTMSGS_NONE          =       0,
+       EVENTMSGS_SET_BIT       =       1,
+       EVENTMSGS_RESET_BIT     =       2,
+       EVENTMSGS_SET_MASK      =       3
+} event_msgs_ext_command_t;
+
+#define EVENTMSGS_VER 1
+#define EVENTMSGS_EXT_STRUCT_SIZE      OFFSETOF(eventmsgs_ext_t, mask[0])
+
+/* len - for SET it would be mask size from the application to the firmware
+ * for GET it would be actual firmware mask size
+ * maxgetsize - is only used for GET. indicate max mask size that the
+ * application can read from the firmware
+ */
+typedef struct eventmsgs_ext
+{
+       uint8   ver;
+       uint8   command;
+       uint8   len;
+       uint8   maxgetsize;
+       uint8   mask[1];
+} eventmsgs_ext_t;
+
 #endif /* _wlioctl_h_ */
index d3f8583..5b0008d 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: linux_osl.c 542523 2015-03-20 03:21:32Z $
+ * $Id: linux_osl.c 658506 2016-09-08 06:44:19Z $
  */
 
 #define LINUX_PORT
@@ -667,30 +667,42 @@ void * BCMFASTPATH
 osl_pkt_frmnative(osl_t *osh, void *pkt)
 #endif /* BCMDBG_CTRACE */
 {
+       struct sk_buff *cskb;
        struct sk_buff *nskb;
-#ifdef BCMDBG_CTRACE
-       struct sk_buff *nskb1, *nskb2;
-#endif
+       unsigned long pktalloced = 0;
 
        if (osh->pub.pkttag)
                OSL_PKTTAG_CLEAR(pkt);
 
-       /* Increment the packet counter */
-       for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) {
-               atomic_add(PKTISCHAINED(nskb) ? PKTCCNT(nskb) : 1, &osh->cmn->pktalloced);
+       /* walk the PKTCLINK() list */
+       for (cskb = (struct sk_buff *)pkt;
+            cskb != NULL;
+            cskb = PKTISCHAINED(cskb) ? PKTCLINK(cskb) : NULL) {
 
-#ifdef BCMDBG_CTRACE
-               for (nskb1 = nskb; nskb1 != NULL; nskb1 = nskb2) {
-                       if (PKTISCHAINED(nskb1)) {
-                               nskb2 = PKTCLINK(nskb1);
-                       }
-                       else
-                               nskb2 = NULL;
+               /* walk the pkt buffer list */
+               for (nskb = cskb; nskb; nskb = nskb->next) {
 
-                       ADD_CTRACE(osh, nskb1, file, line);
-               }
+                       /* Increment the packet counter */
+                       pktalloced++;
+
+                       /* clean the 'prev' pointer
+                        * Kernel 3.18 is leaving skb->prev pointer set to skb
+                        * to indicate a non-fragmented skb
+                        */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+                       nskb->prev = NULL;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) */
+
+
+#ifdef BCMDBG_CTRACE
+                       ADD_CTRACE(osh, nskb, file, line);
 #endif /* BCMDBG_CTRACE */
+               }
        }
+
+       /* Increment the packet counter */
+       atomic_add(pktalloced, &osh->cmn->pktalloced);
+
        return (void *)pkt;
 }
 
index 1c0122d..bd99a9f 100644 (file)
@@ -234,12 +234,10 @@ _sb_coresba(si_info_t *sii)
                break;
        }
 
-#ifdef BCMSDIO
        case SPI_BUS:
        case SDIO_BUS:
                sbaddr = (uint32)(uintptr)sii->curmap;
                break;
-#endif
 
 
        default:
@@ -710,7 +708,6 @@ _sb_setcoreidx(si_info_t *sii, uint coreidx)
                regs = sii->curmap;
                break;
        }
-#ifdef BCMSDIO
        case SPI_BUS:
        case SDIO_BUS:
                /* map new one */
@@ -720,7 +717,6 @@ _sb_setcoreidx(si_info_t *sii, uint coreidx)
                }
                regs = cores_info->regs[coreidx];
                break;
-#endif /* BCMSDIO */
 
 
        default:
@@ -990,9 +986,7 @@ sb_set_initiator_to(si_t *sih, uint32 to, uint idx)
                        idx = SI_CC_IDX;
                        break;
                case PCMCIA_BUS:
-#ifdef BCMSDIO
                case SDIO_BUS:
-#endif
                        idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0);
                        break;
                case SI_BUS:
index 95d5158..edcd1c1 100644 (file)
 #include <pcicfg.h>
 #include <sbpcmcia.h>
 #include <sbsocram.h>
-#ifdef BCMSDIO
 #include <bcmsdh.h>
 #include <sdio.h>
 #include <sbsdio.h>
 #include <sbhnddma.h>
 #include <sbsdpcmdev.h>
 #include <bcmsdpcm.h>
-#endif /* BCMSDIO */
 #include <hndpmu.h>
 
 #ifdef BCM_SDRBL
@@ -167,7 +165,6 @@ si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
                sii->memseg = TRUE;
 
 
-#if defined(BCMSDIO)
        if (BUSTYPE(bustype) == SDIO_BUS) {
                int err;
                uint8 clkset;
@@ -200,7 +197,6 @@ si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
                bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
        }
 
-#endif /* BCMSDIO && BCMDONGLEHOST */
 
        return TRUE;
 }
@@ -294,7 +290,6 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
                        sii->pub.buscoretype = cid;
                        sii->pub.buscoreidx = i;
                }
-#ifdef BCMSDIO
                else if (((BUSTYPE(bustype) == SDIO_BUS) ||
                          (BUSTYPE(bustype) == SPI_BUS)) &&
                         ((cid == PCMCIA_CORE_ID) ||
@@ -303,7 +298,6 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
                        sii->pub.buscoretype = cid;
                        sii->pub.buscoreidx = i;
                }
-#endif /* BCMSDIO */
 
                /* find the core idx before entering this func. */
                if ((savewin && (savewin == cores_info->coresba[i])) ||
@@ -335,7 +329,6 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
                OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL);
 
 
-#if defined(BCMSDIO)
        /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was
         * already running.
         */
@@ -344,7 +337,6 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
                    si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
                        si_core_disable(&sii->pub, 0);
        }
-#endif /* BCMSDIO && BCMDONGLEHOST */
 
        /* return to the original core */
        si_setcoreidx(&sii->pub, *origidx);
@@ -401,10 +393,8 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
                if (!regs)
                        return NULL;
                cc = (chipcregs_t *)regs;
-#ifdef BCMSDIO
        } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
                cc = (chipcregs_t *)sii->curmap;
-#endif
        } else {
                cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
        }
index 7c934d3..9d3580e 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: wl_android.c 555968 2015-05-12 01:56:23Z $
+ * $Id: wl_android.c 662786 2016-11-11 09:06:37Z $
  */
 
 #include <linux/module.h>
@@ -43,9 +43,7 @@
 #ifdef PNO_SUPPORT
 #include <dhd_pno.h>
 #endif
-#ifdef BCMSDIO
 #include <bcmsdbus.h>
-#endif
 #ifdef WL_CFG80211
 #include <wl_cfg80211.h>
 #endif
@@ -87,6 +85,8 @@
 #define CMD_SET_AP_WPS_P2P_IE          "SET_AP_WPS_P2P_IE"
 #define CMD_SETROAMMODE        "SETROAMMODE"
 #define CMD_SETIBSSBEACONOUIDATA       "SETIBSSBEACONOUIDATA"
+#define CMD_ADDIE      "add_ie"
+#define CMD_DELIE      "del_ie"
 #define CMD_MIRACAST           "MIRACAST"
 #define CMD_NAN                                "NAN_"
 #if defined(WL_SUPPORT_AUTO_CHANNEL)
 
 #define CMD_ROAM_OFFLOAD                       "SETROAMOFFLOAD"
 
+#ifdef WLTDLS
+#define CMD_TDLS_RESET "TDLS_RESET"
+#endif /* WLTDLS */
+
+#define CMD_INTERFACE_CREATE                   "INTERFACE_CREATE"
+#define CMD_INTERFACE_DELETE                   "INTERFACE_DELETE"
+
 /* miracast related definition */
 #define MIRACAST_MODE_OFF      0
 #define MIRACAST_MODE_SOURCE   1
@@ -626,8 +633,8 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
                                        " <> params\n", __FUNCTION__));
                                        goto exit;
                                }
-                                       while ((token2 = strsep(&pos2,
-                                       PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
+                               while ((token2 = strsep(&pos2,
+                                               PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
                                        if (token2 == NULL || !*token2)
                                                break;
                                        if (*token2 == '\0')
@@ -638,11 +645,18 @@ wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
                                                DHD_PNO(("band : %s\n",
                                                        (*token2 == 'A')? "A" : "B"));
                                        } else {
+                                               if ((batch_params.nchan >= WL_NUMCHANNELS) ||
+                                                       (i >= WL_NUMCHANNELS)) {
+                                                       DHD_ERROR(("Too many nchan %d\n",
+                                                               batch_params.nchan));
+                                                       err = BCME_BUFTOOSHORT;
+                                                       goto exit;
+                                               }
                                                batch_params.chan_list[i++] =
-                                               simple_strtol(token2, NULL, 0);
+                                                       simple_strtol(token2, NULL, 0);
                                                batch_params.nchan++;
                                                DHD_PNO(("channel :%d\n",
-                                               batch_params.chan_list[i-1]));
+                                                       batch_params.chan_list[i-1]));
                                        }
                                 }
                        } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
@@ -800,6 +814,24 @@ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, i
 }
 
 
+#ifdef WLTDLS
+int wl_android_tdls_reset(struct net_device *dev)
+{
+       int ret = 0;
+       ret = dhd_tdls_enable(dev, false, false, NULL);
+       if (ret < 0) {
+               DHD_ERROR(("Disable tdls failed. %d\n", ret));
+               return ret;
+       }
+       ret = dhd_tdls_enable(dev, true, true, NULL);
+       if (ret < 0) {
+               DHD_ERROR(("enable tdls failed. %d\n", ret));
+               return ret;
+       }
+       return 0;
+}
+#endif /* WLTDLS */
+
 int
 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
 {
@@ -953,9 +985,7 @@ int wl_android_wifi_on(struct net_device *dev)
        if (!g_wifi_on) {
                do {
                        dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
-#ifdef BCMSDIO
                        ret = dhd_net_bus_resume(dev, 0);
-#endif
                        if (ret == 0)
                                break;
                        DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
@@ -966,10 +996,8 @@ int wl_android_wifi_on(struct net_device *dev)
                        DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
                        goto exit;
                }
-#ifdef BCMSDIO
                ret = dhd_net_bus_devreset(dev, FALSE);
                dhd_net_bus_resume(dev, 1);
-#endif
                if (!ret) {
                        if (dhd_dev_init_ioctl(dev) < 0)
                                ret = -EFAULT;
@@ -995,10 +1023,8 @@ int wl_android_wifi_off(struct net_device *dev)
 
        dhd_net_if_lock(dev);
        if (g_wifi_on) {
-#ifdef BCMSDIO
                ret = dhd_net_bus_devreset(dev, TRUE);
                dhd_net_bus_suspend(dev);
-#endif
                dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
                g_wifi_on = FALSE;
        }
@@ -1222,6 +1248,185 @@ int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_le
        return 0;
 }
 
+int wl_android_add_vendor_ie(struct net_device *dev, char *command, int total_len)
+{
+       char ie_buf[VNDR_IE_MAX_LEN];
+       char *ioctl_buf = NULL;
+       char hex[] = "XX";
+       char *pcmd = NULL;
+       int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
+       vndr_ie_setbuf_t *vndr_ie = NULL;
+       s32 iecount;
+       uint32 pktflag;
+       u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+       s32 err = BCME_OK;
+
+       pcmd = command + strlen(CMD_ADDIE) + 1;
+
+       pktflag = simple_strtoul(pcmd, &pcmd, 16);
+
+       pcmd = pcmd + 1;
+
+       for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+               hex[0] = *pcmd++;
+               hex[1] = *pcmd++;
+               ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
+       }
+       pcmd++;
+       while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
+               hex[0] = *pcmd++;
+               hex[1] = *pcmd++;
+               ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
+               datalen++;
+       }
+
+       tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+       vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+       if (!vndr_ie) {
+               WL_ERR(("IE memory alloc failed\n"));
+               return -ENOMEM;
+       }
+
+       /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+       strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
+       vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+       /* Set the IE count - the buffer contains only 1 IE */
+       iecount = htod32(1);
+       memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
+
+       /* Set packet flag to indicate the appropriate frame will contain this IE */
+       pktflag = htod32(1<<pktflag);
+       memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
+               sizeof(u32));
+
+       /* Set the IE ID */
+       vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
+
+       /* Set the OUI */
+       memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
+               DOT11_OUI_LEN);
+       /* Set the Data */
+       memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
+               &ie_buf[DOT11_OUI_LEN], datalen);
+
+       ielen = DOT11_OUI_LEN + datalen;
+       vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
+
+       ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
+       if (!ioctl_buf) {
+               WL_ERR(("ioctl memory alloc failed\n"));
+               if (vndr_ie)
+                       kfree(vndr_ie);
+               return -ENOMEM;
+       }
+       memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+       err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+       if (err != BCME_OK) {
+               err = -EINVAL;
+               if (vndr_ie)
+                       kfree(vndr_ie);
+       }
+       else {
+               /* do NOT free 'vndr_ie' for the next process */
+               wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len);
+       }
+
+       if (ioctl_buf)
+               kfree(ioctl_buf);
+
+       return err;
+}
+
+int wl_android_del_vendor_ie(struct net_device *dev, char *command, int total_len)
+{
+       char ie_buf[VNDR_IE_MAX_LEN];
+       char *ioctl_buf = NULL;
+       char hex[] = "XX";
+       char *pcmd = NULL;
+       int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
+       vndr_ie_setbuf_t *vndr_ie = NULL;
+       s32 iecount;
+       uint32 pktflag;
+       u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+       s32 err = BCME_OK;
+
+       pcmd = command + strlen(CMD_ADDIE) + 1;
+
+       pktflag = simple_strtoul(pcmd, &pcmd, 16);
+
+       pcmd = pcmd + 1;
+       for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+               hex[0] = *pcmd++;
+               hex[1] = *pcmd++;
+               ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
+       }
+       pcmd++;
+       while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
+               hex[0] = *pcmd++;
+               hex[1] = *pcmd++;
+               ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
+               datalen++;
+       }
+
+       tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+       vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+       if (!vndr_ie) {
+               WL_ERR(("IE memory alloc failed\n"));
+               return -ENOMEM;
+       }
+       /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+       strncpy(vndr_ie->cmd, "del", VNDR_IE_CMD_LEN - 1);
+       vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+       /* Set the IE count - the buffer contains only 1 IE */
+       iecount = htod32(1);
+       memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
+
+       /* Set packet flag to indicate the appropriate frame will contain this IE */
+       pktflag = htod32(1<<pktflag);
+       memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
+                       sizeof(u32));
+
+       /* Set the IE ID */
+       vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
+
+       /* Set the OUI */
+       memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
+                       DOT11_OUI_LEN);
+       /* Set the Data */
+       memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
+                       &ie_buf[DOT11_OUI_LEN], datalen);
+
+       ielen = DOT11_OUI_LEN + datalen;
+       vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
+
+       ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
+       if (!ioctl_buf) {
+               WL_ERR(("ioctl memory alloc failed\n"));
+               if (vndr_ie)
+                       kfree(vndr_ie);
+               return -ENOMEM;
+       }
+       memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+       err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+       if (err != BCME_OK) {
+               err = -EINVAL;
+               if (vndr_ie)
+                       kfree(vndr_ie);
+       }
+       else {
+               /* do NOT free 'vndr_ie' for the next process */
+               wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len);
+       }
+
+       if (ioctl_buf)
+               kfree(ioctl_buf);
+       return err;
+}
+
 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
 {
        char ie_buf[VNDR_IE_MAX_LEN];
@@ -1783,6 +1988,11 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
 
        net_os_wake_lock(net);
 
+       if (!capable(CAP_NET_ADMIN)) {
+               ret = -EPERM;
+               goto exit;
+       }
+
        if (!ifr->ifr_data) {
                ret = -EINVAL;
                goto exit;
@@ -2004,6 +2214,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
        else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
                bytes_written = wl_android_set_ibss_beacon_ouidata(net,
                command, priv_cmd.total_len);
+       else if (strnicmp(command, CMD_ADDIE, strlen(CMD_ADDIE)) == 0)
+               bytes_written = wl_android_add_vendor_ie(net, command, priv_cmd.total_len);
+       else if (strnicmp(command, CMD_DELIE, strlen(CMD_DELIE)) == 0)
+               bytes_written = wl_android_del_vendor_ie(net, command, priv_cmd.total_len);
        else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
                int skip = strlen(CMD_KEEP_ALIVE) + 1;
                bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip);
@@ -2012,6 +2226,18 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
                int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
                bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
        }
+#if defined(WL_VIRTUAL_APSTA)
+       else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
+               char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
+               WL_INFO(("Creating %s interface\n", name));
+               bytes_written = wl_cfg80211_interface_create(net, name);
+       }
+       else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
+               char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
+               WL_INFO(("Deleteing %s interface\n", name));
+               bytes_written = wl_cfg80211_interface_delete(net, name);
+       }
+#endif /* defined (WL_VIRTUAL_APSTA) */
 #ifdef CONNECTION_STATISTICS
        else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
                strlen(CMD_GET_CONNECTION_STATS)) == 0) {
@@ -2019,6 +2245,11 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
                        priv_cmd.total_len);
        }
 #endif
+#ifdef WLTDLS
+       else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
+               bytes_written = wl_android_tdls_reset(net);
+       }
+#endif /* WLTDLS */
        else {
                DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
                snprintf(command, 3, "OK");
index bddaf2f..e041dcb 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: wl_cfg80211.c 641576 2016-06-03 08:52:14Z $
+ * $Id: wl_cfg80211.c 662965 2016-11-24 03:53:15Z $
  */
 /* */
 #include <typedefs.h>
@@ -269,6 +269,10 @@ common_iface_combinations[] = {
 
 #define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
 #define LONG_LISTEN_TIME 2000
+
+#define MAX_SCAN_ABORT_WAIT_CNT 20
+#define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
+
 /*
  * cfg80211_ops api/callback list
  */
@@ -409,6 +413,18 @@ static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *d
 #endif
 chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
 
+#if defined(WL_VIRTUAL_APSTA)
+bcm_struct_cfgdev*
+wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype
+                iface_type, u8 *mac_addr, const char *name);
+s32
+wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
+#endif /* defined(WL_VIRTUAL_APSTA) */
+
+s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
+       struct net_device *ndev, s32 bsscfg_idx,
+       enum nl80211_iftype iface_type, s32 del, u8 *addr);
+
 /*
  * event & event Q handlers for cfg80211 interfaces
  */
@@ -613,6 +629,8 @@ int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
 static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        const struct ether_addr *bssid);
 
+static s32 wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len, struct parsed_vndr_ies *vndr_ies);
+
 
 #define RETURN_EIO_IF_NOT_UP(wlpriv)                                           \
 do {                                                                   \
@@ -623,6 +641,14 @@ do {                                                                       \
        }                                                               \
 } while (0)
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
+#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
+       cfg80211_disconnected(dev, reason, ie, len, gfp);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
+       cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
+#endif
+
 #ifdef RSSI_OFFSET
 static s32 wl_rssi_offset(s32 rssi)
 {
@@ -1179,7 +1205,14 @@ wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
                subelt_len = HTON16(val);
 
                len -= 4;                       /* for the attr id, attr len fields */
+
+               if (len < subelt_len) {
+                       WL_ERR(("not enough data, len %d, subelt_len %d\n", len,
+                               subelt_len));
+                       break;
+               }
                len -= subelt_len;      /* for the remaining fields in this attribute */
+
                WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
                        subel, subelt_id, subelt_len));
 
@@ -1194,11 +1227,14 @@ wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
                } else if (subelt_id == WPS_ID_DEVICE_NAME) {
                        char devname[100];
                        int namelen = MIN(subelt_len, (sizeof(devname) - 1));
-                       memcpy(devname, subel, namelen);
-                       devname[namelen] = '\0';
-                       /* Printing len as rx'ed in the IE */
-                       WL_DBG(("  attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
-                               devname, subelt_len));
+
+                       if (namelen) {
+                               memcpy(devname, subel, namelen);
+                               devname[namelen] = '\0';
+                               /* Printing len as rx'ed in the IE */
+                               WL_DBG(("  attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
+                                       devname, subelt_len));
+                       }
                } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
                        valptr[0] = *subel;
                        valptr[1] = *(subel + 1);
@@ -1374,20 +1410,19 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
        struct net_device *new_ndev;
        struct ether_addr primary_mac;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
        s32 up = 1;
        dhd_pub_t *dhd;
        bool enabled;
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
+#ifdef WL_VIRTUAL_APSTA
+       bcm_struct_cfgdev *new_cfgdev;
+#endif /* WL_VIRTUAL_APSTA */
 
        if (!cfg)
                return ERR_PTR(-EINVAL);
 
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
        dhd = (dhd_pub_t *)(cfg->pub);
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
 
 
@@ -1414,13 +1449,32 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
        case NL80211_IFTYPE_P2P_DEVICE:
                return wl_cfgp2p_add_p2p_disc_if(cfg);
 #endif /* WL_CFG80211_P2P_DEV_IF */
-       case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
+#ifdef WL_VIRTUAL_APSTA
+               if (!name) {
+                       WL_ERR(("Interface name not provided \n"));
+                       return ERR_PTR(-ENODEV);
+               }
+
+               if (wl_cfgp2p_vif_created(cfg)) {
+                       WL_ERR(("Could not create new iface."
+                               "Already one p2p interface is running"));
+                       return ERR_PTR(-ENODEV);
+               }
+               new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+                       NL80211_IFTYPE_STATION, NULL, name);
+               if (!new_cfgdev)
+                       return ERR_PTR(-ENOMEM);
+               else
+                       return new_cfgdev;
+#endif /* WL_VIRTUAL_APSTA */
+       case NL80211_IFTYPE_P2P_CLIENT:
                wlif_type = WL_P2P_IF_CLIENT;
                mode = WL_MODE_BSS;
                break;
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_AP:
+               WL_DBG(("Add virtual interface for AP (%d)\n", type));
                wlif_type = WL_P2P_IF_GO;
                mode = WL_MODE_AP;
                break;
@@ -1438,10 +1492,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
                ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */
 
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
                if (!dhd)
                        return ERR_PTR(-ENODEV);
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
                if (!cfg->p2p)
                        return ERR_PTR(-ENODEV);
@@ -1460,7 +1512,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
 
                wl_cfg80211_scan_abort(cfg);
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
                if (!cfg->wlfc_on && !disable_proptx) {
                        dhd_wlfc_get_enable(dhd, &enabled);
                        if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
@@ -1472,7 +1523,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
                        }
                        cfg->wlfc_on = true;
                }
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
 
                /* In concurrency case, STA may be already associated in a particular channel.
@@ -1498,6 +1548,9 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
                timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
                        (wl_get_p2p_status(cfg, IF_ADDING) == false),
                        msecs_to_jiffies(MAX_WAIT_TIME));
+               if (timeout == 0) {
+                       WL_ERR(("%d timeout waiting for IF_ADD.\n", __LINE__));
+               }
 
                if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
                        struct wireless_dev *vwdev;
@@ -1510,7 +1563,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
                         */
                        strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1);
                        new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
-                               event->mac, event->bssidx);
+                               event->mac, event->bssidx, event->name);
                        if (new_ndev == NULL)
                                goto fail;
 
@@ -1528,14 +1581,13 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
                        new_ndev->ieee80211_ptr = vwdev;
                        SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
                        wl_set_drv_status(cfg, READY, new_ndev);
-                       cfg->p2p->vif_created = true;
                        wl_set_mode_by_netdev(cfg, new_ndev, mode);
 
                        if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
                                wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
                                goto fail;
                        }
-                       wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode);
+                       wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode, event->bssidx);
                        val = 1;
                        /* Disable firmware roaming for P2P interface  */
                        wldev_iovar_setint(new_ndev, "roam_off", val);
@@ -1592,16 +1644,14 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
                        }
 
                        memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
-                       cfg->p2p->vif_created = false;
+                       wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = -1;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
                        dhd_wlfc_get_enable(dhd, &enabled);
                if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
                        dhd->op_mode != DHD_FLAG_IBSS_MODE) {
                        dhd_wlfc_deinit(dhd);
                        cfg->wlfc_on = false;
                }
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
                }
        }
@@ -1638,8 +1688,13 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
 #endif /* WL_CFG80211_P2P_DEV_IF */
        dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
 
-       if (wl_cfgp2p_find_idx(cfg, dev, &index) != BCME_OK) {
-               WL_ERR(("Find p2p index from ndev(%p) failed\n", dev));
+#ifdef WL_VIRTUAL_APSTA
+       if (cfgdev == cfg->bss_cfgdev) {
+               return wl_cfg80211_del_iface(wiphy, cfgdev);
+       }
+#endif /* WL_VIRTUAL_APSTA */
+       if ((index = wl_get_bssidx_by_wdev(cfg, ndev_to_wdev(dev))) < 0) {
+               WL_ERR(("Find p2p index from wdev failed\n"));
                return BCME_ERROR;
        }
        if (cfg->p2p_supported) {
@@ -1649,7 +1704,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
                 */
                WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
                wl_clr_p2p_status(cfg, GO_NEG_PHASE);
-               if (cfg->p2p->vif_created) {
+               if (wl_cfgp2p_vif_created(cfg)) {
                        if (wl_get_drv_status(cfg, SCANNING, dev)) {
                                wl_notify_escan_complete(cfg, dev, true, true);
                        }
@@ -1685,7 +1740,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
                                        msleep(300);
                                }
                        }
-                       wl_cfgp2p_clear_management_ie(cfg, index);
+                       wl_cfg80211_clear_per_bss_ies(cfg, index);
 
                        if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)
                                wldev_iovar_setint(dev, "buf_key_b4_m4", 0);
@@ -1768,11 +1823,27 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
        }
        if (!dhd)
                return -EINVAL;
+
+       /* If any scan is going on, abort it */
+       if (wl_get_drv_status_all(cfg, SCANNING)) {
+               int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+               WL_ERR(("Scan in progress. Aborting the scan!\n"));
+               wl_cfg80211_scan_abort(cfg);
+               while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
+                       WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+                       wait_cnt--;
+                       OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+               }
+               if (wl_get_drv_status_all(cfg, SCANNING)) {
+                       wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+               }
+       }
+
        if (ap) {
                wl_set_mode_by_netdev(cfg, ndev, mode);
-               if (cfg->p2p_supported && cfg->p2p->vif_created) {
-                       WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created,
-                       p2p_on(cfg)));
+               if (is_p2p_group_iface(ndev->ieee80211_ptr) &&
+                       cfg->p2p_supported && wl_cfgp2p_vif_created(cfg)) {
+                       WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
                        wldev_iovar_setint(ndev, "mpc", 0);
                        wl_notify_escan_complete(cfg, ndev, true, true);
 
@@ -1798,14 +1869,11 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                        wl_clr_p2p_status(cfg, IF_CHANGED);
                        if (mode == WL_MODE_AP)
                                wl_set_drv_status(cfg, CONNECTED, ndev);
-               } else if (ndev == bcmcfg_to_prmry_ndev(cfg) &&
+               } else if (((ndev == bcmcfg_to_prmry_ndev(cfg)) ||
+                       (ndev == ((struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)))) &&
                        !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
+                       dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
                        wl_set_drv_status(cfg, AP_CREATING, ndev);
-                       if (!cfg->ap_info &&
-                               !(cfg->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
-                               WL_ERR(("struct ap_saved_ie allocation failed\n"));
-                               return -ENOMEM;
-                       }
                } else {
                        WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
                        return -EINVAL;
@@ -1814,9 +1882,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
                WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA"));
 #ifdef  P2PONEINT   /* Cindy: Compare the change with add_virtual_iface */
                wl_set_mode_by_netdev(cfg, ndev, mode);
-               if (cfg->p2p_supported && cfg->p2p->vif_created) {
-                       WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", cfg->p2p->vif_created,
-                               p2p_on(cfg)));
+               if (cfg->p2p_supported && wl_cfgp2p_vif_created(cfg)) {
+                       WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
                        wldev_iovar_setint(ndev, "mpc", 0);
                        wl_notify_escan_complete(cfg, ndev, true, true);
 
@@ -1873,6 +1940,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
 s32
 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx)
 {
+       bool ifadd_expected = FALSE;
        struct bcm_cfg80211 *cfg = g_bcm_cfg;
 
        /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
@@ -1883,6 +1951,14 @@ wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx)
 
        /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
        if (wl_get_p2p_status(cfg, IF_ADDING)) {
+               ifadd_expected = TRUE;
+               wl_clr_p2p_status(cfg, IF_ADDING);
+       } else if (cfg->bss_pending_op) {
+               ifadd_expected = TRUE;
+               cfg->bss_pending_op = FALSE;
+       }
+
+       if (ifadd_expected) {
                wl_if_event_info *if_event_info = &cfg->if_event_info;
 
                if_event_info->valid = TRUE;
@@ -1893,7 +1969,6 @@ wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx)
                if (mac)
                        memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
 
-               wl_clr_p2p_status(cfg, IF_ADDING);
                wake_up_interruptible(&cfg->netif_change_event);
                return BCME_OK;
        }
@@ -1904,14 +1979,23 @@ wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx)
 s32
 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx)
 {
+       bool ifdel_expected = FALSE;
        struct bcm_cfg80211 *cfg = g_bcm_cfg;
        wl_if_event_info *if_event_info = &cfg->if_event_info;
 
+       WL_INFO(("%d: Enter %s\n", __LINE__, name));
        if (wl_get_p2p_status(cfg, IF_DELETING)) {
+               ifdel_expected = TRUE;
+               wl_clr_p2p_status(cfg, IF_DELETING);
+       } else if (cfg->bss_pending_op) {
+               ifdel_expected = TRUE;
+               cfg->bss_pending_op = FALSE;
+       }
+
+       if (ifdel_expected) {
                if_event_info->valid = TRUE;
                if_event_info->ifidx = ifidx;
                if_event_info->bssidx = bssidx;
-               wl_clr_p2p_status(cfg, IF_DELETING);
                wake_up_interruptible(&cfg->netif_change_event);
                return BCME_OK;
        }
@@ -1939,19 +2023,18 @@ static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *
        s32 type = -1;
        s32 bssidx = -1;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
        dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
        bool enabled;
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
 
        bssidx = if_event_info->bssidx;
-       if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) {
+       if ((bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) &&
+               (bssidx != cfg->cfgdev_bssidx)) {
                WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx));
                return BCME_ERROR;
        }
 
-       if (p2p_is_on(cfg) && cfg->p2p->vif_created) {
+       if (p2p_is_on(cfg) && wl_cfgp2p_vif_created(cfg)) {
 
                if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) {
                        /* Abort any pending scan requests */
@@ -1968,17 +2051,14 @@ static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *
                wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type));
                wl_to_p2p_bss_ndev(cfg, type) = NULL;
                wl_to_p2p_bss_bssidx(cfg, type) = WL_INVALID;
-               cfg->p2p->vif_created = false;
 
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
                dhd_wlfc_get_enable(dhd, &enabled);
                if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
                        dhd->op_mode != DHD_FLAG_IBSS_MODE) {
                        dhd_wlfc_deinit(dhd);
                        cfg->wlfc_on = false;
                }
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
        }
 
@@ -2130,7 +2210,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req
                ptr = (char*)params + offset;
                for (i = 0; i < n_ssids; i++) {
                        memset(&ssid, 0, sizeof(wlc_ssid_t));
-                       ssid.SSID_len = request->ssids[i].ssid_len;
+                       ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN);
                        memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
                        if (!ssid.SSID_len)
                                WL_SCAN(("%d: Broadcast scan\n", i));
@@ -2232,7 +2312,7 @@ wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                                        else
                                                continue;
                                }
-                               if (j > CH_MAX_2G_CHANNEL) {
+                               if (j >= CH_MAX_2G_CHANNEL) {
                                        WL_ERR(("Index %d exceeds max 2.4GHz channels %d"
                                                " and previous 5G connected channel\n",
                                                j, CH_MAX_2G_CHANNEL));
@@ -2493,12 +2573,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                WL_INFO(("Scan Command on SoftAP Interface. Ignoring...\n"));
                return 0;
        }
-#elif BCMDONGLEHOST
-       if (((dhd_pub_t *)(cfg->pub))->op_mode & DHD_FLAG_HOSTAP_MODE) {
-               WL_ERR(("Invalid Scan Command at SoftAP mode\n"));
-               return -EINVAL;
-       }
-#endif /* BCMDONGLEHOST */
+#endif /* WL_SUPPORT_ACS */
 
        ndev = ndev_to_wlc_ndev(ndev, cfg);
 
@@ -2583,10 +2658,10 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                }
                        }
                        if (!cfg->p2p_supported || !p2p_scan(cfg)) {
-
-                               if (wl_cfgp2p_find_idx(cfg, ndev, &bssidx) != BCME_OK) {
-                                       WL_ERR(("Find p2p index from ndev(%p) failed\n",
-                                               ndev));
+                               if ((bssidx = wl_get_bssidx_by_wdev(cfg,
+                                       ndev->ieee80211_ptr)) < 0) {
+                                       WL_ERR(("Find p2p index from wdev(%p) failed\n",
+                                               ndev->ieee80211_ptr));
                                        err = BCME_ERROR;
                                        goto scan_out;
                                }
@@ -2598,7 +2673,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                               interworking_ie->data, interworking_ie->len);
 
                                        if (unlikely(err)) {
-                                               goto scan_out;
+                                               WL_ERR(("Failed to add interworking IE"));
                                        }
                                } else if (cfg->iw_ie_len != 0) {
                                /* we have to clear IW IE and disable gratuitous APR */
@@ -2621,7 +2696,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                                        /* we don't care about error */
                                }
 #endif /* WL11U */
-                               err = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx,
+                               err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev, bssidx,
                                        VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie,
                                        request->ie_len);
 
@@ -2635,7 +2710,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
                ssids = this_ssid;
        }
 
-       if (request && !p2p_scan(cfg)) {
+       if (request && cfg->p2p && !p2p_scan(cfg)) {
                WL_TRACE_HW4(("START SCAN\n"));
        }
 
@@ -2672,6 +2747,14 @@ scan_out:
        if (err == BCME_BUSY || err == BCME_NOTREADY) {
                WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY));
                err = -EBUSY;
+       } else if ((err == BCME_EPERM) && cfg->scan_suppressed) {
+               WL_ERR(("Scan not permitted due to scan suppress\n"));
+               err = -EPERM;
+       } else {
+               /* For all other fw errors, use a generic error code as return
+                * value to cfg80211 stack
+                */
+               err = -EAGAIN;
        }
 
 #define SCAN_EBUSY_RETRY_LIMIT 10
@@ -2741,10 +2824,7 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
 
        err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
        if (unlikely(err)) {
-               if ((err == BCME_EPERM) && cfg->scan_suppressed)
-                       WL_DBG(("scan not permitted at this time (%d)\n", err));
-               else
-                       WL_ERR(("scan error (%d)\n", err));
+               WL_ERR(("scan error (%d)\n", err));
                return err;
        }
 
@@ -2995,7 +3075,8 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
        WL_TRACE(("In\n"));
        RETURN_EIO_IF_NOT_UP(cfg);
        WL_INFO(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
-       if (!params->ssid || params->ssid_len <= 0) {
+       if (!params->ssid || params->ssid_len <= 0 ||
+               params->ssid_len > DOT11_MAX_SSID_LEN) {
                WL_ERR(("Invalid parameter\n"));
                return -EINVAL;
        }
@@ -3166,6 +3247,297 @@ static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return err;
 }
 
+s32
+wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
+       struct net_device *ndev, s32 bsscfg_idx,
+       enum nl80211_iftype iface_type, s32 del, u8 *addr)
+{
+       s32 ret = BCME_OK;
+       s32 val = 0;
+
+       struct {
+               s32 cfg;
+               s32 val;
+               struct ether_addr ea;
+       } bss_setbuf;
+
+       WL_INFO(("iface_type:%d del:%d \n", iface_type, del));
+
+       bzero(&bss_setbuf, sizeof(bss_setbuf));
+
+       /* AP=3, STA=2, up=1, down=0, val=-1 */
+       if (del) {
+               val = -1;
+       } else if (iface_type == NL80211_IFTYPE_AP) {
+               /* AP Interface */
+               WL_DBG(("Adding AP Interface \n"));
+               val = 3;
+       } else if (iface_type == NL80211_IFTYPE_STATION) {
+               WL_DBG(("Adding STA Interface \n"));
+               val = 2;
+       } else {
+               WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type));
+               return -EINVAL;
+       }
+
+       bss_setbuf.cfg = htod32(bsscfg_idx);
+       bss_setbuf.val = htod32(val);
+
+       if (addr) {
+               memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
+       }
+
+       ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+               cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+       if (ret != 0)
+               WL_ERR(("'bss %d' failed with %d\n", val, ret));
+
+       return ret;
+}
+
+#if defined(WL_VIRTUAL_APSTA)
+/* Create a Generic Network Interface and initialize it depending up on
+ * the interface type
+ */
+bcm_struct_cfgdev*
+wl_cfg80211_create_iface(struct wiphy *wiphy,
+       enum nl80211_iftype iface_type,
+       u8 *mac_addr, const char *name)
+{
+       struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+       struct net_device *new_ndev = NULL;
+       struct net_device *primary_ndev = NULL;
+       s32 ret = BCME_OK;
+       s32 bsscfg_idx = 0;
+       u32 timeout;
+       wl_if_event_info *event = NULL;
+       struct wireless_dev *wdev = NULL;
+       u8 addr[ETH_ALEN];
+
+       WL_DBG(("Enter\n"));
+
+       if (!name) {
+               WL_ERR(("Interface name not provided\n"));
+               return NULL;
+       }
+
+       if (cfg->bss_cfgdev) {
+               WL_ERR(("More than one virtual interface is not needed/supported\n"));
+               return NULL;
+       }
+
+#ifdef DHD_IFDEBUG
+       primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+       WL_ERR(("cfg=%p, primary_ndev=%p, ifname=%s\n", cfg, primary_ndev, name));
+#endif
+
+       /* If any scan is going on, abort it */
+       if (wl_get_drv_status_all(cfg, SCANNING)) {
+               int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+               WL_ERR(("Scan in progress. Aborting the scan!\n"));
+               wl_cfg80211_scan_abort(cfg);
+               while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
+                       WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+                       wait_cnt--;
+                       OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+               }
+               if (!wait_cnt && wl_get_drv_status_all(cfg, SCANNING)) {
+                       WL_ERR(("Failed to abort scan\n"));
+                       return NULL;
+               }
+       }
+
+       primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+       if (likely(!mac_addr)) {
+               /* Use primary MAC with the locally administered bit for the
+                *  Secondary STA I/F
+                */
+               memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
+               addr[0] |= 0x02;
+
+               /* MAC Adress for virtual interface
+                */
+               addr[3] ^= 0xA0;
+       } else {
+               /* Use the application provided mac address (if any) */
+               memcpy(addr, mac_addr, ETH_ALEN);
+       }
+
+       if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) {
+               WL_ERR(("IFACE type:%d not supported. STA "
+                                       "or AP IFACE is only supported\n", iface_type));
+               return NULL;
+       }
+
+       cfg->bss_pending_op = TRUE;
+       memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+
+       /* p2p-disc takes bsscfgidx=1 */
+       bsscfg_idx = 2;
+
+       /*
+        * Intialize the firmware I/F.
+        */
+       if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
+               bsscfg_idx, iface_type, 0, addr)) < 0) {
+               WL_ERR(("Interface create failed!! ret(%d)\n", ret));
+               return NULL;
+       }
+
+       WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
+
+       /*
+        * Wait till the firmware send a confirmation event back.
+        */
+       WL_DBG(("Wait for the FW I/F Event\n"));
+       timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+               !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+       if (timeout <= 0 || cfg->bss_pending_op) {
+               WL_ERR(("timeout in waiting IF_ADD event\n"));
+               goto fail;
+       }
+
+       /*
+        * Since FW operation is successful,we can go ahead with the
+        * the host interface creation.
+        */
+       event = &cfg->if_event_info;
+       new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
+               (char*)name, addr, event->bssidx, event->name);
+       if (!new_ndev) {
+               WL_ERR(("I/F allocation failed! \n"));
+               goto fail;
+       } else {
+               WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
+                       event->ifidx, event->bssidx));
+       }
+
+       wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+       if (!wdev) {
+               WL_ERR(("wireless_dev alloc failed! \n"));
+               goto fail;
+       }
+
+       wdev->wiphy = wiphy;
+       wdev->iftype = iface_type;
+       new_ndev->ieee80211_ptr = wdev;
+       SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
+
+#ifdef DHD_IFDEBUG
+       WL_ERR(("wdev=%p, new_ndev=%p\n", wdev, new_ndev));
+#endif
+
+       /* RTNL lock must have been acquired. */
+       ASSERT_RTNL();
+
+       /* Set the locally administed mac addr, if not applied already */
+       if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
+               ret = wldev_iovar_setbuf_bsscfg(new_ndev, "cur_etheraddr",
+                       addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+                       event->bssidx, &cfg->ioctl_buf_sync);
+               if (unlikely(ret)) {
+                       WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
+                       goto fail;
+               }
+               memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
+       }
+
+       if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+               WL_ERR(("IFACE register failed \n"));
+               goto fail;
+       }
+
+       /* Initialize with the station mode params */
+       wl_alloc_netinfo(cfg, new_ndev, wdev,
+               (iface_type == NL80211_IFTYPE_STATION) ?
+               WL_MODE_BSS : WL_MODE_AP, PM_ENABLE, event->bssidx);
+       cfg->bss_cfgdev = ndev_to_cfgdev(new_ndev);
+       cfg->cfgdev_bssidx = event->bssidx;
+
+       WL_DBG(("Host Network Interface for Secondary I/F created"));
+
+#ifdef DHD_IFDEBUG
+       WL_ERR(("cfg->bss_cfgdev=%p\n", cfg->bss_cfgdev));
+#endif
+
+       return cfg->bss_cfgdev;
+
+fail:
+       cfg->bss_pending_op = FALSE;
+       cfg->cfgdev_bssidx = -1;
+       if (wdev)
+               kfree(wdev);
+       if (new_ndev)
+               wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+
+#ifdef DHD_IFDEBUG
+       WL_ERR(("failed!!!\n"));
+#endif
+
+       return NULL;
+}
+
+s32
+wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
+{
+       struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+       struct net_device *ndev = NULL;
+#ifdef DHD_IFDEBUG
+       struct net_device *primary_ndev = NULL;
+#endif
+       s32 ret = BCME_OK;
+       u32 timeout = 0;
+       enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
+
+       WL_ERR(("Enter\n"));
+
+       if (!cfg->bss_cfgdev) {
+               WL_ERR(("There is no virtual interface found\n"));
+               return 0;
+       }
+
+       /* If any scan is going on, abort it */
+       if (wl_get_drv_status_all(cfg, SCANNING)) {
+               WL_ERR(("Scan in progress. Aborting the scan!\n"));
+               wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+       }
+
+       ndev = (struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg);
+#ifdef DHD_IFDEBUG
+       primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+       WL_ERR(("cfg->bss_cfgdev=%p, ndev=%p, primary_ndev=%p\n",
+               cfg->bss_cfgdev, ndev, primary_ndev));
+#endif
+
+       cfg->bss_pending_op = TRUE;
+       memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+
+       /* Delete the firmware interface. "interface_remove" command
+        * should go on the interface to be deleted
+        */
+       if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
+               cfg->cfgdev_bssidx, iface_type, true, NULL)) < 0) {
+               WL_ERR(("DEL bss failed ret:%d \n", ret));
+               goto exit;
+       }
+
+       timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+               !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+       if (timeout <= 0 || cfg->bss_pending_op) {
+               WL_ERR(("timeout in waiting IF_DEL event\n"));
+       }
+
+exit:
+       cfg->bss_cfgdev = NULL;
+       cfg->cfgdev_bssidx = -1;
+       cfg->bss_pending_op = FALSE;
+
+       WL_ERR(("IF_DEL Done.\n"));
+
+       return ret;
+}
+#endif /* defined(WL_VIRTUAL_APSTA) */
+
 
 static s32
 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
@@ -3175,7 +3547,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
        s32 val = 0;
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -3212,7 +3584,8 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
        s32 val = 0;
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -3257,7 +3630,8 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
        s32 wsec_val = 0;
 
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -3339,7 +3713,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
        s32 val = 0;
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -3360,8 +3735,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
                                val = WPA_AUTH_PSK;
                                break;
                        default:
-                               WL_ERR(("invalid cipher group (%d)\n",
-                                       sme->crypto.cipher_group));
+                               WL_ERR(("invalid akm suite (0x%x)\n",
+                                       sme->crypto.akm_suites[0]));
                                return -EINVAL;
                        }
                } else if (val & (WPA2_AUTH_PSK |
@@ -3374,8 +3749,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
                                val = WPA2_AUTH_PSK;
                                break;
                        default:
-                               WL_ERR(("invalid cipher group (%d)\n",
-                                       sme->crypto.cipher_group));
+                               WL_ERR(("invalid akm suite (0x%x)\n",
+                                       sme->crypto.akm_suites[0]));
                                return -EINVAL;
                        }
                }
@@ -3403,7 +3778,8 @@ wl_set_set_sharedkey(struct net_device *dev,
        s32 val;
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -3596,12 +3972,16 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                        WL_DBG(("Currently not associated!\n"));
        } else {
                /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */
-               wait_cnt = 500/10;
+               wait_cnt = 200/10;
                while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
                        WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt));
                        wait_cnt--;
                        OSL_SLEEP(10);
                }
+               if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
+                       WL_ERR(("Force clear DISCONNECTING status!\n"));
+                       wl_clr_drv_status(cfg, DISCONNECTING, dev);
+               }
        }
 
        /* Clean BSSID */
@@ -3611,11 +3991,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
 
        if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
                /* we only allow to connect using virtual interface in case of P2P */
-                       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
-                               WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+                       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+                               WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
                                return BCME_ERROR;
                        }
-                       wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
+                       wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
                                VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
        } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
                /* find the RSN_IE */
@@ -3639,11 +4019,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                                cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
                }
 
-               if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
-                       WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+               if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+                       WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
                        return BCME_ERROR;
                }
-               err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
+               err = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
                        VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len);
                if (unlikely(err)) {
                        return err;
@@ -3757,8 +4137,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        }
        wl_set_drv_status(cfg, CONNECTING, dev);
 
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
-               WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+               WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
                kfree(ext_join_params);
                return BCME_ERROR;
        }
@@ -3838,16 +4218,19 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
                        wl_notify_escan_complete(cfg, dev, true, true);
                }
 #endif /* ESCAN_RESULT_PATCH */
-               wl_set_drv_status(cfg, DISCONNECTING, dev);
-               scbval.val = reason_code;
-               memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
-               scbval.val = htod32(scbval.val);
-               err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
-                       sizeof(scb_val_t), true);
-               if (unlikely(err)) {
-                       wl_clr_drv_status(cfg, DISCONNECTING, dev);
-                       WL_ERR(("error (%d)\n", err));
-                       return err;
+               if (wl_get_drv_status(cfg, CONNECTING, dev) ||
+                       wl_get_drv_status(cfg, CONNECTED, dev)) {
+                               wl_set_drv_status(cfg, DISCONNECTING, dev);
+                               scbval.val = reason_code;
+                               memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+                               scbval.val = htod32(scbval.val);
+                               err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+                                               sizeof(scb_val_t), true);
+                               if (unlikely(err)) {
+                                       wl_clr_drv_status(cfg, DISCONNECTING, dev);
+                                       WL_ERR(("error (%d)\n", err));
+                                       return err;
+                               }
                }
        }
 #ifdef CUSTOM_SET_CPUCORE
@@ -3861,7 +4244,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
        /* cfg80211 expects disconnect event from DHD to release wdev->current_bss */
-       cfg80211_disconnected(dev, reason_code, NULL, 0, false, GFP_KERNEL);
+       CFG80211_DISCONNECTED(dev, reason_code, NULL, 0, false, GFP_KERNEL);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
 
        return err;
@@ -3945,7 +4328,8 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
        s32 wsec;
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -3979,7 +4363,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
        s32 err = 0;
        s32 bssidx;
        s32 mode = wl_get_mode_by_netdev(cfg, dev);
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -4093,6 +4478,51 @@ wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable)
        return err;
 }
 
+#if defined(WL_VIRTUAL_APSTA)
+int
+wl_cfg80211_interface_create(struct net_device *dev, char *name)
+{
+       struct bcm_cfg80211 *cfg = g_bcm_cfg;
+       bcm_struct_cfgdev *new_cfgdev;
+
+       new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+                       NL80211_IFTYPE_STATION, NULL, name);
+       if (!new_cfgdev) {
+               return BCME_ERROR;
+       }
+       else {
+               WL_DBG(("Iface %s created successfuly\n", name));
+               return BCME_OK;
+       }
+}
+
+int
+wl_cfg80211_interface_delete(struct net_device *dev, char *name)
+{
+       struct bcm_cfg80211 *cfg = g_bcm_cfg;
+       struct net_info *iter, *next;
+       int err = BCME_ERROR;
+
+       if (name == NULL) {
+               WL_ERR(("Iface name is NULL.\n"));
+               return BCME_ERROR;
+       }
+
+       for_each_ndev(cfg, iter, next) {
+               if (iter->ndev) {
+                       if (strcmp(iter->ndev->name, name) == 0) {
+                               err =  wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev);
+                               break;
+                       }
+               }
+       }
+       if (!err) {
+               WL_DBG(("Iface %s deleted successfuly", name));
+       }
+       return err;
+}
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
 static s32
 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        u8 key_idx, bool pairwise, const u8 *mac_addr,
@@ -4109,7 +4539,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        WL_DBG(("key index (%d)\n", key_idx));
        RETURN_EIO_IF_NOT_UP(cfg);
 
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -4207,7 +4637,8 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
        struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -4254,7 +4685,8 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
        s32 wsec;
        s32 err = 0;
        s32 bssidx;
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -4326,6 +4758,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy,
        s32 rate;
        s32 err = 0;
        sta_info_t *sta;
+       struct ether_addr bssid;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
        s8 eabuf[ETHER_ADDR_STR_LEN];
 #endif
@@ -4359,7 +4792,6 @@ wl_cfg80211_get_station(struct wiphy *wiphy,
                wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) {
                get_pktcnt_t pktcnt;
                u8 *curmacp;
-               struct ether_addr bssid;
 
                if (cfg->roam_offload) {
                        err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
@@ -4378,7 +4810,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy,
                        }
                }
                if (!wl_get_drv_status(cfg, CONNECTED, dev) ||
-                       (dhd_is_associated(dhd, NULL, &err) == FALSE)) {
+                       (dhd_is_associated(dhd, 0, &err) == FALSE)) {
                        WL_ERR(("NOT assoc\n"));
                        if (err == -ERESTARTSYS)
                                return err;
@@ -4449,7 +4881,7 @@ get_station_err:
                        /* Disconnect due to zero BSSID or error to get RSSI */
                        WL_ERR(("force cfg80211_disconnected: %d\n", err));
                        wl_clr_drv_status(cfg, CONNECTED, dev);
-                       cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL);
+                       CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
                        wl_link_down(cfg);
                }
        }
@@ -5200,6 +5632,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
 #endif
        dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
 
+       int32 requested_dwell = af_params->dwell_time;
 
        /* Add the default dwell time
         * Dwell time to stay off-channel to wait for a response action frame
@@ -5251,6 +5684,15 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
                                cfg->next_af_subtype = action + 1;
 
                                af_params->dwell_time = WL_MED_DWELL_TIME;
+                               if (requested_dwell & CUSTOM_RETRY_MASK) {
+                                       config_af_params.max_tx_retry =
+                                               (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
+                                       af_params->dwell_time =
+                                               (requested_dwell & ~CUSTOM_RETRY_MASK);
+                                       WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
+                                               config_af_params.max_tx_retry,
+                                               af_params->dwell_time));
+                               }
                        } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
                                action == P2PSD_ACTION_ID_GAS_CRESP) {
                                /* configure service discovery response frame */
@@ -5339,7 +5781,7 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
        /* search peer's channel */
        if (config_af_params.search_channel) {
                /* initialize afx_hdl */
-               if (wl_cfgp2p_find_idx(cfg, dev, &cfg->afx_hdl->bssidx) != BCME_OK) {
+               if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                        WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                        goto exit;
                }
@@ -5498,7 +5940,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
                bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
        }
        else {
-               if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+               if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev_to_wdev(dev))) < 0) {
                        WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                        return BCME_ERROR;
                }
@@ -5532,7 +5974,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
                        if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
                                bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
                        }
-                       wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
+                       wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
                                VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len);
                        cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
                        goto exit;
@@ -5780,11 +6222,18 @@ change_bw:
 #ifdef CUSTOM_SET_CPUCORE
        if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
                WL_DBG(("SoftAP mode do not need to set cpucore\n"));
-       } else if ((dev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) &&
-               (chspec & WL_CHANSPEC_BW_80)) {
-               /* If GO is vht80 */
-               dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
-               dhd_set_cpucore(dhd, TRUE);
+       } else if (chspec & WL_CHANSPEC_BW_80) {
+               /* SoftAp only mode do not need to set cpucore */
+               if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
+                       dev != bcmcfg_to_prmry_ndev(cfg)) {
+                       /* Soft AP on virtual Iface (AP+STA case) */
+                       dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
+                       dhd_set_cpucore(dhd, TRUE);
+               } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
+                       /* If P2P IF is vht80 */
+                       dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
+                       dhd_set_cpucore(dhd, TRUE);
+               }
        }
 #endif
        return err;
@@ -6124,6 +6573,12 @@ wl_cfg80211_bcn_validate_sec(
        s32 bssidx)
 {
        struct bcm_cfg80211 *cfg = g_bcm_cfg;
+       wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
+
+       if (!bss) {
+               WL_ERR(("cfgbss is NULL \n"));
+               return BCME_ERROR;
+       }
 
        if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
                /* For P2P GO, the sec type is WPA2-PSK */
@@ -6139,43 +6594,43 @@ wl_cfg80211_bcn_validate_sec(
                if ((ies->wpa2_ie || ies->wpa_ie) &&
                        ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx)  < 0 ||
                        wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
-                       cfg->ap_info->security_mode = false;
+                       bss->security_mode = false;
                        return BCME_ERROR;
                }
 
-               cfg->ap_info->security_mode = true;
-               if (cfg->ap_info->rsn_ie) {
-                       kfree(cfg->ap_info->rsn_ie);
-                       cfg->ap_info->rsn_ie = NULL;
+               bss->security_mode = true;
+               if (bss->rsn_ie) {
+                       kfree(bss->rsn_ie);
+                       bss->rsn_ie = NULL;
                }
-               if (cfg->ap_info->wpa_ie) {
-                       kfree(cfg->ap_info->wpa_ie);
-                       cfg->ap_info->wpa_ie = NULL;
+               if (bss->wpa_ie) {
+                       kfree(bss->wpa_ie);
+                       bss->wpa_ie = NULL;
                }
-               if (cfg->ap_info->wps_ie) {
-                       kfree(cfg->ap_info->wps_ie);
-                       cfg->ap_info->wps_ie = NULL;
+               if (bss->wps_ie) {
+                       kfree(bss->wps_ie);
+                       bss->wps_ie = NULL;
                }
                if (ies->wpa_ie != NULL) {
                        /* WPAIE */
-                       cfg->ap_info->rsn_ie = NULL;
-                       cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie,
+                       bss->rsn_ie = NULL;
+                       bss->wpa_ie = kmemdup(ies->wpa_ie,
                                ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
                                GFP_KERNEL);
                } else if (ies->wpa2_ie != NULL) {
                        /* RSNIE */
-                       cfg->ap_info->wpa_ie = NULL;
-                       cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie,
+                       bss->wpa_ie = NULL;
+                       bss->rsn_ie = kmemdup(ies->wpa2_ie,
                                ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
                                GFP_KERNEL);
                }
                if (!ies->wpa2_ie && !ies->wpa_ie) {
                        wl_validate_opensecurity(dev, bssidx);
-                       cfg->ap_info->security_mode = false;
+                       bss->security_mode = false;
                }
 
                if (ies->wps_ie) {
-                       cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+                       bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
                }
        }
 
@@ -6212,16 +6667,16 @@ static s32 wl_cfg80211_bcn_set_params(
        }
 
        if ((info->ssid) && (info->ssid_len > 0) &&
-               (info->ssid_len <= 32)) {
+               (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
                WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
                if (dev_role == NL80211_IFTYPE_AP) {
                        /* Store the hostapd SSID */
-                       memset(cfg->hostapd_ssid.SSID, 0x00, 32);
+                       memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
                        memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
                        cfg->hostapd_ssid.SSID_len = info->ssid_len;
                } else {
                                /* P2P GO */
-                       memset(cfg->p2p->ssid.SSID, 0x00, 32);
+                       memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
                        memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
                        cfg->p2p->ssid.SSID_len = info->ssid_len;
                }
@@ -6284,7 +6739,7 @@ wl_cfg80211_bcn_bringup_ap(
        s32 pm;
        s32 err = BCME_OK;
 
-       WL_DBG(("Enter dev_role: %d\n", dev_role));
+       WL_DBG(("Enter dev_role:%d bssidx:%d\n", dev_role, bssidx));
 
        /* Common code for SoftAP and P2P GO */
        wldev_iovar_setint(dev, "mpc", 0);
@@ -6318,30 +6773,50 @@ wl_cfg80211_bcn_bringup_ap(
                        WL_DBG(("Bss is already up\n"));
        } else if ((dev_role == NL80211_IFTYPE_AP) &&
                (wl_get_drv_status(cfg, AP_CREATING, dev))) {
+
                /* Device role SoftAP */
-               err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
-               if (err < 0) {
-                       WL_ERR(("WLC_DOWN error %d\n", err));
-                       goto exit;
-               }
-               err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
-               if (err < 0) {
-                       WL_ERR(("SET INFRA error %d\n", err));
-                       goto exit;
-               }
-               if ((err = wldev_iovar_setint(dev, "apsta", 0)) < 0) {
-                       WL_ERR(("wl apsta 0 error %d\n", err));
-                       goto exit;
-               }
-               if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
-                       WL_ERR(("setting AP mode failed %d \n", err));
-                       goto exit;
-               }
+               WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
 
-               pm = 0;
-               if ((err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true)) != 0) {
-                       WL_ERR(("wl PM 0 returned error:%d\n", err));
-                       goto exit;
+               if (bssidx == 0) {
+                       if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
+                               NL80211_IFTYPE_AP, 0, NULL)) < 0) {
+                               WL_DBG(("wl add_del_bss returned error (%d)\n", err));
+                               err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
+                               if (err < 0) {
+                                       WL_ERR(("WLC_DOWN error %d\n", err));
+                                       goto exit;
+                               }
+                               if ((err = wldev_iovar_setint(dev, "apsta", 0)) < 0) {
+                                       WL_ERR(("wl apsta 0 error %d\n", err));
+                                       goto exit;
+                               }
+                               if ((err = wldev_ioctl(dev,
+                                       WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
+                                       WL_ERR(("setting AP mode failed %d \n", err));
+                                       goto exit;
+                               }
+                       }
+
+                       pm = 0;
+                       if ((err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true)) != 0) {
+                               WL_ERR(("wl PM 0 returned error:%d\n", err));
+                               goto exit;
+                       }
+
+                       err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+                       if (err < 0) {
+                               WL_ERR(("SET INFRA error %d\n", err));
+                               goto exit;
+                       }
+               } else if (cfg->cfgdev_bssidx && (bssidx == cfg->cfgdev_bssidx)) {
+
+                       WL_DBG(("Bringup SoftAP on virtual Interface bssidx:%d \n", bssidx));
+
+                       if ((err = wl_cfg80211_add_del_bss(cfg, dev,
+                               bssidx, NL80211_IFTYPE_AP, 0, NULL)) < 0) {
+                               WL_ERR(("wl bss ap returned error:%d\n", err));
+                               goto exit;
+                       }
                }
 
 
@@ -6354,9 +6829,11 @@ wl_cfg80211_bcn_bringup_ap(
                memset(&join_params, 0, sizeof(join_params));
                /* join parameters starts with ssid */
                join_params_size = sizeof(join_params.ssid);
+               join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
+                       (uint32)DOT11_MAX_SSID_LEN);
                memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
-                       cfg->hostapd_ssid.SSID_len);
-               join_params.ssid.SSID_len = htod32(cfg->hostapd_ssid.SSID_len);
+                       join_params.ssid.SSID_len);
+               join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
 
                /* create softap */
                if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
@@ -6364,6 +6841,8 @@ wl_cfg80211_bcn_bringup_ap(
                        WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID));
                        wl_clr_drv_status(cfg, AP_CREATING, dev);
                        wl_set_drv_status(cfg, AP_CREATED, dev);
+               } else {
+                       WL_ERR(("SoftAP set SSID (%s) failed!\n", join_params.ssid.SSID));
                }
        }
 
@@ -6432,7 +6911,7 @@ wl_cfg80211_set_ies(
        s32 err = BCME_OK;
 
        /* Set Beacon IEs to FW */
-       if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
+       if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
                VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
                info->tail_len)) < 0) {
                WL_ERR(("Set Beacon IE Failed \n"));
@@ -6455,7 +6934,7 @@ wl_cfg80211_set_ies(
        }
 
        /* Set Probe Response IEs to FW */
-       if ((err = wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
+       if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
                VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
                WL_ERR(("Set Probe Resp IE Failed \n"));
        } else {
@@ -6473,54 +6952,59 @@ static s32 wl_cfg80211_hostapd_sec(
 {
        bool update_bss = 0;
        struct bcm_cfg80211 *cfg = g_bcm_cfg;
+       wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
 
+       if (!bss) {
+               WL_ERR(("cfgbss is NULL \n"));
+               return -EINVAL;
+       }
 
        if (ies->wps_ie) {
-               if (cfg->ap_info->wps_ie &&
-                       memcmp(cfg->ap_info->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
+               if (bss->wps_ie &&
+                       memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
                        WL_DBG((" WPS IE is changed\n"));
-                       kfree(cfg->ap_info->wps_ie);
-                       cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
-               } else if (cfg->ap_info->wps_ie == NULL) {
+                       kfree(bss->wps_ie);
+                       bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+               } else if (bss->wps_ie == NULL) {
                        WL_DBG((" WPS IE is added\n"));
-                       cfg->ap_info->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+                       bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
                }
 
                if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
-                       if (!cfg->ap_info->security_mode) {
+                       if (!bss->security_mode) {
                                /* change from open mode to security mode */
                                update_bss = true;
                                if (ies->wpa_ie != NULL) {
-                                       cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie,
+                                       bss->wpa_ie = kmemdup(ies->wpa_ie,
                                        ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
                                        GFP_KERNEL);
                                } else {
-                                       cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie,
+                                       bss->rsn_ie = kmemdup(ies->wpa2_ie,
                                        ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
                                        GFP_KERNEL);
                                }
-                       } else if (cfg->ap_info->wpa_ie) {
+                       } else if (bss->wpa_ie) {
                                /* change from WPA2 mode to WPA mode */
                                if (ies->wpa_ie != NULL) {
                                        update_bss = true;
-                                       kfree(cfg->ap_info->rsn_ie);
-                                       cfg->ap_info->rsn_ie = NULL;
-                                       cfg->ap_info->wpa_ie = kmemdup(ies->wpa_ie,
+                                       kfree(bss->rsn_ie);
+                                       bss->rsn_ie = NULL;
+                                       bss->wpa_ie = kmemdup(ies->wpa_ie,
                                        ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
                                        GFP_KERNEL);
-                               } else if (memcmp(cfg->ap_info->rsn_ie,
+                               } else if (memcmp(bss->rsn_ie,
                                        ies->wpa2_ie, ies->wpa2_ie->len
                                        + WPA_RSN_IE_TAG_FIXED_LEN)) {
                                        update_bss = true;
-                                       kfree(cfg->ap_info->rsn_ie);
-                                       cfg->ap_info->rsn_ie = kmemdup(ies->wpa2_ie,
+                                       kfree(bss->rsn_ie);
+                                       bss->rsn_ie = kmemdup(ies->wpa2_ie,
                                        ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
                                        GFP_KERNEL);
-                                       cfg->ap_info->wpa_ie = NULL;
+                                       bss->wpa_ie = NULL;
                                }
                        }
                        if (update_bss) {
-                               cfg->ap_info->security_mode = true;
+                               bss->security_mode = true;
                                wl_cfgp2p_bss(cfg, dev, bssidx, 0);
                                if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx)  < 0 ||
                                        wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
@@ -6549,7 +7033,7 @@ wl_cfg80211_del_station(struct wiphy *wiphy,
 static s32
 wl_cfg80211_del_station(struct wiphy *wiphy,
        struct net_device *ndev, u8* mac_addr)
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
 {
        struct net_device *dev;
        struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
@@ -6591,6 +7075,18 @@ wl_cfg80211_del_station(struct wiphy *wiphy,
        else
                num_associated = assoc_maclist->count;
 
+#ifdef REMOVE_P2PIE_BEFORE_DELIF
+       if (num_associated > 0 && ETHER_ISBCAST(mac_addr) && p2p_is_on(cfg))
+       {
+               s32 bssidx = -1;
+               if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+                       WL_ERR(("Find p2p index from ndev(%p) failed\n", dev));
+               } else {
+                       wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
+               }
+       }
+#endif /* REMOVE_P2PIE_BEFORE_DELIF */
+
        memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
        scb_val.val = DOT11_RC_DEAUTH_LEAVING;
        err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
@@ -6661,8 +7157,14 @@ wl_cfg80211_start_ap(
        u32 dev_role = 0;
        dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
 
+#ifdef WL11U
+       bcm_tlv_t *interworking_ie;
+#endif
+
        WL_DBG(("Enter \n"));
-       if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+
+       if ((dev == bcmcfg_to_prmry_ndev(cfg)) ||
+               (dev == ((struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)))) {
                WL_DBG(("Start AP req on primary iface: Softap\n"));
                dev_role = NL80211_IFTYPE_AP;
        }
@@ -6676,7 +7178,8 @@ wl_cfg80211_start_ap(
                dev_role = NL80211_IFTYPE_P2P_GO;
        }
 #endif /* WL_ENABLE_P2P_IF */
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
@@ -6687,19 +7190,6 @@ wl_cfg80211_start_ap(
        } else if (dev_role == NL80211_IFTYPE_AP) {
                WL_DBG(("Start AP req\n"));
                dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
-               /*
-                * Enabling Softap is causing issues with STA NDO operations
-                * as NDO is not interface specific. So disable NDO while
-                * Softap is enabled
-                */
-               err = dhd_ndo_enable(dhd, FALSE);
-               WL_DBG(("%s: Disabling NDO on Hostapd mode %d\n", __FUNCTION__, err));
-               if (err) {
-                       /* Non fatal error. */
-                       WL_ERR(("%s: Disabling NDO Failed %d\n", __FUNCTION__, err));
-               } else {
-                       cfg->revert_ndo_disable = true;
-               }
 
 #ifdef PKT_FILTER_SUPPORT
                /* Disable packet filter */
@@ -6767,6 +7257,31 @@ wl_cfg80211_start_ap(
        }
 #endif /* WL_CFG80211_ACL */
 
+#ifdef WL11U
+       /* Add interworking IE from beacon data */
+       if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+               (u8 *)info->beacon.beacon_ies, info->beacon.beacon_ies_len)) != NULL) {
+               err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+                               VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+                               interworking_ie->data, interworking_ie->len);
+               if (unlikely(err)) {
+                       WL_ERR(("Failed to add interworking IE"));
+               }
+       } else if (cfg->iw_ie_len != 0) {
+               /* we have to clear IW IE and disable gratuitous APR */
+               wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+                       VNDR_IE_CUSTOM_FLAG,
+                       DOT11_MNG_INTERWORKING_ID,
+                       0, 0);
+
+               (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0, bssidx);
+               cfg->wl11u = FALSE;
+               cfg->iw_ie_len = 0;
+               memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
+               /* we don't care about error */
+       }
+#endif /* WL11U */
+
        /* Set IEs to FW */
        if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
                WL_ERR(("Set IEs failed \n"));
@@ -6805,10 +7320,8 @@ wl_cfg80211_stop_ap(
 
        WL_DBG(("Enter \n"));
 
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
-               WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
-               return BCME_ERROR;
-       }
+       wl_clr_drv_status(cfg, AP_CREATING, dev);
+       wl_clr_drv_status(cfg, AP_CREATED, dev);
 
        if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
                dev_role = NL80211_IFTYPE_AP;
@@ -6821,6 +7334,11 @@ wl_cfg80211_stop_ap(
                return -EINVAL;
        }
 
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+               WL_ERR(("find bss index from wdev(%p) failed\n", dev->ieee80211_ptr));
+               return BCME_ERROR;
+       }
+
        if (!check_dev_role_integrity(cfg, dev_role))
                goto exit;
 
@@ -6832,15 +7350,6 @@ wl_cfg80211_stop_ap(
                /* SoftAp on primary Interface.
                 * Shut down AP and turn on MPC
                 */
-               if (cfg->revert_ndo_disable == true) {
-                       err = dhd_ndo_enable(dhd, TRUE);
-                       WL_DBG(("%s: Enabling back NDO on Softap turn off %d\n",
-                               __FUNCTION__, err));
-                       if (err) {
-                               WL_ERR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, err));
-                       }
-                       cfg->revert_ndo_disable = false;
-               }
 
 #ifdef PKT_FILTER_SUPPORT
                /* Enable packet filter */
@@ -6856,35 +7365,42 @@ wl_cfg80211_stop_ap(
                        dhd_arp_offload_enable(dhd, TRUE);
                }
 #endif /* ARP_OFFLOAD_SUPPORT */
-               if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
-                       WL_ERR(("setting AP mode failed %d \n", err));
-                       err = -ENOTSUPP;
-                       goto exit;
-               }
-               err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
-               if (err < 0) {
-                       WL_ERR(("SET INFRA error %d\n", err));
-                       err = -ENOTSUPP;
-                       goto exit;
-               }
 
-               err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
-               if (unlikely(err)) {
-                       WL_ERR(("WLC_UP error (%d)\n", err));
-                       err = -EINVAL;
-                       goto exit;
+               /*
+                * Bring down the AP interface by changing role to STA.
+                * Don't do a down or "WLC_SET_AP 0" since the shared
+                * interface may be still running
+                */
+
+               WL_DBG(("Bring down AP interface by changing role to STA\n"));
+
+               if ((err = wl_cfg80211_add_del_bss(cfg, dev,
+                       bssidx, NL80211_IFTYPE_STATION, 0, NULL)) < 0) {
+                       WL_DBG(("wl add_del_bss returned error (%d)\n", err));
+                       if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
+                               WL_ERR(("setting AP mode failed %d \n", err));
+                               err = -ENOTSUPP;
+                               goto exit;
+                       }
+                       err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+                       if (err < 0) {
+                               WL_ERR(("SET INFRA error %d\n", err));
+                               err = -ENOTSUPP;
+                               goto exit;
+                       }
+
+                       err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
+                       if (unlikely(err)) {
+                               WL_ERR(("WLC_UP error (%d)\n", err));
+                               err = -EINVAL;
+                               goto exit;
+                       }
                }
 
-               wl_clr_drv_status(cfg, AP_CREATED, dev);
                /* Turn on the MPC */
                wldev_iovar_setint(dev, "mpc", 1);
-               if (cfg->ap_info) {
-                       kfree(cfg->ap_info->wpa_ie);
-                       kfree(cfg->ap_info->rsn_ie);
-                       kfree(cfg->ap_info->wps_ie);
-                       kfree(cfg->ap_info);
-                       cfg->ap_info = NULL;
-               }
+
+               wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
        } else {
                WL_DBG(("Stopping P2P GO \n"));
                DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
@@ -6912,10 +7428,14 @@ wl_cfg80211_change_beacon(
        u32 dev_role = 0;
        s32 bssidx = 0;
        bool pbc = 0;
+#ifdef WL11U
+       bcm_tlv_t *interworking_ie;
+#endif
 
        WL_DBG(("Enter \n"));
 
-       if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+       if ((dev == bcmcfg_to_prmry_ndev(cfg)) ||
+               (dev == ((struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)))) {
                dev_role = NL80211_IFTYPE_AP;
        }
 #if defined(WL_ENABLE_P2P_IF)
@@ -6927,13 +7447,12 @@ wl_cfg80211_change_beacon(
                dev_role = NL80211_IFTYPE_P2P_GO;
        }
 #endif /* WL_ENABLE_P2P_IF */
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
-       if (p2p_is_on(cfg) &&
-               (bssidx == wl_to_p2p_bss_bssidx(cfg,
-               P2PAPI_BSSCFG_CONNECTION))) {
+
+       if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
                dev_role = NL80211_IFTYPE_P2P_GO;
        }
 
@@ -6951,6 +7470,31 @@ wl_cfg80211_change_beacon(
                WL_ERR(("Set IEs failed \n"));
                goto fail;
        }
+#ifdef WL11U
+       /* Add interworking IE from beacon data */
+       if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+               (u8 *)info->beacon_ies, info->beacon_ies_len)) != NULL) {
+               err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+                               VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+                               interworking_ie->data, interworking_ie->len);
+               if (unlikely(err)) {
+                       WL_ERR(("Failed to add interworking IE"));
+               }
+       } else if (cfg->iw_ie_len != 0) {
+               /* we have to clear IW IE and disable gratuitous APR */
+               wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+                       VNDR_IE_CUSTOM_FLAG,
+                       DOT11_MNG_INTERWORKING_ID,
+                       0, 0);
+
+               (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0, bssidx);
+               cfg->wl11u = FALSE;
+               cfg->iw_ie_len = 0;
+               memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
+               /* we don't care about error */
+       }
+#endif /* WL11U */
+
 
        if (dev_role == NL80211_IFTYPE_AP) {
                if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
@@ -6985,6 +7529,8 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
        struct parsed_ies ies;
        bcm_tlv_t *ssid_ie;
        bool pbc = 0;
+       dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
        WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
                info->interval, info->dtim_period, info->head_len, info->tail_len));
 
@@ -7000,14 +7546,16 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                dev_role = NL80211_IFTYPE_P2P_GO;
        }
 #endif /* WL_ENABLE_P2P_IF */
-       if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+
+       if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
                WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                return BCME_ERROR;
        }
-       if (p2p_is_on(cfg) &&
-               (bssidx == wl_to_p2p_bss_bssidx(cfg,
-               P2PAPI_BSSCFG_CONNECTION))) {
+
+       if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
                dev_role = NL80211_IFTYPE_P2P_GO;
+       } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
+               dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
        }
 
        if (!check_dev_role_integrity(cfg, dev_role))
@@ -7020,14 +7568,16 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                DOT11_MNG_SSID_ID)) != NULL) {
                if (dev_role == NL80211_IFTYPE_AP) {
                        /* Store the hostapd SSID */
-                       memset(&cfg->hostapd_ssid.SSID[0], 0x00, 32);
-                       memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data, ssid_ie->len);
-                       cfg->hostapd_ssid.SSID_len = ssid_ie->len;
+                       memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+                       cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
+                       memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
+                               cfg->hostapd_ssid.SSID_len);
                } else {
                                /* P2P GO */
-                       memset(&cfg->p2p->ssid.SSID[0], 0x00, 32);
-                       memcpy(cfg->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len);
-                       cfg->p2p->ssid.SSID_len = ssid_ie->len;
+                       memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+                       cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
+                       memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
+                               cfg->p2p->ssid.SSID_len);
                }
        }
 
@@ -7038,7 +7588,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
                goto fail;
        }
 
-       if (wl_cfgp2p_set_management_ie(cfg, dev, bssidx,
+       if (wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
                VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
                info->tail_len) < 0) {
                WL_ERR(("Beacon set IEs failed \n"));
@@ -7145,8 +7695,10 @@ wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
        if (request->n_match_sets > 0) {
                for (i = 0; i < request->n_match_sets; i++) {
                        ssid = &request->match_sets[i].ssid;
-                       memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len);
-                       ssids_local[i].SSID_len = ssid->ssid_len;
+                       ssids_local[ssid_count].SSID_len = MIN(ssid->ssid_len,
+                               (uint32)DOT11_MAX_SSID_LEN);
+                       memcpy(ssids_local[ssid_count].SSID, ssid->ssid,
+                               ssids_local[ssid_count].SSID_len);
                        WL_PNO((">>> PNO filter set for ssid (%s) \n", ssid->ssid));
                        ssid_count++;
                }
@@ -7320,7 +7872,7 @@ static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
        if (!band || idx >= band->n_channels) {
                /* Move to 5G band */
                band = wiphy->bands[NL80211_BAND_5GHZ];
-               if (idx >= band->n_channels) {
+               if (!band || idx >= band->n_channels) {
                        return -ENOENT;
                }
        }
@@ -8348,6 +8900,8 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                                scb_val_t scbval;
                                u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
                                s32 reason = 0;
+                               struct ether_addr bssid;
+
                                if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND)
                                        reason = ntoh32(e->reason);
                                /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */
@@ -8357,8 +8911,16 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                                        "event : %d, reason=%d from " MACDBG "\n",
                                        ndev->name, event, ntoh32(e->reason),
                                        MAC2STRDBG((u8*)(&e->addr)));
-                               if (!cfg->roam_offload &&
-                                       memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
+
+                               /* roam offload does not synch BSSID always, get it from dongle */
+                               if (cfg->roam_offload) {
+                                       if (wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, sizeof(bssid),
+                                               false) == BCME_OK) {
+                                               curbssid = (u8 *)&bssid;
+                                       }
+                               }
+
+                               if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
                                        WL_ERR(("BSSID of event is not the connected BSSID"
                                                "(ignore it) cur: " MACDBG " event: " MACDBG"\n",
                                                MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr))));
@@ -8381,10 +8943,10 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
                                                WL_ERR(("WLC_DISASSOC error %d\n", err));
                                                err = 0;
                                        }
-                                       cfg80211_disconnected(ndev, reason, NULL, 0, false, GFP_KERNEL);
+                                       CFG80211_DISCONNECTED(ndev, reason, NULL, 0,
+                                                             false, GFP_KERNEL);
                                        wl_link_down(cfg);
                                        wl_init_prof(cfg, ndev);
-                                       memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
                                }
                        }
                        else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
@@ -8808,12 +9370,12 @@ wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                        if (wl_get_chan_isvht80(ndev, dhd)) {
                                if (ndev == bcmcfg_to_prmry_ndev(cfg))
                                        dhd->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
-                               else if (ndev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION))
+                               else if (is_p2p_group_iface(dev->ieee80211_ptr))
                                        dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
                                dhd_set_cpucore(dhd, TRUE);
                        }
 #endif /* CUSTOM_SET_CPUCORE */
-
+                       memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
                }
                cfg80211_connect_result(ndev,
                        curbssid,
@@ -8878,7 +9440,7 @@ wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
 #ifndef WL_SCHED_SCAN
        mutex_lock(&cfg->usr_sync);
        /* TODO: Use cfg80211_sched_scan_results(wiphy); */
-       cfg80211_disconnected(ndev, 0, NULL, 0, false, GFP_KERNEL);
+       CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
        mutex_unlock(&cfg->usr_sync);
 #else
        /* If cfg80211 scheduled scan is supported, report the pno results via sched
@@ -9065,10 +9627,21 @@ wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
        u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
        u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
        bool retval;
+       dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
 
        memset(&bssid, 0, ETHER_ADDR_LEN);
 
-       ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+       if (cfg->bss_cfgdev &&
+               (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) &&
+               event == WLC_E_PROBREQ_MSG) {
+               /* Handle probe reqs frame
+                * WPS-AP certification 4.2.13
+                */
+               ndev = cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg);
+               cfgdev = cfg->bss_cfgdev;
+       } else {
+               ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+       }
 #ifdef P2PONEINT
        WL_DBG((" device name is ndev %s \n", ndev->name));
 #endif
@@ -9531,11 +10104,6 @@ static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
                WL_ERR(("pmk list alloc failed\n"));
                goto init_priv_mem_out;
        }
-       cfg->sta_info = (void *)kzalloc(sizeof(*cfg->sta_info), GFP_KERNEL);
-       if (unlikely(!cfg->sta_info)) {
-               WL_ERR(("sta info  alloc failed\n"));
-               goto init_priv_mem_out;
-       }
 
 #if defined(STATIC_WL_PRIV_STRUCT)
        cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL);
@@ -9587,8 +10155,6 @@ static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
        cfg->extra_buf = NULL;
        kfree(cfg->pmk_list);
        cfg->pmk_list = NULL;
-       kfree(cfg->sta_info);
-       cfg->sta_info = NULL;
 #if defined(STATIC_WL_PRIV_STRUCT)
        kfree(cfg->conn_info);
        cfg->conn_info = NULL;
@@ -9602,13 +10168,6 @@ static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
                cfg->afx_hdl = NULL;
        }
 
-       if (cfg->ap_info) {
-               kfree(cfg->ap_info->wpa_ie);
-               kfree(cfg->ap_info->rsn_ie);
-               kfree(cfg->ap_info->wps_ie);
-               kfree(cfg->ap_info);
-               cfg->ap_info = NULL;
-       }
 #ifdef WLTDLS
        if (cfg->tdls_mgmt_frame) {
                kfree(cfg->tdls_mgmt_frame);
@@ -9684,7 +10243,7 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
        switch (state) {
                case NETDEV_DOWN:
                {
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
                        int max_wait_timeout = 2;
                        int max_wait_count = 100;
                        int refcnt = 0;
@@ -9714,13 +10273,15 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
                                set_current_state(TASK_RUNNING);
                                refcnt++;
                        }
-#endif /* LINUX_VERSION <  VERSION(3, 14, 0) */
+#endif /* LINUX_VERSION <  VERSION(3, 11, 0) */
                        break;
                }
 
                case NETDEV_UNREGISTER:
                        /* after calling list_del_rcu(&wdev->list) */
-                       wl_dealloc_netinfo(cfg, dev);
+                       wl_cfg80211_clear_per_bss_ies(cfg,
+                               wl_get_bssidx_by_wdev(cfg, wdev));
+                       wl_dealloc_netinfo_by_wdev(cfg, wdev);
                        break;
                case NETDEV_GOING_DOWN:
                        /* At NETDEV_DOWN state, wdev_cleanup_work work will be called.
@@ -10267,21 +10828,24 @@ static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
                return;
        }
        for_each_ndev(cfg, iter, next) {
-               chanspec = 0;
-               ctl_chan = 0;
-               if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
-                       if (wldev_iovar_getint(iter->ndev, "chanspec",
-                               (s32 *)&chanspec) == BCME_OK) {
-                               chanspec = wl_chspec_driver_to_host(chanspec);
-                               ctl_chan = wf_chspec_ctlchan(chanspec);
-                               wl_update_prof(cfg, iter->ndev, NULL,
-                                       &ctl_chan, WL_PROF_CHAN);
-                       }
-                       if (!cfg->vsdb_mode) {
-                               if (!pre_ctl_chan && ctl_chan)
-                                       pre_ctl_chan = ctl_chan;
-                               else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
-                                       cfg->vsdb_mode = true;
+               /* p2p discovery iface ndev could be null */
+               if (iter->ndev) {
+                       chanspec = 0;
+                       ctl_chan = 0;
+                       if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
+                               if (wldev_iovar_getint(iter->ndev, "chanspec",
+                                       (s32 *)&chanspec) == BCME_OK) {
+                                       chanspec = wl_chspec_driver_to_host(chanspec);
+                                       ctl_chan = wf_chspec_ctlchan(chanspec);
+                                       wl_update_prof(cfg, iter->ndev, NULL,
+                                               &ctl_chan, WL_PROF_CHAN);
+                               }
+                               if (!cfg->vsdb_mode) {
+                                       if (!pre_ctl_chan && ctl_chan)
+                                               pre_ctl_chan = ctl_chan;
+                                       else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
+                                               cfg->vsdb_mode = true;
+                                       }
                                }
                        }
                }
@@ -10326,7 +10890,7 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_
                        }
                        pm = PM_OFF;
                        for_each_ndev(cfg, iter, next) {
-                               if (iter->pm_restore)
+                               if (iter->pm_restore || (iter->ndev == NULL))
                                        continue;
                                /* Save the current power mode */
                                err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
@@ -10339,15 +10903,17 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_
 
                        }
                        for_each_ndev(cfg, iter, next) {
-                               if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
-                                       continue;
-                               if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
-                                       sizeof(pm), true)) != 0) {
-                                       if (err == -ENODEV)
-                                               WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
-                                       else
-                                               WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
-                                       wl_cfg80211_update_power_mode(iter->ndev);
+                               if (iter->ndev) {
+                                       if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
+                                               continue;
+                                       if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
+                                               sizeof(pm), true)) != 0) {
+                                               if (err == -ENODEV)
+                                                       WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+                                               else
+                                                       WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+                                               wl_cfg80211_update_power_mode(iter->ndev);
+                                       }
                                }
                        }
                } else {
@@ -10363,7 +10929,7 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_
                        pm = PM_OFF;
                        if (!_net_info->pm_block) {
                                for_each_ndev(cfg, iter, next) {
-                                       if (iter->pm_restore)
+                                       if (iter->pm_restore || (iter->ndev == NULL))
                                                continue;
                                        /* Save the current power mode */
                                        err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
@@ -10376,14 +10942,17 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_
                                }
                        }
                        for_each_ndev(cfg, iter, next) {
-                               if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
-                                       continue;
-                               if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
-                                       sizeof(pm), true)) != 0) {
-                                       if (err == -ENODEV)
-                                               WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
-                                       else
-                                               WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+                               /* p2p discovery iface ndev ptr could be null */
+                               if (iter->ndev) {
+                                       if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
+                                               continue;
+                                       if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
+                                               sizeof(pm), true)) != 0) {
+                                               if (err == -ENODEV)
+                                                       WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+                                               else
+                                                       WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+                                       }
                                }
                        }
 
@@ -10412,20 +10981,23 @@ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_
                wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
                wl_cfg80211_determine_vsdb_mode(cfg);
                for_each_ndev(cfg, iter, next) {
-                       if (iter->pm_restore && iter->pm) {
-                               WL_DBG(("%s:restoring power save %s\n",
-                                       iter->ndev->name, (iter->pm ? "enabled" : "disabled")));
-                               err = wldev_ioctl(iter->ndev,
-                                       WLC_SET_PM, &iter->pm, sizeof(iter->pm), true);
-                               if (unlikely(err)) {
-                                       if (err == -ENODEV)
-                                               WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
-                                       else
-                                               WL_ERR(("%s:error(%d)\n", iter->ndev->name, err));
-                                       break;
+                       /* p2p discovery iface ndev ptr could be null */
+                       if (iter->ndev) {
+                               if (iter->pm_restore && iter->pm) {
+                                       WL_DBG(("%s:restoring power save %s\n",
+                                               iter->ndev->name, (iter->pm ? "enabled" : "disabled")));
+                                       err = wldev_ioctl(iter->ndev,
+                                               WLC_SET_PM, &iter->pm, sizeof(iter->pm), true);
+                                       if (unlikely(err)) {
+                                               if (err == -ENODEV)
+                                                       WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+                                               else
+                                                       WL_ERR(("%s:error(%d)\n", iter->ndev->name, err));
+                                               break;
+                                       }
+                                       iter->pm_restore = 0;
+                                       wl_cfg80211_update_power_mode(iter->ndev);
                                }
-                               iter->pm_restore = 0;
-                               wl_cfg80211_update_power_mode(iter->ndev);
                        }
                }
                wl_cfg80211_concurrent_roam(cfg, 0);
@@ -10465,11 +11037,10 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
        cfg->active_scan = true;
        cfg->rf_blocked = false;
        cfg->vsdb_mode = false;
-#if defined(BCMSDIO)
        cfg->wlfc_on = false;
-#endif 
        cfg->roamoff_on_concurrent = true;
        cfg->disable_roam_event = false;
+       cfg->cfgdev_bssidx = -1;
        /* register interested state */
        set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
        spin_lock_init(&cfg->cfgdrv_lock);
@@ -10549,7 +11120,7 @@ static s32  wl_cfg80211_detach_p2p(void)
 
        cfg->p2p_wdev = NULL;
        cfg->p2p_net = NULL;
-       WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev));
+       WL_DBG(("Freeing 0x%p \n", wdev));
        kfree(wdev);
 
        return 0;
@@ -10656,11 +11227,12 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
        cfg->wdev = wdev;
        cfg->pub = context;
        INIT_LIST_HEAD(&cfg->net_list);
+       spin_lock_init(&cfg->net_list_sync);
        ndev->ieee80211_ptr = wdev;
        SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
        wdev->netdev = ndev;
        cfg->state_notifier = wl_notifier_change_state;
-       err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE);
+       err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE, 0);
        if (err) {
                WL_ERR(("Failed to alloc net_info (%d)\n", err));
                goto cfg80211_attach_out;
@@ -10753,6 +11325,7 @@ void wl_cfg80211_detach(void *para)
 #endif 
 
        wl_cfg80211_ibss_vsie_free(cfg);
+       wl_cfg80211_clear_mgmt_vndr_ies(cfg);
        wl_deinit_priv(cfg);
        g_bcm_cfg = NULL;
        wl_cfg80211_clear_parent_dev();
@@ -10765,7 +11338,9 @@ void wl_cfg80211_detach(void *para)
 
 static void wl_wakeup_event(struct bcm_cfg80211 *cfg)
 {
-       if (cfg->event_tsk.thr_pid >= 0) {
+       dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+       if (dhd->up && (cfg->event_tsk.thr_pid >= 0)) {
                DHD_OS_WAKE_LOCK(cfg->pub);
                up(&cfg->event_tsk.sema);
        }
@@ -10826,6 +11401,9 @@ static s32 wl_event_handler(void *data)
        struct wl_event_q *e;
        tsk_ctl_t *tsk = (tsk_ctl_t *)data;
        bcm_struct_cfgdev *cfgdev = NULL;
+#if defined(WL_CFG80211_P2P_DEV_IF)
+       struct net_device *ndev = NULL;
+#endif /* WL_CFG80211_P2P_DEV_IF */
 
        cfg = (struct bcm_cfg80211 *)tsk->parent;
 
@@ -10850,8 +11428,11 @@ static s32 wl_event_handler(void *data)
                        if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) {
 #endif
                                cfgdev = bcmcfg_to_p2p_wdev(cfg);
+                       } else if (cfg->bss_cfgdev && (e->emsg.bsscfgidx == cfg->cfgdev_bssidx)) {
+                               /* STA / AP on virtual interface */
+                               cfgdev = (ndev = cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)) ?
+                                       ndev_to_wdev(ndev) : NULL;
                        } else {
-                               struct net_device *ndev = NULL;
 
                                ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx);
                                if (ndev)
@@ -10876,6 +11457,9 @@ static s32 wl_event_handler(void *data)
 #elif defined(WL_ENABLE_P2P_IF)
                        if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_net)) {
                                cfgdev = cfg->p2p_net;
+                       } else if (cfg->bss_cfgdev && (e->emsg.bsscfgidx == cfg->cfgdev_bssidx)) {
+                               /* STA / AP on virtual interface */
+                               cfgdev = cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg);
                        } else {
                                cfgdev = dhd_idx2net((struct dhd_pub *)(cfg->pub),
                                        e->emsg.ifidx);
@@ -10912,6 +11496,7 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
 {
        u32 event_type = ntoh32(e->event_type);
        struct bcm_cfg80211 *cfg = g_bcm_cfg;
+       struct net_info *netinfo;
 
 #if (WL_DBG_LEVEL > 0)
        s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
@@ -10919,23 +11504,29 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
        WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
 #endif /* (WL_DBG_LEVEL > 0) */
 
+       if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
+               WL_ERR(("Stale event ignored\n"));
+               return;
+       }
        if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) {
                WL_ERR(("during IF change, ignore event %d\n", event_type));
                return;
        }
 
-       if (ndev != bcmcfg_to_prmry_ndev(cfg) && cfg->p2p_supported) {
-               if (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) &&
-#if defined(WL_ENABLE_P2P_IF)
-                       (ndev != (cfg->p2p_net ? cfg->p2p_net :
-                       wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE))) &&
-#else
-                       (ndev != wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE)) &&
-#endif /* WL_ENABLE_P2P_IF */
-                       TRUE) {
-                       WL_ERR(("ignore event %d, not interested\n", event_type));
-                       return;
-               }
+#ifdef DHD_IFDEBUG
+       if (event_type != WLC_E_ESCAN_RESULT) {
+               WL_ERR(("Event_type %d , status : %d, reason : %d, bssidx:%d \n",
+                       event_type, ntoh32(e->status), ntoh32(e->reason), e->bsscfgidx));
+       }
+#endif
+       netinfo = wl_get_netinfo_by_bssidx(cfg, e->bsscfgidx);
+       if (!netinfo) {
+               /* Since the netinfo entry is not there, the netdev entry is not
+                * created via cfg80211 interface. so the event is not of interest
+                * to the cfg80211 layer.
+                */
+               WL_ERR(("%d : ignore event %d, not interested\n", __LINE__, event_type));
+               return;
        }
 
        if (event_type == WLC_E_PFN_NET_FOUND) {
@@ -11653,11 +12244,8 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
 #if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) && !defined(PLATFORM_SLP)
        struct net_device *p2p_net = cfg->p2p_net;
 #endif 
-       u32 bssidx = 0;
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
        dhd_pub_t *dhd =  (dhd_pub_t *)(cfg->pub);
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
        WL_DBG(("In\n"));
        /* Delete pm_enable_work */
@@ -11670,8 +12258,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
        if (cfg->p2p_supported) {
                wl_clr_p2p_status(cfg, GO_NEG_PHASE);
 #ifdef PROP_TXSTATUS_VSDB
-#if defined(BCMSDIO)
-               if (cfg->p2p->vif_created) {
+               if (wl_cfgp2p_vif_created(cfg)) {
                        bool enabled = false;
                        dhd_wlfc_get_enable(dhd, &enabled);
                        if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
@@ -11680,7 +12267,6 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
                                cfg->wlfc_on = false;
                        }
                }
-#endif 
 #endif /* PROP_TXSTATUS_VSDB */
        }
 
@@ -11692,14 +12278,17 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
 
 
        /* If primary BSS is operational (for e.g SoftAP), bring it down */
-       if (!(wl_cfgp2p_find_idx(cfg, ndev, &bssidx)) &&
-               wl_cfgp2p_bss_isup(ndev, bssidx)) {
-               if (wl_cfgp2p_bss(cfg, ndev, bssidx, 0) < 0)
+       if (wl_cfgp2p_bss_isup(ndev, 0)) {
+               if (wl_cfgp2p_bss(cfg, ndev, 0, 0) < 0)
                        WL_ERR(("BSS down failed \n"));
        }
 
-       for_each_ndev(cfg, iter, next)
-               wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+       for_each_ndev(cfg, iter, next) {
+               /* p2p discovery iface ndev ptr could be null */
+               if (iter->ndev) {
+                       wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+               }
+       }
 
 
        spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
@@ -11716,7 +12305,7 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
        for_each_ndev(cfg, iter, next) {
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
                if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
-                       cfg80211_disconnected(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
+                       CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
                }
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
                wl_clr_drv_status(cfg, READY, iter->ndev);
@@ -11754,15 +12343,15 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
                del_timer_sync(&cfg->scan_timeout);
        }
 
-       if (cfg->ap_info) {
-               kfree(cfg->ap_info->wpa_ie);
-               kfree(cfg->ap_info->rsn_ie);
-               kfree(cfg->ap_info->wps_ie);
-               kfree(cfg->ap_info);
-               cfg->ap_info = NULL;
-       }
        dhd_monitor_uninit();
 
+#if defined(WL_VIRTUAL_APSTA)
+       /* Clean up if not removed already */
+       if (cfg->bss_cfgdev) {
+               wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev);
+       }
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
 #ifdef WL11U
        /* Clear interworking element. */
        if (cfg->wl11u) {
@@ -11772,6 +12361,11 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
        }
 #endif /* WL11U */
 
+#ifdef DHD_IFDEBUG
+       /* Printout all netinfo entries */
+       wl_probe_wdev_all(cfg);
+#endif /* DHD_IFDEBUG */
+
        return err;
 }
 
@@ -11803,8 +12397,13 @@ s32 wl_cfg80211_up(void *para)
        dhd = (dhd_pub_t *)(cfg->pub);
        if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
                err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
-               if (unlikely(err))
+               if (unlikely(err)) {
+                       mutex_unlock(&cfg->usr_sync);
                        return err;
+               }
+       }  else {
+               WL_ERR(("Disable p2p support in hostap mode\n"));
+               cfg->p2p_supported = FALSE;
        }
        err = __wl_cfg80211_up(cfg);
        if (unlikely(err))
@@ -11838,7 +12437,7 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason)
        } else
 #endif /* SOFTAP_SEND_HANGEVT */
        {
-               cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL);
+               CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
        }
        if (cfg != NULL) {
                wl_link_down(cfg);
@@ -11910,8 +12509,8 @@ wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                ssid = (wlc_ssid_t *) data;
                memset(profile->ssid.SSID, 0,
                        sizeof(profile->ssid.SSID));
-               memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
-               profile->ssid.SSID_len = ssid->SSID_len;
+               profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
+               memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
                break;
        case WL_PROF_BSSID:
                if (data)
@@ -11994,27 +12593,43 @@ static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
 static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam)
 {
        u8 *ssidie;
+       int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
+       int32 remaining_ie_buf_len, available_buffer_len;
        ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
+
+       /* ERROR out if
+        * 1. No ssid IE is FOUND or
+        * 2. New ssid length is > what was allocated for existing ssid (as
+        * we do not want to overwrite the rest of the IEs) or
+        * 3. If in case of erroneous buffer input where ssid length doesnt match the space
+        * allocated to it.
+        */
        if (!ssidie)
                return;
-       if (ssidie[1] != bi->SSID_len) {
+       available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
+       remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
+       if ((ssid_len > ssidie[1]) ||
+               (ssidie[1] > available_buffer_len)) {
+                       return;
+       }
+       if (ssidie[1] != ssid_len) {
                if (ssidie[1]) {
                        WL_ERR(("%s: Wrong SSID len: %d != %d\n",
                                __FUNCTION__, ssidie[1], bi->SSID_len));
                }
                if (roam) {
                        WL_ERR(("Changing the SSID Info.\n"));
-                       memmove(ssidie + bi->SSID_len + 2,
+                       memmove(ssidie + ssid_len + 2,
                                (ssidie + 2) + ssidie[1],
                                *ie_size - (ssidie + 2 + ssidie[1] - ie_stream));
-                       memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
-                       *ie_size = *ie_size + bi->SSID_len - ssidie[1];
-                       ssidie[1] = bi->SSID_len;
+                       memcpy(ssidie + 2, bi->SSID, ssid_len);
+                       *ie_size = *ie_size + ssid_len - ssidie[1];
+                       ssidie[1] = ssid_len;
                }
                return;
        }
        if (*(ssidie + 2) == '\0')
-                memcpy(ssidie + 2, bi->SSID, bi->SSID_len);
+                memcpy(ssidie + 2, bi->SSID, ssid_len);
        return;
 }
 
@@ -12380,14 +12995,12 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
                                goto exit;
                        }
                }
-               if (net  != bcmcfg_to_prmry_ndev(cfg)) {
-                       if (wl_get_mode_by_netdev(cfg, net) == WL_MODE_AP) {
-                               ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION);
-                               bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION);
-                       }
+               if (net  == bcmcfg_to_prmry_ndev(cfg)) {
+                       ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+                       bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
                } else {
-                               ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
-                               bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+                       ndev = net;
+                       bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
                }
        }
        if (ndev != NULL) {
@@ -12403,7 +13016,7 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
                                break;
                }
                if (pktflag)
-                       ret = wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, pktflag, buf, len);
+                       ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev, bssidx, pktflag, buf, len);
        }
 exit:
        return ret;
@@ -12485,7 +13098,7 @@ wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec)
        return valid;
 }
 
-static s32
+s32
 wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
 {
        s32 ret = BCME_ERROR;
@@ -12513,7 +13126,7 @@ wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
        return ret;
 }
 
-static s32
+s32
 wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
 {
        u32 channel = 0;
@@ -12942,7 +13555,7 @@ static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
                ((dev_role == NL80211_IFTYPE_P2P_GO) &&
                !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
        {
-               WL_ERR(("device role select failed\n"));
+               WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
                return false;
        }
        return true;
@@ -13151,11 +13764,12 @@ static void wl_cfg80211_work_handler(struct work_struct * work)
        if (cfg->pm_enable_work_on) {
                cfg->pm_enable_work_on = false;
                for_each_ndev(cfg, iter, next) {
-                       if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
-                               (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
-                               wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
-                               continue;
+                       /* p2p discovery iface ndev could be null */
                        if (iter->ndev) {
+                               if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
+                                       (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
+                                       wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
+                                       continue;
                                if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM,
                                        &pm, sizeof(pm), true)) != 0) {
                                        if (err == -ENODEV)
@@ -13216,6 +13830,317 @@ wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
 }
 
 
+static s32
+wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len,
+    struct parsed_vndr_ies *vndr_ies)
+{
+       s32 err = BCME_OK;
+       vndr_ie_t *vndrie;
+       bcm_tlv_t *ie;
+       struct parsed_vndr_ie_info *parsed_info;
+       u32 count = 0;
+       s32 remained_len;
+
+       remained_len = (s32)len;
+       memset(vndr_ies, 0, sizeof(*vndr_ies));
+
+       WL_INFO(("---> len %d\n", len));
+       ie = (bcm_tlv_t *) parse;
+       if (!bcm_valid_tlv(ie, remained_len))
+               ie = NULL;
+       while (ie) {
+               if (count >= MAX_VNDR_IE_NUMBER)
+                       break;
+               if (ie->id == DOT11_MNG_VS_ID) {
+                       vndrie = (vndr_ie_t *) ie;
+                       /* len should be bigger than OUI length + one data length at least */
+                       if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
+                               WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
+                                       __FUNCTION__, vndrie->len));
+                               goto end;
+                       }
+                       /* if wpa or wme ie, do not add ie */
+                       if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
+                               ((vndrie->data[0] == WPA_OUI_TYPE) ||
+                               (vndrie->data[0] == WME_OUI_TYPE))) {
+                               CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
+                               goto end;
+                       }
+
+                       parsed_info = &vndr_ies->ie_info[count++];
+
+                       /* save vndr ie information */
+                       parsed_info->ie_ptr = (char *)vndrie;
+                       parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
+                       memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
+                       vndr_ies->count = count;
+
+                       WL_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x len:%d\n",
+                       parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1],
+                       parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0],
+                       parsed_info->ie_len));
+               }
+end:
+               ie = bcm_next_tlv(ie, &remained_len);
+       }
+       return err;
+}
+
+s32
+wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+       s32 index;
+       struct net_info *netinfo;
+       s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
+               VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
+
+       netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+       if (!netinfo || !netinfo->wdev) {
+               WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
+               return -1;
+       }
+
+       WL_DBG(("clear management vendor IEs for bssidx:%d \n", bssidx));
+       /* Clear the IEs set in the firmware so that host is in sync with firmware */
+       for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
+               if (wl_cfg80211_set_mgmt_vndr_ies(cfg, netinfo->ndev,
+                       bssidx, vndrie_flag[index], NULL, 0) < 0)
+                       WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
+       }
+
+       return 0;
+}
+
+s32
+wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
+{
+       struct net_info *iter, *next;
+
+       WL_DBG(("clear management vendor IEs \n"));
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+       4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+       for_each_ndev(cfg, iter, next) {
+               wl_cfg80211_clear_per_bss_ies(cfg, iter->bssidx);
+       }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+       4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+       return 0;
+}
+
+#define WL_VNDR_IE_MAXLEN 2048
+static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
+int
+wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+       s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
+{
+       s32 ret = BCME_OK;
+       u8  *curr_ie_buf = NULL;
+       u8  *mgmt_ie_buf = NULL;
+       u32 mgmt_ie_buf_len = 0;
+       u32 *mgmt_ie_len = 0;
+       u32 del_add_ie_buf_len = 0;
+       u32 total_ie_buf_len = 0;
+       u32 parsed_ie_buf_len = 0;
+       struct parsed_vndr_ies old_vndr_ies;
+       struct parsed_vndr_ies new_vndr_ies;
+       s32 i;
+       u8 *ptr;
+       s32 remained_buf_len;
+       wl_bss_vndr_ies_t *ies = NULL;
+       struct net_info *netinfo;
+
+       WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d \n",
+               pktflag, bssidx, vndr_ie_len));
+
+       if (bssidx > WL_MAX_IFS) {
+               WL_ERR(("bssidx > supported concurrent Ifaces \n"));
+               return -EINVAL;
+       }
+
+       netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+       if (!netinfo) {
+               WL_ERR(("net_info ptr is NULL \n"));
+               return -EINVAL;
+       }
+
+       /* Clear the global buffer */
+       memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
+       curr_ie_buf = g_mgmt_ie_buf;
+       ies = &netinfo->bss.ies;
+
+       switch (pktflag) {
+               case VNDR_IE_PRBRSP_FLAG :
+                       mgmt_ie_buf = ies->probe_res_ie;
+                       mgmt_ie_len = &ies->probe_res_ie_len;
+                       mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
+                       break;
+               case VNDR_IE_ASSOCRSP_FLAG :
+                       mgmt_ie_buf = ies->assoc_res_ie;
+                       mgmt_ie_len = &ies->assoc_res_ie_len;
+                       mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
+                       break;
+               case VNDR_IE_BEACON_FLAG :
+                       mgmt_ie_buf = ies->beacon_ie;
+                       mgmt_ie_len = &ies->beacon_ie_len;
+                       mgmt_ie_buf_len = sizeof(ies->beacon_ie);
+                       break;
+               case VNDR_IE_PRBREQ_FLAG :
+                       mgmt_ie_buf = ies->probe_req_ie;
+                       mgmt_ie_len = &ies->probe_req_ie_len;
+                       mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
+                       break;
+               case VNDR_IE_ASSOCREQ_FLAG :
+                       mgmt_ie_buf = ies->assoc_req_ie;
+                       mgmt_ie_len = &ies->assoc_req_ie_len;
+                       mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
+                       break;
+               default:
+                       mgmt_ie_buf = NULL;
+                       mgmt_ie_len = NULL;
+                       WL_ERR(("not suitable packet type (%d)\n", pktflag));
+                       return BCME_ERROR;
+       }
+
+       if (vndr_ie_len > mgmt_ie_buf_len) {
+               WL_ERR(("extra IE size too big\n"));
+               ret = -ENOMEM;
+       } else {
+               /* parse and save new vndr_ie in curr_ie_buff before comparing it */
+               if (vndr_ie && vndr_ie_len && curr_ie_buf) {
+                       ptr = curr_ie_buf;
+/* must discard vndr_ie constness, attempt to change vndr_ie arg to non-const
+ * causes cascade of errors in other places, fix involves const casts there
+ */
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+       4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+                       if ((ret = wl_cfg80211_parse_vndr_ies((u8 *)vndr_ie,
+                               vndr_ie_len, &new_vndr_ies)) < 0) {
+                               WL_ERR(("parse vndr ie failed \n"));
+                               goto exit;
+                       }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+       4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+                       for (i = 0; i < new_vndr_ies.count; i++) {
+                               struct parsed_vndr_ie_info *vndrie_info =
+                                       &new_vndr_ies.ie_info[i];
+
+                               if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
+                                       WL_ERR(("IE size is too big (%d > %d)\n",
+                                               parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
+                                       ret = -EINVAL;
+                                       goto exit;
+                               }
+
+                               memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
+                                       vndrie_info->ie_len);
+                               parsed_ie_buf_len += vndrie_info->ie_len;
+                       }
+               }
+
+               if (mgmt_ie_buf != NULL) {
+                       if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
+                               (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
+                               WL_INFO(("Previous mgmt IE is equals to current IE"));
+                               goto exit;
+                       }
+
+                       /* parse old vndr_ie */
+                       if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
+                               &old_vndr_ies)) < 0) {
+                               WL_ERR(("parse vndr ie failed \n"));
+                               goto exit;
+                       }
+                       /* make a command to delete old ie */
+                       for (i = 0; i < old_vndr_ies.count; i++) {
+                               struct parsed_vndr_ie_info *vndrie_info =
+                               &old_vndr_ies.ie_info[i];
+
+                               WL_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
+                                       vndrie_info->vndrie.id, vndrie_info->vndrie.len,
+                                       vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
+                                       vndrie_info->vndrie.oui[2]));
+
+                               del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
+                                       pktflag, vndrie_info->vndrie.oui,
+                                       vndrie_info->vndrie.id,
+                                       vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
+                                       vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
+                                       "del");
+
+                               curr_ie_buf += del_add_ie_buf_len;
+                               total_ie_buf_len += del_add_ie_buf_len;
+                       }
+               }
+
+               *mgmt_ie_len = 0;
+               /* Add if there is any extra IE */
+               if (mgmt_ie_buf && parsed_ie_buf_len) {
+                       ptr = mgmt_ie_buf;
+
+                       remained_buf_len = mgmt_ie_buf_len;
+
+                       /* make a command to add new ie */
+                       for (i = 0; i < new_vndr_ies.count; i++) {
+                               struct parsed_vndr_ie_info *vndrie_info =
+                                       &new_vndr_ies.ie_info[i];
+
+                               WL_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n",
+                                       vndrie_info->vndrie.id, vndrie_info->vndrie.len,
+                                       vndrie_info->ie_len - 2,
+                                       vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
+                                       vndrie_info->vndrie.oui[2]));
+
+                               del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
+                                       pktflag, vndrie_info->vndrie.oui,
+                                       vndrie_info->vndrie.id,
+                                       vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
+                                       vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
+                                       "add");
+
+                               /* verify remained buf size before copy data */
+                               if (remained_buf_len >= vndrie_info->ie_len) {
+                                       remained_buf_len -= vndrie_info->ie_len;
+                               } else {
+                                       WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
+                                       "found vndr ies # = %d(cur %d), remained len %d, "
+                                       "cur mgmt_ie_len %d, new ie len = %d\n",
+                                       pktflag, new_vndr_ies.count, i, remained_buf_len,
+                                       *mgmt_ie_len, vndrie_info->ie_len));
+                                       break;
+                               }
+
+                               /* save the parsed IE in cfg struct */
+                               memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
+                                       vndrie_info->ie_len);
+                               *mgmt_ie_len += vndrie_info->ie_len;
+                               curr_ie_buf += del_add_ie_buf_len;
+                               total_ie_buf_len += del_add_ie_buf_len;
+                       }
+               }
+
+               if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
+                       ret  = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
+                               total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+                               bssidx, &cfg->ioctl_buf_sync);
+                       if (ret)
+                               WL_ERR(("vndr ie set error : %d\n", ret));
+               }
+       }
+exit:
+
+return ret;
+}
+
 #ifdef WL_CFG80211_ACL
 static int
 wl_cfg80211_set_mac_acl(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
@@ -13277,6 +14202,7 @@ int wl_chspec_chandef(chanspec_t chanspec,
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
 struct cfg80211_chan_def *chandef,
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+       \
        \
        0)))
 struct chan_info *chaninfo,
@@ -13342,6 +14268,7 @@ struct wiphy *wiphy)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
        cfg80211_chandef_create(chandef, ieee80211_get_channel(wiphy, freq), chan_type);
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+       \
        \
        0)))
        chaninfo->freq = freq;
@@ -13356,6 +14283,7 @@ wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wip
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
        struct cfg80211_chan_def chandef;
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+       \
        \
        0)))
        struct chan_info chaninfo;
@@ -13368,6 +14296,7 @@ wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wip
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
        if (wl_chspec_chandef(chanspec, &chandef, wiphy)) {
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+       \
        \
        0)))
        if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) {
@@ -13379,6 +14308,7 @@ wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wip
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
        cfg80211_ch_switch_notify(dev, &chandef);
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+       \
        \
        0)))
        cfg80211_ch_switch_notify(dev, chan_info.freq, chan_info.chan_type);
@@ -13432,3 +14362,43 @@ wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, int cmd_len)
        return wl_cfgnan_cmd_handler(ndev, g_bcm_cfg, cmd, cmd_len);
 }
 #endif /* WL_NAN */
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+int
+wl_cfg80211_set_spect(struct net_device *dev, int spect)
+{
+       struct bcm_cfg80211 *cfg = g_bcm_cfg;
+       int down = 1;
+       int up = 1;
+       int err = BCME_OK;
+
+       if (!wl_get_drv_status_all(cfg, CONNECTED)) {
+               err = wldev_ioctl(dev, WLC_DOWN, &down, sizeof(down), true);
+               if (err) {
+                       WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
+                       return err;
+               }
+
+               err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect), true);
+               if (err) {
+                       WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
+                       return err;
+               }
+
+               err = wldev_ioctl(dev, WLC_UP, &up, sizeof(up), true);
+               if (err) {
+                       WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
+                       return err;
+               }
+       }
+       return err;
+}
+
+int
+wl_cfg80211_get_sta_channel(struct net_device *dev)
+{
+       if (wl_get_drv_status(g_bcm_cfg, CONNECTED, dev)) {
+               return g_bcm_cfg->channel;
+       }
+       return BCME_OK;
+}
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
index b219d1d..5f363bf 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: wl_cfg80211.h 635212 2016-05-03 06:35:20Z $
+ * $Id: wl_cfg80211.h 662786 2016-11-11 09:06:37Z $
  */
 
 #ifndef _wl_cfg80211_h_
@@ -153,7 +153,7 @@ do {                                                                        \
 #define WL_MED_DWELL_TIME       400
 #define WL_MIN_DWELL_TIME      100
 #define WL_LONG_DWELL_TIME     1000
-#define IFACE_MAX_CNT          2
+#define IFACE_MAX_CNT          4
 #define WL_SCAN_CONNECT_DWELL_TIME_MS          200
 #define WL_SCAN_JOIN_PROBE_INTERVAL_MS                 20
 #define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS      320
@@ -346,6 +346,27 @@ struct wl_ibss {
        u8 channel;
 };
 
+typedef struct wl_bss_vndr_ies {
+       u8  probe_req_ie[VNDR_IES_BUF_LEN];
+       u8  probe_res_ie[VNDR_IES_MAX_BUF_LEN];
+       u8  assoc_req_ie[VNDR_IES_BUF_LEN];
+       u8  assoc_res_ie[VNDR_IES_BUF_LEN];
+       u8  beacon_ie[VNDR_IES_MAX_BUF_LEN];
+       u32 probe_req_ie_len;
+       u32 probe_res_ie_len;
+       u32 assoc_req_ie_len;
+       u32 assoc_res_ie_len;
+       u32 beacon_ie_len;
+} wl_bss_vndr_ies_t;
+
+typedef struct wl_cfgbss {
+       u8 *wpa_ie;
+       u8 *rsn_ie;
+       u8 *wps_ie;
+       bool security_mode;
+       struct wl_bss_vndr_ies ies;     /* Common for STA, P2P GC, GO, AP, P2P Disc Interface */
+} wl_cfgbss_t;
+
 /* cfg driver profile */
 struct wl_profile {
        u32 mode;
@@ -370,9 +391,17 @@ struct net_info {
        bool pm_restore;
        bool pm_block;
        s32 pm;
+       s32 bssidx;
+       wl_cfgbss_t bss;
        struct list_head list; /* list of all net_info structure */
 };
 
+#ifdef DHD_MAX_IFS
+#define WL_MAX_IFS DHD_MAX_IFS
+#else
+#define WL_MAX_IFS 16
+#endif
+
 /* association inform */
 #define MAX_REQ_LINE 1024
 struct wl_connect_info {
@@ -509,6 +538,7 @@ struct bcm_cfg80211 {
        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 net_list_sync;       /* to protect scan status (and others if needed) */
        spinlock_t eq_lock;     /* for event queue synchronization */
        spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */
        struct completion act_frm_scan;
@@ -556,9 +586,7 @@ struct bcm_cfg80211 {
        bool pwr_save;
        bool roam_on;           /* on/off switch for self-roaming */
        bool scan_tried;        /* indicates if first scan attempted */
-#if defined(BCMSDIO)
        bool wlfc_on;
-#endif 
        bool vsdb_mode;
        bool roamoff_on_concurrent;
        u8 *ioctl_buf;          /* ioctl buffer */
@@ -576,8 +604,6 @@ struct bcm_cfg80211 {
        wl_if_event_info if_event_info;
        struct completion send_af_done;
        struct afx_hdl *afx_hdl;
-       struct ap_info *ap_info;
-       struct sta_info *sta_info;
        struct p2p_info *p2p;
        bool p2p_supported;
        void *btcoex_info;
@@ -609,6 +635,9 @@ struct bcm_cfg80211 {
        u32 rmc_event_seq;
 #endif /* WL_RELMCAST */
        bool roam_offload;
+       bcm_struct_cfgdev *bss_cfgdev;  /* For DUAL STA/STA+AP */
+       s32 cfgdev_bssidx;
+       bool bss_pending_op;            /* indicate where there is a pending IF operation */
 #ifdef WLTDLS
        u8 *tdls_mgmt_frame;
        u32 tdls_mgmt_frame_len;
@@ -617,7 +646,6 @@ struct bcm_cfg80211 {
        bool nan_running;
        bool need_wait_afrx;
        struct ether_addr last_roamed_addr;
-       bool revert_ndo_disable;
 };
 
 
@@ -626,17 +654,109 @@ static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct
        return bss = bss ?
                (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
 }
+
+static inline void
+wl_probe_wdev_all(struct bcm_cfg80211 *cfg)
+{
+       struct net_info *_net_info, *next;
+       unsigned long int flags;
+       int idx = 0;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
+       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               WL_ERR(("%s: net_list[%d] bssidx: %d, "
+                       "ndev: %p, wdev: %p \n", __FUNCTION__,
+                       idx++, _net_info->bssidx,
+                       _net_info->ndev, _net_info->wdev));
+       }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return;
+}
+
+static inline struct net_info *
+wl_get_netinfo_by_bssidx(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+       struct net_info *_net_info, *next, *info = NULL;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
+       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               if ((bssidx >= 0) && (_net_info->bssidx == bssidx)) {
+                       info = _net_info;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return info;
+}
+
+static inline void
+wl_dealloc_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+       struct net_info *_net_info, *next;
+       unsigned long int flags;
+
+#ifdef DHD_IFDEBUG
+       WL_ERR(("dealloc_netinfo enter wdev=%p \n", wdev));
+#endif
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
+       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               if (wdev && (_net_info->wdev == wdev)) {
+                       wl_cfgbss_t *bss = &_net_info->bss;
+
+                       kfree(bss->wpa_ie);
+                       bss->wpa_ie = NULL;
+                       kfree(bss->rsn_ie);
+                       bss->rsn_ie = NULL;
+                       kfree(bss->wps_ie);
+                       bss->wps_ie = NULL;
+                       list_del(&_net_info->list);
+                       cfg->iface_cnt--;
+                       kfree(_net_info);
+               }
+       }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+#ifdef DHD_IFDEBUG
+       WL_ERR(("dealloc_netinfo exit iface_cnt=%d \n", cfg->iface_cnt));
+#endif
+}
+
 static inline s32
 wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev,
-       struct wireless_dev * wdev, s32 mode, bool pm_block)
+       struct wireless_dev * wdev, s32 mode, bool pm_block, u8 bssidx)
 {
        struct net_info *_net_info;
        s32 err = 0;
-       if (cfg->iface_cnt == IFACE_MAX_CNT)
+       unsigned long int flags;
+
+#ifdef DHD_IFDEBUG
+       WL_ERR(("alloc_netinfo enter bssidx=%d wdev=%p ndev=%p\n", bssidx, wdev, ndev));
+#endif
+       /* Check whether there is any duplicate entry for the
+        *  same bssidx *
+        */
+       if ((_net_info = wl_get_netinfo_by_bssidx(cfg, bssidx))) {
+               /* We have a duplicate entry for the same bssidx
+                * already present which shouldn't have been the case.
+                * Attempt recovery.
+                */
+               WL_ERR(("Duplicate entry for bssidx=%d present\n", bssidx));
+               wl_probe_wdev_all(cfg);
+#ifdef DHD_DEBUG
+               ASSERT(0);
+#endif /* DHD_DEBUG */
+               WL_ERR(("Removing the Dup entry for bssidx=%d \n", bssidx));
+               wl_dealloc_netinfo_by_wdev(cfg, _net_info->wdev);
+       }
+       if (cfg->iface_cnt == IFACE_MAX_CNT) {
+               WL_ERR(("Max interfaces (%d) reached.\n", IFACE_MAX_CNT));
                return -ENOMEM;
+       }
        _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL);
-       if (!_net_info)
+       if (!_net_info) {
+               WL_ERR(("Insufficient memory in the system.\n"));
                err = -ENOMEM;
+       }
        else {
                _net_info->mode = mode;
                _net_info->ndev = ndev;
@@ -645,37 +765,38 @@ wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev,
                _net_info->pm = 0;
                _net_info->pm_block = pm_block;
                _net_info->roam_off = WL_INVALID;
+               _net_info->bssidx = bssidx;
+               spin_lock_irqsave(&cfg->net_list_sync, flags);
                cfg->iface_cnt++;
                list_add(&_net_info->list, &cfg->net_list);
+               spin_unlock_irqrestore(&cfg->net_list_sync, flags);
        }
        return err;
 }
-static inline void
-wl_dealloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev)
-{
-       struct net_info *_net_info, *next;
 
-       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
-               if (ndev && (_net_info->ndev == ndev)) {
-                       list_del(&_net_info->list);
-                       cfg->iface_cnt--;
-                       kfree(_net_info);
-               }
-       }
-
-}
 static inline void
 wl_delete_all_netinfo(struct bcm_cfg80211 *cfg)
 {
        struct net_info *_net_info, *next;
+       unsigned long int flags;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               wl_cfgbss_t *bss = &_net_info->bss;
+
+               kfree(bss->wpa_ie);
+               bss->wpa_ie = NULL;
+               kfree(bss->rsn_ie);
+               bss->rsn_ie = NULL;
+               kfree(bss->wps_ie);
+               bss->wps_ie = NULL;
                list_del(&_net_info->list);
-                       if (_net_info->wdev)
-                               kfree(_net_info->wdev);
-                       kfree(_net_info);
+               if (_net_info->wdev)
+                       kfree(_net_info->wdev);
+               kfree(_net_info);
        }
        cfg->iface_cnt = 0;
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
 }
 static inline u32
 wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status)
@@ -683,17 +804,24 @@ wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status)
 {
        struct net_info *_net_info, *next;
        u32 cnt = 0;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
                if (_net_info->ndev &&
                        test_bit(status, &_net_info->sme_state))
                        cnt++;
        }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
        return cnt;
 }
 static inline void
 wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op)
 {
        struct net_info *_net_info, *next;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
                switch (op) {
                        case 1:
@@ -710,37 +838,48 @@ wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op)
                                return; /* unknown operation */
                }
        }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
 }
 static inline void
 wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status,
        struct net_device *ndev, u32 op)
 {
-
        struct net_info *_net_info, *next;
+       unsigned long int flags;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
                if (ndev && (_net_info->ndev == ndev)) {
                        switch (op) {
                                case 1:
+                                       /*
+                                        * Release the spinlock before calling notifier. Else there
+                                        * will be nested calls
+                                        */
+                                       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
                                        set_bit(status, &_net_info->sme_state);
                                        if (cfg->state_notifier &&
                                                test_bit(status, &(cfg->interrested_state)))
                                                cfg->state_notifier(cfg, _net_info, status, true);
-                                       break;
+                                       return;
                                case 2:
+                                       /*
+                                        * Release the spinlock before calling notifier. Else there
+                                        * will be nested calls
+                                        */
+                                       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
                                        clear_bit(status, &_net_info->sme_state);
                                        if (cfg->state_notifier &&
                                                test_bit(status, &(cfg->interrested_state)))
                                                cfg->state_notifier(cfg, _net_info, status, false);
-                                       break;
+                                       return;
                                case 4:
                                        change_bit(status, &_net_info->sme_state);
                                        break;
                        }
                }
-
        }
-
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
 }
 
 static inline u32
@@ -748,24 +887,56 @@ wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status,
        struct net_device *ndev)
 {
        struct net_info *_net_info, *next;
+       u32 stat = 0;
+       unsigned long int flags;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
-                               if (ndev && (_net_info->ndev == ndev))
-                                       return test_bit(status, &_net_info->sme_state);
+               if (ndev && (_net_info->ndev == ndev)) {
+                       stat = test_bit(status, &_net_info->sme_state);
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return stat;
+}
+
+static inline wl_cfgbss_t *
+wl_get_cfgbss_by_wdev(struct bcm_cfg80211 *cfg,
+       struct wireless_dev *wdev)
+{
+       struct net_info *_net_info, *next;
+       wl_cfgbss_t *bss = NULL;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
+       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               if (wdev && (_net_info->wdev == wdev)) {
+                       bss = &_net_info->bss;
+                       break;
+               }
        }
-       return 0;
+
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return bss;
 }
 
 static inline s32
 wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
 {
        struct net_info *_net_info, *next;
+       s32 mode = -1;
+       unsigned long int flags;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
-                               if (ndev && (_net_info->ndev == ndev))
-                                       return _net_info->mode;
+               if (ndev && (_net_info->ndev == ndev)) {
+                       mode = _net_info->mode;
+                       break;
+               }
        }
-       return -1;
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return mode;
 }
 
 
@@ -774,34 +945,92 @@ wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        s32 mode)
 {
        struct net_info *_net_info, *next;
+       unsigned long int flags;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
-                               if (ndev && (_net_info->ndev == ndev))
-                                       _net_info->mode = mode;
+               if (ndev && (_net_info->ndev == ndev))
+                       _net_info->mode = mode;
        }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
 }
+
 static inline struct wl_profile *
 wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
 {
        struct net_info *_net_info, *next;
+       struct wl_profile *prof = NULL;
+       unsigned long int flags;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
-                               if (ndev && (_net_info->ndev == ndev))
-                                       return &_net_info->profile;
+               if (ndev && (_net_info->ndev == ndev)) {
+                       prof = &_net_info->profile;
+                       break;
+               }
        }
-       return NULL;
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return prof;
 }
+
 static inline struct net_info *
 wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+       struct net_info *_net_info, *next, *info = NULL;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
+       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               if (ndev && (_net_info->ndev == ndev)) {
+                       info = _net_info;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return info;
+}
+
+static inline s32
+wl_get_bssidx_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+       struct net_info *_net_info, *next;
+       s32 bssidx = -1;
+       unsigned long int flags;
+
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
+       list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+               if (_net_info->wdev && (_net_info->wdev == wdev)) {
+                       bssidx = _net_info->bssidx;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return bssidx;
+}
+
+static inline struct wireless_dev *
+wl_get_wdev_by_bssidx(struct bcm_cfg80211 *cfg, s32 bssidx)
 {
        struct net_info *_net_info, *next;
+       struct wireless_dev *wdev = NULL;
+       unsigned long int flags;
+
+       if (bssidx < 0)
+               return NULL;
 
+       spin_lock_irqsave(&cfg->net_list_sync, flags);
        list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
-                               if (ndev && (_net_info->ndev == ndev))
-                                       return _net_info;
+               if (_net_info->bssidx == bssidx) {
+                               wdev = _net_info->wdev;
+                               break;
+               }
        }
-       return NULL;
+       spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+       return wdev;
 }
+
+#define is_p2p_group_iface(wdev) (((wdev->iftype == NL80211_IFTYPE_P2P_GO) || \
+               (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) ? 1 : 0)
 #define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy)
 #define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev)
 #define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev)
@@ -821,7 +1050,7 @@ wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
 #define wdev_to_wlc_ndev(wdev, cfg)    \
        ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \
        bcmcfg_to_prmry_ndev(cfg) : wdev_to_ndev(wdev))
-#define cfgdev_to_wlc_ndev(cfgdev, cfg)        wdev_to_wlc_ndev(cfgdev, cfg)
+#define cfgdev_to_wlc_ndev(cfgdev, cfg)        (cfgdev ? wdev_to_wlc_ndev(cfgdev, cfg) : NULL)
 #define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg)
 #elif defined(WL_ENABLE_P2P_IF)
 #define cfgdev_to_wlc_ndev(cfgdev, cfg)        ndev_to_wlc_ndev(cfgdev, cfg)
@@ -901,13 +1130,17 @@ extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
 void wl_cfg80211_set_parent_dev(void *dev);
 struct device *wl_cfg80211_get_parent_dev(void);
 
+/* clear IEs */
+extern s32 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg);
+extern s32 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx);
+
 extern s32 wl_cfg80211_up(void *para);
 extern s32 wl_cfg80211_down(void *para);
 extern s32 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx);
 extern s32 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx);
 extern s32 wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx);
 extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name,
-       uint8 *mac, uint8 bssidx);
+       uint8 *mac, uint8 bssidx, char *dngl_name);
 extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev);
 extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev);
 extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev);
@@ -961,6 +1194,15 @@ extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev,
 extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
 extern void wl_cfg80211_update_power_mode(struct net_device *dev);
 extern void wl_terminate_event_handler(void);
+extern s32
+wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen);
+extern s32
+wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen);
+extern int
+wl_cfg80211_set_spect(struct net_device *dev, int spect);
+extern int
+wl_cfg80211_get_sta_channel(struct net_device *dev);
+
 #define SCAN_BUF_CNT   2
 #define SCAN_BUF_NEXT  1
 #define WL_SCANTYPE_LEGACY     0x1
@@ -979,6 +1221,10 @@ extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev);
 extern void wl_cfg80211_set_rmc_pid(int pid);
 #endif /* WL_RELMCAST */
 
+extern int wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg,
+       struct net_device *ndev, s32 bssidx, s32 pktflag,
+       const u8 *vndr_ie, u32 vndr_ie_len);
+
 /* Action frame specific functions */
 extern u8 wl_get_action_category(void *frame, u32 frame_len);
 extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action);
@@ -1006,6 +1252,11 @@ struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *c
 
 extern int wl_cfg80211_get_ioctl_version(void);
 
+#if defined(WL_VIRTUAL_APSTA)
+extern int wl_cfg80211_interface_create(struct net_device *dev, char *name);
+extern int wl_cfg80211_interface_delete(struct net_device *dev, char *name);
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
 #ifdef WL_CFG80211_P2P_DEV_IF
 extern void wl_cfg80211_del_p2p_wdev(void);
 #endif /* WL_CFG80211_P2P_DEV_IF */
index 27f42b5..8c3787b 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: wl_cfgp2p.c 584240 2015-09-04 14:17:53Z $
+ * $Id: wl_cfgp2p.c 662965 2016-11-24 03:53:15Z $
  *
  */
 #include <typedefs.h>
 #endif
 
 static s8 scanparambuf[WLC_IOCTL_SMLEN];
-static s8 g_mgmt_ie_buf[2048];
 static bool
 wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
 
-static u32
-wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
-            s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd);
 static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
        struct wireless_dev *wdev, bool notify);
 
@@ -321,35 +317,13 @@ wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg)
                CFGP2P_ERR(("struct p2p_info allocation failed\n"));
                return -ENOMEM;
        }
-#define INIT_IE(IE_TYPE, BSS_TYPE)             \
-       do {                                                    \
-               memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
-                  sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
-               wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
-       } while (0);
-
-       INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY);
-       INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY);
-       INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY);
-       INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY);
-       INIT_IE(beacon,    P2PAPI_BSSCFG_PRIMARY);
-       INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE);
-       INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE);
-       INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE);
-       INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE);
-       INIT_IE(beacon,    P2PAPI_BSSCFG_DEVICE);
-       INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION);
-       INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION);
-       INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION);
-       INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION);
-       INIT_IE(beacon,    P2PAPI_BSSCFG_CONNECTION);
-#undef INIT_IE
+
        wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg);
        wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0;
        wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
        wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
        wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = NULL;
-       wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = 0;
+       wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = -1;
        return BCME_OK;
 
 }
@@ -360,7 +334,7 @@ wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg)
 void
 wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg)
 {
-       CFGP2P_DBG(("In\n"));
+       CFGP2P_ERR(("In\n"));
        if (cfg->p2p) {
                kfree(cfg->p2p);
                cfg->p2p = NULL;
@@ -652,6 +626,14 @@ wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg)
        if (ret < 0) {
                return ret;
        }
+       /* In case of CFG80211 case, check if p2p_discovery interface has allocated p2p_wdev */
+       if (!cfg->p2p_wdev) {
+               CFGP2P_ERR(("p2p_wdev is NULL.\n"));
+               return BCME_NODEVICE;
+       }
+       /* Make an entry in the netinfo */
+       wl_alloc_netinfo(cfg, cfg->p2p_net, cfg->p2p_wdev, WL_MODE_BSS, 0, index);
+
        wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) =
            wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
        wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = index;
@@ -691,6 +673,12 @@ wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg)
        /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
        ret = wl_cfgp2p_set_discovery(cfg, 0);
 
+       /* Remove the p2p disc entry in the netinfo */
+#ifdef DHD_IFDEBUG
+       WL_ERR(("dealloc_net_info by wdev=%p\n", cfg->p2p_wdev));
+#endif
+       wl_dealloc_netinfo_by_wdev(cfg, cfg->p2p_wdev);
+
        /* Clear our saved WPS and P2P IEs for the discovery BSS.  The driver
         * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery
         * BSS.
@@ -719,20 +707,20 @@ wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev,
        s32 ret = BCME_OK;
        s32 bssidx;
 
+       CFGP2P_DBG(("enter\n"));
+
        if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
                CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
                goto set_ie;
        }
 
-       wl_set_p2p_status(cfg, DISCOVERY_ON);
-
-       CFGP2P_DBG(("enter\n"));
-
        ret = wl_cfgp2p_init_discovery(cfg);
        if (unlikely(ret < 0)) {
                CFGP2P_ERR((" init discovery error %d\n", ret));
                goto exit;
        }
+
+       wl_set_p2p_status(cfg, DISCOVERY_ON);
        /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
         * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
         * Some peer devices may not initiate WPS with us if this bit is not set.
@@ -746,12 +734,12 @@ set_ie:
        if (ie_len) {
                if (bcmcfg_to_prmry_ndev(cfg) == dev) {
                        bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
-               } else if (wl_cfgp2p_find_idx(cfg, dev, &bssidx) != BCME_OK) {
+               } else if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfg->p2p_wdev)) < 0) {
                        WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
                        return BCME_ERROR;
                }
 
-               ret = wl_cfgp2p_set_management_ie(cfg, dev,
+               ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev,
                        bssidx,
                        VNDR_IE_PRBREQ_FLAG, ie, ie_len);
 
@@ -1006,348 +994,6 @@ exit:
 #define wl_cfgp2p_is_wfd_ie(ie, tlvs, len)     wl_cfgp2p_has_ie(ie, tlvs, len, \
                (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD)
 
-static s32
-wl_cfgp2p_parse_vndr_ies(u8 *parse, u32 len,
-       struct parsed_vndr_ies *vndr_ies)
-{
-       s32 err = BCME_OK;
-       vndr_ie_t *vndrie;
-       bcm_tlv_t *ie;
-       struct parsed_vndr_ie_info *parsed_info;
-       u32     count = 0;
-       s32 remained_len;
-
-       remained_len = (s32)len;
-       memset(vndr_ies, 0, sizeof(*vndr_ies));
-
-       WL_INFO(("---> len %d\n", len));
-       ie = (bcm_tlv_t *) parse;
-       if (!bcm_valid_tlv(ie, remained_len))
-               ie = NULL;
-       while (ie) {
-               if (count >= MAX_VNDR_IE_NUMBER)
-                       break;
-               if (ie->id == DOT11_MNG_VS_ID) {
-                       vndrie = (vndr_ie_t *) ie;
-                       /* len should be bigger than OUI length + one data length at least */
-                       if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
-                               CFGP2P_ERR(("%s: invalid vndr ie. length is too small %d\n",
-                                       __FUNCTION__, vndrie->len));
-                               goto end;
-                       }
-                       /* if wpa or wme ie, do not add ie */
-                       if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
-                               ((vndrie->data[0] == WPA_OUI_TYPE) ||
-                               (vndrie->data[0] == WME_OUI_TYPE))) {
-                               CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
-                               goto end;
-                       }
-
-                       parsed_info = &vndr_ies->ie_info[count++];
-
-                       /* save vndr ie information */
-                       parsed_info->ie_ptr = (char *)vndrie;
-                       parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
-                       memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
-
-                       vndr_ies->count = count;
-
-                       CFGP2P_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x \n",
-                               parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1],
-                               parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0]));
-               }
-end:
-               ie = bcm_next_tlv(ie, &remained_len);
-       }
-       return err;
-}
-
-
-/* Delete and Set a management vndr ie to firmware
- * Parameters:
- * @cfg       : wl_private data
- * @ndev     : net device for bssidx
- * @bssidx   : bssidx for BSS
- * @pktflag  : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
- *                                 VNDR_IE_ASSOCREQ_FLAG)
- * @ie       :  VNDR IE (such as P2P IE , WPS IE)
- * @ie_len   : VNDR IE Length
- * Returns 0 if success.
- */
-
-s32
-wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx,
-    s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
-{
-       s32 ret = BCME_OK;
-       u8  *curr_ie_buf = NULL;
-       u8  *mgmt_ie_buf = NULL;
-       u32 mgmt_ie_buf_len = 0;
-       u32 *mgmt_ie_len = 0;
-       u32 del_add_ie_buf_len = 0;
-       u32 total_ie_buf_len = 0;
-       u32 parsed_ie_buf_len = 0;
-       struct parsed_vndr_ies old_vndr_ies;
-       struct parsed_vndr_ies new_vndr_ies;
-       s32 i;
-       u8 *ptr;
-       s32 type = -1;
-       s32 remained_buf_len;
-#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie)
-#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(cfg, bsstype).p2p_ ## type ## _ie_len)
-       memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
-       curr_ie_buf = g_mgmt_ie_buf;
-       CFGP2P_DBG((" bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag));
-       if (cfg->p2p != NULL) {
-               if (wl_cfgp2p_find_type(cfg, bssidx, &type)) {
-                       CFGP2P_ERR(("cannot find type from bssidx : %d\n", bssidx));
-                       return BCME_ERROR;
-               }
-
-               switch (pktflag) {
-                       case VNDR_IE_PRBREQ_FLAG :
-                               mgmt_ie_buf = IE_TYPE(probe_req, type);
-                               mgmt_ie_len = &IE_TYPE_LEN(probe_req, type);
-                               mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, type));
-                               break;
-                       case VNDR_IE_PRBRSP_FLAG :
-                               mgmt_ie_buf = IE_TYPE(probe_res, type);
-                               mgmt_ie_len = &IE_TYPE_LEN(probe_res, type);
-                               mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, type));
-                               break;
-                       case VNDR_IE_ASSOCREQ_FLAG :
-                               mgmt_ie_buf = IE_TYPE(assoc_req, type);
-                               mgmt_ie_len = &IE_TYPE_LEN(assoc_req, type);
-                               mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, type));
-                               break;
-                       case VNDR_IE_ASSOCRSP_FLAG :
-                               mgmt_ie_buf = IE_TYPE(assoc_res, type);
-                               mgmt_ie_len = &IE_TYPE_LEN(assoc_res, type);
-                               mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, type));
-                               break;
-                       case VNDR_IE_BEACON_FLAG :
-                               mgmt_ie_buf = IE_TYPE(beacon, type);
-                               mgmt_ie_len = &IE_TYPE_LEN(beacon, type);
-                               mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, type));
-                               break;
-                       default:
-                               mgmt_ie_buf = NULL;
-                               mgmt_ie_len = NULL;
-                               CFGP2P_ERR(("not suitable type\n"));
-                               return BCME_ERROR;
-               }
-       } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
-               if (cfg->ap_info == NULL) {
-                       CFGP2P_ERR(("hostapd ap_info null ptr refrence while setting  IE\n"));
-                       return BCME_ERROR;
-
-               }
-               switch (pktflag) {
-                       case VNDR_IE_PRBRSP_FLAG :
-                               mgmt_ie_buf = cfg->ap_info->probe_res_ie;
-                               mgmt_ie_len = &cfg->ap_info->probe_res_ie_len;
-                               mgmt_ie_buf_len = sizeof(cfg->ap_info->probe_res_ie);
-                               break;
-                       case VNDR_IE_BEACON_FLAG :
-                               mgmt_ie_buf = cfg->ap_info->beacon_ie;
-                               mgmt_ie_len = &cfg->ap_info->beacon_ie_len;
-                               mgmt_ie_buf_len = sizeof(cfg->ap_info->beacon_ie);
-                               break;
-                       case VNDR_IE_ASSOCRSP_FLAG :
-                               /* WPS-AP WSC2.0 assoc res includes wps_ie */
-                               mgmt_ie_buf = cfg->ap_info->assoc_res_ie;
-                               mgmt_ie_len = &cfg->ap_info->assoc_res_ie_len;
-                               mgmt_ie_buf_len = sizeof(cfg->ap_info->assoc_res_ie);
-                               break;
-                       default:
-                               mgmt_ie_buf = NULL;
-                               mgmt_ie_len = NULL;
-                               CFGP2P_ERR(("not suitable type\n"));
-                               return BCME_ERROR;
-               }
-               bssidx = 0;
-       } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) {
-               switch (pktflag) {
-                       case VNDR_IE_PRBREQ_FLAG :
-                               mgmt_ie_buf = cfg->sta_info->probe_req_ie;
-                               mgmt_ie_len = &cfg->sta_info->probe_req_ie_len;
-                               mgmt_ie_buf_len = sizeof(cfg->sta_info->probe_req_ie);
-                               break;
-                       case VNDR_IE_ASSOCREQ_FLAG :
-                               mgmt_ie_buf = cfg->sta_info->assoc_req_ie;
-                               mgmt_ie_len = &cfg->sta_info->assoc_req_ie_len;
-                               mgmt_ie_buf_len = sizeof(cfg->sta_info->assoc_req_ie);
-                               break;
-                       default:
-                               mgmt_ie_buf = NULL;
-                               mgmt_ie_len = NULL;
-                               CFGP2P_ERR(("not suitable type\n"));
-                               return BCME_ERROR;
-               }
-               bssidx = 0;
-       } else {
-               CFGP2P_ERR(("not suitable type\n"));
-               return BCME_ERROR;
-       }
-
-       if (vndr_ie_len > mgmt_ie_buf_len) {
-               CFGP2P_ERR(("extra IE size too big\n"));
-               ret = -ENOMEM;
-       } else {
-               /* parse and save new vndr_ie in curr_ie_buff before comparing it */
-               if (vndr_ie && vndr_ie_len && curr_ie_buf) {
-                       ptr = curr_ie_buf;
-
-                       wl_cfgp2p_parse_vndr_ies((u8*)vndr_ie,
-                               vndr_ie_len, &new_vndr_ies);
-
-                       for (i = 0; i < new_vndr_ies.count; i++) {
-                               struct parsed_vndr_ie_info *vndrie_info =
-                                       &new_vndr_ies.ie_info[i];
-
-                               memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
-                                       vndrie_info->ie_len);
-                               parsed_ie_buf_len += vndrie_info->ie_len;
-                       }
-               }
-
-               if (mgmt_ie_buf != NULL) {
-                       if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
-                            (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
-                               CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
-                               goto exit;
-                       }
-
-                       /* parse old vndr_ie */
-                       wl_cfgp2p_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
-                               &old_vndr_ies);
-
-                       /* make a command to delete old ie */
-                       for (i = 0; i < old_vndr_ies.count; i++) {
-                               struct parsed_vndr_ie_info *vndrie_info =
-                                       &old_vndr_ies.ie_info[i];
-
-                               CFGP2P_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
-                                       vndrie_info->vndrie.id, vndrie_info->vndrie.len,
-                                       vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
-                                       vndrie_info->vndrie.oui[2]));
-
-                               del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
-                                       pktflag, vndrie_info->vndrie.oui,
-                                       vndrie_info->vndrie.id,
-                                       vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
-                                       vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
-                                       "del");
-
-                               curr_ie_buf += del_add_ie_buf_len;
-                               total_ie_buf_len += del_add_ie_buf_len;
-                       }
-               }
-
-               *mgmt_ie_len = 0;
-               /* Add if there is any extra IE */
-               if (mgmt_ie_buf && parsed_ie_buf_len) {
-                       ptr = mgmt_ie_buf;
-
-                       remained_buf_len = mgmt_ie_buf_len;
-
-                       /* make a command to add new ie */
-                       for (i = 0; i < new_vndr_ies.count; i++) {
-                               struct parsed_vndr_ie_info *vndrie_info =
-                                       &new_vndr_ies.ie_info[i];
-
-                               CFGP2P_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n",
-                                       vndrie_info->vndrie.id, vndrie_info->vndrie.len,
-                                       vndrie_info->ie_len - 2,
-                                       vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
-                                       vndrie_info->vndrie.oui[2]));
-
-                               del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
-                                       pktflag, vndrie_info->vndrie.oui,
-                                       vndrie_info->vndrie.id,
-                                       vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
-                                       vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
-                                       "add");
-
-                               /* verify remained buf size before copy data */
-                               if (remained_buf_len >= vndrie_info->ie_len) {
-                                       remained_buf_len -= vndrie_info->ie_len;
-                               } else {
-                                       CFGP2P_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
-                                               "found vndr ies # = %d(cur %d), remained len %d, "
-                                               "cur mgmt_ie_len %d, new ie len = %d\n",
-                                               pktflag, new_vndr_ies.count, i, remained_buf_len,
-                                               *mgmt_ie_len, vndrie_info->ie_len));
-                                       break;
-                               }
-
-                               /* save the parsed IE in cfg struct */
-                               memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
-                                       vndrie_info->ie_len);
-                               *mgmt_ie_len += vndrie_info->ie_len;
-
-                               curr_ie_buf += del_add_ie_buf_len;
-                               total_ie_buf_len += del_add_ie_buf_len;
-                       }
-               }
-               if (total_ie_buf_len) {
-                       ret  = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
-                               total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
-                               bssidx, &cfg->ioctl_buf_sync);
-                       if (ret)
-                               CFGP2P_ERR(("vndr ie set error : %d\n", ret));
-               }
-       }
-#undef IE_TYPE
-#undef IE_TYPE_LEN
-exit:
-       return ret;
-}
-
-/* Clear the manament IE buffer of BSSCFG
- * Parameters:
- * @cfg       : wl_private data
- * @bssidx   : bssidx for BSS
- *
- * Returns 0 if success.
- */
-s32
-wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx)
-{
-
-       s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
-               VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
-       s32 index = -1;
-       s32 type = -1;
-       struct net_device *ndev = wl_cfgp2p_find_ndev(cfg, bssidx);
-#define INIT_IE(IE_TYPE, BSS_TYPE)             \
-       do {                                                    \
-               memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
-                  sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
-               wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
-       } while (0);
-
-       if (bssidx < 0 || ndev == NULL) {
-               CFGP2P_ERR(("invalid %s\n", (bssidx < 0) ? "bssidx" : "ndev"));
-               return BCME_BADARG;
-       }
-
-       if (wl_cfgp2p_find_type(cfg, bssidx, &type)) {
-               CFGP2P_ERR(("invalid argument\n"));
-               return BCME_BADARG;
-       }
-       for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
-               /* clean up vndr ies in dongle */
-               wl_cfgp2p_set_management_ie(cfg, ndev, bssidx, vndrie_flag[index], NULL, 0);
-       }
-       INIT_IE(probe_req, type);
-       INIT_IE(probe_res, type);
-       INIT_IE(assoc_req, type);
-       INIT_IE(assoc_res, type);
-       INIT_IE(beacon, type);
-       return BCME_OK;
-}
-
 
 /* Is any of the tlvs the expected entry? If
  * not update the tlvs buffer pointer/length.
@@ -1425,7 +1071,7 @@ wl_cfgp2p_find_wfdie(u8 *parse, u32 len)
        }
        return NULL;
 }
-static u32
+u32
 wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
             s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd)
 {
@@ -1478,37 +1124,6 @@ wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
 
 }
 
-/*
- * Search the bssidx based on dev argument
- * Parameters:
- * @cfg       : wl_private data
- * @ndev     : net device to search bssidx
- * @bssidx  : output arg to store bssidx of the bsscfg of firmware.
- * Returns error
- */
-s32
-wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *bssidx)
-{
-       u32 i;
-       if (ndev == NULL || bssidx == NULL) {
-               CFGP2P_ERR((" argument is invalid\n"));
-               return BCME_BADARG;
-       }
-       if (!cfg->p2p_supported) {
-               *bssidx = P2PAPI_BSSCFG_PRIMARY;
-               return BCME_OK;
-       }
-       /* we cannot find the bssidx of DISCOVERY BSS
-        *  because the ndev is same with ndev of PRIMARY BSS.
-        */
-       for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
-               if (ndev == wl_to_p2p_bss_ndev(cfg, i)) {
-                       *bssidx = wl_to_p2p_bss_bssidx(cfg, i);
-                       return BCME_OK;
-               }
-       }
-       return BCME_BADARG;
-}
 struct net_device *
 wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx)
 {
@@ -1612,9 +1227,11 @@ wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
 #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
                        if (ndev && (ndev->ieee80211_ptr != NULL)) {
 #if defined(WL_CFG80211_P2P_DEV_IF)
+                               if (bcmcfg_to_p2p_wdev(cfg)) {
                                cfg80211_remain_on_channel_expired(
                                        bcmcfg_to_p2p_wdev(cfg), cfg->last_roc_id,
                                        &cfg->remain_on_chan, GFP_KERNEL);
+                               }
 #else
                                cfg80211_remain_on_channel_expired(cfg->p2p_net, cfg->last_roc_id,
                                        &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
@@ -1919,7 +1536,7 @@ wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
         */
        memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
 #ifndef  P2PONEINT
-       out_int_addr->octet[4] ^= 0x80;
+       out_int_addr->octet[3] ^= 0x80;
 #endif
 
 }
@@ -2080,11 +1697,20 @@ wl_cfgp2p_down(struct bcm_cfg80211 *cfg)
        for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
                        index = wl_to_p2p_bss_bssidx(cfg, i);
                        if (index != WL_INVALID)
-                               wl_cfgp2p_clear_management_ie(cfg, index);
+                               wl_cfg80211_clear_per_bss_ies(cfg, index);
        }
        wl_cfgp2p_deinit_priv(cfg);
        return 0;
 }
+
+int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg)
+{
+       if (cfg->p2p && (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) != -1))
+               return true;
+       else
+               return false;
+}
+
 s32
 wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
 {
@@ -2096,7 +1722,7 @@ wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* b
 
        memset(&dongle_noa, 0, sizeof(dongle_noa));
 
-       if (cfg->p2p && cfg->p2p->vif_created) {
+       if (wl_cfgp2p_vif_created(cfg)) {
 
                cfg->p2p->noa.desc[0].start = 0;
 
@@ -2131,7 +1757,7 @@ wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* b
                }
                else {
                        /* Continuous NoA interval. */
-                       dongle_noa.action = WL_P2P_SCHED_ACTION_NONE;
+                       dongle_noa.action = WL_P2P_SCHED_ACTION_DOZE;
                        dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
                        if ((cfg->p2p->noa.desc[0].interval == 102) ||
                                (cfg->p2p->noa.desc[0].interval == 100)) {
@@ -2178,7 +1804,7 @@ wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* b
 
        CFGP2P_DBG((" Enter\n"));
        buf[0] = '\0';
-       if (cfg->p2p && cfg->p2p->vif_created) {
+       if (wl_cfgp2p_vif_created(cfg)) {
                if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) {
                        _buf[0] = 1; /* noa index */
                        _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) |
@@ -2220,7 +1846,7 @@ wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* bu
        struct net_device *dev;
 
        CFGP2P_DBG((" Enter\n"));
-       if (cfg->p2p && cfg->p2p->vif_created) {
+       if (wl_cfgp2p_vif_created(cfg)) {
                sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw);
                CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
                dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION);
@@ -2470,7 +2096,7 @@ wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
                 */
                strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1);
                new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
-                       event->mac, event->bssidx);
+                       event->mac, event->bssidx, event->name);
                if (new_ndev == NULL)
                        goto fail;
 
@@ -2489,7 +2115,6 @@ wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
                new_ndev->ieee80211_ptr = vwdev;
                SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
                wl_set_drv_status(cfg, READY, new_ndev);
-               cfg->p2p->vif_created = true;
                wl_set_mode_by_netdev(cfg, new_ndev, mode);
 
                if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
@@ -2522,7 +2147,6 @@ wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
                wl_clr_p2p_status(cfg, IF_ADDING);
                WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
                memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
-               cfg->p2p->vif_created = false;
        }
 
 
@@ -2739,7 +2363,7 @@ wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg)
        struct wireless_dev *wdev = NULL;
        struct ether_addr primary_mac;
 
-       if (!cfg)
+       if (!cfg || !(cfg->p2p))
                return ERR_PTR(-EINVAL);
 
        WL_TRACE(("Enter\n"));
index fd1b215..5108c21 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: wl_cfgp2p.h 518957 2014-12-04 08:52:50Z $
+ * $Id: wl_cfgp2p.h 662786 2016-11-11 09:06:37Z $
  */
 #ifndef _wl_cfgp2p_h_
 #define _wl_cfgp2p_h_
@@ -84,7 +84,6 @@ struct p2p_info {
        bool on;    /* p2p on/off switch */
        bool scan;
        int16 search_state;
-       bool vif_created;
        s8 vir_ifname[IFNAMSIZ];
        unsigned long status;
        struct ether_addr dev_addr;
@@ -96,7 +95,7 @@ struct p2p_info {
        wlc_ssid_t ssid;
 };
 
-#define MAX_VNDR_IE_NUMBER     5
+#define MAX_VNDR_IE_NUMBER     10
 
 struct parsed_vndr_ie_info {
        char *ie_ptr;
@@ -282,14 +281,7 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
 
 extern wifi_wfd_ie_t *
 wl_cfgp2p_find_wfdie(u8 *parse, u32 len);
-extern s32
-wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx,
-            s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len);
-extern s32
-wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx);
 
-extern s32
-wl_cfgp2p_find_idx(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 *index);
 extern struct net_device *
 wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx);
 extern s32
@@ -359,6 +351,13 @@ wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg);
 extern bool
 wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops);
 
+extern u32
+wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
+       s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd);
+
+extern
+int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg);
+
 #if defined(WL_CFG80211_P2P_DEV_IF)
 extern struct wireless_dev *
 wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg);
index 3f7ab96..64f3443 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: wldev_common.c 540901 2015-03-13 11:50:58Z $
+ * $Id: wldev_common.c 657248 2016-08-31 11:29:39Z $
  */
 
 #include <osl.h>
 
 #define        WLDEV_ERROR(args)                                               \
        do {                                                                            \
-               printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__);        \
+               printk(KERN_ERR "WLDEV-ERROR) ");       \
+               printk args;                                                    \
+       } while (0)
+
+#define        WLDEV_INFO(args)                                                \
+       do {                                                                            \
+               printk(KERN_INFO "WLDEV-INFO) ");       \
                printk args;                                                    \
        } while (0)
 
@@ -442,7 +448,7 @@ int wldev_set_country(
        }
 
        if ((error < 0) ||
-           (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) {
+           (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) {
 
                if (user_enforced) {
                        bzero(&scbval, sizeof(scb_val_t));
@@ -466,7 +472,7 @@ int wldev_set_country(
                        return error;
                }
                dhd_bus_country_set(dev, &cspec, notify);
-               WLDEV_ERROR(("%s: set country for %s as %s rev %d\n",
+               WLDEV_INFO(("%s: set country for %s as %s rev %d\n",
                        __FUNCTION__, country_code, cspec.ccode, cspec.rev));
        }
        return 0;