net: wireless: bcmdhd: Update to version 5.90.195.75

- Fix false PCB-OVERLAP issue
- Fix simultanious connect request on two P2P devices

Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
Dmitry Shmidt 2012-05-31 14:06:50 -07:00
parent 3f427b101c
commit bc6f92e9cc
13 changed files with 764 additions and 142 deletions

View File

@ -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 328934 2012-04-23 05:15:42Z $
* $Id: dhd.h 333052 2012-05-12 02:09:28Z $
*/
/****************
@ -51,6 +51,7 @@
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
#include <linux/wakelock.h>
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
/* The kernel threading is sdio-specific */
struct task_struct;
struct sched_param;
@ -436,10 +437,14 @@ extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
extern int dhd_pno_clean(dhd_pub_t *dhd);
extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
extern int dhd_pno_set_ex(dhd_pub_t *dhd, wl_pfn_t* ssidnet, int nssid,
ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time);
extern int dhd_pno_get_status(dhd_pub_t *dhd);
extern int dhd_dev_pno_reset(struct net_device *dev);
extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local,
int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
extern int dhd_dev_pno_set_ex(struct net_device *dev, wl_pfn_t* ssidnet, int nssid,
ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time);
extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
extern int dhd_dev_get_pno_status(struct net_device *dev);
#endif /* PNO_SUPPORT */

View File

