unsure.
config BCMDHD_SDIO
- tristate "SDIO bus interface support"
+ bool "SDIO bus interface support"
depends on BCMDHD && MMC
config BCMDHD_PCIE
-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
# 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
# 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
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
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
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
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
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),)
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)/
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"
eromptr = regs;
break;
-#ifdef BCMSDIO
case SPI_BUS:
case SDIO_BUS:
eromptr = (uint32 *)(uintptr)erombase;
break;
-#endif /* BCMSDIO */
case PCMCIA_BUS:
default:
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:
* 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}
#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;
+}
* 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 $
*/
/**
/* 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.
*/
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, ®s);
if (bcmsdh == NULL) {
#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,
* 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>
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
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;
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]);
}
} 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);
#endif /* defined(HW_OOB) */
bcmsdh_oob_intr_set(sd->bcmsdh, TRUE);
}
-#endif /* !defined(OOB_INTR_ONLY) */
+#endif /* defined(OOB_INTR_ONLY) */
}
}
else
*/
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]);
* 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>
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;
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)
{
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
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;
* 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
{
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;
{
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;
* 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>
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)
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)
* 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 $
*/
/****************
struct task_struct * current_rxf;
int chan_isvht80;
#endif /* CUSTOM_SET_CPUCORE */
+#ifdef OOB_PARAM
+ uint oob_disable;
+#endif /* OOB_PARAM */
} dhd_pub_t;
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,
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 */
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);
#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_ */
* 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
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);
}
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)
* 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>
struct bcmstrbuf b;
struct bcmstrbuf *strbuf = &b;
+ if (!dhdp || !dhdp->prot || !buf)
+ return BCME_ERROR;
bcm_binit(strbuf, buf, buflen);
#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
DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
break;
-
case WLC_E_CCA_CHAN_QUAL:
if (datalen) {
buf = (uchar *) 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",
}
#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)
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];
/*
* 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;
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) {
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;
}
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;
}
* 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>
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
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;
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;
extern void dhd_dbg_remove(void);
#endif /* BCMDBGFS */
-#endif /* BCMSDIO */
#ifdef SDTEST
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));
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;
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;
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;
}
#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);
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;
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);
}
#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);
}
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;
*/
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;
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:
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 */
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 */
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;
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;
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);
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;
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;
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 */
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
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
#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 */
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));
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));
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,
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
#endif /* DISABLE_11N */
#endif /* PROP_TXSTATUS */
-#endif /* BCMSDIO || BCMBUS */
#ifdef PNO_SUPPORT
if (!dhd->pno_state) {
dhd_pno_init(dhd);
#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);
}
}
}
#if defined(OOB_INTR_ONLY)
- OOB_PARAM_IF(!dhd_oob_disable) {
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
dhd_bus_oob_intr_unregister(dhdp);
}
#endif
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))
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);
return;
}
-#ifdef BCMSDIO
int
dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
{
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);
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
}
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
}
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)
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
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)
{
"\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;
} 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));
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 {
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;
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);
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);
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;
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) */
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);
}
extern struct semaphore dhd_registration_sem;
#endif
-#ifdef BCMSDIO
static int dhd_wifi_platform_load_sdio(void)
{
int i;
return err;
}
-#else /* BCMSDIO */
-static int dhd_wifi_platform_load_sdio(void)
-{
- return 0;
-}
-#endif /* BCMSDIO */
static int dhd_wifi_platform_load_usb(void)
{
* 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 $
*/
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;
}
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;
* 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>
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) */
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 */
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;
/* 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 */
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 */
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;
}
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);
__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) */
}
#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.
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);
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
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
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
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;
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;
#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))) {
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;
/* 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;
}
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;
}
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);
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);
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;
}
}
-#ifdef BCMSDIO
int
dhd_sr_config(dhd_pub_t *dhd, bool on)
{
else
return 0;
}
-#endif /* BCMSDIO */
#ifdef DEBUGGER
uint32 dhd_sdio_reg_read(void *h, uint32 addr)
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 */
* 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 $
*
*/
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));
* 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 $
*/
/**
#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) */
/* 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 */
#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_ */
* 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_
#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);
#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) { \
* 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_
(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) \
*
* Dependencies: proto/bcmeth.h
*
- * $Id: bcmevent.h 589976 2015-10-01 07:01:27Z $
+ * $Id: bcmevent.h 662961 2016-11-24 01:22:35Z $
*
*/
#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 */
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 */
#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 */
* 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
*
#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)
#ifndef _SDIO_H
#define _SDIO_H
-#ifdef BCMSDIO
/* CCCR structure for function 0 */
typedef volatile struct {
/* command issue options */
#define CMD_OPTION_DEFAULT 0
#define CMD_OPTION_TUNING 1
-
-#endif /* def BCMSDIO */
#endif /* _SDIO_H */
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,
* 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_
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
#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
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. */
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;
#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 {
} 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_ */
* 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
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;
}
break;
}
-#ifdef BCMSDIO
case SPI_BUS:
case SDIO_BUS:
sbaddr = (uint32)(uintptr)sii->curmap;
break;
-#endif
default:
regs = sii->curmap;
break;
}
-#ifdef BCMSDIO
case SPI_BUS:
case SDIO_BUS:
/* map new one */
}
regs = cores_info->regs[coreidx];
break;
-#endif /* BCMSDIO */
default:
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:
#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
sii->memseg = TRUE;
-#if defined(BCMSDIO)
if (BUSTYPE(bustype) == SDIO_BUS) {
int err;
uint8 clkset;
bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
}
-#endif /* BCMSDIO && BCMDONGLEHOST */
return TRUE;
}
sii->pub.buscoretype = cid;
sii->pub.buscoreidx = i;
}
-#ifdef BCMSDIO
else if (((BUSTYPE(bustype) == SDIO_BUS) ||
(BUSTYPE(bustype) == SPI_BUS)) &&
((cid == PCMCIA_CORE_ID) ||
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])) ||
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.
*/
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);
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);
}
* 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>
#ifdef PNO_SUPPORT
#include <dhd_pno.h>
#endif
-#ifdef BCMSDIO
#include <bcmsdbus.h>
-#endif
#ifdef WL_CFG80211
#include <wl_cfg80211.h>
#endif
#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
" <> 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')
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))) {
}
+#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)
{
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",
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;
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;
}
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];
net_os_wake_lock(net);
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
if (!ifr->ifr_data) {
ret = -EINVAL;
goto exit;
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);
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) {
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");
* 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>
#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
*/
#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
*/
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 { \
} \
} 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)
{
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));
} 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);
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 */
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;
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);
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 &&
}
cfg->wlfc_on = true;
}
-#endif
#endif /* PROP_TXSTATUS_VSDB */
/* In concurrency case, STA may be already associated in a particular channel.
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;
*/
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;
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);
}
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 */
}
}
#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) {
*/
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);
}
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);
}
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);
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;
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);
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")
/* 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;
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;
}
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;
}
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 */
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 */
}
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));
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));
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);
}
}
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;
}
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 */
/* 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);
ssids = this_ssid;
}
- if (request && !p2p_scan(cfg)) {
+ if (request && cfg->p2p && !p2p_scan(cfg)) {
WL_TRACE_HW4(("START SCAN\n"));
}
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
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;
}
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;
}
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)
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;
}
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;
}
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;
}
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;
}
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 |
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;
}
}
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;
}
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 */
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 */
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;
}
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;
}
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
#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;
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;
}
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;
}
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,
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;
}
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;
}
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;
}
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
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);
}
}
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;
/* 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);
}
}
#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
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 */
/* 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;
}
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;
}
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;
#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;
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 */
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);
}
}
}
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;
}
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);
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;
+ }
}
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,
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));
}
}
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"));
}
/* 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 {
{
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) {
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);
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,
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;
}
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;
}
} 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 */
}
#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"));
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;
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;
/* 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 */
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),
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)
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;
}
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) {
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));
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))
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);
}
}
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"));
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++;
}
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;
}
}
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 */
"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))));
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)) {
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,
#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
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
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);
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;
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);
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;
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.
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;
+ }
}
}
}
}
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,
}
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 {
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,
}
}
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));
+ }
}
}
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);
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);
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;
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;
#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();
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);
}
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;
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)
#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);
{
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) ?
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) {
#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 */
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 &&
cfg->wlfc_on = false;
}
}
-#endif
#endif /* PROP_TXSTATUS_VSDB */
}
/* 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);
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);
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) {
}
#endif /* WL11U */
+#ifdef DHD_IFDEBUG
+ /* Printout all netinfo entries */
+ wl_probe_wdev_all(cfg);
+#endif /* DHD_IFDEBUG */
+
return err;
}
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))
} 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);
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)
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;
}
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) {
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;
return valid;
}
-static s32
+s32
wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
{
s32 ret = BCME_ERROR;
return ret;
}
-static s32
+s32
wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
{
u32 channel = 0;
((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;
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)
}
+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,
#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,
#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;
#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;
#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)) {
#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);
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 */
* 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_
#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
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;
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 {
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;
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 */
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;
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;
bool nan_running;
bool need_wait_afrx;
struct ether_addr last_roamed_addr;
- bool revert_ndo_disable;
};
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;
_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)
{
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:
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
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;
}
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)
#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)
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);
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
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);
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 */
* 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);
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;
}
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;
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;
/* 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.
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.
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);
#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.
}
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)
{
}
-/*
- * 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)
{
#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);
*/
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
}
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)
{
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;
}
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)) {
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) |
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);
*/
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;
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_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;
}
struct wireless_dev *wdev = NULL;
struct ether_addr primary_mac;
- if (!cfg)
+ if (!cfg || !(cfg->p2p))
return ERR_PTR(-EINVAL);
WL_TRACE(("Enter\n"));
* 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_
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;
wlc_ssid_t ssid;
};
-#define MAX_VNDR_IE_NUMBER 5
+#define MAX_VNDR_IE_NUMBER 10
struct parsed_vndr_ie_info {
char *ie_ptr;
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
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);
* 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)
}
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));
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;