summaryrefslogtreecommitdiffstats
path: root/bcm4329
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2010-09-17 15:45:46 -0700
committerDmitry Shmidt <dimitrysh@google.com>2010-09-17 15:45:46 -0700
commit9984c42af1f24da360515edd81441ef5dfe23da4 (patch)
tree2abfefacbe77996fce91b36d145f8df3a7a0672e /bcm4329
parentd81065e3c1b57aabcc5a29fa5be9e02a5a8527a8 (diff)
downloadhardware_broadcom_wlan-9984c42af1f24da360515edd81441ef5dfe23da4.zip
hardware_broadcom_wlan-9984c42af1f24da360515edd81441ef5dfe23da4.tar.gz
hardware_broadcom_wlan-9984c42af1f24da360515edd81441ef5dfe23da4.tar.bz2
bcm4329: Update to version 4.218.248.6
Auto-merge: no Change-Id: I33451efb37f03abe4008d1bfeef378bc61249c69 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'bcm4329')
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmpcispi.c13
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdh.c2
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdh_linux.c95
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c10
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c20
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c2
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdstd.c21
-rw-r--r--bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c8
-rw-r--r--bcm4329/src/dhd/exe/dhdu.c4
-rw-r--r--bcm4329/src/dhd/linux/Makefile51
-rw-r--r--bcm4329/src/dhd/linux/makefile.267
-rw-r--r--bcm4329/src/dhd/sys/dhd.h73
-rw-r--r--bcm4329/src/dhd/sys/dhd_bus.h8
-rw-r--r--bcm4329/src/dhd/sys/dhd_cdc.c296
-rw-r--r--bcm4329/src/dhd/sys/dhd_common.c1343
-rw-r--r--bcm4329/src/dhd/sys/dhd_custom_gpio.c61
-rw-r--r--bcm4329/src/dhd/sys/dhd_dbg.h7
-rw-r--r--bcm4329/src/dhd/sys/dhd_linux.c587
-rw-r--r--bcm4329/src/dhd/sys/dhd_linux_sched.c2
-rw-r--r--bcm4329/src/dhd/sys/dhd_proto.h10
-rw-r--r--bcm4329/src/dhd/sys/dhd_sdio.c470
-rw-r--r--bcm4329/src/dongle/dngl_stats.h2
-rw-r--r--bcm4329/src/include/aidmp.h2
-rw-r--r--bcm4329/src/include/bcmcdc.h2
-rw-r--r--bcm4329/src/include/bcmdevs.h2
-rw-r--r--bcm4329/src/include/bcmendian.h2
-rw-r--r--bcm4329/src/include/bcmpcispi.h2
-rw-r--r--bcm4329/src/include/bcmperf.h2
-rw-r--r--bcm4329/src/include/bcmsdbus.h2
-rw-r--r--bcm4329/src/include/bcmsdh.h2
-rw-r--r--bcm4329/src/include/bcmsdh_sdmmc.h2
-rw-r--r--bcm4329/src/include/bcmsdpcm.h7
-rw-r--r--bcm4329/src/include/bcmsdspi.h2
-rw-r--r--bcm4329/src/include/bcmspi.h2
-rw-r--r--bcm4329/src/include/bcmutils.h2
-rw-r--r--bcm4329/src/include/bcmwifi.h4
-rw-r--r--bcm4329/src/include/dhdioctl.h5
-rw-r--r--bcm4329/src/include/epivers.h12
-rw-r--r--bcm4329/src/include/hndpmu.h4
-rw-r--r--bcm4329/src/include/hndrte_armtrap.h88
-rw-r--r--bcm4329/src/include/hndrte_cons.h63
-rw-r--r--bcm4329/src/include/hndsoc.h2
-rw-r--r--bcm4329/src/include/linux_osl.h5
-rw-r--r--bcm4329/src/include/linuxver.h7
-rw-r--r--bcm4329/src/include/miniopt.h2
-rw-r--r--bcm4329/src/include/msgtrace.h2
-rw-r--r--bcm4329/src/include/osl.h2
-rw-r--r--bcm4329/src/include/packed_section_end.h2
-rw-r--r--bcm4329/src/include/packed_section_start.h2
-rw-r--r--bcm4329/src/include/pcicfg.h2
-rw-r--r--bcm4329/src/include/proto/802.11.h3
-rw-r--r--bcm4329/src/include/proto/802.11e.h2
-rw-r--r--bcm4329/src/include/proto/802.1d.h2
-rw-r--r--bcm4329/src/include/proto/bcmeth.h2
-rw-r--r--bcm4329/src/include/proto/bcmevent.h2
-rw-r--r--bcm4329/src/include/proto/bcmip.h2
-rw-r--r--bcm4329/src/include/proto/ethernet.h5
-rw-r--r--bcm4329/src/include/proto/sdspi.h2
-rw-r--r--bcm4329/src/include/proto/vlan.h2
-rw-r--r--bcm4329/src/include/proto/wpa.h2
-rw-r--r--bcm4329/src/include/sbconfig.h2
-rw-r--r--bcm4329/src/include/sbhnddma.h2
-rw-r--r--bcm4329/src/include/sbpcmcia.h2
-rw-r--r--bcm4329/src/include/sbsdio.h2
-rw-r--r--bcm4329/src/include/sbsdpcmdev.h2
-rw-r--r--bcm4329/src/include/sbsocram.h2
-rw-r--r--bcm4329/src/include/sdio.h2
-rw-r--r--bcm4329/src/include/siutils.h2
-rw-r--r--bcm4329/src/include/trxhdr.h2
-rw-r--r--bcm4329/src/include/typedefs.h2
-rw-r--r--bcm4329/src/include/wlioctl.h19
-rw-r--r--bcm4329/src/shared/aiutils.c4
-rw-r--r--bcm4329/src/shared/bcmutils.c2
-rw-r--r--bcm4329/src/shared/bcmwifi.c2
-rw-r--r--bcm4329/src/shared/hndpmu.c4
-rw-r--r--bcm4329/src/shared/miniopt.c2
-rw-r--r--bcm4329/src/shared/sbutils.c4
-rw-r--r--bcm4329/src/shared/siutils.c2
-rw-r--r--bcm4329/src/shared/siutils_priv.h2
-rw-r--r--bcm4329/src/wl/sys/wl_cfg80211.c4491
-rw-r--r--bcm4329/src/wl/sys/wl_cfg80211.h372
-rw-r--r--bcm4329/src/wl/sys/wl_iw.c1632
-rw-r--r--bcm4329/src/wl/sys/wl_iw.h100
83 files changed, 9230 insertions, 775 deletions
diff --git a/bcm4329/src/bcmsdio/sys/bcmpcispi.c b/bcm4329/src/bcmsdio/sys/bcmpcispi.c
index ba3e0c5..1a8b671 100644
--- a/bcm4329/src/bcmsdio/sys/bcmpcispi.c
+++ b/bcm4329/src/bcmsdio/sys/bcmpcispi.c
@@ -1,7 +1,7 @@
/*
* Broadcom SPI over PCI-SPI Host Controller, low-level hardware driver
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmpcispi.c,v 1.22.2.4.4.5 2008/07/09 21:23:30 Exp $
+ * $Id: bcmpcispi.c,v 1.22.2.4.4.5.6.1 2010/08/13 00:26:05 Exp $
*/
#include <typedefs.h>
@@ -606,18 +606,23 @@ spi_spinbits(sdioh_info_t *sd)
spin_count = 0;
while ((SPIPCI_RREG(sd->osh, &regs->spih_stat) & SPIH_WFEMPTY) == 0) {
if (spin_count > SPI_SPIN_BOUND) {
- ASSERT(FALSE); /* Spin bound exceeded */
+ sd_err(("%s: SPIH_WFEMPTY spin bits out of bound %u times \n",
+ __FUNCTION__, spin_count));
+ ASSERT(FALSE);
}
spin_count++;
}
- spin_count = 0;
+
/* Wait for SPI Transfer state machine to return to IDLE state.
* The state bits are only implemented in Rev >= 5 FPGA. These
* bits are hardwired to 00 for Rev < 5, so this check doesn't cause
* any problems.
*/
+ spin_count = 0;
while ((SPIPCI_RREG(osh, &regs->spih_stat) & SPIH_STATE_MASK) != 0) {
if (spin_count > SPI_SPIN_BOUND) {
+ sd_err(("%s: SPIH_STATE_MASK spin bits out of bound %u times \n",
+ __FUNCTION__, spin_count));
ASSERT(FALSE);
}
spin_count++;
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh.c b/bcm4329/src/bcmsdio/sys/bcmsdh.c
index aed6859..4bf5889 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdh.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdh.c
@@ -40,9 +40,7 @@
#include <sdio.h> /* sdio spec */
-/* Defines number of access retries to configuration registers */
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
-
const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
index 0555f87..559f481 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdh_linux.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_linux.c,v 1.42.10.10.2.12 2010/03/10 03:09:48 Exp $
+ * $Id: bcmsdh_linux.c,v 1.42.10.10.2.14.4.2 2010/09/15 00:30:11 Exp $
*/
/**
@@ -75,7 +75,11 @@ struct bcmsdh_hc {
bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
void *ch;
unsigned int oob_irq;
- unsigned long oob_flags;
+ unsigned long oob_flags; /* OOB Host specifiction as edge and etc */
+ bool oob_irq_registered;
+#if defined(OOB_INTR_ONLY)
+ spinlock_t irq_lock;
+#endif
};
static bcmsdh_hc_t *sdhcinfo = NULL;
@@ -176,7 +180,7 @@ int bcmsdh_probe(struct device *dev)
#endif /* BCMLXSDMMC */
int irq = 0;
uint32 vendevid;
- unsigned long irq_flags = IRQF_TRIGGER_FALLING;
+ unsigned long irq_flags = 0;
#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
pdev = to_platform_device(dev);
@@ -187,6 +191,12 @@ int bcmsdh_probe(struct device *dev)
#endif /* BCMLXSDMMC */
#if defined(OOB_INTR_ONLY)
+#ifdef HW_OOB
+ irq_flags = \
+ IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
+#else
+ irq_flags = IRQF_TRIGGER_FALLING;
+#endif /* HW_OOB */
irq = dhd_customer_oob_irq_map(&irq_flags);
if (irq < 0) {
SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
@@ -225,6 +235,10 @@ int bcmsdh_probe(struct device *dev)
sdhc->sdh = sdh;
sdhc->oob_irq = irq;
sdhc->oob_flags = irq_flags;
+ sdhc->oob_irq_registered = FALSE; /* to make sure.. */
+#if defined(OOB_INTR_ONLY)
+ spin_lock_init(&sdhc->irq_lock);
+#endif
/* chain SDIO Host Controller info together */
sdhc->next = sdhcinfo;
@@ -338,7 +352,7 @@ extern uint sd_pci_slot; /* Force detection to a particular PCI */
/* slot only . Allows for having multiple */
/* WL devices at once in a PC */
/* Only one instance of dhd will be */
- /* useable at a time */
+ /* usable at a time */
/* Upper word is bus number, */
/* lower word is slot number */
/* Default value of 0xFFFFffff turns this */
@@ -365,20 +379,21 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pdev->bus->number != (sd_pci_slot>>16) ||
PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
- __FUNCTION__,
- bcmsdh_chipmatch(pdev->vendor, pdev->device)
- ? "Found compatible SDIOHC"
- : "Probing unknown device",
- pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
- pdev->device));
+ __FUNCTION__,
+ bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
+ "Found compatible SDIOHC" :
+ "Probing unknown device",
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ pdev->vendor, pdev->device));
return -ENODEV;
}
SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
- __FUNCTION__,
- bcmsdh_chipmatch(pdev->vendor, pdev->device)
- ? "Using compatible SDIOHC"
- : "WARNING, forced use of unkown device",
- pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device));
+ __FUNCTION__,
+ bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
+ "Using compatible SDIOHC" :
+ "WARNING, forced use of unkown device",
+ pdev->bus->number, PCI_SLOT(pdev->devfn),
+ pdev->vendor, pdev->device));
}
if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
@@ -439,7 +454,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
rc = pci_enable_device(pdev);
if (rc) {
- SDLX_MSG(("%s: Cannot enble PCI device\n", __FUNCTION__));
+ SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__));
goto err;
}
if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
@@ -566,15 +581,34 @@ bcmsdh_unregister(void)
#endif /* BCMPLATFORM_BUS */
}
+
+
#if defined(OOB_INTR_ONLY)
+void bcmsdh_oob_intr_set(bool enable)
+{
+ static bool curstate = 1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
+ if (curstate != enable) {
+ if (enable)
+ enable_irq(sdhcinfo->oob_irq);
+ else
+ disable_irq_nosync(sdhcinfo->oob_irq);
+ curstate = enable;
+ }
+ spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
+}
+
static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
{
dhd_pub_t *dhdp;
dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
+ bcmsdh_oob_intr_set(0);
+
if (dhdp == NULL) {
- disable_irq(sdhcinfo->oob_irq);
SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
return IRQ_HANDLED;
}
@@ -592,14 +626,18 @@ int bcmsdh_register_oob_intr(void * dhdp)
dev_set_drvdata(sdhcinfo->dev, dhdp);
- /* Refer to customer Host IRQ docs about proper irqflags definition */
- error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
- "bcmsdh_sdmmc", NULL);
-
- if (error)
- return -ENODEV;
+ if (!sdhcinfo->oob_irq_registered) {
+ SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__, \
+ (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
+ /* Refer to customer Host IRQ docs about proper irqflags definition */
+ error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
+ "bcmsdh_sdmmc", NULL);
+ if (error)
+ return -ENODEV;
- set_irq_wake(sdhcinfo->oob_irq, 1);
+ set_irq_wake(sdhcinfo->oob_irq, 1);
+ sdhcinfo->oob_irq_registered = TRUE;
+ }
return 0;
}
@@ -611,14 +649,7 @@ void bcmsdh_unregister_oob_intr(void)
set_irq_wake(sdhcinfo->oob_irq, 0);
disable_irq(sdhcinfo->oob_irq); /* just in case.. */
free_irq(sdhcinfo->oob_irq, NULL);
-}
-
-void bcmsdh_oob_intr_set(bool enable)
-{
- if (enable)
- enable_irq(sdhcinfo->oob_irq);
- else
- disable_irq(sdhcinfo->oob_irq);
+ sdhcinfo->oob_irq_registered = FALSE;
}
#endif /* defined(OOB_INTR_ONLY) */
/* Module parameters specific to each host-controller driver */
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c
index 48d3f37..bda9193 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_sdmmc.c,v 1.1.2.5.6.29 2010/03/19 17:16:08 Exp $
+ * $Id: bcmsdh_sdmmc.c,v 1.1.2.5.6.30.4.1 2010/09/02 23:12:21 Exp $
*/
#include <typedefs.h>
@@ -55,7 +55,7 @@ extern void sdio_function_cleanup(void);
#if !defined(OOB_INTR_ONLY)
static void IRQHandler(struct sdio_func *func);
static void IRQHandlerF2(struct sdio_func *func);
-#endif
+#endif /* !defined(OOB_INTR_ONLY) */
static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
extern int sdio_reset_comm(struct mmc_card *card);
@@ -676,6 +676,8 @@ sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
else
data = 4; /* disable hw oob interrupt */
+ data |= 4; /* Active HIGH */
+
status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
return status;
}
@@ -1064,11 +1066,13 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
return (Status);
}
+/* this function performs "abort" for both of host & device */
extern int
sdioh_abort(sdioh_info_t *sd, uint func)
{
+#if defined(MMC_SDIO_ABORT)
char t_func = (char) func;
-
+#endif /* defined(MMC_SDIO_ABORT) */
sd_trace(("%s: Enter\n", __FUNCTION__));
#if defined(MMC_SDIO_ABORT)
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c
index 196ad4f..8992a42 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdh_sdmmc_linux.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdh_sdmmc_linux.c,v 1.1.2.5.6.15 2010/04/14 21:11:46 Exp $
+ * $Id: bcmsdh_sdmmc_linux.c,v 1.1.2.5.6.17 2010/08/13 00:36:19 Exp $
*/
#include <typedefs.h>
@@ -39,13 +39,22 @@
#if !defined(SDIO_VENDOR_ID_BROADCOM)
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
-#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
+#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */
+
+#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000
+
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)
+#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4325)
-#define SDIO_DEVICE_ID_BROADCOM_4325 0x0000
+#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4329)
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
+#if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
+#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319
+#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
#include <bcmsdh_sdmmc.h>
@@ -116,15 +125,18 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func)
sd_info(("Function#: 0x%04x\n", func->num));
if (func->num == 2) {
- sd_trace(("F2 found, calling bcmsdh_probe...\n"));
+ sd_trace(("F2 found, calling bcmsdh_remove...\n"));
bcmsdh_remove(&sdmmc_dev);
}
}
/* devices we support, null terminated */
static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
{ /* end: all zeroes */ },
};
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c
index 1046a17..e2e0ca6 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdspi_linux.c
@@ -1,7 +1,7 @@
/*
* Broadcom SPI Host Controller Driver - Linux Per-port
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd.c b/bcm4329/src/bcmsdio/sys/bcmsdstd.c
index 0b1b575..0ca1f8f 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdstd.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdstd.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdstd.c,v 1.64.4.1.4.4.2.17 2010/03/10 03:09:48 Exp $
+ * $Id: bcmsdstd.c,v 1.64.4.1.4.4.2.18 2010/08/17 17:00:48 Exp $
*/
#include <typedefs.h>
@@ -119,7 +119,7 @@ extern void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data);
void
sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data)
{
- *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16) data;
+ *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data;
sd_ctrl(("16: W Reg 0x%02x, Data 0x%x\n", reg, data));
}
@@ -129,7 +129,7 @@ sdstd_or_reg16(sdioh_info_t *sd, uint reg, uint16 val)
volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
sd_ctrl(("16: OR Reg 0x%02x, Val 0x%x\n", reg, val));
data |= val;
- *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data;
+ *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data;
}
static void
@@ -140,7 +140,7 @@ sdstd_mod_reg16(sdioh_info_t *sd, uint reg, int16 mask, uint16 val)
sd_ctrl(("16: MOD Reg 0x%02x, Mask 0x%x, Val 0x%x\n", reg, mask, val));
data &= ~mask;
data |= (val & mask);
- *(volatile uint16 *)(sd->mem_space + reg) = (volatile uint16)data;
+ *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data;
}
@@ -155,7 +155,7 @@ sdstd_rreg(sdioh_info_t *sd, uint reg)
static inline void
sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data)
{
- *(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data;
+ *(volatile uint32 *)(sd->mem_space + reg) = (uint32)data;
sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data));
}
@@ -164,7 +164,7 @@ sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data)
static inline void
sdstd_wreg8(sdioh_info_t *sd, uint reg, uint8 data)
{
- *(volatile uint8 *)(sd->mem_space + reg) = (volatile uint8)data;
+ *(volatile uint8 *)(sd->mem_space + reg) = (uint8)data;
sd_ctrl(("08: W Reg 0x%02x, Data 0x%x\n", reg, data));
}
static uint8
@@ -287,7 +287,7 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd)
return SDIOH_API_RC_SUCCESS;
}
-/* Configure callback to client when we recieve client interrupt */
+/* Configure callback to client when we receive client interrupt */
extern SDIOH_API_RC
sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
{
@@ -2778,10 +2778,6 @@ sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int n
data++;
}
- /* Handle < 4 bytes. wlc_pio.c currently (as of 12/20/05) truncates buflen
- * to be evenly divisable by 4. However dongle passes arbitrary lengths,
- * so handle it here
- */
bytes = blocksize % 4;
/* If no leftover bytes, go to next block */
@@ -2898,7 +2894,8 @@ set_client_block_size(sdioh_info_t *sd, int func, int block_size)
}
/* Reset and re-initialize the device */
-int sdioh_sdio_reset(sdioh_info_t *si)
+int
+sdioh_sdio_reset(sdioh_info_t *si)
{
uint8 hreg;
diff --git a/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c b/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c
index 5746b08..a8b98e2 100644
--- a/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c
+++ b/bcm4329/src/bcmsdio/sys/bcmsdstd_linux.c
@@ -1,7 +1,7 @@
/*
* 'Standard' SDIO HOST CONTROLLER driver - linux portion
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdstd_linux.c,v 1.11.18.2 2008/05/28 18:36:56 Exp $
+ * $Id: bcmsdstd_linux.c,v 1.11.18.2.16.1 2010/08/17 17:03:13 Exp $
*/
#include <typedefs.h>
@@ -186,7 +186,9 @@ sdstd_lock(sdioh_info_t *sd)
spin_lock_irqsave(&sdos->lock, flags);
if (sd->lockcount) {
- sd_err(("%s: Already locked!\n", __FUNCTION__));
+ sd_err(("%s: Already locked! called from %p\n",
+ __FUNCTION__,
+ __builtin_return_address(0)));
ASSERT(sd->lockcount == 0);
}
sdstd_devintr_off(sd);
diff --git a/bcm4329/src/dhd/exe/dhdu.c b/bcm4329/src/dhd/exe/dhdu.c
index afd8b61..2d3ec73 100644
--- a/bcm4329/src/dhd/exe/dhdu.c
+++ b/bcm4329/src/dhd/exe/dhdu.c
@@ -828,7 +828,7 @@ dhd_sdreg(void *dhd, cmd_t *cmd, char **argv)
UNUSED_PARAMETER(cmd);
- memset(&sdreg, 0, sizeof(sdreg));
+ bzero(&sdreg, sizeof(sdreg));
/* arg count */
for (argc = 0; argv[argc]; argc++);
@@ -1880,7 +1880,7 @@ dhd_sd_reg(void *dhd, cmd_t *cmd, char **argv)
uint argc;
void *ptr = NULL;
- memset(&sdreg, 0, sizeof(sdreg));
+ bzero(&sdreg, sizeof(sdreg));
/* arg count */
for (argc = 0; argv[argc]; argc++);
diff --git a/bcm4329/src/dhd/linux/Makefile b/bcm4329/src/dhd/linux/Makefile
index 768dd51..4d5a957 100644
--- a/bcm4329/src/dhd/linux/Makefile
+++ b/bcm4329/src/dhd/linux/Makefile
@@ -21,7 +21,7 @@
# software in any way with any other Broadcom software provided under a license
# other than the GPL, without Broadcom's express prior written consent.
#
-# $Id: Makefile,v 1.55.2.6.2.10.6.28 2010/03/26 21:49:31 Exp $
+# $Id: Makefile,v 1.55.2.6.2.10.6.42 2010/08/20 00:15:16 Exp $
#
# Try a couple of places for LINUXDIR if not specified
@@ -161,17 +161,23 @@ endif
ifeq ($(CONFIG_NET_RADIO),y)
CFILES += bcmwifi.c
- ifeq ($(findstring -cfg-,-$(TARGET)-),)
- CFILES += wl_iw.c
- endif
+CFILES += wl_iw.c
else
ifeq ($(CONFIG_WIRELESS_EXT),y)
CFILES += bcmwifi.c
- ifeq ($(findstring -cfg-,-$(TARGET)-),)
- CFILES += wl_iw.c
- endif
+ CFILES += wl_iw.c
endif
endif
+ifeq ($(BCM_KVER), 2.6)
+CFG80211_KVER:=$(shell echo $(LINUXVER) | cut -c5-6 | sed 's/3[1-9]/true/')
+ifeq ($(CFG80211_KVER), true)
+ ifeq ($(CONFIG_CFG80211),m)
+ DFLAGS += -DCONFIG_CFG80211
+ CFILES += wl_cfg80211.c
+ endif
+endif
+endif
+
OFILES=$(CFILES:.c=.o)
@@ -221,10 +227,18 @@ ifneq ($(findstring -softap-,-$(TARGET)-),)
DFLAGS += -DSOFTAP
CFILES += sha1.c md5.c
endif
-ifneq ($(findstring -cfg-,-$(TARGET)-),)
-DFLAGS += -DWL_CFG80211
-CFILES += wl_cfg80211.c
-endif
+ifneq ($(findstring -nexus-,-$(TARGET)-),)
+DFLAGS += -DOEM_ANDROID -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT
+DFLAGS += -Dlinux
+DFLAGS += -DBCMDBG
+DFLAGS += -DDHD_USE_STATIC_BUF
+DFLAGS += -DCUSTOMER_HW2
+DFLAGS += -DCUSTOM_OOB_GPIO_NUM=152
+DFLAGS += -DOOB_INTR_ONLY
+DFLAGS += -DMMC_SDIO_ABORT
+DFLAGS += -DSOFTAP
+DFLAGS += -DPNO_SUPPORT
+else
ifneq ($(findstring -oob-,-$(TARGET)-),)
DFLAGS += -DOOB_INTR_ONLY
DFLAGS += -DHW_OOB
@@ -234,6 +248,7 @@ ifneq ($(findstring -sdmmc-,-$(TARGET)-),)
DFLAGS += -DSDIO_ISR_THREAD
endif
endif
+endif
ifneq ($(findstring -sdmmc-,-$(TARGET)-),)
DFLAGS += -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS
CFILES += dhd_sdio.c bcmsdh_sdmmc.c bcmsdh.c bcmsdh_linux.c bcmsdh_sdmmc_linux.c
@@ -253,6 +268,13 @@ ifneq ($(findstring -intc1,$(shell echo $(LINUXVER))),)
DFLAGS += -DSANDGATE2G
endif
+ifeq ($(OEM_ANDROID),1)
+DFLAGS += -DOEM_ANDROID -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT
+endif
+ifeq ($(OEM_CHROMIUMOS),1)
+DFLAGS += -DOEM_CHROMIUMOS -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT
+endif
+
CFLAGS += -fshort-wchar $(DFLAGS) $(WFLAGS) $(IFLAGS) $(CUSTOM_FLAGS)
@@ -284,11 +306,10 @@ endif
TARGETS := \
dhd-cdc-usb dhd-cdc-sdstd \
- dhd-cdc-sdspi-pci dhd-cdc-sdmmc-gpl dhd-cdc-sdmmc-oob-gpl \
+ dhd-cdc-sdspi-pci dhd-cdc-sdmmc-gpl dhd-cdc-sdmmc-oob-gpl dhd-cdc-sdmmc-nexus-gpl\
dhd-cdc-usb-apsta dhd-cdc-usb-gpl \
dhd-cdc-sdstd-apsta \
- dhd-cdc-sdmmc-softap-gpl \
- dhd-cdc-sdmmc-cfg-gpl
+ dhd-cdc-sdmmc-softap-gpl
TARGETS += \
@@ -335,7 +356,7 @@ endif
ifeq ($(BCM_KVER), 2.6)
$(OBJCOPY) --strip-unneeded $(OBJDIR)/$(KMODULES) $(OBJDIR)/$(KMODULES).stripped
else
- $(OBJCOPY) --strip-unneeded $(OBJDIR)/$(MODULES) $(OBJDIR)/$(MODULES).stripped
+ $(OBJCOPY) --strip-unneeded $(OBJDIR)/dhd.o $(OBJDIR)/dhd.o.stripped
endif
dep: $(foreach file,$(CFILES),.$(file).depend)
diff --git a/bcm4329/src/dhd/linux/makefile.26 b/bcm4329/src/dhd/linux/makefile.26
index eceee8e..da7319b 100644
--- a/bcm4329/src/dhd/linux/makefile.26
+++ b/bcm4329/src/dhd/linux/makefile.26
@@ -22,8 +22,13 @@
# 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: makefile.26,v 1.1.144.1 2008/05/07 22:53:44 Exp $
+# $Id: makefile.26,v 1.1.144.1.14.1 2010/04/16 20:27:14 Exp $
+ifneq ($(findstring -nexus-,-$(TARGET)-),)
+obj-m += bcm4329.o
+bcm4329-objs = $(DHDOFILES)
+else
obj-m += dhd.o
dhd-objs = $(DHDOFILES)
+endif
EXTRA_CFLAGS = $(DHDCFLAGS)
diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h
index 3b22eb7..cc7e8cb 100644
--- a/bcm4329/src/dhd/sys/dhd.h
+++ b/bcm4329/src/dhd/sys/dhd.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd.h,v 1.32.4.7.2.4.14.29 2010/02/23 06:58:21 Exp $
+ * $Id: dhd.h,v 1.32.4.7.2.4.14.49 2010/08/20 17:32:48 Exp $
*/
/****************
@@ -59,6 +59,11 @@
#include <wlioctl.h>
+#ifdef DHD_DEBUG
+#ifndef DHD_DEBUG_TRAP
+#define DHD_DEBUG_TRAP
+#endif
+#endif
/* Forward decls */
struct dhd_bus;
@@ -145,33 +150,48 @@ typedef struct dhd_pub {
/* Last error from dongle */
int dongle_error;
+ /* Suspend disable flag and "in suspend" flag */
+ int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */
+ int in_suspend; /* flag set to 1 when early suspend called */
+#ifdef PNO_SUPPORT
+ int pno_enable; /* pno status : "1" is pno enable */
+#endif /* PNO_SUPPORT */
+ int dtim_skip; /* dtim skip , default 0 means wake each dtim */
+
+ /* Pkt filter defination */
+ char * pktfilter[100];
+ int pktfilter_count;
+
uint8 country_code[WLC_CNTRY_BUF_SZ];
+ char eventmask[WL_EVENTING_MASK_LEN];
+
} dhd_pub_t;
- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
#define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
- #define _DHD_PM_RESUME_WAIT(a, b) do {\
+ #define _DHD_PM_RESUME_WAIT(a, b) do { \
int retry = 0; \
+ smp_mb(); \
while (dhd_mmc_suspend && retry++ != b) { \
wait_event_interruptible_timeout(a, FALSE, HZ/100); \
} \
} while (0)
- #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30)
+ #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30)
#define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0)
#define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0)
#define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0)
#define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
#define SPINWAIT_SLEEP(a, exp, us) do { \
- uint countdown = (us) + 9; \
- while ((exp) && (countdown >= 10)) { \
+ uint countdown = (us) + 9999; \
+ while ((exp) && (countdown >= 10000)) { \
wait_event_interruptible_timeout(a, FALSE, HZ/100); \
- countdown -= 10; \
+ countdown -= 10000; \
} \
} while (0)
- #else
+#else
#define DHD_PM_RESUME_WAIT_INIT(a)
#define DHD_PM_RESUME_WAIT(a)
@@ -188,7 +208,8 @@ typedef struct dhd_pub {
} \
} while (0)
- #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
+
#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */
/* Wakelock Functions */
@@ -262,9 +283,13 @@ extern void dhd_os_sdlock_rxq(dhd_pub_t * pub);
extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_customer_gpio_wlan_ctrl(int onoff);
+extern int dhd_custom_get_mac_address(unsigned char *buf);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
+#ifdef DHD_DEBUG
+extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
+#endif /* DHD_DEBUG */
#if defined(OOB_INTR_ONLY)
extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr);
#endif /* defined(OOB_INTR_ONLY) */
@@ -311,6 +336,7 @@ extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag);
extern uint dhd_bus_status(dhd_pub_t *dhdp);
extern int dhd_bus_start(dhd_pub_t *dhdp);
+extern void print_buf(void *pbuf, int len, int bytes_per_line);
typedef enum cust_gpio_modes {
@@ -320,6 +346,7 @@ typedef enum cust_gpio_modes {
WLAN_POWER_OFF
} cust_gpio_modes_t;
extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
+extern int wl_iw_send_priv_event(struct net_device *dev, char *flag);
/*
* Insmod parameters for debug/test
*/
@@ -327,6 +354,10 @@ extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag
/* Watchdog timer interval */
extern uint dhd_watchdog_ms;
+#if defined(DHD_DEBUG)
+/* Console output poll interval */
+extern uint dhd_console_ms;
+#endif /* defined(DHD_DEBUG) */
/* Use interrupts */
extern uint dhd_intr;
@@ -334,6 +365,27 @@ extern uint dhd_intr;
/* Use polling */
extern uint dhd_poll;
+/* ARP offload agent mode */
+extern uint dhd_arp_mode;
+
+/* ARP offload enable */
+extern uint dhd_arp_enable;
+
+/* Pkt filte enable control */
+extern uint dhd_pkt_filter_enable;
+
+/* Pkt filter init setup */
+extern uint dhd_pkt_filter_init;
+
+/* Pkt filter mode control */
+extern uint dhd_master_mode;
+
+/* Roaming mode control */
+extern uint dhd_roam;
+
+/* Roaming mode control */
+extern uint dhd_radio_up;
+
/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */
extern int dhd_idletime;
#define DHD_IDLETIME_TICKS 1
@@ -364,9 +416,6 @@ extern char nv_path[MOD_PARAM_PATHLEN];
#define DHD_DEL_IF -0xe
#define DHD_BAD_IF -0xf
-#ifdef APSTA_PINGTEST
-#define MAX_GUEST 8
-#endif
extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
extern void dhd_wait_event_wakeup(dhd_pub_t*dhd);
diff --git a/bcm4329/src/dhd/sys/dhd_bus.h b/bcm4329/src/dhd/sys/dhd_bus.h
index 93392f9..9e29fb9 100644
--- a/bcm4329/src/dhd/sys/dhd_bus.h
+++ b/bcm4329/src/dhd/sys/dhd_bus.h
@@ -4,7 +4,7 @@
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_bus.h,v 1.4.6.3.2.3.6.5 2009/06/02 21:56:30 Exp $
+ * $Id: dhd_bus.h,v 1.4.6.3.2.3.6.6 2010/05/17 18:18:13 Exp $
*/
#ifndef _dhd_bus_h_
@@ -60,6 +60,10 @@ extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
/* Watchdog timer function */
extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
+#ifdef DHD_DEBUG
+/* Device console input function */
+extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
+#endif
/* Deferred processing for the bus, return TRUE requests reschedule */
extern bool dhd_bus_dpc(struct dhd_bus *bus);
diff --git a/bcm4329/src/dhd/sys/dhd_cdc.c b/bcm4329/src/dhd/sys/dhd_cdc.c
index 43b21c3..61f6a6f 100644
--- a/bcm4329/src/dhd/sys/dhd_cdc.c
+++ b/bcm4329/src/dhd/sys/dhd_cdc.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_cdc.c,v 1.22.4.2.4.7.2.34 2010/01/21 22:08:34 Exp $
+ * $Id: dhd_cdc.c,v 1.22.4.2.4.7.2.41 2010/06/23 19:58:18 Exp $
*
* 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
@@ -41,6 +41,7 @@
#include <dhd_bus.h>
#include <dhd_dbg.h>
+extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
/* Packet alignment for most efficient SDIO (can change based on platform) */
#ifndef DHD_SDALIGN
@@ -193,7 +194,7 @@ done:
return ret;
}
-static int
+int
dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
{
dhd_prot_t *prot = dhd->prot;
@@ -210,7 +211,7 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
msg->len = htol32(len);
msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET;
CDC_SET_IF_IDX(msg, ifidx);
- msg->flags |= htol32(msg->flags);
+ msg->flags = htol32(msg->flags);
if (buf)
memcpy(prot->buf, buf, len);
@@ -322,23 +323,12 @@ dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
}
-#ifdef APSTA_PINGTEST
-extern struct ether_addr guest_eas[MAX_GUEST];
-#endif
void
dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
{
#ifdef BDC
struct bdc_header *h;
-#ifdef APSTA_PINGTEST
- struct ether_header *eh;
- int i;
-#ifdef DHD_DEBUG
- char eabuf1[ETHER_ADDR_STR_LEN];
- char eabuf2[ETHER_ADDR_STR_LEN];
-#endif /* DHD_DEBUG */
-#endif /* APSTA_PINGTEST */
#endif /* BDC */
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
@@ -346,9 +336,6 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
#ifdef BDC
/* Push BDC header used to convey priority for buses that don't */
-#ifdef APSTA_PINGTEST
- eh = (struct ether_header *)PKTDATA(dhd->osh, pktbuf);
-#endif
PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN);
@@ -361,19 +348,6 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
h->flags2 = 0;
-#ifdef APSTA_PINGTEST
- for (i = 0; i < MAX_GUEST; ++i) {
- if (!ETHER_ISNULLADDR(eh->ether_dhost) &&
- bcmp(eh->ether_dhost, guest_eas[i].octet, ETHER_ADDR_LEN) == 0) {
- DHD_TRACE(("send on if 1; sa %s, da %s\n",
- bcm_ether_ntoa((struct ether_addr *)(eh->ether_shost), eabuf1),
- bcm_ether_ntoa((struct ether_addr *)(eh->ether_dhost), eabuf2)));
- /* assume all guest STAs are on interface 1 */
- h->flags2 = 1;
- break;
- }
- }
-#endif /* APSTA_PINGTEST */
h->rssi = 0;
#endif /* BDC */
BDC_SET_IF_IDX(h, ifidx);
@@ -510,266 +484,30 @@ dhd_prot_dstats(dhd_pub_t *dhd)
return;
}
-int dhd_set_suspend(int value, dhd_pub_t *dhd)
-{
- int power_mode = PM_MAX;
- wl_pkt_filter_enable_t enable_parm;
- char iovbuf[32];
- int bcn_li_dtim = 3;
-#ifdef CUSTOMER_HW2
- uint roamvar = 1;
-#endif /* CUSTOMER_HW2 */
-
-#define htod32(i) i
-
- if (dhd && dhd->up) {
- dhd_os_proto_block(dhd);
- if (value) {
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM,
- (char *)&power_mode, sizeof(power_mode));
- /* Enable packet filter, only allow unicast packet to send up */
- enable_parm.id = htod32(100);
- enable_parm.enable = htod32(1);
- bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm,
- sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- /* set bcn_li_dtim */
- bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
- 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-#ifdef CUSTOMER_HW2
- /* Disable build-in roaming to allowed ext supplicant to take of romaing */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-#endif /* CUSTOMER_HW2 */
- } else {
- power_mode = PM_FAST;
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
- sizeof(power_mode));
- /* disable pkt filter */
- enable_parm.id = htod32(100);
- enable_parm.enable = htod32(0);
- bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm,
- sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- /* set bcn_li_dtim */
- bcn_li_dtim = 0;
- bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
- 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-#ifdef CUSTOMER_HW2
- roamvar = 0;
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-#endif /* CUSTOMER_HW2 */
- }
- dhd_os_proto_unblock(dhd);
- }
-
- return 0;
-}
-
-#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
-
-/* Convert user's input in hex pattern to byte-size mask */
-static int
-wl_pattern_atoh(char *src, char *dst)
-{
- int i;
- if (strncmp(src, "0x", 2) != 0 &&
- strncmp(src, "0X", 2) != 0) {
- printf("Mask invalid format. Needs to start with 0x\n");
- return -1;
- }
- src = src + 2; /* Skip past 0x */
- if (strlen(src) % 2 != 0) {
- printf("Mask invalid format. Needs to be of even length\n");
- return -1;
- }
- for (i = 0; *src != '\0'; i++) {
- char num[3];
- strncpy(num, src, 2);
- num[2] = '\0';
- dst[i] = (uint8)strtoul(num, NULL, 16);
- src += 2;
- }
- return i;
-}
-
int
-dhd_preinit_ioctls(dhd_pub_t *dhd)
+dhd_prot_init(dhd_pub_t *dhd)
{
- char eventmask[WL_EVENTING_MASK_LEN];
- char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
- int ret;
- uint up = 0;
-#ifdef CUSTOMER_HW2
- uint roamvar = 0;
-#else
- uint roamvar = 1;
-#endif
- uint power_mode = PM_FAST;
- uint32 dongle_align = DHD_SDALIGN;
- uint32 glom = 0;
-
- uint bcn_timeout = 3;
- int arpoe = 1;
- int arp_ol = 0xf;
- int scan_assoc_time = 40;
- int scan_unassoc_time = 80;
- const char *str;
- wl_pkt_filter_t pkt_filter;
- wl_pkt_filter_t *pkt_filterp;
- int buf_len;
- int str_len;
- uint32 mask_size;
- uint32 pattern_size;
- char buf[256];
- uint filter_mode = 1;
-
- dhd_os_proto_block(dhd);
- /* Get the device MAC address */
- strcpy(iovbuf, "cur_etheraddr");
- if ((ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
- DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
- dhd_os_proto_unblock(dhd);
- return BCME_NOTUP;
- }
- memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
-
- /* Set Country code */
- if (dhd->country_code[0] != 0) {
- if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
- dhd->country_code, sizeof(dhd->country_code)) < 0) {
- DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
- }
- }
-
- /* Set PowerSave mode */
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode));
+ int ret = 0;
+ char buf[128];
- /* Match Host and Dongle rx alignment */
- bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
- /* disable glom option per default */
- bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- /* Setup timeout if Beacons are lost and roam is off to report link down */
- if (roamvar) {
- bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- }
+ dhd_os_proto_block(dhd);
- /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */
- bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-
- /* Force STA UP */
- dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
-
- /* Setup event_msgs */
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
- bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
-
- setbit(eventmask, WLC_E_SET_SSID);
- setbit(eventmask, WLC_E_PRUNE);
- setbit(eventmask, WLC_E_AUTH);
- setbit(eventmask, WLC_E_REASSOC);
- setbit(eventmask, WLC_E_REASSOC_IND);
- setbit(eventmask, WLC_E_DEAUTH_IND);
- setbit(eventmask, WLC_E_DISASSOC_IND);
- setbit(eventmask, WLC_E_DISASSOC);
- setbit(eventmask, WLC_E_JOIN);
- setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_PSK_SUP);
- setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_NDIS_LINK);
- setbit(eventmask, WLC_E_MIC_ERROR);
- setbit(eventmask, WLC_E_PMKID_CACHE);
- setbit(eventmask, WLC_E_TXFAIL);
- setbit(eventmask, WLC_E_JOIN_START);
- setbit(eventmask, WLC_E_SCAN_COMPLETE);
-
- bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
- sizeof(scan_assoc_time));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
- sizeof(scan_unassoc_time));
-
- /* Set ARP offload */
- bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
- bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
-
- /* add a default packet filter pattern */
- str = "pkt_filter_add";
- str_len = strlen(str);
- strncpy(buf, str, str_len);
- buf[ str_len ] = '\0';
- buf_len = str_len + 1;
-
- pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
-
- /* Parse packet filter id. */
- pkt_filter.id = htod32(100);
-
- /* Parse filter polarity. */
- pkt_filter.negate_match = htod32(0);
-
- /* Parse filter type. */
- pkt_filter.type = htod32(0);
-
- /* Parse pattern filter offset. */
- pkt_filter.u.pattern.offset = htod32(0);
-
- /* Parse pattern filter mask. */
- mask_size = htod32(wl_pattern_atoh("0xff",
- (char *) pkt_filterp->u.pattern.mask_and_pattern));
-
- /* Parse pattern filter pattern. */
- pattern_size = htod32(wl_pattern_atoh("0x00",
- (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
-
- if (mask_size != pattern_size) {
- DHD_ERROR(("Mask and pattern not the same size\n"));
+ /* Get the device MAC address */
+ strcpy(buf, "cur_etheraddr");
+ ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
+ if (ret < 0) {
dhd_os_proto_unblock(dhd);
- return -EINVAL;
+ return ret;
}
-
- pkt_filter.u.pattern.size_bytes = mask_size;
- buf_len += WL_PKT_FILTER_FIXED_LEN;
- buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
-
- /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
- ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
- ** guarantee that the buffer is properly aligned.
- */
- memcpy((char *)pkt_filterp, &pkt_filter,
- WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
-
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
-
- /* set mode to allow pattern */
- bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf));
- dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
dhd_os_proto_unblock(dhd);
- return 0;
-}
-
-int
-dhd_prot_init(dhd_pub_t *dhd)
-{
- int ret = 0;
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
+#ifdef EMBEDDED_PLATFORM
ret = dhd_preinit_ioctls(dhd);
+#endif /* EMBEDDED_PLATFORM */
/* Always assumes wl for now */
dhd->iswl = TRUE;
diff --git a/bcm4329/src/dhd/sys/dhd_common.c b/bcm4329/src/dhd/sys/dhd_common.c
index a0e6a73..bea33b6 100644
--- a/bcm4329/src/dhd/sys/dhd_common.c
+++ b/bcm4329/src/dhd/sys/dhd_common.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_common.c,v 1.5.6.8.2.6.6.41 2010/02/24 01:52:41 Exp $
+ * $Id: dhd_common.c,v 1.5.6.8.2.6.6.69.4.3 2010/09/10 21:30:16 Exp $
*/
#include <typedefs.h>
#include <osl.h>
@@ -37,9 +37,21 @@
#include <dhd_dbg.h>
#include <msgtrace.h>
+#include <wlioctl.h>
+
+#ifdef SET_RANDOM_MAC_SOFTAP
+#include <linux/random.h>
+#include <linux/jiffies.h>
+#endif
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+int wifi_get_mac_addr(unsigned char *buf);
+#endif /* GET_CUSTOM_MAC_ENABLE */
int dhd_msg_level;
+#include <wl_iw.h>
+
char fw_path[MOD_PARAM_PATHLEN];
char nv_path[MOD_PARAM_PATHLEN];
@@ -48,6 +60,25 @@ uint32 dhd_conn_event;
uint32 dhd_conn_status;
uint32 dhd_conn_reason;
+#define htod32(i) i
+#define htod16(i) i
+#define dtoh32(i) i
+#define dtoh16(i) i
+
+extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
+extern void dhd_ind_scan_confirm(void *h, bool status);
+extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen);
+void dhd_iscan_lock(void);
+void dhd_iscan_unlock(void);
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN 32
+#endif
+#if !ISPOWEROF2(DHD_SDALIGN)
+#error DHD_SDALIGN is not a power of 2!
+#endif
+
#ifdef DHD_DEBUG
const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
__DATE__ " at " __TIME__;
@@ -57,7 +88,6 @@ const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
void dhd_set_timer(void *bus, uint wdtick);
-
/* IOVar table */
enum {
IOV_VERSION = 1,
@@ -66,6 +96,10 @@ enum {
IOV_BCMERROR,
IOV_WDTICK,
IOV_DUMP,
+#ifdef DHD_DEBUG
+ IOV_CONS,
+ IOV_DCONSOLE_POLL,
+#endif
IOV_CLEARCOUNTS,
IOV_LOGDUMP,
IOV_LOGCAL,
@@ -84,6 +118,10 @@ const bcm_iovar_t dhd_iovars[] = {
{"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
{"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
{"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
+#ifdef DHD_DEBUG
+ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
+ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
+#endif
{"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
{"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
{"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
@@ -223,6 +261,21 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch
bcmerror = dhd_dump(dhd_pub, arg, len);
break;
+#ifdef DHD_DEBUG
+ case IOV_GVAL(IOV_DCONSOLE_POLL):
+ int_val = (int32)dhd_console_ms;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_DCONSOLE_POLL):
+ dhd_console_ms = (uint)int_val;
+ break;
+
+ case IOV_SVAL(IOV_CONS):
+ if (len > 0)
+ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
+ break;
+#endif
case IOV_SVAL(IOV_CLEARCOUNTS):
dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
@@ -459,9 +512,6 @@ dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
return bcmerror;
}
-#ifdef APSTA_PINGTEST
-struct ether_addr guest_eas[MAX_GUEST];
-#endif
#ifdef SHOW_EVENTS
static void
@@ -570,16 +620,6 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
case WLC_E_ASSOC_IND:
case WLC_E_REASSOC_IND:
-#ifdef APSTA_PINGTEST
- {
- int i;
- for (i = 0; i < MAX_GUEST; ++i)
- if (ETHER_ISNULLADDR(&guest_eas[i]))
- break;
- if (i < MAX_GUEST)
- bcopy(event->addr.octet, guest_eas[i].octet, ETHER_ADDR_LEN);
- }
-#endif /* APSTA_PINGTEST */
DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
break;
@@ -600,18 +640,6 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data)
case WLC_E_DEAUTH_IND:
case WLC_E_DISASSOC_IND:
-#ifdef APSTA_PINGTEST
- {
- int i;
- for (i = 0; i < MAX_GUEST; ++i) {
- if (bcmp(guest_eas[i].octet, event->addr.octet,
- ETHER_ADDR_LEN) == 0) {
- bzero(guest_eas[i].octet, ETHER_ADDR_LEN);
- break;
- }
- }
- }
-#endif /* APSTA_PINGTEST */
DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
break;
@@ -892,3 +920,1264 @@ wl_event_to_host_order(wl_event_msg_t *evt)
evt->datalen = ntoh32(evt->datalen);
evt->version = ntoh16(evt->version);
}
+
+void print_buf(void *pbuf, int len, int bytes_per_line)
+{
+ int i, j = 0;
+ unsigned char *buf = pbuf;
+
+ if (bytes_per_line == 0) {
+ bytes_per_line = len;
+ }
+
+ for (i = 0; i < len; i++) {
+ printf("%2.2x", *buf++);
+ j++;
+ if (j == bytes_per_line) {
+ printf("\n");
+ j = 0;
+ } else {
+ printf(":");
+ }
+ }
+ printf("\n");
+}
+
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+
+#ifdef PKT_FILTER_SUPPORT
+/* Convert user's input in hex pattern to byte-size mask */
+static int
+wl_pattern_atoh(char *src, char *dst)
+{
+ int i;
+ if (strncmp(src, "0x", 2) != 0 &&
+ strncmp(src, "0X", 2) != 0) {
+ DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
+ return -1;
+ }
+ src = src + 2; /* Skip past 0x */
+ if (strlen(src) % 2 != 0) {
+ DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
+ return -1;
+ }
+ for (i = 0; *src != '\0'; i++) {
+ char num[3];
+ strncpy(num, src, 2);
+ num[2] = '\0';
+ dst[i] = (uint8)strtoul(num, NULL, 16);
+ src += 2;
+ }
+ return i;
+}
+
+void
+dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
+{
+ char *argv[8];
+ int i = 0;
+ const char *str;
+ int buf_len;
+ int str_len;
+ char *arg_save = 0, *arg_org = 0;
+ int rc;
+ char buf[128];
+ wl_pkt_filter_enable_t enable_parm;
+ wl_pkt_filter_enable_t * pkt_filterp;
+
+ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+ arg_org = arg_save;
+ memcpy(arg_save, arg, strlen(arg) + 1);
+
+ argv[i] = bcmstrtok(&arg_save, " ", 0);
+
+ i = 0;
+ if (NULL == argv[i]) {
+ DHD_ERROR(("No args provided\n"));
+ goto fail;
+ }
+
+ str = "pkt_filter_enable";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[str_len] = '\0';
+ buf_len = str_len + 1;
+
+ pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
+
+ /* Parse packet filter id. */
+ enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
+
+ /* Parse enable/disable value. */
+ enable_parm.enable = htod32(enable);
+
+ buf_len += sizeof(enable_parm);
+ memcpy((char *)pkt_filterp,
+ &enable_parm,
+ sizeof(enable_parm));
+
+ /* Enable/disable the specified filter. */
+ rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+ else
+ DHD_TRACE(("%s: successfully added pktfilter %s\n",
+ __FUNCTION__, arg));
+
+ /* Contorl the master mode */
+ bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
+ rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+
+fail:
+ if (arg_org)
+ MFREE(dhd->osh, arg_org, strlen(arg) + 1);
+}
+
+void
+dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
+{
+ const char *str;
+ wl_pkt_filter_t pkt_filter;
+ wl_pkt_filter_t *pkt_filterp;
+ int buf_len;
+ int str_len;
+ int rc;
+ uint32 mask_size;
+ uint32 pattern_size;
+ char *argv[8], * buf = 0;
+ int i = 0;
+ char *arg_save = 0, *arg_org = 0;
+#define BUF_SIZE 2048
+
+ if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+
+ arg_org = arg_save;
+
+ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+
+ memcpy(arg_save, arg, strlen(arg) + 1);
+
+ if (strlen(arg) > BUF_SIZE) {
+ DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
+ goto fail;
+ }
+
+ argv[i] = bcmstrtok(&arg_save, " ", 0);
+ while (argv[i++])
+ argv[i] = bcmstrtok(&arg_save, " ", 0);
+
+ i = 0;
+ if (NULL == argv[i]) {
+ DHD_ERROR(("No args provided\n"));
+ goto fail;
+ }
+
+ str = "pkt_filter_add";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+ buf_len = str_len + 1;
+
+ pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
+
+ /* Parse packet filter id. */
+ pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Polarity not provided\n"));
+ goto fail;
+ }
+
+ /* Parse filter polarity. */
+ pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Filter type not provided\n"));
+ goto fail;
+ }
+
+ /* Parse filter type. */
+ pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Offset not provided\n"));
+ goto fail;
+ }
+
+ /* Parse pattern filter offset. */
+ pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Bitmask not provided\n"));
+ goto fail;
+ }
+
+ /* Parse pattern filter mask. */
+ mask_size =
+ htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
+
+ if (NULL == argv[++i]) {
+ DHD_ERROR(("Pattern not provided\n"));
+ goto fail;
+ }
+
+ /* Parse pattern filter pattern. */
+ pattern_size =
+ htod32(wl_pattern_atoh(argv[i],
+ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
+
+ if (mask_size != pattern_size) {
+ DHD_ERROR(("Mask and pattern not the same size\n"));
+ goto fail;
+ }
+
+ pkt_filter.u.pattern.size_bytes = mask_size;
+ buf_len += WL_PKT_FILTER_FIXED_LEN;
+ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
+
+ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
+ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
+ ** guarantee that the buffer is properly aligned.
+ */
+ memcpy((char *)pkt_filterp,
+ &pkt_filter,
+ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
+
+ rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
+ rc = rc >= 0 ? 0 : rc;
+
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+ else
+ DHD_TRACE(("%s: successfully added pktfilter %s\n",
+ __FUNCTION__, arg));
+
+fail:
+ if (arg_org)
+ MFREE(dhd->osh, arg_org, strlen(arg) + 1);
+
+ if (buf)
+ MFREE(dhd->osh, buf, BUF_SIZE);
+}
+#endif
+
+#ifdef ARP_OFFLOAD_SUPPORT
+void
+dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
+{
+ char iovbuf[32];
+ int retcode;
+
+ bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
+ retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
+ __FUNCTION__, arp_mode, retcode));
+ else
+ DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
+ __FUNCTION__, arp_mode));
+}
+
+void
+dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
+{
+ char iovbuf[32];
+ int retcode;
+
+ bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
+ retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
+ __FUNCTION__, arp_enable, retcode));
+ else
+ DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
+ __FUNCTION__, arp_enable));
+}
+#endif
+
+int
+dhd_preinit_ioctls(dhd_pub_t *dhd)
+{
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ uint up = 0;
+ char buf[128], *ptr;
+ uint power_mode = PM_FAST;
+ uint32 dongle_align = DHD_SDALIGN;
+ uint32 glom = 0;
+ uint bcn_timeout = 3;
+ int scan_assoc_time = 40;
+ int scan_unassoc_time = 40;
+#ifdef GET_CUSTOM_MAC_ENABLE
+ int ret;
+ struct ether_addr ea_addr;
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+ dhd_os_proto_block(dhd);
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ /*
+ ** Read MAC address from external customer place
+ ** NOTE that default mac address has to be present in otp or nvram file
+ ** to bring up firmware but unique per board mac address maybe provided
+ ** by customer code
+ */
+ ret = dhd_custom_get_mac_address(ea_addr.octet);
+ if (!ret) {
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ } else
+ memcpy(dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
+ }
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+#ifdef SET_RANDOM_MAC_SOFTAP
+ if (strstr(fw_path, "apsta") != NULL) {
+ uint rand_mac;
+ int ret;
+
+ srandom32((uint)jiffies);
+ rand_mac = random32();
+ iovbuf[0] = 0x02; /* locally administered bit */
+ iovbuf[1] = 0x1A;
+ iovbuf[2] = 0x11;
+ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
+ iovbuf[4] = (unsigned char)(rand_mac >> 8);
+ iovbuf[5] = (unsigned char)(rand_mac >> 16);
+
+ printk("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5]);
+
+ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ } else
+ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
+ }
+#endif /* SET_RANDOM_MAC_SOFTAP */
+
+ /* Set Country code */
+ if (dhd->country_code[0] != 0) {
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
+ dhd->country_code, sizeof(dhd->country_code)) < 0) {
+ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
+ }
+ }
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ bcm_mkiovar("ver", 0, 0, buf, sizeof(buf));
+ dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
+ bcmstrtok(&ptr, "\n", 0);
+ /* Print fw version info */
+ DHD_ERROR(("Firmware version = %s\n", buf));
+
+ /* Set PowerSave mode */
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode));
+
+ /* Match Host and Dongle rx alignment */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* disable glom option per default */
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* 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));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */
+ bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ if (dhd_roam == 0)
+ {
+ /* set internal roaming roaming parameters */
+ int roam_scan_period = 30; /* in sec */
+ int roam_fullscan_period = 120; /* in sec */
+ int roam_trigger = -85;
+ int roam_delta = 15;
+ int band;
+ int band_temp_set = WLC_BAND_2G;
+
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, \
+ (char *)&roam_scan_period, sizeof(roam_scan_period)) < 0)
+ DHD_ERROR(("%s: roam scan setup failed\n", __FUNCTION__));
+
+ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, \
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, \
+ iovbuf, sizeof(iovbuf)) < 0)
+ DHD_ERROR(("%s: roam fullscan setup failed\n", __FUNCTION__));
+
+ if (dhdcdc_query_ioctl(dhd, 0, WLC_GET_BAND, \
+ (char *)&band, sizeof(band)) < 0)
+ DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__));
+ else {
+ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_ALL))
+ {
+ /* temp set band to insert new roams values */
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \
+ (char *)&band_temp_set, sizeof(band_temp_set)) < 0)
+ DHD_ERROR(("%s: local band seting failed\n", __FUNCTION__));
+ }
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_DELTA, \
+ (char *)&roam_delta, sizeof(roam_delta)) < 0)
+ DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__));
+
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_TRIGGER, \
+ (char *)&roam_trigger, sizeof(roam_trigger)) < 0)
+ DHD_ERROR(("%s: roam trigger setting failed\n", __FUNCTION__));
+
+ /* Restore original band settinngs */
+ if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \
+ (char *)&band, sizeof(band)) < 0)
+ DHD_ERROR(("%s: Original band restore failed\n", __FUNCTION__));
+ }
+ }
+
+ /* Force STA UP */
+ if (dhd_radio_up)
+ dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", dhd->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
+ sizeof(scan_assoc_time));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
+ sizeof(scan_unassoc_time));
+
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* Set and enable ARP offload feature */
+ if (dhd_arp_enable)
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, dhd_arp_enable);
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+#ifdef PKT_FILTER_SUPPORT
+ {
+ int i;
+ /* Set up pkt filter */
+ if (dhd_pkt_filter_enable) {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ dhd_pkt_filter_init, dhd_master_mode);
+ }
+ }
+ }
+#endif /* PKT_FILTER_SUPPORT */
+
+ dhd_os_proto_unblock(dhd);
+
+ return 0;
+}
+
+#ifdef SIMPLE_ISCAN
+
+uint iscan_thread_id;
+iscan_buf_t * iscan_chain = 0;
+
+iscan_buf_t *
+dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
+{
+ iscan_buf_t *iscanbuf_alloc = 0;
+ iscan_buf_t *iscanbuf_head;
+
+ dhd_iscan_lock();
+
+ iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
+ if (iscanbuf_alloc == NULL)
+ goto fail;
+
+ iscanbuf_alloc->next = NULL;
+ iscanbuf_head = *iscanbuf;
+
+ DHD_ISCAN(("%s: addr of allocated node = 0x%X"
+ "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
+ __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
+
+ if (iscanbuf_head == NULL) {
+ *iscanbuf = iscanbuf_alloc;
+ DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
+ goto fail;
+ }
+
+ while (iscanbuf_head->next)
+ iscanbuf_head = iscanbuf_head->next;
+
+ iscanbuf_head->next = iscanbuf_alloc;
+
+fail:
+ dhd_iscan_unlock();
+ return iscanbuf_alloc;
+}
+
+void
+dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
+{
+ iscan_buf_t *iscanbuf_free = 0;
+ iscan_buf_t *iscanbuf_prv = 0;
+ iscan_buf_t *iscanbuf_cur = iscan_chain;
+ dhd_pub_t *dhd = dhd_bus_pub(dhdp);
+
+ dhd_iscan_lock();
+ /* If iscan_delete is null then delete the entire
+ * chain or else delete specific one provided
+ */
+ if (!iscan_delete) {
+ while (iscanbuf_cur) {
+ iscanbuf_free = iscanbuf_cur;
+ iscanbuf_cur = iscanbuf_cur->next;
+ iscanbuf_free->next = 0;
+ MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
+ }
+ iscan_chain = 0;
+ } else {
+ while (iscanbuf_cur) {
+ if (iscanbuf_cur == iscan_delete)
+ break;
+ iscanbuf_prv = iscanbuf_cur;
+ iscanbuf_cur = iscanbuf_cur->next;
+ }
+ if (iscanbuf_prv)
+ iscanbuf_prv->next = iscan_delete->next;
+
+ iscan_delete->next = 0;
+ MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
+
+ if (!iscanbuf_prv)
+ iscan_chain = 0;
+ }
+ dhd_iscan_unlock();
+}
+
+iscan_buf_t *
+dhd_iscan_result_buf(void)
+{
+ return iscan_chain;
+}
+
+
+
+/*
+* print scan cache
+* print partial iscan_skip list differently
+*/
+int
+dhd_iscan_print_cache(iscan_buf_t *iscan_skip)
+{
+ int i = 0, l = 0;
+ iscan_buf_t *iscan_cur;
+ wl_iscan_results_t *list;
+ wl_scan_results_t *results;
+ wl_bss_info_t UNALIGNED *bi;
+
+ dhd_iscan_lock();
+
+ iscan_cur = dhd_iscan_result_buf();
+
+ while (iscan_cur) {
+ list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
+ if (!list)
+ break;
+
+ results = (wl_scan_results_t *)&list->results;
+ if (!results)
+ break;
+
+ if (results->version != WL_BSS_INFO_VERSION) {
+ DHD_ISCAN(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
+ __FUNCTION__, results->version));
+ goto done;
+ }
+
+ bi = results->bss_info;
+ for (i = 0; i < results->count; i++) {
+ if (!bi)
+ break;
+
+ DHD_ISCAN(("%s[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
+ iscan_cur != iscan_skip?"BSS":"bss", l, i,
+ bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5]));
+
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+ }
+ iscan_cur = iscan_cur->next;
+ l++;
+ }
+
+done:
+ dhd_iscan_unlock();
+ return 0;
+}
+
+/*
+* delete disappeared AP from specific scan cache but skip partial list in iscan_skip
+*/
+int
+dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip)
+{
+ int i = 0, j = 0, l = 0;
+ iscan_buf_t *iscan_cur;
+ wl_iscan_results_t *list;
+ wl_scan_results_t *results;
+ wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
+
+ uchar *s_addr = addr;
+
+ dhd_iscan_lock();
+ DHD_ISCAN(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, s_addr[0], s_addr[1], s_addr[2],
+ s_addr[3], s_addr[4], s_addr[5]));
+
+ iscan_cur = dhd_iscan_result_buf();
+
+ while (iscan_cur) {
+ if (iscan_cur != iscan_skip) {
+ list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
+ if (!list)
+ break;
+
+ results = (wl_scan_results_t *)&list->results;
+ if (!results)
+ break;
+
+ if (results->version != WL_BSS_INFO_VERSION) {
+ DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
+ __FUNCTION__, results->version));
+ goto done;
+ }
+
+ bi = results->bss_info;
+ for (i = 0; i < results->count; i++) {
+ if (!bi)
+ break;
+
+ if (!memcmp(bi->BSSID.octet, addr, ETHER_ADDR_LEN)) {
+ DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, l, i, bi->BSSID.octet[0],
+ bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4],
+ bi->BSSID.octet[5]));
+
+ bi_new = bi;
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+/*
+ if(bi && bi_new) {
+ bcopy(bi, bi_new, results->buflen -
+ dtoh32(bi_new->length));
+ results->buflen -= dtoh32(bi_new->length);
+ }
+*/
+ results->buflen -= dtoh32(bi_new->length);
+ results->count--;
+
+ for (j = i; j < results->count; j++) {
+ if (bi && bi_new) {
+ DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]"
+ "%X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, l, j, bi->BSSID.octet[0],
+ bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4],
+ bi->BSSID.octet[5]));
+
+ bi_next = (wl_bss_info_t *)((uintptr)bi +
+ dtoh32(bi->length));
+ bcopy(bi, bi_new, dtoh32(bi->length));
+ bi_new = (wl_bss_info_t *)((uintptr)bi_new +
+ dtoh32(bi_new->length));
+ bi = bi_next;
+ }
+ }
+
+ if (results->count == 0) {
+ /* Prune now empty partial scan list */
+ dhd_iscan_free_buf(dhdp, iscan_cur);
+ goto done;
+ }
+ break;
+ }
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+ }
+ }
+ iscan_cur = iscan_cur->next;
+ l++;
+ }
+
+done:
+ dhd_iscan_unlock();
+ return 0;
+}
+
+int
+dhd_iscan_remove_duplicates(void * dhdp, iscan_buf_t *iscan_cur)
+{
+ int i = 0;
+ wl_iscan_results_t *list;
+ wl_scan_results_t *results;
+ wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
+
+ dhd_iscan_lock();
+
+ DHD_ISCAN(("%s: Scan cache before delete\n",
+ __FUNCTION__));
+ dhd_iscan_print_cache(iscan_cur);
+
+ if (!iscan_cur)
+ goto done;
+
+ list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
+ if (!list)
+ goto done;
+
+ results = (wl_scan_results_t *)&list->results;
+ if (!results)
+ goto done;
+
+ if (results->version != WL_BSS_INFO_VERSION) {
+ DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
+ __FUNCTION__, results->version));
+ goto done;
+ }
+
+ bi = results->bss_info;
+ for (i = 0; i < results->count; i++) {
+ if (!bi)
+ break;
+
+ DHD_ISCAN(("%s: Find dups for BSS[%2.2d] %X:%X:%X:%X:%X:%X\n",
+ __FUNCTION__, i, bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5]));
+
+ dhd_iscan_delete_bss(dhdp, bi->BSSID.octet, iscan_cur);
+
+ bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
+ }
+
+done:
+ DHD_ISCAN(("%s: Scan cache after delete\n", __FUNCTION__));
+ dhd_iscan_print_cache(iscan_cur);
+ dhd_iscan_unlock();
+ return 0;
+}
+
+void
+dhd_iscan_ind_scan_confirm(void *dhdp, bool status)
+{
+
+ dhd_ind_scan_confirm(dhdp, status);
+}
+
+int
+dhd_iscan_request(void * dhdp, uint16 action)
+{
+ int rc;
+ wl_iscan_params_t params;
+ dhd_pub_t *dhd = dhd_bus_pub(dhdp);
+ char buf[WLC_IOCTL_SMLEN];
+
+
+ memset(&params, 0, sizeof(wl_iscan_params_t));
+ memcpy(&params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+
+ params.params.bss_type = DOT11_BSSTYPE_ANY;
+ params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
+
+ params.params.nprobes = htod32(-1);
+ params.params.active_time = htod32(-1);
+ params.params.passive_time = htod32(-1);
+ params.params.home_time = htod32(-1);
+ params.params.channel_num = htod32(0);
+
+ params.version = htod32(ISCAN_REQ_VERSION);
+ params.action = htod16(action);
+ params.scan_duration = htod16(0);
+
+ bcm_mkiovar("iscan", (char *)&params, sizeof(wl_iscan_params_t), buf, WLC_IOCTL_SMLEN);
+ rc = dhd_wl_ioctl(dhdp, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN);
+
+ return rc;
+}
+
+static int
+dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
+{
+ wl_iscan_results_t *list_buf;
+ wl_iscan_results_t list;
+ wl_scan_results_t *results;
+ iscan_buf_t *iscan_cur;
+ int status = -1;
+ dhd_pub_t *dhd = dhd_bus_pub(dhdp);
+ int rc;
+
+
+ iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
+ if (!iscan_cur) {
+ DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
+ dhd_iscan_free_buf(dhdp, 0);
+ dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
+ goto fail;
+ }
+
+ dhd_iscan_lock();
+
+ memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
+ list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
+ results = &list_buf->results;
+ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
+ results->version = 0;
+ results->count = 0;
+
+ memset(&list, 0, sizeof(list));
+ list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
+ bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
+ iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
+ rc = dhd_wl_ioctl(dhdp, WLC_GET_VAR, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
+
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ *scan_count = results->count = dtoh32(results->count);
+ status = dtoh32(list_buf->status);
+
+ dhd_iscan_unlock();
+
+ if (!(*scan_count))
+ dhd_iscan_free_buf(dhdp, iscan_cur);
+ else
+ dhd_iscan_remove_duplicates(dhdp, iscan_cur);
+
+
+fail:
+ return status;
+}
+
+#endif
+
+#ifdef PNO_SUPPORT
+int dhd_pno_clean(dhd_pub_t *dhd)
+{
+ char iovbuf[128];
+ int pfn_enabled = 0;
+ int iov_len = 0;
+ int ret;
+
+ /* Disable pfn */
+ iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) >= 0) {
+ /* clear pfn */
+ iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
+ if (iov_len) {
+ if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0) {
+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
+ }
+ }
+ else {
+ ret = -1;
+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len));
+ }
+ }
+ else
+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
+
+ return ret;
+}
+
+int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
+{
+ char iovbuf[128];
+ int ret = -1;
+
+ if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
+ DHD_ERROR(("%s error exit\n", __FUNCTION__));
+ return ret;
+ }
+
+ /* Enable/disable PNO */
+ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
+ if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
+ DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
+ return ret;
+ }
+ else {
+ dhd->pno_enable = pfn_enabled;
+ DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable));
+ }
+ }
+ else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
+
+ return ret;
+}
+
+/* Function to execute combined scan */
+int
+dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr)
+{
+ int err = -1;
+ char iovbuf[128];
+ int k, i;
+ wl_pfn_param_t pfn_param;
+ wl_pfn_t pfn_element;
+
+ DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr));
+
+ if ((!dhd) && (!ssids_local)) {
+ DHD_ERROR(("%s error exit\n", __FUNCTION__));
+ err = -1;
+ }
+
+ /* Check for broadcast ssid */
+ for (k = 0; k < nssid; k++) {
+ if (!ssids_local[k].SSID_len) {
+ DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
+ return err;
+ }
+ }
+/* #define PNO_DUMP 1 */
+#ifdef PNO_DUMP
+ {
+ int j;
+ for (j = 0; j < nssid; j++) {
+ DHD_ERROR(("%d: scan for %s size =%d\n", j,
+ ssids_local[j].SSID, ssids_local[j].SSID_len));
+ }
+ }
+#endif /* PNO_DUMP */
+
+ /* clean up everything */
+ if ((err = dhd_pno_clean(dhd)) < 0) {
+ DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
+ return err;
+ }
+ memset(&pfn_param, 0, sizeof(pfn_param));
+ memset(&pfn_element, 0, sizeof(pfn_element));
+
+ /* set pfn parameters */
+ pfn_param.version = htod32(PFN_VERSION);
+ pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
+
+ /* set up pno scan fr */
+ if (scan_fr != 0)
+ pfn_param.scan_freq = htod32(scan_fr);
+
+ bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+
+ /* set all pfn ssid */
+ for (i = 0; i < nssid; i++) {
+
+ pfn_element.bss_type = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
+ pfn_element.auth = (DOT11_OPEN_SYSTEM);
+ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
+ pfn_element.wsec = htod32(0);
+ pfn_element.infra = htod32(1);
+
+ memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
+ pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
+
+ if ((err =
+ bcm_mkiovar("pfn_add", (char *)&pfn_element,
+ sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
+ if ((err =
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
+ DHD_ERROR(("%s failed for i=%d error=%d\n",
+ __FUNCTION__, i, err));
+ return err;
+ }
+ }
+ else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err));
+ }
+
+ /* Enable PNO */
+ /* dhd_pno_enable(dhd, 1); */
+ return err;
+}
+
+int dhd_pno_get_status(dhd_pub_t *dhd)
+{
+ int ret = -1;
+
+ if (!dhd)
+ return ret;
+ else
+ return (dhd->pno_enable);
+}
+
+#endif /* PNO_SUPPORT */
+
+#if defined(CSCAN)
+
+/* Androd ComboSCAN support */
+/*
+ * data parsing from ComboScan tlv list
+*/
+int
+wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token,
+ int input_size, int *bytes_left)
+{
+ char* str = *list_str;
+ uint16 short_temp;
+ uint32 int_temp;
+
+ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
+ DHD_ERROR(("%s error paramters\n", __FUNCTION__));
+ return -1;
+ }
+
+ /* Clean all dest bytes */
+ memset(dst, 0, dst_size);
+ while (*bytes_left > 0) {
+
+ if (str[0] != token) {
+ DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
+ __FUNCTION__, token, str[0], *bytes_left));
+ return -1;
+ }
+
+ *bytes_left -= 1;
+ str += 1;
+
+ if (input_size == 1) {
+ memcpy(dst, str, input_size);
+ }
+ else if (input_size == 2) {
+ memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
+ input_size);
+ }
+ else if (input_size == 4) {
+ memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
+ input_size);
+ }
+
+ *bytes_left -= input_size;
+ str += input_size;
+ *list_str = str;
+ return 1;
+ }
+ return 1;
+}
+
+/*
+ * channel list parsing from cscan tlv list
+*/
+int
+wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
+ int channel_num, int *bytes_left)
+{
+ char* str = *list_str;
+ int idx = 0;
+
+ if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
+ DHD_ERROR(("%s error paramters\n", __FUNCTION__));
+ return -1;
+ }
+
+ while (*bytes_left > 0) {
+
+ if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
+ *list_str = str;
+ DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
+ return idx;
+ }
+ /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
+ *bytes_left -= 1;
+ str += 1;
+
+ if (str[0] == 0) {
+ /* All channels */
+ channel_list[idx] = 0x0;
+ }
+ else {
+ channel_list[idx] = (uint16)str[0];
+ DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx]));
+ }
+ *bytes_left -= 1;
+ str += 1;
+
+ if (idx++ > 255) {
+ DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
+ return -1;
+ }
+ }
+
+ *list_str = str;
+ return idx;
+}
+
+/*
+ * SSIDs list parsing from cscan tlv list
+ */
+int
+wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
+{
+ char* str = *list_str;
+ int idx = 0;
+
+ if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
+ DHD_ERROR(("%s error paramters\n", __FUNCTION__));
+ return -1;
+ }
+
+ while (*bytes_left > 0) {
+
+ if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
+ *list_str = str;
+ DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
+ return idx;
+ }
+
+ /* Get proper CSCAN_TLV_TYPE_SSID_IE */
+ *bytes_left -= 1;
+ str += 1;
+
+ if (str[0] == 0) {
+ /* Broadcast SSID */
+ ssid[idx].SSID_len = 0;
+ memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
+ *bytes_left -= 1;
+ str += 1;
+
+ DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left));
+ }
+ else if (str[0] <= DOT11_MAX_SSID_LEN) {
+ /* Get proper SSID size */
+ ssid[idx].SSID_len = str[0];
+ *bytes_left -= 1;
+ str += 1;
+
+ /* Get SSID */
+ if (ssid[idx].SSID_len > *bytes_left) {
+ DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
+ __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
+ return -1;
+ }
+
+ memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len);
+
+ *bytes_left -= ssid[idx].SSID_len;
+ str += ssid[idx].SSID_len;
+
+ DHD_TRACE(("%s :size=%d left=%d\n",
+ (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left));
+ }
+ else {
+ DHD_ERROR(("### SSID size more that %d\n", str[0]));
+ return -1;
+ }
+
+ if (idx++ > max) {
+ DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx));
+ return -1;
+ }
+ }
+
+ *list_str = str;
+ return idx;
+}
+
+/* Parse a comma-separated list from list_str into ssid array, starting
+ * at index idx. Max specifies size of the ssid array. Parses ssids
+ * and returns updated idx; if idx >= max not all fit, the excess have
+ * not been copied. Returns -1 on empty string, or on ssid too long.
+ */
+int
+wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max)
+{
+ char* str, *ptr;
+
+ if ((list_str == NULL) || (*list_str == NULL))
+ return -1;
+
+ for (str = *list_str; str != NULL; str = ptr) {
+
+ /* check for next TAG */
+ if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
+ *list_str = str + strlen(GET_CHANNEL);
+ return idx;
+ }
+
+ if ((ptr = strchr(str, ',')) != NULL) {
+ *ptr++ = '\0';
+ }
+
+ if (strlen(str) > DOT11_MAX_SSID_LEN) {
+ DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
+ return -1;
+ }
+
+ if (strlen(str) == 0)
+ ssid[idx].SSID_len = 0;
+
+ if (idx < max) {
+ strcpy((char*)ssid[idx].SSID, str);
+ ssid[idx].SSID_len = strlen(str);
+ }
+ idx++;
+ }
+ return idx;
+}
+
+/*
+ * Parse channel list from iwpriv CSCAN
+ */
+int
+wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num)
+{
+ int num;
+ int val;
+ char* str;
+ char* endptr = NULL;
+
+ if ((list_str == NULL)||(*list_str == NULL))
+ return -1;
+
+ str = *list_str;
+ num = 0;
+ while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
+ val = (int)strtoul(str, &endptr, 0);
+ if (endptr == str) {
+ printf("could not parse channel number starting at"
+ " substring \"%s\" in list:\n%s\n",
+ str, *list_str);
+ return -1;
+ }
+ str = endptr + strspn(endptr, " ,");
+
+ if (num == channel_num) {
+ DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
+ channel_num, *list_str));
+ return -1;
+ }
+
+ channel_list[num++] = (uint16)val;
+ }
+ *list_str = str;
+ return num;
+}
+
+#endif
diff --git a/bcm4329/src/dhd/sys/dhd_custom_gpio.c b/bcm4329/src/dhd/sys/dhd_custom_gpio.c
index 2dc6e42..8c6ec47 100644
--- a/bcm4329/src/dhd/sys/dhd_custom_gpio.c
+++ b/bcm4329/src/dhd/sys/dhd_custom_gpio.c
@@ -20,7 +20,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
-* $Id: dhd_custom_gpio.c,v 1.1.4.6 2010/02/19 22:56:49 Exp $
+* $Id: dhd_custom_gpio.c,v 1.1.4.8.4.1 2010/09/02 23:13:16 Exp $
*/
@@ -42,11 +42,11 @@
extern void bcm_wlan_power_off(int);
extern void bcm_wlan_power_on(int);
#endif /* CUSTOMER_HW */
-
#ifdef CUSTOMER_HW2
int wifi_set_carddetect(int on);
int wifi_set_power(int on, unsigned long msec);
int wifi_get_irq_number(unsigned long *irq_flags_ptr);
+int wifi_get_mac_addr(unsigned char *buf);
#endif
#if defined(OOB_INTR_ONLY)
@@ -55,6 +55,10 @@ int wifi_get_irq_number(unsigned long *irq_flags_ptr);
extern int sdioh_mmc_irq(int irq);
#endif /* (BCMLXSDMMC) */
+#ifdef CUSTOMER_HW3
+#include <mach/gpio.h>
+#endif
+
/* Customer specific Host GPIO defintion */
static int dhd_oob_gpio_num = -1; /* GG 19 */
@@ -63,27 +67,36 @@ MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number");
int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr)
{
- int host_oob_irq;
+ int host_oob_irq = 0;
+
#ifdef CUSTOMER_HW2
host_oob_irq = wifi_get_irq_number(irq_flags_ptr);
-#else
+
+#else /* for NOT CUSTOMER_HW2 */
#if defined(CUSTOM_OOB_GPIO_NUM)
if (dhd_oob_gpio_num < 0) {
dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM;
}
#endif
- *irq_flags_ptr = IRQF_TRIGGER_FALLING;
+
if (dhd_oob_gpio_num < 0) {
WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n",
- __FUNCTION__));
+ __FUNCTION__));
return (dhd_oob_gpio_num);
}
WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n",
__FUNCTION__, dhd_oob_gpio_num));
- host_oob_irq = sdioh_mmc_irq(dhd_oob_gpio_num);
-#endif
+#if defined CUSTOMER_HW
+ host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num);
+#elif defined CUSTOMER_HW3
+ gpio_request(dhd_oob_gpio_num, "oob irq");
+ host_oob_irq = gpio_to_irq(dhd_oob_gpio_num);
+ gpio_direction_input(dhd_oob_gpio_num);
+#endif /* CUSTOMER_HW */
+#endif /* CUSTOMER_HW2 */
+
return (host_oob_irq);
}
#endif /* defined(OOB_INTR_ONLY) */
@@ -130,9 +143,37 @@ dhd_customer_gpio_wlan_ctrl(int onoff)
__FUNCTION__));
#ifdef CUSTOMER_HW
bcm_wlan_power_on(1);
-#endif /* CUSTOMER_HW */
/* Lets customer power to get stable */
- OSL_DELAY(500);
+ OSL_DELAY(50);
+#endif /* CUSTOMER_HW */
break;
}
}
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+/* Function to get custom MAC address */
+int
+dhd_custom_get_mac_address(unsigned char *buf)
+{
+ int ret = 0;
+
+ WL_TRACE(("%s Enter\n", __FUNCTION__));
+ if (!buf)
+ return -EINVAL;
+
+ /* Customer access to MAC address stored outside of DHD driver */
+#ifdef CUSTOMER_HW2
+ ret = wifi_get_mac_addr(buf);
+#endif
+
+#ifdef EXAMPLE_GET_MAC
+ /* EXAMPLE code */
+ {
+ struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
+ bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
+ }
+#endif /* EXAMPLE_GET_MAC */
+
+ return ret;
+}
+#endif /* GET_CUSTOM_MAC_ENABLE */
diff --git a/bcm4329/src/dhd/sys/dhd_dbg.h b/bcm4329/src/dhd/sys/dhd_dbg.h
index e6d18f7..b48c1d7 100644
--- a/bcm4329/src/dhd/sys/dhd_dbg.h
+++ b/bcm4329/src/dhd/sys/dhd_dbg.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_dbg.h,v 1.5.6.2.4.2.14.4 2009/12/11 01:13:49 Exp $
+ * $Id: dhd_dbg.h,v 1.5.6.2.4.2.14.10 2010/05/21 21:49:38 Exp $
*/
#ifndef _dhd_dbg_
@@ -42,6 +42,7 @@
#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0)
#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
+#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0)
#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
@@ -55,6 +56,7 @@
#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
+#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
#else /* DHD_DEBUG */
@@ -70,6 +72,7 @@
#define DHD_GLOM(args)
#define DHD_EVENT(args)
#define DHD_BTA(args)
+#define DHD_ISCAN(args)
#define DHD_ERROR_ON() 0
#define DHD_TRACE_ON() 0
@@ -83,7 +86,7 @@
#define DHD_GLOM_ON() 0
#define DHD_EVENT_ON() 0
#define DHD_BTA_ON() 0
-
+#define DHD_ISCAN_ON() 0
#endif /* DHD_DEBUG */
#define DHD_LOG(args)
diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c
index c25a9b7..2eff469 100644
--- a/bcm4329/src/dhd/sys/dhd_linux.c
+++ b/bcm4329/src/dhd/sys/dhd_linux.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.66 2010/04/01 17:01:25 Exp $
+ * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.104 2010/08/20 19:15:40 Exp $
*/
#ifdef CONFIG_WIFI_CONTROL_FUNC
@@ -61,7 +61,6 @@
#ifdef CONFIG_HAS_WAKELOCK
#include <linux/wakelock.h>
#endif
-#include <linux/freezer.h>
#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
#include <linux/wlan_plat.h>
@@ -116,6 +115,17 @@ int wifi_set_reset(int on, unsigned long msec)
return 0;
}
+int wifi_get_mac_addr(unsigned char *buf)
+{
+ printk("%s\n", __FUNCTION__);
+ if (!buf)
+ return -EINVAL;
+ if (wifi_control_data && wifi_control_data->get_mac_addr) {
+ return wifi_control_data->get_mac_addr(buf);
+ }
+ return -EOPNOTSUPP;
+}
+
static int wifi_probe(struct platform_device *pdev)
{
struct wifi_platform_data *wifi_ctrl =
@@ -140,8 +150,8 @@ static int wifi_remove(struct platform_device *pdev)
DHD_TRACE(("## %s\n", __FUNCTION__));
wifi_control_data = wifi_ctrl;
- wifi_set_carddetect(0); /* CardDetect (1->0) */
wifi_set_power(0, 0); /* Power Off */
+ wifi_set_carddetect(0); /* CardDetect (1->0) */
up(&wifi_control_sem);
return 0;
@@ -205,12 +215,18 @@ print_tainted()
/* Linux wireless extension support */
#if defined(CONFIG_WIRELESS_EXT)
#include <wl_iw.h>
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
+extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+#ifdef PKT_FILTER_SUPPORT
+extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
+extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
+#endif
+
/* Interface control information */
typedef struct dhd_if {
struct dhd_info *info; /* back pointer to dhd_info */
@@ -230,7 +246,7 @@ typedef struct dhd_if {
typedef struct dhd_info {
#if defined(CONFIG_WIRELESS_EXT)
wl_iw_t iw; /* wireless extensions state (must be first) */
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
dhd_pub_t pub;
@@ -263,6 +279,8 @@ typedef struct dhd_info {
int wl_count;
int wl_packet;
+ int hang_was_sent;
+
/* Thread to issue ioctl for multicast */
long sysioc_pid;
struct semaphore sysioc_sem;
@@ -286,7 +304,8 @@ char nvram_path[MOD_PARAM_PATHLEN];
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
struct semaphore dhd_registration_sem;
-#endif
+#define DHD_REGISTRATION_TIMEOUT 8000 /* msec : allowed time to finished dhd registration */
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
/* load firmware and/or nvram values from the filesystem */
module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0);
module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
@@ -302,6 +321,31 @@ module_param(dhd_sysioc, uint, 0);
uint dhd_watchdog_ms = 10;
module_param(dhd_watchdog_ms, uint, 0);
+#ifdef DHD_DEBUG
+/* Console poll interval */
+uint dhd_console_ms = 0;
+module_param(dhd_console_ms, uint, 0);
+#endif /* DHD_DEBUG */
+
+/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
+uint dhd_arp_mode = 0xb;
+module_param(dhd_arp_mode, uint, 0);
+
+/* ARP offload enable */
+uint dhd_arp_enable = TRUE;
+module_param(dhd_arp_enable, uint, 0);
+
+/* Global Pkt filter enable control */
+uint dhd_pkt_filter_enable = TRUE;
+module_param(dhd_pkt_filter_enable, uint, 0);
+
+/* Pkt filter init setup */
+uint dhd_pkt_filter_init = 0;
+module_param(dhd_pkt_filter_init, uint, 0);
+
+/* Pkt filter mode control */
+uint dhd_master_mode = TRUE;
+module_param(dhd_master_mode, uint, 1);
/* Watchdog thread priority, -1 to use kernel timer */
int dhd_watchdog_prio = 97;
@@ -315,6 +359,16 @@ module_param(dhd_dpc_prio, int, 0);
extern int dhd_dongle_memsize;
module_param(dhd_dongle_memsize, int, 0);
+/* Control fw roaming */
+#ifdef CUSTOMER_HW2
+uint dhd_roam = 0;
+#else
+uint dhd_roam = 1;
+#endif
+
+/* Control radio state */
+uint dhd_radio_up = 1;
+
/* Network inteface name */
char iface_name[IFNAMSIZ];
module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
@@ -383,6 +437,9 @@ module_param(dhd_pktgen_len, uint, 0);
/* Version string to report */
#ifdef DHD_DEBUG
+#ifndef SRCBASE
+#define SRCBASE "drivers/net/wireless/bcm4329"
+#endif
#define DHD_COMPILED "\nCompiled in " SRCBASE
#else
#define DHD_COMPILED
@@ -397,7 +454,7 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
#if defined(CONFIG_WIRELESS_EXT)
struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
static void dhd_dpc(ulong data);
/* forward decl */
@@ -417,18 +474,22 @@ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
{
- switch (action)
- {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- dhd_mmc_suspend = TRUE;
- return NOTIFY_OK;
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- dhd_mmc_suspend = FALSE;
- return NOTIFY_OK;
+ int ret = NOTIFY_DONE;
+
+ switch (action) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ dhd_mmc_suspend = TRUE;
+ ret = NOTIFY_OK;
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ dhd_mmc_suspend = FALSE;
+ ret = NOTIFY_OK;
+ break;
}
- return 0;
+ smp_mb();
+ return ret;
}
static struct notifier_block dhd_sleep_pm_notifier = {
@@ -439,28 +500,126 @@ extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
+static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
+{
+#ifdef PKT_FILTER_SUPPORT
+ DHD_TRACE(("%s: %d\n", __FUNCTION__, value));
+ /* 1 - Enable packet filter, only allow unicast packet to send up */
+ /* 0 - Disable packet filter */
+ if (dhd_pkt_filter_enable) {
+ int i;
+
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+ dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
+ dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
+ value, dhd_master_mode);
+ }
+ }
+#endif
+}
#if defined(CONFIG_HAS_EARLYSUSPEND)
-extern int dhd_set_suspend(int value, dhd_pub_t *dhd);
+static int dhd_set_suspend(int value, dhd_pub_t *dhd)
+{
+ int power_mode = PM_MAX;
+ /* wl_pkt_filter_enable_t enable_parm; */
+ char iovbuf[32];
+ int bcn_li_dtim = 3;
+#ifdef CUSTOMER_HW2
+ uint roamvar = 1;
+#endif /* CUSTOMER_HW2 */
+
+ DHD_TRACE(("%s: enter, value = %d in_suspend = %d\n",
+ __FUNCTION__, value, dhd->in_suspend));
+
+ if (dhd && dhd->up) {
+ if (value && dhd->in_suspend) {
+
+ /* Kernel suspended */
+ DHD_TRACE(("%s: force extra Suspend setting \n", __FUNCTION__));
+
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM,
+ (char *)&power_mode, sizeof(power_mode));
+
+ /* Enable packet filter, only allow unicast packet to send up */
+ dhd_set_packet_filter(1, dhd);
+
+ /* if dtim skip setup as default force it to wake each thrid dtim
+ * for better power saving.
+ * Note that side effect is chance to miss BC/MC packet
+ */
+ if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
+ bcn_li_dtim = 3;
+ else
+ bcn_li_dtim = dhd->dtim_skip;
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+#ifdef CUSTOMER_HW2
+ /* Disable build-in roaming to allowed ext supplicant to take of roaming */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+#endif /* CUSTOMER_HW2 */
+ } else {
+
+ /* Kernel resumed */
+ DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
+
+ power_mode = PM_FAST;
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
+ sizeof(power_mode));
+
+ /* disable pkt filter */
+ dhd_set_packet_filter(0, dhd);
+
+ /* restore pre-suspend setting for dtim_skip */
+ bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
+ 4, iovbuf, sizeof(iovbuf));
+
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+#ifdef CUSTOMER_HW2
+ roamvar = dhd_roam;
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
+#endif /* CUSTOMER_HW2 */
+ }
+ }
+
+ return 0;
+}
+
+static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
+{
+ dhd_pub_t *dhdp = &dhd->pub;
+
+ dhd_os_wake_lock(dhdp);
+ dhd_os_proto_block(dhdp);
+ /* Set flag when early suspend was called */
+ dhdp->in_suspend = val;
+ if (!dhdp->suspend_disable_flag)
+ dhd_set_suspend(val, dhdp);
+ dhd_os_proto_unblock(dhdp);
+ dhd_os_wake_unlock(dhdp);
+}
static void dhd_early_suspend(struct early_suspend *h)
{
- struct dhd_info *dhdp;
- dhdp = container_of(h, struct dhd_info, early_suspend);
+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
DHD_TRACE(("%s: enter\n", __FUNCTION__));
- dhd_set_suspend(1, &dhdp->pub);
+ if (dhd)
+ dhd_suspend_resume_helper(dhd, 1);
}
static void dhd_late_resume(struct early_suspend *h)
{
- struct dhd_info *dhdp;
- dhdp = container_of(h, struct dhd_info, early_suspend);
+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
DHD_TRACE(("%s: enter\n", __FUNCTION__));
- dhd_set_suspend(0, &dhdp->pub);
+ if (dhd)
+ dhd_suspend_resume_helper(dhd, 0);
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
@@ -584,7 +743,11 @@ static void
_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
{
struct net_device *dev;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ struct netdev_hw_addr *ha;
+#else
struct dev_mc_list *mclist;
+#endif
uint32 allmulti, cnt;
wl_ioctl_t ioc;
@@ -594,15 +757,19 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
ASSERT(dhd && dhd->iflist[ifidx]);
dev = dhd->iflist[ifidx]->net;
- mclist = dev->mc_list;
+
+ netif_addr_lock_bh(dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ cnt = netdev_mc_count(dev);
+#else
cnt = dev->mc_count;
+#endif
+ netif_addr_unlock_bh(dev);
/* Determine initial value of allmulti flag */
allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
/* Send down the multicast list first. */
-
-
buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
@@ -617,10 +784,22 @@ _dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
memcpy(bufp, &cnt, sizeof(cnt));
bufp += sizeof(cnt);
- for (cnt = 0; mclist && (cnt < dev->mc_count); cnt++, mclist = mclist->next) {
+ netif_addr_lock_bh(dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ netdev_for_each_mc_addr(ha, dev) {
+ if (!cnt)
+ break;
+ memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
+ bufp += ETHER_ADDR_LEN;
+ cnt--;
+ }
+#else
+ for (mclist = dev->mc_list;(mclist && (cnt > 0)); cnt--, mclist = mclist->next) {
memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
bufp += ETHER_ADDR_LEN;
}
+#endif
+ netif_addr_unlock_bh(dev);
memset(&ioc, 0, sizeof(ioc));
ioc.cmd = WLC_SET_VAR;
@@ -810,8 +989,6 @@ _dhd_sysioc_thread(void *data)
bool in_ap = FALSE;
#endif
- set_freezable();
-
DAEMONIZE("dhd_sysioc");
while (down_interruptible(&dhd->sysioc_sem) == 0) {
@@ -941,11 +1118,19 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ dhd_os_wake_lock(&dhd->pub);
+
/* Reject if down */
if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) {
DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n",
__FUNCTION__, dhd->pub.up, dhd->pub.busstate));
netif_stop_queue(net);
+ /* Send Event when bus down detected during data session */
+ if (dhd->pub.busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__));
+ net_os_send_hang_message(net);
+ }
+ dhd_os_wake_unlock(&dhd->pub);
return -ENODEV;
}
@@ -953,6 +1138,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
if (ifidx == DHD_BAD_IF) {
DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
netif_stop_queue(net);
+ dhd_os_wake_unlock(&dhd->pub);
return -ENODEV;
}
@@ -984,13 +1170,14 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
-
done:
if (ret)
dhd->pub.dstats.tx_dropped++;
else
dhd->pub.tx_packets++;
+ dhd_os_wake_unlock(&dhd->pub);
+
/* Return ok: we always eat the packet */
return 0;
}
@@ -1187,24 +1374,19 @@ dhd_watchdog_thread(void *data)
}
#endif /* DHD_SCHED */
- set_freezable();
-
DAEMONIZE("dhd_watchdog");
/* Run until signal received */
while (1) {
if (down_interruptible (&dhd->watchdog_sem) == 0) {
dhd_os_wake_lock(&dhd->pub);
- /* Call the bus module watchdog */
- dhd_bus_watchdog(&dhd->pub);
+ if (dhd->pub.dongle_reset == FALSE) {
+ /* Call the bus module watchdog */
+ dhd_bus_watchdog(&dhd->pub);
+ }
/* Count the tick for reference */
dhd->pub.tickcnt++;
-
- /* Reschedule the watchdog */
- if (dhd->wd_timer_valid) {
- mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
- }
dhd_os_wake_unlock(&dhd->pub);
}
else
@@ -1219,8 +1401,15 @@ dhd_watchdog(ulong data)
{
dhd_info_t *dhd = (dhd_info_t *)data;
+ dhd_os_wake_lock(&dhd->pub);
if (dhd->watchdog_pid >= 0) {
up(&dhd->watchdog_sem);
+
+ /* Reschedule the watchdog */
+ if (dhd->wd_timer_valid) {
+ mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
+ }
+ dhd_os_wake_unlock(&dhd->pub);
return;
}
@@ -1231,12 +1420,9 @@ dhd_watchdog(ulong data)
dhd->pub.tickcnt++;
/* Reschedule the watchdog */
-#if defined(CONTINUOUS_WATCHDOG)
- mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
-#else
if (dhd->wd_timer_valid)
mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
-#endif /* defined(CONTINUOUS_WATCHDOG) */
+ dhd_os_wake_unlock(&dhd->pub);
}
static int
@@ -1256,8 +1442,6 @@ dhd_dpc_thread(void *data)
}
#endif /* DHD_SCHED */
- set_freezable();
-
DAEMONIZE("dhd_dpc");
/* Run until signal received */
@@ -1526,28 +1710,40 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
uint driver = 0;
int ifidx;
bool is_set_key_cmd;
+ int ret;
+
+ dhd_os_wake_lock(&dhd->pub);
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
- if (ifidx == DHD_BAD_IF)
+ if (ifidx == DHD_BAD_IF) {
+ dhd_os_wake_unlock(&dhd->pub);
return -1;
+ }
#if defined(CONFIG_WIRELESS_EXT)
/* linux wireless extensions */
if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
/* may recurse, do NOT lock */
- return wl_iw_ioctl(net, ifr, cmd);
+ ret = wl_iw_ioctl(net, ifr, cmd);
+ dhd_os_wake_unlock(&dhd->pub);
+ return ret;
}
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
- if (cmd == SIOCETHTOOL)
- return (dhd_ethtool(dhd, (void*)ifr->ifr_data));
+ if (cmd == SIOCETHTOOL) {
+ ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
+ dhd_os_wake_unlock(&dhd->pub);
+ return ret;
+ }
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
- if (cmd != SIOCDEVPRIVATE)
+ if (cmd != SIOCDEVPRIVATE) {
+ dhd_os_wake_unlock(&dhd->pub);
return -EOPNOTSUPP;
+ }
memset(&ioc, 0, sizeof(ioc));
@@ -1600,7 +1796,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
/* send to dongle (must be up, and wl) */
if (dhd->pub.busstate != DHD_BUS_DATA) {
- DHD_ERROR(("%s DONGLE_DOWN,__FUNCTION__\n", __FUNCTION__));
+ DHD_ERROR(("%s DONGLE_DOWN\n", __FUNCTION__));
bcmerror = BCME_DONGLE_DOWN;
goto done;
}
@@ -1625,6 +1821,12 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
bcmerror = dhd_prot_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
done:
+ if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) &&
+ (!dhd->pub.dongle_reset))) {
+ DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__));
+ net_os_send_hang_message(net);
+ }
+
if (!bcmerror && buf && ioc.buf) {
if (copy_to_user(ioc.buf, buf, buflen))
bcmerror = -EFAULT;
@@ -1633,6 +1835,8 @@ done:
if (buf)
MFREE(dhd->pub.osh, buf, buflen);
+ dhd_os_wake_unlock(&dhd->pub);
+
return OSL_ERROR(bcmerror);
}
@@ -1643,7 +1847,6 @@ dhd_stop(struct net_device *net)
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
if (dhd->pub.up == 0) {
return 0;
}
@@ -1673,7 +1876,11 @@ dhd_open(struct net_device *net)
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
- /* ASSERT(ifidx == 0); */
+ if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) {
+ DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
+ return -1;
+ }
+
if (ifidx == 0) { /* do it only for primary eth0 */
@@ -1712,7 +1919,7 @@ dhd_osl_detach(osl_t *osh)
osl_detach(osh);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
up(&dhd_registration_sem);
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
}
int
@@ -1860,7 +2067,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
DHD_ERROR(("wl_iw_attach failed\n"));
goto fail;
}
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
/* Set up the watchdog timer */
init_timer(&dhd->timer);
@@ -1940,6 +2147,9 @@ dhd_bus_start(dhd_pub_t *dhdp)
{
int ret = -1;
dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
+#ifdef EMBEDDED_PLATFORM
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+#endif /* EMBEDDED_PLATFORM */
ASSERT(dhd);
@@ -1985,6 +2195,41 @@ dhd_bus_start(dhd_pub_t *dhdp)
return -ENODEV;
}
+#ifdef EMBEDDED_PLATFORM
+ bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ dhdcdc_query_ioctl(dhdp, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
+ bcopy(iovbuf, dhdp->eventmask, WL_EVENTING_MASK_LEN);
+
+ setbit(dhdp->eventmask, WLC_E_SET_SSID);
+ setbit(dhdp->eventmask, WLC_E_PRUNE);
+ setbit(dhdp->eventmask, WLC_E_AUTH);
+ setbit(dhdp->eventmask, WLC_E_REASSOC);
+ setbit(dhdp->eventmask, WLC_E_REASSOC_IND);
+ setbit(dhdp->eventmask, WLC_E_DEAUTH_IND);
+ setbit(dhdp->eventmask, WLC_E_DISASSOC_IND);
+ setbit(dhdp->eventmask, WLC_E_DISASSOC);
+ setbit(dhdp->eventmask, WLC_E_JOIN);
+ setbit(dhdp->eventmask, WLC_E_ASSOC_IND);
+ setbit(dhdp->eventmask, WLC_E_PSK_SUP);
+ setbit(dhdp->eventmask, WLC_E_LINK);
+ setbit(dhdp->eventmask, WLC_E_NDIS_LINK);
+ setbit(dhdp->eventmask, WLC_E_MIC_ERROR);
+ setbit(dhdp->eventmask, WLC_E_PMKID_CACHE);
+ setbit(dhdp->eventmask, WLC_E_TXFAIL);
+ setbit(dhdp->eventmask, WLC_E_JOIN_START);
+ setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE);
+#ifdef PNO_SUPPORT
+ setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND);
+#endif /* PNO_SUPPORT */
+
+/* enable dongle roaming event */
+ setbit(dhdp->eventmask, WLC_E_ROAM);
+
+ dhdp->pktfilter_count = 1;
+ /* Setup filter to allow only unicast */
+ dhdp->pktfilter[0] = "100 0 0 0 0x01 0x00";
+#endif /* EMBEDDED_PLATFORM */
+
/* Bus is ready, do any protocol initialization */
if ((ret = dhd_prot_init(&dhd->pub)) < 0)
return ret;
@@ -2080,21 +2325,21 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
if (ifidx == 1) {
DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__));
/* ACCESSPOINT INTERFACE CASE */
- temp_addr[0] |= 0X02; /* set bit 2 , - Locally Administered address */
+ temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */
}
net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
net->ethtool_ops = &dhd_ethtool_ops;
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
-#ifdef CONFIG_WIRELESS_EXT
+#if defined(CONFIG_WIRELESS_EXT)
#if WIRELESS_EXT < 19
net->get_wireless_stats = dhd_get_wireless_stats;
#endif /* WIRELESS_EXT < 19 */
#if WIRELESS_EXT > 12
net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
#endif /* WIRELESS_EXT > 12 */
-#endif /* CONFIG_WIRELESS_EXT */
+#endif /* defined(CONFIG_WIRELESS_EXT) */
dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen;
@@ -2108,6 +2353,8 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
printf("%s: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", net->name,
dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2],
dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]);
+
+#if defined(CONFIG_WIRELESS_EXT)
#ifdef SOFTAP
if (ifidx == 0)
/* Don't call for SOFTAP Interface in SOFTAP MODE */
@@ -2115,10 +2362,11 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
#else
wl_iw_iscan_set_scan_broadcast_prep(net, 1);
#endif /* SOFTAP */
+#endif /* CONFIG_WIRELESS_EXT */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
up(&dhd_registration_sem);
-#endif
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
return 0;
fail:
@@ -2170,7 +2418,8 @@ dhd_detach(dhd_pub_t *dhdp)
int i;
#if defined(CONFIG_HAS_EARLYSUSPEND)
- unregister_early_suspend(&dhd->early_suspend);
+ if (dhd->early_suspend.suspend)
+ unregister_early_suspend(&dhd->early_suspend);
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
#if defined(CONFIG_WIRELESS_EXT)
/* Attach and link in the iw */
@@ -2230,6 +2479,19 @@ dhd_detach(dhd_pub_t *dhdp)
}
}
+static void __exit
+dhd_module_cleanup(void)
+{
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ dhd_bus_unregister();
+#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
+ wifi_del_dev();
+#endif
+ /* Call customer gpio to turn off power with WL_REG_ON signal */
+ dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
+}
+
static int __init
dhd_module_init(void)
{
@@ -2289,7 +2551,7 @@ dhd_module_init(void)
* It's needed to make sync up exit from dhd insmod and
* Kernel MMC sdio device callback registration
*/
- if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(10000)) != 0) {
+ if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
error = -EINVAL;
DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
goto fail_2;
@@ -2312,20 +2574,6 @@ fail_0:
return error;
}
-static void __exit
-dhd_module_cleanup(void)
-{
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
- dhd_bus_unregister();
-#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
- wifi_del_dev();
-#endif
- /* Call customer gpio to turn off power with WL_REG_ON signal */
- dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
-}
-
-
module_init(dhd_module_init);
module_exit(dhd_module_cleanup);
@@ -2378,14 +2626,17 @@ dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
int timeout = dhd_ioctl_timeout_msec;
/* Convert timeout in millsecond to jiffies */
- timeout = timeout * HZ / 1000;
+ /* timeout = timeout * HZ / 1000; */
+ timeout = msecs_to_jiffies(timeout);
/* Wait until control frame is available */
add_wait_queue(&dhd->ioctl_resp_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
-
- while (!(*condition) && (!signal_pending(current) && timeout))
+ smp_mb();
+ while (!(*condition) && (!signal_pending(current) && timeout)) {
timeout = schedule_timeout(timeout);
+ smp_mb();
+ }
if (signal_pending(current))
*pending = TRUE;
@@ -2412,8 +2663,12 @@ void
dhd_os_wd_timer(void *bus, uint wdtick)
{
dhd_pub_t *pub = bus;
- dhd_info_t *dhd = (dhd_info_t *)pub->info;
static uint save_dhd_watchdog_ms = 0;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+
+ /* don't start the wd until fw is loaded */
+ if (pub->busstate == DHD_BUS_DOWN)
+ return;
/* Totally stop the timer */
if (!wdtick && dhd->wd_timer_valid == TRUE) {
@@ -2577,7 +2832,7 @@ dhd_get_wireless_stats(struct net_device *dev)
else
return NULL;
}
-#endif
+#endif /* defined(CONFIG_WIRELESS_EXT) */
static int
dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
@@ -2594,8 +2849,18 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
#if defined(CONFIG_WIRELESS_EXT)
ASSERT(dhd->iflist[*ifidx] != NULL);
- wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
-#endif
+ if (ntoh32(event->event_type) == WLC_E_IF) {
+ DHD_INFO(("<0> interface:%d OP:%d don't pass to wext,"
+ "net_device might not be created yet\n",
+ *ifidx, ntoh32(event->event_type)));
+ return bcmerror;
+ }
+
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+
+ if (dhd->iflist[*ifidx]->net)
+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
+#endif /* defined(CONFIG_WIRELESS_EXT) */
return (bcmerror);
}
@@ -2645,12 +2910,70 @@ dhd_dev_reset(struct net_device *dev, uint8 flag)
/* Turning on watchdog back */
if (!flag)
dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
-
DHD_ERROR(("%s: WLAN OFF DONE\n", __FUNCTION__));
return 1;
}
+int net_os_set_suspend_disable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ if (dhd) {
+ ret = dhd->pub.suspend_disable_flag;
+ dhd->pub.suspend_disable_flag = val;
+ }
+ return ret;
+}
+
+int net_os_set_suspend(struct net_device *dev, int val)
+{
+ int ret = 0;
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ if (dhd) {
+ dhd_os_proto_block(&dhd->pub);
+ ret = dhd_set_suspend(val, &dhd->pub);
+ dhd_os_proto_unblock(&dhd->pub);
+ }
+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
+ return ret;
+}
+
+int net_os_set_dtim_skip(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ if (dhd)
+ dhd->pub.dtim_skip = val;
+
+ return 0;
+}
+
+int net_os_set_packet_filter(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ /* Packet filtering is set only if we still in early-suspend and
+ * we need either to turn it ON or turn it OFF
+ * We can always turn it OFF in case of early-suspend, but we turn it
+ * back ON only if suspend_disable_flag was not set
+ */
+ if (dhd && dhd->pub.up) {
+ dhd_os_proto_block(&dhd->pub);
+ if (dhd->pub.in_suspend) {
+ if (!val || (val && !dhd->pub.suspend_disable_flag))
+ dhd_set_packet_filter(val, &dhd->pub);
+ }
+ dhd_os_proto_unblock(&dhd->pub);
+ }
+ return ret;
+}
+
+
void
dhd_dev_init_ioctl(struct net_device *dev)
{
@@ -2659,6 +2982,47 @@ dhd_dev_init_ioctl(struct net_device *dev)
dhd_preinit_ioctls(&dhd->pub);
}
+#ifdef PNO_SUPPORT
+/* Linux wrapper to call common dhd_pno_clean */
+int
+dhd_dev_pno_reset(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_pno_clean(&dhd->pub));
+}
+
+
+/* Linux wrapper to call common dhd_pno_enable */
+int
+dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_pno_enable(&dhd->pub, pfn_enabled));
+}
+
+
+/* Linux wrapper to call common dhd_pno_set */
+int
+dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr));
+}
+
+/* Linux wrapper to get pno status */
+int
+dhd_dev_get_pno_status(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_pno_get_status(&dhd->pub));
+}
+
+#endif /* PNO_SUPPORT */
+
static int
dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
{
@@ -2687,6 +3051,43 @@ dhd_wait_pend8021x(struct net_device *dev)
return pend;
}
+#ifdef DHD_DEBUG
+int
+write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
+{
+ int ret = 0;
+ struct file *fp;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+
+ /* change to KERNEL_DS address limit */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /* open file to write */
+ fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
+ if (!fp) {
+ printf("%s: open file error\n", __FUNCTION__);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Write buf to file */
+ fp->f_op->write(fp, buf, size, &pos);
+
+exit:
+ /* free buf before return */
+ MFREE(dhd->osh, buf, size);
+ /* close file before return */
+ if (fp)
+ filp_close(fp, current->files);
+ /* restore previous address limit */
+ set_fs(old_fs);
+
+ return ret;
+}
+#endif /* DHD_DEBUG */
+
int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
{
dhd_info_t *dhd = (dhd_info_t *)(pub->info);
@@ -2803,3 +3204,17 @@ int net_os_wake_unlock(struct net_device *dev)
ret = dhd_os_wake_unlock(&dhd->pub);
return ret;
}
+
+int net_os_send_hang_message(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ if (dhd) {
+ if (!dhd->hang_was_sent) {
+ dhd->hang_was_sent = 1;
+ ret = wl_iw_send_priv_event(dev, "HANG");
+ }
+ }
+ return ret;
+}
diff --git a/bcm4329/src/dhd/sys/dhd_linux_sched.c b/bcm4329/src/dhd/sys/dhd_linux_sched.c
index 3189123..480b416 100644
--- a/bcm4329/src/dhd/sys/dhd_linux_sched.c
+++ b/bcm4329/src/dhd/sys/dhd_linux_sched.c
@@ -1,7 +1,7 @@
/*
* Expose some of the kernel scheduler routines
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/dhd/sys/dhd_proto.h b/bcm4329/src/dhd/sys/dhd_proto.h
index 1e2401a..7ef6929 100644
--- a/bcm4329/src/dhd/sys/dhd_proto.h
+++ b/bcm4329/src/dhd/sys/dhd_proto.h
@@ -4,7 +4,7 @@
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_proto.h,v 1.2.82.1.4.1.16.6 2009/06/17 01:01:55 Exp $
+ * $Id: dhd_proto.h,v 1.2.82.1.4.1.16.7 2010/05/10 12:54:59 Exp $
*/
#ifndef _dhd_proto_h_
@@ -34,7 +34,11 @@
#include <wlioctl.h>
#ifndef IOCTL_RESP_TIMEOUT
-#define IOCTL_RESP_TIMEOUT 2000 /* In milli second */
+#define IOCTL_RESP_TIMEOUT 3000 /* In milli second */
+#endif
+
+#ifndef IOCTL_CHIP_ACTIVE_TIMEOUT
+#define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */
#endif
/*
diff --git a/bcm4329/src/dhd/sys/dhd_sdio.c b/bcm4329/src/dhd/sys/dhd_sdio.c
index 8cb567f..bd73556 100644
--- a/bcm4329/src/dhd/sys/dhd_sdio.c
+++ b/bcm4329/src/dhd/sys/dhd_sdio.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.109 2010/04/22 05:52:46 Exp $
+ * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.129.4.1 2010/09/02 23:13:16 Exp $
*/
#include <typedefs.h>
@@ -36,13 +36,11 @@
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmdevs.h>
-
#include <siutils.h>
#include <hndpmu.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <sbhnddma.h>
-
#include <sdio.h>
#include <sbsdio.h>
#include <sbsdpcmdev.h>
@@ -60,6 +58,13 @@
#include <dhdioctl.h>
#include <sdiovar.h>
+#ifdef DHD_DEBUG
+#include <hndrte_cons.h>
+#endif /* DHD_DEBUG */
+#ifdef DHD_DEBUG_TRAP
+#include <hndrte_armtrap.h>
+#endif /* DHD_DEBUG_TRAP */
+
#define QLEN 256 /* bulk rx and tx queue lengths */
#define FCHI (QLEN - 10)
#define FCLOW (FCHI / 2)
@@ -119,11 +124,11 @@
/* Bump up limit on waiting for HT to account for first startup;
* if the image is doing a CRC calculation before programming the PMU
* for HT availability, it could take a couple hundred ms more, so
- * max out at a half second (500000us).
+ * max out at a 1 second (1000000us).
*/
-#if (PMU_MAX_TRANSITION_DLY <= 500000)
+#if (PMU_MAX_TRANSITION_DLY < 1000000)
#undef PMU_MAX_TRANSITION_DLY
-#define PMU_MAX_TRANSITION_DLY 500000
+#define PMU_MAX_TRANSITION_DLY 1000000
#endif
/* Value for ChipClockCSR during initial setup */
@@ -141,6 +146,17 @@
DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
+#ifdef DHD_DEBUG
+/* Device console log buffer state */
+typedef struct dhd_console {
+ uint count; /* Poll interval msec counter */
+ uint log_addr; /* Log struct address (fixed) */
+ hndrte_log_t log; /* Log struct (host copy) */
+ uint bufsize; /* Size of log buffer */
+ uint8 *buf; /* Log buffer (host copy) */
+ uint last; /* Last buffer read index */
+} dhd_console_t;
+#endif /* DHD_DEBUG */
/* Private data for SDIO bus interaction */
typedef struct dhd_bus {
@@ -208,6 +224,10 @@ typedef struct dhd_bus {
uint polltick; /* Tick counter */
uint pollcnt; /* Count of active polls */
+#ifdef DHD_DEBUG
+ dhd_console_t console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* DHD_DEBUG */
uint regfails; /* Count of R_REG/W_REG failures */
@@ -404,6 +424,10 @@ static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start);
#endif
+#ifdef DHD_DEBUG_TRAP
+static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
+static int dhdsdio_mem_dump(dhd_bus_t *bus);
+#endif /* DHD_DEBUG_TRAP */
static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
@@ -929,7 +953,6 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
(((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
#ifdef DHD_DEBUG
tx_packets[PKTPRIO(pkt)]++;
@@ -995,6 +1018,9 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
}
}
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
} while ((ret < 0) && retrydata && retries++ < TXRETRIES);
done:
@@ -1046,7 +1072,7 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
/* Check for existing queue, current flow-control, pending event, or pending clock */
if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
(!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
- (bus->clkstate == CLK_PENDING)) {
+ (bus->clkstate != CLK_AVAIL)) {
DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
pktq_len(&bus->txq)));
bus->fcqueued++;
@@ -1082,6 +1108,7 @@ dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
/* Otherwise, send it now */
BUS_WAKE(bus);
+ /* Make sure back plane ht clk is on, no pending allowed */
dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
#ifndef SDTEST
@@ -1236,6 +1263,8 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
if (!DATAOK(bus)) {
+ DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
+ __FUNCTION__, bus->tx_max, bus->tx_seq));
bus->ctrl_frame_stat = TRUE;
/* Send from dpc */
bus->ctrl_frame_buf = frame;
@@ -1243,15 +1272,16 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
- if (bus->ctrl_frame_stat == FALSE)
+ if (bus->ctrl_frame_stat == FALSE) {
+ DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
ret = 0;
- else
+ } else {
+ DHD_INFO(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
ret = -1;
+ }
}
if (ret == -1) {
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
-
#ifdef DHD_DEBUG
if (DHD_BYTES_ON() && DHD_CTL_ON()) {
prhex("Tx Frame", frame, len);
@@ -1261,6 +1291,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
#endif
do {
+ bus->ctrl_frame_stat = FALSE;
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
frame, len, NULL, NULL, NULL);
ASSERT(ret != BCME_PENDING);
@@ -1289,6 +1320,9 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
}
}
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
} while ((ret < 0) && retries++ < TXRETRIES);
}
@@ -1333,11 +1367,21 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
__FUNCTION__, rxlen, msglen));
} else if (timeleft == 0) {
DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
+#ifdef DHD_DEBUG_TRAP
+ dhd_os_sdlock(bus->dhd);
+ dhdsdio_checkdied(bus, NULL, 0);
+ dhd_os_sdunlock(bus->dhd);
+#endif /* DHD_DEBUG_TRAP */
} else if (pending == TRUE) {
DHD_CTL(("%s: cancelled\n", __FUNCTION__));
return -ERESTARTSYS;
} else {
DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
+#ifdef DHD_DEBUG_TRAP
+ dhd_os_sdlock(bus->dhd);
+ dhdsdio_checkdied(bus, NULL, 0);
+ dhd_os_sdunlock(bus->dhd);
+#endif /* DHD_DEBUG_TRAP */
}
if (rxlen)
@@ -1357,6 +1401,9 @@ enum {
IOV_SDCIS,
IOV_MEMBYTES,
IOV_MEMSIZE,
+#ifdef DHD_DEBUG_TRAP
+ IOV_CHECKDIED,
+#endif
IOV_DOWNLOAD,
IOV_FORCEEVEN,
IOV_SDIOD_DRIVE,
@@ -1408,6 +1455,9 @@ const bcm_iovar_t dhdsdio_iovars[] = {
{"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
{"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
#endif /* DHD_DEBUG */
+#ifdef DHD_DEBUG_TRAP
+ {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
+#endif /* DHD_DEBUG_TRAP */
#ifdef SDTEST
{"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
{"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
@@ -1636,6 +1686,301 @@ xfer_done:
return bcmerror;
}
+#ifdef DHD_DEBUG_TRAP
+static int
+dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
+{
+ uint32 addr;
+ int rv;
+
+ /* Read last word in memory to determine address of sdpcm_shared structure */
+ if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
+ return rv;
+
+ addr = ltoh32(addr);
+
+ DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
+
+ /*
+ * Check if addr is valid.
+ * NVRAM length at the end of memory should have been overwritten.
+ */
+ if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
+ DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
+ return BCME_ERROR;
+ }
+
+ /* Read hndrte_shared structure */
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
+ return rv;
+
+ /* Endianness */
+ sh->flags = ltoh32(sh->flags);
+ sh->trap_addr = ltoh32(sh->trap_addr);
+ sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
+ sh->assert_file_addr = ltoh32(sh->assert_file_addr);
+ sh->assert_line = ltoh32(sh->assert_line);
+ sh->console_addr = ltoh32(sh->console_addr);
+ sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
+
+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
+ DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
+ "is different than sdpcm_shared version %d in dongle\n",
+ __FUNCTION__, SDPCM_SHARED_VERSION,
+ sh->flags & SDPCM_SHARED_VERSION_MASK));
+ return BCME_ERROR;
+ }
+
+ return BCME_OK;
+}
+
+static int
+dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
+{
+ int bcmerror = 0;
+ uint msize = 512;
+ char *mbuffer = NULL;
+ uint maxstrlen = 256;
+ char *str = NULL;
+ trap_t tr;
+ sdpcm_shared_t sdpcm_shared;
+ struct bcmstrbuf strbuf;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (data == NULL) {
+ /*
+ * Called after a rx ctrl timeout. "data" is NULL.
+ * allocate memory to trace the trap or assert.
+ */
+ size = msize;
+ mbuffer = data = MALLOC(bus->dhd->osh, msize);
+ if (mbuffer == NULL) {
+ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
+ bcmerror = BCME_NOMEM;
+ goto done;
+ }
+ }
+
+ if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
+ DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
+ bcmerror = BCME_NOMEM;
+ goto done;
+ }
+
+ if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
+ goto done;
+
+ bcm_binit(&strbuf, data, size);
+
+ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
+ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
+
+ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic parsing of output.)
+ */
+ bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
+ }
+
+ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic parsing of output.)
+ */
+ bcm_bprintf(&strbuf, "No trap%s in dongle",
+ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
+ ?"/assrt" :"");
+ } else {
+ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
+ /* Download assert */
+ bcm_bprintf(&strbuf, "Dongle assert");
+ if (sdpcm_shared.assert_exp_addr != 0) {
+ str[0] = '\0';
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.assert_exp_addr,
+ (uint8 *)str, maxstrlen)) < 0)
+ goto done;
+
+ str[maxstrlen - 1] = '\0';
+ bcm_bprintf(&strbuf, " expr \"%s\"", str);
+ }
+
+ if (sdpcm_shared.assert_file_addr != 0) {
+ str[0] = '\0';
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.assert_file_addr,
+ (uint8 *)str, maxstrlen)) < 0)
+ goto done;
+
+ str[maxstrlen - 1] = '\0';
+ bcm_bprintf(&strbuf, " file \"%s\"", str);
+ }
+
+ bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
+ }
+
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.trap_addr,
+ (uint8*)&tr, sizeof(trap_t))) < 0)
+ goto done;
+
+ bcm_bprintf(&strbuf,
+ "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
+ "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
+ "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
+ tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13, tr.r14, tr.pc,
+ sdpcm_shared.trap_addr,
+ tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5, tr.r6, tr.r7);
+ }
+ }
+
+ if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
+ DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
+ }
+
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ /* Mem dump to a file on device */
+ dhdsdio_mem_dump(bus);
+ }
+
+done:
+ if (mbuffer)
+ MFREE(bus->dhd->osh, mbuffer, msize);
+ if (str)
+ MFREE(bus->dhd->osh, str, maxstrlen);
+
+ return bcmerror;
+}
+
+static int
+dhdsdio_mem_dump(dhd_bus_t *bus)
+{
+ int ret = 0;
+ int size; /* Full mem size */
+ int start = 0; /* Start address */
+ int read_size = 0; /* Read size of each iteration */
+ uint8 *buf = NULL, *databuf = NULL;
+
+ /* Get full mem size */
+ size = bus->ramsize;
+ buf = MALLOC(bus->dhd->osh, size);
+ if (!buf) {
+ printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
+ return -1;
+ }
+
+ /* Read mem content */
+ printf("Dump dongle memory");
+ databuf = buf;
+ while (size)
+ {
+ read_size = MIN(MEMBLOCK, size);
+ if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
+ {
+ printf("%s: Error membytes %d\n", __FUNCTION__, ret);
+ if (buf) {
+ MFREE(bus->dhd->osh, buf, size);
+ }
+ return -1;
+ }
+ printf(".");
+
+ /* Decrement size and increment start address */
+ size -= read_size;
+ start += read_size;
+ databuf += read_size;
+ }
+ printf("Done\n");
+
+#ifdef DHD_DEBUG
+ /* free buf before return !!! */
+ if (write_to_file(bus->dhd, buf, bus->ramsize))
+ {
+ printf("%s: Error writing to files\n", __FUNCTION__);
+ return -1;
+ }
+ /* buf free handled in write_to_file, not here */
+#else
+ MFREE(bus->dhd->osh, buf, size);
+#endif
+ return 0;
+}
+#endif /* DHD_DEBUG_TRAP */
+
+#ifdef DHD_DEBUG
+#define CONSOLE_LINE_MAX 192
+
+static int
+dhdsdio_readconsole(dhd_bus_t *bus)
+{
+ dhd_console_t *c = &bus->console;
+ uint8 line[CONSOLE_LINE_MAX], ch;
+ uint32 n, idx, addr;
+ int rv;
+
+ /* Don't do anything until FWREADY updates console address */
+ if (bus->console_addr == 0)
+ return 0;
+
+ /* Read console log struct */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
+ return rv;
+
+ /* Allocate console buffer (one time only) */
+ if (c->buf == NULL) {
+ c->bufsize = ltoh32(c->log.buf_size);
+ if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
+ return BCME_NOMEM;
+ }
+
+ idx = ltoh32(c->log.idx);
+
+ /* Protect against corrupt value */
+ if (idx > c->bufsize)
+ return BCME_ERROR;
+
+ /* Skip reading the console buffer if the index pointer has not moved */
+ if (idx == c->last)
+ return BCME_OK;
+
+ /* Read the console buffer */
+ addr = ltoh32(c->log.buf);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
+ return rv;
+
+ while (c->last != idx) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ if (c->last == idx) {
+ /* This would output a partial line. Instead, back up
+ * the buffer pointer and output this line next time around.
+ */
+ if (c->last >= n)
+ c->last -= n;
+ else
+ c->last = c->bufsize - n;
+ goto break2;
+ }
+ ch = c->buf[c->last];
+ c->last = (c->last + 1) % c->bufsize;
+ if (ch == '\n')
+ break;
+ line[n] = ch;
+ }
+
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ printf("CONSOLE: %s\n", line);
+ }
+ }
+break2:
+
+ return BCME_OK;
+}
+#endif /* DHD_DEBUG */
int
dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
@@ -3881,10 +4226,13 @@ clkwait:
DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
__FUNCTION__, rxdone, framecnt));
bus->intdis = FALSE;
+#if defined(OOB_INTR_ONLY)
+ bcmsdh_oob_intr_set(1);
+#endif /* (OOB_INTR_ONLY) */
bcmsdh_intr_enable(sdh);
}
- if (DATAOK(bus) && bus->ctrl_frame_stat) {
+ if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
int ret, i;
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
@@ -3916,13 +4264,16 @@ clkwait:
}
}
+ if (ret == 0) {
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
+
printf("Return_dpc value is : %d\n", ret);
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
bus->ctrl_frame_stat = FALSE;
dhd_wait_event_wakeup(bus->dhd);
}
/* Send queued frames (limit 1 if rx may still be pending) */
- else if ((bus->clkstate != CLK_PENDING) && !bus->fcstate &&
+ else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
framecnt = dhdsdio_sendfromq(bus, framecnt);
@@ -3937,7 +4288,9 @@ clkwait:
bus->dhd->busstate = DHD_BUS_DOWN;
bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) {
- /* Awaiting I_CHIPACTIVE; don't resched */
+ DHD_INFO(("%s: rescheduled due to CLK_PENDING awaiting \
+ I_CHIPACTIVE interrupt", __FUNCTION__));
+ resched = TRUE;
} else if (bus->intstatus || bus->ipend ||
(!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
PKT_AVAILABLE()) { /* Read multiple frames */
@@ -3961,7 +4314,6 @@ clkwait:
bool
dhd_bus_dpc(struct dhd_bus *bus)
{
-#ifdef SDIO_ISR_THREAD
bool resched;
/* Call the DPC directly. */
@@ -3969,9 +4321,6 @@ dhd_bus_dpc(struct dhd_bus *bus)
resched = dhdsdio_dpc(bus);
return resched;
-#else
- return dhdsdio_dpc(bus);
-#endif /* SDIO_ISR_THREAD */
}
void
@@ -3980,6 +4329,8 @@ dhdsdio_isr(void *arg)
dhd_bus_t *bus = (dhd_bus_t*)arg;
bcmsdh_info_t *sdh;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
if (!bus) {
DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
return;
@@ -3990,9 +4341,6 @@ dhdsdio_isr(void *arg)
DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
return;
}
-
- DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
/* Count the interrupt call */
bus->intrcount++;
bus->ipend = TRUE;
@@ -4319,6 +4667,19 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
bus->lastintrs = bus->intrcount;
}
+#ifdef DHD_DEBUG
+ /* Poll for console output periodically */
+ if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
+ bus->console.count += dhd_watchdog_ms;
+ if (bus->console.count >= dhd_console_ms) {
+ bus->console.count -= dhd_console_ms;
+ /* Make sure backplane clock is on */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+ if (dhdsdio_readconsole(bus) < 0)
+ dhd_console_ms = 0; /* On error, stop trying */
+ }
+ }
+#endif /* DHD_DEBUG */
#ifdef SDTEST
/* Generate packets if configured */
@@ -4336,7 +4697,6 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
bus->idlecount = 0;
if (bus->activity) {
bus->activity = FALSE;
- } else {
dhdsdio_clkctl(bus, CLK_NONE, FALSE);
}
}
@@ -4347,6 +4707,68 @@ dhd_bus_watchdog(dhd_pub_t *dhdp)
return bus->ipend;
}
+#ifdef DHD_DEBUG
+extern int
+dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
+{
+ dhd_bus_t *bus = dhdp->bus;
+ uint32 addr, val;
+ int rv;
+ void *pkt;
+
+ /* Address could be zero if CONSOLE := 0 in dongle Makefile */
+ if (bus->console_addr == 0)
+ return BCME_UNSUPPORTED;
+
+ /* Exclusive bus access */
+ dhd_os_sdlock(bus->dhd);
+
+ /* Don't allow input if dongle is in reset */
+ if (bus->dhd->dongle_reset) {
+ dhd_os_sdunlock(bus->dhd);
+ return BCME_NOTREADY;
+ }
+
+ /* Request clock to allow SDIO accesses */
+ BUS_WAKE(bus);
+ /* No pend allowed since txpkt is called later, ht clk has to be on */
+ dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
+
+ /* Zero cbuf_index */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
+ val = htol32(0);
+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
+ goto done;
+
+ /* Write message into cbuf */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
+ goto done;
+
+ /* Write length into vcons_in */
+ addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
+ val = htol32(msglen);
+ if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
+ goto done;
+
+ /* Bump dongle by sending an empty event pkt.
+ * sdpcm_sendup (RX) checks for virtual console input.
+ */
+ if (((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) &&
+ bus->clkstate == CLK_AVAIL)
+ dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
+
+done:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return rv;
+}
+#endif /* DHD_DEBUG */
#ifdef DHD_DEBUG
static void
diff --git a/bcm4329/src/dongle/dngl_stats.h b/bcm4329/src/dongle/dngl_stats.h
index c1776a8..e5db54e 100644
--- a/bcm4329/src/dongle/dngl_stats.h
+++ b/bcm4329/src/dongle/dngl_stats.h
@@ -2,7 +2,7 @@
* Common stats definitions for clients of dongle
* ports
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/aidmp.h b/bcm4329/src/include/aidmp.h
index 44b3de8..a927e5d 100644
--- a/bcm4329/src/include/aidmp.h
+++ b/bcm4329/src/include/aidmp.h
@@ -1,7 +1,7 @@
/*
* Broadcom AMBA Interconnect definitions.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmcdc.h b/bcm4329/src/include/bcmcdc.h
index 641d755..c2a860b 100644
--- a/bcm4329/src/include/bcmcdc.h
+++ b/bcm4329/src/include/bcmcdc.h
@@ -4,7 +4,7 @@
*
* Definitions subject to change without notice.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmdevs.h b/bcm4329/src/include/bcmdevs.h
index acfd414..14853f1 100644
--- a/bcm4329/src/include/bcmdevs.h
+++ b/bcm4329/src/include/bcmdevs.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmdevs.h,v 13.172.4.5.4.10.2.28 2010/01/28 06:57:23 Exp $
+ * $Id: bcmdevs.h,v 13.172.4.5.4.10.2.36 2010/05/25 08:33:44 Exp $
*/
diff --git a/bcm4329/src/include/bcmendian.h b/bcm4329/src/include/bcmendian.h
index 38887df..ae46838 100644
--- a/bcm4329/src/include/bcmendian.h
+++ b/bcm4329/src/include/bcmendian.h
@@ -1,7 +1,7 @@
/*
* Byte order utilities
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmpcispi.h b/bcm4329/src/include/bcmpcispi.h
index e3be826..7d98fb7 100644
--- a/bcm4329/src/include/bcmpcispi.h
+++ b/bcm4329/src/include/bcmpcispi.h
@@ -1,7 +1,7 @@
/*
* Broadcom PCI-SPI Host Controller Register Definitions
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmperf.h b/bcm4329/src/include/bcmperf.h
index dfc3f44..2a78784 100644
--- a/bcm4329/src/include/bcmperf.h
+++ b/bcm4329/src/include/bcmperf.h
@@ -1,7 +1,7 @@
/*
* Performance counters software interface.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmsdbus.h b/bcm4329/src/include/bcmsdbus.h
index 0e629c0..b7b67bc 100644
--- a/bcm4329/src/include/bcmsdbus.h
+++ b/bcm4329/src/include/bcmsdbus.h
@@ -2,7 +2,7 @@
* Definitions for API from sdio common code (bcmsdh) to individual
* host controller drivers.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmsdh.h b/bcm4329/src/include/bcmsdh.h
index f8ab8ab..f5dee5c 100644
--- a/bcm4329/src/include/bcmsdh.h
+++ b/bcm4329/src/include/bcmsdh.h
@@ -3,7 +3,7 @@
* export functions to client drivers
* abstract OS and BUS specific details of SDIO
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmsdh_sdmmc.h b/bcm4329/src/include/bcmsdh_sdmmc.h
index b572f34..4e6d1b5 100644
--- a/bcm4329/src/include/bcmsdh_sdmmc.h
+++ b/bcm4329/src/include/bcmsdh_sdmmc.h
@@ -1,7 +1,7 @@
/*
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmsdpcm.h b/bcm4329/src/include/bcmsdpcm.h
index b63b1d3..77aca45 100644
--- a/bcm4329/src/include/bcmsdpcm.h
+++ b/bcm4329/src/include/bcmsdpcm.h
@@ -2,7 +2,7 @@
* Broadcom SDIO/PCMCIA
* Software-specific definitions shared between device and host side
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: bcmsdpcm.h,v 1.1.2.3 2009/04/09 18:52:06 Exp $
+ * $Id: bcmsdpcm.h,v 1.1.2.4 2010/07/02 01:15:46 Exp $
*/
#ifndef _bcmsdpcm_h_
@@ -241,7 +241,7 @@ typedef volatile struct {
* Shared structure between dongle and the host
* The structure contains pointers to trap or assert information shared with the host
*/
-#define SDPCM_SHARED_VERSION 0x0001
+#define SDPCM_SHARED_VERSION 0x0002
#define SDPCM_SHARED_VERSION_MASK 0x00FF
#define SDPCM_SHARED_ASSERT_BUILT 0x0100
#define SDPCM_SHARED_ASSERT 0x0200
@@ -255,6 +255,7 @@ typedef struct {
uint32 assert_line;
uint32 console_addr; /* Address of hndrte_cons_t */
uint32 msgtrace_addr;
+ uint8 tag[32];
} sdpcm_shared_t;
extern sdpcm_shared_t sdpcm_shared;
diff --git a/bcm4329/src/include/bcmsdspi.h b/bcm4329/src/include/bcmsdspi.h
index b1e2be9..eaae10d 100644
--- a/bcm4329/src/include/bcmsdspi.h
+++ b/bcm4329/src/include/bcmsdspi.h
@@ -1,7 +1,7 @@
/*
* SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmspi.h b/bcm4329/src/include/bcmspi.h
index 0c46538..2e2bc93 100644
--- a/bcm4329/src/include/bcmspi.h
+++ b/bcm4329/src/include/bcmspi.h
@@ -1,7 +1,7 @@
/*
* Broadcom SPI Low-Level Hardware Driver API
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/bcmutils.h b/bcm4329/src/include/bcmutils.h
index 7010838..f85ed35 100644
--- a/bcm4329/src/include/bcmutils.h
+++ b/bcm4329/src/include/bcmutils.h
@@ -20,7 +20,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: bcmutils.h,v 13.184.4.6.2.1.18.24 2009/12/10 20:19:19 Exp $
+ * $Id: bcmutils.h,v 13.184.4.6.2.1.18.25 2010/04/26 06:05:24 Exp $
*/
diff --git a/bcm4329/src/include/bcmwifi.h b/bcm4329/src/include/bcmwifi.h
index 52f17a6..038aedc 100644
--- a/bcm4329/src/include/bcmwifi.h
+++ b/bcm4329/src/include/bcmwifi.h
@@ -42,7 +42,7 @@ typedef uint16 chanspec_t;
#define CH_5MHZ_APART 1
#define CH_MAX_2G_CHANNEL 14
#define WLC_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL
-#define MAXCHANNEL 224
+#define MAXCHANNEL 224
#define WL_CHANSPEC_CHAN_MASK 0x00ff
#define WL_CHANSPEC_CHAN_SHIFT 0
@@ -118,7 +118,7 @@ typedef uint16 chanspec_t;
(LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \
(UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))))
-#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G((chspec)) ? WLC_BAND_5G : WLC_BAND_2G)
+#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G((chspec))? WLC_BAND_5G: WLC_BAND_2G)
#define CHANSPEC_STR_LEN 8
diff --git a/bcm4329/src/include/dhdioctl.h b/bcm4329/src/include/dhdioctl.h
index ee78c3d..980a143 100644
--- a/bcm4329/src/include/dhdioctl.h
+++ b/bcm4329/src/include/dhdioctl.h
@@ -5,7 +5,7 @@
*
* Definitions subject to change without notice.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -25,7 +25,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: dhdioctl.h,v 13.7.8.1.4.1.16.4 2009/09/05 16:50:35 Exp $
+ * $Id: dhdioctl.h,v 13.7.8.1.4.1.16.5 2010/05/21 21:49:38 Exp $
*/
#ifndef _dhdioctl_h_
@@ -79,6 +79,7 @@ typedef struct dhd_ioctl {
#define DHD_GLOM_VAL 0x0400
#define DHD_EVENT_VAL 0x0800
#define DHD_BTA_VAL 0x1000
+#define DHD_ISCAN_VAL 0x2000
#ifdef SDTEST
/* For pktgen iovar */
diff --git a/bcm4329/src/include/epivers.h b/bcm4329/src/include/epivers.h
index 3ab7ad7..92dc326 100644
--- a/bcm4329/src/include/epivers.h
+++ b/bcm4329/src/include/epivers.h
@@ -31,18 +31,18 @@
#define EPI_MINOR_VERSION 218
-#define EPI_RC_NUMBER 223
+#define EPI_RC_NUMBER 248
-#define EPI_INCREMENTAL_NUMBER 0
+#define EPI_INCREMENTAL_NUMBER 6
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 4, 218, 223, 0
+#define EPI_VERSION 4, 218, 248, 6
-#define EPI_VERSION_NUM 0x04dadf00
+#define EPI_VERSION_NUM 0x04daf806
-#define EPI_VERSION_STR "4.218.223.0"
-#define EPI_ROUTER_VERSION_STR "4.219.223.0"
+#define EPI_VERSION_STR "4.218.248.6"
+#define EPI_ROUTER_VERSION_STR "4.219.248.6"
#endif
diff --git a/bcm4329/src/include/hndpmu.h b/bcm4329/src/include/hndpmu.h
index afd78d7..e829b3d 100644
--- a/bcm4329/src/include/hndpmu.h
+++ b/bcm4329/src/include/hndpmu.h
@@ -1,7 +1,7 @@
/*
* HND SiliconBackplane PMU support.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndpmu.h,v 13.14.4.3.4.3.8.6 2009/09/14 09:21:45 Exp $
+ * $Id: hndpmu.h,v 13.14.4.3.4.3.8.7 2010/04/09 13:20:51 Exp $
*/
#ifndef _hndpmu_h_
diff --git a/bcm4329/src/include/hndrte_armtrap.h b/bcm4329/src/include/hndrte_armtrap.h
new file mode 100644
index 0000000..ca3281b
--- /dev/null
+++ b/bcm4329/src/include/hndrte_armtrap.h
@@ -0,0 +1,88 @@
+/*
+ * HNDRTE arm trap handling.
+ *
+ * Copyright (C) 1999-2010, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: hndrte_armtrap.h,v 13.3.196.2 2010/07/15 19:06:11 Exp $
+ */
+
+#ifndef _hndrte_armtrap_h
+#define _hndrte_armtrap_h
+
+
+/* ARM trap handling */
+
+/* Trap types defined by ARM (see arminc.h) */
+
+/* Trap locations in lo memory */
+#define TRAP_STRIDE 4
+#define FIRST_TRAP TR_RST
+#define LAST_TRAP (TR_FIQ * TRAP_STRIDE)
+
+#if defined(__ARM_ARCH_4T__)
+#define MAX_TRAP_TYPE (TR_FIQ + 1)
+#elif defined(__ARM_ARCH_7M__)
+#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
+#endif /* __ARM_ARCH_7M__ */
+
+/* The trap structure is defined here as offsets for assembly */
+#define TR_TYPE 0x00
+#define TR_EPC 0x04
+#define TR_CPSR 0x08
+#define TR_SPSR 0x0c
+#define TR_REGS 0x10
+#define TR_REG(n) (TR_REGS + (n) * 4)
+#define TR_SP TR_REG(13)
+#define TR_LR TR_REG(14)
+#define TR_PC TR_REG(15)
+
+#define TRAP_T_SIZE 80
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+#include <typedefs.h>
+
+typedef struct _trap_struct {
+ uint32 type;
+ uint32 epc;
+ uint32 cpsr;
+ uint32 spsr;
+ uint32 r0;
+ uint32 r1;
+ uint32 r2;
+ uint32 r3;
+ uint32 r4;
+ uint32 r5;
+ uint32 r6;
+ uint32 r7;
+ uint32 r8;
+ uint32 r9;
+ uint32 r10;
+ uint32 r11;
+ uint32 r12;
+ uint32 r13;
+ uint32 r14;
+ uint32 pc;
+} trap_t;
+
+#endif /* !_LANGUAGE_ASSEMBLY */
+
+#endif /* _hndrte_armtrap_h */
diff --git a/bcm4329/src/include/hndrte_cons.h b/bcm4329/src/include/hndrte_cons.h
new file mode 100644
index 0000000..a424174
--- /dev/null
+++ b/bcm4329/src/include/hndrte_cons.h
@@ -0,0 +1,63 @@
+/*
+ * Console support for hndrte.
+ *
+ * Copyright (C) 1999-2010, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: hndrte_cons.h,v 13.1.2.4 2010/07/15 19:06:11 Exp $
+ */
+
+#include <typedefs.h>
+
+#define CBUF_LEN (128)
+
+#define LOG_BUF_LEN 1024
+
+typedef struct {
+ uint32 buf; /* Can't be pointer on (64-bit) hosts */
+ uint buf_size;
+ uint idx;
+ char *_buf_compat; /* Redundant pointer for backward compat. */
+} hndrte_log_t;
+
+typedef struct {
+ /* Virtual UART
+ * When there is no UART (e.g. Quickturn), the host should write a complete
+ * input line directly into cbuf and then write the length into vcons_in.
+ * This may also be used when there is a real UART (at risk of conflicting with
+ * the real UART). vcons_out is currently unused.
+ */
+ volatile uint vcons_in;
+ volatile uint vcons_out;
+
+ /* Output (logging) buffer
+ * Console output is written to a ring buffer log_buf at index log_idx.
+ * The host may read the output when it sees log_idx advance.
+ * Output will be lost if the output wraps around faster than the host polls.
+ */
+ hndrte_log_t log;
+
+ /* Console input line buffer
+ * Characters are read one at a time into cbuf until <CR> is received, then
+ * the buffer is processed as a command line. Also used for virtual UART.
+ */
+ uint cbuf_idx;
+ char cbuf[CBUF_LEN];
+} hndrte_cons_t;
diff --git a/bcm4329/src/include/hndsoc.h b/bcm4329/src/include/hndsoc.h
index dcbab43..3542417 100644
--- a/bcm4329/src/include/hndsoc.h
+++ b/bcm4329/src/include/hndsoc.h
@@ -1,7 +1,7 @@
/*
* Broadcom HND chip & on-chip-interconnect-related definitions.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/linux_osl.h b/bcm4329/src/include/linux_osl.h
index 98afe9c..b059c2a 100644
--- a/bcm4329/src/include/linux_osl.h
+++ b/bcm4329/src/include/linux_osl.h
@@ -1,7 +1,7 @@
/*
* Linux OS Independent Layer
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: linux_osl.h,v 13.131.30.5 2009/10/27 04:42:45 Exp $
+ * $Id: linux_osl.h,v 13.131.30.8 2010/04/26 05:42:18 Exp $
*/
@@ -319,5 +319,4 @@ extern int osl_error(int bcmerror);
#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ))
-
#endif
diff --git a/bcm4329/src/include/linuxver.h b/bcm4329/src/include/linuxver.h
index a36de95..6ed2265 100644
--- a/bcm4329/src/include/linuxver.h
+++ b/bcm4329/src/include/linuxver.h
@@ -2,7 +2,7 @@
* Linux-specific abstractions to gain some independence from linux kernel versions.
* Pave over some 2.2 versus 2.4 versus 2.6 kernel differences.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: linuxver.h,v 13.38.8.1.8.3 2009/06/19 04:42:45 Exp $
+ * $Id: linuxver.h,v 13.38.8.1.8.6 2010/04/29 05:00:46 Exp $
*/
@@ -32,7 +32,7 @@
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
#include <linux/config.h>
-#else
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))
#include <linux/autoconf.h>
#endif
#include <linux/module.h>
@@ -66,6 +66,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
+#include <linux/semaphore.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
#undef IP_TOS
#endif
diff --git a/bcm4329/src/include/miniopt.h b/bcm4329/src/include/miniopt.h
index 91e6603..3667fb1 100644
--- a/bcm4329/src/include/miniopt.h
+++ b/bcm4329/src/include/miniopt.h
@@ -1,7 +1,7 @@
/*
* Command line options parser.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/msgtrace.h b/bcm4329/src/include/msgtrace.h
index d79a89e..1479086 100644
--- a/bcm4329/src/include/msgtrace.h
+++ b/bcm4329/src/include/msgtrace.h
@@ -1,7 +1,7 @@
/*
* Trace messages sent over HBUS
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/osl.h b/bcm4329/src/include/osl.h
index 02b2b21..5599e53 100644
--- a/bcm4329/src/include/osl.h
+++ b/bcm4329/src/include/osl.h
@@ -1,7 +1,7 @@
/*
* OS Abstraction Layer
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/packed_section_end.h b/bcm4329/src/include/packed_section_end.h
index e455d69..5b61c18 100644
--- a/bcm4329/src/include/packed_section_end.h
+++ b/bcm4329/src/include/packed_section_end.h
@@ -15,7 +15,7 @@
* #include <packed_section_end.h>
*
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/packed_section_start.h b/bcm4329/src/include/packed_section_start.h
index a15562e..cb93aa6 100644
--- a/bcm4329/src/include/packed_section_start.h
+++ b/bcm4329/src/include/packed_section_start.h
@@ -15,7 +15,7 @@
* #include <packed_section_end.h>
*
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/pcicfg.h b/bcm4329/src/include/pcicfg.h
index 61c2f4a..898962c 100644
--- a/bcm4329/src/include/pcicfg.h
+++ b/bcm4329/src/include/pcicfg.h
@@ -1,7 +1,7 @@
/*
* pcicfg.h: PCI configuration constants and structures.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/802.11.h b/bcm4329/src/include/proto/802.11.h
index 3ef7de2..fd26317 100644
--- a/bcm4329/src/include/proto/802.11.h
+++ b/bcm4329/src/include/proto/802.11.h
@@ -976,6 +976,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
#define DOT11_MNG_EXT_CSA_ID 60
#define DOT11_MNG_HT_ADD 61
#define DOT11_MNG_EXT_CHANNEL_OFFSET 62
+#define DOT11_MNG_WAPI_ID 68
#define DOT11_MNG_HT_BSS_COEXINFO_ID 72
#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73
#define DOT11_MNG_HT_OBSS_ID 74
@@ -1422,6 +1423,8 @@ typedef struct vndr_ie vndr_ie_t;
#define AES_KEY_SIZE 16
#define AES_MIC_SIZE 8
+#define SMS4_KEY_LEN 16
+#define SMS4_WPI_CBC_MAC_LEN 16
#include <packed_section_end.h>
diff --git a/bcm4329/src/include/proto/802.11e.h b/bcm4329/src/include/proto/802.11e.h
index 0c53530..1dd6f45 100644
--- a/bcm4329/src/include/proto/802.11e.h
+++ b/bcm4329/src/include/proto/802.11e.h
@@ -1,7 +1,7 @@
/*
* 802.11e protocol header file
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/802.1d.h b/bcm4329/src/include/proto/802.1d.h
index efd7117..45c728b 100644
--- a/bcm4329/src/include/proto/802.1d.h
+++ b/bcm4329/src/include/proto/802.1d.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/bcmeth.h b/bcm4329/src/include/proto/bcmeth.h
index bd34a0b..fdb5a2a 100644
--- a/bcm4329/src/include/proto/bcmeth.h
+++ b/bcm4329/src/include/proto/bcmeth.h
@@ -1,7 +1,7 @@
/*
* Broadcom Ethernettype protocol definitions
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/bcmevent.h b/bcm4329/src/include/proto/bcmevent.h
index 1791478..46c04d3 100644
--- a/bcm4329/src/include/proto/bcmevent.h
+++ b/bcm4329/src/include/proto/bcmevent.h
@@ -1,7 +1,7 @@
/*
* Broadcom Event protocol definitions
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/bcmip.h b/bcm4329/src/include/proto/bcmip.h
index 9645016..9d2fd6f 100644
--- a/bcm4329/src/include/proto/bcmip.h
+++ b/bcm4329/src/include/proto/bcmip.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/ethernet.h b/bcm4329/src/include/proto/ethernet.h
index 05530d5..9ad2ea0 100644
--- a/bcm4329/src/include/proto/ethernet.h
+++ b/bcm4329/src/include/proto/ethernet.h
@@ -1,7 +1,7 @@
/*
* From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: ethernet.h,v 9.45.56.3 2009/08/15 00:51:27 Exp $
+ * $Id: ethernet.h,v 9.45.56.5 2010/02/22 22:04:36 Exp $
*/
@@ -67,6 +67,7 @@
#define ETHER_TYPE_8021Q 0x8100
#define ETHER_TYPE_BRCM 0x886c
#define ETHER_TYPE_802_1X 0x888e
+#define ETHER_TYPE_WAI 0x88b4
#ifdef BCMWPA2
#define ETHER_TYPE_802_1X_PREAUTH 0x88c7
#endif
diff --git a/bcm4329/src/include/proto/sdspi.h b/bcm4329/src/include/proto/sdspi.h
index 3c7bcf3..7739e68 100644
--- a/bcm4329/src/include/proto/sdspi.h
+++ b/bcm4329/src/include/proto/sdspi.h
@@ -1,7 +1,7 @@
/*
* SD-SPI Protocol Standard
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/vlan.h b/bcm4329/src/include/proto/vlan.h
index 2dda4d5..670bc44 100644
--- a/bcm4329/src/include/proto/vlan.h
+++ b/bcm4329/src/include/proto/vlan.h
@@ -1,7 +1,7 @@
/*
* 802.1Q VLAN protocol definitions
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/proto/wpa.h b/bcm4329/src/include/proto/wpa.h
index 4c50125..f5d0cd5 100644
--- a/bcm4329/src/include/proto/wpa.h
+++ b/bcm4329/src/include/proto/wpa.h
@@ -1,7 +1,7 @@
/*
* Fundamental types and constants relating to WPA
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sbconfig.h b/bcm4329/src/include/sbconfig.h
index edf497c..da18ccb 100644
--- a/bcm4329/src/include/sbconfig.h
+++ b/bcm4329/src/include/sbconfig.h
@@ -1,7 +1,7 @@
/*
* Broadcom SiliconBackplane hardware register definitions.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sbhnddma.h b/bcm4329/src/include/sbhnddma.h
index 2aeee9e..7681395 100644
--- a/bcm4329/src/include/sbhnddma.h
+++ b/bcm4329/src/include/sbhnddma.h
@@ -2,7 +2,7 @@
* Generic Broadcom Home Networking Division (HND) DMA engine HW interface
* This supports the following chips: BCM42xx, 44xx, 47xx .
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sbpcmcia.h b/bcm4329/src/include/sbpcmcia.h
index 121b1a9..d6d8033 100644
--- a/bcm4329/src/include/sbpcmcia.h
+++ b/bcm4329/src/include/sbpcmcia.h
@@ -1,7 +1,7 @@
/*
* BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sbsdio.h b/bcm4329/src/include/sbsdio.h
index 43ed6b5..75aaf4d 100644
--- a/bcm4329/src/include/sbsdio.h
+++ b/bcm4329/src/include/sbsdio.h
@@ -4,7 +4,7 @@
*
* SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sbsdpcmdev.h b/bcm4329/src/include/sbsdpcmdev.h
index 57e832d..7c7c7e4 100644
--- a/bcm4329/src/include/sbsdpcmdev.h
+++ b/bcm4329/src/include/sbsdpcmdev.h
@@ -1,7 +1,7 @@
/*
* Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific device core support
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sbsocram.h b/bcm4329/src/include/sbsocram.h
index 170e8f2..5ede0b6 100644
--- a/bcm4329/src/include/sbsocram.h
+++ b/bcm4329/src/include/sbsocram.h
@@ -1,7 +1,7 @@
/*
* BCM47XX Sonics SiliconBackplane embedded ram core
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/sdio.h b/bcm4329/src/include/sdio.h
index d20d69c..280cb84 100644
--- a/bcm4329/src/include/sdio.h
+++ b/bcm4329/src/include/sdio.h
@@ -2,7 +2,7 @@
* SDIO spec header file
* Protocol and standard (common) device definitions
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/siutils.h b/bcm4329/src/include/siutils.h
index c55293b..cb9f140 100644
--- a/bcm4329/src/include/siutils.h
+++ b/bcm4329/src/include/siutils.h
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: siutils.h,v 13.197.4.2.4.3.8.14 2010/03/19 18:31:43 Exp $
+ * $Id: siutils.h,v 13.197.4.2.4.3.8.16 2010/06/23 21:36:05 Exp $
*/
diff --git a/bcm4329/src/include/trxhdr.h b/bcm4329/src/include/trxhdr.h
index b79ac35..8f5eed9 100644
--- a/bcm4329/src/include/trxhdr.h
+++ b/bcm4329/src/include/trxhdr.h
@@ -1,7 +1,7 @@
/*
* TRX image file header format.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/typedefs.h b/bcm4329/src/include/typedefs.h
index e4daeee..4d9dd76 100644
--- a/bcm4329/src/include/typedefs.h
+++ b/bcm4329/src/include/typedefs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/include/wlioctl.h b/bcm4329/src/include/wlioctl.h
index 58a2f6c..345ba34 100644
--- a/bcm4329/src/include/wlioctl.h
+++ b/bcm4329/src/include/wlioctl.h
@@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wlioctl.h,v 1.601.4.15.2.14.2.60 2010/04/12 05:33:02 Exp $
+ * $Id: wlioctl.h,v 1.601.4.15.2.14.2.62 2010/08/19 01:20:12 Exp $
*/
@@ -288,6 +288,7 @@ typedef enum sup_auth_status {
#define CRYPTO_ALGO_AES_OCB_MSDU 5
#define CRYPTO_ALGO_AES_OCB_MPDU 6
#define CRYPTO_ALGO_NALG 7
+#define CRYPTO_ALGO_SMS4 11
#define WSEC_GEN_MIC_ERROR 0x0001
#define WSEC_GEN_REPLAY 0x0002
@@ -338,6 +339,7 @@ typedef struct {
#define AES_ENABLED 0x0004
#define WSEC_SWFLAG 0x0008
#define SES_OW_ENABLED 0x0040
+#define SMS4_ENABLED 0x0100
#define WPA_AUTH_DISABLED 0x0000
@@ -349,6 +351,7 @@ typedef struct {
#define WPA2_AUTH_PSK 0x0080
#define BRCM_AUTH_PSK 0x0100
#define BRCM_AUTH_DPT 0x0200
+#define WPA_AUTH_WAPI 0x0400
#define WPA_AUTH_PFN_ANY 0xffffffff
@@ -1314,6 +1317,8 @@ enum {
#define PFN_VERSION 1
+#define MAX_PFN_LIST_COUNT 16
+
typedef struct wl_pfn_param {
int32 version;
@@ -1324,12 +1329,12 @@ typedef struct wl_pfn_param {
} wl_pfn_param_t;
typedef struct wl_pfn {
- wlc_ssid_t ssid;
- int32 bss_type;
- int32 infra;
- int32 auth;
- uint32 wpa_auth;
- int32 wsec;
+ wlc_ssid_t ssid;
+ int32 bss_type;
+ int32 infra;
+ int32 auth;
+ uint32 wpa_auth;
+ int32 wsec;
#ifdef WLPFN_AUTO_CONNECT
union {
wl_wsec_key_t sec_key;
diff --git a/bcm4329/src/shared/aiutils.c b/bcm4329/src/shared/aiutils.c
index 1962711..df48ac0 100644
--- a/bcm4329/src/shared/aiutils.c
+++ b/bcm4329/src/shared/aiutils.c
@@ -2,7 +2,7 @@
* Misc utility routines for accessing chip-specific features
* of the SiliconBackplane-based Broadcom chips.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: aiutils.c,v 1.6.4.7.4.5 2009/09/25 00:32:01 Exp $
+ * $Id: aiutils.c,v 1.6.4.7.4.6 2010/04/21 20:43:47 Exp $
*/
#include <typedefs.h>
diff --git a/bcm4329/src/shared/bcmutils.c b/bcm4329/src/shared/bcmutils.c
index c553d8e..43c04ee 100644
--- a/bcm4329/src/shared/bcmutils.c
+++ b/bcm4329/src/shared/bcmutils.c
@@ -20,7 +20,7 @@
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
- * $Id: bcmutils.c,v 1.210.4.5.2.4.6.17 2009/11/17 02:20:12 Exp $
+ * $Id: bcmutils.c,v 1.210.4.5.2.4.6.19 2010/04/26 06:05:25 Exp $
*/
#include <typedefs.h>
diff --git a/bcm4329/src/shared/bcmwifi.c b/bcm4329/src/shared/bcmwifi.c
index 641a4fd..803acf8 100644
--- a/bcm4329/src/shared/bcmwifi.c
+++ b/bcm4329/src/shared/bcmwifi.c
@@ -3,7 +3,7 @@
* Contents are wifi-specific, used by any kernel or app-level
* software that might want wifi things as it grows.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/shared/hndpmu.c b/bcm4329/src/shared/hndpmu.c
index 25712ac..307347a 100644
--- a/bcm4329/src/shared/hndpmu.c
+++ b/bcm4329/src/shared/hndpmu.c
@@ -2,7 +2,7 @@
* Misc utility routines for accessing PMU corerev specific features
* of the SiliconBackplane-based Broadcom chips.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: hndpmu.c,v 1.95.2.17.4.11.2.50 2009/10/26 14:45:51 Exp $
+ * $Id: hndpmu.c,v 1.95.2.17.4.11.2.63 2010/07/21 13:55:09 Exp $
*/
#include <typedefs.h>
diff --git a/bcm4329/src/shared/miniopt.c b/bcm4329/src/shared/miniopt.c
index 44199ea..6a184a7 100644
--- a/bcm4329/src/shared/miniopt.c
+++ b/bcm4329/src/shared/miniopt.c
@@ -1,7 +1,7 @@
/*
* Description.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/shared/sbutils.c b/bcm4329/src/shared/sbutils.c
index 567e94e..46cd510 100644
--- a/bcm4329/src/shared/sbutils.c
+++ b/bcm4329/src/shared/sbutils.c
@@ -2,7 +2,7 @@
* Misc utility routines for accessing chip-specific features
* of the SiliconBackplane-based Broadcom chips.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: sbutils.c,v 1.662.4.10.2.7.4.1 2009/09/25 00:32:01 Exp $
+ * $Id: sbutils.c,v 1.662.4.10.2.7.4.2 2010/04/19 05:48:48 Exp $
*/
#include <typedefs.h>
diff --git a/bcm4329/src/shared/siutils.c b/bcm4329/src/shared/siutils.c
index 6472a78..1814db0 100644
--- a/bcm4329/src/shared/siutils.c
+++ b/bcm4329/src/shared/siutils.c
@@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: siutils.c,v 1.662.4.4.4.16.4.26 2010/02/01 05:51:56 Exp $
+ * $Id: siutils.c,v 1.662.4.4.4.16.4.28 2010/06/23 21:37:54 Exp $
*/
#include <typedefs.h>
diff --git a/bcm4329/src/shared/siutils_priv.h b/bcm4329/src/shared/siutils_priv.h
index 1ec59aa..e8ad7e5 100644
--- a/bcm4329/src/shared/siutils_priv.h
+++ b/bcm4329/src/shared/siutils_priv.h
@@ -1,7 +1,7 @@
/*
* Include file private to the SOC Interconnect support files.
*
- * Copyright (C) 1999-2009, Broadcom Corporation
+ * Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
diff --git a/bcm4329/src/wl/sys/wl_cfg80211.c b/bcm4329/src/wl/sys/wl_cfg80211.c
new file mode 100644
index 0000000..81491cb
--- /dev/null
+++ b/bcm4329/src/wl/sys/wl_cfg80211.c
@@ -0,0 +1,4491 @@
+/*
+ * Linux Cfg80211 support
+ *
+ * Copyright (C) 1999-2010, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.c,v 1.1.2.28 2010/05/04 21:43:38 Exp $
+ */
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+
+#include <proto/ethernet.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+
+#include <net/rtnetlink.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/firmware.h>
+#include <wl_cfg80211.h>
+
+static struct sdio_func *cfg80211_sdio_func = NULL;
+static struct wl_dev *wl_cfg80211_dev = NULL;
+
+#ifdef WL_CFG80211_BACKTRACE
+uint32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO | WL_DBG_DBG;
+#else
+uint32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO;
+#endif
+
+#define WL_4329_FW_FILE "brcm/fw_4329.bin"
+#define WL_4329_NVRAM_FILE "brcm/nvram_4329.txt"
+
+/*
+** cfg80211_ops api/callback list
+*/
+static int32 wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
+ enum nl80211_iftype type, uint32 *flags, struct vif_params *params);
+static int32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid);
+static int32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request);
+static int32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, uint32 changed);
+static int32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+static int32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
+static int32 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ uint8 *mac, struct station_info *sinfo);
+static int32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled, int32 timeout);
+static int32 wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
+ struct net_device *dev, const uint8 *addr,
+ const struct cfg80211_bitrate_mask *mask);
+static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static int32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ uint16 reason_code);
+static int32 wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int32 dbm);
+static int32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, int32 *dbm);
+static int32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx);
+static int32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr, struct key_params *params);
+static int32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr);
+static int32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params *params));
+static int32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev, uint8 key_idx);
+static int32 wl_cfg80211_resume(struct wiphy *wiphy);
+static int32 wl_cfg80211_suspend(struct wiphy *wiphy);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+static int32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+static int32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+static int32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev);
+#endif
+/*
+** event & event Q handlers for cfg80211 interfaces
+*/
+static int32 wl_create_event_handler(struct wl_priv *wl);
+static void wl_destroy_event_handler(struct wl_priv *wl);
+static int32 wl_event_handler(void *data);
+static void wl_init_eq(struct wl_priv *wl);
+static void wl_flush_eq(struct wl_priv *wl);
+static void wl_lock_eq(struct wl_priv *wl);
+static void wl_unlock_eq(struct wl_priv *wl);
+static void wl_init_eq_lock(struct wl_priv *wl);
+static void wl_init_eloop_handler(struct wl_event_loop *el);
+static struct wl_event_q *wl_deq_event(struct wl_priv *wl);
+static int32 wl_enq_event(struct wl_priv *wl, uint32 type, const wl_event_msg_t *msg, void *data);
+static void wl_put_event(struct wl_event_q *e);
+static void wl_wakeup_event(struct wl_priv *wl);
+static int32 wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data);
+static int32 wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data);
+static int32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data);
+static int32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data);
+static int32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data);
+static int32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data);
+
+/*
+** register/deregister sdio function
+*/
+static struct sdio_func *wl_sdio_func(void);
+static void wl_clear_sdio_func(void);
+
+/*
+** ioctl utilites
+*/
+static int32 wl_dev_bufvar_get(struct net_device *dev, int8 *name, int8 *buf, int32 buf_len);
+static __used int32 wl_dev_bufvar_set(struct net_device *dev, int8 *name, int8 *buf, int32 len);
+static int32 wl_dev_intvar_set(struct net_device *dev, int8 *name, int32 val);
+static int32 wl_dev_intvar_get(struct net_device *dev, int8 *name, int32 *retval);
+static int32 wl_dev_ioctl(struct net_device *dev, uint32 cmd, void *arg, uint32 len);
+
+
+/*
+** cfg80211 set_wiphy_params utilities
+*/
+static int32 wl_set_frag(struct net_device *dev, uint32 frag_threshold);
+static int32 wl_set_rts(struct net_device *dev, uint32 frag_threshold);
+static int32 wl_set_retry(struct net_device *dev, uint32 retry, bool l);
+
+/*
+** wl profile utilities
+*/
+static int32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, int32 item);
+static void * wl_read_prof(struct wl_priv *wl, int32 item);
+static void wl_init_prof(struct wl_profile *prof);
+
+
+/*
+** cfg80211 connect utilites
+*/
+static int32 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme);
+static int32 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme);
+static int32 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme);
+static int32 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme);
+static int32 wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme);
+static int32 wl_get_assoc_ies(struct wl_priv *wl);
+
+
+/*
+** information element utilities
+*/
+static void wl_rst_ie(struct wl_priv *wl);
+static int32 wl_add_ie(struct wl_priv *wl, uint8 t, uint8 l, uint8 *v);
+static int32 wl_mrg_ie(struct wl_priv *wl, uint8 *ie_stream, uint16 ie_size);
+static int32 wl_cp_ie(struct wl_priv *wl, uint8 *dst, uint16 dst_size);
+static uint32 wl_get_ielen(struct wl_priv *wl);
+
+
+static int32 wl_mode_to_nl80211_iftype(int32 mode);
+
+static struct wireless_dev *wl_alloc_wdev(int32 sizeof_iface, struct device *dev);
+static void wl_free_wdev(struct wl_priv *wl);
+
+static int32 wl_inform_bss(struct wl_priv *wl);
+static int32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
+static int32 wl_update_bss_info(struct wl_priv *wl);
+
+static int32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr, struct key_params *params);
+
+
+/*
+** key indianess swap utilities
+*/
+static void swap_key_from_BE(struct wl_wsec_key *key);
+static void swap_key_to_BE(struct wl_wsec_key *key);
+
+
+/*
+** wl_priv memory init/deinit utilities
+*/
+static int32 wl_init_priv_mem(struct wl_priv *wl);
+static void wl_deinit_priv_mem(struct wl_priv *wl);
+
+static void wl_delay(uint32 ms);
+
+/*
+** store/restore cfg80211 instance data
+*/
+static void wl_set_drvdata(struct wl_dev *dev, void *data);
+static void *wl_get_drvdata(struct wl_dev *dev);
+
+/*
+** ibss mode utilities
+*/
+static bool wl_is_ibssmode(struct wl_priv *wl);
+static bool wl_is_ibssstarter(struct wl_priv *wl);
+
+/*
+** dongle up/down , default configuration utilities
+*/
+static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
+static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e);
+static void wl_link_up(struct wl_priv *wl);
+static void wl_link_down(struct wl_priv *wl);
+static int32 wl_dongle_mode(struct net_device *ndev, int32 iftype);
+static int32 __wl_cfg80211_up(struct wl_priv *wl);
+static int32 __wl_cfg80211_down(struct wl_priv *wl);
+static int32 wl_dongle_probecap(struct wl_priv *wl);
+static void wl_init_conf(struct wl_conf *conf);
+
+/*
+** dongle configuration utilities
+*/
+#ifndef EMBEDDED_PLATFORM
+static int32 wl_dongle_mode(struct net_device *ndev, int32 iftype);
+static int32 wl_dongle_country(struct net_device *ndev, uint8 ccode);
+static int32 wl_dongle_up(struct net_device *ndev, uint32 up);
+static int32 wl_dongle_power(struct net_device *ndev, uint32 power_mode);
+static int32 wl_dongle_glom(struct net_device *ndev, uint32 glom, uint32 dongle_align);
+static int32 wl_dongle_roam(struct net_device *ndev, uint32 roamvar, uint32 bcn_timeout);
+static int32 wl_dongle_eventmsg(struct net_device *ndev);
+static int32 wl_dongle_scantime(struct net_device *ndev, int32 scan_assoc_time,
+ int32 scan_unassoc_time);
+static int32 wl_dongle_offload(struct net_device *ndev, int32 arpoe, int32 arp_ol);
+static int32 wl_pattern_atoh(int8 *src, int8 *dst);
+static int32 wl_dongle_filter(struct net_device *ndev, uint32 filter_mode);
+static int32 wl_update_wiphybands(struct wl_priv *wl);
+#endif /* !EMBEDDED_PLATFORM */
+static int32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
+
+/*
+** iscan handler
+*/
+static void wl_iscan_timer(ulong data);
+static void wl_term_iscan(struct wl_priv *wl);
+static int32 wl_init_iscan(struct wl_priv *wl);
+static int32 wl_iscan_thread(void *data);
+static int32 wl_dev_iovar_setbuf(struct net_device *dev, int8 *iovar, void *param,
+ int32 paramlen, void *bufptr, int32 buflen);
+static int32 wl_dev_iovar_getbuf(struct net_device *dev, int8 *iovar, void *param,
+ int32 paramlen, void *bufptr, int32 buflen);
+static int32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, uint16 action);
+static int32 wl_do_iscan(struct wl_priv *wl);
+static int32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan);
+static int32 wl_invoke_iscan(struct wl_priv *wl);
+static int32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, uint32 *status,
+ struct wl_scan_results **bss_list);
+static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted);
+static void wl_init_iscan_eloop(struct wl_iscan_eloop *el);
+static int32 wl_iscan_done(struct wl_priv *wl);
+static int32 wl_iscan_pending(struct wl_priv *wl);
+static int32 wl_iscan_inprogress(struct wl_priv *wl);
+static int32 wl_iscan_aborted(struct wl_priv *wl);
+
+/*
+** fw/nvram downloading handler
+*/
+static void wl_init_fw(struct wl_fw_ctrl *fw);
+
+/*
+* find most significant bit set
+*/
+static __used uint32 wl_find_msb(uint16 bit16);
+
+/*
+* update pmklist to dongle
+*/
+static __used int32 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
+ int32 err);
+
+
+#define WL_PRIV_GET() \
+ ({ \
+ struct wl_iface *ci; \
+ if (unlikely(!(wl_cfg80211_dev && (ci = wl_get_drvdata(wl_cfg80211_dev))))) { \
+ WL_ERR(("wl_cfg80211_dev is unavailable\n")); \
+ BUG(); \
+ } \
+ ci_to_wl(ci); \
+ })
+
+#define CHECK_SYS_UP() \
+ do { \
+ struct wl_priv *wl = wiphy_to_wl(wiphy); \
+ if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \
+ WL_INFO(("device is not ready : status (%d)\n", (int)wl->status)); \
+ return -EIO; \
+ } \
+ } while (0)
+
+
+extern int dhd_wait_pend8021x(struct net_device *dev);
+
+#if (WL_DBG_LEVEL > 0)
+#define WL_DBG_ESTR_MAX 32
+static int8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
+"SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND",
+"DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC",
+"REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END",
+"BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM",
+"TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH",
+"EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND",
+"BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND", "PFN_NET_LOST",
+"RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START", "IBSS_ASSOC",
+"RADIO", "PSM_WATCHDOG",
+"PROBREQ_MSG",
+"SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED", "EXCEEDED_MEDIUM_TIME", "ICV_ERROR",
+"UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE",
+"IF",
+"RSSI", "PFN_SCAN_COMPLETE", "ACTION_FRAME", "ACTION_FRAME_COMPLETE",
+};
+#endif /* WL_DBG_LEVEL */
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel, _flags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .bitrate = RATE_TO_BASE100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+static struct ieee80211_rate __wl_rates[] = {
+ RATETAB_ENT(WLC_RATE_1M, 0),
+ RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(WLC_RATE_6M, 0),
+ RATETAB_ENT(WLC_RATE_9M, 0),
+ RATETAB_ENT(WLC_RATE_12M, 0),
+ RATETAB_ENT(WLC_RATE_18M, 0),
+ RATETAB_ENT(WLC_RATE_24M, 0),
+ RATETAB_ENT(WLC_RATE_36M, 0),
+ RATETAB_ENT(WLC_RATE_48M, 0),
+ RATETAB_ENT(WLC_RATE_54M, 0),
+};
+
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size 8
+#define wl_g_rates (__wl_rates + 0)
+#define wl_g_rates_size 12
+
+static struct ieee80211_channel __wl_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel __wl_5ghz_a_channels[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(149, 0),
+ CHAN5G(153, 0), CHAN5G(157, 0),
+ CHAN5G(161, 0), CHAN5G(165, 0),
+ CHAN5G(184, 0), CHAN5G(188, 0),
+ CHAN5G(192, 0), CHAN5G(196, 0),
+ CHAN5G(200, 0), CHAN5G(204, 0),
+ CHAN5G(208, 0), CHAN5G(212, 0),
+ CHAN5G(216, 0),
+};
+
+static struct ieee80211_channel __wl_5ghz_n_channels[] = {
+ CHAN5G(32, 0), CHAN5G(34, 0),
+ CHAN5G(36, 0), CHAN5G(38, 0),
+ CHAN5G(40, 0), CHAN5G(42, 0),
+ CHAN5G(44, 0), CHAN5G(46, 0),
+ CHAN5G(48, 0), CHAN5G(50, 0),
+ CHAN5G(52, 0), CHAN5G(54, 0),
+ CHAN5G(56, 0), CHAN5G(58, 0),
+ CHAN5G(60, 0), CHAN5G(62, 0),
+ CHAN5G(64, 0), CHAN5G(66, 0),
+ CHAN5G(68, 0), CHAN5G(70, 0),
+ CHAN5G(72, 0), CHAN5G(74, 0),
+ CHAN5G(76, 0), CHAN5G(78, 0),
+ CHAN5G(80, 0), CHAN5G(82, 0),
+ CHAN5G(84, 0), CHAN5G(86, 0),
+ CHAN5G(88, 0), CHAN5G(90, 0),
+ CHAN5G(92, 0), CHAN5G(94, 0),
+ CHAN5G(96, 0), CHAN5G(98, 0),
+ CHAN5G(100, 0), CHAN5G(102, 0),
+ CHAN5G(104, 0), CHAN5G(106, 0),
+ CHAN5G(108, 0), CHAN5G(110, 0),
+ CHAN5G(112, 0), CHAN5G(114, 0),
+ CHAN5G(116, 0), CHAN5G(118, 0),
+ CHAN5G(120, 0), CHAN5G(122, 0),
+ CHAN5G(124, 0), CHAN5G(126, 0),
+ CHAN5G(128, 0), CHAN5G(130, 0),
+ CHAN5G(132, 0), CHAN5G(134, 0),
+ CHAN5G(136, 0), CHAN5G(138, 0),
+ CHAN5G(140, 0), CHAN5G(142, 0),
+ CHAN5G(144, 0), CHAN5G(145, 0),
+ CHAN5G(146, 0), CHAN5G(147, 0),
+ CHAN5G(148, 0), CHAN5G(149, 0),
+ CHAN5G(150, 0), CHAN5G(151, 0),
+ CHAN5G(152, 0), CHAN5G(153, 0),
+ CHAN5G(154, 0), CHAN5G(155, 0),
+ CHAN5G(156, 0), CHAN5G(157, 0),
+ CHAN5G(158, 0), CHAN5G(159, 0),
+ CHAN5G(160, 0), CHAN5G(161, 0),
+ CHAN5G(162, 0), CHAN5G(163, 0),
+ CHAN5G(164, 0), CHAN5G(165, 0),
+ CHAN5G(166, 0), CHAN5G(168, 0),
+ CHAN5G(170, 0), CHAN5G(172, 0),
+ CHAN5G(174, 0), CHAN5G(176, 0),
+ CHAN5G(178, 0), CHAN5G(180, 0),
+ CHAN5G(182, 0), CHAN5G(184, 0),
+ CHAN5G(186, 0), CHAN5G(188, 0),
+ CHAN5G(190, 0), CHAN5G(192, 0),
+ CHAN5G(194, 0), CHAN5G(196, 0),
+ CHAN5G(198, 0), CHAN5G(200, 0),
+ CHAN5G(202, 0), CHAN5G(204, 0),
+ CHAN5G(206, 0), CHAN5G(208, 0),
+ CHAN5G(210, 0), CHAN5G(212, 0),
+ CHAN5G(214, 0), CHAN5G(216, 0),
+ CHAN5G(218, 0), CHAN5G(220, 0),
+ CHAN5G(222, 0), CHAN5G(224, 0),
+ CHAN5G(226, 0), CHAN5G(228, 0),
+};
+
+static struct ieee80211_supported_band __wl_band_2ghz = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = __wl_2ghz_channels,
+ .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
+ .bitrates = wl_g_rates,
+ .n_bitrates = wl_g_rates_size,
+};
+
+static struct ieee80211_supported_band __wl_band_5ghz_a = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = __wl_5ghz_a_channels,
+ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size,
+};
+
+static struct ieee80211_supported_band __wl_band_5ghz_n = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = __wl_5ghz_n_channels,
+ .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size,
+};
+
+static const uint32 __wl_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+};
+
+static void
+swap_key_from_BE(struct wl_wsec_key *key)
+{
+ key->index = htod32(key->index);
+ key->len = htod32(key->len);
+ key->algo = htod32(key->algo);
+ key->flags = htod32(key->flags);
+ key->rxiv.hi = htod32(key->rxiv.hi);
+ key->rxiv.lo = htod16(key->rxiv.lo);
+ key->iv_initialized = htod32(key->iv_initialized);
+}
+
+static void
+swap_key_to_BE(struct wl_wsec_key *key)
+{
+ key->index = dtoh32(key->index);
+ key->len = dtoh32(key->len);
+ key->algo = dtoh32(key->algo);
+ key->flags = dtoh32(key->flags);
+ key->rxiv.hi = dtoh32(key->rxiv.hi);
+ key->rxiv.lo = dtoh16(key->rxiv.lo);
+ key->iv_initialized = dtoh32(key->iv_initialized);
+}
+
+static int32
+wl_dev_ioctl(struct net_device *dev, uint32 cmd, void *arg, uint32 len)
+{
+ struct ifreq ifr;
+ struct wl_ioctl ioc;
+ mm_segment_t fs;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In : cmd (%d)\n", cmd));
+#endif
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = cmd;
+ ioc.buf = arg;
+ ioc.len = len;
+ strcpy(ifr.ifr_name, dev->name);
+ ifr.ifr_data = (caddr_t) &ioc;
+
+
+ fs = get_fs();
+ set_fs(get_ds());
+ err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
+ set_fs(fs);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
+ enum nl80211_iftype type, uint32 *flags, struct vif_params *params)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct wireless_dev *wdev;
+ int32 infra = 0;
+ int32 ap = 0;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ WL_ERR(("type (%d) : currently we do not support this type\n", type));
+ return -EOPNOTSUPP;
+ case NL80211_IFTYPE_ADHOC:
+ wl->conf->mode = WL_MODE_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ wl->conf->mode = WL_MODE_BSS;
+ infra = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ infra = htod32(infra);
+ ap = htod32(ap);
+ wdev = ndev->ieee80211_ptr;
+ wdev->iftype = type;
+ WL_DBG(("%s : ap (%d), infra (%d)\n", ndev->name, ap, infra));
+ if (unlikely((err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra)))) ||
+ unlikely((err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap))))) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ /* -EINPROGRESS: Call commit handler */
+ return -EINPROGRESS;
+}
+
+static void
+wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
+{
+ memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = 0;
+ params->nprobes = -1;
+ params->active_time = -1;
+ params->passive_time = -1;
+ params->home_time = -1;
+ params->channel_num = 0;
+
+ params->nprobes = htod32(params->nprobes);
+ params->active_time = htod32(params->active_time);
+ params->passive_time = htod32(params->passive_time);
+ params->home_time = htod32(params->home_time);
+ if (ssid && ssid->SSID_len)
+ memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
+
+}
+
+static int32
+wl_dev_iovar_setbuf(struct net_device *dev, int8 *iovar, void *param,
+ int32 paramlen, void *bufptr, int32 buflen)
+{
+ int32 iolen;
+
+ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ BUG_ON(unlikely(!iolen));
+
+ return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
+}
+
+static int32
+wl_dev_iovar_getbuf(struct net_device *dev, int8 *iovar, void *param,
+ int32 paramlen, void *bufptr, int32 buflen)
+{
+ int32 iolen;
+
+ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ BUG_ON(unlikely(!iolen));
+
+ return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen);
+}
+
+static int32
+wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, uint16 action)
+{
+ int32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
+ struct wl_iscan_params *params;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (ssid && ssid->SSID_len)
+ params_size += sizeof(struct wlc_ssid);
+ params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
+ if (unlikely(!params))
+ return -ENOMEM;
+ memset(params, 0, params_size);
+ BUG_ON(unlikely(params_size >= WLC_IOCTL_SMLEN));
+
+ wl_iscan_prep(&params->params, ssid);
+
+ params->version = htod32(ISCAN_REQ_VERSION);
+ params->action = htod16(action);
+ params->scan_duration = htod16(0);
+
+ /* params_size += OFFSETOF(wl_iscan_params_t, params); */
+ if (unlikely((err = wl_dev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
+ iscan->ioctl_buf, WLC_IOCTL_SMLEN)))) {
+ if (err == -EBUSY) {
+ WL_INFO(("system busy : iscan canceled\n"));
+ } else {
+ WL_ERR(("error (%d)\n", err));
+ }
+ }
+ kfree(params);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+
+static int32
+wl_do_iscan(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
+ struct wlc_ssid ssid;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ /* Broadcast scan by default */
+ memset(&ssid, 0, sizeof(ssid));
+
+ iscan->state = WL_ISCAN_STATE_SCANING;
+
+ if (wl->active_scan) {
+ int32 passive_scan = 0;
+ /* make it active scan */
+ if (unlikely((err = wl_dev_ioctl(wl_to_ndev(wl), WLC_SET_PASSIVE_SCAN,
+ &passive_scan, sizeof(passive_scan))))) {
+ WL_DBG(("error (%d)\n", err));
+ return err;
+ }
+ }
+ wl->iscan_kickstart = TRUE;
+ wl_run_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
+ iscan->timer_on = 1;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+
+static int32
+__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid)
+{
+ struct wl_priv *wl = ndev_to_wl(ndev);
+ struct cfg80211_ssid *ssids;
+ struct wl_scan_req *sr = wl_to_sr(wl);
+ uint32 n_ssids;
+ bool iscan_req;
+ bool spec_scan;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) {
+ WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
+ return -EAGAIN;
+ }
+ if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) {
+ WL_ERR(("Scanning being aborted : status (%d)\n", (int)wl->status));
+ return -EAGAIN;
+ }
+
+ iscan_req = FALSE;
+ spec_scan = FALSE;
+ if (request) { /* scan bss */
+ ssids = request->ssids;
+ n_ssids = min(request->n_ssids, WL_NUM_SCAN_MAX);
+ if (wl->iscan_on && n_ssids && !ssids->ssid_len) { /* for specific scan,
+ * ssids->ssid_len has
+ * non-zero(ssid string) length.
+ * Otherwise this is 0.
+ * we do not iscan for
+ * specific scan request
+ */
+ iscan_req = TRUE;
+ }
+ } else { /* scan in ibss */
+ /* we don't do iscan in ibss */
+ ssids = this_ssid;
+ n_ssids = 1;
+ }
+ wl->scan_request = request;
+ set_bit(WL_STATUS_SCANNING, &wl->status);
+ if (iscan_req) {
+ if (likely(!(err = wl_do_iscan(wl))))
+ return err;
+ else
+ goto scan_out;
+ } else {
+ WL_DBG(("n_ssid (%d), ssid \"%s\", ssid_len (%d)\n",
+ n_ssids, ssids->ssid, ssids->ssid_len));
+ memset(&sr->ssid, 0, sizeof(sr->ssid));
+ if (n_ssids) {
+ sr->ssid.SSID_len = MIN(sizeof(sr->ssid.SSID), ssids->ssid_len);
+ if (sr->ssid.SSID_len) {
+ memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
+ sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
+ WL_DBG(("Specific scan ssid=\"%s\" len=%d\n", sr->ssid.SSID,
+ sr->ssid.SSID_len));
+ spec_scan = TRUE;
+ } else {
+ WL_DBG(("Broadcast scan\n"));
+ }
+ } else {
+ /* broadcast scan */
+ WL_DBG(("Broadcast scan\n"));
+ }
+ WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
+ if (wl->active_scan) {
+ int32 pssive_scan = 0;
+ /* make it active scan */
+ if (unlikely((err = wl_dev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
+ &pssive_scan, sizeof(pssive_scan))))) {
+ WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
+ goto scan_out;
+ }
+ }
+ if ((err = wl_dev_ioctl(ndev, WLC_SCAN, &sr->ssid, sizeof(sr->ssid)))) {
+ if (err == -EBUSY) {
+ WL_INFO(("system busy : scan for \"%s\" canceled\n",
+ sr->ssid.SSID));
+ } else {
+ WL_ERR(("WLC_SCAN error (%d)\n", err));
+ }
+ goto scan_out;
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return 0;
+
+scan_out:
+ clear_bit(WL_STATUS_SCANNING, &wl->status);
+ wl->scan_request = NULL;
+ return err;
+}
+
+
+static int32
+wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+{
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ if (unlikely((err = __wl_cfg80211_scan(wiphy, ndev, request, NULL)))) {
+ WL_DBG(("scan error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_dev_intvar_set(struct net_device *dev, int8 *name, int32 val)
+{
+ int8 buf[WLC_IOCTL_SMLEN];
+ uint32 len;
+ int32 err = 0;
+
+ val = htod32(val);
+ len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
+ BUG_ON(unlikely(!len));
+
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len)))) {
+ WL_ERR(("error (%d)\n", err));
+ }
+
+ return err;
+}
+
+static int32
+wl_dev_intvar_get(struct net_device *dev, int8 *name, int32 *retval)
+{
+ union {
+ int8 buf[WLC_IOCTL_SMLEN];
+ int32 val;
+ } var;
+ uint32 len;
+ uint32 data_null;
+ int32 err = 0;
+
+ len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
+ BUG_ON(unlikely(!len));
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len)))) {
+ WL_ERR(("error (%d)\n", err));
+ }
+ *retval = dtoh32(var.val);
+
+ return err;
+}
+
+static int32
+wl_set_rts(struct net_device *dev, uint32 rts_threshold)
+{
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely((err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold)))) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_set_frag(struct net_device *dev, uint32 frag_threshold)
+{
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely((err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold)))) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_set_retry(struct net_device *dev, uint32 retry, bool l)
+{
+ int32 err = 0;
+ uint32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ retry = htod32(retry);
+ if (unlikely((err = wl_dev_ioctl(dev, cmd, &retry, sizeof(retry))))) {
+ WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, uint32 changed)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct net_device *ndev = wl_to_ndev(wl);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
+ (wl->conf->rts_threshold != wiphy->rts_threshold)) {
+ wl->conf->rts_threshold = wiphy->rts_threshold;
+ if (!(err = wl_set_rts(ndev, wl->conf->rts_threshold))) {
+ return err;
+ }
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
+ (wl->conf->frag_threshold != wiphy->frag_threshold)) {
+ wl->conf->frag_threshold = wiphy->frag_threshold;
+ if (!(err = wl_set_frag(ndev, wl->conf->frag_threshold))) {
+ return err;
+ }
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG && (wl->conf->retry_long != wiphy->retry_long)) {
+ wl->conf->retry_long = wiphy->retry_long;
+ if (!(err = wl_set_retry(ndev, wl->conf->retry_long, TRUE))) {
+ return err;
+ }
+ }
+ if (changed & WIPHY_PARAM_RETRY_SHORT && (wl->conf->retry_short != wiphy->retry_short)) {
+ wl->conf->retry_short = wiphy->retry_short;
+ if (!(err = wl_set_retry(ndev, wl->conf->retry_short, FALSE))) {
+ return err;
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct cfg80211_bss *bss;
+ struct ieee80211_channel *chan;
+ struct wl_join_params join_params;
+ struct cfg80211_ssid ssid;
+ int32 scan_retry = 0;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In \n"));
+#endif
+ CHECK_SYS_UP();
+ if (params->bssid) {
+ WL_ERR(("Invalid bssid\n"));
+ return -EOPNOTSUPP;
+ }
+ bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
+ if (!bss) {
+ memcpy(ssid.ssid, params->ssid, params->ssid_len);
+ ssid.ssid_len = params->ssid_len;
+ do {
+ if (unlikely(__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) == -EBUSY)) {
+ wl_delay(150);
+ } else {
+ break;
+ }
+ } while (++scan_retry < WL_SCAN_RETRY_MAX);
+ rtnl_unlock(); /* to allow scan_inform to paropagate to cfg80211 plane */
+ schedule_timeout_interruptible(4 * HZ); /* wait 4 secons till scan done.... */
+ rtnl_lock();
+ bss = cfg80211_get_ibss(wiphy, NULL,
+ params->ssid, params->ssid_len);
+ }
+ if (bss) {
+ wl->ibss_starter = FALSE;
+ WL_DBG(("Found IBSS\n"));
+ } else {
+ wl->ibss_starter = TRUE;
+ }
+ if ((chan = params->channel)) {
+ wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ }
+ /*
+ ** Join with specific BSSID and cached SSID
+ ** If SSID is zero join based on BSSID only
+ */
+ memset(&join_params, 0, sizeof(join_params));
+ memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, params->ssid_len);
+ join_params.ssid.SSID_len = htod32(params->ssid_len);
+ if (params->bssid)
+ memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
+ else
+ memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
+
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params))))) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ wl_link_down(wl);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ struct wl_security *sec;
+ int32 val = 0;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
+ else
+ val = WPA_AUTH_DISABLED;
+ WL_DBG(("setting wpa_auth to 0x%0x\n", val));
+ if (unlikely((err = wl_dev_intvar_set(dev, "wpa_auth", val)))) {
+ WL_ERR(("set wpa_auth failed (%d)\n", err));
+ return err;
+ }
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec->wpa_versions = sme->crypto.wpa_versions;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ struct wl_security *sec;
+ int32 val = 0;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ val = 0;
+ WL_DBG(("open system\n"));
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ val = 1;
+ WL_DBG(("shared key\n"));
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ val = 2;
+ WL_DBG(("automatic\n"));
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ WL_DBG(("network eap\n"));
+ default :
+ val = 2;
+ WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
+ break;
+ }
+
+ if (unlikely((err = wl_dev_intvar_set(dev, "auth", val)))) {
+ WL_ERR(("set auth failed (%d)\n", err));
+ return err;
+ }
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec->auth_type = sme->auth_type;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+
+static int32
+wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ struct wl_security *sec;
+ int32 pval = 0;
+ int32 gval = 0;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (sme->crypto.n_ciphers_pairwise) {
+ switch (sme->crypto.ciphers_pairwise[0]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ pval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ pval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ pval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("invalid cipher pairwise (%d)\n",
+ sme->crypto.ciphers_pairwise[0]));
+ return -EINVAL;
+ }
+ }
+ if (sme->crypto.cipher_group) {
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ gval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ gval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ gval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group));
+ return -EINVAL;
+ }
+ }
+
+ WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
+ if (unlikely((err = wl_dev_intvar_set(dev, "wsec", pval|gval)))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
+ sec->cipher_group = sme->crypto.cipher_group;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ struct wl_security *sec;
+ int32 val = 0;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+
+ if (sme->crypto.n_akm_suites) {
+ if (unlikely((err = wl_dev_intvar_get(dev, "wpa_auth", &val)))) {
+ WL_ERR(("could not get wpa_auth (%d)\n", err));
+ return err;
+ }
+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA_AUTH_PSK;
+ break;
+ default :
+ WL_ERR(("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group));
+ return -EINVAL;
+ }
+ } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA2_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA2_AUTH_PSK;
+ break;
+ default :
+ WL_ERR(("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group));
+ return -EINVAL;
+ }
+ }
+
+ WL_DBG(("setting wpa_auth to %d\n", val));
+ if (unlikely((err = wl_dev_intvar_set(dev, "wpa_auth", val)))) {
+ WL_ERR(("could not set wpa_auth (%d)\n", err));
+ return err;
+ }
+ }
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ sec->wpa_auth = sme->crypto.akm_suites[0];
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ struct wl_security *sec;
+ struct wl_wsec_key key;
+ int32 val;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ WL_DBG(("key len (%d)\n", sme->key_len));
+ if (sme->key_len) {
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions,
+ sec->cipher_pairwise));
+ if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) &&
+ (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
+ WLAN_CIPHER_SUITE_WEP104))) {
+ memset(&key, 0, sizeof(key));
+ key.len = (uint32)sme->key_len;
+ key.index = (uint32)sme->key_idx;
+ if (unlikely(key.len > sizeof(key.data))) {
+ WL_ERR(("Too long key length (%u)\n", key.len));
+ return -EINVAL;
+ }
+ memcpy(key.data, sme->key, key.len);
+ key.flags = WL_PRIMARY_KEY;
+ switch (sec->cipher_pairwise) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+ default :
+ WL_ERR(("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]));
+ return -EINVAL;
+ }
+ /* Set the new key/index */
+ WL_DBG(("key length (%d) key index (%d) algo (%d)\n", key.len,
+ key.index, key.algo));
+ WL_DBG(("key \"%s\"\n", key.data));
+ swap_key_from_BE(&key);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+ if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+ WL_DBG(("set auth_type to shared key\n"));
+ val = 1; /* shared key */
+ if (unlikely((err = wl_dev_intvar_set(dev, "auth", val)))) {
+ WL_ERR(("set auth failed (%d)\n", err));
+ return err;
+ }
+ }
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ struct wlc_ssid ssid;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In \n"));
+#endif
+ CHECK_SYS_UP();
+ if (unlikely(!sme->ssid)) {
+ WL_ERR(("Invalid ssid\n"));
+ return -EOPNOTSUPP;
+ }
+ if (chan) {
+ wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ WL_DBG(("channel (%d), center_req (%d) \n", wl->channel, chan->center_freq));
+ }
+ WL_DBG(("ie (%p), ie_len (%d)\n", sme->ie, sme->ie_len));
+ if (unlikely((err = wl_set_wpa_version(dev, sme)))) {
+ return err;
+ }
+ if (unlikely((err = wl_set_auth_type(dev, sme)))) {
+ return err;
+ }
+ if (unlikely((err = wl_set_set_cipher(dev, sme)))) {
+ return err;
+ }
+ if (unlikely((err = wl_set_key_mgmt(dev, sme)))) {
+ return err;
+ }
+ if (unlikely((err = wl_set_set_sharedkey(dev, sme)))) {
+ return err;
+ }
+ wl_update_prof(wl, NULL, sme->bssid, WL_PROF_BSSID);
+ /*
+ ** Join with specific BSSID and cached SSID
+ ** If SSID is zero join based on BSSID only
+ */
+ memset(&ssid, 0, sizeof(ssid));
+ ssid.SSID_len = MIN(sizeof(ssid.SSID), sme->ssid_len);
+ memcpy(ssid.SSID, sme->ssid, ssid.SSID_len);
+ ssid.SSID_len = htod32(ssid.SSID_len);
+ wl_update_prof(wl, NULL, &ssid, WL_PROF_SSID);
+ if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ WL_DBG(("ssid \"%s\", len (%d)\n", ssid.SSID, ssid.SSID_len));
+ }
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid))))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ set_bit(WL_STATUS_CONNECTING, &wl->status);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ uint16 reason_code)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ scb_val_t scbval;
+ bool act = FALSE;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ WL_DBG(("Reason %d\n", reason_code));
+ CHECK_SYS_UP();
+ if (likely((act = *(bool *)wl_read_prof(wl, WL_PROF_ACT)))) {
+ scbval.val = reason_code;
+ memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t))))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type, int32 dbm)
+{
+
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct net_device *ndev = wl_to_ndev(wl);
+ uint16 txpwrmw;
+ int32 err = 0;
+ int32 disable = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ switch (type) {
+ case TX_POWER_AUTOMATIC:
+ break;
+ case TX_POWER_LIMITED:
+ if (dbm < 0) {
+ WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
+ return -EINVAL;
+ }
+ break;
+ case TX_POWER_FIXED:
+ if (dbm < 0) {
+ WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
+ return -EINVAL;
+ }
+ break;
+ }
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+ disable = htod32(disable);
+ if (unlikely((err = wl_dev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable))))) {
+ WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
+ return err;
+ }
+
+ if (dbm > 0xffff)
+ txpwrmw = 0xffff;
+ else
+ txpwrmw = (uint16)dbm;
+ if (unlikely((err = wl_dev_intvar_set(ndev, "qtxpower",
+ (int32)(bcm_mw_to_qdbm(txpwrmw)))))) {
+ WL_ERR(("qtxpower error (%d)\n", err));
+ return err;
+ }
+ wl->conf->tx_power = dbm;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_get_tx_power(struct wiphy *wiphy, int32 *dbm)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct net_device *ndev = wl_to_ndev(wl);
+ int32 txpwrdbm;
+ uint8 result;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ if (unlikely((err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm)))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
+ *dbm = (int32)bcm_qdbm_to_mw(result);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, uint8 key_idx)
+{
+ uint32 index;
+ int32 wsec;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ WL_DBG(("key index (%d)\n", key_idx));
+ CHECK_SYS_UP();
+
+ if (unlikely(err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)))) {
+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ return err;
+ }
+ wsec = dtoh32(wsec);
+ if (wsec & WEP_ENABLED) {
+ /* Just select a new current key */
+ index = (uint32)key_idx;
+ index = htod32(index);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_KEY_PRIMARY,
+ &index, sizeof(index))))) {
+ WL_ERR(("error (%d)\n", err));
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr, struct key_params *params)
+{
+ struct wl_wsec_key key;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ memset(&key, 0, sizeof(key));
+ key.index = (uint32)key_idx;
+ /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */
+ if (!ETHER_ISMULTI(mac_addr))
+ memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN);
+ key.len = (uint32)params->key_len;
+ /* check for key index change */
+ if (key.len == 0) {
+ /* key delete */
+ swap_key_from_BE(&key);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))) {
+ WL_ERR(("key delete error (%d)\n", err));
+ return err;
+ }
+ } else {
+ if (key.len > sizeof(key.data)) {
+ WL_ERR(("Invalid key length (%d)\n", key.len));
+ return -EINVAL;
+ }
+
+ WL_DBG(("Setting the key index %d\n", key.index));
+ memcpy(key.data, params->key, key.len);
+
+ if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ uint8 keybuf[8];
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ }
+
+ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
+ if (params->seq && params->seq_len == 6) {
+ /* rx iv */
+ uint8 *ivptr;
+ ivptr = (uint8 *)params->seq;
+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
+ (ivptr[3] << 8) | ivptr[2];
+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
+ key.iv_initialized = TRUE;
+ }
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ break;
+ default:
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ return -EINVAL;
+ }
+ swap_key_from_BE(&key);
+
+ dhd_wait_pend8021x(dev);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr, struct key_params *params)
+{
+ struct wl_wsec_key key;
+ int32 val;
+ int32 wsec;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ WL_DBG(("key index (%d)\n", key_idx));
+ CHECK_SYS_UP();
+
+ if (mac_addr)
+ return wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
+ memset(&key, 0, sizeof(key));
+
+ key.len = (uint32)params->key_len;
+ key.index = (uint32)key_idx;
+
+ if (unlikely(key.len > sizeof(key.data))) {
+ WL_ERR(("Too long key length (%u)\n", key.len));
+ return -EINVAL;
+ }
+ memcpy(key.data, params->key, key.len);
+
+ key.flags = WL_PRIMARY_KEY;
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ break;
+ default:
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ return -EINVAL;
+ }
+
+ /* Set the new key/index */
+ swap_key_from_BE(&key);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+
+ val = WEP_ENABLED;
+ if (unlikely((err = wl_dev_intvar_get(dev, "wsec", &wsec)))) {
+ WL_ERR(("get wsec error (%d)\n", err));
+ return err;
+ }
+ wsec &= ~(WEP_ENABLED);
+ wsec |= val;
+ if (unlikely((err = wl_dev_intvar_set(dev, "wsec", wsec)))) {
+ WL_ERR(("set wsec error (%d)\n", err));
+ return err;
+ }
+
+ val = 1; /* assume shared key. otherwise 0 */
+ val = htod32(val);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))) {
+ WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr)
+{
+ struct wl_wsec_key key;
+ int32 err = 0;
+ int32 val;
+ int32 wsec;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ memset(&key, 0, sizeof(key));
+
+ key.index = (uint32)key_idx;
+ key.flags = WL_PRIMARY_KEY;
+ key.algo = CRYPTO_ALGO_OFF;
+
+ WL_DBG(("key index (%d)\n", key_idx));
+ /* Set the new key/index */
+ swap_key_from_BE(&key);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))) {
+ if (err == -EINVAL) {
+ if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
+ /* we ignore this key index in this case */
+ WL_DBG(("invalid key index (%d)\n", key_idx));
+ }
+ } else {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ }
+ return err;
+ }
+
+ val = 0;
+ if (unlikely((err = wl_dev_intvar_get(dev, "wsec", &wsec)))) {
+ WL_ERR(("get wsec error (%d)\n", err));
+ return err;
+ }
+ wsec &= ~(WEP_ENABLED);
+ wsec |= val;
+ if (unlikely((err = wl_dev_intvar_set(dev, "wsec", wsec)))) {
+ WL_ERR(("set wsec error (%d)\n", err));
+ return err;
+ }
+
+ val = 0; /* assume open key. otherwise 1 */
+ val = htod32(val);
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))) {
+ WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ uint8 key_idx, const uint8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie, struct key_params *params))
+{
+ struct key_params params;
+ struct wl_wsec_key key;
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct wl_security *sec;
+ int32 wsec;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ WL_DBG(("key index (%d)\n", key_idx));
+ CHECK_SYS_UP();
+
+ memset(&key, 0, sizeof(key));
+ key.index = key_idx;
+ swap_key_to_BE(&key);
+ memset(&params, 0, sizeof(params));
+ params.key_len = (uint8)MIN(DOT11_MAX_KEY_SIZE, key.len);
+ memcpy(params.key, key.data, params.key_len);
+
+ if (unlikely(err = wl_dev_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec)))) {
+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ return err;
+ }
+ wsec = dtoh32(wsec);
+ switch (wsec) {
+ case WEP_ENABLED:
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ }
+ break;
+ case TKIP_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case AES_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ default:
+ WL_ERR(("Invalid algo (0x%x)\n", wsec));
+ return -EINVAL;
+ }
+
+ callback(cookie, &params);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev, uint8 key_idx)
+{
+ WL_INFO(("Not supported\n"));
+ CHECK_SYS_UP();
+ return -EOPNOTSUPP;
+}
+
+static int32
+wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ uint8 *mac, struct station_info *sinfo)
+
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ scb_val_t scb_val;
+ int rssi;
+ int32 rate;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ if (unlikely(memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) {
+ WL_ERR(("Wrong Mac address\n"));
+ return -ENOENT;
+ }
+
+ /* Report the current tx rate */
+ if ((err = wl_dev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate)))) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+ rate = dtoh32(rate);
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate/2)));
+ }
+
+ if (test_bit(WL_STATUS_CONNECTED, &wl->status)) {
+ scb_val.val = 0;
+ if (unlikely(err = wl_dev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ return err;
+ }
+ rssi = dtoh32(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, int32 timeout)
+{
+ int32 pm;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ pm = enabled ? PM_FAST : PM_OFF;
+ pm = htod32(pm);
+ WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))) {
+ if (err == -ENODEV) {
+ WL_DBG(("net_device is not ready yet\n"));
+ } else {
+ WL_ERR(("error (%d)\n", err));
+ }
+ return err;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static __used uint32
+wl_find_msb(uint16 bit16)
+{
+ uint32 ret = 0;
+
+ if (bit16 & 0xff00) {
+ ret += 8;
+ bit16 >>= 8;
+ }
+
+ if (bit16 & 0xf0) {
+ ret += 4;
+ bit16 >>= 4;
+ }
+
+ if (bit16 & 0xc) {
+ ret += 2;
+ bit16 >>= 2;
+ }
+
+ if (bit16 & 2)
+ ret += bit16 & 2;
+ else if (bit16)
+ ret += bit16;
+
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+static int32
+wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
+ const uint8 *addr, const struct cfg80211_bitrate_mask *mask)
+{
+ struct wl_rateset rateset;
+ int32 rate;
+ int32 val;
+ int32 err_bg;
+ int32 err_a;
+ uint32 legacy;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ /* addr param is always NULL. ignore it */
+ /* Get current rateset */
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
+ sizeof(rateset))))) {
+ WL_ERR(("could not get current rateset (%d)\n", err));
+ return err;
+ }
+
+ rateset.count = dtoh32(rateset.count);
+
+ if (!(legacy = wl_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy)))
+ legacy = wl_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy);
+
+ val = wl_g_rates[legacy-1].bitrate * 100000;
+
+ if (val < rateset.count) {
+ /* Select rate by rateset index */
+ rate = rateset.rates[val] & 0x7f;
+ } else {
+ /* Specified rate in bps */
+ rate = val / 500000;
+ }
+
+ WL_DBG(("rate %d mbps\n", (rate/2)));
+
+ /*
+ *
+ * Set rate override,
+ * Since the is a/b/g-blind, both a/bg_rate are enforced.
+ */
+ err_bg = wl_dev_intvar_set(dev, "bg_rate", rate);
+ err_a = wl_dev_intvar_set(dev, "a_rate", rate);
+ if (unlikely(err_bg && err_a)) {
+ WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a));
+ return (err_bg | err_a);
+ }
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+#else
+static int32
+wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
+ const uint8 *addr, const struct cfg80211_bitrate_mask *mask)
+{
+ struct wl_rateset rateset;
+ int32 rate;
+ int32 val;
+ int32 err_bg;
+ int32 err_a;
+ int32 err = 0;
+ int i;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ /* addr param is always NULL. ignore it */
+ /* Get current rateset */
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
+ sizeof(rateset))))) {
+ WL_ERR(("could not get current rateset (%d)\n", err));
+ return err;
+ }
+
+ rateset.count = dtoh32(rateset.count);
+
+ if (mask->fixed || mask->maxrate) {
+ val = mask->fixed ? (mask->fixed * 1000) : (mask->maxrate * 1000);
+ if (val < rateset.count) {
+ /* Select rate by rateset index */
+ rate = rateset.rates[val] & 0x7f;
+ } else {
+ /* Specified rate in bps */
+ rate = val / 500000;
+ }
+ } else {
+ /* Select maximum rate */
+ rate = rateset.rates[rateset.count - 1] & 0x7f;
+ }
+
+ if (mask->fixed) {
+ /*
+ Set rate override,
+ Since the is a/b/g-blind, both a/bg_rate are enforced.
+ */
+ err_bg = wl_dev_intvar_set(dev, "bg_rate", rate);
+ err_a = wl_dev_intvar_set(dev, "a_rate", rate);
+ if (unlikely(err_bg && err_a)) {
+ WL_ERR(("could not set fixed rate (%d) (%d)\n", err_bg, err_a));
+ return (err_bg | err_a);
+ }
+ } else {
+ /*
+ clear rate override
+ Since the is a/b/g-blind, both a/bg_rate are enforced.
+ */
+ /* 0 is for clearing rate override */
+ err_bg = wl_dev_intvar_set(dev, "bg_rate", 0);
+ /* 0 is for clearing rate override */
+ err_a = wl_dev_intvar_set(dev, "a_rate", 0);
+
+ if (unlikely(err_bg && err_a)) {
+ WL_ERR(("could not set max rate (%d) (%d)\n", err_bg, err_a));
+ return (err_bg | err_a);
+ }
+
+ /* Remove rates above selected rate */
+ for (i = 0; i < rateset.count; i++)
+ if ((rateset.rates[i] & 0x7f) > rate)
+ break;
+ rateset.count = htod32(i);
+
+ /* Set current rateset */
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_RATESET, &rateset,
+ sizeof(rateset))))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) */
+
+static int32
+wl_cfg80211_resume(struct wiphy *wiphy)
+{
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ wl_invoke_iscan(wiphy_to_wl(wiphy));
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_suspend(struct wiphy *wiphy)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+
+ set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ wl_term_iscan(wl);
+ if (wl->scan_request) {
+ cfg80211_scan_done(wl->scan_request, TRUE); /* TRUE means abort */
+ wl->scan_request = NULL;
+ }
+ clear_bit(WL_STATUS_SCANNING, &wl->status);
+ clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static __used int32
+wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, int32 err)
+{
+ int8 eabuf[ETHER_ADDR_STR_LEN];
+ int i, j;
+
+ memset(eabuf, 0, ETHER_ADDR_STR_LEN);
+
+ WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
+ for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
+ WL_DBG(("PMKID[%d]: %s =\n", i,
+ bcm_ether_ntoa(&pmk_list->pmkids.pmkid[i].BSSID,
+ eabuf)));
+ for (j = 0; j < WPA2_PMKID_LEN; j++) {
+ WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
+ }
+ }
+ if (likely(!err)) {
+ err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
+ sizeof(*pmk_list));
+ }
+
+ return err;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+static int32
+wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ int8 eabuf[ETHER_ADDR_STR_LEN];
+ int32 err = 0;
+ int i;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+
+ CHECK_SYS_UP();
+ memset(eabuf, 0, ETHER_ADDR_STR_LEN);
+ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
+ if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
+ ETHER_ADDR_LEN))
+ break;
+ if (i < WL_NUM_PMKIDS_MAX) {
+ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
+ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
+ if (i == wl->pmk_list->pmkids.npmkid)
+ wl->pmk_list->pmkids.npmkid++;
+ } else {
+ err = -EINVAL;
+ }
+ WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %s =\n",
+ bcm_ether_ntoa(&wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID,
+ eabuf)));
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
+ WL_DBG(("%02x\n",
+ wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].PMKID[i]));
+ }
+
+ err = wl_update_pmklist(dev, wl->pmk_list, err);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ int8 eabuf[ETHER_ADDR_STR_LEN];
+ struct _pmkid_list pmkid;
+ int32 err = 0;
+ int i;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+
+ CHECK_SYS_UP();
+ memset(eabuf, 0, ETHER_ADDR_STR_LEN);
+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
+ memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
+
+ WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %s =\n",
+ bcm_ether_ntoa(&pmkid.pmkid[0].BSSID, eabuf)));
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
+ WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
+ }
+
+ for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
+ if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN))
+ break;
+
+ if ((wl->pmk_list->pmkids.npmkid > 0) && (i < wl->pmk_list->pmkids.npmkid)) {
+ memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
+ for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) {
+ memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID,
+ &wl->pmk_list->pmkids.pmkid[i+1].BSSID, ETHER_ADDR_LEN);
+ memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID,
+ &wl->pmk_list->pmkids.pmkid[i+1].PMKID, WPA2_PMKID_LEN);
+ }
+ wl->pmk_list->pmkids.npmkid--;
+ }
+ else {
+ err = -EINVAL;
+ }
+
+ err = wl_update_pmklist(dev, wl->pmk_list, err);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+
+}
+
+static int32
+wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct wl_priv *wl = wiphy_to_wl(wiphy);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ CHECK_SYS_UP();
+ memset(wl->pmk_list, 0, sizeof(*wl->pmk_list));
+ err = wl_update_pmklist(dev, wl->pmk_list, err);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) */
+
+static struct cfg80211_ops wl_cfg80211_ops = {
+ .change_virtual_intf = wl_cfg80211_change_iface,
+ .scan = wl_cfg80211_scan,
+ .set_wiphy_params = wl_cfg80211_set_wiphy_params,
+ .join_ibss = wl_cfg80211_join_ibss,
+ .leave_ibss = wl_cfg80211_leave_ibss,
+ .get_station = wl_cfg80211_get_station,
+ .set_tx_power = wl_cfg80211_set_tx_power,
+ .get_tx_power = wl_cfg80211_get_tx_power,
+ .add_key = wl_cfg80211_add_key,
+ .del_key = wl_cfg80211_del_key,
+ .get_key = wl_cfg80211_get_key,
+ .set_default_key = wl_cfg80211_config_default_key,
+ .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
+ .set_power_mgmt = wl_cfg80211_set_power_mgmt,
+ .set_bitrate_mask = wl_cfg80211_set_bitrate_mask,
+ .connect = wl_cfg80211_connect,
+ .disconnect = wl_cfg80211_disconnect,
+ .suspend = wl_cfg80211_suspend,
+ .resume = wl_cfg80211_resume,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+ .set_pmksa = wl_cfg80211_set_pmksa,
+ .del_pmksa = wl_cfg80211_del_pmksa,
+ .flush_pmksa = wl_cfg80211_flush_pmksa
+#endif
+};
+
+static int32
+wl_mode_to_nl80211_iftype(int32 mode)
+{
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ switch (mode) {
+ case WL_MODE_BSS:
+ return NL80211_IFTYPE_STATION;
+ case WL_MODE_IBSS:
+ return NL80211_IFTYPE_ADHOC;
+ default:
+ return NL80211_IFTYPE_UNSPECIFIED;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static struct wireless_dev *
+wl_alloc_wdev(int32 sizeof_iface, struct device *dev)
+{
+ struct wireless_dev *wdev;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return ERR_PTR(-ENOMEM);
+ }
+ wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface);
+ if (unlikely(!wdev->wiphy)) {
+ WL_ERR(("Couldn not allocate wiphy device\n"));
+ err = -ENOMEM;
+ goto wiphy_new_out;
+ }
+ set_wiphy_dev(wdev->wiphy, dev);
+ wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#endif
+ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)| BIT(NL80211_IFTYPE_ADHOC);
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set it as 11a by default.
+ ** This will be updated with
+ ** 11n phy tables in "ifconfig up"
+ ** if phy has 11n capability
+ */
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = __wl_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+#ifndef WL_POWERSAVE_DISABLED
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
+ * save mode by default
+ */
+#else
+ wdev->wiphy->ps_default = TRUE; /* enable power save mode by default */
+#endif
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+ wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#else
+ wdev->wiphy->ps_default = FALSE;
+#endif
+#endif /* !WL_POWERSAVE_DISABLED */
+ if (unlikely(((err = wiphy_register(wdev->wiphy)) < 0))) {
+ WL_ERR(("Couldn not register wiphy device (%d)\n", err));
+ goto wiphy_register_out;
+ }
+ return wdev;
+
+wiphy_register_out:
+ wiphy_free(wdev->wiphy);
+
+wiphy_new_out:
+ kfree(wdev);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return ERR_PTR(err);
+}
+
+static void
+wl_free_wdev(struct wl_priv *wl)
+{
+ struct wireless_dev *wdev = wl_to_wdev(wl);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely(!wdev)) {
+ WL_ERR(("wdev is invalid\n"));
+ return;
+ }
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ wl_to_wdev(wl) = NULL;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+}
+
+static int32
+wl_inform_bss(struct wl_priv *wl)
+{
+ struct wl_scan_results *bss_list;
+ struct wl_bss_info *bi = NULL; /* must be initialized */
+ int32 err = 0;
+ int i;
+
+
+ bss_list = wl->bss_list;
+ if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) {
+ WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n", bss_list->version));
+ return -EOPNOTSUPP;
+ }
+ WL_DBG(("scanned AP count (%d)\n", bss_list->count));
+ bi = next_bss(bss_list, bi);
+ for_each_bss(bss_list, bi, i) {
+ if (unlikely(err = wl_inform_single_bss(wl, bi)))
+ break;
+ }
+ return err;
+}
+
+static int32
+wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
+{
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_channel *channel;
+ struct ieee80211_supported_band *band;
+ struct wl_cfg80211_bss_info *notif_bss_info;
+ struct wl_scan_req *sr = wl_to_sr(wl);
+ uint32 signal;
+ uint32 freq;
+ int32 err = 0;
+
+ if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
+ WL_DBG(("Beacon size is larger than allocated buffer. Discard it!!\n"));
+ return err;
+ }
+ notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt) - sizeof(uint8) +
+ WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (unlikely(!notif_bss_info)) {
+ WL_ERR(("notif_bss_info alloc failed\n"));
+ return -ENOMEM;
+ }
+ mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
+ notif_bss_info->channel = CHSPEC_CHANNEL(bi->chanspec);
+ if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ notif_bss_info->rssi = bi->RSSI;
+ memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
+ if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ }
+ mgmt->u.probe_resp.timestamp = 0;
+ mgmt->u.probe_resp.beacon_int = cpu_to_le16(bi->beacon_period);
+ mgmt->u.probe_resp.capab_info = cpu_to_le16(bi->capability);
+ wl_rst_ie(wl);
+ wl_add_ie(wl, WLAN_EID_SSID, bi->SSID_len, bi->SSID);
+ wl_add_ie(wl, WLAN_EID_SUPP_RATES, bi->rateset.count, bi->rateset.rates);
+ wl_mrg_ie(wl, ((uint8 *)bi) + bi->ie_offset, bi->ie_length);
+ wl_cp_ie(wl, mgmt->u.probe_resp.variable, WL_BSS_INFO_MAX -
+ offsetof(struct wl_cfg80211_bss_info, frame_buf));
+ notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt, u.probe_resp.variable) +
+ wl_get_ielen(wl);
+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
+ channel = ieee80211_get_channel(wiphy, freq);
+
+ WL_DBG(("SSID : \"%s\", rssi (%d), capability : 0x04%x\n", bi->SSID, notif_bss_info->rssi,
+ mgmt->u.probe_resp.capab_info));
+
+ signal = notif_bss_info->rssi * 100;
+ if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+ le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL))) {
+ WL_ERR(("cfg80211_inform_bss_frame error\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ kfree(notif_bss_info);
+
+ return err;
+}
+
+static bool
+wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e)
+{
+ uint32 event = ntoh32(e->event_type);
+ uint16 flags = ntoh16(e->flags);
+
+ if (event == WLC_E_JOIN || event == WLC_E_ASSOC_IND || event == WLC_E_REASSOC_IND) {
+ return TRUE;
+ } else if (event == WLC_E_LINK) {
+ if (flags & WLC_EVENT_MSG_LINK) {
+ if (wl_is_ibssmode(wl)) {
+ if (wl_is_ibssstarter(wl)) {
+ }
+ } else {
+
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static bool
+wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e)
+{
+ uint32 event = ntoh32(e->event_type);
+ uint16 flags = ntoh16(e->flags);
+
+ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
+ return TRUE;
+ } else if (event == WLC_E_LINK) {
+ if (!(flags & WLC_EVENT_MSG_LINK)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int32
+wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data)
+{
+ bool act;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (wl_is_linkup(wl, e)) {
+ wl_link_up(wl);
+ if (wl_is_ibssmode(wl)) {
+ cfg80211_ibss_joined(ndev, (int8 *)&e->addr, GFP_KERNEL);
+ WL_DBG(("joined in IBSS network\n"));
+ } else {
+ wl_bss_connect_done(wl, ndev, e, data);
+ WL_DBG(("joined in BSS network \"%s\"\n",
+ ((struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID))->SSID));
+ }
+ act = TRUE;
+ wl_update_prof(wl, e, &act, WL_PROF_ACT);
+ } else if (wl_is_linkdown(wl, e)) {
+ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+ clear_bit(WL_STATUS_CONNECTED, &wl->status);
+ wl_link_down(wl);
+ wl_init_prof(wl->profile);
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data)
+{
+ bool act;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl_bss_roaming_done(wl, ndev, e, data);
+ act = TRUE;
+ wl_update_prof(wl, e, &act, WL_PROF_ACT);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static __used int32
+wl_dev_bufvar_set(struct net_device *dev, int8 *name, int8 *buf, int32 len)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ uint32 buflen;
+
+ buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
+ BUG_ON(unlikely(!buflen));
+
+ return (wl_dev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen));
+}
+
+static int32
+wl_dev_bufvar_get(struct net_device *dev, int8 *name, int8 *buf, int32 buf_len)
+{
+ struct wl_priv *wl = ndev_to_wl(dev);
+ uint32 len;
+ int32 err = 0;
+
+ len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
+ BUG_ON(unlikely(!len));
+ if (unlikely((err = wl_dev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
+ WL_IOCTL_LEN_MAX)))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ memcpy(buf, wl->ioctl_buf, buf_len);
+
+ return err;
+}
+
+static int32
+wl_get_assoc_ies(struct wl_priv *wl)
+{
+ struct net_device *ndev = wl_to_ndev(wl);
+ struct wl_assoc_ielen *assoc_info;
+ struct wl_connect_info *conn_info = wl_to_conn(wl);
+ uint32 req_len;
+ uint32 resp_len;
+ int32 err = 0;
+
+ if (unlikely(err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
+ WL_ASSOC_INFO_MAX))) {
+ WL_ERR(("could not get assoc info (%d)\n", err));
+ return err;
+ }
+ assoc_info = (struct wl_assoc_ielen *)wl->extra_buf;
+ req_len = assoc_info->req_len;
+ resp_len = assoc_info->resp_len;
+ if (req_len) {
+ if (unlikely(err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
+ WL_ASSOC_INFO_MAX))) {
+ WL_ERR(("could not get assoc req (%d)\n", err));
+ return err;
+ }
+ conn_info->req_ie_len = req_len;
+ conn_info->req_ie = kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL);
+ } else {
+ conn_info->req_ie_len = 0;
+ conn_info->req_ie = NULL;
+ }
+ if (resp_len) {
+ if (unlikely(err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
+ WL_ASSOC_INFO_MAX))) {
+ WL_ERR(("could not get assoc resp (%d)\n", err));
+ return err;
+ }
+ conn_info->resp_ie_len = resp_len;
+ conn_info->resp_ie = kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL);
+ } else {
+ conn_info->resp_ie_len = 0;
+ conn_info->resp_ie = NULL;
+ }
+ WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, conn_info->resp_ie_len));
+
+ return err;
+}
+
+static int32
+wl_update_bss_info(struct wl_priv *wl)
+{
+ struct cfg80211_bss *bss;
+ struct wl_bss_info *bi;
+ struct wlc_ssid *ssid;
+ int32 err = 0;
+
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (wl_is_ibssmode(wl))
+ return err;
+
+ ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
+ bss = cfg80211_get_bss(wl_to_wiphy(wl), NULL, (int8 *)&wl->bssid, ssid->SSID,
+ ssid->SSID_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+
+ rtnl_lock();
+ if (unlikely(!bss)) {
+ WL_DBG(("Could not find the AP\n"));
+ *(uint32*)wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ if (unlikely(err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_BSS_INFO, wl->extra_buf,
+ WL_EXTRA_BUF_MAX))) {
+ WL_ERR(("Could not get bss info %d\n", err));
+ goto update_bss_info_out;
+ }
+ bi = (struct wl_bss_info *)(wl->extra_buf + 4);
+ if (unlikely(memcmp(&bi->BSSID, &wl->bssid, ETHER_ADDR_LEN))) {
+ err = -EIO;
+ goto update_bss_info_out;
+ }
+ if (unlikely((err = wl_inform_single_bss(wl, bi))))
+ goto update_bss_info_out;
+ } else {
+ WL_DBG(("Found the AP in the list - BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bss->bssid[0], bss->bssid[1], bss->bssid[2], bss->bssid[3],
+ bss->bssid[4], bss->bssid[5]));
+ cfg80211_put_bss(bss);
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+update_bss_info_out:
+ rtnl_unlock();
+ return err;
+}
+
+static int32
+wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(wl);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl_get_assoc_ies(wl);
+ memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ wl_update_bss_info(wl);
+ cfg80211_roamed(ndev,
+ (uint8 *)&wl->bssid,
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len,
+ GFP_KERNEL);
+ WL_DBG(("Report roaming result\n"));
+
+ set_bit(WL_STATUS_CONNECTED, &wl->status);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(wl);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl_get_assoc_ies(wl);
+ memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ wl_update_bss_info(wl);
+ if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) {
+ cfg80211_connect_result(ndev,
+ (uint8 *)&wl->bssid,
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len,
+ WLAN_STATUS_SUCCESS,
+ GFP_KERNEL);
+ WL_DBG(("Report connect result\n"));
+ } else {
+ cfg80211_roamed(ndev,
+ (uint8 *)&wl->bssid,
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len,
+ GFP_KERNEL);
+ WL_DBG(("Report roaming result\n"));
+ }
+ set_bit(WL_STATUS_CONNECTED, &wl->status);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data)
+{
+ uint16 flags = ntoh16(e->flags);
+ enum nl80211_key_type key_type;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+
+ rtnl_lock();
+ if (flags & WLC_EVENT_MSG_GROUP)
+ key_type = NL80211_KEYTYPE_GROUP;
+ else
+ key_type = NL80211_KEYTYPE_PAIRWISE;
+
+ cfg80211_michael_mic_failure(ndev, (uint8 *)&e->addr, key_type, -1, NULL, GFP_KERNEL);
+ rtnl_unlock();
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return 0;
+}
+
+static int32
+wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void* data)
+{
+ struct channel_info channel_inform;
+ struct wl_scan_results *bss_list;
+ uint32 len = WL_SCAN_BUF_MAX;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+
+ if (wl->iscan_on && wl->iscan_kickstart)
+ return wl_wakeup_iscan(wl_to_iscan(wl));
+
+ if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
+ WL_ERR(("Scan complete while device not scanning\n"));
+ return -EINVAL;
+ }
+ if (unlikely(!wl->scan_request)) {
+ }
+ rtnl_lock();
+ if (unlikely((err = wl_dev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
+ sizeof(channel_inform))))) {
+ WL_ERR(("scan busy (%d)\n", err));
+ goto scan_done_out;
+ }
+ channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
+ if (unlikely(channel_inform.scan_channel)) {
+
+ WL_DBG(("channel_inform.scan_channel (%d)\n", channel_inform.scan_channel));
+ }
+ wl->bss_list = wl->scan_results;
+ bss_list = wl->bss_list;
+ memset(bss_list, 0, len);
+ bss_list->buflen = htod32(len);
+ if (unlikely((err = wl_dev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len)))) {
+ WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
+ err = -EINVAL;
+ goto scan_done_out;
+ }
+ bss_list->buflen = dtoh32(bss_list->buflen);
+ bss_list->version = dtoh32(bss_list->version);
+ bss_list->count = dtoh32(bss_list->count);
+
+ if ((err = wl_inform_bss(wl))) {
+ goto scan_done_out;
+ }
+
+scan_done_out :
+ if (wl->scan_request) {
+ cfg80211_scan_done(wl->scan_request, FALSE);
+ wl->scan_request = NULL;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ rtnl_unlock();
+ return err;
+}
+
+static void
+wl_init_conf(struct wl_conf *conf)
+{
+ conf->mode = (uint32)-1;
+ conf->frag_threshold = (uint32)-1;
+ conf->rts_threshold = (uint32)-1;
+ conf->retry_short = (uint32)-1;
+ conf->retry_long = (uint32)-1;
+ conf->tx_power = -1;
+}
+
+static void
+wl_init_prof(struct wl_profile *prof)
+{
+ memset(prof, 0, sizeof(*prof));
+}
+
+static void
+wl_init_eloop_handler(struct wl_event_loop *el)
+{
+ memset(el, 0, sizeof(*el));
+ el->handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
+ el->handler[WLC_E_JOIN] = wl_notify_connect_status;
+ el->handler[WLC_E_LINK] = wl_notify_connect_status;
+ el->handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
+ el->handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
+ el->handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
+ el->handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
+ el->handler[WLC_E_ROAM] = wl_notify_roaming_status;
+ el->handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
+}
+
+static int32
+wl_init_priv_mem(struct wl_priv *wl)
+{
+ wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
+ if (unlikely(!wl->scan_results)) {
+ WL_ERR(("Scan results alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL);
+ if (unlikely(!wl->conf)) {
+ WL_ERR(("wl_conf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
+ if (unlikely(!wl->profile)) {
+ WL_ERR(("wl_profile alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (unlikely(!wl->bss_info)) {
+ WL_ERR(("Bss information alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->scan_req_int = (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
+ if (unlikely(!wl->scan_req_int)) {
+ WL_ERR(("Scan req alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+ if (unlikely(!wl->ioctl_buf)) {
+ WL_ERR(("Ioctl buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (unlikely(!wl->extra_buf)) {
+ WL_ERR(("Extra buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
+ if (unlikely(!wl->iscan)) {
+ WL_ERR(("Iscan buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
+ if (unlikely(!wl->fw)) {
+ WL_ERR(("fw object alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
+ if (unlikely(!wl->pmk_list)) {
+ WL_ERR(("pmk list alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+
+ return 0;
+
+init_priv_mem_out:
+ wl_deinit_priv_mem(wl);
+
+ return -ENOMEM;
+}
+
+static void
+wl_deinit_priv_mem(struct wl_priv *wl)
+{
+ if (wl->scan_results) {
+ kfree(wl->scan_results);
+ wl->scan_results = NULL;
+ }
+ if (wl->bss_info) {
+ kfree(wl->bss_info);
+ wl->bss_info = NULL;
+ }
+ if (wl->conf) {
+ kfree(wl->conf);
+ wl->conf = NULL;
+ }
+ if (wl->profile) {
+ kfree(wl->profile);
+ wl->profile = NULL;
+ }
+ if (wl->scan_req_int) {
+ kfree(wl->scan_req_int);
+ wl->scan_req_int = NULL;
+ }
+ if (wl->ioctl_buf) {
+ kfree(wl->ioctl_buf);
+ wl->ioctl_buf = NULL;
+ }
+ if (wl->extra_buf) {
+ kfree(wl->extra_buf);
+ wl->extra_buf = NULL;
+ }
+ if (wl->iscan) {
+ kfree(wl->iscan);
+ wl->iscan = NULL;
+ }
+ if (wl->fw) {
+ kfree(wl->fw);
+ wl->fw = NULL;
+ }
+ if (wl->pmk_list) {
+ kfree(wl->pmk_list);
+ wl->pmk_list = NULL;
+ }
+}
+
+
+static int32
+wl_create_event_handler(struct wl_priv *wl)
+{
+ sema_init(&wl->event_sync, 0);
+ init_completion(&wl->event_exit);
+ if (unlikely(((wl->event_pid = kernel_thread(wl_event_handler, wl, 0)) < 0))) {
+ WL_ERR(("failed to create event thread\n"));
+ return -ENOMEM;
+ }
+ WL_DBG(("pid %d\n", wl->event_pid));
+ return 0;
+}
+
+static void
+wl_destroy_event_handler(struct wl_priv *wl)
+{
+ if (wl->event_pid >= 0) {
+ KILL_PROC(wl->event_pid, SIGTERM);
+ wait_for_completion(&wl->event_exit);
+ }
+}
+
+static void
+wl_term_iscan(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
+
+ if (wl->iscan_on && iscan->pid >= 0) {
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ KILL_PROC(iscan->pid, SIGTERM);
+ wait_for_completion(&iscan->exited);
+ iscan->pid = -1;
+ }
+}
+
+static void
+wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
+{
+ struct wl_priv *wl = iscan_to_wl(iscan);
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
+ WL_ERR(("Scan complete while device not scanning\n"));
+ return;
+ }
+ if (likely(wl->scan_request)) {
+ cfg80211_scan_done(wl->scan_request, aborted);
+ wl->scan_request = NULL;
+ }
+ wl->iscan_kickstart = FALSE;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+}
+
+static int32
+wl_wakeup_iscan(struct wl_iscan_ctrl *iscan)
+{
+ if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) {
+ WL_DBG(("wake up iscan\n"));
+ up(&iscan->sync);
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static int32
+wl_get_iscan_results(struct wl_iscan_ctrl *iscan, uint32 *status, struct wl_scan_results **bss_list)
+{
+ struct wl_iscan_results list;
+ struct wl_scan_results *results;
+ struct wl_iscan_results *list_buf;
+ int32 err = 0;
+
+ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
+ list_buf = (struct wl_iscan_results *)iscan->scan_buf;
+ results = &list_buf->results;
+ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
+ results->version = 0;
+ results->count = 0;
+
+ memset(&list, 0, sizeof(list));
+ list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
+ if (unlikely((err = wl_dev_iovar_getbuf(
+ iscan->dev,
+ "iscanresults",
+ &list,
+ WL_ISCAN_RESULTS_FIXED_SIZE,
+ iscan->scan_buf,
+ WL_ISCAN_BUF_MAX)))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ results->count = dtoh32(results->count);
+ WL_DBG(("results->count = %d\n", results->count));
+ WL_DBG(("results->buflen = %d\n", results->buflen));
+ *status = dtoh32(list_buf->status);
+ *bss_list = results;
+
+ return err;
+}
+
+static int32
+wl_iscan_done(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl->iscan;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ rtnl_lock();
+ wl_inform_bss(wl);
+ wl_notify_iscan_complete(iscan, FALSE);
+ rtnl_unlock();
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_iscan_pending(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl->iscan;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ /* Reschedule the timer */
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
+ iscan->timer_on = 1;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_iscan_inprogress(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl->iscan;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ rtnl_lock();
+ wl_inform_bss(wl);
+ wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
+ rtnl_unlock();
+ /* Reschedule the timer */
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
+ iscan->timer_on = 1;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_iscan_aborted(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl->iscan;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ rtnl_lock();
+ wl_notify_iscan_complete(iscan, TRUE);
+ rtnl_unlock();
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_iscan_thread(void *data)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
+ struct wl_priv *wl = iscan_to_wl(iscan);
+ struct wl_iscan_eloop *el = &iscan->el;
+ uint32 status;
+ int err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ sched_setscheduler(current, SCHED_FIFO, &param);
+ status = WL_SCAN_RESULTS_PARTIAL;
+ while (likely(!down_interruptible(&iscan->sync))) {
+ if (iscan->timer_on) {
+ del_timer_sync(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+ rtnl_lock();
+ if (unlikely((err = wl_get_iscan_results(iscan, &status, &wl->bss_list)))) {
+ status = WL_SCAN_RESULTS_ABORTED;
+ WL_ERR(("Abort iscan\n"));
+ }
+ rtnl_unlock();
+ el->handler[status](wl);
+ }
+ if (iscan->timer_on) {
+ del_timer_sync(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+ complete_and_exit(&iscan->exited, 0);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return 0;
+}
+
+static void
+wl_iscan_timer(ulong data)
+{
+ struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
+
+ if (iscan) {
+ iscan->timer_on = 0;
+ WL_DBG(("timer expired\n"));
+ wl_wakeup_iscan(iscan);
+ }
+}
+
+static int32
+wl_invoke_iscan(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
+ int err = 0;
+
+ if (wl->iscan_on && iscan->pid < 0) {
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ sema_init(&iscan->sync, 0);
+ init_completion(&iscan->exited);
+ iscan->pid = kernel_thread(wl_iscan_thread, iscan, 0);
+ if (unlikely(iscan->pid < 0)) {
+ WL_ERR(("Could not create iscan thread\n"));
+ return -ENOMEM;
+ }
+ }
+
+ return err;
+}
+
+static void
+wl_init_iscan_eloop(struct wl_iscan_eloop *el)
+{
+ memset(el, 0, sizeof(*el));
+ el->handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done;
+ el->handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress;
+ el->handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending;
+ el->handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted;
+ el->handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
+}
+
+static int32
+wl_init_iscan(struct wl_priv *wl)
+{
+ struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
+ int err = 0;
+
+ if (wl->iscan_on) {
+ iscan->dev = wl_to_ndev(wl);
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ wl_init_iscan_eloop(&iscan->el);
+ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
+ init_timer(&iscan->timer);
+ iscan->timer.data = (ulong)iscan;
+ iscan->timer.function = wl_iscan_timer;
+ sema_init(&iscan->sync, 0);
+ init_completion(&iscan->exited);
+ iscan->pid = kernel_thread(wl_iscan_thread, iscan, 0);
+ if (unlikely(iscan->pid < 0)) {
+ WL_ERR(("Could not create iscan thread\n"));
+ return -ENOMEM;
+ }
+ iscan->data = wl;
+ }
+
+ return err;
+}
+
+static void
+wl_init_fw(struct wl_fw_ctrl *fw)
+{
+ fw->status = 0; /* init fw loading status. 0 means nothing was loaded yet */
+}
+
+static int32
+wl_init_priv(struct wl_priv *wl)
+{
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl->scan_request = NULL;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) || \
+ defined(CHROMIUMOS_COMPAT_WIRELESS)
+ wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
+#else
+ wl->pwr_save = wiphy->ps_default;
+#endif
+#ifndef WL_ISCAN_DISABLED
+ wl->iscan_on = TRUE; /* iscan on & off switch. we enable iscan per default */
+#else
+ wl->iscan_on = FALSE;
+#endif /* WL_ISCAN_DISABLED */
+#ifndef WL_ROAM_DISABLED
+ wl->roam_on = TRUE; /* roam on & off switch. we enable roam per default */
+#else
+ wl->roam_on = FALSE;
+#endif /* WL_ROAM_DISABLED */
+
+ wl->iscan_kickstart = FALSE;
+ wl->active_scan = TRUE; /* we do active scan for specific scan per default */
+ wl->dongle_up = FALSE; /* dongle is not up yet */
+ wl_init_eq(wl);
+ if (unlikely((err = wl_init_priv_mem(wl))))
+ return err;
+ if (unlikely(wl_create_event_handler(wl)))
+ return -ENOMEM;
+ wl_init_eloop_handler(&wl->el);
+ mutex_init(&wl->usr_sync);
+ if (unlikely((err = wl_init_iscan(wl))))
+ return err;
+ wl_init_fw(wl->fw);
+ wl_init_conf(wl->conf);
+ wl_init_prof(wl->profile);
+ wl_link_down(wl);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static void
+wl_deinit_priv(struct wl_priv *wl)
+{
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl_destroy_event_handler(wl);
+ wl->dongle_up = FALSE; /* dongle down */
+ wl_flush_eq(wl);
+ wl_link_down(wl);
+ wl_term_iscan(wl);
+ wl_deinit_priv_mem(wl);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+}
+
+int32
+wl_cfg80211_attach(struct net_device *ndev, void *data)
+{
+ struct wireless_dev *wdev;
+ struct wl_priv *wl;
+ struct wl_iface *ci;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely(!ndev)) {
+ WL_ERR(("ndev is invaild\n"));
+ return -ENODEV;
+ }
+ wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL);
+ if (unlikely(!wl_cfg80211_dev)) {
+ WL_ERR(("wl_cfg80211_dev is invalid\n"));
+ return -ENOMEM;
+ }
+ WL_DBG(("func %p\n", wl_sdio_func()));
+#ifndef WL_CFG80211_LOCALTEST
+ wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_sdio_func()->dev);
+#else
+ wdev = wl_alloc_wdev(sizeof(struct wl_iface), NULL);
+#endif
+ if (unlikely(IS_ERR(wdev)))
+ return -ENOMEM;
+
+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+ wl = wdev_to_wl(wdev);
+ wl->wdev = wdev;
+ wl->pub = data;
+ ci = (struct wl_iface *)wl_to_ci(wl);
+ ci->wl = wl;
+ ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
+ wdev->netdev = ndev;
+ if (unlikely((err = wl_init_priv(wl)))) {
+ WL_ERR(("Failed to init iwm_priv (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
+ wl_set_drvdata(wl_cfg80211_dev, ci);
+ set_bit(WL_STATUS_READY, &wl->status);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+
+cfg80211_attach_out:
+ wl_free_wdev(wl);
+ return err;
+}
+
+void
+wl_cfg80211_detach(void)
+{
+ struct wl_priv *wl;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl = WL_PRIV_GET();
+
+ wl_deinit_priv(wl);
+ wl_free_wdev(wl);
+ wl_set_drvdata(wl_cfg80211_dev, NULL);
+ kfree(wl_cfg80211_dev);
+ wl_cfg80211_dev = NULL;
+ wl_clear_sdio_func();
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+}
+
+static void
+wl_wakeup_event(struct wl_priv *wl)
+{
+ up(&wl->event_sync);
+}
+
+static int32
+wl_event_handler(void *data)
+{
+ struct wl_priv *wl = (struct wl_priv *)data;
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+ struct wl_event_q *e;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ sched_setscheduler(current, SCHED_FIFO, &param);
+ while (likely(!down_interruptible(&wl->event_sync))) {
+ if (unlikely(!(e = wl_deq_event(wl)))) {
+ WL_ERR(("eqeue empty..\n"));
+ BUG();
+ }
+ WL_DBG(("event type (%d)\n", e->etype));
+ if (wl->el.handler[e->etype]) {
+ wl->el.handler[e->etype](wl, wl_to_ndev(wl), &e->emsg, e->edata);
+ } else {
+ WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
+ }
+ wl_put_event(e);
+ }
+ complete_and_exit(&wl->event_exit, 0);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+}
+
+void
+wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void* data)
+{
+ uint32 event_type = ntoh32(e->event_type);
+ struct wl_priv *wl = ndev_to_wl(ndev);
+#if (WL_DBG_LEVEL > 0)
+ int8 *estr = (event_type <= sizeof(wl_dbg_estr)/WL_DBG_ESTR_MAX-1) ?
+ wl_dbg_estr[event_type] : (int8 *)"Unknown";
+#endif /* (WL_DBG_LEVEL > 0) */
+ WL_DBG(("event_type (%d):""WLC_E_""%s\n", event_type, estr));
+ if (likely(!wl_enq_event(wl, event_type, e, data)))
+ wl_wakeup_event(wl);
+}
+
+static void
+wl_init_eq(struct wl_priv *wl)
+{
+ wl_init_eq_lock(wl);
+ INIT_LIST_HEAD(&wl->eq_list);
+}
+
+static void
+wl_flush_eq(struct wl_priv *wl)
+{
+ struct wl_event_q *e;
+
+ wl_lock_eq(wl);
+ while (!list_empty(&wl->eq_list)) {
+ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
+ list_del(&e->eq_list);
+ kfree(e);
+ }
+ wl_unlock_eq(wl);
+}
+
+/*
+* retrieve first queued event from head
+*/
+
+static struct wl_event_q *
+wl_deq_event(struct wl_priv *wl)
+{
+ struct wl_event_q *e = NULL;
+
+ wl_lock_eq(wl);
+ if (likely(!list_empty(&wl->eq_list))) {
+ e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
+ list_del(&e->eq_list);
+ }
+ wl_unlock_eq(wl);
+
+ return e;
+}
+
+/*
+** push event to tail of the queue
+*/
+
+static int32
+wl_enq_event(struct wl_priv *wl, uint32 event, const wl_event_msg_t *msg, void *data)
+{
+ struct wl_event_q *e;
+ int32 err = 0;
+
+ if (unlikely(!(e = kzalloc(sizeof(struct wl_event_q), GFP_KERNEL)))) {
+ WL_ERR(("event alloc failed\n"));
+ return -ENOMEM;
+ }
+
+ e->etype = event;
+ memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
+ if (data) {
+ }
+ wl_lock_eq(wl);
+ list_add_tail(&e->eq_list, &wl->eq_list);
+ wl_unlock_eq(wl);
+
+ return err;
+}
+
+static void
+wl_put_event(struct wl_event_q *e)
+{
+ kfree(e);
+}
+
+void
+wl_cfg80211_sdio_func(void *func)
+{
+ cfg80211_sdio_func = (struct sdio_func *)func;
+}
+
+static void
+wl_clear_sdio_func(void)
+{
+ cfg80211_sdio_func = NULL;
+}
+
+
+static struct sdio_func *
+wl_sdio_func(void)
+{
+ return cfg80211_sdio_func;
+}
+
+static int32
+wl_dongle_mode(struct net_device *ndev, int32 iftype)
+{
+ int32 infra = 0;
+ int32 ap = 0;
+ int32 err = 0;
+
+ switch (iftype) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ WL_ERR(("type (%d) : currently we do not support this mode\n", iftype));
+ err = -EINVAL;
+ return err;
+ case NL80211_IFTYPE_ADHOC:
+ break;
+ case NL80211_IFTYPE_STATION:
+ infra = 1;
+ break;
+ default:
+ err = -EINVAL;
+ WL_ERR(("invalid type (%d)\n", iftype));
+ return err;
+ }
+ infra = htod32(infra);
+ ap = htod32(ap);
+ WL_DBG(("%s ap (%d), infra (%d)\n", ndev->name, ap, infra));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
+ unlikely(err = wl_dev_ioctl(ndev, WLC_SET_AP, &ap, sizeof(ap)))) {
+ WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+ return err;
+ }
+
+ return -EINPROGRESS;
+}
+
+#ifndef EMBEDDED_PLATFORM
+static int32
+wl_dongle_country(struct net_device *ndev, uint8 ccode)
+{
+
+ int32 err = 0;
+
+
+ return err;
+}
+
+static int32
+wl_dongle_up(struct net_device *ndev, uint32 up)
+{
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_UP, &up, sizeof(up)))) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return err;
+}
+
+static int32
+wl_dongle_power(struct net_device *ndev, uint32 power_mode)
+{
+ int32 err = 0;
+
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode)))) {
+ WL_ERR(("WLC_SET_PM error (%d)\n", err));
+ }
+ return err;
+}
+
+static int32
+wl_dongle_glom(struct net_device *ndev, uint32 glom, uint32 dongle_align)
+{
+ int8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ int32 err = 0;
+
+ /* Match Host and Dongle rx alignment */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ WL_ERR(("txglomalign error (%d)\n", err));
+ goto dongle_glom_out;
+ }
+ /* disable glom option per default */
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ WL_ERR(("txglom error (%d)\n", err));
+ goto dongle_glom_out;
+ }
+dongle_glom_out :
+ return err;
+}
+
+static int32
+wl_dongle_roam(struct net_device *ndev, uint32 roamvar, uint32 bcn_timeout)
+{
+ int8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ int32 err = 0;
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ if (roamvar) {
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ WL_ERR(("bcn_timeout error (%d)\n", err));
+ goto dongle_rom_out;
+ }
+ }
+ /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ WL_ERR(("roam_off error (%d)\n", err));
+ goto dongle_rom_out;
+ }
+dongle_rom_out :
+ return err;
+}
+
+static int32
+wl_dongle_eventmsg(struct net_device *ndev)
+{
+
+ int8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ int8 eventmask[WL_EVENTING_MASK_LEN];
+ int32 err = 0;
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf)))) {
+ WL_ERR(("Get event_msgs error (%d)\n", err));
+ goto dongle_eventmsg_out;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+
+ setbit(eventmask, WLC_E_SET_SSID);
+ setbit(eventmask, WLC_E_PRUNE);
+ setbit(eventmask, WLC_E_AUTH);
+ setbit(eventmask, WLC_E_REASSOC);
+ setbit(eventmask, WLC_E_REASSOC_IND);
+ setbit(eventmask, WLC_E_DEAUTH_IND);
+ setbit(eventmask, WLC_E_DISASSOC_IND);
+ setbit(eventmask, WLC_E_DISASSOC);
+ setbit(eventmask, WLC_E_JOIN);
+ setbit(eventmask, WLC_E_ASSOC_IND);
+ setbit(eventmask, WLC_E_PSK_SUP);
+ setbit(eventmask, WLC_E_LINK);
+ setbit(eventmask, WLC_E_NDIS_LINK);
+ setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_PMKID_CACHE);
+ setbit(eventmask, WLC_E_TXFAIL);
+ setbit(eventmask, WLC_E_JOIN_START);
+ setbit(eventmask, WLC_E_SCAN_COMPLETE);
+
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if (unlikely(err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ WL_ERR(("Set event_msgs error (%d)\n", err));
+ goto dongle_eventmsg_out;
+ }
+
+dongle_eventmsg_out :
+ return err;
+}
+
+static int32
+wl_dongle_scantime(struct net_device *ndev, int32 scan_assoc_time, int32 scan_unassoc_time)
+{
+ int32 err = 0;
+
+ if ((err = wl_dev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
+ sizeof(scan_assoc_time)))) {
+ if (err == -EOPNOTSUPP) {
+ WL_INFO(("Scan assoc time is not supported\n"));
+ } else {
+ WL_ERR(("Scan assoc time error (%d)\n", err));
+ }
+ goto dongle_scantime_out;
+ }
+ if ((err = wl_dev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
+ sizeof(scan_unassoc_time)))) {
+ if (err == -EOPNOTSUPP) {
+ WL_INFO(("Scan unassoc time is not supported\n"));
+ } else {
+ WL_ERR(("Scan unassoc time error (%d)\n", err));
+ }
+ goto dongle_scantime_out;
+ }
+
+dongle_scantime_out :
+ return err;
+}
+
+static int32
+wl_dongle_offload(struct net_device *ndev, int32 arpoe, int32 arp_ol)
+{
+ int8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ int32 err = 0;
+
+ /* Set ARP offload */
+ bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
+ if ((err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ if (err == -EOPNOTSUPP) {
+ WL_INFO(("arpoe is not supported\n"));
+ } else {
+ WL_ERR(("arpoe error (%d)\n", err));
+ }
+ goto dongle_offload_out;
+ }
+ bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
+ if ((err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ if (err == -EOPNOTSUPP) {
+ WL_INFO(("arp_ol is not supported\n"));
+ } else {
+ WL_ERR(("arp_ol error (%d)\n", err));
+ }
+ goto dongle_offload_out;
+ }
+
+dongle_offload_out :
+ return err;
+}
+
+static int32
+wl_pattern_atoh(int8 *src, int8 *dst)
+{
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+ int i;
+ if (strncmp(src, "0x", 2) != 0 &&
+ strncmp(src, "0X", 2) != 0) {
+ WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
+ return -1;
+ }
+ src = src + 2; /* Skip past 0x */
+ if (strlen(src) % 2 != 0) {
+ WL_ERR(("Mask invalid format. Needs to be of even length\n"));
+ return -1;
+ }
+ for (i = 0; *src != '\0'; i++) {
+ char num[3];
+ strncpy(num, src, 2);
+ num[2] = '\0';
+ dst[i] = (uint8)strtoul(num, NULL, 16);
+ src += 2;
+ }
+ return i;
+}
+
+static int32
+wl_dongle_filter(struct net_device *ndev, uint32 filter_mode)
+{
+ int8 iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ const int8 *str;
+ struct wl_pkt_filter pkt_filter;
+ struct wl_pkt_filter *pkt_filterp;
+ int32 buf_len;
+ int32 str_len;
+ uint32 mask_size;
+ uint32 pattern_size;
+ int8 buf[256];
+ int32 err = 0;
+
+/* add a default packet filter pattern */
+ str = "pkt_filter_add";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+ buf_len = str_len + 1;
+
+ pkt_filterp = (struct wl_pkt_filter *) (buf + str_len + 1);
+
+ /* Parse packet filter id. */
+ pkt_filter.id = htod32(100);
+
+ /* Parse filter polarity. */
+ pkt_filter.negate_match = htod32(0);
+
+ /* Parse filter type. */
+ pkt_filter.type = htod32(0);
+
+ /* Parse pattern filter offset. */
+ pkt_filter.u.pattern.offset = htod32(0);
+
+ /* Parse pattern filter mask. */
+ mask_size = htod32(wl_pattern_atoh("0xff",
+ (char *) pkt_filterp->u.pattern.mask_and_pattern));
+
+ /* Parse pattern filter pattern. */
+ pattern_size = htod32(wl_pattern_atoh("0x00",
+ (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
+
+ if (mask_size != pattern_size) {
+ WL_ERR(("Mask and pattern not the same size\n"));
+ err = -EINVAL;
+ goto dongle_filter_out;
+ }
+
+ pkt_filter.u.pattern.size_bytes = mask_size;
+ buf_len += WL_PKT_FILTER_FIXED_LEN;
+ buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
+
+ /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
+ ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
+ ** guarantee that the buffer is properly aligned.
+ */
+ memcpy((char *)pkt_filterp, &pkt_filter,
+ WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
+
+ if ((err = wl_dev_ioctl(ndev, WLC_SET_VAR, buf, buf_len))) {
+ if (err == -EOPNOTSUPP) {
+ WL_INFO(("filter not supported\n"));
+ } else {
+ WL_ERR(("filter (%d)\n", err));
+ }
+ goto dongle_filter_out;
+ }
+
+ /* set mode to allow pattern */
+ bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, sizeof(iovbuf));
+ if ((err = wl_dev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf)))) {
+ if (err == -EOPNOTSUPP) {
+ WL_INFO(("filter_mode not supported\n"));
+ } else {
+ WL_ERR(("filter_mode (%d)\n", err));
+ }
+ goto dongle_filter_out;
+ }
+
+dongle_filter_out :
+ return err;
+}
+#endif /* !EMBEDDED_PLATFORM */
+
+int32
+wl_config_dongle(struct wl_priv *wl, bool need_lock)
+{
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN 32
+#endif
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (wl->dongle_up)
+ return err;
+
+
+ ndev = wl_to_ndev(wl);
+ wdev = ndev->ieee80211_ptr;
+ if (need_lock)
+ rtnl_lock();
+
+#ifndef EMBEDDED_PLATFORM
+ if (unlikely((err = wl_dongle_up(ndev, 0))))
+ goto default_conf_out;
+ if (unlikely((err = wl_dongle_country(ndev, 0))))
+ goto default_conf_out;
+ if (unlikely((err = wl_dongle_power(ndev, PM_FAST))))
+ goto default_conf_out;
+ if (unlikely((err = wl_dongle_glom(ndev, 0, DHD_SDALIGN))))
+ goto default_conf_out;
+ if (unlikely((err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3))))
+ goto default_conf_out;
+ if (unlikely((err = wl_dongle_eventmsg(ndev))))
+ goto default_conf_out;
+
+ wl_dongle_scantime(ndev, 40, 80);
+ wl_dongle_offload(ndev, 1, 0xf);
+ wl_dongle_filter(ndev, 1);
+#endif /* !EMBEDDED_PLATFORM */
+
+ err = wl_dongle_mode(ndev, wdev->iftype);
+ if (unlikely(err && err != -EINPROGRESS))
+ goto default_conf_out;
+ if (unlikely((err = wl_dongle_probecap(wl))))
+ goto default_conf_out;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ /* -EINPROGRESS: Call commit handler */
+
+default_conf_out :
+ if (need_lock)
+ rtnl_unlock();
+
+ wl->dongle_up = TRUE;
+
+ return err;
+
+}
+
+static int32
+wl_update_wiphybands(struct wl_priv *wl)
+{
+ struct wiphy *wiphy;
+ int32 phy_list;
+ int8 phy;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ if (unlikely(err = wl_dev_ioctl(wl_to_ndev(wl), WLC_GET_PHYLIST, &phy_list,
+ sizeof(phy_list)))) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ phy = ((char *)&phy_list)[1];
+ WL_DBG(("%c phy\n", phy));
+ if (phy == 'n' || phy == 'a') {
+ wiphy = wl_to_wiphy(wl);
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+__wl_cfg80211_up(struct wl_priv *wl)
+{
+ int32 err = 0;
+
+ if (unlikely(err = wl_config_dongle(wl, FALSE)))
+ return err;
+
+ wl_invoke_iscan(wl);
+ set_bit(WL_STATUS_READY, &wl->status);
+ return err;
+}
+
+static int32
+__wl_cfg80211_down(struct wl_priv *wl)
+{
+ int32 err = 0;
+
+ /* Check if cfg80211 interface is already down */
+ if (!test_bit(WL_STATUS_READY, &wl->status))
+ return err; /* it is even not ready */
+
+ set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ wl_term_iscan(wl);
+ if (wl->scan_request) {
+ cfg80211_scan_done(wl->scan_request, TRUE); /* TRUE means abort */
+ wl->scan_request = NULL;
+ }
+ clear_bit(WL_STATUS_READY, &wl->status);
+ clear_bit(WL_STATUS_SCANNING, &wl->status);
+ clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ clear_bit(WL_STATUS_CONNECTED, &wl->status);
+
+ return err;
+}
+
+int32
+wl_cfg80211_up(void)
+{
+ struct wl_priv *wl;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl = WL_PRIV_GET();
+ mutex_lock(&wl->usr_sync);
+ err = __wl_cfg80211_up(wl);
+ mutex_unlock(&wl->usr_sync);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+int32
+wl_cfg80211_down(void)
+{
+ struct wl_priv *wl;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl = WL_PRIV_GET();
+ mutex_lock(&wl->usr_sync);
+ err = __wl_cfg80211_down(wl);
+ mutex_unlock(&wl->usr_sync);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+ return err;
+}
+
+static int32
+wl_dongle_probecap(struct wl_priv *wl)
+{
+ int32 err = 0;
+
+ if (unlikely((err = wl_update_wiphybands(wl))))
+ return err;
+
+ return err;
+}
+
+static void *
+wl_read_prof(struct wl_priv *wl, int32 item)
+{
+ switch (item) {
+ case WL_PROF_SEC:
+ return &wl->profile->sec;
+ case WL_PROF_ACT:
+ return &wl->profile->active;
+ case WL_PROF_BSSID:
+ return &wl->profile->bssid;
+ case WL_PROF_SSID:
+ return &wl->profile->ssid;
+ }
+ WL_ERR(("invalid item (%d)\n", item));
+ return NULL;
+}
+
+static int32
+wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, int32 item)
+{
+ int32 err = 0;
+ struct wlc_ssid *ssid;
+
+ switch (item) {
+ case WL_PROF_SSID:
+ ssid = (wlc_ssid_t *)data;
+ memset(wl->profile->ssid.SSID, 0, sizeof(wl->profile->ssid.SSID));
+ memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
+ wl->profile->ssid.SSID_len = ssid->SSID_len;
+ break;
+ case WL_PROF_BSSID:
+ if (data)
+ memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
+ else
+ memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
+ break;
+ case WL_PROF_SEC:
+ memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
+ break;
+ case WL_PROF_ACT:
+ wl->profile->active = *(bool *)data;
+ break;
+ default :
+ WL_ERR(("unsupported item (%d)\n", item));
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+void
+wl_cfg80211_dbg_level(uint32 level)
+{
+ wl_dbg_level = level;
+}
+
+static bool
+wl_is_ibssmode(struct wl_priv *wl)
+{
+ return (wl->conf->mode == WL_MODE_IBSS);
+}
+
+static bool
+wl_is_ibssstarter(struct wl_priv *wl)
+{
+ return wl->ibss_starter;
+}
+
+static void
+wl_rst_ie(struct wl_priv *wl)
+{
+ struct wl_ie *ie = wl_to_ie(wl);
+
+ ie->offset = 0;
+}
+
+static int32
+wl_add_ie(struct wl_priv *wl, uint8 t, uint8 l, uint8 *v)
+{
+ struct wl_ie *ie = wl_to_ie(wl);
+ int32 err = 0;
+
+ if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
+ WL_ERR(("ei crosses buffer boundary\n"));
+ return -ENOSPC;
+ }
+ ie->buf[ie->offset] = t;
+ ie->buf[ie->offset+1] = l;
+ memcpy(&ie->buf[ie->offset+2], v, l);
+ ie->offset += l+2;
+
+ return err;
+}
+
+static int32
+wl_mrg_ie(struct wl_priv *wl, uint8 *ie_stream, uint16 ie_size)
+{
+ struct wl_ie *ie = wl_to_ie(wl);
+ int32 err = 0;
+
+ if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
+ WL_ERR(("ei_stream crosses buffer boundary\n"));
+ return -ENOSPC;
+ }
+ memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
+ ie->offset += ie_size;
+
+ return err;
+}
+
+static int32
+wl_cp_ie(struct wl_priv *wl, uint8 *dst, uint16 dst_size)
+{
+ struct wl_ie *ie = wl_to_ie(wl);
+ int32 err = 0;
+
+ if (unlikely(ie->offset > dst_size)) {
+ WL_ERR(("dst_size is not enough\n"));
+ return -ENOSPC;
+ }
+ memcpy(dst, &ie->buf[0], ie->offset);
+
+ return err;
+}
+
+static uint32
+wl_get_ielen(struct wl_priv *wl)
+{
+ struct wl_ie *ie = wl_to_ie(wl);
+
+ return ie->offset;
+}
+
+static void
+wl_link_up(struct wl_priv *wl)
+{
+ wl->link_up = TRUE;
+}
+
+static void
+wl_link_down(struct wl_priv *wl)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(wl);
+
+ wl->link_up = FALSE;
+ if (conn_info->req_ie) {
+ kfree(conn_info->req_ie);
+ conn_info->req_ie = NULL;
+ }
+ conn_info->req_ie_len = 0;
+ if (conn_info->resp_ie) {
+ kfree(conn_info->resp_ie);
+ conn_info->resp_ie = NULL;
+ }
+ conn_info->resp_ie_len = 0;
+}
+
+static void
+wl_lock_eq(struct wl_priv *wl)
+{
+ spin_lock_irq(&wl->eq_lock);
+}
+
+static void
+wl_unlock_eq(struct wl_priv *wl)
+{
+ spin_unlock_irq(&wl->eq_lock);
+}
+
+static void
+wl_init_eq_lock(struct wl_priv *wl)
+{
+ spin_lock_init(&wl->eq_lock);
+}
+
+static void
+wl_delay(uint32 ms)
+{
+ if (ms < 1000 / HZ) {
+ cond_resched();
+ mdelay(ms);
+ } else {
+ msleep(ms);
+ }
+}
+
+static void
+wl_set_drvdata(struct wl_dev *dev, void *data)
+{
+ dev->driver_data = data;
+}
+
+static void *
+wl_get_drvdata(struct wl_dev *dev)
+{
+ return dev->driver_data;
+}
+
+int32
+wl_cfg80211_read_fw(int8 *buf, uint32 size)
+{
+ const struct firmware *fw_entry;
+ struct wl_priv *wl;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In : size (%d)\n", size));
+#endif
+ wl = WL_PRIV_GET();
+
+ fw_entry = wl->fw->fw_entry;
+
+ if (fw_entry->size < wl->fw->ptr + size) {
+ size = fw_entry->size - wl->fw->ptr;
+ }
+ memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
+ wl->fw->ptr += size;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out : size (%d)\n", size));
+#endif
+ return size;
+}
+
+void
+wl_cfg80211_release_fw(void)
+{
+ struct wl_priv *wl;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl = WL_PRIV_GET();
+ release_firmware(wl->fw->fw_entry);
+ wl->fw->ptr = 0;
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+}
+
+void *
+wl_cfg80211_request_fw(int8 *file_name)
+{
+ struct wl_priv *wl;
+ const struct firmware *fw_entry = NULL;
+ int32 err = 0;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ WL_DBG(("file name : \"%s\"\n", file_name));
+ wl = WL_PRIV_GET();
+
+ if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
+ if (unlikely(err = request_firmware(&wl->fw->fw_entry, file_name,
+ &wl_sdio_func()->dev))) {
+ WL_ERR(("Could not download fw (%d)\n", err));
+ goto req_fw_out;
+ }
+ set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
+ fw_entry = wl->fw->fw_entry;
+ if (fw_entry) {
+ WL_DBG(("fw size (%d), data (%p)\n", fw_entry->size, fw_entry->data));
+ }
+ } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
+ if (unlikely(err = request_firmware(&wl->fw->fw_entry, file_name,
+ &wl_sdio_func()->dev))) {
+ WL_ERR(("Could not download nvram (%d)\n", err));
+ goto req_fw_out;
+ }
+ set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
+ fw_entry = wl->fw->fw_entry;
+ if (fw_entry) {
+ WL_DBG(("nvram size (%d), data (%p)\n", fw_entry->size, fw_entry->data));
+ }
+ } else {
+ WL_DBG(("Downloading already done. Nothing to do more\n"));
+ err = -EPERM;
+ }
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+
+req_fw_out:
+ if (unlikely(err)) {
+ return NULL;
+ }
+ wl->fw->ptr = 0;
+ return (void *)fw_entry->data;
+}
+
+int8 *
+wl_cfg80211_get_fwname(void)
+{
+ struct wl_priv *wl;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl = WL_PRIV_GET();
+ strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return wl->fw->fw_name;
+}
+
+int8 *
+wl_cfg80211_get_nvramname(void)
+{
+ struct wl_priv *wl;
+
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("In\n"));
+#endif
+ wl = WL_PRIV_GET();
+ strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
+#ifdef WL_CFG80211_BACKTRACE
+ WL_DBG(("Out\n"));
+#endif
+ return wl->fw->nvram_name;
+}
diff --git a/bcm4329/src/wl/sys/wl_cfg80211.h b/bcm4329/src/wl/sys/wl_cfg80211.h
new file mode 100644
index 0000000..2722699
--- /dev/null
+++ b/bcm4329/src/wl/sys/wl_cfg80211.h
@@ -0,0 +1,372 @@
+/*
+ * Linux Cfg80211 support
+ *
+ * Copyright (C) 1999-2010, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * you also meet, for each linked independent module, the terms and conditions of
+ * the license of that module. An independent module is a module which is not
+ * derived from this software. The special exception does not apply to any
+ * modifications of the software.
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a license
+ * other than the GPL, without Broadcom's express prior written consent.
+ *
+ * $Id: wl_cfg80211.h,v 1.1.2.19 2010/05/04 21:21:00 Exp $
+ */
+
+#ifndef _wl_cfg80211_h_
+#define _wl_cfg80211_h_
+
+#include <linux/wireless.h>
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <wlioctl.h>
+#include <linux/wireless.h>
+#include <net/cfg80211.h>
+
+struct wl_conf;
+struct wl_iface;
+struct wl_priv;
+struct wl_security;
+struct wl_ibss;
+
+#if defined(IL_BIGENDIAN)
+#include <bcmendian.h>
+#define htod32(i) (bcmswap32(i))
+#define htod16(i) (bcmswap16(i))
+#define dtoh32(i) (bcmswap32(i))
+#define dtoh16(i) (bcmswap16(i))
+#define htodchanspec(i) htod16(i)
+#define dtohchanspec(i) dtoh16(i)
+#else
+#define htod32(i) i
+#define htod16(i) i
+#define dtoh32(i) i
+#define dtoh16(i) i
+#define htodchanspec(i) i
+#define dtohchanspec(i) i
+#endif
+
+#define WL_DBG_NONE 0
+#define WL_DBG_DBG (1 << 2)
+#define WL_DBG_INFO (1 << 1)
+#define WL_DBG_ERR (1 << 0)
+#define WL_DBG_MASK ((WL_DBG_DBG | WL_DBG_INFO | WL_DBG_ERR) << 1)
+
+#define WL_DBG_LEVEL 1 /* 0 invalidates all debug messages. default is 1 */
+#define WL_ERR(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ if (net_ratelimit()) { \
+ printk("ERROR @%s : ", __FUNCTION__); \
+ printk args; \
+ } \
+ } \
+ } while (0)
+#define WL_INFO(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_INFO) { \
+ if (net_ratelimit()) { \
+ printk("INFO @%s : ", __FUNCTION__); \
+ printk args; \
+ } \
+ } \
+ } while (0)
+#if (WL_DBG_LEVEL > 0)
+#define WL_DBG(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_DBG) { \
+ printk("DEBUG @%s :", __FUNCTION__); \
+ printk args; \
+ } \
+ } while (0)
+#else /* !(WL_DBG_LEVEL > 0) */
+#define WL_DBG(args)
+#endif /* (WL_DBG_LEVEL > 0) */
+
+#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */
+#define WL_NUM_SCAN_MAX 1
+#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used for 2.6.33 kernel
+ * or later
+ */
+#define WL_SCAN_BUF_MAX (1024 * 8)
+#define WL_TLV_INFO_MAX 1024
+#define WL_BSS_INFO_MAX 2048
+#define WL_ASSOC_INFO_MAX 512 /*
+ * needs to grab assoc info from dongle to
+ * report it to cfg80211 through "connect"
+ * event
+ */
+#define WL_IOCTL_LEN_MAX 1024
+#define WL_EXTRA_BUF_MAX 2048
+#define WL_ISCAN_BUF_MAX 2048 /* the buf lengh can be WLC_IOCTL_MAXLEN (8K)
+ * to reduce iteration
+ */
+#define WL_ISCAN_TIMER_INTERVAL_MS 3000
+#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1)
+#define WL_AP_MAX 256 /* virtually unlimitted as long
+ * as kernel memory allows
+ */
+#define WL_FILE_NAME_MAX 256
+
+/* dongle status */
+enum wl_status {
+ WL_STATUS_READY,
+ WL_STATUS_SCANNING,
+ WL_STATUS_SCAN_ABORTING,
+ WL_STATUS_CONNECTING,
+ WL_STATUS_CONNECTED
+};
+
+/* wi-fi mode */
+enum wl_mode {
+ WL_MODE_BSS,
+ WL_MODE_IBSS,
+ WL_MODE_AP
+};
+
+/* dongle profile list */
+enum wl_prof_list {
+ WL_PROF_MODE,
+ WL_PROF_SSID,
+ WL_PROF_SEC,
+ WL_PROF_IBSS,
+ WL_PROF_BAND,
+ WL_PROF_BSSID,
+ WL_PROF_ACT
+};
+
+/* dongle iscan state */
+enum wl_iscan_state {
+ WL_ISCAN_STATE_IDLE,
+ WL_ISCAN_STATE_SCANING
+};
+
+/* fw downloading status */
+enum wl_fw_status {
+ WL_FW_LOADING_DONE,
+ WL_NVRAM_LOADING_DONE
+};
+
+/* dongle configuration */
+struct wl_conf {
+ uint32 mode; /* adhoc , infrastructure or ap */
+ uint32 frag_threshold;
+ uint32 rts_threshold;
+ uint32 retry_short;
+ uint32 retry_long;
+ int32 tx_power;
+ struct ieee80211_channel channel;
+};
+
+/* cfg80211 main event loop */
+struct wl_event_loop {
+ int32 (*handler[WLC_E_LAST])(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+};
+
+/* representing interface of cfg80211 plane */
+struct wl_iface {
+ struct wl_priv *wl;
+};
+
+struct wl_dev {
+ void *driver_data; /* to store cfg80211 object information */
+};
+
+/* bss inform structure for cfg80211 interface */
+struct wl_cfg80211_bss_info {
+ uint16 band;
+ uint16 channel;
+ int16 rssi;
+ uint16 frame_len;
+ uint8 frame_buf[1];
+};
+
+/* basic structure of scan request */
+struct wl_scan_req {
+ struct wlc_ssid ssid;
+};
+
+/* basic structure of information element */
+struct wl_ie {
+ uint16 offset;
+ uint8 buf[WL_TLV_INFO_MAX];
+};
+
+/* event queue for cfg80211 main event */
+struct wl_event_q {
+ struct list_head eq_list;
+ uint32 etype;
+ wl_event_msg_t emsg;
+ int8 edata[1];
+};
+
+/* security information with currently associated ap */
+struct wl_security {
+ uint32 wpa_versions;
+ uint32 auth_type;
+ uint32 cipher_pairwise;
+ uint32 cipher_group;
+ uint32 wpa_auth;
+};
+
+/* ibss information for currently joined ibss network */
+struct wl_ibss {
+ uint8 beacon_interval; /* in millisecond */
+ uint8 atim; /* in millisecond */
+ int8 join_only;
+ uint8 band;
+ uint8 channel;
+};
+
+/* dongle profile */
+struct wl_profile {
+ uint32 mode;
+ struct wlc_ssid ssid;
+ uint8 bssid[ETHER_ADDR_LEN];
+ struct wl_security sec;
+ struct wl_ibss ibss;
+ int32 band;
+ bool active;
+};
+
+/* dongle iscan event loop */
+struct wl_iscan_eloop {
+ int32 (*handler[WL_SCAN_ERSULTS_LAST])(struct wl_priv *wl);
+};
+
+/* dongle iscan controller */
+struct wl_iscan_ctrl {
+ struct net_device *dev;
+ struct timer_list timer;
+ uint32 timer_ms;
+ uint32 timer_on;
+ int32 state;
+ int32 pid;
+ struct semaphore sync;
+ struct completion exited;
+ struct wl_iscan_eloop el;
+ void *data;
+ int8 ioctl_buf[WLC_IOCTL_SMLEN];
+ int8 scan_buf[WL_ISCAN_BUF_MAX];
+};
+
+/* association inform */
+struct wl_connect_info {
+ uint8 *req_ie;
+ int32 req_ie_len;
+ uint8 *resp_ie;
+ int32 resp_ie_len;
+};
+
+/* firmware /nvram downloading controller */
+struct wl_fw_ctrl {
+ const struct firmware *fw_entry;
+ ulong status;
+ uint32 ptr;
+ int8 fw_name[WL_FILE_NAME_MAX];
+ int8 nvram_name[WL_FILE_NAME_MAX];
+};
+
+/* assoc ie length */
+struct wl_assoc_ielen {
+ uint32 req_len;
+ uint32 resp_len;
+};
+
+/* wpa2 pmk list */
+struct wl_pmk_list {
+ pmkid_list_t pmkids;
+ pmkid_t foo[MAXPMKID-1];
+};
+
+
+/* dongle private data of cfg80211 interface */
+struct wl_priv {
+ struct wireless_dev *wdev; /* representing wl cfg80211 device */
+ struct wl_conf *conf; /* dongle configuration */
+ struct cfg80211_scan_request *scan_request; /* scan request object */
+ struct wl_event_loop el; /* main event loop */
+ struct list_head eq_list; /* used for event queue */
+ spinlock_t eq_lock; /* for event queue synchronization */
+ struct mutex usr_sync; /* maily for dongle up/down synchronization */
+ struct wl_scan_results *bss_list; /* bss_list holding scanned ap information */
+ struct wl_scan_results *scan_results;
+ struct wl_scan_req *scan_req_int; /* scan request object for internal purpose */
+ struct wl_cfg80211_bss_info *bss_info; /* bss information for cfg80211 layer */
+ struct wl_ie ie; /* information element object for internal purpose */
+ struct ether_addr bssid; /* bssid of currently engaged network */
+ struct semaphore event_sync; /* for synchronization of main event thread */
+ struct completion event_exit;
+ struct wl_profile *profile; /* holding dongle profile */
+ struct wl_iscan_ctrl *iscan; /* iscan controller */
+ struct wl_connect_info conn_info; /* association information container */
+ struct wl_fw_ctrl *fw; /* control firwmare / nvram paramter downloading */
+ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
+ int32 event_pid; /* pid of main event handler thread */
+ ulong status; /* current dongle status */
+ void * pub;
+ uint32 channel; /* current channel */
+ bool iscan_on; /* iscan on/off switch */
+ bool iscan_kickstart; /* indicate iscan already started */
+ bool active_scan; /* current scan mode */
+ bool ibss_starter; /* indicates this sta is ibss starter */
+ bool link_up; /* link/connection up flag */
+ bool pwr_save; /* indicate whether dongle to support power save mode */
+ bool dongle_up; /* indicate whether dongle up or not */
+ bool roam_on; /* on/off switch for dongle self-roaming */
+ bool scan_tried; /* indicates if first scan attempted */
+ uint8 *ioctl_buf; /* ioctl buffer */
+ uint8 *extra_buf; /* maily to grab assoc information */
+ uint8 ci[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+};
+
+#define wl_to_dev(w) (wiphy_dev(wl->wdev->wiphy))
+#define wl_to_wiphy(w) (w->wdev->wiphy)
+#define wiphy_to_wl(w) ((struct wl_priv *)(wiphy_priv(w)))
+#define wl_to_wdev(w) (w->wdev)
+#define wdev_to_wl(w) ((struct wl_priv *)(wdev_priv(w)))
+#define wl_to_ndev(w) (w->wdev->netdev)
+#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
+#define ci_to_wl(c) (ci->wl)
+#define wl_to_ci(w) (&w->ci)
+#define wl_to_sr(w) (w->scan_req_int)
+#define wl_to_ie(w) (&w->ie)
+#define iscan_to_wl(i) ((struct wl_priv *)(i->data))
+#define wl_to_iscan(w) (w->iscan)
+#define wl_to_conn(w) (&w->conn_info)
+
+inline static struct wl_bss_info * next_bss(struct wl_scan_results *list,
+ struct wl_bss_info *bss) {
+ return (bss = bss ?
+ (struct wl_bss_info *)((uintptr)bss + dtoh32(bss->length)) : list->bss_info);
+}
+#define for_each_bss(list, bss, __i) \
+ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
+
+extern int32 wl_cfg80211_attach(struct net_device *ndev, void *data);
+extern void wl_cfg80211_detach(void);
+/* event handler from dongle */
+extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void* data);
+extern void wl_cfg80211_sdio_func(void *func); /* set sdio function info */
+extern int32 wl_cfg80211_up(void); /* dongle up */
+extern int32 wl_cfg80211_down(void); /* dongle down */
+extern void wl_cfg80211_dbg_level(uint32 level); /* set dongle debugging level */
+extern void * wl_cfg80211_request_fw(int8 *file_name); /* request fw /nvram downloading */
+extern int32 wl_cfg80211_read_fw(int8 *buf, uint32 size); /* read fw image */
+extern void wl_cfg80211_release_fw(void); /* release fw */
+extern int8 * wl_cfg80211_get_fwname(void); /* get firmware name for the dongle */
+extern int8 * wl_cfg80211_get_nvramname(void); /* get nvram name for the dongle */
+
+#endif /* _wl_cfg80211_h_ */
diff --git a/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c
index de32e94..2cd629c 100644
--- a/bcm4329/src/wl/sys/wl_iw.c
+++ b/bcm4329/src/wl/sys/wl_iw.c
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_iw.c,v 1.51.4.9.2.6.4.104 2010/04/21 23:21:00 Exp $
+ * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.13 2010/09/15 03:34:56 Exp $
*/
@@ -53,11 +53,38 @@ typedef const struct si_pub si_t;
#define WL_ASSOC(x)
#define WL_INFORM(x)
#define WL_WSEC(x)
+#define WL_SCAN(x)
#include <wl_iw.h>
-#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+
+#ifndef IW_ENCODE_ALG_SM4
+#define IW_ENCODE_ALG_SM4 0x20
+#endif
+
+#ifndef IW_AUTH_WAPI_ENABLED
+#define IW_AUTH_WAPI_ENABLED 0x20
+#endif
+
+#ifndef IW_AUTH_WAPI_VERSION_1
+#define IW_AUTH_WAPI_VERSION_1 0x00000008
+#endif
+
+#ifndef IW_AUTH_CIPHER_SMS4
+#define IW_AUTH_CIPHER_SMS4 0x00000020
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
+#define IW_AUTH_KEY_MGMT_WAPI_PSK 4
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
+#define IW_AUTH_KEY_MGMT_WAPI_CERT 8
+#endif
+
+
+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
#include <linux/rtnetlink.h>
#include <linux/mutex.h>
@@ -82,6 +109,7 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev);
} while (0)
static int g_onoff = G_WLAN_SET_ON;
+wl_iw_extra_params_t g_wl_iw_params;
static struct mutex wl_start_lock;
static struct mutex wl_cache_lock;
@@ -133,7 +161,9 @@ static wlc_ssid_t g_specific_ssid;
static wlc_ssid_t g_ssid;
static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;
-static volatile uint g_first_broadcast_scan;
+static volatile uint g_first_broadcast_scan;
+static volatile uint g_first_counter_scans;
+#define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
@@ -150,8 +180,10 @@ static volatile uint g_first_broadcast_scan;
#endif
#if defined(WL_IW_USE_ISCAN)
+#if !defined(CSCAN)
static void wl_iw_free_ss_cache(void);
static int wl_iw_run_ss_cache_timer(int kick_off);
+#endif
int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len);
#define ISCAN_STATE_IDLE 0
@@ -178,8 +210,13 @@ typedef struct iscan_info {
struct completion sysioc_exited;
uint32 scan_flag;
-
+#if defined CSCAN
+ char ioctlbuf[WLC_IOCTL_MEDLEN];
+#else
char ioctlbuf[WLC_IOCTL_SMLEN];
+#endif
+ wl_iscan_params_t *iscan_ex_params_p;
+ int iscan_ex_param_size;
} iscan_info_t;
#define COEX_DHCP 1
static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
@@ -222,6 +259,8 @@ wl_iw_set_scan(
union iwreq_data *wrqu,
char *extra
);
+
+#ifndef CSCAN
static int
wl_iw_get_scan(
struct net_device *dev,
@@ -237,7 +276,7 @@ wl_iw_get_scan_prep(
char *extra,
short max_size
);
-
+#endif
static void swap_key_from_BE(
wl_wsec_key_t *key
@@ -283,7 +322,9 @@ dev_wlc_ioctl(
return ret;
}
- WL_TRACE(("%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
+ net_os_wake_lock(dev);
+
+ WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
__FUNCTION__, current->pid, cmd, arg, len));
if (g_onoff == G_WLAN_SET_ON) {
@@ -298,6 +339,7 @@ dev_wlc_ioctl(
ret = dev_open(dev);
if (ret) {
WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
+ net_os_wake_unlock(dev);
return ret;
}
@@ -311,8 +353,11 @@ dev_wlc_ioctl(
set_fs(fs);
}
else {
- WL_TRACE(("%s: call after driver stop\n", __FUNCTION__));
+ WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__));
}
+
+ net_os_wake_unlock(dev);
+
return ret;
}
@@ -388,6 +433,9 @@ dev_iw_iovar_setbuf(
iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
ASSERT(iolen);
+ if (iolen == 0)
+ return 0;
+
return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
}
@@ -624,15 +672,21 @@ wl_iw_set_power_mode(
dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
- }
- else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
+
+ /* Disable packet filtering if necessary */
+ net_os_set_packet_filter(dev, 0);
+
+ } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
WL_TRACE(("%s: DHCP session done\n", __FUNCTION__));
dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
- }
- else {
- WL_TRACE(("Unkwown yet power setting, ignored\n"));
+
+ /* Enable packet filtering if was turned off */
+ net_os_set_packet_filter(dev, 1);
+
+ } else {
+ WL_ERROR(("Unkwown yet power setting, ignored\n"));
}
p += snprintf(p, MAX_WX_STRING, "OK");
@@ -644,6 +698,35 @@ wl_iw_set_power_mode(
#endif
static int
+wl_iw_get_power_mode(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error;
+ char *p = extra;
+ int pm_local = PM_FAST;
+
+ error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local));
+ if (!error) {
+ WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local));
+ if (pm_local == PM_OFF)
+ pm_local = 1; /* Active */
+ else
+ pm_local = 0; /* Auto */
+ p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local);
+ }
+ else {
+ WL_TRACE(("%s: Error = %d\n", __func__, error));
+ p += snprintf(p, MAX_WX_STRING, "FAIL");
+ }
+ wrqu->data.length = p - extra + 1;
+ return error;
+}
+
+static int
wl_iw_set_btcoex_dhcp(
struct net_device *dev,
struct iw_request_info *info,
@@ -768,6 +851,36 @@ wl_iw_set_btcoex_dhcp(
return error;
}
+static int
+wl_iw_set_suspend(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int suspend_flag;
+ int ret_now;
+ int ret = 0;
+
+ suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
+
+ if (suspend_flag != 0)
+ suspend_flag = 1;
+
+ ret_now = net_os_set_suspend_disable(dev, suspend_flag);
+
+ if (ret_now != suspend_flag) {
+ if (!(ret = net_os_set_suspend(dev, ret_now)))
+ WL_ERROR(("%s: Suspend Flag %d -> %d\n", \
+ __FUNCTION__, ret_now, suspend_flag));
+ else
+ WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
+ }
+
+ return ret;
+}
+
int
wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
{
@@ -804,7 +917,7 @@ wl_iw_get_link_speed(
char *p = extra;
static int link_speed;
-
+ net_os_wake_lock(dev);
if (g_onoff == G_WLAN_SET_ON) {
error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed));
link_speed *= 500000;
@@ -814,9 +927,356 @@ wl_iw_get_link_speed(
wrqu->data.length = p - extra + 1;
+ net_os_wake_unlock(dev);
+ return error;
+}
+
+
+static int
+wl_iw_get_dtim_skip(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error = -1;
+ char *p = extra;
+ char iovbuf[32];
+
+ net_os_wake_lock(dev);
+ if (g_onoff == G_WLAN_SET_ON) {
+
+ memset(iovbuf, 0, sizeof(iovbuf));
+ strcpy(iovbuf, "bcn_li_dtim");
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR,
+ &iovbuf, sizeof(iovbuf))) >= 0) {
+
+ p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]);
+ WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0]));
+ wrqu->data.length = p - extra + 1;
+ }
+ else
+ WL_ERROR(("%s: get dtim_skip failed code %d\n", \
+ __FUNCTION__, error));
+ }
+ net_os_wake_unlock(dev);
+ return error;
+}
+
+
+static int
+wl_iw_set_dtim_skip(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error = -1;
+ char *p = extra;
+ int bcn_li_dtim;
+ char iovbuf[32];
+
+ net_os_wake_lock(dev);
+ if (g_onoff == G_WLAN_SET_ON) {
+
+ bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0');
+
+ if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) {
+
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR,
+ &iovbuf, sizeof(iovbuf))) >= 0) {
+ p += snprintf(p, MAX_WX_STRING, "OK");
+
+ net_os_set_dtim_skip(dev, bcn_li_dtim);
+
+ WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__, \
+ bcn_li_dtim));
+ goto exit;
+ }
+ else WL_ERROR(("%s: set dtim_skip %d failed code %d\n", \
+ __FUNCTION__, bcn_li_dtim, error));
+ }
+ else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n", \
+ __FUNCTION__, bcn_li_dtim));
+ }
+
+ p += snprintf(p, MAX_WX_STRING, "FAIL");
+
+exit:
+ wrqu->data.length = p - extra + 1;
+ net_os_wake_unlock(dev);
+ return error;
+}
+
+
+static int
+wl_iw_get_band(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error = -1;
+ char *p = extra;
+ static int band;
+
+ net_os_wake_lock(dev);
+
+ if (g_onoff == G_WLAN_SET_ON) {
+ error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band));
+
+ p += snprintf(p, MAX_WX_STRING, "Band %d", band);
+
+ wrqu->data.length = p - extra + 1;
+ }
+
+ net_os_wake_unlock(dev);
+ return error;
+}
+
+
+static int
+wl_iw_set_band(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error = -1;
+ char *p = extra;
+ uint band;
+
+ net_os_wake_lock(dev);
+
+ if (g_onoff == G_WLAN_SET_ON) {
+
+ band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0');
+
+ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
+
+
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
+ &band, sizeof(band))) >= 0) {
+ p += snprintf(p, MAX_WX_STRING, "OK");
+ WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band));
+ goto exit;
+ }
+ else WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, \
+ band, error));
+ }
+ else WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band));
+ }
+
+ p += snprintf(p, MAX_WX_STRING, "FAIL");
+
+exit:
+ wrqu->data.length = p - extra + 1;
+ net_os_wake_unlock(dev);
+ return error;
+}
+
+#ifdef PNO_SUPPORT
+
+static int
+wl_iw_set_pno_reset(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error = -1;
+ char *p = extra;
+
+ net_os_wake_lock(dev);
+ if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
+
+ if ((error = dhd_dev_pno_reset(dev)) >= 0) {
+ p += snprintf(p, MAX_WX_STRING, "OK");
+ WL_TRACE(("%s: set OK\n", __FUNCTION__));
+ goto exit;
+ }
+ else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
+ }
+
+ p += snprintf(p, MAX_WX_STRING, "FAIL");
+
+exit:
+ wrqu->data.length = p - extra + 1;
+ net_os_wake_unlock(dev);
+ return error;
+}
+
+
+
+static int
+wl_iw_set_pno_enable(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int error = -1;
+ char *p = extra;
+ int pfn_enabled;
+
+ net_os_wake_lock(dev);
+ pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0');
+
+ if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
+
+ if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) {
+ p += snprintf(p, MAX_WX_STRING, "OK");
+ WL_TRACE(("%s: set OK\n", __FUNCTION__));
+ goto exit;
+ }
+ else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
+ }
+
+ p += snprintf(p, MAX_WX_STRING, "FAIL");
+
+exit:
+ wrqu->data.length = p - extra + 1;
+ net_os_wake_unlock(dev);
return error;
}
+
+
+static int
+wl_iw_set_pno_set(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int res = -1;
+ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
+ int nssid = 0;
+ cmd_tlv_t *cmd_tlv_temp;
+ char type;
+ char *str_ptr;
+ int tlv_size_left;
+ int pno_time;
+
+#ifdef PNO_SET_DEBUG
+ int i;
+ char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', \
+ 'S', 0x01, 0x01, 0x00,
+ 'S',
+ 0x04,
+ 'B', 'R', 'C', 'M',
+ 'S',
+ 0x04,
+ 'G', 'O', 'O', 'G',
+ 'T',
+ 0x00,
+ 0x0A
+ };
+#endif
+
+ net_os_wake_lock(dev);
+ WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+ __FUNCTION__, info->cmd, info->flags,
+ wrqu->data.pointer, wrqu->data.length));
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+ if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
+ WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \
+ wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t)));
+ goto exit_proc;
+ }
+
+#ifdef PNO_SET_DEBUG
+ if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) {
+ res = -ENOMEM;
+ goto exit_proc;
+ }
+ memcpy(extra, pno_in_example, sizeof(pno_in_example));
+ wrqu->data.length = sizeof(pno_in_example);
+ for (i = 0; i < wrqu->data.length; i++)
+ printf("%02X ", extra[i]);
+ printf("\n");
+#endif
+
+ str_ptr = extra;
+#ifdef PNO_SET_DEBUG
+ str_ptr += strlen("PNOSETUP ");
+ tlv_size_left = wrqu->data.length - strlen("PNOSETUP ");
+#else
+ str_ptr += strlen(PNOSETUP_SET_CMD);
+ tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
+#endif
+
+ cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
+ memset(ssids_local, 0, sizeof(ssids_local));
+
+ if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && \
+ (cmd_tlv_temp->version == PNO_TLV_VERSION) && \
+ (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION))
+ {
+ str_ptr += sizeof(cmd_tlv_t);
+ tlv_size_left -= sizeof(cmd_tlv_t);
+
+ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
+ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
+ WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
+ goto exit_proc;
+ }
+ else {
+ while (tlv_size_left > 0)
+ {
+ type = str_ptr[0];
+ switch (type) {
+ case PNO_TLV_TYPE_TIME:
+
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &pno_time, \
+ sizeof(pno_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+
+ default:
+ WL_ERROR(("%s get unkwown type %X\n", \
+ __FUNCTION__, type));
+ goto exit_proc;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+ res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time);
+
+exit_proc:
+ net_os_wake_unlock(dev);
+ return res;
+}
+#endif
+
static int
wl_iw_get_rssi(
struct net_device *dev,
@@ -832,12 +1292,15 @@ wl_iw_get_rssi(
static char ssidbuf[SSID_FMT_BUF_LEN];
scb_val_t scb_val;
+ net_os_wake_lock(dev);
+
bzero(&scb_val, sizeof(scb_val_t));
if (g_onoff == G_WLAN_SET_ON) {
error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
if (error) {
WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error));
+ net_os_wake_unlock(dev);
return error;
}
rssi = dtoh32(scb_val.val);
@@ -852,10 +1315,11 @@ wl_iw_get_rssi(
p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi);
wrqu->data.length = p - extra + 1;
+ net_os_wake_unlock(dev);
return error;
}
-static int
+int
wl_iw_send_priv_event(
struct net_device *dev,
char *flag
@@ -873,6 +1337,7 @@ wl_iw_send_priv_event(
strcpy(extra, flag);
wrqu.data.length = strlen(extra);
wireless_send_event(dev, cmd, &wrqu, extra);
+ net_os_wake_lock_timeout_enable(dev);
WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
return 0;
@@ -946,25 +1411,28 @@ wl_iw_control_wl_off(
dhd_dev_reset(dev, 1);
#if defined(WL_IW_USE_ISCAN)
+#if !defined(CSCAN)
wl_iw_free_ss_cache();
wl_iw_run_ss_cache_timer(0);
- memset(g_scan, 0, G_SCAN_RESULTS);
g_ss_cache_ctrl.m_link_down = 1;
+#endif
+ memset(g_scan, 0, G_SCAN_RESULTS);
g_scan_specified_ssid = 0;
g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
+ g_first_counter_scans = 0;
#endif
#if defined(BCMLXSDMMC)
sdioh_stop(NULL);
#endif
+ net_os_set_dtim_skip(dev, 0);
+
dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
wl_iw_send_priv_event(dev, "STOP");
-
- net_os_wake_lock_timeout_enable(dev);
}
mutex_unlock(&wl_start_lock);
@@ -996,8 +1464,6 @@ wl_iw_control_wl_on(
wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
#endif
- net_os_wake_lock_timeout_enable(dev);
-
WL_TRACE(("Exited %s \n", __FUNCTION__));
return ret;
@@ -1153,28 +1619,6 @@ static int iwpriv_set_ap_config(struct net_device *dev,
#ifdef SOFTAP
-void print_buf(void *pbuf, int len, int bytes_per_line)
-{
- int i, j = 0;
- unsigned char *buf = pbuf;
-
- if (bytes_per_line == 0) {
- bytes_per_line = len;
- }
-
- for (i = 0; i < len; i++) {
- WL_SOFTAP(("%2.2x", *buf++));
- j++;
- if (j == bytes_per_line) {
- WL_SOFTAP(("\n"));
- j = 0;
- } else {
- WL_SOFTAP((":"));
- }
- }
- WL_SOFTAP(("\n"));
-}
-
static int iwpriv_get_assoc_list(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *p_iwrq,
@@ -1431,6 +1875,7 @@ wl_iw_set_freq(
if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
return error;
+ g_wl_iw_params.target_channel = chan;
return -EINPROGRESS;
}
@@ -1451,7 +1896,6 @@ wl_iw_get_freq(
if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
return error;
-
fwrq->m = dtoh32(ci.hw_channel);
fwrq->e = dtoh32(0);
return 0;
@@ -1525,9 +1969,9 @@ wl_iw_get_range(
)
{
struct iw_range *range = (struct iw_range *) extra;
- int channels[MAXCHANNEL+1];
- wl_uint32_list_t *list = (wl_uint32_list_t *) channels;
+ wl_uint32_list_t *list;
wl_rateset_t rateset;
+ int8 *channels;
int error, i, k;
uint sf, ch;
@@ -1545,14 +1989,23 @@ wl_iw_get_range(
if (!extra)
return -EINVAL;
+ channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
+ if (!channels) {
+ WL_ERROR(("Could not alloc channels\n"));
+ return -ENOMEM;
+ }
+ list = (wl_uint32_list_t *)channels;
+
dwrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(range));
range->min_nwid = range->max_nwid = 0;
list->count = htod32(MAXCHANNEL);
- if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels))))
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
+ kfree(channels);
return error;
+ }
for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
range->freq[i].i = dtoh32(list->element[i]);
@@ -1584,8 +2037,10 @@ wl_iw_get_range(
range->avg_qual.noise = 0x100 - 75;
#endif
- if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
+ kfree(channels);
return error;
+ }
rateset.count = dtoh32(rateset.count);
range->num_bitrates = rateset.count;
for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
@@ -1620,8 +2075,10 @@ wl_iw_get_range(
}
}
- if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i))))
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
+ kfree(channels);
return error;
+ }
i = dtoh32(i);
if (i == WLC_PHY_TYPE_A)
range->throughput = 24000000;
@@ -1690,6 +2147,8 @@ wl_iw_get_range(
#endif
#endif
+ kfree(channels);
+
return 0;
}
@@ -1764,6 +2223,41 @@ wl_iw_get_spy(
return 0;
}
+
+static int
+wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size)
+{
+ chanspec_t chanspec = 0;
+
+ if (ch != 0) {
+
+ join_params->params.chanspec_num = 1;
+ join_params->params.chanspec_list[0] = ch;
+
+ if (join_params->params.chanspec_list[0])
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
+ join_params->params.chanspec_num * sizeof(chanspec_t);
+
+ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
+ join_params->params.chanspec_list[0] |= chanspec;
+ join_params->params.chanspec_list[0] =
+ htodchanspec(join_params->params.chanspec_list[0]);
+
+ join_params->params.chanspec_num = htod32(join_params->params.chanspec_num);
+
+ WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n", \
+ __FUNCTION__, join_params->params.chanspec_list[0]));
+ }
+ return 1;
+}
+
static int
wl_iw_set_wap(
struct net_device *dev,
@@ -1774,6 +2268,7 @@ wl_iw_set_wap(
{
int error = -EINVAL;
wl_join_params_t join_params;
+ int join_params_size;
WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
@@ -1795,16 +2290,26 @@ wl_iw_set_wap(
memset(&join_params, 0, sizeof(join_params));
+ join_params_size = sizeof(join_params.ssid);
memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
- if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params)))) {
- WL_ERROR(("Invalid ioctl data.\n"));
+ WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel));
+ wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
+
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
+ WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error));
return error;
}
+ if (g_ssid.SSID_len) {
+ WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, \
+ g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), \
+ g_wl_iw_params.target_channel));
+ }
+
memset(&g_ssid, 0, sizeof(g_ssid));
return 0;
@@ -1871,6 +2376,7 @@ wl_iw_mlme(
}
#endif
+#ifndef WL_IW_USE_ISCAN
static int
wl_iw_get_aplist(
struct net_device *dev,
@@ -1946,6 +2452,7 @@ wl_iw_get_aplist(
}
return 0;
}
+#endif
#ifdef WL_IW_USE_ISCAN
static int
@@ -1971,7 +2478,8 @@ wl_iw_iscan_get_aplist(
return -EINVAL;
if ((!iscan) || (iscan->sysioc_pid < 0)) {
- return wl_iw_get_aplist(dev, info, dwrq, extra);
+ WL_ERROR(("%s error\n", __FUNCTION__));
+ return 0;
}
buf = iscan->list_hdr;
@@ -2048,35 +2556,26 @@ wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
static int
wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
{
- int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
- wl_iscan_params_t *params;
int err = 0;
- WL_TRACE(("%s: start\n", __func__));
-
- if (ssid && ssid->SSID_len) {
- params_size += sizeof(wlc_ssid_t);
- }
- params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
- if (params == NULL) {
- return -ENOMEM;
- }
- memset(params, 0, params_size);
- ASSERT(params_size < WLC_IOCTL_SMLEN);
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(action);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
- err = wl_iw_iscan_prep(&params->params, ssid);
+ WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
+ WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
+ WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
+ WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
+ WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
+ WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
- if (!err) {
- params->version = htod32(ISCAN_REQ_VERSION);
- params->action = htod16(action);
- params->scan_duration = htod16(0);
-
-
- (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size,
- iscan->ioctlbuf, WLC_IOCTL_SMLEN);
+
+ if ((err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \
+ iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
+ WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
+ err = -1;
}
- kfree(params);
return err;
}
@@ -2087,7 +2586,7 @@ wl_iw_timerfunc(ulong data)
if (iscan) {
iscan->timer_on = 0;
if (iscan->iscan_state != ISCAN_STATE_IDLE) {
- WL_TRACE(("timer trigger\n"));
+ WL_SCAN(("timer trigger\n"));
up(&iscan->sysioc_sem);
}
}
@@ -2113,6 +2612,7 @@ wl_iw_iscan_get(iscan_info_t *iscan)
wl_iscan_results_t list;
wl_scan_results_t *results;
uint32 status;
+ int res;
mutex_lock(&wl_cache_lock);
if (iscan->list_cur) {
@@ -2147,20 +2647,25 @@ wl_iw_iscan_get(iscan_info_t *iscan)
memset(&list, 0, sizeof(list));
list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
- (void) dev_iw_iovar_getbuf(
+ res = dev_iw_iovar_getbuf(
iscan->dev,
"iscanresults",
&list,
WL_ISCAN_RESULTS_FIXED_SIZE,
buf->iscan_buf,
WLC_IW_ISCAN_MAXLEN);
- results->buflen = dtoh32(results->buflen);
- results->version = dtoh32(results->version);
- results->count = dtoh32(results->count);
- WL_TRACE(("results->count = %d\n", results->count));
-
- WL_TRACE(("results->buflen = %d\n", results->buflen));
- status = dtoh32(list_buf->status);
+ if (res == 0) {
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ results->count = dtoh32(results->count);
+ WL_SCAN(("results->count = %d\n", results->count));
+
+ WL_SCAN(("results->buflen = %d\n", results->buflen));
+ status = dtoh32(list_buf->status);
+ } else {
+ WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
+ status = WL_SCAN_RESULTS_NO_MEM;
+ }
mutex_unlock(&wl_cache_lock);
return status;
}
@@ -2203,13 +2708,15 @@ _iscan_sysioc_thread(void *data)
status = WL_SCAN_RESULTS_PARTIAL;
while (down_interruptible(&iscan->sysioc_sem) == 0) {
+ net_os_wake_lock(iscan->dev);
+
#if defined(SOFTAP)
if (ap_cfg_running) {
- WL_TRACE(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
+ WL_SCAN(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
+ net_os_wake_unlock(iscan->dev);
continue;
}
#endif
- net_os_wake_lock(iscan->dev);
if (iscan->timer_on) {
iscan->timer_on = 0;
@@ -2225,7 +2732,7 @@ _iscan_sysioc_thread(void *data)
#endif
if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) {
- WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
+ WL_SCAN(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
wl_iw_send_scan_complete(iscan);
iscan_pass_abort = FALSE;
status = -1;
@@ -2233,7 +2740,7 @@ _iscan_sysioc_thread(void *data)
switch (status) {
case WL_SCAN_RESULTS_PARTIAL:
- WL_TRACE(("iscanresults incomplete\n"));
+ WL_SCAN(("iscanresults incomplete\n"));
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
rtnl_lock();
#endif
@@ -2247,18 +2754,18 @@ _iscan_sysioc_thread(void *data)
iscan->timer_on = 1;
break;
case WL_SCAN_RESULTS_SUCCESS:
- WL_TRACE(("iscanresults complete\n"));
+ WL_SCAN(("iscanresults complete\n"));
iscan->iscan_state = ISCAN_STATE_IDLE;
wl_iw_send_scan_complete(iscan);
break;
case WL_SCAN_RESULTS_PENDING:
- WL_TRACE(("iscanresults pending\n"));
+ WL_SCAN(("iscanresults pending\n"));
mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
iscan->timer_on = 1;
break;
case WL_SCAN_RESULTS_ABORTED:
- WL_TRACE(("iscanresults aborted\n"));
+ WL_SCAN(("iscanresults aborted\n"));
iscan->iscan_state = ISCAN_STATE_IDLE;
if (g_scan_specified_ssid == 0)
wl_iw_send_scan_complete(iscan);
@@ -2268,11 +2775,11 @@ _iscan_sysioc_thread(void *data)
}
break;
case WL_SCAN_RESULTS_NO_MEM:
- WL_TRACE(("iscanresults can't alloc memory: skip\n"));
+ WL_SCAN(("iscanresults can't alloc memory: skip\n"));
iscan->iscan_state = ISCAN_STATE_IDLE;
break;
default:
- WL_TRACE(("iscanresults returned unknown status %d\n", status));
+ WL_SCAN(("iscanresults returned unknown status %d\n", status));
break;
}
@@ -2288,6 +2795,7 @@ _iscan_sysioc_thread(void *data)
}
#endif
+#if !defined(CSCAN)
static void
wl_iw_set_ss_cache_timer_flag(void)
@@ -2453,18 +2961,14 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list)
if (node) {
continue;
}
- leaf = kmalloc(WLC_IW_SS_CACHE_MAXLEN, GFP_KERNEL);
+ leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
if (!leaf) {
+ WL_ERROR(("Memory alloc failure %d\n", \
+ bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
mutex_unlock(&wl_cache_lock);
return -ENOMEM;
}
- if (bi->length > WLC_IW_BSS_INFO_MAXLEN) {
- WL_TRACE(("bss info length is too long : %d\n", bi->length));
- kfree(leaf);
- continue;
- }
-
memcpy(leaf->bss_info, bi, bi->length);
leaf->next = NULL;
leaf->dirty = 1;
@@ -2544,6 +3048,7 @@ wl_iw_delete_bss_from_ss_cache(void *addr)
return 0;
}
+#endif
static int
@@ -2557,6 +3062,11 @@ wl_iw_set_scan(
int error;
WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
+#if defined(CSCAN)
+ WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
+ return -EINVAL;
+#endif
+
#if defined(SOFTAP)
if (ap_cfg_running) {
WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
@@ -2603,7 +3113,7 @@ wl_iw_set_scan(
if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) {
WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error));
- g_scan_specified_ssid = 0; /* Clean to allow future ISCAN */
+ g_scan_specified_ssid = 0;
return -EBUSY;
}
@@ -2626,11 +3136,6 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
return 0;
}
- memset(&ssid, 0, sizeof(ssid));
-
- iscan->list_cur = iscan->list_hdr;
- iscan->iscan_state = ISCAN_STATE_SCANING;
-
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
if (flag)
rtnl_lock();
@@ -2640,7 +3145,14 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
wl_iw_set_event_mask(dev);
WL_TRACE(("+++: Set Broadcast ISCAN\n"));
+
+ memset(&ssid, 0, sizeof(ssid));
+
+ iscan->list_cur = iscan->list_hdr;
+ iscan->iscan_state = ISCAN_STATE_SCANING;
+ memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size);
+ wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
@@ -2654,6 +3166,7 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
return 0;
}
+
static int
wl_iw_iscan_set_scan(
struct net_device *dev,
@@ -2664,31 +3177,45 @@ wl_iw_iscan_set_scan(
{
wlc_ssid_t ssid;
iscan_info_t *iscan = g_iscan;
+ int ret = 0;
WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
+#if defined(CSCAN)
+ WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
+ return -EINVAL;
+#endif
+
+ net_os_wake_lock(dev);
+
#if defined(SOFTAP)
if (ap_cfg_running) {
WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
- return 0;
+ goto set_scan_end;
}
#endif
if (g_onoff == G_WLAN_SET_OFF) {
WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
- return 0;
+ goto set_scan_end;
+ }
+
+#ifdef PNO_SUPPORT
+ if (dhd_dev_get_pno_status(dev)) {
+ WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
}
+#endif
if ((!iscan) || (iscan->sysioc_pid < 0)) {
- WL_TRACE(("%s use backup if iscan thread is not successful\n", \
- __FUNCTION__));
- return wl_iw_set_scan(dev, info, wrqu, extra);
+ WL_ERROR(("%s error\n", __FUNCTION__));
+ goto set_scan_end;
}
if (g_scan_specified_ssid) {
WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", \
__FUNCTION__));
- return EBUSY;
+ ret = EBUSY;
+ goto set_scan_end;
}
memset(&ssid, 0, sizeof(ssid));
@@ -2699,32 +3226,47 @@ wl_iw_iscan_set_scan(
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
int as = 0;
struct iw_scan_req *req = (struct iw_scan_req *)extra;
- if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
- WL_TRACE(("%s First ISCAN in progress : ignoring SC = %s\n", \
- __FUNCTION__, req->essid));
- return -EBUSY;
- }
ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
memcpy(ssid.SSID, req->essid, ssid.SSID_len);
ssid.SSID_len = htod32(ssid.SSID_len);
dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
wl_iw_set_event_mask(dev);
- return wl_iw_set_scan(dev, info, wrqu, extra);
+ ret = wl_iw_set_scan(dev, info, wrqu, extra);
+ goto set_scan_end;
}
else {
g_scan_specified_ssid = 0;
if (iscan->iscan_state == ISCAN_STATE_SCANING) {
WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__));
- return 0;
+ goto set_scan_end;
}
}
}
#endif
+#if !defined(CSCAN)
+ if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
+ if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
+
+ WL_ERROR(("%s Clean up First scan flag which is %d\n", \
+ __FUNCTION__, g_first_broadcast_scan));
+ g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
+ }
+ else {
+ WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n", \
+ __FUNCTION__, g_first_counter_scans));
+ ret = -EBUSY;
+ goto set_scan_end;
+ }
+ }
+#endif
+
wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
- return 0;
+set_scan_end:
+ net_os_wake_unlock(dev);
+ return ret;
}
#endif
@@ -2766,6 +3308,32 @@ ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
}
#endif
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+ size_t len, int uppercase)
+{
+ size_t i;
+ char *pos = buf, *end = buf + buf_size;
+ int ret;
+ if (buf_size == 0)
+ return 0;
+ for (i = 0; i < len; i++) {
+ ret = snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+ data[i]);
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return pos - buf;
+ }
+ pos += ret;
+ }
+ end[-1] = '\0';
+ return pos - buf;
+}
+
+
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
static int
wl_iw_handle_scanresults_ies(char **event_p, char *end,
@@ -2774,6 +3342,8 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end,
#if WIRELESS_EXT > 17
struct iw_event iwe;
char *event;
+ char *buf;
+ int custom_event_len;
event = *event_p;
if (bi->ie_length) {
@@ -2812,6 +3382,35 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end,
}
}
+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+ ptr_len = bi->ie_length;
+
+ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) {
+ WL_TRACE(("%s: found a WAPI IE...\n", __FUNCTION__));
+#ifdef WAPI_IE_USE_GENIE
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ie->len + 2;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
+#else
+ iwe.cmd = IWEVCUSTOM;
+ custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2);
+ iwe.u.data.length = custom_event_len;
+
+ buf = kmalloc(custom_event_len+1, GFP_KERNEL);
+ if (buf == NULL)
+ {
+ WL_ERROR(("malloc(%d) returned NULL...\n", custom_event_len));
+ break;
+ }
+
+ memcpy(buf, "wapi_ie=", 8);
+ wpa_snprintf_hex(buf + 8, 2+1, &(ie->id), 1);
+ wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1);
+ wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len);
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf);
+#endif
+ break;
+ }
*event_p = event;
}
#endif
@@ -2819,6 +3418,7 @@ wl_iw_handle_scanresults_ies(char **event_p, char *end,
return 0;
}
+#ifndef CSCAN
static uint
wl_iw_get_scan_prep(
wl_scan_results_t *list,
@@ -2931,12 +3531,16 @@ wl_iw_get_scan(
uint buflen_from_user = dwrq->length;
uint len = G_SCAN_RESULTS;
__u16 len_ret = 0;
+#if !defined(CSCAN)
__u16 merged_len = 0;
+#endif
#if defined(WL_IW_USE_ISCAN)
iscan_info_t *iscan = g_iscan;
iscan_buf_t * p_buf;
+#if !defined(CSCAN)
uint32 counter = 0;
#endif
+#endif
WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
if (!extra) {
@@ -2951,6 +3555,7 @@ wl_iw_get_scan(
if (ci.scan_channel)
return -EAGAIN;
+#if !defined(CSCAN)
if (g_ss_cache_ctrl.m_timer_expired) {
wl_iw_free_ss_cache();
g_ss_cache_ctrl.m_timer_expired ^= 1;
@@ -2968,7 +3573,7 @@ wl_iw_get_scan(
else {
g_ss_cache_ctrl.m_cons_br_scan_cnt++;
}
-
+#endif
if (g_scan_specified_ssid) {
@@ -2983,10 +3588,12 @@ wl_iw_get_scan(
memset(list, 0, len);
list->buflen = htod32(len);
if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) {
- WL_TRACE(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, len));
+ WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error));
dwrq->length = len;
- if (g_scan_specified_ssid)
+ if (g_scan_specified_ssid) {
+ g_scan_specified_ssid = 0;
kfree(list);
+ }
return 0;
}
list->buflen = dtoh32(list->buflen);
@@ -3003,6 +3610,7 @@ wl_iw_get_scan(
return -EINVAL;
}
+#if !defined(CSCAN)
if (g_scan_specified_ssid) {
wl_iw_add_bss_to_ss_cache(list);
@@ -3038,6 +3646,37 @@ wl_iw_get_scan(
len_ret += merged_len;
wl_iw_run_ss_cache_timer(0);
wl_iw_run_ss_cache_timer(1);
+#else
+
+ if (g_scan_specified_ssid) {
+ WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
+ len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
+ kfree(list);
+
+#if defined(WL_IW_USE_ISCAN)
+ p_buf = iscan->list_hdr;
+
+ while (p_buf != iscan->list_cur) {
+ list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
+ WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
+ if (list_merge->count > 0)
+ len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
+ extra+len_ret, buflen_from_user -len_ret);
+ p_buf = p_buf->next;
+ }
+#else
+ list_merge = (wl_scan_results_t *) g_scan;
+ WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
+ if (list_merge->count > 0)
+ len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
+ buflen_from_user -len_ret);
+#endif
+ }
+ else {
+ list = (wl_scan_results_t *) g_scan;
+ len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
+ }
+#endif
#if defined(WL_IW_USE_ISCAN)
@@ -3053,6 +3692,7 @@ wl_iw_get_scan(
WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count));
return 0;
}
+#endif
#if defined(WL_IW_USE_ISCAN)
static int
@@ -3072,8 +3712,11 @@ wl_iw_iscan_get_scan(
iscan_info_t *iscan = g_iscan;
iscan_buf_t * p_buf;
uint32 counter = 0;
+ uint8 channel;
+#if !defined(CSCAN)
__u16 merged_len = 0;
uint buflen_from_user = dwrq->length;
+#endif
WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
@@ -3094,12 +3737,13 @@ wl_iw_iscan_get_scan(
dev->name, __FUNCTION__));
return -EAGAIN;
}
-
+
if ((!iscan) || (iscan->sysioc_pid < 0)) {
- WL_TRACE(("%ssysioc_pid\n", __FUNCTION__));
- return wl_iw_get_scan(dev, info, dwrq, extra);
+ WL_ERROR(("%ssysioc_pid\n", __FUNCTION__));
+ return -EAGAIN;
}
+#if !defined(CSCAN)
if (g_ss_cache_ctrl.m_timer_expired) {
wl_iw_free_ss_cache();
g_ss_cache_ctrl.m_timer_expired ^= 1;
@@ -3119,6 +3763,7 @@ wl_iw_iscan_get_scan(
g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
g_ss_cache_ctrl.m_cons_br_scan_cnt++;
}
+#endif
WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
apcnt = 0;
@@ -3169,8 +3814,9 @@ wl_iw_iscan_get_scan(
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
- CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
+ channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
+ iwe.u.freq.m = wf_channel2mhz(channel,
+ channel <= CH_MAX_2G_CHANNEL ?
WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
iwe.u.freq.e = 6;
event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
@@ -3217,18 +3863,16 @@ wl_iw_iscan_get_scan(
dwrq->length = event - extra;
dwrq->flags = 0;
+#if !defined(CSCAN)
wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
dwrq->length += merged_len;
wl_iw_run_ss_cache_timer(0);
wl_iw_run_ss_cache_timer(1);
-
+#endif /* CSCAN */
g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
- if (!dwrq->length)
- return -EAGAIN;
-
return 0;
}
#endif
@@ -3242,6 +3886,8 @@ wl_iw_set_essid(
)
{
int error;
+ wl_join_params_t join_params;
+ int join_params_size;
WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
@@ -3262,11 +3908,24 @@ wl_iw_set_essid(
g_ssid.SSID_len = 0;
}
g_ssid.SSID_len = htod32(g_ssid.SSID_len);
- if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &g_ssid, sizeof(g_ssid))))
+
+ memset(&join_params, 0, sizeof(join_params));
+ join_params_size = sizeof(join_params.ssid);
+
+ memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
+ join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
+ memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+
+ wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
+
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
+ WL_ERROR(("Invalid ioctl data=%d\n", error));
return error;
+ }
if (g_ssid.SSID_len) {
- WL_TRACE(("%s: join SSID=%s\n", __FUNCTION__, g_ssid.SSID));
+ WL_TRACE(("%s: join SSID=%s ch=%d\n", __FUNCTION__, \
+ g_ssid.SSID, g_wl_iw_params.target_channel));
}
return 0;
}
@@ -3294,7 +3953,6 @@ wl_iw_get_essid(
ssid.SSID_len = dtoh32(ssid.SSID_len);
-
memcpy(extra, ssid.SSID, ssid.SSID_len);
dwrq->length = ssid.SSID_len;
@@ -3319,7 +3977,6 @@ wl_iw_set_nick(
if (!extra)
return -EINVAL;
-
if (dwrq->length > sizeof(iw->nickname))
return -E2BIG;
@@ -3889,11 +4546,21 @@ wl_iw_set_wpaie(
char *extra
)
{
+ uchar buf[WLC_IOCTL_SMLEN] = {0};
+ uchar *p = buf;
+ int wapi_ie_size;
WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
CHECK_EXTRA_FOR_NULL(extra);
+ if (extra[0] == DOT11_MNG_WAPI_ID)
+ {
+ wapi_ie_size = iwp->length;
+ memcpy(p, extra, iwp->length);
+ dev_wlc_bufvar_set(dev, "wapiie", buf, wapi_ie_size);
+ }
+ else
dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
return 0;
@@ -4010,6 +4677,12 @@ wl_iw_set_encodeext(
case IW_ENCODE_ALG_CCMP:
key.algo = CRYPTO_ALGO_AES_CCM;
break;
+ case IW_ENCODE_ALG_SM4:
+ key.algo = CRYPTO_ALGO_SMS4;
+ if (iwe->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ key.flags &= ~WL_PRIMARY_KEY;
+ }
+ break;
default:
break;
}
@@ -4193,6 +4866,8 @@ wl_iw_set_wpaauth(
else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
#endif
+ else if (paramval & IW_AUTH_WAPI_VERSION_1)
+ val = WPA_AUTH_WAPI;
WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
return error;
@@ -4207,6 +4882,8 @@ wl_iw_set_wpaauth(
val = TKIP_ENABLED;
if (paramval & IW_AUTH_CIPHER_CCMP)
val = AES_ENABLED;
+ if (paramval & IW_AUTH_CIPHER_SMS4)
+ val = SMS4_ENABLED;
if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
iw->pwsec = val;
@@ -4254,9 +4931,12 @@ wl_iw_set_wpaauth(
val = WPA2_AUTH_UNSPECIFIED;
}
#endif
+ if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT))
+ val = WPA_AUTH_WAPI;
WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
return error;
+
break;
case IW_AUTH_TKIP_COUNTERMEASURES:
dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
@@ -4339,6 +5019,24 @@ wl_iw_set_wpaauth(
break;
}
#endif
+ case IW_AUTH_WAPI_ENABLED:
+ if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
+ return error;
+ if (paramval) {
+ val |= SMS4_ENABLED;
+ if ((error = dev_wlc_intvar_set(dev, "wsec", val))) {
+ WL_ERROR(("%s: setting wsec to 0x%0x returned error %d\n",
+ __FUNCTION__, val, error));
+ return error;
+ }
+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", WPA_AUTH_WAPI))) {
+ WL_ERROR(("%s: setting wpa_auth(WPA_AUTH_WAPI) returned %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
+ }
+
+ break;
default:
break;
}
@@ -4574,6 +5272,7 @@ int dev_iw_read_cfg1_bss_var(struct net_device *dev, int *val)
}
+#ifndef AP_ONLY
static int wl_bssiovar_mkbuf(
const char *iovar,
int bssidx,
@@ -4616,6 +5315,7 @@ static int wl_bssiovar_mkbuf(
*perr = 0;
return iolen;
}
+#endif
int get_user_params(char *user_params, struct iw_point *dwrq)
@@ -4634,7 +5334,414 @@ int get_user_params(char *user_params, struct iw_point *dwrq)
}
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+
+#if defined(CSCAN)
+
+static int
+wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
+{
+ int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
+ int err = 0;
+ char *p;
+ int i;
+ iscan_info_t *iscan = g_iscan;
+
+ WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
+
+ if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
+ WL_ERROR(("%s error exit\n", __FUNCTION__));
+ err = -1;
+ goto exit;
+ }
+
+#ifdef PNO_SUPPORT
+ if (dhd_dev_get_pno_status(dev)) {
+ WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
+ }
+#endif
+
+ params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+
+ if (nssid > 0) {
+ i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
+ i = ROUNDUP(i, sizeof(uint32));
+ if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
+ printf("additional ssids exceed params_size\n");
+ err = -1;
+ goto exit;
+ }
+
+ p = ((char*)&iscan->iscan_ex_params_p->params) + i;
+ memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
+ p += nssid * sizeof(wlc_ssid_t);
+ } else {
+ p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
+ }
+
+
+ iscan->iscan_ex_params_p->params.channel_num = \
+ htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \
+ (nchan & WL_SCAN_PARAMS_COUNT_MASK));
+
+ nssid = \
+ (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \
+ WL_SCAN_PARAMS_COUNT_MASK);
+
+
+ params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
+ iscan->iscan_ex_param_size = params_size;
+
+ iscan->list_cur = iscan->list_hdr;
+ iscan->iscan_state = ISCAN_STATE_SCANING;
+ wl_iw_set_event_mask(dev);
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
+
+ iscan->timer_on = 1;
+
+#ifdef SCAN_DUMP
+ {
+ int i;
+ WL_SCAN(("\n### List of SSIDs to scan ###\n"));
+ for (i = 0; i < nssid; i++) {
+ if (!ssids_local[i].SSID_len)
+ WL_SCAN(("%d: Broadcast scan\n", i));
+ else
+ WL_SCAN(("%d: scan for %s size =%d\n", i, \
+ ssids_local[i].SSID, ssids_local[i].SSID_len));
+ }
+ WL_SCAN(("### List of channels to scan ###\n"));
+ for (i = 0; i < nchan; i++)
+ {
+ WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
+ }
+ WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
+ WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
+ WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
+ WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
+ WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
+ WL_SCAN(("\n###################\n"));
+ }
+#endif
+
+ if (params_size > WLC_IOCTL_MEDLEN) {
+ WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", \
+ __FUNCTION__, params_size));
+ err = -1;
+ }
+
+ if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \
+ iscan->iscan_ex_param_size, \
+ iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
+ WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
+ err = -1;
+ }
+
+exit:
+
+ return err;
+}
+
+
+static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, \
+ union iwreq_data *wrqu, char *ext)
+{
+ int res = 0;
+ char *extra = NULL;
+ iscan_info_t *iscan = g_iscan;
+ wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
+ int nssid = 0;
+ int nchan = 0;
+
+ WL_TRACE(("\%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+ __FUNCTION__, info->cmd, info->flags,
+ wrqu->data.pointer, wrqu->data.length));
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ return -1;
+ }
+
+ if (wrqu->data.length != 0) {
+
+ char *str_ptr;
+
+ if (!iscan->iscan_ex_params_p) {
+ return -EFAULT;
+ }
+
+ if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
+ kfree(extra);
+ return -EFAULT;
+ }
+
+ extra[wrqu->data.length] = 0;
+ WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
+
+ str_ptr = extra;
+
+ if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
+ WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
+ goto exit_proc;
+ }
+ str_ptr += strlen(GET_SSID);
+ nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, \
+ WL_SCAN_PARAMS_SSID_MAX);
+ if (nssid == -1) {
+ WL_ERROR(("%s wrong ssid list", __FUNCTION__));
+ return -1;
+ }
+
+ memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
+ ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN);
+
+
+ wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
+
+
+ if ((nchan = wl_iw_parse_channel_list(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.channel_list[0], \
+ WL_NUMCHANNELS)) == -1) {
+ WL_ERROR(("%s missing channel list\n", __FUNCTION__));
+ return -1;
+ }
+
+
+ get_parmeter_from_string(&str_ptr, \
+ GET_NPROBE, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.nprobes, 2);
+
+ get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.active_time, 4);
+
+ get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.passive_time, 4);
+
+ get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.home_time, 4);
+
+ get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \
+ &iscan->iscan_ex_params_p->params.scan_type, 1);
+
+ res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
+
+ } else {
+ WL_ERROR(("IWPRIV argument len = 0 \n"));
+ return -1;
+ }
+
+exit_proc:
+
+ kfree(extra);
+
+ return res;
+}
+
+
+static int
+wl_iw_set_cscan(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int res = -1;
+ iscan_info_t *iscan = g_iscan;
+ wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
+ int nssid = 0;
+ int nchan = 0;
+ cscan_tlv_t *cscan_tlv_temp;
+ char type;
+ char *str_ptr;
+ int tlv_size_left;
+#ifdef TLV_DEBUG
+ int i;
+ char tlv_in_example[] = { 'C', 'S', 'C', 'A', 'N', ' ', \
+ 0x53, 0x01, 0x00, 0x00,
+ 'S',
+ 0x00,
+ 'S',
+ 0x04,
+ 'B', 'R', 'C', 'M',
+ 'C',
+ 0x06,
+ 'P',
+ 0x94,
+ 0x11,
+ 'T',
+ 0x01
+ };
+#endif
+
+ WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
+ __FUNCTION__, info->cmd, info->flags,
+ wrqu->data.pointer, wrqu->data.length));
+
+ net_os_wake_lock(dev);
+
+ if (g_onoff == G_WLAN_SET_OFF) {
+ WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+
+ if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
+ WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \
+ wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t)));
+ goto exit_proc;
+ }
+
+#ifdef TLV_DEBUG
+ memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
+ wrqu->data.length = sizeof(tlv_in_example);
+ for (i = 0; i < wrqu->data.length; i++)
+ printf("%02X ", extra[i]);
+ printf("\n");
+#endif
+
+ str_ptr = extra;
+ str_ptr += strlen(CSCAN_COMMAND);
+ tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
+
+ cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
+ memset(ssids_local, 0, sizeof(ssids_local));
+
+ if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \
+ (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \
+ (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
+ {
+ str_ptr += sizeof(cscan_tlv_t);
+ tlv_size_left -= sizeof(cscan_tlv_t);
+
+
+ if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
+ WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
+ WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
+ goto exit_proc;
+ }
+ else {
+
+ memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
+
+
+ wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
+ iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
+ iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
+ iscan->iscan_ex_params_p->scan_duration = htod16(0);
+
+
+ while (tlv_size_left > 0)
+ {
+ type = str_ptr[0];
+ switch (type) {
+ case CSCAN_TLV_TYPE_CHANNEL_IE:
+
+ if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.channel_list[0], \
+ WL_NUMCHANNELS, &tlv_size_left)) == -1) {
+ WL_ERROR(("%s missing channel list\n", \
+ __FUNCTION__));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_NPROBE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.nprobes, \
+ sizeof(iscan->iscan_ex_params_p->params.nprobes), \
+ type, sizeof(char), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_ACTIVE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.active_time, \
+ sizeof(iscan->iscan_ex_params_p->params.active_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_PASSIVE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.passive_time, \
+ sizeof(iscan->iscan_ex_params_p->params.passive_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_HOME_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.home_time, \
+ sizeof(iscan->iscan_ex_params_p->params.home_time), \
+ type, sizeof(short), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+ case CSCAN_TLV_TYPE_STYPE_IE:
+ if ((res = wl_iw_parse_data_tlv(&str_ptr, \
+ &iscan->iscan_ex_params_p->params.scan_type, \
+ sizeof(iscan->iscan_ex_params_p->params.scan_type), \
+ type, sizeof(char), &tlv_size_left)) == -1) {
+ WL_ERROR(("%s return %d\n", \
+ __FUNCTION__, res));
+ goto exit_proc;
+ }
+ break;
+
+ default :
+ WL_ERROR(("%s get unkwown type %X\n", \
+ __FUNCTION__, type));
+ goto exit_proc;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
+ goto exit_proc;
+ }
+
+ if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
+ if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
+
+ WL_ERROR(("%s Clean up First scan flag which is %d\n", \
+ __FUNCTION__, g_first_broadcast_scan));
+ g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
+ }
+ else {
+ WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n", \
+ __FUNCTION__, g_first_counter_scans));
+ res = -EBUSY;
+ goto exit_proc;
+ }
+ }
+
+ res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
+
+exit_proc:
+ net_os_wake_unlock(dev);
+ return res;
+}
+
+#endif
+
#ifdef SOFTAP
+#ifndef AP_ONLY
static int thr_wait_for_2nd_eth_dev(void *data)
{
@@ -4670,7 +5777,10 @@ fail:
return ret;
}
-
+#endif
+#ifndef AP_ONLY
+static int last_auto_channel = 6;
+#endif
static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap)
{
int chosen = 0;
@@ -4681,12 +5791,30 @@ static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap
int ret = 0;
wlc_ssid_t null_ssid;
int res = 0;
-
+#ifndef AP_ONLY
+ int iolen = 0;
+ int mkvar_err = 0;
+ int bsscfg_index = 1;
+ char buf[WLC_IOCTL_SMLEN];
+#endif
WL_SOFTAP(("Enter %s\n", __FUNCTION__));
+
+#ifndef AP_ONLY
+ if (ap_cfg_running) {
+ ap->channel = last_auto_channel;
+ return res;
+ }
+#endif
memset(&null_ssid, 0, sizeof(wlc_ssid_t));
res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown));
+#ifdef AP_ONLY
res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid));
-
+#else
+ iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid), \
+ null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
+ ASSERT(iolen);
+ res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen);
+#endif
auto_channel_retry:
request.count = htod32(0);
ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request));
@@ -4716,6 +5844,11 @@ static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap
WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res));
goto fail;
}
+#ifndef AP_ONLY
+ if (!res)
+ last_auto_channel = ap->channel;
+#endif
+
fail :
return res;
}
@@ -4728,21 +5861,23 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
wlc_ssid_t ap_ssid;
int max_assoc = 8;
- int mpc = 0;
int res = 0;
int apsta_var = 0;
+#ifndef AP_ONLY
+ int mpc = 0;
int iolen = 0;
int mkvar_err = 0;
int bsscfg_index = 1;
char buf[WLC_IOCTL_SMLEN];
+#endif
if (!dev) {
WL_ERROR(("%s: dev is null\n", __FUNCTION__));
return -1;
}
- net_os_wake_lock(dev);
+ net_os_wake_lock(dev);
WL_SOFTAP(("wl_iw: set ap profile:\n"));
WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
@@ -4752,8 +5887,17 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
WL_SOFTAP((" channel = %d\n", ap->channel));
WL_SOFTAP((" max scb = %d\n", ap->max_scb));
+#ifdef AP_ONLY
+ if (ap_cfg_running) {
+ wl_iw_softap_deassoc_stations(dev);
+ ap_cfg_running = FALSE;
+ }
+#endif
+
if (ap_cfg_running == FALSE) {
+#ifndef AP_ONLY
+
sema_init(&ap_eth_sema, 0);
mpc = 0;
@@ -4761,6 +5905,7 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
goto fail;
}
+#endif
updown = 0;
if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) {
@@ -4845,6 +5990,15 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
ap_ssid.SSID_len = strlen(ap->ssid);
strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
+#ifdef AP_ONLY
+ if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
+ WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n", \
+ res, __FUNCTION__));
+ goto fail;
+ }
+ wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START");
+ ap_cfg_running = TRUE;
+#else
iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid),
ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
ASSERT(iolen);
@@ -4874,12 +6028,13 @@ static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
goto fail;
}
}
+#endif
fail:
WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res));
- net_os_wake_unlock(dev);
+ net_os_wake_unlock(dev);
- return res;
+ return res;
}
@@ -4890,6 +6045,11 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
int res = 0;
int i;
char *ptr;
+#ifdef AP_ONLY
+ int mpc = 0;
+ wlc_ssid_t ap_ssid;
+#endif
+ wl_wsec_key_t key;
WL_SOFTAP(("\nsetting SOFTAP security mode:\n"));
WL_SOFTAP(("wl_iw: set ap profile:\n"));
@@ -4912,7 +6072,6 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
} else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
- wl_wsec_key_t key;
memset(&key, 0, sizeof(key));
wsec = WEP_ENABLED;
@@ -5030,6 +6189,16 @@ static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res));
}
+#ifdef AP_ONLY
+ ap_ssid.SSID_len = strlen(ap->ssid);
+ strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
+ res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid));
+ mpc = 0;
+ res |= dev_wlc_intvar_set(dev, "mpc", mpc);
+ if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
+ res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
+ }
+#endif
return res;
}
@@ -5045,7 +6214,7 @@ int get_parmeter_from_string(
char *param_str_end;
char *orig_str = *str_ptr;
- if (!strncmp(*str_ptr, token, strlen(token))) {
+ if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) {
strsep(str_ptr, "=,");
param_str_begin = *str_ptr;
@@ -5163,13 +6332,17 @@ static int iwpriv_softap_stop(struct net_device *dev,
return res;
}
- net_os_wake_lock(dev);
+ net_os_wake_lock(dev);
if ((ap_cfg_running == TRUE)) {
- wl_iw_softap_deassoc_stations(ap_net_dev);
+#ifdef AP_ONLY
+ wl_iw_softap_deassoc_stations(dev);
+#else
+ wl_iw_softap_deassoc_stations(ap_net_dev);
if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0)
WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res));
+#endif
bcm_mdelay(100);
@@ -5181,9 +6354,9 @@ static int iwpriv_softap_stop(struct net_device *dev,
WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res));
- net_os_wake_unlock(dev);
+ net_os_wake_unlock(dev);
- return res;
+ return res;
}
@@ -5293,10 +6466,11 @@ iwpriv_en_ap_bss(
return -1;
}
- net_os_wake_lock(dev);
+ net_os_wake_lock(dev);
WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name));
+#ifndef AP_ONLY
if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res));
}
@@ -5307,9 +6481,10 @@ iwpriv_en_ap_bss(
bcm_mdelay(100);
}
+#endif
WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res));
- net_os_wake_unlock(dev);
+ net_os_wake_unlock(dev);
return res;
}
@@ -5440,6 +6615,7 @@ int wl_iw_process_private_ascii_cmd(
WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name));
+#ifndef AP_ONLY
if (ap_net_dev == NULL) {
printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n");
} else {
@@ -5447,15 +6623,21 @@ int wl_iw_process_private_ascii_cmd(
WL_ERROR(("%s line %d fail to set bss up\n", \
__FUNCTION__, __LINE__));
}
-
+#else
+ if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0)
+ WL_ERROR(("%s line %d fail to set bss up\n", \
+ __FUNCTION__, __LINE__));
+#endif
} else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) {
/* no code yet */
} else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
WL_SOFTAP((" \n temp DOWN SOFTAP\n"));
+#ifndef AP_ONLY
if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
WL_ERROR(("%s line %d fail to set bss down\n", \
__FUNCTION__, __LINE__));
}
+#endif
}
return ret;
@@ -5520,6 +6702,28 @@ static int wl_iw_set_priv(
ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
ret = wl_iw_control_wl_off(dev, info);
+ else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
+ ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
+ ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
+ ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
+ ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
+ ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
+#if defined(PNO_SUPPORT)
+ else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
+ ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
+ ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
+ else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
+ ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
+#endif
+#if defined(CSCAN)
+ else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
+ ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
+#endif
#ifdef CUSTOMER_HW2
else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
@@ -5529,6 +6733,8 @@ static int wl_iw_set_priv(
else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
#endif
+ else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
+ ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
#ifdef SOFTAP
else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
@@ -5677,8 +6883,13 @@ static const iw_handler wl_iw_priv_handler[] = {
(iw_handler)iwpriv_softap_stop,
NULL,
- (iw_handler)iwpriv_fw_reload
+ (iw_handler)iwpriv_fw_reload,
#endif
+#if defined(CSCAN)
+
+ NULL,
+ (iw_handler)iwpriv_set_cscan
+#endif
};
static const struct iw_priv_args wl_iw_priv_args[] = {
@@ -5775,6 +6986,14 @@ static const struct iw_priv_args wl_iw_priv_args[] = {
"WL_FW_RELOAD"
},
#endif
+#if defined(CSCAN)
+ {
+ WL_COMBO_SCAN,
+ IW_PRIV_TYPE_CHAR | 1024,
+ 0,
+ "CSCAN"
+ },
+#endif
};
const struct iw_handler_def wl_iw_handler_def =
@@ -5805,11 +7024,14 @@ int wl_iw_ioctl(
char *extra = NULL;
int token_size = 1, max_tokens = 0, ret = 0;
+ net_os_wake_lock(dev);
+
WL_TRACE(("%s: cmd:%x alled via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd));
if (cmd < SIOCIWFIRST ||
IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
!(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) {
WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd));
+ net_os_wake_unlock(dev);
return -EOPNOTSUPP;
}
@@ -5874,14 +7096,18 @@ int wl_iw_ioctl(
if (wrq->u.data.length > max_tokens) {
WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n", \
__FUNCTION__, cmd, wrq->u.data.length, max_tokens));
- return -E2BIG;
+ ret = -E2BIG;
+ goto wl_iw_ioctl_done;
+ }
+ if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) {
+ ret = -ENOMEM;
+ goto wl_iw_ioctl_done;
}
- if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL)))
- return -ENOMEM;
if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
kfree(extra);
- return -EFAULT;
+ ret = -EFAULT;
+ goto wl_iw_ioctl_done;
}
}
@@ -5893,12 +7119,17 @@ int wl_iw_ioctl(
if (extra) {
if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
kfree(extra);
- return -EFAULT;
+ ret = -EFAULT;
+ goto wl_iw_ioctl_done;
}
kfree(extra);
}
+wl_iw_ioctl_done:
+
+ net_os_wake_unlock(dev);
+
return ret;
}
@@ -6015,6 +7246,8 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
uint32 datalen = ntoh32(e->datalen);
uint32 status = ntoh32(e->status);
uint32 toto;
+ static uint32 roam_no_success = 0;
+ static bool roam_no_success_send = FALSE;
memset(&wrqu, 0, sizeof(wrqu));
memset(extra, 0, sizeof(extra));
@@ -6024,7 +7257,7 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
return;
}
- net_os_wake_lock(dev);
+ net_os_wake_lock(dev);
WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type));
@@ -6071,20 +7304,41 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
WL_SOFTAP(("STA connect received %d\n", event_type));
if (ap_cfg_running) {
wl_iw_send_priv_event(priv_dev, "STA_JOIN");
- goto wl_iw_event_end;
+ goto wl_iw_event_end;
}
#endif
memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
wrqu.addr.sa_family = ARPHRD_ETHER;
cmd = IWEVREGISTERED;
break;
+ case WLC_E_ROAM:
+ if (status != WLC_E_STATUS_SUCCESS) {
+ roam_no_success++;
+ if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) {
+
+ roam_no_success_send = TRUE;
+ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
+ bzero(&extra, ETHER_ADDR_LEN);
+ cmd = SIOCGIWAP;
+ WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n", \
+ __FUNCTION__));
+ } else {
+ WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success));
+ goto wl_iw_event_end;
+ }
+ } else {
+ memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+ cmd = SIOCGIWAP;
+ }
+ break;
case WLC_E_DEAUTH_IND:
case WLC_E_DISASSOC_IND:
#if defined(SOFTAP)
WL_SOFTAP(("STA disconnect received %d\n", event_type));
if (ap_cfg_running) {
wl_iw_send_priv_event(priv_dev, "STA_LEAVE");
- goto wl_iw_event_end;
+ goto wl_iw_event_end;
}
#endif
cmd = SIOCGIWAP;
@@ -6097,7 +7351,11 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
cmd = SIOCGIWAP;
if (!(flags & WLC_EVENT_MSG_LINK)) {
#ifdef SOFTAP
+#ifdef AP_ONLY
+ if (ap_cfg_running) {
+#else
if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
+#endif
WL_SOFTAP(("AP DOWN %d\n", event_type));
wl_iw_send_priv_event(priv_dev, "AP_DOWN");
} else {
@@ -6111,7 +7369,6 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
bzero(&extra, ETHER_ADDR_LEN);
- net_os_wake_lock_timeout_enable(dev);
}
else {
memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
@@ -6120,16 +7377,23 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN);
#ifdef SOFTAP
+#ifdef AP_ONLY
+ if (ap_cfg_running) {
+#else
if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
+#endif
WL_SOFTAP(("AP UP %d\n", event_type));
wl_iw_send_priv_event(priv_dev, "AP_UP");
} else {
WL_TRACE(("STA_LINK_UP\n"));
+ roam_no_success_send = FALSE;
+ roam_no_success = 0;
}
#endif
WL_TRACE(("Link UP\n"));
}
+ net_os_wake_lock_timeout_enable(dev);
wrqu.addr.sa_family = ARPHRD_ETHER;
break;
case WLC_E_ACTION_FRAME:
@@ -6210,15 +7474,30 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
} else {
cmd = SIOCGIWSCAN;
wrqu.data.length = strlen(extra);
- WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan\n"));
+ WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n", \
+ g_iscan->iscan_state));
}
#else
cmd = SIOCGIWSCAN;
wrqu.data.length = strlen(extra);
WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
-#endif
+#endif
break;
+ case WLC_E_PFN_NET_FOUND:
+ {
+ wlc_ssid_t * ssid;
+ ssid = (wlc_ssid_t *)data;
+ WL_TRACE(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", \
+ __FUNCTION__, PNO_EVENT_UP, ssid->SSID, ssid->SSID_len));
+ net_os_wake_lock_timeout_enable(dev);
+ cmd = IWEVCUSTOM;
+ memset(&wrqu, 0, sizeof(wrqu));
+ strcpy(extra, PNO_EVENT_UP);
+ wrqu.data.length = strlen(extra);
+ }
+ break;
+
default:
WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
@@ -6247,8 +7526,8 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
}
#endif
wl_iw_event_end:
- net_os_wake_unlock(dev);
-#endif
+ net_os_wake_unlock(dev);
+#endif
}
int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
@@ -6416,7 +7695,7 @@ _bt_dhcp_sysioc_thread(void *data)
g_bt->bt_state = BT_DHCP_IDLE;
g_bt->timer_on = 0;
break;
- }
+ }
net_os_wake_unlock(g_bt->dev);
}
@@ -6480,6 +7759,7 @@ wl_iw_bt_init(struct net_device *dev)
int wl_iw_attach(struct net_device *dev, void * dhdp)
{
+ int params_size;
wl_iw_t *iw;
#if defined(WL_IW_USE_ISCAN)
iscan_info_t *iscan = NULL;
@@ -6492,19 +7772,33 @@ int wl_iw_attach(struct net_device *dev, void * dhdp)
if (!dev)
return 0;
+ memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
+
+#ifdef CSCAN
+ params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
+ (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
+#else
+ params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
+#endif
iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
if (!iscan)
return -ENOMEM;
memset(iscan, 0, sizeof(iscan_info_t));
+
+ iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
+ if (!iscan->iscan_ex_params_p)
+ return -ENOMEM;
+ iscan->iscan_ex_param_size = params_size;
iscan->sysioc_pid = -1;
g_iscan = iscan;
iscan->dev = dev;
iscan->iscan_state = ISCAN_STATE_IDLE;
g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
+ g_first_counter_scans = 0;
g_iscan->scan_flag = 0;
- iscan->timer_ms = 3000;
+ iscan->timer_ms = 8000;
init_timer(&iscan->timer);
iscan->timer.data = (ulong)iscan;
iscan->timer.function = wl_iw_timerfunc;
@@ -6530,11 +7824,12 @@ int wl_iw_attach(struct net_device *dev, void * dhdp)
memset(g_scan, 0, G_SCAN_RESULTS);
g_scan_specified_ssid = 0;
+#if !defined(CSCAN)
wl_iw_init_ss_cache_ctrl();
+#endif
wl_iw_bt_init(dev);
-
return 0;
}
@@ -6556,6 +7851,7 @@ void wl_iw_detach(void)
kfree(iscan->list_hdr);
iscan->list_hdr = buf;
}
+ kfree(iscan->iscan_ex_params_p);
kfree(iscan);
g_iscan = NULL;
mutex_unlock(&wl_cache_lock);
@@ -6565,7 +7861,9 @@ void wl_iw_detach(void)
kfree(g_scan);
g_scan = NULL;
+#if !defined(CSCAN)
wl_iw_release_ss_cache_ctrl();
+#endif
wl_iw_bt_release();
#ifdef SOFTAP
if (ap_cfg_running) {
diff --git a/bcm4329/src/wl/sys/wl_iw.h b/bcm4329/src/wl/sys/wl_iw.h
index aea656b..43088cf 100644
--- a/bcm4329/src/wl/sys/wl_iw.h
+++ b/bcm4329/src/wl/sys/wl_iw.h
@@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
- * $Id: wl_iw.h,v 1.5.34.1.6.16 2010/04/19 21:32:10 Exp $
+ * $Id: wl_iw.h,v 1.5.34.1.6.36.4.1 2010/09/10 19:24:30 Exp $
*/
@@ -34,6 +34,32 @@
#include <proto/ethernet.h>
#include <wlioctl.h>
+#define WL_SCAN_PARAMS_SSID_MAX 10
+#define GET_SSID "SSID="
+#define GET_CHANNEL "CH="
+#define GET_NPROBE "NPROBE="
+#define GET_ACTIVE_ASSOC_DWELL "ACTIVE="
+#define GET_PASSIVE_ASSOC_DWELL "PASSIVE="
+#define GET_HOME_DWELL "HOME="
+#define GET_SCAN_TYPE "TYPE="
+
+#define BAND_GET_CMD "GETBAND"
+#define BAND_SET_CMD "SETBAND"
+#define DTIM_SKIP_GET_CMD "DTIMSKIPGET"
+#define DTIM_SKIP_SET_CMD "DTIMSKIPSET"
+#define SETSUSPEND_CMD "SETSUSPENDOPT"
+#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR"
+#define PNOSETUP_SET_CMD "PNOSETUP "
+#define PNOENABLE_SET_CMD "PNOFORCE"
+#define PNODEBUG_SET_CMD "PNODEBUG"
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+
+typedef struct wl_iw_extra_params {
+ int target_channel;
+} wl_iw_extra_params_t;
#define WL_IW_RSSI_MINVAL -200
#define WL_IW_RSSI_NO_SIGNAL -91
@@ -61,7 +87,7 @@
#define AP_LPB_CMD (SIOCIWFIRSTPRIV+23)
#define WL_AP_STOP (SIOCIWFIRSTPRIV+25)
#define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27)
-#define WL_AP_SPARE2 (SIOCIWFIRSTPRIV+29)
+#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+29)
#define WL_AP_SPARE3 (SIOCIWFIRSTPRIV+31)
#define G_SCAN_RESULTS (8*1024)
#define WE_ADD_EVENT_FIX 0x80
@@ -95,7 +121,7 @@ typedef struct wl_iw {
#define WLC_IW_BSS_INFO_MAXLEN \
(WLC_IW_SS_CACHE_MAXLEN - WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)
-typedef struct wl_iw_ss_cache{
+typedef struct wl_iw_ss_cache {
uint32 buflen;
uint32 version;
uint32 count;
@@ -166,6 +192,11 @@ extern int net_os_wake_lock(struct net_device *dev);
extern int net_os_wake_unlock(struct net_device *dev);
extern int net_os_wake_lock_timeout(struct net_device *dev);
extern int net_os_wake_lock_timeout_enable(struct net_device *dev);
+extern int net_os_set_suspend_disable(struct net_device *dev, int val);
+extern int net_os_set_suspend(struct net_device *dev, int val);
+extern int net_os_set_dtim_skip(struct net_device *dev, int val);
+extern int net_os_set_packet_filter(struct net_device *dev, int val);
+extern int net_os_send_hang_message(struct net_device *dev);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
@@ -183,4 +214,65 @@ extern int net_os_wake_lock_timeout_enable(struct net_device *dev);
iwe_stream_add_point(stream, ends, iwe, extra)
#endif
-#endif
+extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
+extern int dhd_pno_clean(dhd_pub_t *dhd);
+extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr);
+extern int dhd_pno_get_status(dhd_pub_t *dhd);
+extern int dhd_dev_pno_reset(struct net_device *dev);
+extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, \
+ int nssid, ushort scan_fr);
+extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
+extern int dhd_dev_get_pno_status(struct net_device *dev);
+
+#define PNO_TLV_PREFIX 'S'
+#define PNO_TLV_VERSION 1
+#define PNO_TLV_SUBVERSION 1
+#define PNO_TLV_RESERVED 0
+#define PNO_TLV_TYPE_SSID_IE 'S'
+#define PNO_TLV_TYPE_TIME 'T'
+#define PNO_EVENT_UP "PNO_EVENT"
+
+typedef struct cmd_tlv {
+ char prefix;
+ char version;
+ char subver;
+ char reserved;
+} cmd_tlv_t;
+
+#if defined(CSCAN)
+
+typedef struct cscan_tlv {
+ char prefix;
+ char version;
+ char subver;
+ char reserved;
+} cscan_tlv_t;
+
+#define CSCAN_COMMAND "CSCAN "
+#define CSCAN_TLV_PREFIX 'S'
+#define CSCAN_TLV_VERSION 1
+#define CSCAN_TLV_SUBVERSION 0
+#define CSCAN_TLV_TYPE_SSID_IE 'S'
+#define CSCAN_TLV_TYPE_CHANNEL_IE 'C'
+#define CSCAN_TLV_TYPE_NPROBE_IE 'N'
+#define CSCAN_TLV_TYPE_ACTIVE_IE 'A'
+#define CSCAN_TLV_TYPE_PASSIVE_IE 'P'
+#define CSCAN_TLV_TYPE_HOME_IE 'H'
+#define CSCAN_TLV_TYPE_STYPE_IE 'T'
+
+extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \
+ int channel_num, int *bytes_left);
+
+extern int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, \
+ const char token, int input_size, int *bytes_left);
+
+extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, \
+ int max, int *bytes_left);
+
+extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max);
+
+extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num);
+
+#endif
+
+#endif