@ -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 329682 2012-04-26 09:20:38Z $
* $Id: dhd_common.c 331276 2012-05-04 08:05:57Z $
*/
#include <typedefs.h>
#include <osl.h>
@ -1763,7 +1763,6 @@ bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
}
}
/* Function to estimate possible DTIM_SKIP value */
int
dhd_get_dtim_skip(dhd_pub_t *dhd)
@ -1885,12 +1884,13 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
return ret;
}
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (ret);
memset(iovbuf, 0, sizeof(iovbuf));
#ifndef WL_SCHED_SCAN
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (ret);
if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) {
DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
return ret;
@ -1934,9 +1934,10 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
err = -1;
return err;
}
#ifndef WL_SCHED_SCAN
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (err);
#endif /* !WL_SCHED_SCAN */
/* Check for broadcast ssid */
for (k = 0; k < nssid; k++) {
@ -2029,6 +2030,123 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
return err;
}
int
dhd_pno_set_ex(dhd_pub_t *dhd, wl_pfn_t* ssidnet, int nssid, ushort pno_interval,
int pno_repeat, int pno_expo_max, int pno_lost_time)
{
int err = -1;
char iovbuf[128];
int k, i;
wl_pfn_param_t pfn_param;
wl_pfn_t pfn_element;
uint len = 0;
DHD_TRACE(("%s nssid=%d pno_interval=%d\n", __FUNCTION__, nssid, pno_interval));
if ((!dhd) && (!ssidnet)) {
DHD_ERROR(("%s error exit\n", __FUNCTION__));
err = -1;
return err;
}
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (err);
/* Check for broadcast ssid */
for (k = 0; k < nssid; k++) {
if (!ssidnet[k].ssid.SSID_len) {
DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
return err;
}
}
/* #define PNO_DUMP 1 */
#ifdef PNO_DUMP
{
int j;
for (j = 0; j < nssid; j++) {
DHD_ERROR(("%d: scan for %s size =%d\n", j,
ssidnet[j].ssid.SSID, ssidnet[j].ssid.SSID_len));
}
}
#endif /* PNO_DUMP */
/* clean up everything */
if ((err = dhd_pno_clean(dhd)) < 0) {
DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
return err;
}
memset(iovbuf, 0, sizeof(iovbuf));
memset(&pfn_param, 0, sizeof(pfn_param));
memset(&pfn_element, 0, sizeof(pfn_element));
/* set pfn parameters */
pfn_param.version = htod32(PFN_VERSION);
pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
/* check and set extra pno params */
if ((pno_repeat != 0) || (pno_expo_max != 0)) {
pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
pfn_param.repeat = (uchar) (pno_repeat);
pfn_param.exp = (uchar) (pno_expo_max);
}
/* set up pno scan fr */
if (pno_interval != 0)
pfn_param.scan_freq = htod32(pno_interval);
if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) {
DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC));
return err;
}
if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) {
DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
return err;
}
/* network lost time */
pfn_param.lost_network_timeout = htod32(pno_lost_time);
len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
DHD_ERROR(("%s pfn_set failed for error=%d\n",
__FUNCTION__, err));
return err;
} else {
DHD_TRACE(("%s pfn_set OK with PNO time=%d repeat=%d max_adjust=%d\n",
__FUNCTION__, pfn_param.scan_freq,
pfn_param.repeat, pfn_param.exp));
}
/* set all pfn ssid */
for (i = 0; i < nssid; i++) {
pfn_element.flags = htod32(ssidnet[i].flags);
pfn_element.infra = htod32(ssidnet[i].infra);
pfn_element.auth = htod32(ssidnet[i].auth);
pfn_element.wpa_auth = htod32(ssidnet[i].wpa_auth);
pfn_element.wsec = htod32(ssidnet[i].wsec);
memcpy((char *)pfn_element.ssid.SSID, ssidnet[i].ssid.SSID, ssidnet[i].ssid.SSID_len);
pfn_element.ssid.SSID_len = htod32(ssidnet[i].ssid.SSID_len);
if ((len =
bcm_mkiovar("pfn_add", (char *)&pfn_element,
sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
if ((err =
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
DHD_ERROR(("%s pfn_add failed with ssidnet[%d] error=%d\n",
__FUNCTION__, i, err));
return err;
} else {
DHD_TRACE(("%s pfn_add OK with ssidnet[%d]\n", __FUNCTION__, i));
}
} else {
DHD_ERROR(("%s bcm_mkiovar failed with ssidnet[%d]\n", __FUNCTION__, i));
}
}
return err;
}
int
dhd_pno_get_status(dhd_pub_t *dhd)
{

View File

@ -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 329682 2012-04-26 09:20:38Z $
* $Id: dhd_linux.c 333885 2012-05-18 00:39:03Z $
*/
#include <typedefs.h>
@ -1525,9 +1525,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
tout_ctrl = DHD_PACKET_TIMEOUT_MS;
if (event.event_type == WLC_E_BTA_HCI_EVENT) {
dhd_bta_doevt(dhdp, data, event.datalen);
} else if (event.event_type == WLC_E_PFN_NET_FOUND) {
}
#ifdef PNO_SUPPORT
if (event.event_type == WLC_E_PFN_NET_FOUND) {
tout_ctrl *= 2;
}
#endif /* PNO_SUPPORT */
} else {
tout_rx = DHD_PACKET_TIMEOUT_MS;
}
@ -1562,6 +1565,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
}
}
DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx);
DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl);
}
@ -2939,16 +2943,20 @@ dhd_concurrent_fw(dhd_pub_t *dhd)
bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
FALSE, 0)) < 0) {
DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret));
} else if (buf[0] == 1) {
DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__));
return 1;
}
}
return 0;
return ret;
}
#endif
/*
* dhd_preinit_ioctls makes special pre-setting in the firmware before radio turns on
* returns : 0 if all settings passed or negative value if anything failed
*/
int
dhd_preinit_ioctls(dhd_pub_t *dhd)
{
@ -2957,7 +2965,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
#if !defined(WL_CFG80211)
uint up = 0;
#endif
#endif /* defined(WL_CFG80211) */
uint power_mode = PM_FAST;
uint32 dongle_align = DHD_SDALIGN;
uint32 glom = 0;
@ -3041,19 +3049,31 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* SET_RANDOM_MAC_SOFTAP */
DHD_TRACE(("Firmware = %s\n", fw_path));
#if !defined(AP) && defined(WLP2P)
/* Check if firmware with WFD support used */
#if defined(WL_ENABLE_P2P_IF)
if ((ret = dhd_concurrent_fw(dhd)) < 0) {
DHD_ERROR(("%s error : firmware can't support p2p mode\n", __FUNCTION__));
goto done;
}
#endif /* (WL_ENABLE_P2P_IF) */
if ((!op_mode && strstr(fw_path, "_p2p") != NULL)
#if defined(WL_ENABLE_P2P_IF)
|| (op_mode == 0x04) ||(dhd_concurrent_fw(dhd))
|| (op_mode == WFD_MASK) || (dhd_concurrent_fw(dhd) == 1)
#endif
) {
bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
DHD_ERROR(("%s APSTA setting failed ret= %d\n", __FUNCTION__, ret));
} else {
dhd->op_mode |= WFD_MASK;
#if !defined(WL_ENABLE_P2P_IF)
/* ICS back capability : disable any packet filtering for p2p only mode */
dhd_pkt_filter_enable = FALSE;
#endif /*!defined(WL_ENABLE_P2P_IF) */
}
}
#endif
@ -3098,16 +3118,20 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#if defined(ARP_OFFLOAD_SUPPORT)
arpoe = 0;
#endif /* (ARP_OFFLOAD_SUPPORT) */
/* disable any filtering for SoftAP mode */
dhd_pkt_filter_enable = FALSE;
}
}
#endif
#if !defined(WL_ENABLE_P2P_IF)
/* ICS mode setting for sta */
if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
/* STA only operation mode */
dhd->op_mode |= STA_MASK;
dhd_pkt_filter_enable = TRUE;
}
#endif /* !defined(WL_ENABLE_P2P_IF) */
DHD_ERROR(("Firmware up: op_mode=%d, "
"Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
@ -3260,6 +3284,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd->pktfilter[1] = NULL;
dhd->pktfilter[2] = NULL;
dhd->pktfilter[3] = NULL;
/* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
#if defined(SOFTAP)
if (ap_fw_loaded) {
@ -4446,6 +4471,17 @@ dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max));
}
/* Linux wrapper to call common dhd_pno_set_ex */
int
dhd_dev_pno_set_ex(struct net_device *dev, wl_pfn_t* ssidnet, int nssid,
ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
return (dhd_pno_set_ex(&dhd->pub, ssidnet, nssid,
pno_interval, pno_repeat, pno_expo_max, pno_lost_time));
}
/* Linux wrapper to get pno status */
int
dhd_dev_get_pno_status(struct net_device *dev)

View File

@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: bcmdevs.h 295140 2011-11-09 17:22:01Z $
* $Id: bcmdevs.h 332966 2012-05-11 22:40:21Z $
*/
@ -373,6 +373,7 @@
#define BFL2_EXTLNA_TX 0x08000000
#define BFL2_4313_RADIOREG 0x10000000
#define BFL2_SECI_LOPWR_DIS 0x20000000

View File

@ -23,6 +23,7 @@
*
*/
#ifndef _epivers_h_
#define _epivers_h_
@ -32,17 +33,17 @@
#define EPI_RC_NUMBER 195
#define EPI_INCREMENTAL_NUMBER 61
#define EPI_INCREMENTAL_NUMBER 75
#define EPI_BUILD_NUMBER 0
#define EPI_VERSION 5, 90, 195, 61
#define EPI_VERSION 5, 90, 195, 75
#define EPI_VERSION_NUM 0x055ac33d
#define EPI_VERSION_NUM 0x055ac34b
#define EPI_VERSION_DEV 5.90.195
#define EPI_VERSION_STR "5.90.195.61"
#define EPI_VERSION_STR "5.90.195.75"
#endif

View File

@ -21,7 +21,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: hndpmu.h 277737 2011-08-16 17:54:59Z $
* $Id: hndpmu.h 335486 2012-05-28 09:47:55Z $
*/
#ifndef _hndpmu_h_
@ -31,4 +31,7 @@
extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on);
extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength);
extern void si_pmu_set_otp_wr_volts(si_t *sih);
extern void si_pmu_set_otp_rd_volts(si_t *sih);
#endif /* _hndpmu_h_ */

