From 0eb5aac3aac77dfc78652ebbecaeb27d887781fc Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 21 Sep 2011 13:09:58 -0700 Subject: [PATCH] net: wireless: bcmdhd: Update to Version 5.90.125.87 - Improve discovery of FW hanging - Add WFD noa and power-safe related functions Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd.h | 12 +- drivers/net/wireless/bcmdhd/dhd_common.c | 59 ++++---- drivers/net/wireless/bcmdhd/dhd_linux.c | 26 +++- drivers/net/wireless/bcmdhd/dhd_sdio.c | 34 +++-- drivers/net/wireless/bcmdhd/include/epivers.h | 10 +- drivers/net/wireless/bcmdhd/wl_android.c | 85 ++++++++--- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 95 +++++++++--- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 10 ++ drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 137 ++++++++++++++++++ drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 11 ++ drivers/net/wireless/bcmdhd/wl_iw.c | 26 +--- 11 files changed, 393 insertions(+), 112 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 5d9e678e7db6..ac374af3ca50 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h,v 1.60.4.17 2011-01-09 08:11:56 Exp $ + * $Id: dhd.h 285209 2011-09-21 01:21:24Z $ */ /**************** @@ -80,6 +80,9 @@ enum dhd_bus_state { #define WFD_MASK 0x0004 #define SOFTAP_FW_MASK 0x0008 +/* max sequential rxcntl timeouts to set HANG event */ +#define MAX_CNTL_TIMEOUT 2 + enum dhd_bus_wake_state { WAKE_LOCK_OFF, WAKE_LOCK_PRIV, @@ -96,6 +99,7 @@ enum dhd_bus_wake_state { WAKE_LOCK_SOFTAP_THREAD, WAKE_LOCK_MAX }; + enum dhd_prealloc_index { DHD_PREALLOC_PROT = 0, DHD_PREALLOC_RXBUF, @@ -121,6 +125,7 @@ void dhd_os_prefree(void *osh, void *addr, uint size); #ifndef DHD_SDALIGN #define DHD_SDALIGN 32 #endif + /* Common structure for module and instance linkage */ typedef struct dhd_pub { /* Linkage ponters */ @@ -203,6 +208,8 @@ typedef struct dhd_pub { #endif bool dongle_isolation; int hang_was_sent; + int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ + int txcnt_timeout; /* counter txcnt timeout to send HANG */ #ifdef WLMEDIA_HTSF uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ #endif @@ -296,6 +303,7 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) #define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) #define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) #define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val) + #define DHD_PACKET_TIMEOUT 1 #define DHD_EVENT_TIMEOUT 2 @@ -468,6 +476,7 @@ extern uint dhd_bus_status(dhd_pub_t *dhdp); extern int dhd_bus_start(dhd_pub_t *dhdp); extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); + #if defined(KEEP_ALIVE) extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); #endif /* KEEP_ALIVE */ @@ -707,4 +716,5 @@ void dhd_aoe_arp_clr(dhd_pub_t *dhd); int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen); void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr); #endif /* ARP_OFFLOAD_SUPPORT */ + #endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 146b7a7f1796..8496f17bb059 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c,v 1.57.2.22 2011-02-01 18:38:37 Exp $ + * $Id: dhd_common.c 284903 2011-09-20 02:36:51Z $ */ #include #include @@ -484,7 +484,7 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch #endif /* PROP_TXSTATUS */ case IOV_GVAL(IOV_BUS_TYPE): - /* The dhd application query the driver to check if its usb or sdio. */ + /* The dhd application queries the driver to check if its usb or sdio. */ #ifdef BCMDHDUSB int_val = BUS_TYPE_USB; #endif @@ -1004,27 +1004,27 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, case WLC_E_IF: { - dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; + dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; #ifdef PROP_TXSTATUS -{ - uint8* ea = pvt_data->eth.ether_dhost; - WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " - "[%02x:%02x:%02x:%02x:%02x:%02x]\n", - ifevent->ifidx, - ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), - ((ifevent->is_AP == 0) ? "STA":"AP "), - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); - (void)ea; - - dhd_wlfc_interface_event(dhd_pub->info, - ((ifevent->action == WLC_E_IF_ADD) ? - eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), - ifevent->ifidx, ifevent->is_AP, ea); - - /* dhd already has created an interface by default, for 0 */ - if (ifevent->ifidx == 0) - break; -} + { + uint8* ea = pvt_data->eth.ether_dhost; + WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " + "[%02x:%02x:%02x:%02x:%02x:%02x]\n", + ifevent->ifidx, + ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), + ((ifevent->is_AP == 0) ? "STA":"AP "), + ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); + (void)ea; + + dhd_wlfc_interface_event(dhd_pub->info, + ((ifevent->action == WLC_E_IF_ADD) ? + eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), + ifevent->ifidx, ifevent->is_AP, ea); + + /* dhd already has created an interface by default, for 0 */ + if (ifevent->ifidx == 0) + break; + } #endif /* PROP_TXSTATUS */ #ifdef WL_CFG80211 @@ -1032,7 +1032,7 @@ wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, DHD_ERROR(("%s: ifidx %d for %s action %d\n", __FUNCTION__, ifevent->ifidx, event->ifname, ifevent->action)); - if (ifevent->action == WLC_E_IF_ADD) + if (ifevent->action == WLC_E_IF_ADD) wl_cfg80211_notify_ifchange(); return (BCME_OK); } @@ -1868,7 +1868,7 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) if ((pfn_enabled) && (is_associated(dhd, NULL) == TRUE)) { DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); return ret; -} + } /* Enable/disable PNO */ if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { @@ -1906,6 +1906,7 @@ 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); @@ -2016,13 +2017,13 @@ dhd_pno_get_status(dhd_pub_t *dhd) #if defined(KEEP_ALIVE) int dhd_keep_alive_onoff(dhd_pub_t *dhd) { - char buf[256]; - const char *str; + char buf[256]; + const char *str; wl_mkeep_alive_pkt_t mkeep_alive_pkt; wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; + int buf_len; + int str_len; + int res = -1; if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) return (res); diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 6a69b2bff76a..02331899b025 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $ + * $Id: dhd_linux.c 285209 2011-09-21 01:21:24Z $ */ #include @@ -1986,6 +1986,20 @@ dhd_ethtool(dhd_info_t *dhd, void *uaddr) } #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ +static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) +{ + dhd_info_t *dhd = (dhd_info_t*)dhdp->info; + + if ((error == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) && + (!dhd->pub.dongle_reset))) { + DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, + dhd->pub.rxcnt_timeout, dhd->pub.txcnt_timeout, error, dhd->pub.busstate)); + net_os_send_hang_message(net); + return TRUE; + } + return FALSE; +} + static int dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) { @@ -2036,6 +2050,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) if (cmd == SIOCDEVPRIVATE+1) { ret = wl_android_priv_cmd(net, ifr, cmd); + dhd_check_hang(net, &dhd->pub, ret); DHD_OS_WAKE_UNLOCK(&dhd->pub); return ret; } @@ -2173,11 +2188,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); done: - if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) && - (!dhd->pub.dongle_reset))) { - DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__)); - net_os_send_hang_message(net); - } + dhd_check_hang(net, &dhd->pub, bcmerror); if (!bcmerror && buf && ioc.buf) { if (copy_to_user(ioc.buf, buf, buflen)) @@ -2270,6 +2281,8 @@ dhd_stop(struct net_device *net) wl_android_wifi_off(net); #endif dhd->pub.hang_was_sent = 0; + dhd->pub.rxcnt_timeout = 0; + dhd->pub.txcnt_timeout = 0; OLD_MOD_DEC_USE_COUNT; return 0; } @@ -4504,6 +4517,7 @@ int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) DHD_OS_WAKE_LOCK(&dhd->pub); ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); + dhd_check_hang(net, &dhd->pub, ret); DHD_OS_WAKE_UNLOCK(&dhd->pub); return ret; diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 37ab6805d6d9..b79ef4417121 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c,v 1.274.2.40 2011-02-09 22:42:44 Exp $ + * $Id: dhd_sdio.c 285209 2011-09-21 01:21:24Z $ */ #include @@ -422,6 +422,11 @@ do { \ } \ } while (0) +#define BUS_WAKE(bus) \ + do { \ + if ((bus)->sleeping) \ + dhdsdio_bussleep((bus), FALSE); \ + } while (0); /* * pktavail interrupts from dongle to host can be managed in 3 different ways @@ -920,13 +925,6 @@ dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) } #endif /* defined(OOB_INTR_ONLY) */ -#define BUS_WAKE(bus) \ - do { \ - if ((bus)->sleeping) \ - dhdsdio_bussleep((bus), FALSE); \ - } while (0); - - /* Writes a HW/SW header into the packet and sends it. */ /* Assumes: (a) header space already there, (b) caller holds lock */ static int @@ -1375,14 +1373,18 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); ret = 0; } else { + bus->dhd->txcnt_timeout++; if (!bus->dhd->hang_was_sent) - DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__)); + DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", + __FUNCTION__, bus->dhd->txcnt_timeout)); ret = -1; bus->ctrl_frame_stat = FALSE; goto done; } } + bus->dhd->txcnt_timeout = 0; + if (ret == -1) { #ifdef DHD_DEBUG if (DHD_BYTES_ON() && DHD_CTL_ON()) { @@ -1440,6 +1442,9 @@ done: else bus->dhd->tx_ctlpkts++; + if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) + return -ETIMEDOUT; + return ret ? -EIO : 0; } @@ -1485,13 +1490,22 @@ dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) dhd_os_sdunlock(bus->dhd); #endif /* DHD_DEBUG */ } + if (timeleft == 0) { + bus->dhd->rxcnt_timeout++; + DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); + } + else + bus->dhd->rxcnt_timeout = 0; if (rxlen) bus->dhd->rx_ctlpkts++; else bus->dhd->rx_ctlerrs++; - return rxlen ? (int)rxlen : -ETIMEDOUT; + if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) + return -ETIMEDOUT; + + return rxlen ? (int)rxlen : -EIO; } /* IOVar table */ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 60f842c6d968..63db714ae883 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -19,7 +19,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 Exp $ + * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 $ * */ @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 125 -#define EPI_INCREMENTAL_NUMBER 84 +#define EPI_INCREMENTAL_NUMBER 87 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 125, 84 +#define EPI_VERSION 5, 90, 125, 87 -#define EPI_VERSION_NUM 0x055a7d54 +#define EPI_VERSION_NUM 0x055a7d57 #define EPI_VERSION_DEV 5.90.125 -#define EPI_VERSION_STR "5.90.125.84" +#define EPI_VERSION_STR "5.90.125.87" #endif diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 8bc6b361e868..8c0e3ae7a261 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -36,7 +36,9 @@ #include #include #include - +#ifdef WL_CFG80211 +#include +#endif #if defined(CONFIG_WIFI_CONTROL_FUNC) #include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) @@ -51,25 +53,31 @@ * so they can be updated easily in the future (if needed) */ -#define CMD_START "START" -#define CMD_STOP "STOP" -#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" -#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" -#define CMD_RSSI "RSSI" -#define CMD_LINKSPEED "LINKSPEED" -#define CMD_RXFILTER_START "RXFILTER-START" -#define CMD_RXFILTER_STOP "RXFILTER-STOP" -#define CMD_RXFILTER_ADD "RXFILTER-ADD" -#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" +#define CMD_START "START" +#define CMD_STOP "STOP" +#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" +#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" +#define CMD_RSSI "RSSI" +#define CMD_LINKSPEED "LINKSPEED" +#define CMD_RXFILTER_START "RXFILTER-START" +#define CMD_RXFILTER_STOP "RXFILTER-STOP" +#define CMD_RXFILTER_ADD "RXFILTER-ADD" +#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" #define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" -#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" -#define CMD_BTCOEXMODE "BTCOEXMODE" -#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" -#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" -#define CMD_SETFWPATH "SETFWPATH" -#define CMD_SETBAND "SETBAND" -#define CMD_GETBAND "GETBAND" -#define CMD_COUNTRY "COUNTRY" +#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" +#define CMD_BTCOEXMODE "BTCOEXMODE" +#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" +#define CMD_SETFWPATH "SETFWPATH" +#define CMD_SETBAND "SETBAND" +#define CMD_GETBAND "GETBAND" +#define CMD_COUNTRY "COUNTRY" +#define CMD_P2P_SET_NOA "P2P_SET_NOA" +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#define CMD_P2P_SET_PS "P2P_SET_PS" +#define CMD_SET_ASSOC_RESP_IE "SET_ASSOC_RESP_IE" +#define CMD_SET_PROBE_RESP_IE "SET_PROBE_RESP_IE" +#define CMD_SET_BEACON_IE "SET_BEACON_IE" #ifdef PNO_SUPPORT #define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" @@ -112,6 +120,12 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); #else int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; } +int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) +{ return 0; } +int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) +{ return 0; } +int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) +{ return 0; } #endif extern bool ap_fw_loaded; @@ -517,7 +531,38 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) #endif else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) { bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len); - } else { + } + else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) { + int skip = strlen(CMD_P2P_SET_NOA) + 1; + bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, + priv_cmd.total_len - skip); + } + else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { + bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); + } + else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { + int skip = strlen(CMD_P2P_SET_PS) + 1; + bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, + priv_cmd.total_len - skip); + } +#ifdef WL_CFG80211 + else if (strnicmp(command, CMD_SET_ASSOC_RESP_IE, strlen(CMD_SET_ASSOC_RESP_IE)) == 0) { + int skip = strlen(CMD_SET_ASSOC_RESP_IE) + 1; + bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, + priv_cmd.total_len - skip, WL_ASSOC_RESP); + } + else if (strnicmp(command, CMD_SET_PROBE_RESP_IE, strlen(CMD_SET_PROBE_RESP_IE)) == 0) { + int skip = strlen(CMD_SET_PROBE_RESP_IE) + 1; + bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, + priv_cmd.total_len - skip, WL_PROBE_RESP); + } + else if (strnicmp(command, CMD_SET_BEACON_IE, strlen(CMD_SET_BEACON_IE)) == 0) { + int skip = strlen(CMD_SET_BEACON_IE) + 1; + bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip, + priv_cmd.total_len - skip, WL_BEACON); + } +#endif /* WL_CFG80211 */ + else { DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command)); snprintf(command, 3, "OK"); bytes_written = strlen("OK"); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 0c3854d17e4c..7153a4ed5999 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -1402,8 +1402,10 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, err = -ENOMEM; goto exit; } - wldev_iovar_setbuf(ndev, "escan", params, params_size, + err = wldev_iovar_setbuf(ndev, "escan", params, params_size, wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN); + if (unlikely(err)) + WL_ERR((" Escan set error (%d)\n", err)); kfree(params); } else if (p2p_on(wl) && p2p_scan(wl)) { @@ -2171,7 +2173,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) { /* we only allow to connect using virtual interface in case of P2P */ if (p2p_on(wl) && is_wps_conn(sme)) { - WL_DBG(("p2p index : %d\n", wl_cfgp2p_find_idx(wl, dev))); + WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n", + wl_cfgp2p_find_idx(wl, dev), sme->ie_len)); /* Have to apply WPS IE + P2P IE in assoc req frame */ wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG, @@ -2187,6 +2190,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * the newly received IEs from Supplicant. This will remove the WPS IE from * the Assoc Req. */ + WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n", + wl_cfgp2p_find_idx(wl, dev), sme->ie_len)); wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); } @@ -2902,11 +2907,8 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) wl_clr_drv_status(wl, SCANNING); wl_clr_drv_status(wl, SCAN_ABORTING); dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); - if (wl_get_drv_status(wl, CONNECTING)) { wl_bss_connect_done(wl, ndev, NULL, NULL, false); - wl_delay(500); - return -EAGAIN; } #endif return 0; @@ -3286,6 +3288,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, if (wl->p2p->vif_created) { wifi_p2p_pub_act_frame_t *act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); + WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n", + action_frame->len, af_params->channel, + act_frm->category, act_frm->subtype)); /* * To make sure to send successfully action frame, we have to turn off mpc */ @@ -3687,6 +3692,8 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, } else { WL_ERR(("No P2PIE in beacon \n")); } + /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ + wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, beacon_ie, wpsie_len + p2pie_len); @@ -4129,15 +4136,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period); beacon_proberesp->capab_info = cpu_to_le16(bi->capability); wl_rst_ie(wl); - /* - * wl_add_ie is not necessary because it can only add duplicated - * SSID, rate information to frame_buf - */ - /* - * wl_add_ie(wl, WLAN_EID_SSID, bi->SSID_len, bi->SSID); - * wl_add_ie(wl, WLAN_EID_SUPP_RATES, bi->rateset.count, - * bi->rateset.rates); - */ + wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length); wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX - offsetof(struct wl_cfg80211_bss_info, frame_buf)); @@ -4150,10 +4149,11 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) #endif channel = ieee80211_get_channel(wiphy, freq); - WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM\n", - bi->SSID, - notif_bss_info->rssi, notif_bss_info->channel, - mgmt->u.beacon.capab_info, &bi->BSSID)); + WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM" + "mgmt_type %d frame_len %d\n", bi->SSID, + notif_bss_info->rssi, notif_bss_info->channel, + mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type, + notif_bss_info->frame_len)); signal = notif_bss_info->rssi * 100; @@ -5832,7 +5832,7 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo s32 err = 0; /* Setup event_msgs */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, + bcm_mkiovar("event_msgs", NULL, 0, iovbuf, sizeof(iovbuf)); err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); if (unlikely(err)) { @@ -6619,7 +6619,64 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd return 0; } +s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) +{ + struct wl_priv *wl; + wl = wlcfg_drv_priv; + + return wl_cfgp2p_set_p2p_noa(wl, net, buf, len); +} + +s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) +{ + struct wl_priv *wl; + wl = wlcfg_drv_priv; + + return wl_cfgp2p_get_p2p_noa(wl, net, buf, len); +} +s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) +{ + struct wl_priv *wl; + wl = wlcfg_drv_priv; + + return wl_cfgp2p_set_p2p_ps(wl, net, buf, len); +} + +s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, + enum wl_management_type type) +{ + struct wl_priv *wl; + struct net_device *ndev = NULL; + s32 ret = 0; + s32 bssidx = 0; + s32 pktflag = 0; + wl = wlcfg_drv_priv; + if (wl->p2p && wl->p2p->vif_created) { + ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); + } else if (wl_get_drv_status(wl, AP_CREATING) || + wl_get_drv_status(wl, AP_CREATED)) { + ndev = net; + bssidx = 0; + } + if (ndev != NULL) { + switch (type) { + case WL_BEACON: + pktflag = VNDR_IE_BEACON_FLAG; + break; + case WL_PROBE_RESP: + pktflag = VNDR_IE_PRBRSP_FLAG; + break; + case WL_ASSOC_RESP: + pktflag = VNDR_IE_ASSOCRSP_FLAG; + break; + } + ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len); + } + + return ret; +} static __used void wl_dongle_poweron(struct wl_priv *wl) { diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 9fae79ed83dc..066103ebe10e 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -182,6 +182,11 @@ enum wl_fw_status { WL_NVRAM_LOADING_DONE }; +enum wl_management_type { + WL_BEACON = 0x1, + WL_PROBE_RESP = 0x2, + WL_ASSOC_RESP = 0x4 +}; /* beacon / probe_response */ struct beacon_proberesp { __le64 timestamp; @@ -538,6 +543,11 @@ extern void wl_cfg80211_release_fw(void); extern s8 *wl_cfg80211_get_fwname(void); extern s8 *wl_cfg80211_get_nvramname(void); extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); +extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); +extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); +extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, + enum wl_management_type type); +extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); #ifdef CONFIG_SYSCTL extern s32 wl_cfg80211_sysctl_export_devaddr(void *data); diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index dd5f5facd728..653fbcdf7e65 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -1305,6 +1305,7 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev) } return p2p_supported; } + /* Cleanup P2P resources */ s32 wl_cfgp2p_down(struct wl_priv *wl) @@ -1313,3 +1314,139 @@ wl_cfgp2p_down(struct wl_priv *wl) del_timer_sync(&wl->p2p->listen_timer); return 0; } + +s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +{ + s32 ret = -1; + int count, start, duration; + wl_p2p_sched_t dongle_noa; + + CFGP2P_DBG((" Enter\n")); + memset(&dongle_noa, 0, sizeof(dongle_noa)); + + if (wl->p2p && wl->p2p->vif_created) { + + wl->p2p->noa.desc[0].start = 0; + + sscanf(buf, "%d %d %d", &count, &start, &duration); + CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", + count, start, duration)); + if (count != -1) + wl->p2p->noa.desc[0].count = count; + + /* supplicant gives interval as start */ + if (start != -1) + wl->p2p->noa.desc[0].interval = start * 1000; + + if (duration != -1) + wl->p2p->noa.desc[0].duration = duration * 1000; + + if (wl->p2p->noa.desc[0].count != 255) { + wl->p2p->noa.desc[0].start = 200 * 1000; + dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS; + dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF; + dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS; + } + else { + /* Continuous NoA interval. */ + dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; + dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; + if ((wl->p2p->noa.desc[0].interval == 102000) || + (wl->p2p->noa.desc[0].interval == 100000)) { + wl->p2p->noa.desc[0].start = 100 - + (wl->p2p->noa.desc[0].duration / 1000); + wl->p2p->noa.desc[0].duration /= 1000; + dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT; + } + else { + dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL; + } + } + /* Put the noa descriptor in dongle format for dongle */ + + dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count); + dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start); + dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval); + dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration); + + ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), + "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf)); + + if (ret < 0) { + CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); + } + } + else { + CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); + } + return ret; +} + +s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +{ + wifi_p2p_noa_desc_t* noa_desc; + CFGP2P_DBG((" Enter\n")); + if (wl->p2p && wl->p2p->vif_created) { + if (wl->p2p->noa.desc[0].count) { +#define P2P_ATTR_NOTICE_OF_ABSENCE_LEN 2 + buf[0] = 0; /* noa index */ + buf[1] = (wl->p2p->ops.ops ? 0x80: 0) | + (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */ + noa_desc = (wifi_p2p_noa_desc_t*)&buf[P2P_ATTR_NOTICE_OF_ABSENCE_LEN]; + noa_desc->cnt_type = wl->p2p->noa.desc[0].count; + noa_desc->duration = wl->p2p->noa.desc[0].duration; + noa_desc->interval = wl->p2p->noa.desc[0].interval; + noa_desc->start = wl->p2p->noa.desc[0].start; + /* wl_android.c is adding 1 to ret value for all returned bufs */ + return sizeof(wifi_p2p_noa_desc_t) + + P2P_ATTR_NOTICE_OF_ABSENCE_LEN - 1; + } + else { + /* NOA parameters are not set */ + return 0; + } + } + else { + CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); + return -1; + } +} + +s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +{ + int ps, ctw, legacy_ps; + int ret = -1; + + CFGP2P_DBG((" Enter\n")); + if (wl->p2p && wl->p2p->vif_created) { + sscanf(buf, "%d %d %d", &legacy_ps, &ps, &ctw); + CFGP2P_DBG((" Enter ps %d ctw %d\n", ps, ctw)); + if (ctw != -1) { + wl->p2p->ops.ctw = ctw; + ret = 0; + } + if (ps != -1) { + wl->p2p->ops.ops = ps; + ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), + "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops), + ioctlbuf, sizeof(ioctlbuf)); + if (ret < 0) { + CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); + } + } + + if (legacy_ps != -1) { + s32 pm = legacy_ps ? PM_FAST : PM_OFF; + ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), + WLC_SET_PM, &pm, sizeof(pm), true); + if (unlikely(ret)) { + CFGP2P_ERR(("error (%d)\n", ret)); + } + } + } + else { + CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n")); + ret = -1; + } + return ret; +} diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 5aff46831f85..a7fdf7662e9f 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -74,6 +74,8 @@ struct p2p_info { struct ether_addr int_addr; struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; struct timer_list listen_timer; + wl_p2p_sched_t noa; + wl_p2p_ops_t ops; wlc_ssid_t ssid; spinlock_t timer_lock; }; @@ -224,6 +226,15 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev); extern s32 wl_cfgp2p_down(struct wl_priv *wl); +extern s32 +wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); + +extern s32 +wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); + +extern s32 +wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); + /* WiFi Direct */ #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index ef77cdc9bda8..f71f29a242fb 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -8077,8 +8077,6 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) uint32 datalen = ntoh32(e->datalen); uint32 status = ntoh32(e->status); uint32 toto; - static uint32 roam_no_success = 0; - static bool roam_no_success_send = FALSE; memset(&wrqu, 0, sizeof(wrqu)); memset(extra, 0, sizeof(extra)); @@ -8146,26 +8144,12 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) cmd = IWEVREGISTERED; break; case WLC_E_ROAM: - if (status != WLC_E_STATUS_SUCCESS) { - roam_no_success++; - if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) { - - roam_no_success_send = TRUE; - bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN); - bzero(&extra, ETHER_ADDR_LEN); - cmd = SIOCGIWAP; - WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n", - __FUNCTION__)); - } else { - WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success)); - goto wl_iw_event_end; - } - } else { - memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN); - wrqu.addr.sa_family = ARPHRD_ETHER; - cmd = SIOCGIWAP; + if (status == WLC_E_STATUS_SUCCESS) { + WL_ASSOC((" WLC_E_ROAM : success \n")); + return; } break; + case WLC_E_DEAUTH_IND: case WLC_E_DISASSOC_IND: #if defined(SOFTAP) @@ -8225,8 +8209,6 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) wl_iw_send_priv_event(priv_dev, "AP_UP"); } else { WL_TRACE(("STA_LINK_UP\n")); - roam_no_success_send = FALSE; - roam_no_success = 0; } #else #endif -- 2.34.1