diff options
author | Howard M. Harte <hharte@broadcom.com> | 2010-07-27 16:40:06 -0700 |
---|---|---|
committer | Howard M. Harte <hharte@broadcom.com> | 2010-07-27 16:40:06 -0700 |
commit | dd0ed55b6892078730078b3b971d2768954891c4 (patch) | |
tree | 836ebf982573ebc6f607a8b564665ce575a70869 | |
parent | 5a838529e6197475cbe8f5a4557fbd31f90586a6 (diff) | |
download | broadcom-dd0ed55b6892078730078b3b971d2768954891c4.tar.gz |
Update driver to RC243.
Change-Id: Ie5a9b6f902fefea100b4d288397fd08db0a6e850
30 files changed, 2249 insertions, 258 deletions
diff --git a/bcm4329/src/dhd/linux/Makefile b/bcm4329/src/dhd/linux/Makefile index 94f1712..e25b395 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.39 2010/04/20 02:30:25 Exp $ +# $Id: Makefile,v 1.55.2.6.2.10.6.40 2010/04/29 23:29:33 Exp $ # # Try a couple of places for LINUXDIR if not specified @@ -228,8 +228,7 @@ DFLAGS += -DSOFTAP CFILES += sha1.c md5.c endif ifneq ($(findstring -nexus-,-$(TARGET)-),) -DFLAGS += -DEMBEDDED_PLATFORM -DFLAGS += -DOEM_ANDROID +DFLAGS += -DOEM_ANDROID -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT DFLAGS += -DBCMDBG DFLAGS += -DDHD_USE_STATIC_BUF DFLAGS += -DCUSTOMER_HW2 diff --git a/bcm4329/src/dhd/sys/dhd.h b/bcm4329/src/dhd/sys/dhd.h index 08e0fb8..1c5f8dd 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.35.4.2 2010/05/18 03:54:02 Exp $ + * $Id: dhd.h,v 1.32.4.7.2.4.14.44 2010/06/03 21:27:48 Exp $ */ /**************** @@ -35,6 +35,9 @@ #define _dhd_h_ #if defined(LINUX) +#if defined(CHROMIUMOS_COMPAT_WIRELESS) +#include <linux/sched.h> +#endif #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -180,10 +183,10 @@ typedef struct dhd_pub { #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_timeout(a, FALSE, HZ/100); \ - countdown -= 10; \ + countdown -= 10000; \ } \ } while (0) @@ -249,6 +252,31 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 +extern struct mutex g_wl_ss_scan_lock; /* lock/unlock for Scan/Cache settings */ +#endif + +inline static void MUTEX_LOCK_WL_SCAN_SET_INIT(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + mutex_init(&g_wl_ss_scan_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +inline static void MUTEX_LOCK_WL_SCAN_SET(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + mutex_lock(&g_wl_ss_scan_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + +inline static void MUTEX_UNLOCK_WL_SCAN_SET(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + mutex_unlock(&g_wl_ss_scan_lock); +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ +} + inline static void WAKE_LOCK_INIT(dhd_pub_t * dhdp, int index, char * y) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) @@ -350,9 +378,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) */ @@ -420,7 +452,7 @@ extern uint dhd_watchdog_ms; #if defined(DHD_DEBUG) /* Console output poll interval */ extern uint dhd_console_ms; -#endif +#endif /* defined(DHD_DEBUG) */ /* Use interrupts */ extern uint dhd_intr; @@ -437,6 +469,9 @@ 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; diff --git a/bcm4329/src/dhd/sys/dhd_bus.h b/bcm4329/src/dhd/sys/dhd_bus.h index 7156543..9e29fb9 100644 --- a/bcm4329/src/dhd/sys/dhd_bus.h +++ b/bcm4329/src/dhd/sys/dhd_bus.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_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 8829ef4..e98af39 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.36 2010/04/14 12:09:11 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 @@ -40,6 +40,9 @@ #include <dhd_proto.h> #include <dhd_bus.h> #include <dhd_dbg.h> +#ifdef CUSTOMER_HW2 +int wifi_get_mac_addr(unsigned char *buf); +#endif extern int dhd_preinit_ioctls(dhd_pub_t *dhd); @@ -207,7 +210,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); @@ -521,10 +524,13 @@ dhd_prot_init(dhd_pub_t *dhd) strcpy(buf, "cur_etheraddr"); ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf)); if (ret < 0) { - goto fail; + dhd_os_proto_unblock(dhd); + return ret; } memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); + dhd_os_proto_unblock(dhd); + #ifdef EMBEDDED_PLATFORM ret = dhd_preinit_ioctls(dhd); #endif /* EMBEDDED_PLATFORM */ @@ -532,9 +538,6 @@ dhd_prot_init(dhd_pub_t *dhd) /* Always assumes wl for now */ dhd->iswl = TRUE; -fail: - dhd_os_proto_unblock(dhd); - return ret; } diff --git a/bcm4329/src/dhd/sys/dhd_common.c b/bcm4329/src/dhd/sys/dhd_common.c index 37ea7e9..15a91fb 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.46 2010/04/21 09:54:43 Exp $ + * $Id: dhd_common.c,v 1.5.6.8.2.6.6.65 2010/07/07 00:05:07 Exp $ */ #include <typedefs.h> #include <osl.h> @@ -43,6 +43,10 @@ int dhd_msg_level; +#if defined(CSCAN) +#include <wl_iw.h> +#endif + char fw_path[MOD_PARAM_PATHLEN]; char nv_path[MOD_PARAM_PATHLEN]; @@ -55,7 +59,12 @@ uint32 dhd_conn_reason; #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 @@ -65,7 +74,6 @@ extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint #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__; @@ -75,7 +83,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, @@ -84,6 +91,10 @@ enum { IOV_BCMERROR, IOV_WDTICK, IOV_DUMP, +#ifdef DHD_DEBUG + IOV_CONS, + IOV_DCONSOLE_POLL, +#endif IOV_CLEARCOUNTS, IOV_LOGDUMP, IOV_LOGCAL, @@ -102,6 +113,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 }, @@ -242,6 +257,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; @@ -1212,6 +1242,29 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint bcn_timeout = 3; int scan_assoc_time = 40; int scan_unassoc_time = 80; +#ifdef GET_CUSTOM_MAC_ENABLE + int ret = 0; + 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 */ /* Set Country code */ if (dhd->country_code[0] != 0) { @@ -1277,11 +1330,647 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) for (i = 0; i < dhd->pktfilter_count; i++) { dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 1, dhd_master_mode); + 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(¶ms, 0, sizeof(wl_iscan_params_t)); + memcpy(¶ms.params.bssid, ðer_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 *)¶ms, 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 + +/* Android ComboSCAN support */ +#if defined(CSCAN) + +/* + * 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 cb67ae2..7a98762 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.7 2010/06/03 21:27:48 Exp $ */ @@ -148,3 +148,26 @@ dhd_customer_gpio_wlan_ctrl(int onoff) break; } } + +#ifdef GET_CUSTOM_MAC_ENABLE +/* Function to get custom MAC address */ +int +dhd_custom_get_mac_address(unsigned char *buf) +{ + WL_TRACE(("%s Enter\n", __FUNCTION__)); + if (!buf) + return -EINVAL; + + /* Customer access to MAC address stored outside of DHD driver */ + +#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 0; +} +#endif /* GET_CUSTOM_MAC_ENABLE */ diff --git a/bcm4329/src/dhd/sys/dhd_dbg.h b/bcm4329/src/dhd/sys/dhd_dbg.h index a4f180c..9f09ce7 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.9 2010/04/20 05:27:52 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 /* (defined BCMDBG) || (defined 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 #define DHD_LOG(args) diff --git a/bcm4329/src/dhd/sys/dhd_linux.c b/bcm4329/src/dhd/sys/dhd_linux.c index 1b3f611..f1ddba4 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.79.2.2 2010/05/18 01:39:35 Exp $ + * $Id: dhd_linux.c,v 1.65.4.9.2.12.2.87 2010/06/23 00:14:28 Exp $ */ #ifdef CONFIG_WIFI_CONTROL_FUNC @@ -298,20 +298,24 @@ module_param(dhd_watchdog_ms, uint, 0); /* Console poll interval */ uint dhd_console_ms = 0; module_param(dhd_console_ms, uint, 0); -#endif +#endif /* DHD_DEBUG */ -/* ARP offload agent mode */ -uint dhd_arp_mode = 0; +/* 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 = FALSE; +uint dhd_arp_enable = TRUE; module_param(dhd_arp_enable, uint, 0); -/* Pkt filte enable control */ -uint dhd_pkt_filter_enable = FALSE; +/* 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); @@ -484,6 +488,8 @@ int dhd_set_suspend(int value, dhd_pub_t *dhd) if (dhd && dhd->up) { dhd_os_proto_block(dhd); if (value) { + + /* Kernel suspended */ dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); @@ -506,6 +512,8 @@ int dhd_set_suspend(int value, dhd_pub_t *dhd) dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf)); #endif /* CUSTOMER_HW2 */ } else { + + /* Kernel resumed */ power_mode = PM_FAST; dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode)); @@ -2247,7 +2255,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) 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]); -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) && !defined(CSCAN) #ifdef SOFTAP if (ifidx == 0) /* Don't call for SOFTAP Interface in SOFTAP MODE */ @@ -2551,6 +2559,7 @@ dhd_os_wd_timer(void *bus, uint wdtick) /* 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) { del_timer(&dhd->timer); @@ -2835,3 +2844,40 @@ 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 */ diff --git a/bcm4329/src/dhd/sys/dhd_proto.h b/bcm4329/src/dhd/sys/dhd_proto.h index 79584d6..382785a 100644 --- a/bcm4329/src/dhd/sys/dhd_proto.h +++ b/bcm4329/src/dhd/sys/dhd_proto.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_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_ @@ -37,6 +37,10 @@ #define IOCTL_RESP_TIMEOUT 2000 /* In milli second */ #endif +#ifndef IOCTL_CHIP_ACTIVE_TIMEOUT +#define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */ +#endif + /* * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) */ diff --git a/bcm4329/src/dhd/sys/dhd_sdio.c b/bcm4329/src/dhd/sys/dhd_sdio.c index aa938de..127260a 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.2.2 2010/05/18 01:13:11 Exp $ + * $Id: dhd_sdio.c,v 1.157.2.27.2.33.2.126 2010/06/15 23:38:39 Exp $ */ #include <typedefs.h> @@ -551,6 +551,7 @@ dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); DHD_INFO(("CLKCTL: set PENDING\n")); bus->clkstate = CLK_PENDING; + return BCME_OK; } else if (bus->clkstate == CLK_PENDING) { /* Cancel CA-only interrupt filter */ @@ -956,7 +957,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)]++; @@ -1022,6 +1022,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: @@ -1073,7 +1076,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++; @@ -1109,6 +1112,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 @@ -1263,6 +1267,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; @@ -1270,15 +1276,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); @@ -1288,8 +1295,10 @@ 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); if (ret < 0) { @@ -1316,6 +1325,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); } @@ -1727,78 +1739,6 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) return BCME_OK; } -#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; -} - static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) { @@ -1891,7 +1831,7 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) goto done; bcm_bprintf(&strbuf, - "Dongle trap type 0x%x @ pc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," + "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, @@ -1904,10 +1844,12 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size) DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); } +#ifdef DHD_DEBUG if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - /* Mem dump to a file on device */ - dhdsdio_mem_dump(bus); + /* Mem dump to a file on device */ + dhdsdio_mem_dump(bus); } +#endif /* DHD_DEBUG */ done: if (mbuffer) @@ -1922,9 +1864,125 @@ static int dhdsdio_mem_dump(dhd_bus_t *bus) { int ret = 0; - return ret; + 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"); + + /* 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 */ + return 0; } -#endif + +#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) @@ -4173,7 +4231,7 @@ clkwait: 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, @@ -4205,13 +4263,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); @@ -4226,7 +4287,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 */ @@ -4250,7 +4313,6 @@ clkwait: bool dhd_bus_dpc(struct dhd_bus *bus) { -#ifdef SDIO_ISR_THREAD bool resched; /* Call the DPC directly. */ @@ -4258,9 +4320,6 @@ dhd_bus_dpc(struct dhd_bus *bus) resched = dhdsdio_dpc(bus); return resched; -#else - return dhdsdio_dpc(bus); -#endif /* SDIO_ISR_THREAD */ } void @@ -4269,6 +4328,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; @@ -4279,9 +4340,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; @@ -4637,6 +4695,7 @@ dhd_bus_watchdog(dhd_pub_t *dhdp) bus->idlecount = 0; if (bus->activity) { bus->activity = FALSE; + dhd_os_wd_timer(bus->dhd,dhd_watchdog_ms); } else { dhdsdio_clkctl(bus, CLK_NONE, FALSE); } @@ -4648,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/include/bcmdefs.h b/bcm4329/src/include/bcmdefs.h index f4e9946..e3c6876 100644 --- a/bcm4329/src/include/bcmdefs.h +++ b/bcm4329/src/include/bcmdefs.h @@ -29,6 +29,7 @@ #define STATIC static + #define SI_BUS 0 #define PCI_BUS 1 #define PCMCIA_BUS 2 diff --git a/bcm4329/src/include/bcmdevs.h b/bcm4329/src/include/bcmdevs.h index cad7d31..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.33 2010/04/05 06:52:57 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/bcmsdpcm.h b/bcm4329/src/include/bcmsdpcm.h index 450c9c3..77aca45 100644 --- a/bcm4329/src/include/bcmsdpcm.h +++ b/bcm4329/src/include/bcmsdpcm.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: 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/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/dhdioctl.h b/bcm4329/src/include/dhdioctl.h index 706b4a8..980a143 100644 --- a/bcm4329/src/include/dhdioctl.h +++ b/bcm4329/src/include/dhdioctl.h @@ -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 a76ea3f..42704f0 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 243 -#define EPI_INCREMENTAL_NUMBER 1 +#define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 4, 218, 223, 1 +#define EPI_VERSION 4, 218, 243, 0 -#define EPI_VERSION_NUM 0x04dadf01 +#define EPI_VERSION_NUM 0x04daf300 -#define EPI_VERSION_STR "4.218.223.1" -#define EPI_ROUTER_VERSION_STR "4.219.223.1" +#define EPI_VERSION_STR "4.218.243.0" +#define EPI_ROUTER_VERSION_STR "4.219.243.0" #endif diff --git a/bcm4329/src/include/linux_osl.h b/bcm4329/src/include/linux_osl.h index 6c9597d..b059c2a 100644 --- a/bcm4329/src/include/linux_osl.h +++ b/bcm4329/src/include/linux_osl.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: linux_osl.h,v 13.131.30.7 2010/03/29 19:03:11 Exp $ + * $Id: linux_osl.h,v 13.131.30.8 2010/04/26 05:42:18 Exp $ */ @@ -319,9 +319,4 @@ extern int osl_error(int bcmerror); #define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ)) - -#define FILE void -#define F_OPEN(fp, mode) NULL -#define F_WRITE(buf, w_size, len, fp) do { } while (0) -#define F_CLOSE(fp) do { } while (0) #endif diff --git a/bcm4329/src/include/linuxver.h b/bcm4329/src/include/linuxver.h index c329ec2..6ee5c58 100644 --- a/bcm4329/src/include/linuxver.h +++ b/bcm4329/src/include/linuxver.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: linuxver.h,v 13.38.8.1.8.5 2010/02/04 13:47:16 Exp $ + * $Id: linuxver.h,v 13.38.8.1.8.6 2010/04/29 05:00:46 Exp $ */ @@ -33,8 +33,12 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) #include <linux/config.h> #else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) +#include <generated/autoconf.h> +#else #include <linux/autoconf.h> #endif +#endif #include <linux/module.h> #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)) 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/ethernet.h b/bcm4329/src/include/proto/ethernet.h index c2fc4bf..9ad2ea0 100644 --- a/bcm4329/src/include/proto/ethernet.h +++ b/bcm4329/src/include/proto/ethernet.h @@ -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/sbchipc.h b/bcm4329/src/include/sbchipc.h index 39e5c8d..05b3fd8 100644 --- a/bcm4329/src/include/sbchipc.h +++ b/bcm4329/src/include/sbchipc.h @@ -1001,6 +1001,7 @@ typedef volatile struct { #define CST4315_CBUCK_MODE_BURST 0x00000400 #define CST4315_CBUCK_MODE_LPBURST 0x00000c00 + #define PMU_MAX_TRANSITION_DLY 15000 diff --git a/bcm4329/src/include/siutils.h b/bcm4329/src/include/siutils.h index c3e1b29..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.15 2010/04/19 05:21:30 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/wlioctl.h b/bcm4329/src/include/wlioctl.h index 6324156..d346945 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.61 2010/05/04 20:26:25 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 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/linux_osl.c b/bcm4329/src/shared/linux_osl.c index c2f5682..242af39 100644 --- a/bcm4329/src/shared/linux_osl.c +++ b/bcm4329/src/shared/linux_osl.c @@ -21,12 +21,14 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.c,v 1.125.12.3.8.6 2009/12/09 01:29:03 Exp $ + * $Id: linux_osl.c,v 1.125.12.3.8.7 2010/05/04 21:10:04 Exp $ */ #define LINUX_OSL - +#if defined(CHROMIUMOS_COMPAT_WIRELESS) +#include <linux/sched.h> +#endif #include <typedefs.h> #include <bcmendian.h> #include <linuxver.h> @@ -509,7 +511,7 @@ osl_mfree(osl_t *osh, void *addr, uint size) #ifdef DHD_USE_STATIC_BUF if (bcm_static_buf) { - if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr \ + if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN))) { int buf_idx = 0; diff --git a/bcm4329/src/shared/siutils.c b/bcm4329/src/shared/siutils.c index 4ec0501..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.27 2010/04/19 05:21:23 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/wl/sys/wl_cfg80211.c b/bcm4329/src/wl/sys/wl_cfg80211.c index 45a2907..81491cb 100644 --- a/bcm4329/src/wl/sys/wl_cfg80211.c +++ b/bcm4329/src/wl/sys/wl_cfg80211.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_cfg80211.c,v 1.1.2.23 2010/04/19 17:10:31 Exp $ + * $Id: wl_cfg80211.c,v 1.1.2.28 2010/05/04 21:43:38 Exp $ */ #include <typedefs.h> @@ -51,6 +51,7 @@ #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> @@ -65,8 +66,8 @@ uint32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO | WL_DBG_DBG; uint32 wl_dbg_level = WL_DBG_ERR | WL_DBG_INFO; #endif -#define WL_4329_FW_FILE "brcm/4329/fw_4329.bin" -#define WL_4329_NVRAM_FILE "brcm/4329/nvram_4329.txt" +#define WL_4329_FW_FILE "brcm/fw_4329.bin" +#define WL_4329_NVRAM_FILE "brcm/nvram_4329.txt" /* ** cfg80211_ops api/callback list @@ -107,8 +108,14 @@ 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 */ @@ -122,19 +129,21 @@ 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, wl_event_msg_t *msg, void *data); +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, - wl_event_msg_t *e, void* data); + const wl_event_msg_t *e, void* data); static int32 wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, - wl_event_msg_t *e, void* data); + const wl_event_msg_t *e, void* data); static int32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, - wl_event_msg_t *e, void* data); + const wl_event_msg_t *e, void* data); static int32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, - wl_event_msg_t *e, void* data); + const wl_event_msg_t *e, void* data); static int32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, - wl_event_msg_t *e, void* data); + 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 @@ -146,6 +155,7 @@ 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); @@ -161,7 +171,7 @@ 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, wl_event_msg_t *e, void *data, int32 item); +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); @@ -230,8 +240,8 @@ static bool wl_is_ibssstarter(struct wl_priv *wl); /* ** dongle up/down , default configuration utilities */ -static bool wl_is_linkdown(struct wl_priv *wl, wl_event_msg_t *e); -static bool wl_is_linkup(struct wl_priv *wl, wl_event_msg_t *e); +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); @@ -289,6 +299,18 @@ static int32 wl_iscan_aborted(struct wl_priv *wl); */ 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; \ @@ -634,7 +656,7 @@ wl_dev_iovar_setbuf(struct net_device *dev, int8 *iovar, void *param, int32 iolen; iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); - ASSERT(iolen); + BUG_ON(unlikely(!iolen)); return wl_dev_ioctl(dev, WLC_SET_VAR, bufptr, iolen); } @@ -646,7 +668,7 @@ wl_dev_iovar_getbuf(struct net_device *dev, int8 *iovar, void *param, int32 iolen; iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen); - ASSERT(iolen); + BUG_ON(unlikely(!iolen)); return wl_dev_ioctl(dev, WLC_GET_VAR, bufptr, buflen); } @@ -667,7 +689,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, uint16 action) if (unlikely(!params)) return -ENOMEM; memset(params, 0, params_size); - ASSERT(params_size < WLC_IOCTL_SMLEN); + BUG_ON(unlikely(params_size >= WLC_IOCTL_SMLEN)); wl_iscan_prep(¶ms->params, ssid); @@ -861,7 +883,7 @@ wl_dev_intvar_set(struct net_device *dev, int8 *name, int32 val) val = htod32(val); len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); - ASSERT(len); + BUG_ON(unlikely(!len)); if (unlikely((err = wl_dev_ioctl(dev, WLC_SET_VAR, buf, len)))) { WL_ERR(("error (%d)\n", err)); @@ -882,7 +904,7 @@ wl_dev_intvar_get(struct net_device *dev, int8 *name, int32 *retval) int32 err = 0; len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf)); - ASSERT(len); + BUG_ON(unlikely(!len)); if (unlikely((err = wl_dev_ioctl(dev, WLC_GET_VAR, &var, len)))) { WL_ERR(("error (%d)\n", err)); } @@ -1090,10 +1112,8 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) #endif if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; -#ifdef BCMWPA2 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; -#endif else val = WPA_AUTH_DISABLED; WL_DBG(("setting wpa_auth to 0x%0x\n", val)); @@ -1254,9 +1274,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) sme->crypto.cipher_group)); return -EINVAL; } - } -#ifdef BCMWPA2 - else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { switch (sme->crypto.akm_suites[0]) { case WLAN_AKM_SUITE_8021X: val = WPA2_AUTH_UNSPECIFIED; @@ -1270,7 +1288,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) return -EINVAL; } } -#endif + 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)); @@ -1530,6 +1548,7 @@ 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 @@ -1538,11 +1557,19 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, uint WL_DBG(("key index (%d)\n", key_idx)); CHECK_SYS_UP(); - /* 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)); + 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")); @@ -1791,6 +1818,9 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, { 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 @@ -1801,34 +1831,37 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, memset(&key, 0, sizeof(key)); key.index = key_idx; - if (unlikely((err = wl_dev_ioctl(dev, WLC_GET_KEY, &key, sizeof(key))))) { - WL_ERR(("WLC_GET_KEY error (%d)\n", err)); - return err; - } swap_key_to_BE(&key); memset(¶ms, 0, sizeof(params)); params.key_len = (uint8)MIN(DOT11_MAX_KEY_SIZE, key.len); memcpy(params.key, key.data, params.key_len); - switch (key.algo) { - case CRYPTO_ALGO_WEP1: - params.cipher = WLAN_CIPHER_SUITE_WEP40; - WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); - break; - case CRYPTO_ALGO_WEP128: - params.cipher = WLAN_CIPHER_SUITE_WEP104; - WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n")); + 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 CRYPTO_ALGO_TKIP: + case TKIP_ENABLED: params.cipher = WLAN_CIPHER_SUITE_TKIP; WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n")); break; - case CRYPTO_ALGO_AES_CCM: + 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", key.algo)); + WL_ERR(("Invalid algo (0x%x)\n", wsec)); return -EINVAL; } @@ -1924,7 +1957,36 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, 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) @@ -1934,8 +1996,68 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, int32 val; int32 err_bg; int32 err_a; + uint32 legacy; int32 err = 0; - int32 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 (!(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")); @@ -2010,6 +2132,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, return err; } +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) */ static int32 wl_cfg80211_resume(struct wiphy *wiphy) @@ -2055,6 +2178,148 @@ wl_cfg80211_suspend(struct wiphy *wiphy) 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, @@ -2075,6 +2340,12 @@ static struct cfg80211_ops wl_cfg80211_ops = { .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 @@ -2122,7 +2393,8 @@ wl_alloc_wdev(int32 sizeof_iface, struct device *dev) } set_wiphy_dev(wdev->wiphy, dev); wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) +#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); @@ -2136,10 +2408,22 @@ wl_alloc_wdev(int32 sizeof_iface, struct device *dev) 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; @@ -2185,8 +2469,8 @@ wl_inform_bss(struct wl_priv *wl) { struct wl_scan_results *bss_list; struct wl_bss_info *bi = NULL; /* must be initialized */ - int32 i; int32 err = 0; + int i; bss_list = wl->bss_list; @@ -2268,7 +2552,7 @@ wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) } static bool -wl_is_linkup(struct wl_priv *wl, wl_event_msg_t *e) +wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e) { uint32 event = ntoh32(e->event_type); uint16 flags = ntoh16(e->flags); @@ -2290,7 +2574,7 @@ wl_is_linkup(struct wl_priv *wl, wl_event_msg_t *e) } static bool -wl_is_linkdown(struct wl_priv *wl, wl_event_msg_t *e) +wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e) { uint32 event = ntoh32(e->event_type); uint16 flags = ntoh16(e->flags); @@ -2307,7 +2591,8 @@ wl_is_linkdown(struct wl_priv *wl, wl_event_msg_t *e) } static int32 -wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t *e, void* data) +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; @@ -2341,7 +2626,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, wl_event_m } static int32 -wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t *e, void* data) +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; @@ -2359,18 +2645,27 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, wl_event_m 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) +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); - ASSERT(len); + 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)); @@ -2479,7 +2774,8 @@ update_bss_info_out: } static int32 -wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t *e, void* data) +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; @@ -2506,7 +2802,8 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t } static int32 -wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t *e, void* data) +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; @@ -2542,7 +2839,34 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t } static int32 -wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, wl_event_msg_t *e, void* data) +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; @@ -2631,6 +2955,7 @@ wl_init_eloop_handler(struct wl_event_loop *el) 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 @@ -2681,6 +3006,11 @@ wl_init_priv_mem(struct wl_priv *wl) 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; @@ -2729,6 +3059,10 @@ wl_deinit_priv_mem(struct wl_priv *wl) kfree(wl->fw); wl->fw = NULL; } + if (wl->pmk_list) { + kfree(wl->pmk_list); + wl->pmk_list = NULL; + } } @@ -3048,7 +3382,12 @@ wl_init_priv(struct wl_priv *wl) 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 @@ -3213,7 +3552,7 @@ wl_event_handler(void *data) } void -wl_cfg80211_event(struct net_device *ndev, wl_event_msg_t *e, void* data) +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); @@ -3271,7 +3610,7 @@ wl_deq_event(struct wl_priv *wl) */ static int32 -wl_enq_event(struct wl_priv *wl, uint32 event, wl_event_msg_t *msg, void *data) +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; @@ -3544,7 +3883,7 @@ static int32 wl_pattern_atoh(int8 *src, int8 *dst) { #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) - int32 i; + int i; if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { WL_ERR(("Mask invalid format. Needs to start with 0x\n")); @@ -3847,7 +4186,7 @@ wl_read_prof(struct wl_priv *wl, int32 item) } static int32 -wl_update_prof(struct wl_priv *wl, wl_event_msg_t *e, void *data, int32 item) +wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, int32 item) { int32 err = 0; struct wlc_ssid *ssid; diff --git a/bcm4329/src/wl/sys/wl_cfg80211.h b/bcm4329/src/wl/sys/wl_cfg80211.h index 79c7cf9..2722699 100644 --- a/bcm4329/src/wl/sys/wl_cfg80211.h +++ b/bcm4329/src/wl/sys/wl_cfg80211.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_cfg80211.h,v 1.1.2.17 2010/04/13 04:45:43 Exp $ + * $Id: wl_cfg80211.h,v 1.1.2.19 2010/05/04 21:21:00 Exp $ */ #ifndef _wl_cfg80211_h_ @@ -96,11 +96,14 @@ struct wl_ibss; #define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */ #define WL_NUM_SCAN_MAX 1 -#define WL_NUM_PMKIDS_MAX 4 /* will be used for 2.6.33 kernel or later */ +#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 +#define WL_ASSOC_INFO_MAX 512 /* + * needs to grab assoc info from dongle to * report it to cfg80211 through "connect" * event */ @@ -169,7 +172,7 @@ struct wl_conf { /* cfg80211 main event loop */ struct wl_event_loop { int32 (*handler[WLC_E_LAST])(struct wl_priv *wl, struct net_device *ndev, - wl_event_msg_t *e, void *data); + const wl_event_msg_t *e, void *data); }; /* representing interface of cfg80211 plane */ @@ -282,6 +285,12 @@ struct wl_assoc_ielen { 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 { @@ -300,12 +309,13 @@ struct wl_priv { struct ether_addr bssid; /* bssid of currently engaged network */ struct semaphore event_sync; /* for synchronization of main event thread */ struct completion event_exit; - int32 event_pid; /* pid of main event handler thread */ - ulong status; /* current dongle status */ 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 */ @@ -316,6 +326,7 @@ struct wl_priv { 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))); @@ -347,7 +358,7 @@ inline static struct wl_bss_info * next_bss(struct wl_scan_results *list, 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, wl_event_msg_t *e, void* data); +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 */ diff --git a/bcm4329/src/wl/sys/wl_iw.c b/bcm4329/src/wl/sys/wl_iw.c index ad138bf..ec52705 100644 --- a/bcm4329/src/wl/sys/wl_iw.c +++ b/bcm4329/src/wl/sys/wl_iw.c @@ -21,9 +21,10 @@ * 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.2.1 2010/05/18 00:12:00 Exp $ + * $Id: wl_iw.c,v 1.51.4.9.2.6.4.116 2010/07/08 00:51:57 Exp $ */ +#include <wlioctl.h> #include <typedefs.h> #include <linuxver.h> @@ -58,7 +59,32 @@ typedef const struct si_pub si_t; -#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> @@ -66,6 +92,10 @@ typedef const struct si_pub si_t; #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 + struct mutex g_wl_ss_scan_lock; +#endif + #if defined(SOFTAP) #define WL_SOFTAP(x) printk x static struct net_device *priv_dev; @@ -135,6 +165,8 @@ static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; static volatile uint g_first_broadcast_scan; + + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define DAEMONIZE(a) daemonize(a); \ allow_signal(SIGKILL); \ @@ -149,8 +181,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 +212,12 @@ 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 + } iscan_info_t; #define COEX_DHCP 1 static void wl_iw_bt_flag_set(struct net_device *dev, bool set); @@ -283,7 +321,7 @@ dev_wlc_ioctl( return ret; } - WL_TRACE(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n", + WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n", __FUNCTION__, current->pid, cmd, arg, len)); memset(&ioc, 0, sizeof(ioc)); ioc.cmd = cmd; @@ -382,6 +420,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)); } @@ -561,6 +602,7 @@ wl_iw_get_macaddr( } + static int wl_iw_set_country( struct net_device *dev, @@ -964,16 +1006,18 @@ 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; -#endif +#endif #if defined(BCMLXSDMMC) sdioh_stop(NULL); @@ -1006,6 +1050,7 @@ wl_iw_control_wl_on( wl_iw_send_priv_event(dev, "START"); +#if !defined(CSCAN) #ifdef SOFTAP if (!ap_fw_loaded) { wl_iw_iscan_set_scan_broadcast_prep(dev, 0); @@ -1013,6 +1058,7 @@ wl_iw_control_wl_on( #else wl_iw_iscan_set_scan_broadcast_prep(dev, 0); #endif +#endif WL_TRACE(("Exited %s \n", __FUNCTION__)); @@ -1568,8 +1614,10 @@ wl_iw_get_range( list->count = htod32(MAXCHANNEL); - if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) + 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]); @@ -1603,8 +1651,10 @@ wl_iw_get_range( #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++) @@ -1640,8 +1690,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; @@ -1715,6 +1767,8 @@ wl_iw_get_range( #endif #endif + kfree(channels); + return 0; } @@ -2088,7 +2142,7 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) return -ENOMEM; } memset(params, 0, params_size); - ASSERT(params_size < WLC_IOCTL_SMLEN); + ASSERT(params_size < sizeof(iscan->ioctlbuf)); err = wl_iw_iscan_prep(¶ms->params, ssid); @@ -2099,7 +2153,7 @@ wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action) (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size, - iscan->ioctlbuf, WLC_IOCTL_SMLEN); + iscan->ioctlbuf, sizeof(iscan->ioctlbuf)); } kfree(params); @@ -2141,6 +2195,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) uint32 status; + MUTEX_LOCK_WL_SCAN_SET(); if (iscan->list_cur) { buf = iscan->list_cur; iscan->list_cur = buf->next; @@ -2150,6 +2205,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) if (!buf) { WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \ __FUNCTION__)); + MUTEX_UNLOCK_WL_SCAN_SET(); return WL_SCAN_RESULTS_NO_MEM; } buf->next = NULL; @@ -2186,6 +2242,7 @@ wl_iw_iscan_get(iscan_info_t *iscan) WL_TRACE(("results->buflen = %d\n", results->buflen)); status = dtoh32(list_buf->status); + MUTEX_UNLOCK_WL_SCAN_SET(); return status; } @@ -2211,8 +2268,10 @@ static void wl_iw_send_scan_complete(iscan_info_t *iscan) wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL); +#if !defined(CSCAN) if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY; +#endif WL_TRACE(("Send Event ISCAN complete\n")); #endif } @@ -2307,6 +2366,7 @@ _iscan_sysioc_thread(void *data) } #endif +#if !defined(CSCAN) static void wl_iw_set_ss_cache_timer_flag(void) @@ -2346,6 +2406,7 @@ wl_iw_free_ss_cache(void) WL_TRACE(("%s called\n", __FUNCTION__)); + MUTEX_LOCK_WL_SCAN_SET(); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; @@ -2356,6 +2417,7 @@ wl_iw_free_ss_cache(void) kfree(cur); } *spec_scan_head = NULL; + MUTEX_UNLOCK_WL_SCAN_SET(); } @@ -2401,6 +2463,7 @@ wl_iw_reset_ss_cache(void) wl_iw_ss_cache_t *node, *prev, *cur; wl_iw_ss_cache_t **spec_scan_head; + MUTEX_LOCK_WL_SCAN_SET(); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; prev = node; @@ -2427,7 +2490,7 @@ wl_iw_reset_ss_cache(void) prev = node; node = node->next; } - + MUTEX_UNLOCK_WL_SCAN_SET(); } @@ -2440,13 +2503,13 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) wl_bss_info_t *bi = NULL; int i; - spec_scan_head = &g_ss_cache_ctrl.m_cache_head; if (!ss_list->count) { return 0; } - + MUTEX_LOCK_WL_SCAN_SET(); + spec_scan_head = &g_ss_cache_ctrl.m_cache_head; for (i = 0; i < ss_list->count; i++) { node = *spec_scan_head; @@ -2469,17 +2532,12 @@ 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) { + MUTEX_UNLOCK_WL_SCAN_SET(); 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; @@ -2493,6 +2551,7 @@ wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list) prev->next = leaf; } } + MUTEX_UNLOCK_WL_SCAN_SET(); return 0; } @@ -2505,6 +2564,7 @@ __u16 *merged_len) wl_iw_ss_cache_t *node; wl_scan_results_t *list_merge; + MUTEX_LOCK_WL_SCAN_SET(); node = g_ss_cache_ctrl.m_cache_head; for (;node;) { list_merge = (wl_scan_results_t *)node; @@ -2519,6 +2579,7 @@ __u16 *merged_len) } node = node->next; } + MUTEX_UNLOCK_WL_SCAN_SET(); return 0; } @@ -2530,6 +2591,7 @@ wl_iw_delete_bss_from_ss_cache(void *addr) wl_iw_ss_cache_t *node, *prev; wl_iw_ss_cache_t **spec_scan_head; + MUTEX_LOCK_WL_SCAN_SET(); spec_scan_head = &g_ss_cache_ctrl.m_cache_head; node = *spec_scan_head; prev = node; @@ -2552,10 +2614,12 @@ wl_iw_delete_bss_from_ss_cache(void *addr) } memset(addr, 0, ETHER_ADDR_LEN); + MUTEX_UNLOCK_WL_SCAN_SET(); return 0; } +#endif static int @@ -2570,6 +2634,11 @@ wl_iw_set_scan( WL_TRACE(("\n:%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) { @@ -2637,6 +2706,7 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) wlc_ssid_t ssid; iscan_info_t *iscan = g_iscan; +#if !defined(CSCAN) if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) { g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED; @@ -2646,6 +2716,7 @@ wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag) WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__)); return 0; } +#endif memset(&ssid, 0, sizeof(ssid)); @@ -2689,6 +2760,11 @@ wl_iw_iscan_set_scan( WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", 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) { @@ -2724,12 +2800,14 @@ 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 !defined(CSCAN) 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; } +#endif 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); @@ -2800,6 +2878,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, @@ -2808,6 +2912,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) { @@ -2846,6 +2952,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 @@ -2971,12 +3106,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)); @@ -2992,6 +3131,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; @@ -3009,6 +3149,7 @@ wl_iw_get_scan( else { g_ss_cache_ctrl.m_cons_br_scan_cnt++; } +#endif @@ -3046,12 +3187,16 @@ wl_iw_get_scan( return -EINVAL; } +#if !defined(CSCAN) if (g_scan_specified_ssid) { wl_iw_add_bss_to_ss_cache(list); kfree(list); } +#endif +#if !defined(CSCAN) + MUTEX_LOCK_WL_SCAN_SET(); #if defined(WL_IW_USE_ISCAN) if (g_scan_specified_ssid) WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count)); @@ -3071,6 +3216,7 @@ wl_iw_get_scan( list_merge = (wl_scan_results_t *) g_scan; len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user); #endif + MUTEX_UNLOCK_WL_SCAN_SET(); if (g_ss_cache_ctrl.m_link_down) { wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid); @@ -3080,6 +3226,38 @@ 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) @@ -3114,8 +3292,10 @@ wl_iw_iscan_get_scan( iscan_info_t *iscan = g_iscan; iscan_buf_t * p_buf; uint32 counter = 0; +#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)); @@ -3131,11 +3311,13 @@ wl_iw_iscan_get_scan( return -EINVAL; } +#if !defined(CSCAN) if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) { WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \ dev->name, __FUNCTION__)); return -EAGAIN; } +#endif if ((!iscan) || (iscan->sysioc_pid < 0)) { WL_TRACE(("%ssysioc_pid\n", __FUNCTION__)); @@ -3144,6 +3326,7 @@ wl_iw_iscan_get_scan( +#if !defined(CSCAN) if (g_ss_cache_ctrl.m_timer_expired) { wl_iw_free_ss_cache(); g_ss_cache_ctrl.m_timer_expired ^= 1; @@ -3164,6 +3347,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; @@ -3262,6 +3446,7 @@ 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; @@ -3269,6 +3454,7 @@ wl_iw_iscan_get_scan( wl_iw_run_ss_cache_timer(1); g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED; +#endif WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter)); @@ -3937,11 +4123,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; @@ -4058,6 +4254,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; } @@ -4243,6 +4445,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; @@ -4257,6 +4461,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; @@ -4304,6 +4510,8 @@ 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; @@ -4391,6 +4599,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; } @@ -4699,6 +4925,406 @@ 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, wl_iscan_params_t *iscan_params, \ + 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_params)) { + WL_ERROR(("%s error exit\n", __FUNCTION__)); + err = -1; + } + + 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_params->params) + i; + memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t)); + p += nssid * sizeof(wlc_ssid_t); + } else { + p = (char*)iscan_params->params.channel_list + nchan * sizeof(uint16); + } + + + iscan_params->params.channel_num = htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \ + (nchan & WL_SCAN_PARAMS_COUNT_MASK)); + + + params_size = (int) (p - (char*)iscan_params + nssid * sizeof(wlc_ssid_t)); + + 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; + +#define SCAN_DUMP 1 +#ifdef SCAN_DUMP + printf("\n### List of SSIDs to scan ###\n"); + for (i = 0; i < nssid; i++) { + if (!ssids_local[i].SSID_len) + printf("%d: Broadcast scan\n", i); + else + printf("%d: scan for %s size =%d\n", i, \ + ssids_local[i].SSID, ssids_local[i].SSID_len); + } + printf("### List of channels to scan ###\n"); + for (i = 0; i < nchan; i++) + { + printf("%d ", iscan_params->params.channel_list[i]); + } + printf("\nnprobes=%d\n", iscan_params->params.nprobes); + printf("active_time=%d\n", iscan_params->params.active_time); + printf("passive_time=%d\n", iscan_params->params.passive_time); + printf("home_time=%d\n", iscan_params->params.home_time); + printf("\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_params, params_size, \ + iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) { + WL_TRACE(("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; + int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + + (WL_NUMCHANNELS * sizeof(uint16)); + wl_iscan_params_t *iscan_params; + 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 (!(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; + } + + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + + iscan_params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + if (iscan_params == NULL) { + WL_ERROR(("%s Failed allocate %d bytes \n", __FUNCTION__, params_size)); + return -ENOMEM; + } + + memset(iscan_params, 0, params_size); + ASSERT(params_size < WLC_IOCTL_MAXLEN); + + + iscan_params->version = htod32(ISCAN_REQ_VERSION); + iscan_params->action = htod16(WL_SCAN_ACTION_START); + iscan_params->scan_duration = htod16(0); + + wl_iw_iscan_prep(&iscan_params->params, NULL); + + + if ((nchan = wl_iw_parse_channel_list(&str_ptr, \ + &iscan_params->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_params->params.nprobes, 2); + + get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \ + &iscan_params->params.active_time, 3); + + get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \ + &iscan_params->params.passive_time, 3); + + get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \ + &iscan_params->params.home_time, 3); + + + res = wl_iw_combined_scan_set(dev, iscan_params, \ + ssids_local, nssid, nchan); + + kfree(iscan_params); + } 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; + int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) + \ + (WL_NUMCHANNELS * sizeof(uint16)); + wl_iscan_params_t *iscan_params; + 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, + 0x01, + 0x00, + 0x01, + 0x04, + 'B', 'R', 'C', 'M', + 0x02, + 0x00 + }; +#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)); + + 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 < (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))); + return -1; + } + +#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 { + + params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t); + + iscan_params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL); + if (iscan_params == NULL) { + WL_ERROR(("%s Failed allocate %d bytes \n", \ + __FUNCTION__, params_size)); + return -ENOMEM; + } + memset(iscan_params, 0, params_size); + ASSERT(params_size < WLC_IOCTL_MAXLEN); + + + iscan_params->version = htod32(ISCAN_REQ_VERSION); + iscan_params->action = htod16(WL_SCAN_ACTION_START); + iscan_params->scan_duration = htod16(0); + wl_iw_iscan_prep(&iscan_params->params, NULL); + + + 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_params->params.channel_list[0], \ + WL_NUMCHANNELS, &tlv_size_left)) == -1) { + WL_ERROR(("%s missing channel list\n", \ + __FUNCTION__)); + goto exit_scan; + } + break; + case CSCAN_TLV_TYPE_NPROBE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan_params->params.nprobes, \ + sizeof(iscan_params->params.nprobes), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_scan; + } + break; + case CSCAN_TLV_TYPE_ACTIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan_params->params.active_time, \ + sizeof(iscan_params->params.active_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_scan; + } + break; + case CSCAN_TLV_TYPE_PASSIVE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan_params->params.passive_time, \ + sizeof(iscan_params->params.passive_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_scan; + } + break; + case CSCAN_TLV_TYPE_HOME_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan_params->params.home_time, \ + sizeof(iscan_params->params.home_time), \ + type, sizeof(short), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_scan; + } + break; + case CSCAN_TLV_TYPE_STYPE_IE: + if ((res = wl_iw_parse_data_tlv(&str_ptr, \ + &iscan_params->params.scan_type, \ + sizeof(iscan_params->params.scan_type), \ + type, sizeof(char), &tlv_size_left)) == -1) { + WL_ERROR(("%s return %d\n", \ + __FUNCTION__, res)); + goto exit_scan; + } + break; + + default : + WL_ERROR(("%s get unkwown type %X\n", \ + __FUNCTION__, type)); + goto exit_scan; + break; + } + } + } + } + else { + WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__)); + goto exit_proc; + } + + + res = wl_iw_combined_scan_set(dev, iscan_params, \ + ssids_local, nssid, nchan); + +exit_scan: + kfree(iscan_params); + +exit_proc: + + return res; +} + +#endif + + + #ifdef SOFTAP @@ -4749,11 +5375,18 @@ 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; + int iolen = 0; + int mkvar_err = 0; + int bsscfg_index = 1; + char buf[WLC_IOCTL_SMLEN]; WL_SOFTAP(("Enter %s\n", __FUNCTION__)); memset(&null_ssid, 0, sizeof(wlc_ssid_t)); res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)); - res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid)); + 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); auto_channel_retry: request.count = htod32(0); @@ -5143,7 +5776,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; @@ -5160,7 +5793,7 @@ int get_parmeter_from_string( WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len)); if (parm_str_len > param_max_len) { - WL_TRACE((" WARNING: extracted param len:%d is > MAX:%d\n", + WL_ERROR((" WARNING: extracted param len:%d is > MAX:%d\n", parm_str_len, param_max_len)); parm_str_len = param_max_len; @@ -5194,7 +5827,7 @@ int get_parmeter_from_string( memcpy(dst, param_str_begin, parm_str_len); *((char *)dst + parm_str_len) = 0; - WL_TRACE((" written as a string:%s\n", (char *)dst)); + WL_ERROR((" written as a string:%s\n", (char *)dst)); break; } @@ -5352,6 +5985,7 @@ exit_proc: return ret; } #ifdef SOFTAP + static int iwpriv_wpasupp_loop_tst(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, @@ -5611,7 +6245,7 @@ static int wl_iw_set_priv( return -EFAULT; } - WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d", + WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d\n", dev->name, extra, info->cmd, info->flags, dwrq->length)); @@ -5656,6 +6290,11 @@ 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); +#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); @@ -5823,8 +6462,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[] = @@ -5923,6 +6567,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 = @@ -6372,7 +7024,8 @@ 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; @@ -6425,7 +7078,7 @@ int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstat phy_noise = dtoh32(phy_noise); WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise)); - scb_val.val = 0; + bzero(&scb_val, sizeof(scb_val_t)); if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t)))) goto done; @@ -6671,6 +7324,7 @@ int wl_iw_attach(struct net_device *dev, void * dhdp) iw = *(wl_iw_t **)netdev_priv(dev); iw->pub = (dhd_pub_t *)dhdp; MUTEX_LOCK_INIT(iw->pub); + MUTEX_LOCK_WL_SCAN_SET_INIT(); #ifdef SOFTAP priv_dev = dev; MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub); @@ -6685,8 +7339,10 @@ 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); @@ -6706,12 +7362,13 @@ void wl_iw_detach(void) KILL_PROC(iscan->sysioc_pid, SIGTERM); wait_for_completion(&iscan->sysioc_exited); } - + MUTEX_LOCK_WL_SCAN_SET(); while (iscan->list_hdr) { buf = iscan->list_hdr->next; kfree(iscan->list_hdr); iscan->list_hdr = buf; } + MUTEX_UNLOCK_WL_SCAN_SET(); kfree(iscan); g_iscan = NULL; #endif @@ -6720,7 +7377,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 diff --git a/bcm4329/src/wl/sys/wl_iw.h b/bcm4329/src/wl/sys/wl_iw.h index f354d68..0b7ece1 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.21 2010/07/08 00:50:58 Exp $ */ @@ -34,6 +34,14 @@ #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 SOFTAP 1 @@ -63,7 +71,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 @@ -98,14 +106,13 @@ int wl_control_wl_start(struct net_device *dev); #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 { + struct wl_iw_ss_cache *next; uint32 buflen; uint32 version; uint32 count; - wl_bss_info_t bss_info[1]; - char dummy[WLC_IW_BSS_INFO_MAXLEN - sizeof(wl_bss_info_t)]; int dirty; - struct wl_iw_ss_cache *next; + wl_bss_info_t bss_info[1]; } wl_iw_ss_cache_t; typedef struct wl_iw_ss_cache_ctrl { @@ -179,4 +186,40 @@ void wl_iw_detach(void); iwe_stream_add_point(stream, ends, iwe, extra) #endif +#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 1 +#define CSCAN_TLV_TYPE_CHANNEL_IE 2 +#define CSCAN_TLV_TYPE_NPROBE_IE 3 +#define CSCAN_TLV_TYPE_ACTIVE_IE 4 +#define CSCAN_TLV_TYPE_PASSIVE_IE 5 +#define CSCAN_TLV_TYPE_HOME_IE 6 +#define CSCAN_TLV_TYPE_STYPE_IE 7 + +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 |