View File

@ -5,7 +5,7 @@
* JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
* GPIO interface, extbus, and support for serial and parallel flashes.
*
* $Id: sbchipc.h 311371 2012-01-28 05:47:25Z $
* $Id: sbchipc.h 333924 2012-05-18 04:48:52Z $
*
* Copyright (C) 1999-2011, Broadcom Corporation
*
@ -1441,17 +1441,17 @@ typedef volatile struct {
#define CCTRL4331_EXT_LNA_G (1<<2)
#define CCTRL4331_SPROM_GPIO13_15 (1<<3)
#define CCTRL4331_EXTPA_EN (1<<4)
#define CCTRL4331_GPIOCLK_ON_SPROMCS <1<<5)
#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5)
#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6)
#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7)
#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8)
#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9)
#define CCTRL4331_PCIE_AUXCLKEN <1<<10)
#define CCTRL4331_PCIE_PIPE_PLLDOWN <1<<11)
#define CCTRL4331_PCIE_AUXCLKEN (1<<10)
#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11)
#define CCTRL4331_EXTPA_EN2 (1<<12)
#define CCTRL4331_EXT_LNA_A (1<<13)
#define CCTRL4331_BT_SHD0_ON_GPIO4 <1<<16)
#define CCTRL4331_BT_SHD1_ON_GPIO5 <1<<17)
#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16)
#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17)
#define CCTRL4331_EXTPA_ANA_EN (1<<24)

View File

@ -22,7 +22,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: siutils.h 285387 2011-09-21 18:38:37Z $
* $Id: siutils.h 335486 2012-05-28 09:47:55Z $
*/
@ -222,6 +222,8 @@ static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
extern bool si_is_otp_disabled(si_t *sih);
extern bool si_is_otp_powered(si_t *sih);
extern void si_otp_power(si_t *sih, bool on);
extern void si_set_otp_wr_volts(si_t *sih);
extern void si_set_otp_rd_volts(si_t *sih);
extern bool si_is_sprom_available(si_t *sih);

View File

@ -24,7 +24,7 @@
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: wlioctl.h 312596 2012-02-03 02:53:30Z $
* $Id: wlioctl.h 331292 2012-05-04 09:04:23Z $
*/
@ -1460,6 +1460,14 @@ typedef struct wl_sampledata {
} wl_sampledata_t;
#define WL_CHAN_VALID_HW (1 << 0)
#define WL_CHAN_VALID_SW (1 << 1)
#define WL_CHAN_BAND_5G (1 << 2)
#define WL_CHAN_RADAR (1 << 3)
#define WL_CHAN_INACTIVE (1 << 4)
#define WL_CHAN_PASSIVE (1 << 5)
#define WL_CHAN_RESTRICTED (1 << 6)
#define WL_ERROR_VAL 0x00000001
#define WL_TRACE_VAL 0x00000002

View File

@ -231,6 +231,8 @@ static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data, bool completed);
static s32 wl_ibss_join_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data, bool completed);
static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
@ -296,6 +298,7 @@ static void wl_free_wdev(struct wl_priv *wl);
static s32 wl_inform_bss(struct wl_priv *wl);
static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
static s32 wl_inform_ibss(struct wl_priv *wl, const u8 *bssid);
static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
@ -335,7 +338,6 @@ static void wl_link_up(struct wl_priv *wl);
static void wl_link_down(struct wl_priv *wl);
static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
static void wl_init_conf(struct wl_conf *conf);
static s32 wl_update_wiphybands(struct wl_priv *wl);
/*
* iscan handler
@ -704,7 +706,7 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf,
sizeof(WL_EXTRA_BUF_MAX), false))) {
WL_EXTRA_BUF_MAX, false))) {
WL_ERR(("Failed to get associated bss info, use temp channel \n"));
chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
}
@ -925,6 +927,11 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
/* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
*/
WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
wl_clr_p2p_status(wl, GO_NEG_PHASE);
if (wl->p2p->vif_created) {
if (wl_get_drv_status(wl, SCANNING, dev)) {
wl_notify_escan_complete(wl, dev, true, true);
@ -1004,6 +1011,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
default:
return -EINVAL;
}
WL_DBG(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type));
if (ap) {
wl_set_mode_by_netdev(wl, ndev, mode);
@ -1019,7 +1027,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
*/
chspec = wl_cfg80211_get_shared_freq(wiphy);
wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
wlif_type = WL_P2P_IF_GO;
WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
ndev->name, ap, infra, type));
wl_set_p2p_status(wl, IF_CHANGING);
@ -1043,6 +1051,14 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
return -EINVAL;
}
} else {
infra = htod32(infra);
err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true);
if (err) {
WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
return -EAGAIN;
}
wl_set_mode_by_netdev(wl, ndev, mode);
}
ndev->ieee80211_ptr->iftype = type;
@ -1587,6 +1603,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
wl_cfgp2p_generate_bss_mac(&primary_mac,
&wl->p2p->dev_addr, &wl->p2p->int_addr);
}
wl_clr_p2p_status(wl, GO_NEG_PHASE);
WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
p2p_scan(wl) = true;
}
} else {
@ -1625,10 +1643,13 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
} else {
wpsie_len = 0;
}
err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
if (unlikely(err)) {
goto scan_out;
if (wpsie_len > 0) {
err = wl_cfgp2p_set_management_ie(wl,
ndev, -1, VNDR_IE_PRBREQ_FLAG,
wpsie, wpsie_len);
if (unlikely(err)) {
goto scan_out;
}
}
}
}
@ -1808,86 +1829,192 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_bss *bss;
struct ieee80211_channel *chan;
struct wl_join_params join_params;
struct cfg80211_ssid ssid;
s32 scan_retry = 0;
struct wlc_ssid ssid;
struct ether_addr bssid;
size_t join_params_size = 0;
s32 wsec = 0;
s32 bcnprd;
s32 err = 0;
bool rollback_lock = false;
WL_TRACE(("In\n"));
CHECK_SYS_UP(wl);
if (params->bssid) {
WL_ERR(("Invalid bssid\n"));
return -EOPNOTSUPP;
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
wl_notify_escan_complete(wl, dev, true, true);
}
bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
if (!bss) {
memcpy(ssid.ssid, params->ssid, params->ssid_len);
ssid.ssid_len = params->ssid_len;
do {
if (unlikely
(__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
-EBUSY)) {
wl_delay(150);
} else {
break;
}
} while (++scan_retry < WL_SCAN_RETRY_MAX);
/* to allow scan_inform to propagate to cfg80211 plane */
if (rtnl_is_locked()) {
rtnl_unlock();
rollback_lock = true;
/* Clean BSSID */
bzero(&bssid, sizeof(bssid));
wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
if (params->ssid)
WL_INFO(("SSID: %s\n", params->ssid));
else {
WL_ERR(("SSID: NULL, Not supported\n"));
err = -EOPNOTSUPP;
goto CleanUp;
}
if (params->bssid)
WL_INFO(("BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
params->bssid[0], params->bssid[1], params->bssid[2],
params->bssid[3], params->bssid[4], params->bssid[5]));
if (params->channel)
WL_INFO(("channel: %d\n", params->channel->center_freq));
if (params->channel_fixed)
WL_INFO(("fixed channel required\n"));
if (params->ie && params->ie_len)
WL_INFO(("ie len: %d\n", params->ie_len));
if (params->beacon_interval)
WL_INFO(("beacon interval: %d\n", params->beacon_interval));
if (params->basic_rates)
WL_INFO(("basic rates: %08X\n", params->basic_rates));
if (params->privacy)
WL_INFO(("privacy required\n"));
wl_set_drv_status(wl, CONNECTING, dev);
/* Configure Privacy for starter */
if (params->privacy)
wsec |= WEP_ENABLED;
err = wldev_iovar_setint(dev, "wsec", wsec);
if (err) {
WL_ERR(("wsec failed (%d)\n", err));
goto CleanUp;
}
err = wldev_iovar_setint(dev, "auth", WL_AUTH_OPEN_SYSTEM);
if (err) {
WL_ERR(("auth failed (%d)\n", err));
goto CleanUp;
}
err = wldev_iovar_setint(dev, "wpa_auth", 0);
if (err) {
WL_ERR(("wpa_auth failed (%d)\n", err));
goto CleanUp;
}
/* Configure Beacon Interval for starter */
if (params->beacon_interval)
bcnprd = params->beacon_interval;
else
bcnprd = 100;
bcnprd = htod32(bcnprd);
err = wldev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd), true);
if (err) {
WL_ERR(("WLC_SET_BCNPRD failed (%d)\n", err));
goto CleanUp;
}
/* Configure required join parameter */
memset(&join_params, 0, sizeof(struct wl_join_params));
/* SSID */
memset(&ssid, 0, sizeof(struct wlc_ssid));
ssid.SSID_len = MIN(params->ssid_len, 32);
join_params.ssid.SSID_len = htod32(ssid.SSID_len);
memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
memcpy(join_params.ssid.SSID, params->ssid, ssid.SSID_len);
join_params_size = sizeof(join_params.ssid);
wl_update_prof(wl, dev, NULL, &ssid, WL_PROF_SSID);
/* BSSID */
if (params->bssid) {
memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
join_params_size = sizeof(join_params.ssid) +
WL_ASSOC_PARAMS_FIXED_SIZE;
wl_update_prof(wl, dev, NULL, params->bssid, WL_PROF_BSSID);
} else {
memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
}
/* Channel */
if (params->channel) {
u32 target_channel;
target_channel = ieee80211_frequency_to_channel(
params->channel->center_freq);
if (params->channel_fixed) {
/* adding chanspec */
wl_ch_to_chanspec(target_channel,
&join_params, &join_params_size);
}
/* wait 4 secons till scan done.... */
schedule_timeout_interruptible(4 * HZ);
if (rollback_lock)
rtnl_lock();
bss = cfg80211_get_ibss(wiphy, NULL,
params->ssid, params->ssid_len);
/* set channel for starter */
target_channel = htod32(target_channel);
err = wldev_ioctl(dev, WLC_SET_CHANNEL,
&target_channel, sizeof(target_channel), true);
if (err) {
WL_ERR(("WLC_SET_CHANNEL failed (%d)\n", err));
goto CleanUp;
}
}
if (bss) {
wl->ibss_starter = false;
WL_DBG(("Found IBSS\n"));
} else {
wl->ibss_starter = true;
}
chan = params->channel;
if (chan)
wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
/*
* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only
*/
memset(&join_params, 0, sizeof(join_params));
memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
params->ssid_len);
join_params.ssid.SSID_len = htod32(params->ssid_len);
if (params->bssid)
memcpy(&join_params.params.bssid, params->bssid,
ETHER_ADDR_LEN);
else
memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
sizeof(join_params), false);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
wl->ibss_starter = false;
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
if (err) {
WL_ERR(("WLC_SET_SSID failed (%d)\n", err));
goto CleanUp;
}
CleanUp:
if (err)
wl_clr_drv_status(wl, CONNECTING, dev);
WL_TRACE(("Exit\n"));
return err;
}
static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
struct wl_priv *wl = wiphy_priv(wiphy);
scb_val_t scbval;
bool act = false;
s32 err = 0;
u8 *curbssid;
WL_TRACE(("Enter\n"));
CHECK_SYS_UP(wl);
wl_link_down(wl);
act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT);
curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID);
if (act) {
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
wl_notify_escan_complete(wl, dev, true, true);
}
wl_set_drv_status(wl, DISCONNECTING, dev);
scbval.val = DOT11_RC_DISASSOC_LEAVING;
memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
scbval.val = htod32(scbval.val);
err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t), true);
if (unlikely(err)) {
wl_clr_drv_status(wl, DISCONNECTING, dev);
WL_ERR(("error (%d)\n", err));
return err;
}
}
WL_TRACE(("Exit\n"));
return err;
}
@ -3436,8 +3563,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
scb_val.val));
/* Wait for the deauth event to come, supplicant will do the delete iface immediately
* and we will have problem in sending deauth frame if we delete the bss in firmware
/* Wait for the deauth event to come, supplicant will do the
* delete iface immediately and we will have problem in sending
* deauth frame if we delete the bss in firmware
*/
wl_delay(400);
cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
@ -3506,6 +3634,36 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n",
action_frame->len, af_params->channel,
act_frm->category, act_frm->subtype));
if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
(act_frm->subtype == P2P_PAF_GON_RSP) ||
(act_frm->subtype == P2P_PAF_GON_CONF) ||
(act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
wldev_iovar_setint(dev, "mpc", 0);
}
if (act_frm->subtype == P2P_PAF_GON_REQ) {
WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
wl_set_p2p_status(wl, GO_NEG_PHASE);
} else if (act_frm->subtype == P2P_PAF_GON_CONF) {
/* If we reached till GO Neg confirmation
* reset the filter
*/
WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
wl_clr_p2p_status(wl, GO_NEG_PHASE);
}
if (act_frm->subtype == P2P_PAF_GON_RSP)
retry_cnt = 1;
else retry_cnt = WL_ACT_FRAME_RETRY;
if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
af_params->dwell_time = WL_LONG_DWELL_TIME;
} else if (act_frm &&
(act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
act_frm->subtype == P2P_PAF_GON_RSP)) {
af_params->dwell_time = WL_MED_DWELL_TIME;
}
} else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) {
p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data);
WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n",
@ -3522,26 +3680,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
/*
* To make sure to send successfully action frame, we have to turn off mpc
*/
if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) ||
(act_frm->subtype == P2P_PAF_GON_RSP) ||
(act_frm->subtype == P2P_PAF_GON_CONF) ||
(act_frm->subtype == P2P_PAF_PROVDIS_REQ))) {
wldev_iovar_setint(dev, "mpc", 0);
}
if (act_frm->subtype == P2P_PAF_GON_RSP)
retry_cnt = 1;
else retry_cnt = WL_ACT_FRAME_RETRY;
if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
af_params->dwell_time = WL_LONG_DWELL_TIME;
} else if (act_frm &&
(act_frm->subtype == P2P_PAF_PROVDIS_REQ ||
act_frm->subtype == P2P_PAF_PROVDIS_RSP ||
act_frm->subtype == P2P_PAF_GON_RSP)) {
af_params->dwell_time = WL_MED_DWELL_TIME;
}
if (IS_P2P_SOCIAL(af_params->channel) &&
(IS_P2P_PUB_ACT_REQ(act_frm, &act_frm->elts[0], action_frame->len) ||
IS_GAS_REQ(sd_act_frm, action_frame->len)) &&
@ -4245,7 +4383,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
#ifdef WL_SCHED_SCAN
#define PNO_TIME 30
#define PNO_REPEAT 4
#define PNO_FREQ_EXPO_MAX 3
#define PNO_FREQ_EXPO_MAX 2
int wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_sched_scan_request *request)
@ -4589,8 +4727,13 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
kfree(notif_bss_info);
return err;
}
else if( wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO) == NULL)
{
WL_DBG(("Couldn't find P2P_SEID_DEV_INFO in probe response/beacon\n"));
kfree(notif_bss_info);
return err;
}
}
if (!mgmt->u.probe_resp.timestamp) {
struct timeval tv;
@ -4613,6 +4756,114 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
return err;
}
static s32 wl_inform_ibss(struct wl_priv *wl, const u8 *bssid)
{
struct net_device *ndev = wl_to_prmry_ndev(wl);
struct wiphy *wiphy = wl_to_wiphy(wl);
struct wl_bss_info *bi = NULL;
struct ieee80211_channel *notify_channel;
struct ieee80211_supported_band *band;
struct cfg80211_bss *bss;
s32 err = 0;
u16 channel;
u32 freq;
u32 wsec = 0;
u16 notify_capability;
u16 notify_interval;
u8 *notify_ie;
size_t notify_ielen;
s32 notify_signal;
WL_TRACE(("Enter\n"));
if (wl->scan_request) {
wl_notify_escan_complete(wl, ndev, true, true);
}
mutex_lock(&wl->usr_sync);
*(u32 *)wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, wl->extra_buf,
WL_EXTRA_BUF_MAX, false);
if (err) {
WL_ERR(("Failed to get bss info for IBSS\n"));
err = -EIO;
goto CleanUp;
}
bi = (struct wl_bss_info *)(wl->extra_buf + 4);
if (memcmp(bssid, &bi->BSSID, ETHER_ADDR_LEN)) {
WL_ERR(("BSSID mismatch: Inform %02x:%02x:%02x:%02x:%02x:%02x,"
"%02x:%02x:%02x:%02x:%02x:%02x\n",
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5],
bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
bi->BSSID.octet[3], bi->BSSID.octet[4],
bi->BSSID.octet[5]));
err = -EINVAL;
goto CleanUp;
}
err = wldev_iovar_getint(ndev, "wsec", &wsec);
if (err) {
WL_ERR(("wsec failed: %d\n", err));
err = -EIO;
goto CleanUp;
}
channel = bi->ctl_ch ? bi->ctl_ch :
CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
freq = ieee80211_channel_to_frequency(channel);
(void)band->band;
#else
freq = ieee80211_channel_to_frequency(channel, band->band);
#endif
notify_channel = ieee80211_get_channel(wiphy, freq);
notify_capability = dtoh16(bi->capability);
notify_interval = dtoh16(bi->beacon_period);
notify_ie = (u8 *)bi + dtoh16(bi->ie_offset);
notify_ielen = dtoh32(bi->ie_length);
notify_signal = (int16)dtoh16(bi->RSSI) * 100;
if (wl->p2p_supported) {
notify_capability |= DOT11_CAP_IBSS;
if (wsec)
notify_capability |= DOT11_CAP_PRIVACY;
}
WL_DBG(("BSSID %02x:%02x:%02x:%02x:%02x:%02x",
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]));
WL_INFO(("channel: %d(%d)\n", channel, freq));
WL_INFO(("capability: %X\n", notify_capability));
WL_INFO(("beacon interval: %d ms\n", notify_interval));
WL_INFO(("signal: %d dBm\n", notify_signal));
WL_INFO(("ie_len: %d\n", notify_ielen));
bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, 0,
notify_capability, notify_interval,
notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
if (!bss) {
WL_ERR(("cfg80211_inform_bss() Failed\n"));
err = -ENOMEM;
goto CleanUp;
}
cfg80211_put_bss(bss);
err = 0;
CleanUp:
mutex_unlock(&wl->usr_sync);
WL_TRACE(("Exit\n"));
return err;
}
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev)
{
u32 event = ntoh32(e->event_type);
@ -4622,12 +4873,12 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
if (event == WLC_E_SET_SSID) {
if (status == WLC_E_STATUS_SUCCESS) {
if (!wl_is_ibssmode(wl, ndev))
return true;
return true;
}
} else if (event == WLC_E_LINK) {
if (flags & WLC_EVENT_MSG_LINK)
return true;
if (!wl_is_ibssmode(wl, ndev))
return true;
}
WL_DBG(("wl_is_linkup false\n"));
@ -4808,7 +5059,9 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
if((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DISASSOC_IND)) {
reason = ntoh32(e->reason);
wl->deauth_reason = reason;
WL_ERR(("Received %s event with reason code: %d\n", (event == WLC_E_DEAUTH_IND)? "WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
WL_ERR(("Received %s event with reason code: %d\n",
(event == WLC_E_DEAUTH_IND)?
"WLC_E_DEAUTH_IND":"WLC_E_DISASSOC_IND", reason));
}
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
@ -4817,10 +5070,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
wl->deauth_reason = 0;
if (wl_is_ibssmode(wl, ndev)) {
printk("cfg80211_ibss_joined\n");
cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
GFP_KERNEL);
WL_DBG(("joined in IBSS network\n"));
wl_ibss_join_done(wl, ndev, e, data, true);
WL_DBG(("wl_ibss_join_done succeeded\n"));
} else {
if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
printk("wl_bss_connect_done succeeded\n");
@ -4830,7 +5081,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID));
}
}
} else if (wl_is_linkdown(wl, e)) {
if (wl->scan_request) {
if (wl->escan_on) {
@ -4854,15 +5104,21 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
scbval.val = htod32(scbval.val);
wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
sizeof(scb_val_t), true);
WL_ERR(("link down, calling cfg80211_disconnected with deauth_reason:%d\n", wl->deauth_reason));
cfg80211_disconnected(ndev, wl->deauth_reason , NULL, 0, GFP_KERNEL);
WL_ERR(("link down, calling cfg80211_disconnected"
" with deauth_reason:%d\n", wl->deauth_reason));
if (!wl_is_ibssmode(wl, ndev))
cfg80211_disconnected(ndev, wl->deauth_reason,
NULL, 0, GFP_KERNEL);
wl_link_down(wl);
wl_init_prof(wl, ndev);
}
}
else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
printk("link down, during connecting\n");
wl_bss_connect_done(wl, ndev, e, data, false);
if (wl_is_ibssmode(wl, ndev))
wl_ibss_join_done(wl, ndev, e, data, false);
else
wl_bss_connect_done(wl, ndev, e, data, false);
}
wl_clr_drv_status(wl, DISCONNECTING, ndev);
@ -5157,6 +5413,35 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
return err;
}
static s32
wl_ibss_join_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data, bool completed)
{
s32 err = 0;
WL_TRACE(("Enter\n"));
if (wl->scan_request) {
wl_notify_escan_complete(wl, ndev, true, true);
}
if (wl_get_drv_status(wl, CONNECTING, ndev)) {
wl_clr_drv_status(wl, CONNECTING, ndev);
if (completed) {
err = wl_inform_ibss(wl, (u8 *)&e->addr);
if (err) {
WL_ERR(("wl_inform_ibss() failed: %d\n", err));
}
wl_set_drv_status(wl, CONNECTED, ndev);
cfg80211_ibss_joined(ndev, (u8 *)&e->addr, GFP_KERNEL);
WL_DBG(("cfg80211_ibss_joined() called with valid BSSID\n"));
}
}
WL_TRACE(("Exit\n"));
return err;
}
static s32
wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
@ -5339,6 +5624,13 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
WL_ERR(("No valid band"));
return -EINVAL;
}
if ((event == WLC_E_P2P_PROBREQ_MSG) &&
wl->p2p && wl_get_p2p_status(wl, GO_NEG_PHASE)) {
WL_DBG(("Filtering P2P probe_req while being in GO-Neg state\n"));
goto exit;
}
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
freq = ieee80211_channel_to_frequency(channel);
#else
@ -5383,6 +5675,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
(act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
wldev_iovar_setint(dev, "mpc", 1);
}
if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
wl_clr_p2p_status(wl, GO_NEG_PHASE);
}
} else {
mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
}
@ -6060,7 +6357,7 @@ static s32 wl_escan_handler(struct wl_priv *wl,
if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
WL_ERR(("Ignoring IBSS result\n"));
WL_DBG(("Ignoring IBSS result\n"));
goto exit;
}
}
@ -6695,20 +6992,148 @@ static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
}
static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
{
struct net_device *dev = wl_to_prmry_ndev(wl);
struct ieee80211_channel *band_chan_arr = NULL;
wl_uint32_list_t *list;
u32 i, j, index, n_2g, n_5g, band, channel, array_size;
u32 *n_cnt = NULL;
chanspec_t c = 0;
s32 err = BCME_OK;
bool update;
bool ht40_allowed;
u8 *pbuf = NULL;
#define LOCAL_BUF_LEN 1024
pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
if (pbuf == NULL) {
WL_ERR(("failed to allocate local buf\n"));
return -ENOMEM;
}
list = (wl_uint32_list_t *)(void *)pbuf;
list->count = htod32(WL_NUMCHANSPECS);
err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync);
if (err != 0) {
WL_ERR(("get chanspecs failed with %d\n", err));
kfree(pbuf);
return err;
}
#undef LOCAL_BUF_LEN
band = array_size = n_2g = n_5g = 0;
for (i = 0; i < dtoh32(list->count); i++) {
index = 0;
update = FALSE;
ht40_allowed = FALSE;
c = (chanspec_t)dtoh32(list->element[i]);
channel = CHSPEC_CHANNEL(c);
if (CHSPEC_IS40(c)) {
if (CHSPEC_SB_UPPER(c))
channel += CH_10MHZ_APART;
else
channel -= CH_10MHZ_APART;
}
if (CHSPEC_IS2G(c) && channel <= CH_MAX_2G_CHANNEL) {
band_chan_arr = __wl_2ghz_channels;
array_size = ARRAYSIZE(__wl_2ghz_channels);
n_cnt = &n_2g;
band = IEEE80211_BAND_2GHZ;
ht40_allowed = (bw_cap == WLC_N_BW_40ALL) ? TRUE : FALSE;
} else if (CHSPEC_IS5G(c) && channel > CH_MAX_2G_CHANNEL) {
band_chan_arr = __wl_5ghz_a_channels;
array_size = ARRAYSIZE(__wl_5ghz_a_channels);
n_cnt = &n_5g;
band = IEEE80211_BAND_5GHZ;
ht40_allowed = (bw_cap == WLC_N_BW_20ALL) ? FALSE : TRUE;
}
for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
if (band_chan_arr[j].hw_value == channel) {
update = TRUE;
break;
}
}
if (update)
index = j;
else
index = *n_cnt;
if (index < array_size) {
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
band_chan_arr[index].center_freq =
ieee80211_channel_to_frequency(channel);
#else
band_chan_arr[index].center_freq =
ieee80211_channel_to_frequency(channel, band);
#endif
band_chan_arr[index].hw_value = channel;
if (CHSPEC_IS40(c) && ht40_allowed) {
u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
if (CHSPEC_SB_UPPER(c)) {
if (ht40_flag == IEEE80211_CHAN_NO_HT40)
band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
} else {
band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
if (ht40_flag == IEEE80211_CHAN_NO_HT40)
band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40MINUS;
}
} else {
band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
if (band == IEEE80211_BAND_2GHZ)
channel |= WL_CHANSPEC_BAND_2G;
else
channel |= WL_CHANSPEC_BAND_5G;
err = wldev_iovar_getint(dev, "per_chan_info", &channel);
if (!err) {
if (channel & WL_CHAN_RADAR) {
band_chan_arr[index].flags |= IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS;
}
if (channel & WL_CHAN_PASSIVE) {
band_chan_arr[index].flags |= IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS;
}
}
}
if (!update)
(*n_cnt)++;
}
}
__wl_band_2ghz.n_channels = n_2g;
__wl_band_5ghz_a.n_channels = n_5g;
kfree(pbuf);
return err;
}
s32 wl_update_wiphybands(struct wl_priv *wl)
{
struct wiphy *wiphy;
struct net_device *dev;
u32 bandlist[3];
u32 nband = 0;
u32 i = 0;
s32 err = 0;
int nmode = 0;
int bw_40 = 0;
int bw_cap = 0;
int index = 0;
WL_DBG(("Entry"));
if (wl == NULL)
wl = wlcfg_drv_priv;
dev = wl_to_prmry_ndev(wl);
memset(bandlist, 0, sizeof(bandlist));
err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
sizeof(bandlist), false);
if (unlikely(err)) {
WL_ERR(("error read bandlist (%d)\n", err));
@ -6719,13 +7144,12 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode);
err = wldev_iovar_getint(dev, "nmode", &nmode);
if (unlikely(err)) {
WL_ERR(("error reading nmode (%d)\n", err));
}
else {
} else {
/* For nmodeonly check bw cap */
err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40);
err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
if (unlikely(err)) {
WL_ERR(("error get mimo_bw_cap (%d)\n", err));
}
@ -6751,7 +7175,7 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
wiphy->bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
}
if ((index >= 0) && bw_40) {
if ((index >= 0) && bw_cap) {
wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
}
}
@ -7080,8 +7504,7 @@ static void wl_init_eq_lock(struct wl_priv *wl)
static void wl_delay(u32 ms)
{
if (ms < 1000 / HZ) {
cond_resched();
if (in_atomic() || ms < 1000 / HZ) {
mdelay(ms);
} else {
msleep(ms);

View File

@ -136,6 +136,12 @@ do { \
#define WL_INVALID -1
/* Bring down SCB Timeout to 20secs from 60secs default */
#ifndef WL_SCB_TIMEOUT
#define WL_SCB_TIMEOUT 20
#endif
/* driver status */
enum wl_status {
WL_STATUS_READY = 0,
@ -662,5 +668,6 @@ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
extern s32 wl_mode_to_nl80211_iftype(s32 mode);
int wl_cfg80211_do_driver_init(struct net_device *net);
void wl_cfg80211_enable_trace(int level);
extern s32 wl_update_wiphybands(struct wl_priv *wl);
extern s32 wl_cfg80211_if_is_group_owner(void);
#endif /* _wl_cfg80211_h_ */

View File

@ -59,6 +59,8 @@ static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
static int wl_cfgp2p_if_open(struct net_device *net);
static int wl_cfgp2p_if_stop(struct net_device *net);
static s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
bool notify);
static const struct net_device_ops wl_cfgp2p_if_ops = {
.ndo_open = wl_cfgp2p_if_open,
@ -338,6 +340,7 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
wl_p2p_if_t ifreq;
s32 err;
struct net_device *ndev = wl_to_prmry_ndev(wl);
u32 scb_timeout = WL_SCB_TIMEOUT;
ifreq.type = if_type;
ifreq.chspec = chspec;
@ -351,6 +354,15 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
if (unlikely(err < 0)) {
printk("'wl p2p_ifadd' error %d\n", err);
} else if (if_type == WL_P2P_IF_GO) {
err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
if (unlikely(err < 0))
printk("'wl scb_timeout' error %d\n", err);
}
return err;
}
@ -387,6 +399,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
{
wl_p2p_if_t ifreq;
s32 err;
u32 scb_timeout = WL_SCB_TIMEOUT;
struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
ifreq.type = if_type;
@ -404,6 +417,10 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
if (unlikely(err < 0)) {
printk("'wl p2p_ifupd' error %d\n", err);
} else if (if_type == WL_P2P_IF_GO) {
err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
if (unlikely(err < 0))
printk("'wl scb_timeout' error %d\n", err);
}
return err;
}
@ -1219,7 +1236,7 @@ wl_cfgp2p_listen_expired(unsigned long data)
/*
* Routine for cancelling the P2P LISTEN
*/
s32
static s32
wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
bool notify)
{

View File

@ -42,7 +42,7 @@ typedef enum {
P2PAPI_BSSCFG_MAX
} p2p_bsscfg_type_t;
#define IE_MAX_LEN 300
#define IE_MAX_LEN 512
/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */
struct p2p_saved_ie {
u8 p2p_probe_req_ie[IE_MAX_LEN];
@ -91,7 +91,8 @@ enum wl_cfgp2p_status {
WLP2P_STATUS_LISTEN_EXPIRED,
WLP2P_STATUS_ACTION_TX_COMPLETED,
WLP2P_STATUS_ACTION_TX_NOACK,
WLP2P_STATUS_SCANNING
WLP2P_STATUS_SCANNING,
WLP2P_STATUS_GO_NEG_PHASE
};