diff options
author | Benn Pörscke <benn.porscke@stericsson.com> | 2011-12-16 15:04:55 +0100 |
---|---|---|
committer | Benn Pörscke <benn.porscke@stericsson.com> | 2011-12-16 15:04:55 +0100 |
commit | 93f379e6cfadfded0d262192ca69d1abc096d90e (patch) | |
tree | 43f180e31ee26ee94f7d2dd559132c30c6476b4d /drivers/net/wireless | |
parent | 77955e37bd395f789900b8e180991ad67cabd899 (diff) |
Squashandroid-20111223
Change-Id: I2fcf46d1fc4b0cd4c61e5be3654c43b80db86015
Diffstat (limited to 'drivers/net/wireless')
21 files changed, 694 insertions, 565 deletions
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 56500b7220c..e82c9856f00 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -1,5 +1,5 @@ # bcmdhd -DHDCFLAGS = -Wall -Wstrict-prototypes -Werror -Dlinux -DBCMDRIVER \ +DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DWLBTAMP -DBCMFILEIMAGE \ -DDHDTHREAD -DDHD_GPL -DDHD_SCHED -DDHD_DEBUG -DSDTEST -DBDC -DTOE \ -DDHD_BCMEVENTS -DSHOW_EVENTS -DDONGLEOVERLAYS -DBCMDBG \ diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index 3cee7c214e3..24581ddd353 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -29,7 +29,7 @@ #include <proto/bcmeth.h> #include <proto/bcmevent.h> -#if WLC_E_LAST != 84 +#if WLC_E_LAST != 85 #error "You need to add an entry to bcmevent_names[] for the new event" #endif @@ -115,7 +115,10 @@ const bcmevent_name_t bcmevent_names[] = { { WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND" }, { WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" }, { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" }, - { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" } + { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" }, +#ifdef SOFTAP + { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" } +#endif }; diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index 6fa47378cfe..a4dc6ff4042 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -48,15 +48,6 @@ extern void dhdsdio_isr(void * args); #include <dngl_stats.h> #include <dhd.h> #endif /* defined(OOB_INTR_ONLY) */ -#if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270) -#if !defined(BCMPLATFORM_BUS) -#define BCMPLATFORM_BUS -#endif /* !defined(BCMPLATFORM_BUS) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)) -#include <linux/platform_device.h> -#endif /* KERNEL_VERSION(2, 6, 19) */ -#endif /* CONFIG_MACH_SANDGATE2G || CONFIG_MACH_LOGICPD_PXA270 */ /** * SDIO Host Controller info diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index ea8f67ce8b4..281e047af85 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -71,6 +71,12 @@ enum dhd_bus_state { DHD_BUS_DATA /* Ready for frame transfers */ }; +/* Firmware requested operation mode */ +#define STA_MASK 0x0001 +#define HOSTAPD_MASK 0x0002 +#define WFD_MASK 0x0004 +#define SOFTAP_FW_MASK 0x0008 + enum dhd_bus_wake_state { WAKE_LOCK_OFF, WAKE_LOCK_PRIV, @@ -173,6 +179,7 @@ typedef struct dhd_pub { wl_country_t dhd_cspec; /* Current Locale info */ char eventmask[WL_EVENTING_MASK_LEN]; + int op_mode; /* STA, HostAPD, WFD, SoftAP */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) struct wake_lock wakelock[WAKE_LOCK_MAX]; @@ -423,6 +430,7 @@ extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); extern int dhd_timeout_expired(dhd_timeout_t *tmo); extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); +extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx); extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, wl_event_msg_t *, void **data_ptr); diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h index 294322026e9..bccb8b6603f 100644 --- a/drivers/net/wireless/bcmdhd/dhd_bus.h +++ b/drivers/net/wireless/bcmdhd/dhd_bus.h @@ -48,6 +48,11 @@ extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); /* Initialize bus module: prepare for communication w/dongle */ extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); +/* Get the Bus Idle Time */ +extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); + +/* Set the Bus Idle Time*/ +extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); /* Send a data frame to the dongle. Callee disposes of txp. */ extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index 91c461f7bbe..0f9893a1537 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -916,7 +916,10 @@ _dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descript #ifdef PROP_TXSTATUS_DEBUG ctx->stats.signal_only_pkts_sent++; #endif - dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); + rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); + if (rc != BCME_OK) { + PKTFREE(ctx->osh, p, TRUE); + } } else { DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", @@ -1920,7 +1923,6 @@ dhd_wlfc_init(dhd_pub_t *dhd) WLFC_FLAGS_CREDIT_STATUS_SIGNALS | WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE : 0; - dhd->wlfc_state = NULL; /* try to enable/disable signaling by sending "tlv" iovar. if that fails, @@ -2237,49 +2239,6 @@ dhd_prot_dstats(dhd_pub_t *dhd) return; } -int dhd_set_suspend(int value, dhd_pub_t *dhd) -{ - int power_mode = PM_MAX; - wl_pkt_filter_enable_t enable_parm; - char iovbuf[32]; - int bcn_li_dtim = 3; - -#define htod32(i) i - - if (dhd && dhd->up) { - if (value) { - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, - (char *)&power_mode, sizeof(power_mode), TRUE, 0); - /* Enable packet filter, only allow unicast packet to send up */ - enable_parm.id = htod32(100); - enable_parm.enable = htod32(1); - bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm, - sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* set bcn_li_dtim */ - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } else { - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); - /* disable pkt filter */ - enable_parm.id = htod32(100); - enable_parm.enable = htod32(0); - bcm_mkiovar("pkt_filter_enable", (char *)&enable_parm, - sizeof(wl_pkt_filter_enable_t), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* set bcn_li_dtim */ - bcn_li_dtim = 0; - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } - } - - return 0; -} int dhd_prot_init(dhd_pub_t *dhd) @@ -2297,16 +2256,17 @@ dhd_prot_init(dhd_pub_t *dhd) goto done; +#ifdef PROP_TXSTATUS + ret = dhd_wlfc_init(dhd); +#endif + +#ifndef WL_CFG80211 ret = dhd_preinit_ioctls(dhd); +#endif /* WL_CFG80211 */ /* Always assumes wl for now */ dhd->iswl = TRUE; -#ifdef PROP_TXSTATUS - ret = dhd_wlfc_init(dhd); -#endif - goto done; - done: return ret; } diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index c50f05325f6..f6bb8e5bb56 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -70,6 +70,7 @@ char nv_path[MOD_PARAM_PATHLEN]; #ifdef SOFTAP char fw_path2[MOD_PARAM_PATHLEN]; +extern bool softap_enabled; #endif /* Last connection success/failure status */ @@ -1533,8 +1534,10 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint32 dongle_align = DHD_SDALIGN; uint32 glom = 0; uint bcn_timeout = 4; + uint retry_max = 3; +#if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; - int arp_ol = 0xf; +#endif int scan_assoc_time = 40; int scan_unassoc_time = 40; const char *str; @@ -1551,14 +1554,17 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(SOFTAP) uint dtim = 1; #endif -#ifdef AP +#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ +#endif /* AP */ +#if defined(AP) || defined(WLP2P) uint32 apsta = 1; /* Enable APSTA mode */ -#endif +#endif /* defined(AP) || defined(WLP2P) */ #ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ + dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE ret = dhd_custom_get_mac_address(ea_addr.octet); if (!ret) { @@ -1586,7 +1592,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* GET_CUSTOM_MAC_ENABLE */ #ifdef SET_RANDOM_MAC_SOFTAP - if (strstr(fw_path, "apsta") != NULL) { + if (strstr(fw_path, "_apsta") != NULL) { uint rand_mac; srandom32((uint)jiffies); @@ -1607,9 +1613,52 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #endif /* SET_RANDOM_MAC_SOFTAP */ - DHD_ERROR(("Firmware up: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2], - dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5])); + DHD_TRACE(("Firmware = %s\n", fw_path)); +#if !defined(AP) && defined(WLP2P) + /* Check if firmware with WFD support used */ + if (strstr(fw_path, "_p2p") != NULL) { + bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, + iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret)); + } else { + dhd->op_mode |= WFD_MASK; +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif /* (ARP_OFFLOAD_SUPPORT) */ + dhd_pkt_filter_enable = FALSE; + } + } +#endif /* !defined(AP) && defined(WLP2P) */ + +#if !defined(AP) && defined(WL_CFG80211) + /* Check if firmware with HostAPD support used */ + if (strstr(fw_path, "_apsta") != NULL) { + /* Turn off MPC in AP mode */ + bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); + } else { + dhd->op_mode |= HOSTAPD_MASK; +#if defined(ARP_OFFLOAD_SUPPORT) + arpoe = 0; +#endif /* (ARP_OFFLOAD_SUPPORT) */ + dhd_pkt_filter_enable = FALSE; + } + } +#endif /* !defined(AP) && defined(WL_CFG80211) */ + + if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) { + /* STA only operation mode */ + dhd->op_mode |= STA_MASK; + dhd_pkt_filter_enable = TRUE; + } + DHD_ERROR(("Firmware up: op_mode=%d, " + "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", + dhd->op_mode, + dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2], + dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5])); /* Set Country code */ if (dhd->dhd_cspec.ccode[0] != 0) { @@ -1649,15 +1698,16 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Setup timeout if Beacons are lost and roam is off to report link down */ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#ifdef AP + /* Setup assoc_retry_max count to reconnect target AP in dongle */ + bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); +#if defined(AP) && !defined(WLP2P) /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* Enable APSTA mode */ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif +#endif /* defined(AP) && !defined(WLP2P) */ #if defined(SOFTAP) if (ap_fw_loaded == TRUE) { dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); @@ -1720,12 +1770,6 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, sizeof(scan_unassoc_time), TRUE, 0); - /* Set ARP offload */ - bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* add a default packet filter pattern */ str = "pkt_filter_add"; str_len = strlen(str); @@ -1779,9 +1823,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #ifdef ARP_OFFLOAD_SUPPORT /* Set and enable ARP offload feature for STA only */ - if (dhd_arp_enable && !ap_fw_loaded) { + if (arpoe && !ap_fw_loaded) { dhd_arp_offload_set(dhd, dhd_arp_mode); - dhd_arp_offload_enable(dhd, dhd_arp_enable); + dhd_arp_offload_enable(dhd, arpoe); } else { dhd_arp_offload_set(dhd, 0); dhd_arp_offload_enable(dhd, FALSE); @@ -2061,6 +2105,17 @@ exit: return bcn_li_dtim; } +/* Check if HostAPD or WFD mode setup */ +bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) +{ +#ifdef WL_CFG80211 + if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) || + ((dhd->op_mode & WFD_MASK) == WFD_MASK)) + return TRUE; + else +#endif /* WL_CFG80211 */ + return FALSE; +} #ifdef PNO_SUPPORT int @@ -2105,6 +2160,8 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) return ret; } + if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) + return (ret); memset(iovbuf, 0, sizeof(iovbuf)); /* Check if disassoc to enable pno */ if ((pfn_enabled) && @@ -2152,6 +2209,8 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, DHD_ERROR(("%s error exit\n", __FUNCTION__)); err = -1; } + if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) + return (err); /* Check for broadcast ssid */ for (k = 0; k < nssid; k++) { @@ -2268,7 +2327,10 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) int str_len; int res = -1; - DHD_ERROR(("%s Enter\n", __FUNCTION__)); + if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) + return (res); + + DHD_TRACE(("%s execution\n", __FUNCTION__)); str = "mkeep_alive"; str_len = strlen(str); diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 5d35f78cf2a..03ba34a2c82 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -443,11 +443,9 @@ static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); static void dhd_dump_htsfhisto(histo_t *his, char *s); #endif /* WLMEDIA_HTSF */ -extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); - /* Monitor interface */ -extern int dhd_monitor_init(void *dhd_pub); -extern int dhd_monitor_uninit(void); +int dhd_monitor_init(void *dhd_pub); +int dhd_monitor_uninit(void); #if defined(CONFIG_WIRELESS_EXT) @@ -673,7 +671,7 @@ dhd_timeout_expired(dhd_timeout_t *tmo) return 0; } -static int +int dhd_net2idx(dhd_info_t *dhd, struct net_device *net) { int i = 0; @@ -971,7 +969,8 @@ dhd_op_if(dhd_if_t *ifp) memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) - if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, dhd_net_attach)) { + if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, + dhd_net_attach)) { ifp->state = 0; return; } @@ -1023,10 +1022,10 @@ dhd_op_if(dhd_if_t *ifp) free_netdev(ifp->net); } dhd->iflist[ifp->idx] = NULL; - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); #ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) + if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { wl_cfg80211_notify_ifdel(ifp->net); + } #endif #ifdef SOFTAP flags = dhd_os_spin_lock(&dhd->pub); @@ -1034,6 +1033,7 @@ dhd_op_if(dhd_if_t *ifp) ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ dhd_os_spin_unlock(&dhd->pub, flags); #endif /* SOFTAP */ + MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); } } @@ -1385,7 +1385,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) struct sk_buff *skb; uchar *eth; uint len; - void *data, *pnext, *save_pktbuf; + void *data, *pnext = NULL, *save_pktbuf; int i; dhd_if_t *ifp; wl_event_msg_t event; @@ -1398,6 +1398,16 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) struct ether_header *eh; struct dot11_llc_snap_header *lsh; + ifp = dhd->iflist[ifidx]; + + /* Dropping packets before registering net device to avoid kernel panic */ + if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { + DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", + __FUNCTION__)); + PKTFREE(dhdp->osh, pktbuf, TRUE); + continue; + } + pnext = PKTNEXT(dhdp->osh, pktbuf); PKTSETNEXT(wl->sh.osh, pktbuf, NULL); @@ -1487,14 +1497,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) dhdp->dstats.rx_bytes += skb->len; dhdp->rx_packets++; /* Local count */ - /* Dropping packets before registering net device to avoid kernel panic */ - if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) { - DHD_ERROR(("%s: net device is NOT registered yet. drop [%s] packet\n", - __FUNCTION__, (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) ? "event" : "data")); - PKTFREE(dhdp->osh, pktbuf, TRUE); - continue; - } - if (in_interrupt()) { netif_rx(skb); } else { @@ -2355,6 +2357,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, if (handle == NULL) { ifp->state = WLC_E_IF_ADD; ifp->idx = ifidx; + ifp->bssidx = bssidx; ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } else @@ -3057,6 +3060,7 @@ void dhd_detach(dhd_pub_t *dhdp) { dhd_info_t *dhd; unsigned long flags; + int timer_valid = FALSE; if (!dhdp) return; @@ -3118,17 +3122,23 @@ void dhd_detach(dhd_pub_t *dhdp) if (ifp->net->netdev_ops == &dhd_ops_pri) #endif { - unregister_netdev(ifp->net); + if (ifp->net) { + unregister_netdev(ifp->net); + free_netdev(ifp->net); + ifp->net = NULL; + } MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - + dhd->iflist[0] = NULL; } } /* Clear the watchdog timer */ flags = dhd_os_spin_lock(&dhd->pub); + timer_valid = dhd->wd_timer_valid; dhd->wd_timer_valid = FALSE; dhd_os_spin_unlock(&dhd->pub, flags); - del_timer_sync(&dhd->timer); + if (timer_valid) + del_timer_sync(&dhd->timer); if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { #ifdef DHDTHREAD diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c index 6c1ff4d8ad4..dd9c71f75be 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c @@ -106,8 +106,10 @@ static struct net_device* lookup_real_netdev(char *name) for (i = 0; i < DHD_MAX_IFS; i++) { ndev = dhd_idx2net(g_monitor.dhd_pub, i); if (ndev && strstr(name, ndev->name)) { - if (strlen(ndev->name) > last_name_len) + if (strlen(ndev->name) > last_name_len) { ndev_found = ndev; + last_name_len = strlen(ndev->name); + } } } diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index db763ab8c3d..6d89f6b984a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -52,6 +52,7 @@ #include <sbsdio.h> #include <sbsdpcmdev.h> #include <bcmsdpcm.h> +#include <bcmsdbus.h> #include <proto/ethernet.h> #include <proto/802.1d.h> @@ -76,11 +77,7 @@ #define TXRETRIES 2 /* # of retries for tx frames */ -#if defined(CONFIG_MACH_SANDGATE2G) -#define DHD_RXBOUND 250 /* Default for max rx frames in one scheduling */ -#else #define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ -#endif /* defined(CONFIG_MACH_SANDGATE2G) */ #define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ @@ -360,7 +357,7 @@ static const uint retry_limit = 2; static bool forcealign; /* Flag to indicate if we should download firmware on driver load */ -uint dhd_download_fw_on_driverload = TRUE; +uint dhd_download_fw_on_driverload = FALSE; #define ALIGNMENT 4 @@ -1026,7 +1023,9 @@ dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); #ifdef DHD_DEBUG - tx_packets[PKTPRIO(pkt)]++; + if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) { + tx_packets[PKTPRIO(pkt)]++; + } if (DHD_BYTES_ON() && (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { @@ -1843,6 +1842,8 @@ dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) sh->console_addr = ltoh32(sh->console_addr); sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) + return BCME_OK; if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { DHD_ERROR(("%s: sdpcm_shared version %d in dhd " "is different than sdpcm_shared version %d in dongle\n", @@ -6219,10 +6220,13 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) dhd_os_sdunlock(dhdp); } else { - bcmerror = BCME_NOTDOWN; - DHD_ERROR(("%s: Set DEVRESET=FALSE invoked when device is on\n", + DHD_INFO(("%s called when dongle is not in reset\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; + DHD_INFO(("Will call dhd_bus_start instead\n")); + sdioh_start(NULL, 1); + if ((bcmerror = dhd_bus_start(dhdp)) != 0) + DHD_ERROR(("%s: dhd_bus_start fail with %d\n", + __FUNCTION__, bcmerror)); } } return bcmerror; diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h index f7f23009fdd..530036f0ba7 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h @@ -140,7 +140,9 @@ typedef bool (*ifpkt_cb_t)(void*, int); #define SHARED_POOL ((struct pktpool *)NULL) #endif +#ifndef PKTPOOL_LEN_MAX #define PKTPOOL_LEN_MAX 40 +#endif #define PKTPOOL_CB_MAX 3 struct pktpool; diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 5c63a391321..f474dfa482a 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 125 -#define EPI_INCREMENTAL_NUMBER 52 +#define EPI_INCREMENTAL_NUMBER 69 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 125, 52 +#define EPI_VERSION 5, 90, 125, 69 -#define EPI_VERSION_NUM 0x055a7d34 +#define EPI_VERSION_NUM 0x055a7d45 #define EPI_VERSION_DEV 5.90.125 -#define EPI_VERSION_STR "5.90.125.52" +#define EPI_VERSION_STR "5.90.125.69" #endif diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h index 7f51faa0d3d..30ec848c40a 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h @@ -181,7 +181,8 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_EXCESS_PM_WAKE_EVENT 81 #define WLC_E_PFN_SCAN_NONE 82 #define WLC_E_PFN_SCAN_ALLGONE 83 -#define WLC_E_LAST 84 +#define WLC_E_GTK_PLUMBED 84 +#define WLC_E_LAST 85 typedef struct { diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h index 7e94e7df13c..ca932266a1b 100644 --- a/drivers/net/wireless/bcmdhd/include/sdio.h +++ b/drivers/net/wireless/bcmdhd/include/sdio.h @@ -376,6 +376,7 @@ typedef volatile struct { #define SDIOH_CMD_5 5 #define SDIOH_CMD_7 7 #define SDIOH_CMD_11 11 +#define SDIOH_CMD_14 14 #define SDIOH_CMD_15 15 #define SDIOH_CMD_19 19 #define SDIOH_CMD_52 52 @@ -411,6 +412,10 @@ typedef volatile struct { #define CMD7_RCA_M BITFIELD_MASK(16) #define CMD7_RCA_S 16 +#define CMD14_RCA_M BITFIELD_MASK(16) +#define CMD14_RCA_S 16 +#define CMD14_SLEEP_M BITFIELD_MASK(1) +#define CMD14_SLEEP_S 15 #define CMD_15_RCA_M BITFIELD_MASK(16) #define CMD_15_RCA_S 16 diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index a441eabc076..1059de147ef 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -190,6 +190,7 @@ typedef struct wlc_ssid { #define WL_SCANFLAGS_RESERVED 0x02 #define WL_SCANFLAGS_PROHIBITED 0x04 +#define WL_SCAN_PARAMS_SSID_MAX 10 typedef struct wl_scan_params { wlc_ssid_t ssid; struct ether_addr bssid; @@ -554,6 +555,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_PMK 12 #define WSEC_GEN_MIC_ERROR 0x0001 #define WSEC_GEN_REPLAY 0x0002 @@ -615,6 +617,9 @@ typedef struct { #define WPA2_AUTH_PSK 0x0080 #define BRCM_AUTH_PSK 0x0100 #define BRCM_AUTH_DPT 0x0200 +#define WPA2_AUTH_MFP 0x1000 +#define WPA2_AUTH_TPK 0x2000 +#define WPA2_AUTH_FT 0x4000 #define MAXPMKID 16 @@ -1498,6 +1503,7 @@ typedef struct wl_sampledata { #define WL_JOIN_PREF_WPA 2 #define WL_JOIN_PREF_BAND 3 #define WL_JOIN_PREF_RSSI_DELTA 4 +#define WL_JOIN_PREF_TRANS_PREF 5 #define WLJP_BAND_ASSOC_PREF 255 diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index e054d7b3886..d6471d99106 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -338,10 +338,10 @@ int wl_android_wifi_off(struct net_device *dev) dhd_net_if_lock(dev); if (g_wifi_on) { dhd_dev_reset(dev, 1); - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); sdioh_stop(NULL); /* clean up dtim_skip setting */ net_os_set_dtim_skip(dev, TRUE); + dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); g_wifi_on = 0; } dhd_net_if_unlock(dev); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 366ce2224ab..09529136787 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -2,13 +2,13 @@ * Linux cfg80211 driver * * Copyright (C) 1999-2011, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -74,7 +74,7 @@ #include <wl_cfgp2p.h> static struct sdio_func *cfg80211_sdio_func; -static struct wl_dev *wl_cfg80211_dev; +static struct wl_priv *wlcfg_drv_priv; u32 wl_dbg_level = WL_DBG_ERR; @@ -83,7 +83,7 @@ u32 wl_dbg_level = WL_DBG_ERR; #define WL_TRACE(a) printk("%s ", __FUNCTION__); printk a #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" -#define MAX_WAIT_TIME 3000 +#define MAX_WAIT_TIME 1500 static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; #if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL) @@ -148,13 +148,10 @@ static const struct ieee80211_regdomain brcm_regdom = { NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | NL80211_RRF_NO_OFDM), - /* IEEE 802.11a, channel 36..48 */ - REG_RULE(5180-10, 5240+10, 40, 6, 20, 0), - - /* NB: 5260 MHz - 5700 MHz requies DFS */ - - /* IEEE 802.11a, channel 149..165 */ - REG_RULE(5745-10, 5825+10, 40, 6, 20, 0), } + /* IEEE 802.11a, channel 36..64 */ + REG_RULE(5150-10, 5350+10, 40, 6, 20, 0), + /* IEEE 802.11a, channel 100..165 */ + REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), } }; @@ -339,8 +336,7 @@ static u32 wl_get_ielen(struct wl_priv *wl); static s32 wl_mode_to_nl80211_iftype(s32 mode); -static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, - struct device *dev); +static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev); static void wl_free_wdev(struct wl_priv *wl); static s32 wl_inform_bss(struct wl_priv *wl); @@ -365,12 +361,6 @@ static void wl_deinit_priv_mem(struct wl_priv *wl); static void wl_delay(u32 ms); /* - * store/restore cfg80211 instance data - */ -static void wl_set_drvdata(struct wl_dev *dev, void *data); -static void *wl_get_drvdata(struct wl_dev *dev); - -/* * ibss mode utilities */ static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev); @@ -423,9 +413,9 @@ static void wl_iscan_timer(unsigned long data); static void wl_term_iscan(struct wl_priv *wl); static s32 wl_init_scan(struct wl_priv *wl); static s32 wl_iscan_thread(void *data); -static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, +static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action); -static s32 wl_do_iscan(struct wl_priv *wl); +static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request); static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan); static s32 wl_invoke_iscan(struct wl_priv *wl); static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, @@ -474,23 +464,11 @@ int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); -#define WL_PRIV_GET() \ - ({ \ - struct wl_iface *ci = NULL; \ - if (unlikely(!(wl_cfg80211_dev && \ - (ci = wl_get_drvdata(wl_cfg80211_dev))))) { \ - WL_ERR(("wl_cfg80211_dev is unavailable\n")); \ - BUG(); \ - } \ - ci_to_wl(ci); \ -}) - -#define CHECK_SYS_UP() \ +#define CHECK_SYS_UP(wlpriv) \ do { \ - struct wl_priv *wl = WL_PRIV_GET(); \ - if (unlikely(!wl_get_drv_status(wl, READY))) { \ + if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \ WL_INFO(("device is not ready : status (%d)\n", \ - (int)wl->status)); \ + (int)wlpriv->status)); \ return -EIO; \ } \ } while (0) @@ -609,70 +587,7 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = { CHAN5G(132, 0), CHAN5G(136, 0), CHAN5G(140, 0), CHAN5G(149, 0), CHAN5G(153, 0), CHAN5G(157, 0), - CHAN5G(161, 0), CHAN5G(165, 0), - CHAN5G(184, 0), CHAN5G(188, 0), - CHAN5G(192, 0), CHAN5G(196, 0), - CHAN5G(200, 0), CHAN5G(204, 0), - CHAN5G(208, 0), CHAN5G(212, 0), - CHAN5G(216, 0) -}; - -static struct ieee80211_channel __wl_5ghz_n_channels[] = { - CHAN5G(32, 0), CHAN5G(34, 0), - CHAN5G(36, 0), CHAN5G(38, 0), - CHAN5G(40, 0), CHAN5G(42, 0), - CHAN5G(44, 0), CHAN5G(46, 0), - CHAN5G(48, 0), CHAN5G(50, 0), - CHAN5G(52, 0), CHAN5G(54, 0), - CHAN5G(56, 0), CHAN5G(58, 0), - CHAN5G(60, 0), CHAN5G(62, 0), - CHAN5G(64, 0), CHAN5G(66, 0), - CHAN5G(68, 0), CHAN5G(70, 0), - CHAN5G(72, 0), CHAN5G(74, 0), - CHAN5G(76, 0), CHAN5G(78, 0), - CHAN5G(80, 0), CHAN5G(82, 0), - CHAN5G(84, 0), CHAN5G(86, 0), - CHAN5G(88, 0), CHAN5G(90, 0), - CHAN5G(92, 0), CHAN5G(94, 0), - CHAN5G(96, 0), CHAN5G(98, 0), - CHAN5G(100, 0), CHAN5G(102, 0), - CHAN5G(104, 0), CHAN5G(106, 0), - CHAN5G(108, 0), CHAN5G(110, 0), - CHAN5G(112, 0), CHAN5G(114, 0), - CHAN5G(116, 0), CHAN5G(118, 0), - CHAN5G(120, 0), CHAN5G(122, 0), - CHAN5G(124, 0), CHAN5G(126, 0), - CHAN5G(128, 0), CHAN5G(130, 0), - CHAN5G(132, 0), CHAN5G(134, 0), - CHAN5G(136, 0), CHAN5G(138, 0), - CHAN5G(140, 0), CHAN5G(142, 0), - CHAN5G(144, 0), CHAN5G(145, 0), - CHAN5G(146, 0), CHAN5G(147, 0), - CHAN5G(148, 0), CHAN5G(149, 0), - CHAN5G(150, 0), CHAN5G(151, 0), - CHAN5G(152, 0), CHAN5G(153, 0), - CHAN5G(154, 0), CHAN5G(155, 0), - CHAN5G(156, 0), CHAN5G(157, 0), - CHAN5G(158, 0), CHAN5G(159, 0), - CHAN5G(160, 0), CHAN5G(161, 0), - CHAN5G(162, 0), CHAN5G(163, 0), - CHAN5G(164, 0), CHAN5G(165, 0), - CHAN5G(166, 0), CHAN5G(168, 0), - CHAN5G(170, 0), CHAN5G(172, 0), - CHAN5G(174, 0), CHAN5G(176, 0), - CHAN5G(178, 0), CHAN5G(180, 0), - CHAN5G(182, 0), CHAN5G(184, 0), - CHAN5G(186, 0), CHAN5G(188, 0), - CHAN5G(190, 0), CHAN5G(192, 0), - CHAN5G(194, 0), CHAN5G(196, 0), - CHAN5G(198, 0), CHAN5G(200, 0), - CHAN5G(202, 0), CHAN5G(204, 0), - CHAN5G(206, 0), CHAN5G(208, 0), - CHAN5G(210, 0), CHAN5G(212, 0), - CHAN5G(214, 0), CHAN5G(216, 0), - CHAN5G(218, 0), CHAN5G(220, 0), - CHAN5G(222, 0), CHAN5G(224, 0), - CHAN5G(226, 0), CHAN5G(228, 0) + CHAN5G(161, 0), CHAN5G(165, 0) }; static struct ieee80211_supported_band __wl_band_2ghz = { @@ -691,14 +606,6 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .n_bitrates = wl_a_rates_size }; -static struct ieee80211_supported_band __wl_band_5ghz_n = { - .band = IEEE80211_BAND_5GHZ, - .channels = __wl_5ghz_n_channels, - .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), - .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size -}; - static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, @@ -876,11 +783,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 index = 0; s32 mode = 0; chanspec_t chspec; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); int (*net_attach)(dhd_pub_t *dhdp, int ifidx); - WL_DBG(("if name: %s, type: %d\n", name, type)); switch (type) { case NL80211_IFTYPE_ADHOC: @@ -968,7 +874,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-ENOMEM); } vwdev->wiphy = wl->wdev->wiphy; - WL_INFO((" virtual interface(%s) is created \n", wl->p2p->vir_ifname)); + WL_INFO((" virtual interface(%s) is created memalloc done \n", + wl->p2p->vir_ifname)); index = alloc_idx_vwdev(wl); wl->vwdev[index] = vwdev; vwdev->iftype = @@ -981,12 +888,11 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, wl_set_drv_status(wl, READY); wl->p2p->vif_created = true; set_mode_by_netdev(wl, _ndev, mode); - wl = wdev_to_wl(vwdev); net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION); rtnl_unlock(); if (net_attach && !net_attach(dhd, _ndev->ifindex)) WL_DBG((" virtual interface(%s) is " - "created\n", wl->p2p->vir_ifname)); + "created net attach done\n", wl->p2p->vir_ifname)); else { rtnl_lock(); goto fail; @@ -1010,10 +916,10 @@ static s32 wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) { struct ether_addr p2p_mac; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 timeout = -1; s32 ret = 0; - + WL_DBG(("Enter\n")); if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); if (wl->p2p->vif_created) { @@ -1021,8 +927,17 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) wl_cfg80211_scan_abort(wl, dev); } - wl_cfgp2p_ifdel(wl, &p2p_mac); + ret = wl_cfgp2p_ifdel(wl, &p2p_mac); wl_set_p2p_status(wl, IF_DELETING); + if (ret) { + /* Firmware could not delete the interface so we will not get WLC_E_IF event for cleaning the dhd virtual nw interace + * So lets do it here. Failures from fw will ensure the application to do ifconfig <inter> down and up sequnce, which will reload the fw + * however we should cleanup the linux network virtual interfaces + */ + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + WL_ERR(("Firmware returned an error from p2p_ifdel, try to remove linux virtual network interface dev->name %s\n", dev->name)); + dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev)); + } /* Wait for any pending scan req to get aborted from the sysioc context */ timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, @@ -1052,7 +967,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, s32 wlif_type; s32 mode = 0; chanspec_t chspec; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); WL_DBG(("Enter \n")); switch (type) { case NL80211_IFTYPE_MONITOR: @@ -1118,10 +1033,10 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, } s32 -wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, +wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx, int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; s32 ret = BCME_OK; if (!net) { WL_ERR(("net is NULL\n")); @@ -1133,11 +1048,11 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) /* Assign the net device to CONNECT BSSCFG */ strncpy(net->name, wl->p2p->vir_ifname, IFNAMSIZ - 1); wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net; - wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = - P2PAPI_BSSCFG_CONNECTION; + wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx; wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach; - wl_clr_p2p_status(wl, IF_ADD); net->ifindex = idx; + wl_clr_p2p_status(wl, IF_ADD); + wake_up_interruptible(&wl->dongle_event_wait); } return ret; @@ -1146,7 +1061,7 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) s32 wl_cfg80211_ifdel_ops(struct net_device *net) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; if (!net || !net->name) { WL_DBG(("net is NULL\n")); @@ -1172,14 +1087,14 @@ wl_cfg80211_ifdel_ops(struct net_device *net) s32 wl_cfg80211_notify_ifdel(struct net_device *net) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; if (wl->p2p->vif_created) { s32 index = 0; - WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n", - net->name, wl->p2p->vir_ifname)); + WL_DBG(("IF_DEL event called from dongle, net %x, vif name: %s\n", + (unsigned int)net, wl->p2p->vir_ifname)); memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); index = wl_cfgp2p_find_idx(wl, net); @@ -1208,7 +1123,7 @@ s32 wl_cfg80211_is_progress_ifadd(void) { s32 is_progress = 0; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; if (wl_get_p2p_status(wl, IF_ADD)) is_progress = 1; return is_progress; @@ -1218,7 +1133,7 @@ s32 wl_cfg80211_is_progress_ifchange(void) { s32 is_progress = 0; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; if (wl_get_p2p_status(wl, IF_CHANGING)) is_progress = 1; return is_progress; @@ -1228,7 +1143,7 @@ wl_cfg80211_is_progress_ifchange(void) s32 wl_cfg80211_notify_ifchange(void) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; if (wl_get_p2p_status(wl, IF_CHANGING)) { wl_set_p2p_status(wl, IF_CHANGED); wake_up_interruptible(&wl->dongle_event_wait); @@ -1236,8 +1151,16 @@ wl_cfg80211_notify_ifchange(void) return 0; } -static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid) +static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) { + u32 n_ssids = request->n_ssids; + u32 n_channels = request->n_channels; + u16 channel; + chanspec_t chanspec; + s32 i, offset; + char *ptr; + wlc_ssid_t ssid; + memcpy(¶ms->bssid, ðer_bcast, ETHER_ADDR_LEN); params->bss_type = DOT11_BSSTYPE_ANY; params->scan_type = 0; @@ -1246,63 +1169,142 @@ static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid) params->passive_time = -1; params->home_time = -1; params->channel_num = 0; + memset(¶ms->ssid, 0, sizeof(wlc_ssid_t)); + + WL_SCAN(("Preparing Scan request\n")); + WL_SCAN(("nprobes=%d\n", params->nprobes)); + WL_SCAN(("active_time=%d\n", params->active_time)); + WL_SCAN(("passive_time=%d\n", params->passive_time)); + WL_SCAN(("home_time=%d\n", params->home_time)); + WL_SCAN(("scan_type=%d\n", params->scan_type)); params->nprobes = htod32(params->nprobes); params->active_time = htod32(params->active_time); params->passive_time = htod32(params->passive_time); params->home_time = htod32(params->home_time); - if (ssid && ssid->SSID_len) - memcpy(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); + /* Copy channel array if applicable */ + WL_SCAN(("### List of channelspecs to scan ###\n")); + if (n_channels > 0) { + for (i = 0; i < n_channels; i++) { + chanspec = 0; + channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq); + if (request->channels[i]->band == IEEE80211_BAND_2GHZ) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40) { + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + } else { + chanspec |= WL_CHANSPEC_BW_40; + if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40PLUS) + chanspec |= WL_CHANSPEC_CTL_SB_LOWER; + else + chanspec |= WL_CHANSPEC_CTL_SB_UPPER; + } + + params->channel_list[i] = channel; + params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK; + params->channel_list[i] |= chanspec; + WL_SCAN(("Chan : %d, Channel spec: %x \n", + channel, params->channel_list[i])); + params->channel_list[i] = htod16(params->channel_list[i]); + } + } else { + WL_SCAN(("Scanning all channels\n")); + } + + /* Copy ssid array if applicable */ + WL_SCAN(("### List of SSIDs to scan ###\n")); + if (n_ssids > 0) { + offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16); + offset = roundup(offset, sizeof(u32)); + ptr = (char*)params + offset; + for (i = 0; i < n_ssids; i++) { + memset(&ssid, 0, sizeof(wlc_ssid_t)); + ssid.SSID_len = request->ssids[i].ssid_len; + memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len); + if (!ssid.SSID_len) + WL_SCAN(("%d: Broadcast scan\n", i)); + else + WL_SCAN(("%d: scan for %s size =%d\n", i, + ssid.SSID, ssid.SSID_len)); + memcpy(ptr, &ssid, sizeof(wlc_ssid_t)); + ptr += sizeof(wlc_ssid_t); + } + } else { + WL_SCAN(("Broadcast scan\n")); + } + /* Adding mask to channel numbers */ + params->channel_num = + htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) | + (n_channels & WL_SCAN_PARAMS_COUNT_MASK)); } static s32 -wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action) +wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action) { + u32 n_channels; + u32 n_ssids; s32 params_size = - (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); + (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params)); struct wl_iscan_params *params; s32 err = 0; - if (ssid && ssid->SSID_len) - params_size += sizeof(struct wlc_ssid); + if (request != NULL) { + n_channels = request->n_channels; + n_ssids = request->n_ssids; + /* Allocate space for populating ssids in wl_iscan_params struct */ + if (n_channels % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + + /* Allocate space for populating ssids in wl_iscan_params struct */ + params_size += sizeof(struct wlc_ssid) * n_ssids; + } params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); - if (unlikely(!params)) - return -ENOMEM; - memset(params, 0, params_size); - BUG_ON(unlikely(params_size >= WLC_IOCTL_SMLEN)); + if (!params) { + err = -ENOMEM; + goto done; + } - wl_iscan_prep(¶ms->params, ssid); + if (request != NULL) + wl_scan_prep(¶ms->params, request); params->version = htod32(ISCAN_REQ_VERSION); params->action = htod16(action); params->scan_duration = htod16(0); - /* params_size += offsetof(wl_iscan_params_t, params); */ + if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) { + WL_ERR(("ioctl buffer length is not sufficient\n")); + err = -ENOMEM; + goto done; + } err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size, - iscan->ioctl_buf, WLC_IOCTL_SMLEN); + iscan->ioctl_buf, WLC_IOCTL_MEDLEN); if (unlikely(err)) { if (err == -EBUSY) { - WL_INFO(("system busy : iscan canceled\n")); + WL_INFO(("system busy : iscan canceled\n")); } else { WL_ERR(("error (%d)\n", err)); } } kfree(params); +done: return err; } -static s32 wl_do_iscan(struct wl_priv *wl) +static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request) { struct wl_iscan_ctrl *iscan = wl_to_iscan(wl); struct net_device *ndev = wl_to_prmry_ndev(wl); - struct wlc_ssid ssid; s32 passive_scan; s32 err = 0; - /* Broadcast scan by default */ - memset(&ssid, 0, sizeof(ssid)); - iscan->state = WL_ISCAN_STATE_SCANING; passive_scan = wl->active_scan ? 0 : 1; @@ -1313,7 +1315,7 @@ static s32 wl_do_iscan(struct wl_priv *wl) return err; } wl->iscan_kickstart = true; - wl_run_iscan(iscan, &ssid, WL_SCAN_ACTION_START); + wl_run_iscan(iscan, request, WL_SCAN_ACTION_START); mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); iscan->timer_on = 1; @@ -1321,9 +1323,12 @@ static s32 wl_do_iscan(struct wl_priv *wl) } static s32 -wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint16 action) +wl_run_escan(struct wl_priv *wl, struct net_device *ndev, + struct cfg80211_scan_request *request, uint16 action) { s32 err = BCME_OK; + u32 n_channels; + u32 n_ssids; s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); wl_escan_params_t *params; struct cfg80211_scan_request *scan_request = wl->scan_request; @@ -1337,31 +1342,37 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) && !p2p_scan(wl))) { /* LEGACY SCAN TRIGGER */ - WL_DBG(("LEGACY SCAN START\n")); - if (ssid && ssid->SSID_len) { - params_size += sizeof(wlc_ssid_t); + WL_SCAN((" LEGACY E-SCAN START\n")); + + if (request != NULL) { + n_channels = request->n_channels; + n_ssids = request->n_ssids; + /* Allocate space for populating ssids in wl_iscan_params struct */ + if (n_channels % 2) + /* If n_channels is odd, add a padd of u16 */ + params_size += sizeof(u16) * (n_channels + 1); + else + params_size += sizeof(u16) * n_channels; + + /* Allocate space for populating ssids in wl_iscan_params struct */ + params_size += sizeof(struct wlc_ssid) * n_ssids; } - params = (wl_escan_params_t *) kmalloc(params_size, GFP_KERNEL); - - if (params == NULL) - return -ENOMEM; - - memset(params, 0, params_size); - memcpy(¶ms->params.bssid, ðer_bcast, ETHER_ADDR_LEN); - params->params.bss_type = DOT11_BSSTYPE_ANY; - params->params.scan_type = 0; - 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 = 0; - if (ssid && ssid->SSID_len) { - memcpy(params->params.ssid.SSID, ssid->SSID, ssid->SSID_len); - params->params.ssid.SSID_len = htod32(ssid->SSID_len); + params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL); + if (params == NULL) { + err = -ENOMEM; + goto exit; } + + if (request != NULL) + wl_scan_prep(¶ms->params, request); params->version = htod32(ESCAN_REQ_VERSION); params->action = htod16(action); params->sync_id = htod16(0x1234); + if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) { + WL_ERR(("ioctl buffer length not sufficient\n")); + err = -ENOMEM; + goto exit; + } wldev_iovar_setbuf(ndev, "escan", params, params_size, wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN); kfree(params); @@ -1370,7 +1381,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint /* P2P SCAN TRIGGER */ if (scan_request && scan_request->n_channels) { num_chans = scan_request->n_channels; - WL_INFO((" chann number : %d\n", num_chans)); + WL_SCAN((" chann number : %d\n", num_chans)); default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list), GFP_KERNEL); if (default_chan_list == NULL) { @@ -1407,12 +1418,13 @@ exit: static s32 -wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wlc_ssid_t *ssid) +wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) { s32 err = BCME_OK; s32 passive_scan; wl_scan_results_t *results; - WL_DBG(("Enter \n")); + WL_SCAN(("Enter \n")); wl->escan_info.wiphy = wiphy; wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; @@ -1428,7 +1440,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wl results->count = 0; results->buflen = WL_SCAN_RESULTS_FIXED_SIZE; - wl_run_escan(wl, ndev, ssid, WL_SCAN_ACTION_START); + wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START); return err; } @@ -1437,15 +1449,16 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request, struct cfg80211_ssid *this_ssid) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct cfg80211_ssid *ssids; struct wl_scan_req *sr = wl_to_sr(wl); - wlc_ssid_t ssid_info; s32 passive_scan; bool iscan_req; bool escan_req; bool spec_scan; + bool p2p_ssid; s32 err = 0; + s32 i; if (unlikely(wl_get_drv_status(wl, SCANNING))) { WL_ERR(("Scanning already : status (%d)\n", (int)wl->status)); @@ -1456,6 +1469,10 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, (int)wl->status)); return -EAGAIN; } + if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { + WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); + return -EOPNOTSUPP; + } WL_DBG(("wiphy (%p)\n", wiphy)); @@ -1463,11 +1480,18 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, spec_scan = false; if (request) { /* scan bss */ ssids = request->ssids; - if (wl->iscan_on && (!ssids || !ssids->ssid_len)) { + if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) { iscan_req = true; } else if (wl->escan_on) { escan_req = true; - if (ssids->ssid_len && IS_P2P_SSID(ssids->ssid)) { + p2p_ssid = false; + for (i = 0; i < request->n_ssids; i++) { + if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid)) { + p2p_ssid = true; + break; + } + } + if (p2p_ssid) { if (wl->p2p_supported) { /* p2p scan trigger */ if (p2p_on(wl) == false) { @@ -1477,7 +1501,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } p2p_scan(wl) = true; } - } else { /* legacy scan trigger * So, we have to disable p2p discovery if p2p discovery is on @@ -1510,17 +1533,12 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, wl->scan_request = request; wl_set_drv_status(wl, SCANNING); if (iscan_req) { - err = wl_do_iscan(wl); + err = wl_do_iscan(wl, request); if (likely(!err)) return err; else goto scan_out; } else if (escan_req) { - WL_DBG(("ssid \"%s\", ssid_len (%d)\n", - ssids->ssid, ssids->ssid_len)); - - memcpy(ssid_info.SSID, ssids->ssid, ssids->ssid_len); - ssid_info.SSID_len = ssids->ssid_len; if (wl->p2p_supported) { if (p2p_on(wl) && p2p_scan(wl)) { @@ -1532,7 +1550,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } } - err = wl_do_escan(wl, wiphy, ndev, &ssid_info); + err = wl_do_escan(wl, wiphy, ndev, request); if (likely(!err)) return err; else @@ -1546,18 +1564,18 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (sr->ssid.SSID_len) { memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len); sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); - WL_DBG(("Specific scan ssid=\"%s\" len=%d\n", + WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n", sr->ssid.SSID, sr->ssid.SSID_len)); spec_scan = true; } else { - WL_DBG(("Broadcast scan\n")); + WL_SCAN(("Broadcast scan\n")); } - WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); + WL_SCAN(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len)); passive_scan = wl->active_scan ? 0 : 1; err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN, &passive_scan, sizeof(passive_scan), false); if (unlikely(err)) { - WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); + WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err)); goto scan_out; } err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid, @@ -1586,9 +1604,10 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) { s32 err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); WL_DBG(("Enter \n")); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); err = __wl_cfg80211_scan(wiphy, ndev, request, NULL); if (unlikely(err)) { WL_ERR(("scan error (%d)\n", err)); @@ -1679,11 +1698,11 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l) static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { - struct wl_priv *wl = wiphy_to_wl(wiphy); + struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy); struct net_device *ndev = wl_to_prmry_ndev(wl); s32 err = 0; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); if (changed & WIPHY_PARAM_RTS_THRESHOLD && (wl->conf->rts_threshold != wiphy->rts_threshold)) { wl->conf->rts_threshold = wiphy->rts_threshold; @@ -1721,7 +1740,7 @@ static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct cfg80211_bss *bss; struct ieee80211_channel *chan; struct wl_join_params join_params; @@ -1730,7 +1749,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; WL_TRACE(("In\n")); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); if (params->bssid) { WL_ERR(("Invalid bssid\n")); return -EOPNOTSUPP; @@ -1791,10 +1810,10 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); wl_link_down(wl); return err; @@ -1803,7 +1822,7 @@ static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) static s32 wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; struct wl_security *sec; s32 val = 0; s32 err = 0; @@ -1833,7 +1852,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) static s32 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; struct wl_security *sec; s32 val = 0; s32 err = 0; @@ -1872,7 +1891,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) static s32 wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; struct wl_security *sec; s32 pval = 0; s32 gval = 0; @@ -1944,7 +1963,7 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) static s32 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; struct wl_security *sec; s32 val = 0; s32 err = 0; @@ -2002,7 +2021,7 @@ static s32 wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; struct wl_security *sec; struct wl_wsec_key key; s32 val; @@ -2068,14 +2087,17 @@ static s32 wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct ieee80211_channel *chan = sme->channel; struct wl_join_params join_params; size_t join_params_size; s32 err = 0; - + wpa_ie_fixed_t *wpa_ie; + bcm_tlv_t *wpa2_ie; + u8* wpaie = 0; + u32 wpaie_len = 0; WL_DBG(("In\n")); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. @@ -2107,8 +2129,28 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); } - } else { - WL_INFO(("No P2PIE in beacon \n")); + } else if (dev == wl_to_prmry_ndev(wl)) { + /* find the RSN_IE */ + if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len, + DOT11_MNG_RSN_ID)) != NULL) { + WL_DBG((" WPA2 IE is found\n")); + } + /* find the WPA_IE */ + if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie, + sme->ie_len)) != NULL) { + WL_DBG((" WPA IE is found\n")); + } + if (wpa_ie != NULL || wpa2_ie != NULL) { + wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie; + wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; + wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; + wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, + ioctlbuf, sizeof(ioctlbuf)); + } else { + wldev_iovar_setbuf(dev, "wpaie", NULL, 0, + ioctlbuf, sizeof(ioctlbuf)); + } + } if (unlikely(!sme->ssid)) { @@ -2119,7 +2161,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl->channel = ieee80211_frequency_to_channel(chan->center_freq); WL_DBG(("channel (%d), center_req (%d)\n", wl->channel, chan->center_freq)); - } + } else + wl->channel = 0; WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); err = wl_set_wpa_version(dev, sme); if (unlikely(err)) @@ -2153,7 +2196,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID); - memcpy(&join_params.params.bssid, ðer_bcast, ETHER_ADDR_LEN); + if (sme->bssid) + memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); + else + memcpy(&join_params.params.bssid, ðer_bcast, ETH_ALEN); wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size); WL_DBG(("join_param_size %d\n", join_params_size)); @@ -2162,13 +2208,13 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, join_params.ssid.SSID_len)); } + wl_set_drv_status(wl, CONNECTING); err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); + wl_clr_drv_status(wl, CONNECTING); return err; } - wl_set_drv_status(wl, CONNECTING); - return err; } @@ -2176,21 +2222,29 @@ static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); scb_val_t scbval; bool act = false; s32 err = 0; WL_ERR(("Reason %d\n\n\n", reason_code)); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); act = *(bool *) wl_read_prof(wl, WL_PROF_ACT); if (likely(act)) { + /* + * Cancel ongoing scan to sync up with sme state machine of cfg80211. + */ + if (wl->scan_request) { + wl_cfg80211_scan_abort(wl, dev); + } + wl_set_drv_status(wl, DISCONNECTING); scbval.val = reason_code; memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), false); if (unlikely(err)) { + wl_clr_drv_status(wl, DISCONNECTING); WL_ERR(("error (%d)\n", err)); return err; } @@ -2204,13 +2258,13 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, s32 dbm) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *ndev = wl_to_prmry_ndev(wl); u16 txpwrmw; s32 err = 0; s32 disable = 0; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); switch (type) { case NL80211_TX_POWER_AUTOMATIC: break; @@ -2253,13 +2307,13 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *ndev = wl_to_prmry_ndev(wl); s32 txpwrdbm; u8 result; s32 err = 0; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); @@ -2275,14 +2329,14 @@ static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool unicast, bool multicast) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); u32 index; s32 wsec; s32 err = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); WL_DBG(("key index (%d)\n", key_idx)); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx); if (unlikely(err)) { WL_ERR(("WLC_GET_WSEC error (%d)\n", err)); @@ -2305,7 +2359,7 @@ static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, const u8 *mac_addr, struct key_params *params) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct wl_wsec_key key; s32 err = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); @@ -2404,10 +2458,10 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, s32 err = 0; u8 keybuf[8]; s32 bssidx = 0; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 mode = get_mode_by_netdev(wl, dev); WL_DBG(("key index (%d)\n", key_idx)); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); bssidx = wl_cfgp2p_find_idx(wl, dev); @@ -2505,12 +2559,12 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, bool pairwise, const u8 *mac_addr) { struct wl_wsec_key key; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); WL_DBG(("Enter\n")); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -2554,14 +2608,14 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, { struct key_params params; struct wl_wsec_key key; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct wl_security *sec; s32 wsec; s32 err = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); WL_DBG(("key index (%d)\n", key_idx)); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); memset(&key, 0, sizeof(key)); key.index = key_idx; swap_key_to_BE(&key); @@ -2607,7 +2661,6 @@ wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, struct net_device *dev, u8 key_idx) { WL_INFO(("Not supported\n")); - CHECK_SYS_UP(); return -EOPNOTSUPP; } @@ -2615,13 +2668,13 @@ static s32 wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); scb_val_t scb_val; int rssi; s32 rate; s32 err = 0; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); if (unlikely (memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) { WL_ERR(("Wrong Mac address\n")); @@ -2672,9 +2725,15 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, { s32 pm; s32 err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); pm = enabled ? PM_FAST : PM_OFF; + /* Do not enable the power save after assoc if it is p2p interface */ + if (wl->p2p && wl->p2p->vif_created) { + WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n")); + pm = PM_OFF; + } pm = htod32(pm); WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled"))); err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), false); @@ -2717,7 +2776,7 @@ static __used u32 wl_find_msb(u16 bit16) static s32 wl_cfg80211_resume(struct wiphy *wiphy) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; if (unlikely(!wl_get_drv_status(wl, READY))) { @@ -2737,9 +2796,8 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) static s32 wl_cfg80211_suspend(struct wiphy *wiphy) #endif { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; - if (unlikely(!wl_get_drv_status(wl, READY))) { WL_INFO(("device is not ready : status (%d)\n", (int)wl->status)); @@ -2763,7 +2821,7 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, s32 err) { int i, j; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; struct net_device *primary_dev = wl_to_prmry_ndev(wl); /* Firmware is supporting pmk list only for STA interface i.e. primary interface @@ -2771,7 +2829,7 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, * Do we really need to support PMK cache in P2P in firmware? */ if (primary_dev != dev) { - WL_ERR(("Not supporting Flushing pmklist on virtual" + WL_INFO(("Not supporting Flushing pmklist on virtual" " interfaces than primary interface\n")); return err; } @@ -2796,11 +2854,11 @@ static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; int i; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++) if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID, ETHER_ADDR_LEN)) @@ -2816,10 +2874,10 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev, err = -EINVAL; } WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", - &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID)); + &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID)); for (i = 0; i < WPA2_PMKID_LEN; i++) { WL_DBG(("%02x\n", - wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid]. + wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1]. PMKID[i])); } @@ -2832,12 +2890,12 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct _pmkid_list pmkid; s32 err = 0; int i; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN); memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN); @@ -2878,9 +2936,9 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); s32 err = 0; - CHECK_SYS_UP(); + CHECK_SYS_UP(wl); memset(wl->pmk_list, 0, sizeof(*wl->pmk_list)); err = wl_update_pmklist(dev, wl->pmk_list, err); return err; @@ -2956,7 +3014,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, s32 target_channel; s32 err = BCME_OK; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex)); if (likely(wl_get_drv_status(wl, SCANNING))) { @@ -2976,12 +3034,12 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, * without turning on P2P */ + p2p_on(wl) = true; err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0); if (unlikely(err)) { goto exit; } - p2p_on(wl) = true; } if (p2p_on(wl)) wl_cfgp2p_discover_listen(wl, target_channel, duration); @@ -3012,7 +3070,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, wifi_p2p_ie_t *p2p_ie; wpa_ie_fixed_t *wps_ie; const struct ieee80211_mgmt *mgmt; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); s32 err = BCME_OK; s32 bssidx = 0; @@ -3467,7 +3525,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, s32 err = BCME_OK; bcm_tlv_t *ssid_ie; wlc_ssid_t ssid; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wiphy_priv(wiphy); struct wl_join_params join_params; wpa_ie_fixed_t *wps_ie; wpa_ie_fixed_t *wpa_ie; @@ -3582,7 +3640,10 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, wldev_iovar_setint(dev, "mpc", 0); wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), false); wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false); - wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), false); + if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), false)) < 0) { + WL_ERR(("setting AP mode failed %d \n", err)); + return err; + } /* find the RSN_IE */ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, DOT11_MNG_RSN_ID)) != NULL) { @@ -3757,7 +3818,6 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, static s32 wl_cfg80211_drv_start(struct wiphy *wiphy, struct net_device *dev) { - /* struct wl_priv *wl = wiphy_to_wl(wiphy); */ s32 err = 0; printk("Android driver start command\n"); @@ -3767,7 +3827,6 @@ wl_cfg80211_drv_start(struct wiphy *wiphy, struct net_device *dev) static s32 wl_cfg80211_drv_stop(struct wiphy *wiphy, struct net_device *dev) { - /* struct wl_priv *wl = wiphy_to_wl(wiphy); */ s32 err = 0; printk("Android driver stop command\n"); @@ -3830,28 +3889,26 @@ static s32 wl_mode_to_nl80211_iftype(s32 mode) return err; } -static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface, - struct device *dev) +static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev) { struct wireless_dev *wdev; s32 err = 0; - struct wl_priv *wl; wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); if (unlikely(!wdev)) { WL_ERR(("Could not allocate wireless device\n")); return ERR_PTR(-ENOMEM); } wdev->wiphy = - wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface); + wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); if (unlikely(!wdev->wiphy)) { WL_ERR(("Couldn not allocate wiphy device\n")); err = -ENOMEM; goto wiphy_new_out; } - set_wiphy_dev(wdev->wiphy, dev); - wl = wiphy_to_wl(wdev->wiphy); + set_wiphy_dev(wdev->wiphy, sdiofunc_dev); wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; - wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; + /* Report how many SSIDs Driver can support per Scan request */ + wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) @@ -3899,7 +3956,7 @@ wiphy_new_out: static void wl_free_wdev(struct wl_priv *wl) { int i; - struct wireless_dev *wdev = wl_to_wdev(wl); + struct wireless_dev *wdev = wl->wdev; if (unlikely(!wdev)) { WL_ERR(("wdev is invalid\n")); @@ -3913,9 +3970,9 @@ static void wl_free_wdev(struct wl_priv *wl) } } wiphy_unregister(wdev->wiphy); + wdev->wiphy->dev.parent = NULL; wiphy_free(wdev->wiphy); kfree(wdev); - wl_to_wdev(wl) = NULL; } static s32 wl_inform_bss(struct wl_priv *wl) @@ -3926,13 +3983,6 @@ static s32 wl_inform_bss(struct wl_priv *wl) s32 i; bss_list = wl->bss_list; -#if 0 - if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) { - WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n", - bss_list->version)); - return -EOPNOTSUPP; - } -#endif WL_DBG(("scanned AP count (%d)\n", bss_list->count)); bi = next_bss(bss_list, bi); for_each_bss(bss_list, bi, i) { @@ -4165,33 +4215,42 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, ntoh32(e->event_type), ntoh32(e->status))); if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); + act = true; + wl_update_prof(wl, e, &act, WL_PROF_ACT); if (wl_is_ibssmode(wl, ndev)) { printk("cfg80211_ibss_joined"); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); WL_DBG(("joined in IBSS network\n")); } else { - printk("wl_bss_connect_done succeeded"); - wl_bss_connect_done(wl, ndev, e, data, true); - WL_DBG(("joined in BSS network \"%s\"\n", + if (!wl_get_drv_status(wl, DISCONNECTING)) { + printk("wl_bss_connect_done succeeded"); + wl_bss_connect_done(wl, ndev, e, data, true); + WL_DBG(("joined in BSS network \"%s\"\n", ((struct wlc_ssid *) wl_read_prof(wl, WL_PROF_SSID))->SSID)); + } } - act = true; - wl_update_prof(wl, e, &act, WL_PROF_ACT); + } else if (wl_is_linkdown(wl, e)) { + if (wl->scan_request) { + if (wl->escan_on) { + wl_notify_escan_complete(wl, true); + } else + wl_iscan_aborted(wl); + } if (wl_get_drv_status(wl, CONNECTED)) { printk("link down, call cfg80211_disconnected "); - rtnl_lock(); - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); wl_clr_drv_status(wl, CONNECTED); + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); wl_link_down(wl); wl_init_prof(wl->profile); - rtnl_unlock(); } else if (wl_get_drv_status(wl, CONNECTING)) { printk("link down, during connecting"); wl_bss_connect_done(wl, ndev, e, data, false); } + wl_clr_drv_status(wl, DISCONNECTING); + } else if (wl_is_nonetwork(wl, e)) { printk("connect failed e->status 0x%x", (int)ntoh32(e->status)); if (wl_get_drv_status(wl, CONNECTING)) @@ -4215,24 +4274,22 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, s32 err = 0; u32 event = be32_to_cpu(e->event_type); u32 status = be32_to_cpu(e->status); - WL_DBG(("Enter \n")); if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) { - if (test_bit(WL_STATUS_CONNECTED, &wl->status)) + if (wl_get_drv_status(wl, CONNECTED)) wl_bss_roaming_done(wl, ndev, e, data); else wl_bss_connect_done(wl, ndev, e, data, true); act = true; wl_update_prof(wl, e, &act, WL_PROF_ACT); } - return err; } static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; u32 buflen; buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX); @@ -4245,7 +4302,7 @@ static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, s32 buf_len) { - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; u32 len; s32 err = 0; @@ -4279,6 +4336,14 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) assoc_info.req_len = htod32(assoc_info.req_len); assoc_info.resp_len = htod32(assoc_info.resp_len); assoc_info.flags = htod32(assoc_info.flags); + if (conn_info->req_ie_len) { + conn_info->req_ie_len = 0; + bzero(conn_info->req_ie, sizeof(conn_info->req_ie)); + } + if (conn_info->resp_ie_len) { + conn_info->resp_ie_len = 0; + bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); + } if (assoc_info.req_len) { err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf, WL_ASSOC_INFO_MAX); @@ -4290,11 +4355,15 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) { conn_info->req_ie_len -= ETHER_ADDR_LEN; } - conn_info->req_ie = - kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL); + if (conn_info->req_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len); + else { + WL_ERR(("%s IE size %d above max %d size \n", + __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE)); + return err; + } } else { conn_info->req_ie_len = 0; - conn_info->req_ie = NULL; } if (assoc_info.resp_len) { err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf, @@ -4304,11 +4373,15 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) return err; } conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp); - conn_info->resp_ie = - kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL); + if (conn_info->resp_ie_len <= MAX_REQ_LINE) + memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len); + else { + WL_ERR(("%s IE size %d above max %d size \n", + __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE)); + return err; + } } else { conn_info->resp_ie_len = 0; - conn_info->resp_ie = NULL; } WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len, conn_info->resp_ie_len)); @@ -4437,6 +4510,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, wl_get_assoc_ies(wl, ndev); memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); wl_update_bss_info(wl, ndev); + wl_update_pmklist(ndev, wl->pmk_list, err); cfg80211_roamed(ndev, #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) NULL, @@ -4459,11 +4533,18 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, s32 err = 0; WL_DBG((" enter\n")); - wl_get_assoc_ies(wl, ndev); - memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); - wl_update_bss_info(wl, ndev); + if (wl->scan_request) { + wl_cfg80211_scan_abort(wl, ndev); + } if (wl_get_drv_status(wl, CONNECTING)) { wl_clr_drv_status(wl, CONNECTING); + if (completed) { + wl_get_assoc_ies(wl, ndev); + memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN); + wl_update_bss_info(wl, ndev); + wl_update_pmklist(ndev, wl->pmk_list, err); + wl_set_drv_status(wl, CONNECTED); + } cfg80211_connect_result(ndev, (u8 *)&wl->bssid, conn_info->req_ie, @@ -4475,14 +4556,6 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, WL_DBG(("Report connect result - connection %s\n", completed ? "succeeded" : "failed")); } - if (completed) - wl_set_drv_status(wl, CONNECTED); - else { - if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, ndev); - } - } - return err; } @@ -4740,7 +4813,7 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("Ioctl buf alloc failed\n")); goto init_priv_mem_out; } - wl->escan_ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); + wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); if (unlikely(!wl->escan_ioctl_buf)) { WL_ERR(("Ioctl buf alloc failed\n")); goto init_priv_mem_out; @@ -4809,24 +4882,20 @@ static void wl_deinit_priv_mem(struct wl_priv *wl) static s32 wl_create_event_handler(struct wl_priv *wl) { + int ret = 0; WL_DBG(("Enter \n")); - sema_init(&wl->event_sync, 0); - wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler"); - if (IS_ERR(wl->event_tsk)) { - wl->event_tsk = NULL; - WL_ERR(("failed to create event thread\n")); - return -ENOMEM; - } - return 0; + + wl->event_tsk.thr_pid = DHD_PID_KT_INVALID; + PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); + if (wl->event_tsk.thr_pid < 0) + ret = -ENOMEM; + return ret; } static void wl_destroy_event_handler(struct wl_priv *wl) { - if (wl->event_tsk) { - send_sig(SIGTERM, wl->event_tsk, 1); - kthread_stop(wl->event_tsk); - wl->event_tsk = NULL; - } + if (wl->event_tsk.thr_pid >= 0) + PROC_STOP(&wl->event_tsk); } static void wl_term_iscan(struct wl_priv *wl) @@ -5046,6 +5115,7 @@ static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted) if (unlikely(!wl_get_drv_status(wl, SCANNING))) { wl_clr_drv_status(wl, SCANNING); WL_ERR(("Scan complete while device not scanning\n")); + wl->scan_request = NULL; return; } wl_clr_drv_status(wl, SCANNING); @@ -5152,7 +5222,9 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; if (likely(wl->scan_request)) { rtnl_lock(); - WL_INFO(("ESCAN COMPLETED\n")); + WL_INFO(("ESCAN ABORTED\n")); + wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; + wl_inform_bss(wl); wl_notify_escan_complete(wl, true); rtnl_unlock(); } @@ -5251,7 +5323,7 @@ s32 wl_cfg80211_sysctl_export_devaddr(void *data) * so that wpa_supplicant can access it */ dhd_pub_t *dhd = (dhd_pub_t *)data; - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); @@ -5271,7 +5343,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) WL_ERR(("ndev is invaild\n")); return -ENODEV; } - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; if (wl && !wl_get_drv_status(wl, READY)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { @@ -5296,7 +5368,6 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) { struct wireless_dev *wdev; struct wl_priv *wl; - struct wl_iface *ci; s32 err = 0; WL_TRACE(("In\n")); @@ -5304,23 +5375,16 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) WL_ERR(("ndev is invaild\n")); return -ENODEV; } - wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL); - if (unlikely(!wl_cfg80211_dev)) { - WL_ERR(("wl_cfg80211_dev is invalid\n")); - return -ENOMEM; - } WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func())); - wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev); + wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev); if (unlikely(IS_ERR(wdev))) return -ENOMEM; wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); - wl = wdev_to_wl(wdev); + wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); wl->wdev = wdev; wl->pub = data; - ci = (struct wl_iface *)wl_to_ci(wl); - ci->wl = wl; ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; @@ -5343,7 +5407,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) goto cfg80211_attach_out; } #endif - wl_set_drvdata(wl_cfg80211_dev, ci); + wlcfg_drv_priv = wl; return err; cfg80211_attach_out: @@ -5356,7 +5420,7 @@ void wl_cfg80211_detach(void) { struct wl_priv *wl; - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; WL_TRACE(("In\n")); #if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL) @@ -5367,29 +5431,30 @@ void wl_cfg80211_detach(void) if (wl->p2p_supported) wl_cfgp2p_deinit_priv(wl); wl_deinit_priv(wl); - wl_free_wdev(wl); - wl_set_drvdata(wl_cfg80211_dev, NULL); - kfree(wl_cfg80211_dev); - wl_cfg80211_dev = NULL; + wlcfg_drv_priv = NULL; wl_clear_sdio_func(); + wl_free_wdev(wl); } static void wl_wakeup_event(struct wl_priv *wl) { - up(&wl->event_sync); + if (wl->event_tsk.thr_pid >= 0) + up(&wl->event_tsk.sema); } static s32 wl_event_handler(void *data) { struct net_device *netdev; - struct wl_priv *wl = (struct wl_priv *)data; - struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; + struct wl_priv *wl = NULL; struct wl_event_q *e; + tsk_ctl_t *tsk = (tsk_ctl_t *)data; - sched_setscheduler(current, SCHED_FIFO, ¶m); - allow_signal(SIGTERM); - while (likely(!down_interruptible(&wl->event_sync))) { - if (kthread_should_stop()) + wl = (struct wl_priv *)tsk->parent; + complete(&tsk->completed); + + while (down_interruptible (&tsk->sema) == 0) { + SMP_RD_BARRIER_DEPENDS(); + if (tsk->terminated) break; e = wl_deq_event(wl); if (unlikely(!e)) { @@ -5400,7 +5465,7 @@ static s32 wl_event_handler(void *data) netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); if (!netdev) netdev = wl_to_prmry_ndev(wl); - if (wl->evt_handler[e->etype]) { + if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); } else { WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); @@ -5408,6 +5473,7 @@ static s32 wl_event_handler(void *data) wl_put_event(e); } WL_DBG(("%s was terminated\n", __func__)); + complete_and_exit(&tsk->completed, 0); return 0; } @@ -5415,7 +5481,7 @@ void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) { u32 event_type = ntoh32(e->event_type); - struct wl_priv *wl = WL_PRIV_GET(); + struct wl_priv *wl = wlcfg_drv_priv; #if (WL_DBG_LEVEL > 0) s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ? @@ -5619,14 +5685,12 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev) setbit(eventmask, WLC_E_DISASSOC_IND); setbit(eventmask, WLC_E_DISASSOC); setbit(eventmask, WLC_E_JOIN); + setbit(eventmask, WLC_E_ROAM); setbit(eventmask, WLC_E_ASSOC_IND); - setbit(eventmask, WLC_E_PSK_SUP); setbit(eventmask, WLC_E_LINK); - setbit(eventmask, WLC_E_NDIS_LINK); setbit(eventmask, WLC_E_MIC_ERROR); setbit(eventmask, WLC_E_PMKID_CACHE); setbit(eventmask, WLC_E_TXFAIL); - setbit(eventmask, WLC_E_JOIN_START); setbit(eventmask, WLC_E_SCAN_COMPLETE); setbit(eventmask, WLC_E_ACTION_FRAME_RX); setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE); @@ -5997,27 +6061,24 @@ default_conf_out: static s32 wl_update_wiphybands(struct wl_priv *wl) { struct wiphy *wiphy; - s32 phy_list; - s8 phy; + s8 phylist_buf[128]; + s8 *phy; s32 err = 0; - err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list, - sizeof(phy_list), false); + err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf, + sizeof(phylist_buf), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; } - - phy = ((char *)&phy_list)[1]; - WL_DBG(("%c phy\n", phy)); - if (phy == 'a') { - wiphy = wl_to_wiphy(wl); - wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - } else if (phy == 'n') { - wiphy = wl_to_wiphy(wl); - wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + phy = phylist_buf; + for (; *phy; phy++) { + if (*phy == 'a' || *phy == 'n') { + wiphy = wl_to_wiphy(wl); + wiphy->bands[IEEE80211_BAND_5GHZ] = + &__wl_band_5ghz_a; + } } - return err; } @@ -6056,7 +6117,9 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) wl_clr_drv_status(wl, READY); wl_clr_drv_status(wl, SCANNING); wl_clr_drv_status(wl, SCAN_ABORTING); + wl_clr_drv_status(wl, CONNECTING); wl_clr_drv_status(wl, CONNECTED); + wl_clr_drv_status(wl, DISCONNECTING); if (wl_get_drv_status(wl, AP_CREATED)) { wl_clr_drv_status(wl, AP_CREATED); wl_clr_drv_status(wl, AP_CREATING); @@ -6081,7 +6144,7 @@ s32 wl_cfg80211_up(void) s32 err = 0; WL_TRACE(("In\n")); - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); err = __wl_cfg80211_up(wl); @@ -6098,7 +6161,7 @@ s32 wl_cfg80211_down(void) s32 err = 0; WL_TRACE(("In\n")); - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); err = __wl_cfg80211_down(wl); mutex_unlock(&wl->usr_sync); @@ -6266,11 +6329,7 @@ static void wl_link_down(struct wl_priv *wl) WL_DBG(("In\n")); wl->link_up = false; - kfree(conn_info->req_ie); - conn_info->req_ie = NULL; conn_info->req_ie_len = 0; - kfree(conn_info->resp_ie); - conn_info->resp_ie = NULL; conn_info->resp_ie_len = 0; } @@ -6299,22 +6358,12 @@ static void wl_delay(u32 ms) } } -static void wl_set_drvdata(struct wl_dev *dev, void *data) -{ - dev->driver_data = data; -} - -static void *wl_get_drvdata(struct wl_dev *dev) -{ - return dev->driver_data; -} - s32 wl_cfg80211_read_fw(s8 *buf, u32 size) { const struct firmware *fw_entry; struct wl_priv *wl; - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; fw_entry = wl->fw->fw_entry; @@ -6330,7 +6379,7 @@ void wl_cfg80211_release_fw(void) { struct wl_priv *wl; - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; release_firmware(wl->fw->fw_entry); wl->fw->ptr = 0; } @@ -6343,7 +6392,7 @@ void *wl_cfg80211_request_fw(s8 *file_name) WL_TRACE(("In\n")); WL_DBG(("file name : \"%s\"\n", file_name)); - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) { err = request_firmware(&wl->fw->fw_entry, file_name, @@ -6388,7 +6437,7 @@ s8 *wl_cfg80211_get_fwname(void) { struct wl_priv *wl; - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; strcpy(wl->fw->fw_name, WL_4329_FW_FILE); return wl->fw->fw_name; } @@ -6397,7 +6446,7 @@ s8 *wl_cfg80211_get_nvramname(void) { struct wl_priv *wl; - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE); return wl->fw->nvram_name; } @@ -6408,7 +6457,7 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd dhd_pub_t *dhd_pub; struct ether_addr p2pif_addr; - wl = WL_PRIV_GET(); + wl = wlcfg_drv_priv; dhd_pub = (dhd_pub_t *)wl->pub; wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 838003bd644..a5637240c17 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -52,6 +52,7 @@ struct wl_ibss; #define dtohchanspec(i) i #define WL_DBG_NONE 0 +#define WL_DBG_SCAN (1 << 3) #define WL_DBG_DBG (1 << 2) #define WL_DBG_INFO (1 << 1) #define WL_DBG_ERR (1 << 0) @@ -74,6 +75,13 @@ do { \ printk args; \ } \ } while (0) +#define WL_SCAN(args) \ +do { \ + if (wl_dbg_level & WL_DBG_SCAN) { \ + printk(KERN_ERR "CFG80211-SCAN) %s :", __func__); \ + printk args; \ + } \ +} while (0) #if (WL_DBG_LEVEL > 0) #define WL_DBG(args) \ do { \ @@ -87,7 +95,6 @@ do { \ #endif /* (WL_DBG_LEVEL > 0) */ #define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */ -#define WL_NUM_SCAN_MAX 1 #define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used * for 2.6.33 kernel * or later @@ -122,6 +129,7 @@ enum wl_status { WL_STATUS_SCAN_ABORTING, WL_STATUS_CONNECTING, WL_STATUS_CONNECTED, + WL_STATUS_DISCONNECTING, WL_STATUS_AP_CREATING, WL_STATUS_AP_CREATED }; @@ -188,14 +196,6 @@ struct wl_conf { typedef s32(*EVENT_HANDLER) (struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); -/* representing interface of cfg80211 plane */ -struct wl_iface { - struct wl_priv *wl; -}; - -struct wl_dev { - void *driver_data; /* to store cfg80211 object information */ -}; /* bss inform structure for cfg80211 interface */ struct wl_cfg80211_bss_info { @@ -274,10 +274,11 @@ struct wl_iscan_ctrl { }; /* association inform */ +#define MAX_REQ_LINE 1024 struct wl_connect_info { - u8 *req_ie; + u8 req_ie[MAX_REQ_LINE]; s32 req_ie_len; - u8 *resp_ie; + u8 resp_ie[MAX_REQ_LINE]; s32 resp_ie_len; }; @@ -347,7 +348,6 @@ struct wl_priv { struct ether_addr bssid; /* bssid of currently engaged network */ /* for synchronization of main event thread */ - struct semaphore event_sync; struct wl_profile *profile; /* holding dongle profile */ struct wl_iscan_ctrl *iscan; /* iscan controller */ @@ -357,7 +357,7 @@ struct wl_priv { /* control firwmare and nvram paramter downloading */ struct wl_fw_ctrl *fw; struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ - struct task_struct *event_tsk; /* task of main event handler thread */ + tsk_ctl_t event_tsk; /* task of main event handler thread */ unsigned long status; /* current dongle status */ void *pub; u32 channel; /* current channel */ @@ -388,18 +388,11 @@ struct wl_priv { struct p2p_info *p2p; bool p2p_supported; s8 last_eventmask[WL_EVENTING_MASK_LEN]; - u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN))); }; -#define wl_to_dev(w) (wiphy_dev(wl->wdev->wiphy)) #define wl_to_wiphy(w) (w->wdev->wiphy) -#define wiphy_to_wl(w) ((struct wl_priv *)(wiphy_priv(w))) -#define wl_to_wdev(w) (w->wdev) -#define wdev_to_wl(w) ((struct wl_priv *)(wdev_priv(w))) #define wl_to_prmry_ndev(w) (w->wdev->netdev) #define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) -#define ci_to_wl(c) (ci->wl) -#define wl_to_ci(w) (&w->ci) #define wl_to_sr(w) (w->scan_req_int) #define wl_to_ie(w) (&w->ie) #define iscan_to_wl(i) ((struct wl_priv *)(i->data)) @@ -499,7 +492,7 @@ extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */ extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */ extern s32 wl_cfg80211_up(void); /* dongle up */ extern s32 wl_cfg80211_down(void); /* dongle down */ -extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, +extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx, int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)); extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); extern s32 wl_cfg80211_notify_ifdel(struct net_device *net); diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 7a5619e8ec4..98271c28658 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -176,8 +176,8 @@ wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) s32 ret; struct net_device *netdev = wl_to_prmry_ndev(wl); - CFGP2P_INFO(("---wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n", - mac->octet[0], mac->octet[1], mac->octet[2], + CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5])); ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), @@ -200,7 +200,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, { wl_p2p_if_t ifreq; s32 err; - struct net_device *netdev = wl_to_prmry_ndev(wl); + struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); ifreq.type = if_type; ifreq.chspec = chspec; @@ -970,8 +970,7 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) } while (0); s32 ret = BCME_OK; - CFGP2P_DBG((" Enter\n")); - CFGP2P_INFO(("Channel : %d, Duration : %d\n", channel, duration_ms)); + CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms)); if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) { CFGP2P_ERR((" Discovery is not set, so we have noting to do\n")); @@ -996,9 +995,9 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms) } /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , - * otherwise we will wait up to duration_ms + 10ms + * otherwise we will wait up to duration_ms + 200ms */ - INIT_TIMER(wl->p2p->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 20); + INIT_TIMER(wl->p2p->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 200); #undef INIT_TIMER exit: @@ -1048,10 +1047,13 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, if (event_type == WLC_E_ACTION_FRAME_COMPLETE) { CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status)); - if (status == WLC_E_STATUS_SUCCESS) + if (status == WLC_E_STATUS_SUCCESS) { wl_set_p2p_status(wl, ACTION_TX_COMPLETED); - else + } + else { + wl_set_p2p_status(wl, ACTION_TX_NOACK); CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); + } wake_up_interruptible(&wl->dongle_event_wait); } else { CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," @@ -1082,6 +1084,7 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, af_params->channel, af_params->dwell_time)); wl_clr_p2p_status(wl, ACTION_TX_COMPLETED); + wl_clr_p2p_status(wl, ACTION_TX_NOACK); #define MAX_WAIT_TIME 2000 if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); @@ -1095,7 +1098,7 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, goto exit; } timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, - (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) == TRUE), + (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) ||wl_get_p2p_status(wl, ACTION_TX_NOACK)), msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) { diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index d62f5422708..b08504d8f95 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -88,6 +88,7 @@ enum wl_cfgp2p_status { WLP2P_STATUS_IF_CHANGED, WLP2P_STATUS_LISTEN_EXPIRED, WLP2P_STATUS_ACTION_TX_COMPLETED, + WLP2P_STATUS_ACTION_TX_NOACK, WLP2P_STATUS_SCANNING }; diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index ae28c6d0215..6d546fcd396 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -792,7 +792,7 @@ wl_iw_set_power_mode( #ifdef COEX_DHCP g_bt->ts_dhcp_start = JF2MS; - g_bt->dhcp_done = false; + g_bt->dhcp_done = FALSE; WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n", __FUNCTION__, pm, pm_local)); @@ -806,7 +806,7 @@ wl_iw_set_power_mode( net_os_set_packet_filter(dev, 1); #ifdef COEX_DHCP - g_bt->dhcp_done = true; + g_bt->dhcp_done = TRUE; g_bt->ts_dhcp_ok = JF2MS; WL_TRACE_COEX(("%s: DHCP done for:%d ms, restored pm:%d\n", __FUNCTION__, (g_bt->ts_dhcp_ok - g_bt->ts_dhcp_start), pm)); @@ -828,7 +828,7 @@ wl_iw_set_power_mode( bool btcoex_is_sco_active(struct net_device *dev) { int ioc_res = 0; - bool res = false; + bool res = FALSE; int sco_id_cnt = 0; int param27; int i; @@ -852,7 +852,7 @@ bool btcoex_is_sco_active(struct net_device *dev) if (sco_id_cnt > 2) { WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", __FUNCTION__, sco_id_cnt, i)); - res = true; + res = TRUE; break; } @@ -866,7 +866,7 @@ bool btcoex_is_sco_active(struct net_device *dev) static int set_btc_esco_params(struct net_device *dev, bool trump_sco) { - static bool saved_status = false; + static bool saved_status = FALSE; char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; @@ -902,7 +902,7 @@ static int set_btc_esco_params(struct net_device *dev, bool trump_sco) } else { WL_ERROR((":%s: save btc_params failed\n", __FUNCTION__)); - saved_status = false; + saved_status = FALSE; return -1; } @@ -920,7 +920,7 @@ static int set_btc_esco_params(struct net_device *dev, bool trump_sco) dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8); dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8); - saved_status = true; + saved_status = TRUE; } else if (saved_status) { @@ -946,7 +946,7 @@ static int set_btc_esco_params(struct net_device *dev, bool trump_sco) saved_reg50, saved_reg51, saved_reg64, saved_reg65, saved_reg71)); - saved_status = false; + saved_status = FALSE; } else { WL_ERROR((":%s att to restore not saved BTCOEX params\n", __FUNCTION__)); @@ -6320,12 +6320,12 @@ fail: #ifndef AP_ONLY static int last_auto_channel = 6; #endif + static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap) { int chosen = 0; wl_uint32_list_t request; - int rescan = 0; int retry = 0; int updown = 0; int ret = 0; @@ -6354,42 +6354,57 @@ get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap) null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err); ASSERT(iolen); res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen); + #endif - auto_channel_retry: - request.count = htod32(0); - ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request)); - if (ret < 0) { - WL_ERROR(("can't start auto channel scan\n")); - goto fail; - } + + request.count = htod32(0); + ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request)); + if (ret < 0) { + WL_ERROR(("can't start auto channel scan\n")); + goto fail; + } get_channel_retry: - bcm_mdelay(500); + bcm_mdelay(350); - ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); - if (ret < 0 || dtoh32(chosen) == 0) { - if (retry++ < 3) - goto get_channel_retry; - else { + ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen)); + if (ret < 0 || dtoh32(chosen) == 0) { + if (retry++ < 15) { + goto get_channel_retry; + } else { + if (ret < 0) { WL_ERROR(("can't get auto channel sel, err = %d, " - "chosen = %d\n", ret, chosen)); + "chosen = 0x%04X\n", ret, (uint16)chosen)); goto fail; + } else { + ap->channel = (uint16)last_auto_channel; + WL_ERROR(("auto channel sel timed out. we get channel %d\n", + ap->channel)); } } - if ((chosen == 1) && (!rescan++)) - goto auto_channel_retry; - WL_SOFTAP(("Set auto channel = %d\n", chosen)); - ap->channel = chosen; - if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) { - WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res)); - goto fail; - } + } + + if (chosen) { + ap->channel = (uint16)chosen & 0x00FF; + WL_SOFTAP(("%s: Got auto channel = %d, attempt:%d\n", + __FUNCTION__, ap->channel, retry)); + } + + if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) { + WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res)); + goto fail; + } + #ifndef AP_ONLY - if (!res) + if (!res || !ret) last_auto_channel = ap->channel; #endif fail : + if (ret < 0) { + WL_TRACE(("%s: return value %d\n", __FUNCTION__, ret)); + return ret; + } return res; } @@ -6482,6 +6497,15 @@ set_ap_cfg(struct net_device *dev, struct ap_profile *ap) goto fail; } WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res)); + + + mpc = 0; + if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) { + WL_ERROR(("%s fail to set mpc\n", __FUNCTION__)); + goto fail; + } + + #endif updown = 1; @@ -6528,16 +6552,16 @@ set_ap_cfg(struct net_device *dev, struct ap_profile *ap) if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) { ap->channel = 1; - WL_ERROR(("%s auto channel failed, pick up channel=%d\n", + WL_ERROR(("%s auto channel failed, use channel=%d\n", __FUNCTION__, ap->channel)); } channel = ap->channel; if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) { WL_ERROR(("%s fail to set channel\n", __FUNCTION__)); - goto fail; } + if (ap_cfg_running == FALSE) { updown = 0; if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) { @@ -6877,11 +6901,11 @@ static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac) char z_mac[6] = {0, 0, 0, 0, 0, 0}; char *sta_mac; struct maclist *assoc_maclist = (struct maclist *) mac_buf; - bool deauth_all = false; + bool deauth_all = FALSE; if (mac == NULL) { - deauth_all = true; + deauth_all = TRUE; sta_mac = z_mac; } else { sta_mac = mac; @@ -7179,7 +7203,7 @@ set_ap_mac_list(struct net_device *dev, void *buf) if (assoc_maclist->count) for (i = 0; i < assoc_maclist->count; i++) { int j; - bool assoc_mac_matched = false; + bool assoc_mac_matched = FALSE; WL_SOFTAP(("\n Cheking assoc STA: ")); dhd_print_buf(&assoc_maclist->ea[i], 6, 7); @@ -7189,7 +7213,7 @@ set_ap_mac_list(struct net_device *dev, void *buf) if (!bcmp(&assoc_maclist->ea[i], &maclist->ea[j], ETHER_ADDR_LEN)) { - assoc_mac_matched = true; + assoc_mac_matched = TRUE; break; } |