* 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: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $
+ * $Id: bcmsdh_sdmmc.c 314904 2012-02-14 21:36:04Z $
*/
#include <typedefs.h>
#include <sdiovar.h> /* ioctl/iovars */
#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
sd->sd_blockmode = TRUE;
sd->use_client_ints = TRUE;
sd->client_block_size[0] = 64;
+ sd->use_rxchain = FALSE;
gInstance->sd = sd;
}
case IOV_GVAL(IOV_RXCHAIN):
- int_val = FALSE;
+ int_val = (int32)si->use_rxchain;
bcopy(&int_val, arg, val_size);
break;
bool fifo = (fix_inc == SDIOH_DATA_FIX);
uint32 SGCount = 0;
int err_ret = 0;
-
- void *pnext;
+ void *pnext, *pprev;
+ uint ttl_len, dma_len, lft_len, xfred_len, pkt_len;
+ uint blk_num;
+ struct mmc_request mmc_req;
+ struct mmc_command mmc_cmd;
+ struct mmc_data mmc_dat;
sd_trace(("%s: Enter\n", __FUNCTION__));
DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
- /* Claim host controller */
- sdio_claim_host(gInstance->func[func]);
- for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
- uint pkt_len = PKTLEN(sd->osh, pnext);
- pkt_len += 3;
- pkt_len &= 0xFFFFFFFC;
+ ttl_len = xfred_len = 0;
+ /* at least 4 bytes alignment of skb buff is guaranteed */
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext))
+ ttl_len += PKTLEN(sd->osh, pnext);
-#ifdef CONFIG_MMC_MSM7X00A
- if ((pkt_len % 64) == 32) {
- sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
- pkt_len += 32;
- }
-#endif /* CONFIG_MMC_MSM7X00A */
- /* Make sure the packet is aligned properly. If it isn't, then this
- * is the fault of sdioh_request_buffer() which is supposed to give
- * us something we can work with.
- */
- ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
-
- if ((write) && (!fifo)) {
- err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
- ((uint8*)PKTDATA(sd->osh, pnext)),
- pkt_len);
- } else if (write) {
- err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
- ((uint8*)PKTDATA(sd->osh, pnext)),
- pkt_len);
- } else if (fifo) {
- err_ret = sdio_readsb(gInstance->func[func],
- ((uint8*)PKTDATA(sd->osh, pnext)),
- addr,
- pkt_len);
- } else {
- err_ret = sdio_memcpy_fromio(gInstance->func[func],
- ((uint8*)PKTDATA(sd->osh, pnext)),
- addr,
+ if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) {
+ blk_num = 0;
+ dma_len = 0;
+ } else {
+ blk_num = ttl_len / sd->client_block_size[func];
+ dma_len = blk_num * sd->client_block_size[func];
+ }
+ lft_len = ttl_len - dma_len;
+
+ sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n",
+ __FUNCTION__, write ? "W" : "R",
+ ttl_len, func, addr, blk_num, lft_len));
+
+ if (0 != dma_len) {
+ memset(&mmc_req, 0, sizeof(struct mmc_request));
+ memset(&mmc_cmd, 0, sizeof(struct mmc_command));
+ memset(&mmc_dat, 0, sizeof(struct mmc_data));
+
+ /* Set up DMA descriptors */
+ pprev = pkt;
+ for (pnext = pkt;
+ pnext && dma_len;
+ pnext = PKTNEXT(sd->osh, pnext)) {
+ pkt_len = PKTLEN(sd->osh, pnext);
+
+ if (dma_len > pkt_len)
+ dma_len -= pkt_len;
+ else {
+ pkt_len = xfred_len = dma_len;
+ dma_len = 0;
+ pkt = pnext;
+ }
+
+ sg_set_buf(&sd->sg_list[SGCount++],
+ (uint8*)PKTDATA(sd->osh, pnext),
pkt_len);
- }
- if (err_ret) {
- sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
- __FUNCTION__,
- (write) ? "TX" : "RX",
- pnext, SGCount, addr, pkt_len, err_ret));
- } else {
- sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
- __FUNCTION__,
- (write) ? "TX" : "RX",
- pnext, SGCount, addr, pkt_len));
+ if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) {
+ sd_err(("%s: sg list entries exceed limit\n",
+ __FUNCTION__));
+ return (SDIOH_API_RC_FAIL);
+ }
}
- if (!fifo) {
- addr += pkt_len;
- }
- SGCount ++;
+ mmc_dat.sg = sd->sg_list;
+ mmc_dat.sg_len = SGCount;
+ mmc_dat.blksz = sd->client_block_size[func];
+ mmc_dat.blocks = blk_num;
+ mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+ mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */
+ mmc_cmd.arg = write ? 1<<31 : 0;
+ mmc_cmd.arg |= (func & 0x7) << 28;
+ mmc_cmd.arg |= 1<<27;
+ mmc_cmd.arg |= fifo ? 0 : 1<<26;
+ mmc_cmd.arg |= (addr & 0x1FFFF) << 9;
+ mmc_cmd.arg |= blk_num & 0x1FF;
+ mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ mmc_req.cmd = &mmc_cmd;
+ mmc_req.data = &mmc_dat;
+
+ sdio_claim_host(gInstance->func[func]);
+ mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card);
+ mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req);
+ sdio_release_host(gInstance->func[func]);
+
+ err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error;
+ if (0 != err_ret) {
+ sd_err(("%s:CMD53 %s failed with code %d\n",
+ __FUNCTION__,
+ write ? "write" : "read",
+ err_ret));
+ sd_err(("%s:Disabling rxchain and fire it with PIO\n",
+ __FUNCTION__));
+ sd->use_rxchain = FALSE;
+ pkt = pprev;
+ lft_len = ttl_len;
+ } else if (!fifo) {
+ addr = addr + ttl_len - lft_len - dma_len;
+ }
}
- /* Release host controller */
- sdio_release_host(gInstance->func[func]);
+ /* PIO mode */
+ if (0 != lft_len) {
+ /* Claim host controller */
+ sdio_claim_host(gInstance->func[func]);
+ for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
+ uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) +
+ xfred_len;
+ pkt_len = PKTLEN(sd->osh, pnext);
+ if (0 != xfred_len) {
+ pkt_len -= xfred_len;
+ xfred_len = 0;
+ }
+ pkt_len = (pkt_len + 3) & 0xFFFFFFFC;
+#ifdef CONFIG_MMC_MSM7X00A
+ if ((pkt_len % 64) == 32) {
+ sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
+ pkt_len += 32;
+ }
+#endif /* CONFIG_MMC_MSM7X00A */
+
+ if ((write) && (!fifo))
+ err_ret = sdio_memcpy_toio(
+ gInstance->func[func],
+ addr, buf, pkt_len);
+ else if (write)
+ err_ret = sdio_memcpy_toio(
+ gInstance->func[func],
+ addr, buf, pkt_len);
+ else if (fifo)
+ err_ret = sdio_readsb(
+ gInstance->func[func],
+ buf, addr, pkt_len);
+ else
+ err_ret = sdio_memcpy_fromio(
+ gInstance->func[func],
+ buf, addr, pkt_len);
+
+ if (err_ret)
+ sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, SGCount, addr, pkt_len, err_ret));
+ else
+ sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ __FUNCTION__,
+ (write) ? "TX" : "RX",
+ pnext, SGCount, addr, pkt_len));
+
+ if (!fifo)
+ addr += pkt_len;
+ SGCount ++;
+ }
+ sdio_release_host(gInstance->func[func]);
+ }
sd_trace(("%s: Exit\n", __FUNCTION__));
return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
2.6.27. The implementation prior to that is buggy, and needs broadcom's
patch for it
*/
- if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
+ if ((ret = sdio_reset_comm(gInstance->func[0]->card))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
+ return ret;
+ }
else {
sd->num_funcs = 2;
sd->sd_blockmode = TRUE;
* 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 308879 2012-01-17 22:03:47Z $
+ * $Id: dhd_linux.c 314746 2012-02-14 03:45:02Z $
*/
#include <typedefs.h>
#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
/* Linux wireless extension support */
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
#include <wl_iw.h>
extern wl_iw_extra_params_t g_wl_iw_params;
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
/* Local private structure (extension of pub) */
typedef struct dhd_info {
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
wl_iw_t iw; /* wireless extensions state (must be first) */
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
dhd_pub_t pub;
char iface_name[IFNAMSIZ] = {'\0'};
module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
-#define BLOCKABLE() (!in_atomic())
-#else
-#define BLOCKABLE() (!in_interrupt())
-#endif
-
/* The following are specific to the SDIO dongle */
/* IOCTL response timeout */
int dhd_monitor_uninit(void);
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
static void dhd_dpc(ulong data);
/* forward decl */
return -1;
}
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
/* linux wireless extensions */
if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
/* may recurse, do NOT lock */
DHD_OS_WAKE_UNLOCK(&dhd->pub);
return ret;
}
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
if (cmd == SIOCETHTOOL) {
}
dhd->pub.hang_was_sent = 0;
-
#if !defined(WL_CFG80211)
/*
* Force start if ifconfig_up gets called before START command
dhd_monitor_init(&dhd->pub);
dhd_state |= DHD_ATTACH_STATE_CFG80211;
#endif
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
/* Attach and link in the iw */
if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
}
dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
}
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
/* Set up the watchdog timer */
#if defined(ARP_OFFLOAD_SUPPORT)
int arpoe = 1;
#endif
+#if defined(KEEP_ALIVE)
+ int res;
+#endif /* defined(KEEP_ALIVE) */
int scan_assoc_time = DHD_SCAN_ACTIVE_TIME;
int scan_unassoc_time = 40;
int scan_passive_time = DHD_SCAN_PASSIVE_TIME;
#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
#endif
-
#if defined(AP) || defined(WLP2P)
uint32 apsta = 1; /* Enable APSTA mode */
#endif /* defined(AP) || defined(WLP2P) */
#ifdef GET_CUSTOM_MAC_ENABLE
struct ether_addr ea_addr;
#endif /* GET_CUSTOM_MAC_ENABLE */
-
DHD_TRACE(("Enter %s\n", __FUNCTION__));
dhd->op_mode = 0;
#ifdef GET_CUSTOM_MAC_ENABLE
/* Setup assoc_retry_max count to reconnect target AP in dongle */
bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
#if defined(AP) && !defined(WLP2P)
/* Turn off MPC in AP mode */
bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
#endif
#if defined(KEEP_ALIVE)
- {
/* Set Keep Alive : be sure to use FW with -keepalive */
- int res;
-
#if defined(SOFTAP)
if (ap_fw_loaded == FALSE)
#endif
if ((res = dhd_keep_alive_onoff(dhd)) < 0)
DHD_ERROR(("%s set keeplive failed %d\n",
__FUNCTION__, res));
- }
#endif /* defined(KEEP_ALIVE) */
/* Read event_msgs mask */
net->ethtool_ops = &dhd_ethtool_ops;
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
#if WIRELESS_EXT < 19
net->get_wireless_stats = dhd_get_wireless_stats;
#endif /* WIRELESS_EXT < 19 */
#if WIRELESS_EXT > 12
net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
#endif /* WIRELESS_EXT > 12 */
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
net->dev_addr[0], net->dev_addr[1], net->dev_addr[2],
net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]);
-#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211)
+#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
wl_iw_iscan_set_scan_broadcast_prep(net, 1);
#endif
}
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
/* Detatch and unlink in the iw */
wl_iw_detach();
}
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
if (dhd->thr_sysioc_ctl.thr_pid >= 0) {
PROC_STOP(&dhd->thr_sysioc_ctl);
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
- /*
- * Wait till MMC sdio_register_driver callback called and made driver attach.
- * It's needed to make sync up exit from dhd insmod and
- * Kernel MMC sdio device callback registration
- */
+ /*
+ * Wait till MMC sdio_register_driver callback called and made driver attach.
+ * It's needed to make sync up exit from dhd insmod and
+ * Kernel MMC sdio device callback registration
+ */
if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
- error = -EINVAL;
+ error = -ENODEV;
DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
goto fail_2;
}
#endif
#if defined(WL_CFG80211)
wl_android_post_init();
-#endif
+#endif /* defined(WL_CFG80211) */
return error;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
}
#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
struct iw_statistics *
dhd_get_wireless_stats(struct net_device *dev)
{
else
return NULL;
}
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
static int
dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
if (bcmerror != BCME_OK)
return (bcmerror);
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
if (event->bsscfgidx == 0) {
/*
* Wireless ext is on primary interface only
wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
}
}
-#endif /* defined(CONFIG_WIRELESS_EXT) */
+#endif /* defined(WL_WIRELESS_EXT) */
#ifdef WL_CFG80211
if ((ntoh32(event->event_type) == WLC_E_IF) &&
#endif /* PNO_SUPPORT */
+struct work_struct work;
+
int net_os_send_hang_message(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
dev_close(dev);
if (need_unlock)
rtnl_unlock();
-#if defined(CONFIG_WIRELESS_EXT)
+#if defined(WL_WIRELESS_EXT)
ret = wl_iw_send_priv_event(dev, "HANG");
#endif
#if defined(WL_CFG80211)
memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
}
-
void dhd_net_if_lock(struct net_device *dev)
{
dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
struct cfg80211_pmksa *pmksa);
static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
struct net_device *dev);
-static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted);
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
+ struct net_device *ndev, bool aborted, bool fw_abort);
/*
* event & event Q handlers for cfg80211 interfaces
*/
const wl_event_msg_t *e, void *data);
static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
+#ifdef WL_SCHED_SCAN
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WL_SCHED_SCAN */
+#ifdef PNO_SUPPORT
static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
+#endif /* PNO_SUPPORT */
/*
* register/deregister parent device
*/
* doesn't match with the IE present in the 3/4 EAPOL msg.
*/
.ht_cap = {
- IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
- .ht_supported = TRUE,
- .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
- .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
+ .ht_supported = TRUE,
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
}
#endif
};
.channels = __wl_5ghz_a_channels,
.n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
.bitrates = wl_a_rates,
- .n_bitrates = wl_a_rates_size
+ .n_bitrates = wl_a_rates_size,
+#if ENABLE_P2P_INTERFACE
+ /* wpa_supplicant sets wmm_enabled based on whether ht_cap
+ * is present or not. The wmm_enabled is inturn used to
+ * set the replay counters in the RSN IE. Without this
+ * the 4way handshake will fail complaining that IE in beacon
+ * doesn't match with the IE present in the 3/4 EAPOL msg.
+ */
+ .ht_cap = {
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU,
+ .ht_supported = TRUE,
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16
+ }
+#endif
};
static const u32 __wl_cipher_suites[] = {
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
if (wl->p2p->vif_created) {
- if (wl_get_drv_status(wl, SCANNING, dev)) {
- wl_cfg80211_scan_abort(wl, dev);
+ if (wl->scan_request) {
+ wl_notify_escan_complete(wl, dev, true, true);
}
wldev_iovar_setint(dev, "mpc", 1);
wl_set_p2p_status(wl, IF_DELETING);
rollback_lock = true;
}
WL_DBG(("ESCAN COMPLETED\n"));
- wl_notify_escan_complete(wl, ndev, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
if (rollback_lock)
rtnl_unlock();
}
wpa_ie_fixed_t *wps_ie;
s32 passive_scan;
bool iscan_req;
- bool escan_req;
+ bool escan_req = false;
bool p2p_ssid;
s32 err = 0;
s32 i;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
switch (sme->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
- val = 0;
+ val = WL_AUTH_OPEN_SYSTEM;
WL_DBG(("open system\n"));
break;
case NL80211_AUTHTYPE_SHARED_KEY:
- val = 1;
+ val = WL_AUTH_SHARED_KEY;
WL_DBG(("shared key\n"));
break;
case NL80211_AUTHTYPE_AUTOMATIC:
- val = 2;
+ val = WL_AUTH_OPEN_SHARED;
WL_DBG(("automatic\n"));
break;
case NL80211_AUTHTYPE_NETWORK_EAP:
WL_DBG(("network eap\n"));
default:
- val = 2;
+ val = WL_AUTH_OPEN_SHARED;
WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
break;
}
WL_ERR(("WLC_SET_KEY error (%d)\n", err));
return err;
}
- if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
WL_DBG(("set auth_type to shared key\n"));
- val = 1; /* shared key */
+ val = WL_AUTH_SHARED_KEY; /* shared key */
err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
if (unlikely(err)) {
WL_ERR(("set auth failed (%d)\n", err));
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
/* Clean BSSID */
bzero(&bssid, sizeof(bssid));
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
wl_set_drv_status(wl, DISCONNECTING, dev);
scbval.val = reason_code;
return -EINVAL;
}
swap_key_from_BE(&key);
-#if defined(CONFIG_WIRELESS_EXT)
- dhd_wait_pend8021x(dev);
-#endif
wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
if (unlikely(err)) {
sta->idle * 1000));
#endif
} else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
- u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
- if (!wl_get_drv_status(wl, CONNECTED, dev) ||
- (dhd_is_associated(dhd, NULL) == FALSE)) {
- WL_ERR(("NOT assoc\n"));
- err = -ENODEV;
- goto get_station_err;
- }
- if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
- WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
- MAC2STR(mac), MAC2STR(curmacp)));
- }
+ u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID);
+ if (!wl_get_drv_status(wl, CONNECTED, dev) ||
+ (dhd_is_associated(dhd, NULL) == FALSE)) {
- /* Report the current tx rate */
- err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
- if (err) {
- WL_ERR(("Could not get rate (%d)\n", err));
- } else {
- rate = dtoh32(rate);
- sinfo->filled |= STATION_INFO_TX_BITRATE;
- sinfo->txrate.legacy = rate * 5;
- WL_DBG(("Rate %d Mbps\n", (rate / 2)));
- }
+ WL_ERR(("NOT assoc\n"));
+ err = -ENODEV;
+ goto get_station_err;
+ }
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+ WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
+ MAC2STR(mac), MAC2STR(curmacp)));
+ }
- memset(&scb_val, 0, sizeof(scb_val));
- scb_val.val = 0;
- err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
- sizeof(scb_val_t), false);
- if (err) {
- WL_ERR(("Could not get rssi (%d)\n", err));
- goto get_station_err;
- }
+ /* Report the current tx rate */
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+ rate = dtoh32(rate);
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+ }
- rssi = dtoh32(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
- sinfo->signal = rssi;
- WL_DBG(("RSSI %d dBm\n", rssi));
+ memset(&scb_val, 0, sizeof(scb_val));
+ scb_val.val = 0;
+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+ sizeof(scb_val_t), false);
+ if (err) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ goto get_station_err;
+ }
+ rssi = dtoh32(scb_val.val);
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
get_station_err:
if (err) {
return -EINVAL;
}
/* pmk list is supported only for STA interface i.e. primary interface
- * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
- */
+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+ */
if (primary_dev != dev) {
WL_INFO(("Not supporting Flushing pmklist on virtual"
" interfaces than primary interface\n"));
s32 params_size = 0;
s32 err = BCME_OK;
unsigned long flags;
+ struct net_device *dev;
WL_DBG(("Enter\n"));
+ if (wl->scan_request) {
+ if (wl->scan_request->dev == wl->p2p_net)
+ dev = wl_to_prmry_ndev(wl);
+ else
+ dev = wl->scan_request->dev;
+ }
+ else {
+ WL_ERR(("wl->scan_request is NULL did we already do scan_abort?"
+ "Now scan_abort for ndev %p primary %p p2p_net %p",
+ ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
+ dev = ndev;
+ }
/* Our scan params only need space for 1 channel and 0 ssids */
params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size);
err = -ENOMEM;
} else {
/* Do a scan abort to stop the driver's scan engine */
- err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
if (err < 0) {
WL_ERR(("scan abort failed \n"));
}
}
del_timer_sync(&wl->scan_timeout);
spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+
+#ifdef WL_SCHED_SCAN
+ if (wl->sched_scan_req && !wl->scan_request) {
+ cfg80211_sched_scan_stopped(wl_to_wiphy(wl));
+ wl->sched_scan_req = NULL;
+ }
+#endif /* WL_SCHED_SCAN */
+
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
- wl_clr_drv_status(wl, SCANNING, ndev);
+ wl_clr_drv_status(wl, SCANNING, dev);
spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
if (params)
kfree(params);
ndev = dev;
}
- if (wl_get_drv_status(wl, SCANNING, ndev)) {
- wl_cfg80211_scan_abort(wl, ndev);
+ if (wl->scan_request) {
+ wl_notify_escan_complete(wl, ndev, true, true);
}
-
target_channel = ieee80211_frequency_to_channel(channel->center_freq);
memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
wl->remain_on_chan_type = channel_type;
*/
wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev);
wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
wl_cfgp2p_discover_enable_search(wl, false);
tx_act_frm->channel = wl->afx_hdl->peer_chan;
wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev,
scb_val.val = mgmt->u.disassoc.reason_code;
wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
sizeof(scb_val_t), true);
- WL_DBG(("Disconnect STA : %s\n",
- bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf)));
+ WL_DBG(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val));
cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
goto exit;
* tx is still in progress (including the dwell time),
* then this new action frame will not be sent out.
*/
- wl_cfg80211_scan_abort(wl, dev);
+ wl_notify_escan_complete(wl, dev, true, true);
}
ieee80211_frequency_to_channel(channel->center_freq);
if (channel->band == IEEE80211_BAND_5GHZ) {
+ WL_DBG(("5GHz channel %d", af_params->channel));
err = wldev_ioctl(dev, WLC_SET_CHANNEL,
&af_params->channel, sizeof(af_params->channel), true);
if (err < 0) {
{
s32 len = 0;
s32 err = BCME_OK;
- u16 auth = 0; /* d11 open authentication */
+ u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
u32 wsec;
u32 pval = 0;
u32 gval = 0;
wpa_suite_mcast_t *mcast;
wpa_suite_ucast_t *ucast;
wpa_suite_auth_key_mgmt_t *mgmt;
- u16 auth = 0; /* d11 open authentication */
+ u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */
u16 count;
s32 err = BCME_OK;
s32 len = 0;
memcpy(beacon_ie, wps_ie, wpsie_len);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
beacon_ie, wpsie_len);
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else {
memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
WL_DBG((" WPS IE is changed\n"));
kfree(wl->ap_info->wps_ie);
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
} else if (wl->ap_info->wps_ie == NULL) {
WL_DBG((" WPS IE is added\n"));
- wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
+ wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
}
return err;
}
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME 30
+#define PNO_REPEAT 4
+#define PNO_FREQ_EXPO_MAX 3
+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];
+ struct wl_priv *wl = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssid = NULL;
+ int ssid_count = 0;
+ int i;
+ int ret = 0;
+
+ WL_DBG(("Enter n_match_sets:%d n_ssids:%d \n",
+ request->n_match_sets, request->n_ssids));
+ WL_DBG(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+ if (wl_get_drv_status_all(wl, SCANNING)) {
+ WL_ERR(("Scanning already\n"));
+ return -EAGAIN;
+ }
+
+ if (!request || !request->n_ssids || !request->n_match_sets) {
+ WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
+ return -EINVAL;
+ }
+
+ 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_DBG((">>> 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_DBG((">>> 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 (ssid_count) {
+ if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets,
+ pno_time, pno_repeat, pno_freq_expo_max)) < 0) {
+ WL_ERR(("PNO setup failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+
+ /* Enable the PNO */
+ if (dhd_dev_pno_enable(dev, 1) < 0) {
+ WL_ERR(("PNO enable failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+ wl->sched_scan_req = request;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct wl_priv *wl = wiphy_priv(wiphy);
+
+ WL_DBG(("Enter \n"));
+
+ if (dhd_dev_pno_enable(dev, 0) < 0)
+ WL_ERR(("PNO disable failed"));
+
+ if (dhd_dev_pno_reset(dev) < 0)
+ WL_ERR(("PNO reset failed"));
+
+ if (wl->scan_request && wl->sched_scan_running) {
+ wl_cfg80211_scan_abort(wl, dev);
+ }
+
+ wl->sched_scan_req = NULL;
+ wl->sched_scan_running = FALSE;
+
+ return 0;
+}
+#endif /* WL_SCHED_SCAN */
+
static struct cfg80211_ops wl_cfg80211_ops = {
.add_virtual_intf = wl_cfg80211_add_virtual_iface,
.del_virtual_intf = wl_cfg80211_del_virtual_iface,
.set_channel = wl_cfg80211_set_channel,
.set_beacon = wl_cfg80211_add_set_beacon,
.add_beacon = wl_cfg80211_add_set_beacon,
+#ifdef WL_SCHED_SCAN
+ .sched_scan_start = wl_cfg80211_sched_scan_start,
+ .sched_scan_stop = wl_cfg80211_sched_scan_stop,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */
};
s32 wl_mode_to_nl80211_iftype(s32 mode)
/* Report how many SSIDs Driver can support per Scan request */
wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#ifdef WL_SCHED_SCAN
+ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* WL_SCHED_SCAN */
wdev->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION)
| BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
- wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
+ /* wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - set in runtime */
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wdev->wiphy->cipher_suites = __wl_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
#endif
WIPHY_FLAG_4ADDR_STATION;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
- wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
#endif
WL_DBG(("Registering custom regulatory)\n"));
wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
u32 status = ntoh32(e->status);
u16 flags = ntoh16(e->flags);
- WL_DBG(("event %d, status %d\n", event, status));
+ 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))
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE
memset(body, 0, sizeof(body));
memset(&bssid, 0, ETHER_ADDR_LEN);
- WL_DBG(("Enter \n"));
+ WL_DBG(("Enter event %d ndev %p\n", event, ndev));
if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID)
return WL_INVALID;
if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
wl_notify_connect_status_ap(wl, ndev, e, data);
} else {
- WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
- ntoh32(e->event_type), ntoh32(e->status)));
+ WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
+ ntoh32(e->event_type), ntoh32(e->status), ndev));
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
act = true;
} else if (wl_is_linkdown(wl, e)) {
if (wl->scan_request) {
- del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
- wl_notify_escan_complete(wl, ndev, true);
- } else
+ wl_notify_escan_complete(wl, ndev, true, true);
+ } else {
+ del_timer_sync(&wl->scan_timeout);
wl_iscan_aborted(wl);
+ }
}
if (wl_get_drv_status(wl, CONNECTED, ndev)) {
scb_val_t scbval;
u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID);
printk("link down, call cfg80211_disconnected\n");
wl_clr_drv_status(wl, CONNECTED, ndev);
- /* To make sure disconnect, explictly send dissassoc
- * for BSSID 00:00:00:00:00:00 issue
- */
- scbval.val = WLAN_REASON_DEAUTH_LEAVING;
-
- memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
- scbval.val = htod32(scbval.val);
- wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
- sizeof(scb_val_t), true);
- cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
- wl_link_down(wl);
- wl_init_prof(wl, ndev);
- } else if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+ if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) {
+ /* To make sure disconnect, explictly send dissassoc
+ * for BSSID 00:00:00:00:00:00 issue
+ */
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ cfg80211_disconnected(ndev, 0, 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);
}
event, (int)ntoh32(e->status));
/* Clean up any pending scan request */
if (wl->scan_request) {
- del_timer_sync(&wl->scan_timeout);
if (wl->escan_on) {
- wl_notify_escan_complete(wl, ndev, true);
- } else
+ wl_notify_escan_complete(wl, ndev, true, true);
+ } else {
+ del_timer_sync(&wl->scan_timeout);
wl_iscan_aborted(wl);
+ }
}
if (wl_get_drv_status(wl, CONNECTING, ndev))
wl_bss_connect_done(wl, ndev, e, data, false);
u8 *curbssid;
s32 err = 0;
struct wiphy *wiphy;
+
wiphy = wl_to_wiphy(wl);
if (wl_is_ibssmode(wl, ndev))
WL_DBG((" enter\n"));
if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, ndev);
+ wl_notify_escan_complete(wl, ndev, true, true);
}
if (wl_get_drv_status(wl, CONNECTING, ndev)) {
wl_clr_drv_status(wl, CONNECTING, ndev);
return 0;
}
+#ifdef PNO_SUPPORT
static s32
wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
WL_ERR((" PNO Event\n"));
mutex_lock(&wl->usr_sync);
+#ifndef WL_SCHED_SCAN
/* TODO: Use cfg80211_sched_scan_results(wiphy); */
cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
+#else
+ /* If cfg80211 scheduled scan is supported, report the pno results via sched
+ * scan results
+ */
+ wl_notify_sched_scan_results(wl, ndev, e, data);
+#endif /* WL_SCHED_SCAN */
mutex_unlock(&wl->usr_sync);
return 0;
}
+#endif /* PNO_SUPPORT */
static s32
wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
* After complete GO Negotiation, roll back to mpc mode
*/
if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
- (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
wldev_iovar_setint(dev, "mpc", 1);
}
} else {
return 0;
}
+#ifdef WL_SCHED_SCAN
+/* If target scan is not reliable, set the below define to "0" to do a
+ * full escan
+ */
+#define FULL_ESCAN_ON_PFN_NET_FOUND 1
+static s32
+wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ wl_pfn_net_info_t *netinfo, *pnetinfo;
+ struct cfg80211_scan_request request;
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ int err = 0;
+ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
+ struct ieee80211_channel *channel = NULL;
+ int channel_req = 0;
+ int band = 0;
+ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
+
+ WL_DBG(("Enter\n"));
+
+ if (e->event_type == WLC_E_PFN_NET_LOST) {
+ WL_DBG(("PFN NET LOST event. Do Nothing \n"));
+ return 0;
+ } else {
+ WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count));
+
+
+ if (pfn_result->count > 0) {
+ int i;
+
+ memset(&request, 0x00, sizeof(struct cfg80211_scan_request));
+ memset(&ssid, 0x00, sizeof(ssid));
+ request.wiphy = wiphy;
+
+ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
+ - sizeof(wl_pfn_net_info_t));
+
+ channel = (struct ieee80211_channel *)kzalloc(
+ (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT),
+ GFP_KERNEL);
+ if (!channel) {
+ WL_ERR(("No memory"));
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ for (i = 0; i < pfn_result->count; i++) {
+ netinfo = &pnetinfo[i];
+ if (!netinfo) {
+ WL_ERR(("Invalid netinfo ptr. index:%d", i));
+ err = -EINVAL;
+ goto out_err;
+ }
+
+ WL_DBG(("SSID:%s Channel:%d \n",
+ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
+ /* PFN result doesn't have all the info which are required by the supplicant
+ * (For e.g IEs) Do a target Escan so that sched scan results are reported
+ * via wl_inform_single_bss in the required format. Escan does require the
+ * scan request in the form of cfg80211_scan_request. For timebeing, create
+ * cfg80211_scan_request one out of the received PNO event.
+ */
+ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID,
+ netinfo->pfnsubnet.SSID_len);
+ ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len;
+ request.n_ssids++;
+
+ channel_req = netinfo->pfnsubnet.channel;
+ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
+ : NL80211_BAND_2GHZ;
+ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
+ channel[i].band = band;
+ channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+ request.channels[i] = &channel[i];
+ request.n_channels++;
+ }
+
+ /* assign parsed ssid array */
+ if (request.n_ssids)
+ request.ssids = &ssid[0];
+
+ if (wl_get_drv_status_all(wl, SCANNING)) {
+ /* Abort any on-going scan */
+ wl_cfg80211_scan_abort(wl, ndev);
+ }
+
+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
+ err = wl_cfgp2p_discover_enable_search(wl, false);
+ if (unlikely(err)) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
+ goto out_err;
+ }
+ }
+
+ wl_set_drv_status(wl, SCANNING, ndev);
+#if FULL_ESCAN_ON_PFN_NET_FOUND
+ err = wl_do_escan(wl, wiphy, ndev, &request);
+#else
+ err = wl_do_escan(wl, wiphy, ndev, NULL);
+#endif
+ if (err) {
+ wl_clr_drv_status(wl, SCANNING, ndev);
+ goto out_err;
+ }
+ } else {
+ WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
+ }
+ wl->sched_scan_running = TRUE;
+ }
+
+ kfree(channel);
+ return 0;
+
+out_err:
+ if (channel)
+ kfree(channel);
+ return err;
+}
+#endif /* WL_SCHED_SCAN */
+
static void wl_init_conf(struct wl_conf *conf)
{
WL_DBG(("Enter \n"));
wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
+#ifdef PNO_SUPPORT
wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
+#endif /* PNO_SUPPORT */
}
static s32 wl_init_priv_mem(struct wl_priv *wl)
if (wl->scan_request) {
WL_ERR(("timer expired\n"));
if (wl->escan_on)
- wl_notify_escan_complete(wl, wl->escan_info.ndev, true);
+ wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true);
else
wl_notify_iscan_complete(wl_to_iscan(wl), true);
}
.notifier_call = wl_cfg80211_netdev_notifier_call,
};
-static void wl_notify_escan_complete(struct wl_priv *wl,
+static s32 wl_notify_escan_complete(struct wl_priv *wl,
struct net_device *ndev,
- bool aborted)
+ bool aborted, bool fw_abort)
{
+ wl_scan_params_t *params = NULL;
+ s32 params_size = 0;
+ s32 err = BCME_OK;
unsigned long flags;
+ struct net_device *dev;
WL_DBG(("Enter \n"));
- wl_clr_drv_status(wl, SCANNING, ndev);
- if (p2p_is_on(wl))
- wl_clr_p2p_status(wl, SCANNING);
+
+ if (wl->scan_request) {
+ if (wl->scan_request->dev == wl->p2p_net)
+ dev = wl_to_prmry_ndev(wl);
+ else
+ dev = wl->scan_request->dev;
+ }
+ else {
+ WL_ERR(("wl->scan_request is NULL may be internal scan."
+ "doing scan_abort for ndev %p primary %p p2p_net %p",
+ ndev, wl_to_prmry_ndev(wl), wl->p2p_net));
+ dev = ndev;
+ }
+ if (fw_abort) {
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size);
+ if (params == NULL) {
+ WL_ERR(("scan params allocation failed \n"));
+ err = -ENOMEM;
+ } else {
+ /* Do a scan abort to stop the driver's scan engine */
+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
+ if (err < 0) {
+ WL_ERR(("scan abort failed \n"));
+ }
+ }
+ }
+ del_timer_sync(&wl->scan_timeout);
spin_lock_irqsave(&wl->cfgdrv_lock, flags);
+
+#ifdef WL_SCHED_SCAN
+ if (wl->sched_scan_req && wl->sched_scan_running && !wl->scan_request) {
+ WL_DBG((" REPORTING SCHED SCAN RESULTS \n"));
+ cfg80211_sched_scan_results(wl->sched_scan_req->wiphy);
+ wl->sched_scan_running = FALSE;
+ wl->sched_scan_req = NULL;
+ wl->scan_request = NULL;
+ }
+#endif /* WL_SCHED_SCAN */
+
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
}
+ if (p2p_is_on(wl))
+ wl_clr_p2p_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCANNING, dev);
spin_unlock_irqrestore(&wl->cfgdrv_lock, flags);
+ if (params)
+ kfree(params);
+
+ return err;
}
static s32 wl_escan_handler(struct wl_priv *wl,
wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
if (wl->afx_hdl->peer_chan == WL_INVALID)
complete(&wl->act_frm_scan);
- } else if (likely(wl->scan_request)) {
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN COMPLETED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, ndev, false);
+ wl_notify_escan_complete(wl, ndev, false, false);
mutex_unlock(&wl->usr_sync);
}
}
wl_clr_p2p_status(wl, SCANNING);
if (wl->afx_hdl->peer_chan == WL_INVALID)
complete(&wl->act_frm_scan);
- } else if (likely(wl->scan_request)) {
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
WL_INFO(("ESCAN ABORTED\n"));
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, ndev, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
mutex_unlock(&wl->usr_sync);
}
}
wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev);
if (wl->afx_hdl->peer_chan == WL_INVALID)
complete(&wl->act_frm_scan);
- } else if (likely(wl->scan_request)) {
+ } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) {
mutex_lock(&wl->usr_sync);
- del_timer_sync(&wl->scan_timeout);
wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
wl_inform_bss(wl);
- wl_notify_escan_complete(wl, ndev, true);
+ wl_notify_escan_complete(wl, ndev, true, false);
mutex_unlock(&wl->usr_sync);
}
}
tsk_ctl_t *tsk = (tsk_ctl_t *)data;
wl = (struct wl_priv *)tsk->parent;
-
- DAEMONIZE("wl_event_handler");
-
+ DAEMONIZE("dhd_cfg80211_event");
complete(&tsk->completed);
while (down_interruptible (&tsk->sema) == 0) {
}
DHD_OS_WAKE_UNLOCK(wl->pub);
}
- WL_DBG(("%s was terminated\n", __func__));
+ WL_ERR(("%s was terminated\n", __func__));
complete_and_exit(&tsk->completed, 0);
return 0;
}
s32 wl_update_wiphybands(struct wl_priv *wl)
{
struct wiphy *wiphy;
- s8 phylist_buf[128];
- s8 *phy;
+ u32 bandlist[3];
+ u32 nband = 0;
+ u32 i = 0;
s32 err = 0;
-
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
- sizeof(phylist_buf), false);
+ WL_DBG(("Entry"));
+ memset(bandlist, 0, sizeof(bandlist));
+ err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
+ sizeof(bandlist), false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
}
- phy = phylist_buf;
- for (; *phy; phy++) {
- if (*phy == 'a' || *phy == 'n') {
- wiphy = wl_to_wiphy(wl);
+ wiphy = wl_to_wiphy(wl);
+ nband = bandlist[0];
+ wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+ wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ for (i = 1; i <= nband && i < sizeof(bandlist); i++) {
+ if (bandlist[i] == WLC_BAND_5G)
wiphy->bands[IEEE80211_BAND_5GHZ] =
&__wl_band_5ghz_a;
- }
+ else if (bandlist[i] == WLC_BAND_2G)
+ wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &__wl_band_2ghz;
}
+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
return err;
}
struct net_device *ndev = wl_to_prmry_ndev(wl);
struct wireless_dev *wdev = ndev->ieee80211_ptr;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
err = dhd_config_dongle(wl, false);
if (unlikely(err))
struct net_info *iter, *next;
struct net_device *ndev = wl_to_prmry_ndev(wl);
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
/* Check if cfg80211 interface is already down */
if (!wl_get_drv_status(wl, READY, ndev))
return err; /* it is even not ready */
struct wl_priv *wl;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
struct wl_priv *wl;
s32 err = 0;
- WL_TRACE(("In\n"));
+ WL_DBG(("In\n"));
wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
err = __wl_cfg80211_down(wl);