diff options
| author | Ecco Park <eccopark@broadcom.com> | 2013-09-18 06:41:49 +0900 |
|---|---|---|
| committer | doc HD <doc.divxm@gmail.com> | 2014-08-13 23:48:08 +0200 |
| commit | c0ee0eb826d12cbd04dbdbb8b5f4daac737c7c70 (patch) | |
| tree | b3641b26831b1b592dd1635d371609b3d4c8494c | |
| parent | c6450016dacd0d49ac07ebce342c353d73c4c535 (diff) | |
net: bcmdhd: update driver
This is a squash of updates to the bcmdhd driver. If testing goes ok,
the commits can be merged from
https://github.com/mdmower/android_kernel_htc_msm8960/commits/cm-11.0-bcmdhd
CM merged to kernel_htc_msm8960 only last patch in this squashed commit: http://review.cyanogenmod.org/#/c/69806/
----
net: wireless: bcmdhd: new feature for Roaming.
1) The functionality help to prevent the device from doing roam
scan forever in the environment which has just one AP nearbyt,
but the RSSI of the AP is -75dbm ~ 78dbm
2) The feature will set the roam trigger from -75dbm to -85dbm
in case that there are only one AP.
3) The value will be reset to -75dbm after disconnecting from
current AP.
4) This patch will Fixed Google issue: [10718651]
WiFi draining battery life even while phone connected to charge
5) Enable flow control in DHD driver to fix
10430352 UDP speed is less than 40% of TCP speed with LInksys
WRT110
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: Fixed Coverity issue.
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: fix for negative padding
Signed-off-by: Iliyan Malchev <malchev@google.com>
net: wireless: bcmdhd: Fixed Wi-Fi Location Service issues.
1. 10954142 [BATCHED-SCAN]Wifi Batching stopped after long time
2. 10412309 [BATCHED-SCAN] Batched scans aren't as frequent as
expected.
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: add code for WLS service.
add protection code to fix the issue#11051053
( [Issue 11051053] [BATCHED-SCAN] Batched scan results
become unavailable after disabling/re-enabling wifi scan)
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: Fix country checking
Bug: 11319610
Change-Id: I5c52ed594614d8039f167de3c98bd9f802b521df
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
net: wireless: bcmdhd: fixed power consumption issue of P2P.
solution : add wake_lock not to go to suspend during removing P2P GO
interface in wl_cfg80211.c.
Description of this issue :
if device goes to suspend during removing the interface,
we will fail to remove P2P GO virtual
interface(p2p-p2p0-0).
This will causes P2P GO still alive in firmware
Bugnizer case id : 10874302
This issue is reported by LG team.
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: Fixed a problem of buganizer issue (11190960)
Problem : if PNO scan occurs in Driver after p2p scan,
we failed to do PNO scan
Root cause : In the wl_run_escan function, we still goes into
p2p scan code even though current scan is PNO which is kind of
legacy scan.
Solution : we need to clear the staus of P2P scan before doing
PNO SCAN.
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: reduced the wakelock time of RX packet
Reduce time : 1secs -> 500ms
Problem : [Issue 11512235] 34% battery eaten overnight
[Issue 11374623] OS + Wifi used 41% of battery,
wlan_rx_wake
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: cancel current PNO if connection will happen
Issue : Manta: Lack of WLS causes PNO problem
Problem : we found that race condition happens
between connection and PNO sometimes.
Connection is failed due to this race condition.
Solution: we need to cancel PNO explicitly if the connection
request start in DHD driver.
Bug : 11174374
Signed-off-by: Ecco Park <eccopark@broadcom.com>
Change-Id: I7bf81d127901a74e9f47d6cc4ee7b265c6936dc3
net: wireless: bcmdhd: Change DTIM skip policy in suspend
issue : WiFi continuously disconnects
Root cause :
Sometimes we got link down event due to beacon
lost when device goes to suspend.
This problem sometimes happens in case that DTIM is 3 and beacon
100ms because we wake up on 900ms (100ms * 3 * 3) during
suspend.
This value(900ms) is too big to STA for sync up with AP time.
This causes STA out of sync for time with the AP.
Eventually STA got lost of beacon during long time (4secs).
Solution :
If the total dtim skip interval (beacon_interval *
DTIM * 3) is greater than 300ms, we will not extend DTIM to DTIM
* 3.
Instead of that, we will use original value (DTIM) for wake up
in suspend.
Bug : 1343127 WiFi continuously disconnects
Signed-off-by: Ecco Park <eccopark@broadcom.com>
Change-Id: I6d89bd1c56127befe4d9606869396ee25b7911ef
net: wireless: bcmdhd: Set MAX_DTIM_ALLOWED_INTERVAL to 600
Change-Id: Ie4d9cac1e0828651a142d64762b251537431ea99
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
net: wireless: bcmdhd: Enable IPv6 RA filter feature
1) We will block IPv6 Router Advertisement multicast packet in suspend mode to save power on device.
Bug: 11638281
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: enable TDLS_auto_mode
Requirement :
1. enable auto mode for SETUP request
2. disable auto mode for TEARDOWN request
bug : 11632025 TDLS hybrid mode support
Change-Id: Idc0cb60e65a45bb32b8beb2bb3daf72c9112eab6
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: Sync with N5 branch
Change-Id: I8152c52ae7da4932ff4b588d456548498bd4bab7
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
net: wireless: bcmdhd: Change the parameter for TDLS
1) tuned the parameter for TDLS connection to transit between AP
and TDLS smoothly.
2) tdls_rssi_high : -70 dbm -> -60 dbm (for setup)
tdls_rssi_low : -80 dbm -> -70dbm (for teardown)
bug : 11632025
Signed-off-by: Ecco Park <eccopark@broadcom.com>
net: wireless: bcmdhd: support Hotspot 2.0 release 1.0
Change-Id: I0d893b85741da628cb5c49c0a1b70c9d2d1ffac9
Signed-off-by: Ecco Park <eccopark@broadcom.com>
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
net: wireless: bcmdhd: ifdef wl_cfg80211_sched_scan_stop declaration
wl_cfg80211_sched_scan_stop() was introduced in
4e98e4ad9f77dffa3e6d977453f92259d0370e3d "net: wireless: bcmdhd: cancel
current PNO if connection will happen" but its declaration was not
ifdef'd like its usage is. Picky compilers are picky.
Change-Id: Ibd97b98c99e2b0bb2bf933b7ba858181f346e1de
net: wireless: bcmdhd: Add WIPHY_WOWLAN_ANY support
Change-Id: Ia6afe2ebcd0c68622c7f7a1fb36efa62dc009abf
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
net: wireless: bcmdhd: Add support for hidden ssid PNO scan
Changes to support hidden ssid config to be sent to FW. Earlier
all ssids were hard coded as hidden, now only those indicated
as such by supplicant will be.
Change-Id: I927030fe12f162c52c93277b2ebfb4bf55daef4a
Signed-off-by: Ashwin <ashwin.bhat@broadcom.com>
20 files changed, 735 insertions, 244 deletions
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index d2e56a73..cf7d7efb 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -39,10 +39,10 @@ ifneq ($(CONFIG_CFG80211),) bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o dhd_cfg80211.o DHDCFLAGS += -DWL_CFG80211 -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS -DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 -DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 +DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75 +DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10 DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 -DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 +DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10 endif ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),) DHDCFLAGS += -DWL_SCHED_SCAN @@ -52,6 +52,10 @@ ifeq ($(CONFIG_BCMDHD),m) EXTRA_LDFLAGS += --strip-debug endif +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-60 +DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-70 +DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=40000 + ######################### # Chip dependent feature ######################### @@ -67,6 +71,8 @@ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=32 DHDCFLAGS += -DPROP_TXSTATUS_VSDB DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32 DHDCFLAGS += -DREPEAT_READFRAME +DHDCFLAGS += -DROAM_AP_ENV_DETECTION +DHDCFLAGS += -DWL11U else DHDCFLAGS += -DCUSTOM_SDIO_F2_BLKSIZE=128 endif diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index 0c0f9067..96e88f4c 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -1184,7 +1184,7 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + xfred_len; - uint pad = 0; + int pad = 0; pkt_len = PKTLEN(sd->osh, pnext); if (0 != xfred_len) { pkt_len -= xfred_len; @@ -1231,11 +1231,11 @@ txglomfail: !need_txglom && #endif TRUE) { - pkt_len = sdioh_request_packet_align(pkt_len, write, + int align_pkt_len = 0; + align_pkt_len = sdioh_request_packet_align(pkt_len, write, func, blk_size); - pad = pkt_len - PKTLEN(sd->osh, pnext); - + pad = align_pkt_len - pkt_len; if (pad > 0) { if (func == SDIO_FUNC_2) { sd_err(("%s: padding is unexpected! pkt_len %d," diff --git a/drivers/net/wireless/bcmdhd/common/include/proto/802.3.h b/drivers/net/wireless/bcmdhd/common/include/proto/802.3.h index 2fd09fc9..caf2dc30 100644 --- a/drivers/net/wireless/bcmdhd/common/include/proto/802.3.h +++ b/drivers/net/wireless/bcmdhd/common/include/proto/802.3.h @@ -1,15 +1,27 @@ /* - * Copyright (C) 2013, Broadcom Corporation - * All Rights Reserved. + * Copyright (C) 1999-2013, 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: * - * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; - * the contents of this file may not be disclosed to third parties, copied - * or duplicated in any form, in whole or in part, without the prior - * written permission of Broadcom Corporation. + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. * * Fundamental constants relating to 802.3 * - * $Id: 802.3.h 382882 2013-02-04 23:24:31Z $ + * $Id: 802.3.h 417942 2013-08-13 07:53:57Z $ */ #ifndef _802_3_h_ diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 1c0eef48..573a8463 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -317,6 +317,9 @@ typedef struct dhd_pub { #ifdef PNO_SUPPORT void *pno_state; #endif +#ifdef ROAM_AP_ENV_DETECTION + bool roam_env_detection; +#endif bool dongle_isolation; bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ int hang_was_sent; @@ -412,6 +415,7 @@ extern int dhd_os_wake_unlock(dhd_pub_t *pub); extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); +extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); @@ -445,7 +449,9 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) dhd_os_wake_lock_rx_timeout_enable(pub, val) #define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ dhd_os_wake_lock_ctrl_timeout_enable(pub, val) -#define DHD_PACKET_TIMEOUT_MS 1000 +#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ + dhd_os_wake_lock_ctrl_timeout_cancel(pub) +#define DHD_PACKET_TIMEOUT_MS 500 #define DHD_EVENT_TIMEOUT_MS 1500 /* interface operations (register, remove) should be atomic, use this lock to prevent race @@ -783,7 +789,9 @@ extern uint dhd_force_tx_queueing; #endif #endif /* WLTDLS */ -#define MAX_DTIM_SKIP_BEACON_ITERVAL 100 /* max allowed associated AP beacon for dtim skip */ +#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ +#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ +#define NO_DTIM_SKIP 1 #ifdef SDTEST /* Echo packet generator (SDIO), pkts/s */ @@ -984,7 +992,7 @@ void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); #endif /* ARP_OFFLOAD_SUPPORT */ #ifdef WLTDLS -int dhd_tdls_enable_disable(dhd_pub_t *dhd, bool flag); +int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); #endif /* Neighbor Discovery Offload Support */ diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 82398a67..93f5e4da 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -54,12 +54,12 @@ #include <linux/jiffies.h> #endif -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) #ifdef PROP_TXSTATUS #include <wlfc_proto.h> @@ -1863,9 +1863,9 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) { int bcn_li_dtim = 1; /* deafult no dtim skip setting */ int ret = -1; - int dtim_assoc = 0; + int dtim_period = 0; int ap_beacon = 0; - + int allowed_skip_dtim_cnt = 0; /* Check if associated */ if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); @@ -1880,20 +1880,20 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) } /* if associated APs Beacon more that 100msec do no dtim skip */ - if (ap_beacon > MAX_DTIM_SKIP_BEACON_ITERVAL) { + if (ap_beacon > MAX_DTIM_SKIP_BEACON_INTERVAL) { DHD_ERROR(("%s NO dtim skip for AP with beacon %d ms\n", __FUNCTION__, ap_beacon)); goto exit; } /* read associated ap's dtim setup */ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) { + &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); goto exit; } /* if not assocated just eixt */ - if (dtim_assoc == 0) { + if (dtim_period == 0) { goto exit; } @@ -1901,22 +1901,27 @@ dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) bcn_li_dtim = dhd->suspend_bcn_li_dtim; /* check if sta listen interval fits into AP dtim */ - if (dtim_assoc > CUSTOM_LISTEN_INTERVAL) { + if (dtim_period > CUSTOM_LISTEN_INTERVAL) { /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = 1; + bcn_li_dtim = NO_DTIM_SKIP; DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_assoc, CUSTOM_LISTEN_INTERVAL)); + __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); goto exit; } - if ((bcn_li_dtim * dtim_assoc) > CUSTOM_LISTEN_INTERVAL) { + if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { + allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); + bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; + } + + if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_assoc); + bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); } DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_assoc, CUSTOM_LISTEN_INTERVAL)); + __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); exit: return bcn_li_dtim; @@ -2079,7 +2084,7 @@ wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, * SSIDs list parsing from cscan tlv list */ int -wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) +wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) { char* str; int idx = 0; @@ -2127,6 +2132,7 @@ wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes *bytes_left -= ssid[idx].SSID_len; str += ssid[idx].SSID_len; + ssid[idx].hidden = TRUE; DHD_TRACE(("%s :size=%d left=%d\n", (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 98401b08..71caa5ea 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -217,16 +217,16 @@ typedef struct dhd_if { /* OS/stack specifics */ struct net_device *net; struct net_device_stats stats; - int idx; /* iface idx in dongle */ - dhd_if_state_t state; /* interface state */ - uint subunit; /* subunit */ + int idx; /* iface idx in dongle */ + dhd_if_state_t state; /* interface state */ + uint subunit; /* subunit */ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ bool attached; /* Delayed attachment when unset */ bool txflowcontrol; /* Per interface flow control indicator */ char name[IFNAMSIZ+1]; /* linux interface name */ uint8 bssidx; /* bsscfg index for the interface */ bool set_multicast; - struct list_head ipv6_list; + struct list_head ipv6_list; spinlock_t ipv6_lock; bool event2cfg80211; /* To determine if pass event to cfg80211 */ } dhd_if_t; @@ -673,7 +673,7 @@ static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) dhd_read_macaddr(dhd); } else { /* post process */ dhd_write_macaddr(&dhd->pub.mac); - } + } return 0; } @@ -750,6 +750,8 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) #ifndef ENABLE_FW_ROAM_SUSPEND uint roamvar = 1; #endif /* ENABLE_FW_ROAM_SUSPEND */ + uint nd_ra_filter = 0; + int ret = 0; if (!dhd) return -ENODEV; @@ -792,6 +794,14 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* ENABLE_FW_ROAM_SUSPEND */ + if (FW_SUPPORTED(dhd, ndoe)) { + /* enable IPv6 RA filter in firmware during suspend */ + nd_ra_filter = 1; + bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4, + iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + DHD_ERROR(("failed to set nd_ra_filter (%d)\n", ret)); + } } else { #ifdef PKT_FILTER_SUPPORT dhd->early_suspended = 0; @@ -820,6 +830,15 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); #endif /* ENABLE_FW_ROAM_SUSPEND */ + if (FW_SUPPORTED(dhd, ndoe)) { + /* disable IPv6 RA filter in firmware during suspend */ + nd_ra_filter = 0; + bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4, + iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) + DHD_ERROR(("failed to set nd_ra_filter (%d)\n", ret)); + } + } } dhd_suspend_unlock(dhd); @@ -3522,43 +3541,70 @@ dhd_bus_start(dhd_pub_t *dhdp) } #ifdef WLTDLS -int dhd_tdls_enable_disable(dhd_pub_t *dhd, bool flag) +int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) { char iovbuf[WLC_IOCTL_SMLEN]; - uint32 tdls = flag; - int ret; -#ifdef WLTDLS_AUTO_ENABLE - uint32 tdls_auto_op = 1; + uint32 tdls = tdls_on; + int ret = 0; + uint32 tdls_auto_op = 0; uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; -#endif /* WLTDLS_AUTO_ENABLE */ + int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; + int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; if (!FW_SUPPORTED(dhd, tdls)) return BCME_ERROR; + if (dhd->tdls_enable == tdls_on) + goto auto_mode; bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); goto exit; } - dhd->tdls_enable = flag; - if (!flag) - goto exit; -#ifdef WLTDLS_AUTO_ENABLE - bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); - goto exit; - } - bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, sizeof(tdls_idle_time), - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); - goto exit; + dhd->tdls_enable = tdls_on; +auto_mode: + if (mac) { + tdls_auto_op = auto_on; + bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), + iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); + goto exit; + } + + if (tdls_auto_op) { + bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time, + sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, + sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); + goto exit; + } + bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); + goto exit; + } + bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { + DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); + goto exit; + } + } } -#endif /* WLTDLS_AUTO_ENABLE */ exit: return ret; } +int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) +{ + dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); + int ret = 0; + if (dhd) + ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); + else + ret = BCME_ERROR; + return ret; +} #endif /* WLTDLS */ bool dhd_is_concurrent_mode(dhd_pub_t *dhd) @@ -3659,6 +3705,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; int roam_scan_period[2] = {10, WLC_BAND_ALL}; int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; +#ifdef ROAM_AP_ENV_DETECTION + int roam_env_mode = AP_ENV_INDETERMINATE; +#endif /* ROAM_AP_ENV_DETECTION */ #ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC int roam_fullscan_period = 60; #else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ @@ -3710,6 +3759,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) dhd->wlfc_enabled = FALSE; #endif /* PROP_TXSTATUS_VSDB */ #endif /* PROP_TXSTATUS */ +#ifdef WLTDLS + dhd->tdls_enable = FALSE; +#endif /* WLTDLS */ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; @@ -3875,10 +3927,22 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); +#ifdef ROAM_AP_ENV_DETECTION + if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { + bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode, + 4, iovbuf, sizeof(iovbuf)); + if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK) + dhd->roam_env_detection = TRUE; + else { + dhd->roam_env_detection = FALSE; + } + } +#endif /* ROAM_AP_ENV_DETECTION */ #endif /* ROAM_ENABLE */ #ifdef WLTDLS - dhd_tdls_enable_disable(dhd, 1); + /* by default TDLS on and auto mode off */ + _dhd_tdls_enable(dhd, true, false, NULL); #endif /* WLTDLS */ /* Set PowerSave mode */ @@ -5311,6 +5375,10 @@ dhd_dev_reset(struct net_device *dev, uint8 flag) if (dhd->pub.plat_deinit) dhd->pub.plat_deinit((void *)&dhd->pub); #endif /* PROP_TXSTATUS && !PROP_TXSTATUS_VSDB */ +#ifdef PNO_SUPPORT + if (dhd->pub.pno_state) + dhd_pno_deinit(&dhd->pub); +#endif } ret = dhd_bus_devreset(&dhd->pub, flag); @@ -5448,7 +5516,7 @@ done: } #ifdef PNO_SUPPORT -/* Linux wrapper to call common dhd_pno_clean */ +/* Linux wrapper to call common dhd_pno_stop_for_ssid */ int dhd_dev_pno_stop_for_ssid(struct net_device *dev) { @@ -5459,7 +5527,7 @@ dhd_dev_pno_stop_for_ssid(struct net_device *dev) /* Linux wrapper to call common dhd_pno_set_for_ssid */ int -dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -5788,6 +5856,23 @@ int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) return 0; } +int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) +{ + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + unsigned long flags; + + if (dhd) { + spin_lock_irqsave(&dhd->wakelock_spinlock, flags); + dhd->wakelock_ctrl_timeout_enable = 0; +#ifdef CONFIG_HAS_WAKELOCK + if (wake_lock_active(&dhd->wl_ctrlwake)) + wake_unlock(&dhd->wl_ctrlwake); +#endif + spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); + } + return 0; +} + int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c index 5f7657d1..dd81ccf9 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.c +++ b/drivers/net/wireless/bcmdhd/dhd_pno.c @@ -53,12 +53,12 @@ #define htodchanspec(i) htod16(i) #define dtohchanspec(i) dtoh16(i) #else -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) #endif /* IL_BIGENDINA */ #define NULL_CHECK(p, s, err) \ @@ -81,6 +81,8 @@ #define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====") #define TIME_MIN_DIFF 5 +static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state); static inline bool is_dfs(uint16 channel) { @@ -91,8 +93,9 @@ is_dfs(uint16 channel) else return FALSE; } -static int -_dhd_pno_clean(dhd_pub_t *dhd) + +int +dhd_pno_clean(dhd_pub_t *dhd) { int pfn = 0; int err; @@ -126,7 +129,9 @@ _dhd_pno_suspend(dhd_pub_t *dhd) dhd_pno_status_info_t *_pno_state; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); err = dhd_iovar(dhd, 0, "pfn_suspend", (char *)&suspend, sizeof(suspend), 1); if (err < 0) { DHD_ERROR(("%s : failed to suspend pfn(error :%d)\n", __FUNCTION__, err)); @@ -169,7 +174,7 @@ _dhd_pno_enable(dhd_pub_t *dhd, int enable) /* Enable/Disable PNO */ err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), 1); if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_set\n", __FUNCTION__)); + DHD_ERROR(("%s : failed to execute pfn_set - %d\n", __FUNCTION__, err)); goto exit; } _pno_state->pno_status = (enable)? @@ -299,13 +304,13 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t /* set bestn to calculate the max mscan which firmware supports */ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 1); if (err < 0) { - DHD_ERROR(("%s : failed to set pfnmscan\n", __FUNCTION__)); + DHD_ERROR(("%s : failed to set pfnmem\n", __FUNCTION__)); goto exit; } /* get max mscan which the firmware supports */ err = dhd_iovar(dhd, 0, "pfnmem", (char *)&_tmp, sizeof(_tmp), 0); if (err < 0) { - DHD_ERROR(("%s : failed to get pfnmscan\n", __FUNCTION__)); + DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__)); goto exit; } DHD_PNO((" returned mscan : %d, set bestn : %d\n", _tmp, pfn_param.bestn)); @@ -313,7 +318,7 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t } err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1); if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_set\n", __FUNCTION__)); + DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err)); goto exit; } /* need to return mscan if this is for batch scan instead of err */ @@ -322,7 +327,7 @@ exit: return err; } static int -_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssids_list, int nssid) +_dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssids_list, int nssid) { int err = BCME_OK; int i = 0; @@ -335,8 +340,8 @@ _dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssids_list, int nssid) { int j; for (j = 0; j < nssid; j++) { - DHD_PNO(("%d: scan for %s size = %d\n", j, - ssids_list[j].SSID, ssids_list[j].SSID_len)); + DHD_PNO(("%d: scan for %s size = %d hidden = %d\n", j, + ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden)); } } /* Check for broadcast ssid */ @@ -354,7 +359,10 @@ _dhd_pno_add_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssids_list, int nssid) pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); pfn_element.wsec = htod32(0); pfn_element.infra = htod32(1); - pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); + if (ssids_list[i].hidden) + pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT); + else + pfn_element.flags = 0; memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID, ssids_list[i].SSID_len); pfn_element.ssid.SSID_len = ssids_list[i].SSID_len; @@ -667,6 +675,7 @@ _dhd_pno_reinitialize_prof(dhd_pub_t *dhd, dhd_pno_params_t *params, dhd_pno_mod kfree(iter); } } + params->params_legacy.nssid = 0; params->params_legacy.scan_fr = 0; params->params_legacy.pno_freq_expo_max = 0; params->params_legacy.pno_repeat = 0; @@ -732,7 +741,7 @@ _dhd_pno_add_bssid(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid, int nbssid) if (nbssid) { NULL_CHECK(p_pfn_bssid, "bssid list is NULL", err); } - err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)&p_pfn_bssid, + err = dhd_iovar(dhd, 0, "pfn_add_bssid", (char *)p_pfn_bssid, sizeof(wl_pfn_bssid_t) * nbssid, 1); if (err < 0) { DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__)); @@ -764,7 +773,7 @@ dhd_pno_stop_for_ssid(dhd_pub_t *dhd) dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); /* save current pno_mode before calling dhd_pno_clean */ mode = _pno_state->pno_mode; - _dhd_pno_clean(dhd); + dhd_pno_clean(dhd); /* restore previous pno_mode */ _pno_state->pno_mode = mode; if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { @@ -808,9 +817,9 @@ dhd_pno_stop_for_ssid(dhd_pub_t *dhd) } } } else { - err = _dhd_pno_clean(dhd); + err = dhd_pno_clean(dhd); if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_clean (err: %d)\n", + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", __FUNCTION__, err)); goto exit; } @@ -828,11 +837,73 @@ dhd_pno_enable(dhd_pub_t *dhd, int enable) return (_dhd_pno_enable(dhd, enable)); } +static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, + dhd_pno_status_info_t *pno_state) +{ + int err = BCME_OK; + int i; + struct dhd_pno_ssid *iter, *next; + dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + wlc_ssid_ext_t *p_ssid_list; + + p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) * + _params1->params_legacy.nssid, GFP_KERNEL); + if (p_ssid_list == NULL) { + DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)", + __FUNCTION__, _params1->params_legacy.nssid)); + err = BCME_ERROR; + pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + goto exit; + } + i = 0; + /* convert dhd_pno_ssid to wlc_ssid_ext_t */ + list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) { + p_ssid_list[i].SSID_len = iter->SSID_len; + p_ssid_list[i].hidden = iter->hidden; + memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); + i++; + } +exit: + return p_ssid_list; + +} + +static int +dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list, + int nssid) +{ + int ret = 0; + int i; + struct dhd_pno_ssid *_pno_ssid; + + for (i = 0; i < nssid; i++) { + if (ssid_list[i].SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s : Invalid SSID length %d\n", + __FUNCTION__, ssid_list[i].SSID_len)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); + if (_pno_ssid == NULL) { + DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", + __FUNCTION__)); + ret = BCME_ERROR; + goto exit; + } + _pno_ssid->SSID_len = ssid_list[i].SSID_len; + _pno_ssid->hidden = ssid_list[i].hidden; + memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); + list_add_tail(&_pno_ssid->list, ¶ms->params_legacy.ssid_list); + } + +exit: + return ret; +} + int -dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, +dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan) { - struct dhd_pno_ssid *_pno_ssid; dhd_pno_params_t *_params; dhd_pno_params_t *_params2; dhd_pno_status_info_t *_pno_state; @@ -847,22 +918,30 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, if (!dhd_support_sta_mode(dhd)) { err = BCME_BADOPTION; - goto exit; + goto exit_no_clear; } DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d," "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__, scan_fr, pno_repeat, pno_freq_expo_max, nchan)); _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]); - if (!(_pno_state->pno_mode & DHD_PNO_LEGACY_MODE)) { - _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; - err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + DHD_ERROR(("%s : Legacy PNO mode was already started, " + "will disable previous one to start new one\n", __FUNCTION__)); + err = dhd_pno_stop_for_ssid(dhd); if (err < 0) { - DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", + DHD_ERROR(("%s : failed to stop legacy PNO (err %d)\n", __FUNCTION__, err)); - goto exit; + goto exit_no_clear; } } + _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE; + err = _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + if (err < 0) { + DHD_ERROR(("%s : failed to reinitialize profile (err %d)\n", + __FUNCTION__, err)); + goto exit_no_clear; + } memset(_chan_list, 0, sizeof(_chan_list)); tot_nchan = nchan; if (tot_nchan > 0 && channel_list) { @@ -878,7 +957,7 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, err = _dhd_pno_enable(dhd, PNO_OFF); if (err < 0) { DHD_ERROR(("%s : failed to disable PNO\n", __FUNCTION__)); - goto exit; + goto exit_no_clear; } /* restore the previous mode */ _pno_state->pno_mode = mode; @@ -894,7 +973,7 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, DHD_ERROR(("%s : failed to merge channel list" " between legacy and batch\n", __FUNCTION__)); - goto exit; + goto exit_no_clear; } } else { DHD_PNO(("superset channel will use" @@ -911,7 +990,7 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, DHD_ERROR(("%s : failed to merge channel list" " between legacy and hotlist\n", __FUNCTION__)); - goto exit; + goto exit_no_clear; } } } @@ -927,20 +1006,12 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, goto exit; } if ((err = _dhd_pno_add_ssid(dhd, ssid_list, nssid)) < 0) { - DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); + DHD_ERROR(("failed to add ssid list(err %d), %d in firmware\n", err, nssid)); goto exit; } - for (i = 0; i < nssid; i++) { - _pno_ssid = kzalloc(sizeof(struct dhd_pno_ssid), GFP_KERNEL); - if (_pno_ssid == NULL) { - DHD_ERROR(("%s : failed to allocate struct dhd_pno_ssid\n", - __FUNCTION__)); - goto exit; - } - _pno_ssid->SSID_len = ssid_list[i].SSID_len; - memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len); - list_add_tail(&_pno_ssid->list, &_params->params_legacy.ssid_list); - + if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) { + err = BCME_ERROR; + goto exit; } if (tot_nchan > 0) { if ((err = _dhd_pno_cfg(dhd, _chan_list, tot_nchan)) < 0) { @@ -954,6 +1025,9 @@ dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, DHD_ERROR(("%s : failed to enable PNO\n", __FUNCTION__)); } exit: + if (err < 0) + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); +exit_no_clear: /* clear mode in case of error */ if (err < 0) _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; @@ -966,11 +1040,10 @@ dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) uint16 _chan_list[WL_NUMCHANNELS]; int rem_nchan = 0, tot_nchan = 0; int mode = 0, mscan = 0; - int i = 0; dhd_pno_params_t *_params; dhd_pno_params_t *_params2; dhd_pno_status_info_t *_pno_state; - wlc_ssid_t *p_ssid_list = NULL; + wlc_ssid_ext_t *p_ssid_list = NULL; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); NULL_CHECK(batch_params, "batch_params is NULL", err); @@ -994,6 +1067,9 @@ dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) __FUNCTION__)); goto exit; } + } else { + /* batch mode is already started */ + return -EBUSY; } _params->params_batch.scan_fr = batch_params->scan_fr; _params->params_batch.bestn = batch_params->bestn; @@ -1037,7 +1113,6 @@ dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) tot_nchan = _params->params_batch.nchan; } if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { - struct dhd_pno_ssid *iter, *next; DHD_PNO(("PNO SSID is on progress in firmware\n")); /* store current pno_mode before disabling pno */ mode = _pno_state->pno_mode; @@ -1064,22 +1139,12 @@ dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params) } else { DHD_PNO(("superset channel will use all channels in firmware\n")); } - p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * - _params2->params_legacy.nssid, GFP_KERNEL); - if (p_ssid_list == NULL) { - DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)", - __FUNCTION__, _params2->params_legacy.nssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); goto exit; } - i = 0; - /* convert dhd_pno_ssid to dhd_pno_ssid */ - list_for_each_entry_safe(iter, next, &_params2->params_legacy.ssid_list, list) { - p_ssid_list[i].SSID_len = iter->SSID_len; - memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list[i].SSID_len); - i++; - } if ((err = _dhd_pno_add_ssid(dhd, p_ssid_list, _params2->params_legacy.nssid)) < 0) { DHD_ERROR(("failed to add ssid list (err %d) in firmware\n", err)); @@ -1113,8 +1178,7 @@ exit: /* return #max scan firmware can do */ err = mscan; } - if (p_ssid_list) - kfree(p_ssid_list); + kfree(p_ssid_list); return err; } @@ -1286,6 +1350,11 @@ _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) pbestnet_entry->rtt0 = plnetinfo->rtt0; pbestnet_entry->rtt1 = plnetinfo->rtt1; pbestnet_entry->timestamp = plnetinfo->timestamp; + if (plnetinfo->pfnsubnet.SSID_len > DOT11_MAX_SSID_LEN) { + DHD_ERROR(("%s: Invalid SSID length %d: trimming it to max\n", + __FUNCTION__, plnetinfo->pfnsubnet.SSID_len)); + plnetinfo->pfnsubnet.SSID_len = DOT11_MAX_SSID_LEN; + } pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len; memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.SSID, pbestnet_entry->SSID_len); @@ -1314,6 +1383,15 @@ _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason) plnetinfo++; } } + if (pscan_results->cnt_header == 0) { + /* In case that we didn't get any data from the firmware + * Remove the current scan_result list from get_bach.scan_results_list. + */ + DHD_PNO(("NO BATCH DATA from Firmware, Delete current SCAN RESULT LIST\n")); + list_del(&pscan_results->list); + MFREE(dhd->osh, pscan_results, SCAN_RESULTS_SIZE); + _params->params_batch.get_batch.top_node_cnt--; + } /* increase total scan count using current scan count */ _params->params_batch.get_batch.tot_scan_cnt += pscan_results->cnt_header; @@ -1342,9 +1420,11 @@ convert_format: exit: if (plbestnet) MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN); - _params->params_batch.get_batch.buf = NULL; - _params->params_batch.get_batch.bufsize = 0; - _params->params_batch.get_batch.bytes_written = err; + if (_params) { + _params->params_batch.get_batch.buf = NULL; + _params->params_batch.get_batch.bufsize = 0; + _params->params_batch.get_batch.bytes_written = err; + } mutex_unlock(&_pno_state->pno_mutex); if (waitqueue_active(&_pno_state->get_batch_done.wait)) complete(&_pno_state->get_batch_done); @@ -1419,7 +1499,7 @@ dhd_pno_stop_for_batch(dhd_pub_t *dhd) dhd_pno_status_info_t *_pno_state; dhd_pno_params_t *_params; wl_pfn_bssid_t *p_pfn_bssid; - wlc_ssid_t *p_ssid_list = NULL; + wlc_ssid_ext_t *p_ssid_list = NULL; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); _pno_state = PNO_GET_PNOSTATE(dhd); @@ -1441,30 +1521,19 @@ dhd_pno_stop_for_batch(dhd_pub_t *dhd) _pno_state->pno_mode &= ~DHD_PNO_BATCH_MODE; if (_pno_state->pno_mode & (DHD_PNO_LEGACY_MODE | DHD_PNO_HOTLIST_MODE)) { mode = _pno_state->pno_mode; - _dhd_pno_clean(dhd); + dhd_pno_clean(dhd); _pno_state->pno_mode = mode; /* restart Legacy PNO if the Legacy PNO is on */ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { struct dhd_pno_legacy_params *_params_legacy; - struct dhd_pno_ssid *iter, *next; _params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = kzalloc(sizeof(wlc_ssid_t) * - _params_legacy->nssid, GFP_KERNEL); - if (p_ssid_list == NULL) { - DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)", - __FUNCTION__, _params_legacy->nssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); goto exit; } - i = 0; - /* convert dhd_pno_ssid to dhd_pno_ssid */ - list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { - p_ssid_list[i].SSID_len = iter->SSID_len; - memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len); - i++; - } err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, _params_legacy->scan_fr, _params_legacy->pno_repeat, _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, @@ -1505,9 +1574,9 @@ dhd_pno_stop_for_batch(dhd_pub_t *dhd) } } } else { - err = _dhd_pno_clean(dhd); + err = dhd_pno_clean(dhd); if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_clean (err: %d)\n", + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", __FUNCTION__, err)); goto exit; } @@ -1515,8 +1584,7 @@ dhd_pno_stop_for_batch(dhd_pub_t *dhd) exit: _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); - if (p_ssid_list) - kfree(p_ssid_list); + kfree(p_ssid_list); return err; } @@ -1676,7 +1744,7 @@ dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) uint32 mode = 0; dhd_pno_status_info_t *_pno_state; dhd_pno_params_t *_params; - wlc_ssid_t *p_ssid_list; + wlc_ssid_ext_t *p_ssid_list; NULL_CHECK(dhd, "dhd is NULL", err); NULL_CHECK(dhd->pno_state, "pno_state is NULL", err); _pno_state = PNO_GET_PNOSTATE(dhd); @@ -1700,9 +1768,9 @@ dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) dhd_pno_get_for_batch(dhd, NULL, 0, PNO_STATUS_DISABLE); /* save current pno_mode before calling dhd_pno_clean */ mode = _pno_state->pno_mode; - err = _dhd_pno_clean(dhd); + err = dhd_pno_clean(dhd); if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_clean (err: %d)\n", + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", __FUNCTION__, err)); goto exit; } @@ -1711,24 +1779,14 @@ dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { /* restart Legacy PNO Scan */ struct dhd_pno_legacy_params *_params_legacy; - struct dhd_pno_ssid *iter, *next; _params_legacy = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy); - p_ssid_list = - kzalloc(sizeof(wlc_ssid_t) * _params_legacy->nssid, GFP_KERNEL); - if (p_ssid_list == NULL) { - DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)", - __FUNCTION__, _params_legacy->nssid)); - err = BCME_ERROR; - _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE; + p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state); + if (!p_ssid_list) { + err = BCME_NOMEM; + DHD_ERROR(("failed to get Legacy PNO SSID list\n")); goto exit; } - /* convert dhd_pno_ssid to dhd_pno_ssid */ - list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) { - p_ssid_list->SSID_len = iter->SSID_len; - memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list->SSID_len); - p_ssid_list++; - } err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid, _params_legacy->scan_fr, _params_legacy->pno_repeat, _params_legacy->pno_freq_expo_max, _params_legacy->chan_list, @@ -1752,9 +1810,9 @@ dhd_pno_stop_for_hotlist(dhd_pub_t *dhd) } } } else { - err = _dhd_pno_clean(dhd); + err = dhd_pno_clean(dhd); if (err < 0) { - DHD_ERROR(("%s : failed to call _dhd_pno_clean (err: %d)\n", + DHD_ERROR(("%s : failed to call dhd_pno_clean (err: %d)\n", __FUNCTION__, err)); goto exit; } @@ -1792,11 +1850,15 @@ dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data) { struct dhd_pno_batch_params *params_batch; params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch; - DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); - params_batch->get_batch.buf = NULL; - params_batch->get_batch.bufsize = 0; - params_batch->get_batch.reason = PNO_STATUS_EVENT; - schedule_work(&_pno_state->work); + if (!waitqueue_active(&_pno_state->get_batch_done.wait)) { + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__)); + params_batch->get_batch.buf = NULL; + params_batch->get_batch.bufsize = 0; + params_batch->get_batch.reason = PNO_STATUS_EVENT; + schedule_work(&_pno_state->work); + } else + DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING" + "will skip this event\n", __FUNCTION__)); break; } default: @@ -1816,8 +1878,8 @@ int dhd_pno_init(dhd_pub_t *dhd) if (dhd->pno_state) goto exit; dhd->pno_state = MALLOC(dhd->osh, sizeof(dhd_pno_status_info_t)); + NULL_CHECK(dhd->pno_state, "failed to create dhd_pno_state", err); memset(dhd->pno_state, 0, sizeof(dhd_pno_status_info_t)); - NULL_CHECK(dhd, "failed to create dhd_pno_state", err); /* need to check whether current firmware support batching and hotlist scan */ _pno_state = PNO_GET_PNOSTATE(dhd); _pno_state->wls_supported = TRUE; @@ -1837,18 +1899,25 @@ exit: int dhd_pno_deinit(dhd_pub_t *dhd) { int err = BCME_OK; - dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd); + dhd_pno_status_info_t *_pno_state; dhd_pno_params_t *_params; NULL_CHECK(dhd, "dhd is NULL", err); + DHD_PNO(("%s enter\n", __FUNCTION__)); + _pno_state = PNO_GET_PNOSTATE(dhd); + NULL_CHECK(_pno_state, "pno_state is NULL", err); + /* may need to free legacy ssid_list */ + if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) { + _params = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]; + _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_LEGACY_MODE); + } if (_pno_state->pno_mode & DHD_PNO_BATCH_MODE) { _params = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS]; /* clear resource if the BATCH MODE is on */ _dhd_pno_reinitialize_prof(dhd, _params, DHD_PNO_BATCH_MODE); } cancel_work_sync(&_pno_state->work); - if (dhd->pno_state) - MFREE(dhd->osh, dhd->pno_state, sizeof(dhd_pno_status_info_t)); + MFREE(dhd->osh, _pno_state, sizeof(dhd_pno_status_info_t)); dhd->pno_state = NULL; return err; } diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h index 0cf1bf48..49a8fd26 100644 --- a/drivers/net/wireless/bcmdhd/dhd_pno.h +++ b/drivers/net/wireless/bcmdhd/dhd_pno.h @@ -104,6 +104,7 @@ typedef enum dhd_pno_mode { DHD_PNO_HOTLIST_MODE = (1 << (2)) } dhd_pno_mode_t; struct dhd_pno_ssid { + bool hidden; uint32 SSID_len; uchar SSID[DOT11_MAX_SSID_LEN]; struct list_head list; @@ -209,7 +210,7 @@ extern int dhd_dev_pno_stop_for_ssid(struct net_device *dev); extern int -dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, +dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid, uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); extern int @@ -229,7 +230,7 @@ dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid, /* dhd pno fuctions */ extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd); extern int dhd_pno_enable(dhd_pub_t *dhd, int enable); -extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid, +extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid, uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan); extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params); diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 33bfb45f..6a5a2248 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -6966,7 +6966,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, sd1idle = TRUE; dhd_readahead = TRUE; retrydata = FALSE; - dhd_doflow = FALSE; + dhd_doflow = TRUE; dhd_dongle_ramsize = 0; dhd_txminmax = DHD_TXMINMAX; diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h index 1b60285e..495076ce 100644 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. -* $Id: dhd_wlfc.h 390836 2013-03-13 23:43:53Z $ +* $Id: dhd_wlfc.h 398418 2013-04-24 15:18:27Z $ * */ #ifndef __wlfc_host_driver_definitions_h__ @@ -290,7 +290,6 @@ int dhd_wlfc_init(dhd_pub_t *dhd); void dhd_wlfc_deinit(dhd_pub_t *dhd); int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, uint *reorder_info_len); - int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf); void dhd_wlfc_cleanup(dhd_pub_t *dhd, ifpkt_cb_t fn, int arg); diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c index 11faede8..e94fe802 100644 --- a/drivers/net/wireless/bcmdhd/hndpmu.c +++ b/drivers/net/wireless/bcmdhd/hndpmu.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: hndpmu.c 385540 2013-02-15 23:14:50Z $ + * $Id: hndpmu.c 414368 2013-07-24 15:00:23Z $ */ /* diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h index 65ef1282..b491aecf 100644 --- a/drivers/net/wireless/bcmdhd/include/typedefs.h +++ b/drivers/net/wireless/bcmdhd/include/typedefs.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: typedefs.h 286783 2011-09-29 06:18:57Z $ + * $Id: typedefs.h 397286 2013-04-18 01:42:19Z $ */ #ifndef _TYPEDEFS_H_ @@ -121,7 +121,7 @@ typedef long unsigned int size_t; #if defined(__GNUC__) && defined(__STRICT_ANSI__) #define TYPEDEF_INT64 #define TYPEDEF_UINT64 -#endif +#endif /* defined(__GNUC__) && defined(__STRICT_ANSI__) */ /* ICL accepts unsigned 64 bit type only, and complains in ANSI mode * for signed or unsigned diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index 2d0f90ed..4901a497 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -313,6 +313,12 @@ typedef struct wlc_ssid { uchar SSID[DOT11_MAX_SSID_LEN]; } wlc_ssid_t; +typedef struct wlc_ssid_ext { + bool hidden; + uint32 SSID_len; + uchar SSID[DOT11_MAX_SSID_LEN]; +} wlc_ssid_ext_t; + #ifndef LINUX_POSTMOGRIFY_REMOVAL #define MAX_PREFERRED_AP_NUM 5 diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 3c2dc425..e0f7199b 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.c 402429 2013-05-15 16:55:28Z $ + * $Id: siutils.c 414368 2013-07-24 15:00:23Z $ */ #include <bcm_cfg.h> diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 4b1f1496..742d873d 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -401,7 +401,7 @@ exit: #ifndef WL_SCHED_SCAN static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { - wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; + wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; int res = -1; int nssid = 0; cmd_tlv_t *cmd_tlv_temp; diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 9f99c81f..83a79131 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -67,6 +67,12 @@ #include <dhd_wlfc.h> #endif +#ifdef WL11U +#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) +#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \ + according to Kernel version and is supported only in Android-JB +#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */ +#endif /* WL11U */ #define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) @@ -334,6 +340,9 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, u8 *peer, enum nl80211_tdls_operation oper); #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0) */ +#ifdef WL_SCHED_SCAN +static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev); +#endif /* * event & event Q handlers for cfg80211 interfaces @@ -433,6 +442,13 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); +static s32 +wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len); +#endif /* WL11U */ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data); static void wl_free_wdev(struct wl_priv *wl); @@ -1405,6 +1421,9 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev) WL_ERR(("IFDEL didn't complete properly\n")); } ret = dhd_del_monitor(dev); + if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(wl->pub)); + } } } return ret; @@ -2120,6 +2139,9 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, bool iscan_req; bool escan_req = false; bool p2p_ssid; +#ifdef WL11U + bcm_tlv_t *interworking_ie; +#endif s32 err = 0; s32 bssidx = -1; s32 i; @@ -2167,7 +2189,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } #endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */ - /* Arm scan timeout timer */ mod_timer(&wl->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS)); iscan_req = false; @@ -2229,6 +2250,29 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, err = BCME_ERROR; goto scan_out; } +#ifdef WL11U + if ((interworking_ie = wl_cfg80211_find_interworking_ie( + (u8 *)request->ie, request->ie_len)) != NULL) { + err = wl_cfg80211_add_iw_ie(wl, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, interworking_ie->id, + interworking_ie->data, interworking_ie->len); + + if (unlikely(err)) { + goto scan_out; + } + } else if (wl->iw_ie_len != 0) { + /* we have to clear IW IE and disable gratuitous APR */ + wl_cfg80211_add_iw_ie(wl, ndev, bssidx, + VNDR_IE_CUSTOM_FLAG, + DOT11_MNG_INTERWORKING_ID, + 0, 0); + + wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, + bssidx); + wl->wl11u = FALSE; + /* we don't care about error */ + } +#endif /* WL11U */ err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie, request->ie_len); @@ -3093,6 +3137,9 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl_extjoin_params_t *ext_join_params; struct wl_join_params join_params; size_t join_params_size; +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* ROAM_AP_ENV_DETECTION */ s32 err = 0; wpa_ie_fixed_t *wpa_ie; bcm_tlv_t *wpa2_ie; @@ -3127,6 +3174,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wl_notify_escan_complete(wl, dev, true, true); } #endif +#ifdef WL_SCHED_SCAN + if (wl->sched_scan_req) { + wl_cfg80211_sched_scan_stop(wiphy, wl_to_prmry_ndev(wl)); + } +#endif #if defined(ESCAN_RESULT_PATCH) if (sme->bssid) memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN); @@ -3220,6 +3272,17 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, return err; } } +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + if (dhd->roam_env_detection && (wldev_iovar_setint(dev, "roam_env_detection", + AP_ENV_DETECT_NOT_USED) == BCME_OK)) { + s32 roam_trigger[2] = {WL_AUTO_ROAM_TRIGGER, WLC_BAND_ALL}; + err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, + sizeof(roam_trigger), true); + if (unlikely(err)) { + WL_ERR((" failed to restore roam_trigger for auto env detection\n")); + } + } +#endif /* ROAM_AP_ENV_DETECTION */ if (chan) { wl->channel = ieee80211_frequency_to_channel(chan->center_freq); chan_cnt = 1; @@ -3454,7 +3517,8 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, #ifdef SUPPORT_WL_TXPOWER if (type == NL80211_TX_POWER_AUTOMATIC) txpwrqdbm = 127; - txpwrqdbm |= WL_TXPWR_OVERRIDE; + else + txpwrqdbm |= WL_TXPWR_OVERRIDE; #endif /* SUPPORT_WL_TXPOWER */ err = wldev_iovar_setint(ndev, "qtxpower", txpwrqdbm); if (unlikely(err)) { @@ -4648,12 +4712,50 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy, return err; } +#ifdef WL11U +static bool +wl_cfg80211_check_DFS_channel(struct wl_priv *wl, wl_af_params_t *af_params, + void *frame, u16 frame_len) +{ + struct wl_scan_results *bss_list; + struct wl_bss_info *bi = NULL; + bool result = false; + s32 i; + + /* If DFS channel is 52~148, check to block it or not */ + if (af_params && + (af_params->channel >= 52 && af_params->channel <= 148)) { + if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) { + bss_list = wl->bss_list; + bi = next_bss(bss_list, bi); + for_each_bss(bss_list, bi, i) { + if (CHSPEC_IS5G(bi->chanspec) && + ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec)) + == af_params->channel)) { + result = true; /* do not block the action frame */ + break; + } + } + } + } + else { + result = true; + } + + WL_DBG(("result=%s", result?"true":"false")); + return result; +} +#endif /* WL11U */ + static bool wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params, wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx) { +#ifdef WL11U + struct net_device *ndev = NULL; +#endif /* WL11U */ struct wl_priv *wl = wiphy_priv(wiphy); bool ack = false; u8 category, action; @@ -4664,6 +4766,13 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, #endif dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#ifdef WL11U +#if defined(WL_CFG80211_P2P_DEV_IF) + ndev = dev; +#else + ndev = ndev_to_cfgdev(cfgdev); +#endif /* WL_CFG80211_P2P_DEV_IF */ +#endif /* WL11U */ category = action_frame->data[DOT11_ACTION_CAT_OFF]; action = action_frame->data[DOT11_ACTION_ACT_OFF]; @@ -4735,6 +4844,10 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, } else { config_af_params.search_channel = false; } +#ifdef WL11U + if (ndev == wl_to_prmry_ndev(wl)) + config_af_params.search_channel = false; +#endif /* WL11U */ #ifdef VSDB /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */ @@ -4747,6 +4860,12 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev, if (wl_get_drv_status_all(wl, SCANNING)) { wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); } +#ifdef WL11U + /* handling DFS channel exceptions */ + if (!wl_cfg80211_check_DFS_channel(wl, af_params, action_frame->data, action_frame->len)) { + return false; /* the action frame was blocked */ + } +#endif /* WL11U */ /* set status and destination address before sending af */ if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { @@ -6097,8 +6216,17 @@ wl_cfg80211_stop_ap( wl_clr_drv_status(wl, AP_CREATED, dev); /* Turn on the MPC */ wldev_iovar_setint(dev, "mpc", 1); + if (wl->ap_info) { + kfree(wl->ap_info->wpa_ie); + kfree(wl->ap_info->rsn_ie); + kfree(wl->ap_info->wps_ie); + kfree(wl->ap_info); + wl->ap_info = NULL; + } } else { WL_DBG(("Stopping P2P GO \n")); + DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(wl->pub), DHD_EVENT_TIMEOUT_MS*3); + DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(wl->pub)); } exit: @@ -6298,17 +6426,36 @@ fail: #define PNO_TIME 30 #define PNO_REPEAT 4 #define PNO_FREQ_EXPO_MAX 2 -int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, +static bool +is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count) +{ + int i; + + if (!ssid || !ssid_list) + return FALSE; + + for (i = 0; i < count; i++) { + if (ssid->ssid_len == ssid_list[i].ssid_len) { + if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0) + return TRUE; + } + } + return FALSE; +} + +static int +wl_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_sched_scan_request *request) { ushort pno_time = PNO_TIME; int pno_repeat = PNO_REPEAT; int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; - wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; + wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT]; struct wl_priv *wl = wiphy_priv(wiphy); struct cfg80211_ssid *ssid = NULL; - int ssid_count = 0; + struct cfg80211_ssid *hidden_ssid_list = NULL; + int ssid_cnt = 0; int i; int ret = 0; @@ -6327,30 +6474,29 @@ int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, memset(&ssids_local, 0, sizeof(ssids_local)); - if (request->n_match_sets > 0) { - for (i = 0; i < request->n_match_sets; i++) { - ssid = &request->match_sets[i].ssid; - memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len); - ssids_local[i].SSID_len = ssid->ssid_len; - WL_PNO((">>> PNO filter set for ssid (%s) \n", ssid->ssid)); - ssid_count++; - } - } - - if (request->n_ssids > 0) { - for (i = 0; i < request->n_ssids; i++) { - /* Active scan req for ssids */ - WL_PNO((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid)); - - /* match_set ssids is a supert set of n_ssid list, so we need - * not add these set seperately - */ + if (request->n_ssids > 0) + hidden_ssid_list = request->ssids; + + for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) { + ssid = &request->match_sets[i].ssid; + /* No need to include null ssid */ + if (ssid->ssid_len) { + memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid, ssid->ssid_len); + ssids_local[ssid_cnt].SSID_len = ssid->ssid_len; + if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) { + ssids_local[ssid_cnt].hidden = TRUE; + WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid)); + } else { + ssids_local[ssid_cnt].hidden = FALSE; + WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid)); + } + ssid_cnt++; } } - if (ssid_count) { - if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, request->n_match_sets, - pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { + if (ssid_cnt) { + if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt, pno_time, + pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) { WL_ERR(("PNO setup failed!! ret=%d \n", ret)); return -EINVAL; } @@ -6362,7 +6508,8 @@ int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, return 0; } -int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +static int +wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) { struct wl_priv *wl = wiphy_priv(wiphy); @@ -6605,6 +6752,9 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || 0 wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; #endif +#if defined(CONFIG_PM) + wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; +#endif WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); @@ -7490,6 +7640,9 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, { struct wl_connect_info *conn_info = wl_to_conn(wl); struct wl_security *sec = wl_read_prof(wl, ndev, WL_PROF_SEC); +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); +#endif /* ROAM_AP_ENV_DETECTION */ s32 err = 0; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); if (!sec) { @@ -7526,6 +7679,11 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); wl_set_drv_status(wl, CONNECTED, ndev); +#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION) + if (dhd->roam_env_detection) + wldev_iovar_setint(ndev, "roam_env_detection", + AP_ENV_INDETERMINATE); +#endif /* ROAM_AP_ENV_DETECTION */ if (ndev != wl_to_prmry_ndev(wl)) { /* reinitialize completion to clear previous count */ INIT_COMPLETION(wl->iface_disable); @@ -8010,6 +8168,7 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, wl_clr_drv_status(wl, SCANNING, ndev); goto out_err; } + p2p_scan(wl) = false; } wl_set_drv_status(wl, SCANNING, ndev); @@ -10528,33 +10687,42 @@ wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, #ifdef WLTDLS struct wl_priv *wl = wlcfg_drv_priv; tdls_iovar_t info; - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); memset(&info, 0, sizeof(tdls_iovar_t)); if (peer) memcpy(&info.ea, peer, ETHER_ADDR_LEN); switch (oper) { case NL80211_TDLS_DISCOVERY_REQ: - if (!dhd->tdls_enable) - ret = dhd_tdls_enable_disable(dhd, 1); + /* turn on TDLS */ + ret = dhd_tdls_enable(dev, true, false, NULL); if (ret < 0) return ret; info.mode = TDLS_MANUAL_EP_DISCOVERY; break; case NL80211_TDLS_SETUP: - info.mode = TDLS_MANUAL_EP_CREATE; + /* auto mode on */ + ret = dhd_tdls_enable(dev, true, true, (struct ether_addr *)peer); + if (ret < 0) + return ret; break; case NL80211_TDLS_TEARDOWN: info.mode = TDLS_MANUAL_EP_DELETE; + /* auto mode off */ + ret = dhd_tdls_enable(dev, true, false, (struct ether_addr *)peer); + if (ret < 0) + return ret; break; default: WL_ERR(("Unsupported operation : %d\n", oper)); goto out; } - ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), - wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); - if (ret) { - WL_ERR(("tdls_endpoint error %d\n", ret)); + + if (info.mode) { + ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); + if (ret) { + WL_ERR(("tdls_endpoint error %d\n", ret)); + } } out: #endif /* WLTDLS */ @@ -10573,8 +10741,12 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, s32 pktflag = 0; wl = wlcfg_drv_priv; - if (wl_get_drv_status(wl, AP_CREATING, net) || - wl_get_drv_status(wl, AP_CREATED, net)) { + if (wl_get_drv_status(wl, AP_CREATING, net)) { + /* Vendor IEs should be set to FW + * after SoftAP interface is brought up + */ + goto exit; + } else if (wl_get_drv_status(wl, AP_CREATED, net)) { ndev = net; bssidx = 0; } else if (wl->p2p) { @@ -10870,6 +11042,100 @@ wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, return 0; } +#ifdef WL11U +bcm_tlv_t * +wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) +{ + bcm_tlv_t *ie; + + while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) { + return (bcm_tlv_t *)ie; + } + return NULL; +} + +static s32 +wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, + uint8 ie_id, uint8 *data, uint8 data_len) +{ + s32 err = BCME_OK; + s32 buf_len; + s32 iecount; + ie_setbuf_t *ie_setbuf; + + if (ie_id != DOT11_MNG_INTERWORKING_ID) + return BCME_UNSUPPORTED; + + /* Validate the pktflag parameter */ + if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | + VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | + VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| + VNDR_IE_CUSTOM_FLAG))) { + WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); + return -1; + } + + /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ + pktflag = htod32(pktflag); + + buf_len = sizeof(ie_setbuf_t) + data_len - 1; + ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); + + if (!ie_setbuf) { + WL_ERR(("Error allocating buffer for IE\n")); + return -ENOMEM; + } + + if (wl->iw_ie_len == data_len && !memcmp(wl->iw_ie, data, data_len)) { + WL_ERR(("Previous IW IE is equals to current IE\n")); + err = BCME_OK; + goto exit; + } + + strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); + ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + + /* Buffer contains only 1 IE */ + iecount = htod32(1); + memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); + memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); + + /* Now, add the IE to the buffer */ + ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; + + /* if already set with previous values, delete it first */ + if (wl->iw_ie_len != 0) { + WL_DBG(("Different IW_IE was already set. clear first\n")); + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + + if (err != BCME_OK) + goto exit; + } + + ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; + memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); + + err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + + if (err == BCME_OK) { + memcpy(wl->iw_ie, data, data_len); + wl->iw_ie_len = data_len; + wl->wl11u = TRUE; + + err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); + } + +exit: + if (ie_setbuf) + kfree(ie_setbuf); + return err; +} +#endif /* WL11U */ static void wl_cfg80211_work_handler(struct work_struct * work) { diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index f4146235..7567c4e2 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -44,12 +44,12 @@ struct wl_security; struct wl_ibss; -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) #define WL_DBG_NONE 0 #define WL_DBG_P2P_ACTION (1 << 5) @@ -473,6 +473,13 @@ struct parsed_ies { +#ifdef WL11U +/* Max length of Interworking element */ +#define IW_IES_MAX_BUF_LEN 9 +#endif +#ifdef WLFBT +#define FBT_KEYLEN 32 +#endif #define MAX_EVENT_BUF_NUM 16 typedef struct wl_eventmsg_buf { u16 num; @@ -573,6 +580,11 @@ struct wl_priv { struct net_info *_net_info, enum wl_status state, bool set); unsigned long interrested_state; wlc_ssid_t hostapd_ssid; +#ifdef WL11U + bool wl11u; + u8 iw_ie[IW_IES_MAX_BUF_LEN]; + u32 iw_ie_len; +#endif /* WL11U */ bool sched_scan_running; /* scheduled scan req status */ #ifdef WL_SCHED_SCAN struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 1816e60b..f3e8c364 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -65,10 +65,10 @@ static int wl_cfgp2p_if_open(struct net_device *net); static int wl_cfgp2p_if_stop(struct net_device *net); static const struct net_device_ops wl_cfgp2p_if_ops = { - .ndo_open = wl_cfgp2p_if_open, - .ndo_stop = wl_cfgp2p_if_stop, - .ndo_do_ioctl = wl_cfgp2p_do_ioctl, - .ndo_start_xmit = wl_cfgp2p_start_xmit, + .ndo_open = wl_cfgp2p_if_open, + .ndo_stop = wl_cfgp2p_if_stop, + .ndo_do_ioctl = wl_cfgp2p_do_ioctl, + .ndo_start_xmit = wl_cfgp2p_start_xmit, }; #endif /* WL_ENABLE_P2P_IF */ @@ -157,6 +157,26 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) return false; +#ifdef WL11U + /* XXX Hotspot2.0 STA mode can receive only response + * SoftAP mode cannot run Hotspot2.0 compliant Ap because + * Hotspot2.0 support only Enterprise mode + */ + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP) + return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, + (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET, + frame_len); + + else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) + return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE, + (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET, + frame_len); + else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ) + return true; + else + return false; +#else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || @@ -164,6 +184,7 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) return true; else return false; +#endif /* WL11U */ } void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel) { diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index 73b75119..c9004938 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -32,12 +32,12 @@ #include <wldev_common.h> #include <bcmutils.h> -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i +#define htod32(i) (i) +#define htod16(i) (i) +#define dtoh32(i) (i) +#define dtoh16(i) (i) +#define htodchanspec(i) (i) +#define dtohchanspec(i) (i) #define WLDEV_ERROR(args) \ do { \ @@ -354,7 +354,7 @@ int wldev_set_country( } if ((error < 0) || - (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) { + (strncmp(country_code, cspec.country_abbrev, WLC_CNTRY_BUF_SZ) != 0)) { if (user_enforced) { bzero(&scbval, sizeof(scb_val_t)); diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index ca87b3c0..e00b2244 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -95,7 +95,7 @@ extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); extern int net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_set_suspend_disable(struct net_device *dev, int val); extern int net_os_set_suspend(struct net_device *dev, int val, int force); -extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, +extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left); /* Get the link speed from dongle, speed is in kpbs */ |
