summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLin Ma <linm@broadcom.com>2011-07-18 11:42:36 -0700
committerDmitry Shmidt <dimitrysh@google.com>2011-07-21 17:13:52 -0700
commit2f66cb426e32ac6c731e4eda09aded204a800d64 (patch)
tree35cc7eeb8ec6f72697259048e85e6b21c25dce9d
parentb06f3b5edb8f9256f0435f13a439074291cd9055 (diff)
Update to 5.90.125.40
Add monitor interface support and fix cfg80211 management frame isses Add support for hostapd Use private command to get p2p device address Change-Id: Ie490e38f1af9f259ff4a96b2f7d367119c65c377 Signed-off-by: Howard M. Harte <hharte@broadcom.com> Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c68
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_mon.c331
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c119
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c19
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c1143
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h32
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c190
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h32
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c26
9 files changed, 1488 insertions, 472 deletions
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index e952ee1ccc2..ff9f9fa9c21 100644
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -91,6 +91,7 @@ static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
#if defined(SOFTAP)
extern bool ap_cfg_running;
+extern bool ap_fw_loaded;
#endif
/* enable HOSTIP cache update from the host side when an eth0:N is up */
@@ -442,6 +443,12 @@ static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
static void dhd_dump_htsfhisto(histo_t *his, char *s);
#endif /* WLMEDIA_HTSF */
+extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
+
+/* Monitor interface */
+extern int dhd_monitor_init(void *dhd_pub);
+extern int dhd_monitor_uninit(void);
+
#if defined(CONFIG_WIRELESS_EXT)
struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
@@ -491,6 +498,7 @@ extern int register_pm_notifier(struct notifier_block *nb);
extern int unregister_pm_notifier(struct notifier_block *nb);
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
/* && defined(DHD_GPL) */
+
static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
{
#ifdef PKT_FILTER_SUPPORT
@@ -972,7 +980,7 @@ dhd_op_if(dhd_if_t *ifp)
ret = -EOPNOTSUPP;
} else {
#if defined(SOFTAP)
- if (ap_cfg_running && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+ if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
/* semaphore that the soft AP CODE waits on */
flags = dhd_os_spin_lock(&dhd->pub);
@@ -992,6 +1000,9 @@ dhd_op_if(dhd_if_t *ifp)
case WLC_E_IF_DEL:
if (ifp->net != NULL) {
DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__));
+#ifdef WL_CFG80211
+ wl_cfg80211_ifdel_ops(ifp->net);
+#endif
netif_stop_queue(ifp->net);
unregister_netdev(ifp->net);
ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
@@ -1234,7 +1245,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
return ret;
}
-static int
+int
dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
{
int ret;
@@ -1462,7 +1473,6 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
}
}
-
ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state)
ifp = dhd->iflist[ifidx];
@@ -1473,6 +1483,14 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
dhdp->dstats.rx_bytes += skb->len;
dhdp->rx_packets++; /* Local count */
+ /* Dropping packets before registering net device to avoid kernel panic */
+ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) {
+ DHD_ERROR(("%s: net device is NOT registered yet. drop [%s] packet\n",
+ __FUNCTION__, (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) ? "event" : "data"));
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ continue;
+ }
+
if (in_interrupt()) {
netif_rx(skb);
} else {
@@ -2363,7 +2381,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
-
/* updates firmware nvram path if it was provided as module parameters */
if ((firmware_path != NULL) && (firmware_path[0] != '\0'))
strcpy(fw_path, firmware_path);
@@ -2469,6 +2486,8 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
DHD_ERROR(("wl_cfg80211_attach failed\n"));
goto fail;
}
+
+ dhd_monitor_init(&dhd->pub);
dhd_state |= DHD_ATTACH_STATE_CFG80211;
#endif
#if defined(CONFIG_WIRELESS_EXT)
@@ -2563,7 +2582,6 @@ fail:
dhd_free(&dhd->pub);
}
-
return NULL;
}
@@ -2665,7 +2683,11 @@ dhd_bus_start(dhd_pub_t *dhdp)
setbit(dhdp->eventmask, WLC_E_TXFAIL);
setbit(dhdp->eventmask, WLC_E_JOIN_START);
setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE);
-
+ setbit(dhdp->eventmask, WLC_E_ACTION_FRAME_RX);
+ setbit(dhdp->eventmask, WLC_E_ACTION_FRAME_COMPLETE);
+#if defined(WLP2P)
+ setbit(dhdp->eventmask, WLC_E_P2P_PROBREQ_MSG);
+#endif /* WLP2P */
#ifdef PNO_SUPPORT
setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND);
#endif /* PNO_SUPPORT */
@@ -2694,10 +2716,6 @@ dhd_bus_start(dhd_pub_t *dhdp)
dhd_write_macaddr(dhd->pub.mac.octet);
#endif
-#if defined(CONFIG_SYSCTL) && defined(WL_CFG80211)
- wl_cfg80211_sysctl_export_devaddr(&dhd->pub);
-#endif
-
return 0;
}
@@ -2724,6 +2742,7 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in
return ret;
}
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
static struct net_device_ops dhd_ops_pri = {
.ndo_open = dhd_open,
@@ -2848,6 +2867,8 @@ static int dhd_device_event(struct notifier_block *this,
__FUNCTION__));
aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
}
+ else
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
#endif
break;
@@ -2923,12 +2944,18 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
* We have to use the primary MAC for virtual interfaces
*/
memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
- if (ifidx == 1) {
- DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__));
- /* ACCESSPOINT INTERFACE CASE */
- temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */
+ /*
+ * Android sets the locally administered bit to indicate that this is a
+ * portable hotspot. This will not work in simultaneous AP/STA mode,
+ * nor with P2P. Need to set the Donlge's MAC address, and then use that.
+ */
+ if (ifidx > 0) {
+ DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
+ __func__, net->name));
+ temp_addr[0] |= 0x02;
}
}
+
net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
net->ethtool_ops = &dhd_ethtool_ops;
@@ -2951,11 +2978,11 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
DHD_ERROR(("couldn't register the net device, err %d\n", err));
goto fail;
}
-
- printf("%s: Driver up: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ printf("Broadcom Dongle Host Driver: register interface [%s]"
+ " MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
net->name,
- dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2],
- dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]);
+ 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)
wl_iw_iscan_set_scan_broadcast_prep(net, 1);
@@ -3106,8 +3133,10 @@ void dhd_detach(dhd_pub_t *dhdp)
}
#ifdef WL_CFG80211
- if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
wl_cfg80211_detach();
+ dhd_monitor_uninit();
+ }
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
@@ -3120,6 +3149,7 @@ void dhd_detach(dhd_pub_t *dhdp)
wake_lock_destroy(&dhd->wl_rxwake);
#endif
}
+
}
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
new file mode 100644
index 00000000000..a51db01a870
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
@@ -0,0 +1,331 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
+ *
+ * Copyright (C) 1999-2011, Broadcom Corporation
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2 (the "GPL"),
+ * available at http://www.broadcom.com/licenses/GPLv2.php, with the
+ * following added to such license:
+ *
+ * As a special exception, the copyright holders of this software give you
+ * permission to link this software with independent modules, and to copy and
+ * distribute the resulting executable under terms of your choice, provided that
+ * 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.
+ *
+ * $Id: dhd_linux_mon.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
+#include <net/ieee80211_radiotap.h>
+
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+/*
+ * Some external functions, TODO: move them to dhd_linux.h
+ */
+int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+
+/**
+ * Local declarations and defintions (not exposed)
+ */
+#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
+#define MON_TRACE MON_PRINT
+
+typedef struct monitor_interface {
+ int radiotap_enabled;
+ struct net_device* real_ndev; /* The real interface that the monitor is on */
+ struct net_device* mon_ndev;
+} monitor_interface;
+
+typedef struct dhd_linux_monitor {
+ void *dhd_pub;
+ monitor_interface mon_if[DHD_MAX_IFS];
+ int count; /* Number of total monitor interface */
+ struct mutex lock; /* lock to protect count and mon_if */
+} dhd_linux_monitor_t;
+
+static dhd_linux_monitor_t g_monitor;
+
+static struct net_device* lookup_real_netdev(char *name);
+static monitor_interface* ndev_to_monif(struct net_device *ndev);
+static int dhd_mon_if_open(struct net_device *ndev);
+static int dhd_mon_if_stop(struct net_device *ndev);
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
+
+static const struct net_device_ops dhd_mon_if_ops = {
+ .ndo_open = dhd_mon_if_open,
+ .ndo_stop = dhd_mon_if_stop,
+ .ndo_start_xmit = dhd_mon_if_subif_start_xmit,
+ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
+ .ndo_set_mac_address = dhd_mon_if_change_mac,
+};
+
+/**
+ * Local static function defintions
+ */
+
+/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
+ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
+ */
+static struct net_device* lookup_real_netdev(char *name)
+{
+ int i;
+ int last_name_len = 0;
+ struct net_device *ndev;
+ struct net_device *ndev_found = NULL;
+
+ /* We want to find interface "p2p-eth0-0" for monitor interface "mon.p2p-eth0-0", so
+ * we skip "eth0" even if "mon.p2p-eth0-0" contains "eth0"
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = dhd_idx2net(g_monitor.dhd_pub, i);
+ if (ndev && strstr(name, ndev->name)) {
+ if (strlen(ndev->name) > last_name_len)
+ ndev_found = ndev;
+ }
+ }
+
+ return ndev_found;
+}
+
+static monitor_interface* ndev_to_monif(struct net_device *ndev)
+{
+ int i;
+
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev)
+ return &g_monitor.mon_if[i];
+ }
+
+ return NULL;
+}
+
+static int dhd_mon_if_open(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_stop(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int ret = 0;
+ int rtap_len;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *rtap_hdr;
+ monitor_interface* mon_if;
+
+ MON_PRINT("enter\n");
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ goto fail;
+ }
+
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+ goto fail;
+
+ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+ if (unlikely(rtap_hdr->it_version))
+ goto fail;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (unlikely(skb->len < rtap_len))
+ goto fail;
+
+ MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
+
+ /* Skip the ratio tap header */
+ skb_pull(skb, rtap_len);
+
+ dot11_hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* Check if the QoS bit is set */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+
+ /* Check if this ia a Wireless Distribution System (WDS) frame
+ * which has 4 MAC addresses
+ */
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ * for two MAC addresses
+ */
+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char*)skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+
+ MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+
+ /* Use the real net device to transmit the packet */
+ ret = dhd_start_xmit(skb, mon_if->real_ndev);
+
+ return ret;
+
+fail:
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
+{
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ }
+
+ MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+}
+
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
+{
+ int ret = 0;
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ }
+
+ MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+ return ret;
+}
+
+/**
+ * Global function definitions (declared in dhd_linux_mon.h)
+ */
+
+int dhd_add_monitor(char *name, struct net_device **new_ndev)
+{
+ int idx;
+ int ret = 0;
+ struct net_device* ndev = NULL;
+ dhd_linux_monitor_t **dhd_mon;
+
+ mutex_lock(&g_monitor.lock);
+
+ MON_TRACE("enter, if name: %s\n", name);
+ if (!name || !new_ndev) {
+ MON_PRINT("invalid parameters\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (g_monitor.count >= DHD_MAX_IFS) {
+ MON_PRINT("exceeds maximum interfaces\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
+ if (!ndev) {
+ MON_PRINT("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(ndev->name, name, IFNAMSIZ);
+ ndev->name[IFNAMSIZ - 1] = 0;
+ ndev->netdev_ops = &dhd_mon_if_ops;
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ MON_PRINT(" register_netdevice failed (%d)\n", ret);
+ goto out;
+ }
+
+ *new_ndev = ndev;
+ idx = g_monitor.count;
+ g_monitor.mon_if[idx].radiotap_enabled = TRUE;
+ g_monitor.mon_if[idx].mon_ndev = ndev;
+ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
+ g_monitor.count++;
+ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
+ *dhd_mon = &g_monitor;
+
+ MON_PRINT("net device returned: 0x%p\n", ndev);
+ MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
+
+out:
+ if (ret && ndev)
+ free_netdev(ndev);
+
+ mutex_unlock(&g_monitor.lock);
+ return ret;
+
+}
+
+int dhd_monitor_init(void *dhd_pub)
+{
+ g_monitor.dhd_pub = dhd_pub;
+ mutex_init(&g_monitor.lock);
+ return 0;
+}
+
+int dhd_monitor_uninit(void)
+{
+ int i;
+ struct net_device *ndev;
+
+ mutex_lock(&g_monitor.lock);
+
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = g_monitor.mon_if[i].mon_ndev;
+ if (ndev) {
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ g_monitor.mon_if[i].real_ndev = NULL;
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ g_monitor.count--;
+ }
+ }
+
+ mutex_unlock(&g_monitor.lock);
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
index ce9d26b90cf..2dbb8027569 100644
--- a/drivers/net/wireless/bcmdhd/dhd_sdio.c
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -392,6 +392,11 @@ static bool dhd_readahead;
/* To check if there's window offered */
#define DATAOK(bus) \
+ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
+ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
+
+/* To check if there's window offered for ctrl frame*/
+#define TXCTLOK(bus) \
(((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
(((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
@@ -1364,7 +1369,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
- if (!DATAOK(bus)) {
+ if (!TXCTLOK(bus)) {
DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
__FUNCTION__, bus->tx_max, bus->tx_seq));
bus->ctrl_frame_stat = TRUE;
@@ -2602,46 +2607,44 @@ dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const ch
break;
#ifdef SOFTAP
- case IOV_GVAL(IOV_FWPATH):
- {
- uint32 fw_path_len;
-
- fw_path_len = strlen(bus->fw_path);
-
- DHD_INFO(("[softap] get fwpath, l=%d\n", len));
-
- if ( fw_path_len > len-1 ) {
- bcmerror = BCME_BUFTOOSHORT;
- break;
- }
-
- if ( fw_path_len )
- bcopy(bus->fw_path, arg, fw_path_len);
-
- ((uchar*)arg)[fw_path_len] = 0;
- }
- break;
-
- case IOV_SVAL(IOV_FWPATH):
- {
- DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
-
- switch(int_val) {
- case 1:
- bus->fw_path = fw_path; /* ordinary one */
- break;
- case 2:
- bus->fw_path = fw_path2;
- break;
- default:
- bcmerror = BCME_BADARG;
- return bcmerror;
- }
-
- DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0]?bus->fw_path:"NULL")));
- }
- break;
-#endif
+ case IOV_GVAL(IOV_FWPATH):
+ {
+ uint32 fw_path_len;
+
+ fw_path_len = strlen(bus->fw_path);
+ DHD_INFO(("[softap] get fwpath, l=%d\n", len));
+
+ if (fw_path_len > len-1) {
+ bcmerror = BCME_BUFTOOSHORT;
+ break;
+ }
+
+ if (fw_path_len) {
+ bcopy(bus->fw_path, arg, fw_path_len);
+ ((uchar*)arg)[fw_path_len] = 0;
+ }
+ break;
+ }
+
+ case IOV_SVAL(IOV_FWPATH):
+ DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
+
+ switch (int_val) {
+ case 1:
+ bus->fw_path = fw_path; /* ordinary one */
+ break;
+ case 2:
+ bus->fw_path = fw_path2;
+ break;
+ default:
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
+ break;
+
+#endif /* SOFTAP */
case IOV_GVAL(IOV_DEVRESET):
DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
@@ -4386,6 +4389,12 @@ dhdsdio_dpc(dhd_bus_t *bus)
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+ if (bus->dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
+ bus->intstatus = 0;
+ return 0;
+ }
+
/* Start with leftover status bits */
intstatus = bus->intstatus;
@@ -4544,7 +4553,7 @@ clkwait:
bcmsdh_intr_enable(sdh);
}
- if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
+ if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
int ret, i;
ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
@@ -4589,6 +4598,9 @@ clkwait:
framecnt = dhdsdio_sendfromq(bus, framecnt);
txlimit -= framecnt;
}
+ /* Resched the DPC if ctrl cmd is pending on bus credit*/
+ if (bus->ctrl_frame_stat)
+ resched = TRUE;
/* Resched if events or tx frames are pending, else await next interrupt */
/* On failed register access, all bets are off: no resched or interrupts */
@@ -5176,7 +5188,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
sd1idle = TRUE;
dhd_readahead = TRUE;
retrydata = FALSE;
- dhd_doflow = TRUE;
+ dhd_doflow = FALSE;
dhd_dongle_memsize = 0;
dhd_txminmax = DHD_TXMINMAX;
@@ -5291,15 +5303,20 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
goto fail;
}
- /* Register interrupt callback, but mask it (not operational yet). */
- DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
- bcmsdh_intr_disable(sdh);
- if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
- DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
- __FUNCTION__, ret));
- goto fail;
+ if (bus->intr) {
+ /* Register interrupt callback, but mask it (not operational yet). */
+ DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
+ bcmsdh_intr_disable(sdh);
+ if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
+ DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
+ __FUNCTION__, ret));
+ goto fail;
+ }
+ DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
+ } else {
+ DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
+ __FUNCTION__));
}
- DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
DHD_INFO(("%s: completed!!\n", __FUNCTION__));
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 432e2539ab0..fa6e305f45b 100644
--- a/drivers/net/wireless/bcmdhd/wl_android.c
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -65,6 +65,7 @@
#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
#define CMD_BTCOEXMODE "BTCOEXMODE"
#define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
+#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
#define CMD_SETFWPATH "SETFWPATH"
#define CMD_SETBAND "SETBAND"
#define CMD_GETBAND "GETBAND"
@@ -105,6 +106,7 @@ typedef struct android_wifi_priv_cmd {
void dhd_customer_gpio_wlan_ctrl(int onoff);
uint dhd_dev_reset(struct net_device *dev, uint8 flag);
void dhd_dev_init_ioctl(struct net_device *dev);
+int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
extern bool ap_fw_loaded;
#ifdef CUSTOMER_HW2
@@ -276,6 +278,18 @@ exit_proc:
}
#endif
+static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
+{
+ int ret;
+ int bytes_written = 0;
+
+ ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
+ if (ret)
+ return 0;
+ bytes_written = sizeof(struct ether_addr);
+ return bytes_written;
+}
+
/**
* Global function definitions (declared in wl_android.h)
*/
@@ -439,8 +453,8 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
char *country_code = command + strlen(CMD_COUNTRY) + 1;
bytes_written = wldev_set_country(net, country_code);
-#ifdef PNO_SUPPORT
}
+#ifdef PNO_SUPPORT
else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
bytes_written = dhd_dev_pno_reset(net);
}
@@ -450,7 +464,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
+ }
#endif
+ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
+ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd->total_len);
} else {
DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
snprintf(command, 3, "OK");
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 22b636d9caf..69180b56b42 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -29,6 +29,11 @@
#include <osl.h>
#include <linux/kernel.h>
+/*
+ * sys proc file will be REMOVED in next release
+ */
+#undef CONFIG_SYSCTL
+
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
@@ -189,6 +194,7 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *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, bool aborted);
/*
* event & event Q handlers for cfg80211 interfaces
*/
@@ -331,6 +337,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl);
static s32 __wl_cfg80211_down(struct wl_priv *wl);
static s32 wl_dongle_probecap(struct wl_priv *wl);
static void wl_init_conf(struct wl_conf *conf);
+static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
static s32 wl_dongle_eventmsg(struct net_device *ndev);
/*
@@ -353,6 +360,8 @@ static s32 wl_pattern_atoh(s8 *src, s8 *dst);
static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
static s32 wl_update_wiphybands(struct wl_priv *wl);
#endif /* !EMBEDDED_PLATFORM */
+static __used void wl_dongle_poweron(struct wl_priv *wl);
+static __used void wl_dongle_poweroff(struct wl_priv *wl);
static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
/*
@@ -404,6 +413,12 @@ static void wl_debugfs_remove_netdev(struct wl_priv *wl);
static int wl_setup_rfkill(struct wl_priv *wl);
static int wl_rfkill_set(void *data, bool blocked);
+/*
+ * Some external functions, TODO: move them to dhd_linux.h
+ */
+int dhd_add_monitor(char *name, struct net_device **new_ndev);
+int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+
#define WL_PRIV_GET() \
({ \
struct wl_iface *ci = NULL; \
@@ -418,13 +433,17 @@ static int wl_rfkill_set(void *data, bool blocked);
#define CHECK_SYS_UP() \
do { \
struct wl_priv *wl = WL_PRIV_GET(); \
- if (unlikely(!test_bit(WL_STATUS_READY, &wl->status))) { \
+ if (unlikely(!wl_get_drv_status(wl, READY))) { \
WL_INFO(("device is not ready : status (%d)\n", \
(int)wl->status)); \
return -EIO; \
} \
} while (0)
+#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
+ (akm) == RSN_AKM_UNSPECIFIED || \
+ (akm) == RSN_AKM_PSK)
+
extern int dhd_wait_pend8021x(struct net_device *dev);
#if (WL_DBG_LEVEL > 0)
@@ -773,6 +792,16 @@ wl_dbg_dump_wps_ie(char *wps_ie)
}
}
+static struct net_device* wl_cfg80211_add_monitor_if(char *name)
+{
+ int ret = 0;
+ struct net_device* ndev = NULL;
+
+ ret = dhd_add_monitor(name, &ndev);
+ WL_ERR(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
+ return ndev;
+}
+
static struct net_device *
wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
enum nl80211_iftype type, u32 *flags,
@@ -780,7 +809,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
{
s32 err;
s32 timeout = -1;
- s32 wlif_type;
+ s32 wlif_type = -1;
s32 index = 0;
s32 mode = 0;
chanspec_t chspec;
@@ -798,7 +827,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
mode = WL_MODE_IBSS;
return NULL;
case NL80211_IFTYPE_MONITOR:
- return wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
+ return wl_cfg80211_add_monitor_if(name);
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
wlif_type = WL_P2P_IF_CLIENT;
@@ -819,35 +848,37 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
WL_ERR(("name is NULL\n"));
return NULL;
}
+ if (wl->p2p_supported && (wlif_type != -1)) {
+ if (wl_get_p2p_status(wl, IF_DELETING) == 1) {
+ /* wait till IF_DEL is complete
+ * release the lock for the unregister to proceed
+ */
+ rtnl_unlock();
+ WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
+ __func__));
+ timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ (wl_get_p2p_status(wl, IF_DELETING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
- if (wl_get_p2p_status(wl, IF_DELETING) == 1) {
- /* wait till IF_DEL is complete
- * release the lock for the unregister to proceed
- */
- rtnl_unlock();
- WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n", __func__));
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl_get_p2p_status(wl, IF_DELETING) == FALSE),
- msecs_to_jiffies(MAX_WAIT_TIME));
-
- /* put back the rtnl_lock again */
- rtnl_lock();
- if (timeout > 0) {
- WL_ERR(("IF DEL is Success\n"));
+ /* put back the rtnl_lock again */
+ rtnl_lock();
+ if (timeout > 0) {
+ WL_ERR(("IF DEL is Success\n"));
- } else {
- WL_ERR(("%s: timeount < 0, return -EAGAIN\n", __func__));
- return ERR_PTR(-EAGAIN);
+ } else {
+ WL_ERR(("%s: timeount < 0, return -EAGAIN\n", __func__));
+ return ERR_PTR(-EAGAIN);
+ }
+ }
+ if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ p2p_on(wl) = true;
+ wl_cfgp2p_set_firm_p2p(wl);
+ wl_cfgp2p_init_discovery(wl);
}
- }
- if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
- p2p_on(wl) = true;
- wl_cfgp2p_init_discovery(wl);
- }
- memset(wl->p2p.vir_ifname, 0, IFNAMSIZ);
- strncpy(wl->p2p.vir_ifname, name, IFNAMSIZ - 1);
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr);
+ memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
+ strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
+ wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
/* Temporary use channel 11, in case GO will be changed with set_channel API */
chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
@@ -856,13 +887,13 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
* bss: "wl p2p_ifadd"
*/
wl_set_p2p_status(wl, IF_ADD);
- err = wl_cfgp2p_ifadd(wl, &wl->p2p.int_addr, htod32(wlif_type), chspec);
+ err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
if (unlikely(err))
return ERR_PTR(-ENOMEM);
timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl_get_p2p_status(wl, IF_ADD) == FALSE),
+ (wl_get_p2p_status(wl, IF_ADD) == false),
msecs_to_jiffies(MAX_WAIT_TIME));
if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
@@ -873,7 +904,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
return ERR_PTR(-ENOMEM);
}
vwdev->wiphy = wl->wdev->wiphy;
- WL_INFO((" virtual interface(%s) is created \n", wl->p2p.vir_ifname));
+ WL_INFO((" virtual interface(%s) is created \n", wl->p2p->vir_ifname));
index = alloc_idx_vwdev(wl);
wl->vwdev[index] = vwdev;
vwdev->iftype =
@@ -883,20 +914,19 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
_ndev->ieee80211_ptr = vwdev;
SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
vwdev->netdev = _ndev;
- set_bit(WL_STATUS_READY, &wl->status);
- wl->p2p.vif_created = TRUE;
+ wl_set_drv_status(wl, READY);
+ wl->p2p->vif_created = true;
set_mode_by_netdev(wl, _ndev, mode);
wl = wdev_to_wl(vwdev);
return _ndev;
} else {
wl_clr_p2p_status(wl, IF_ADD);
- WL_ERR((" virtual interface(%s) is not created timeout=%d\n",
- wl->p2p.vir_ifname, timeout));
- memset(wl->p2p.vir_ifname, '\0', IFNAMSIZ);
- wl->p2p.vif_created = FALSE;
+ WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname));
+ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
+ wl->p2p->vif_created = false;
+ }
}
-
return ERR_PTR(-ENODEV);
}
@@ -906,19 +936,31 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
{
struct ether_addr p2p_mac;
struct wl_priv *wl = WL_PRIV_GET();
- memcpy(p2p_mac.octet, wl->p2p.int_addr.octet, ETHER_ADDR_LEN);
- if (wl->p2p.vif_created) {
- if (test_bit(WL_STATUS_SCANNING, &wl->status)) {
- wl_cfg80211_scan_abort(wl, dev);
- }
- wl_cfgp2p_ifdel(wl, &p2p_mac);
- WL_ERR(("ifdel command sent to Firmware.. "
- "and we just come out without waiting.."));
- wl_set_p2p_status(wl, IF_DELETING);
+ s32 timeout = -1;
+
+ 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)) {
+ wl_cfg80211_scan_abort(wl, dev);
+ }
+ wl_cfgp2p_ifdel(wl, &p2p_mac);
+ wl_set_p2p_status(wl, IF_DELETING);
+
+ /* Wait for any pending scan req to get aborted from the sysioc context */
+ timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ (wl->scan_request == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+
+ if (timeout > 0 && (!wl->scan_request)) {
+ WL_DBG(("IFDEL Operations Done"));
+ } else {
+ WL_ERR(("IFDEL didn't complete properly"));
+ }
+ }
}
- WL_DBG(("Done\n"));
return 0;
}
@@ -935,7 +977,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
s32 mode = 0;
chanspec_t chspec;
struct wl_priv *wl = WL_PRIV_GET();
- CHECK_SYS_UP();
+ WL_DBG(("Enter \n"));
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_WDS:
@@ -963,21 +1005,36 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
}
- if (ap && wl->p2p.vif_created) {
- WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p.vif_created,
- p2p_on(wl)));
- chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
- wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
- WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type));
- wl_set_p2p_status(wl, IF_CHANGING);
- wl_clr_p2p_status(wl, IF_CHANGED);
- err = wl_cfgp2p_ifchange(wl, &wl->p2p.int_addr, htod32(wlif_type), chspec);
- timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
- (wl_get_p2p_status(wl, IF_CHANGED) == TRUE),
- msecs_to_jiffies(MAX_WAIT_TIME));
+ if (ap) {
set_mode_by_netdev(wl, ndev, mode);
- wl_clr_p2p_status(wl, IF_CHANGING);
- wl_clr_p2p_status(wl, IF_CHANGED);
+ if (wl->p2p_supported && wl->p2p->vif_created) {
+ WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
+ p2p_on(wl)));
+ chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
+ wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
+ WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
+ ndev->name, ap, infra, type));
+ wl_set_p2p_status(wl, IF_CHANGING);
+ wl_clr_p2p_status(wl, IF_CHANGED);
+ err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
+ timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
+ (wl_get_p2p_status(wl, IF_CHANGED) == true),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ set_mode_by_netdev(wl, ndev, mode);
+ wl_clr_p2p_status(wl, IF_CHANGING);
+ wl_clr_p2p_status(wl, IF_CHANGED);
+ } else if (ndev == wl_to_prmry_ndev(wl) &&
+ !wl_get_drv_status(wl, AP_CREATED)) {
+ wl_set_drv_status(wl, AP_CREATING);
+ if (!wl->ap_info &&
+ !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
+ WL_ERR(("struct ap_saved_ie allocation failed\n"));
+ return -ENOMEM;
+ }
+ } else {
+ WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
+ return -EINVAL;
+ }
}
ndev->ieee80211_ptr->iftype = type;
@@ -993,20 +1050,22 @@ wl_cfg80211_notify_ifadd(struct net_device *net)
WL_ERR(("net is NULL\n"));
return 0;
}
-
- WL_DBG(("IF_ADD event called from dongle, old interface name: %s, new name: %s\n",
- net->name, wl->p2p.vir_ifname));
- /* Assign the net device to CONNECT BSSCFG */
- strncpy(net->name, wl->p2p.vir_ifname, IFNAMSIZ - 1);
- wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net;
- wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = P2PAPI_BSSCFG_CONNECTION;
- wl_clr_p2p_status(wl, IF_ADD);
- wake_up_interruptible(&wl->dongle_event_wait);
+ if (wl->p2p_supported) {
+ WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
+ "new name: %s\n", net->name, wl->p2p->vir_ifname));
+ /* Assign the net device to CONNECT BSSCFG */
+ strncpy(net->name, wl->p2p->vir_ifname, IFNAMSIZ - 1);
+ wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = net;
+ wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) =
+ P2PAPI_BSSCFG_CONNECTION;
+ wl_clr_p2p_status(wl, IF_ADD);
+ wake_up_interruptible(&wl->dongle_event_wait);
+ }
return ret;
}
s32
-wl_cfg80211_notify_ifdel(struct net_device *net)
+wl_cfg80211_ifdel_ops(struct net_device *net)
{
struct wl_priv *wl = WL_PRIV_GET();
@@ -1015,15 +1074,39 @@ wl_cfg80211_notify_ifdel(struct net_device *net)
return 0;
}
- WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n",
- net->name, wl->p2p.vir_ifname));
- if (wl->p2p.vif_created) {
+ if ((wl->p2p->vif_created) && (wl->scan_request)) {
+
+ /* Abort any pending scan requests */
+ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ rtnl_lock();
+ WL_INFO(("ESCAN COMPLETED\n"));
+ wl_notify_escan_complete(wl, true);
+ rtnl_unlock();
+ }
+
+ /* Wake up any waiting thread */
+ wake_up_interruptible(&wl->dongle_event_wait);
+
+ return 0;
+}
+
+s32
+wl_cfg80211_notify_ifdel(struct net_device *net)
+{
+ struct wl_priv *wl = WL_PRIV_GET();
+
+
+ if (wl->p2p->vif_created) {
s32 index = 0;
- memset(wl->p2p.vir_ifname, '\0', IFNAMSIZ);
+
+ WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n",
+ net->name, wl->p2p->vir_ifname));
+
+ memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
index = wl_cfgp2p_find_idx(wl, net);
wl_to_p2p_bss_ndev(wl, index) = NULL;
wl_to_p2p_bss_bssidx(wl, index) = 0;
- wl->p2p.vif_created = FALSE;
+ wl->p2p->vif_created = false;
set_mode_by_netdev(wl, net, -1);
wl_cfgp2p_clear_management_ie(wl,
index);
@@ -1032,12 +1115,13 @@ wl_cfg80211_notify_ifdel(struct net_device *net)
if (index >= 0) {
free_vwdev_by_index(wl, index);
}
- /* Another option.. Make the IF_ADD wait, if the IF_DEL is not complete.. */
+ }
+
wl_clr_p2p_status(wl, IF_DELETING);
- WL_ERR(("Cleared IF_DELETING status bit\n"));
+
+ /* Wake up any waiting thread */
wake_up_interruptible(&wl->dongle_event_wait);
- WL_ERR(("Cleared IF_DELETING status bit DONE WAKEUP Interruptible\n"));
- }
+
return 0;
}
@@ -1144,7 +1228,7 @@ static s32 wl_do_iscan(struct wl_priv *wl)
passive_scan = wl->active_scan ? 0 : 1;
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
- &passive_scan, sizeof(passive_scan), FALSE);
+ &passive_scan, sizeof(passive_scan), false);
if (unlikely(err)) {
WL_DBG(("error (%d)\n", err));
return err;
@@ -1171,8 +1255,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint
WL_DBG(("Enter \n"));
- if ((ndev == wl_to_prmry_ndev(wl)) &&
- !p2p_scan(wl)) {
+ if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) &&
+ !p2p_scan(wl))) {
/* LEGACY SCAN TRIGGER */
WL_DBG(("LEGACY SCAN START\n"));
if (ssid && ssid->SSID_len) {
@@ -1255,7 +1339,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wl
wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
passive_scan = wl->active_scan ? 0 : 1;
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
- &passive_scan, sizeof(passive_scan), FALSE);
+ &passive_scan, sizeof(passive_scan), false);
if (unlikely(err)) {
WL_DBG(("error (%d)\n", err));
return err;
@@ -1284,11 +1368,11 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
bool spec_scan;
s32 err = 0;
- if (unlikely(test_bit(WL_STATUS_SCANNING, &wl->status))) {
+ if (unlikely(wl_get_drv_status(wl, SCANNING))) {
WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
return -EAGAIN;
}
- if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &wl->status))) {
+ if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) {
WL_ERR(("Scanning being aborted : status (%d)\n",
(int)wl->status));
return -EAGAIN;
@@ -1305,33 +1389,37 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
} else if (wl->escan_on) {
escan_req = true;
if (ssids->ssid_len && IS_P2P_SSID(ssids->ssid)) {
- /* p2p scan trigger */
- if (p2p_on(wl) == false) {
- /* p2p on at the first time */
- p2p_on(wl) = true;
- wl_cfgp2p_set_firm_p2p(wl);
+ if (wl->p2p_supported) {
+ /* p2p scan trigger */
+ if (p2p_on(wl) == false) {
+ /* p2p on at the first time */
+ p2p_on(wl) = true;
+ wl_cfgp2p_set_firm_p2p(wl);
+ }
+ p2p_scan(wl) = true;
}
- p2p_scan(wl) = true;
-
} else {
/* legacy scan trigger
* So, we have to disable p2p discovery if p2p discovery is on
*/
- p2p_scan(wl) = false;
- /* If Netdevice is not equals to primary and p2p is on
- * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
- */
- if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl)))
- p2p_scan(wl) = true;
+ if (wl->p2p_supported) {
+ p2p_scan(wl) = false;
+ /* If Netdevice is not equals to primary and p2p is on
+ * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
+ */
+ if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl)))
+ p2p_scan(wl) = true;
+
+ if (p2p_scan(wl) == false) {
+ if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
+ err = wl_cfgp2p_discover_enable_search(wl,
+ false);
+ if (unlikely(err)) {
+ goto scan_out;
+ }
- if (p2p_scan(wl) == false) {
- if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
- err = wl_cfgp2p_discover_enable_search(wl, FALSE);
- if (unlikely(err)) {
- goto scan_out;
}
-
}
}
}
@@ -1341,7 +1429,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
ssids = this_ssid;
}
wl->scan_request = request;
- set_bit(WL_STATUS_SCANNING, &wl->status);
+ wl_set_drv_status(wl, SCANNING);
if (iscan_req) {
err = wl_do_iscan(wl);
if (likely(!err))
@@ -1354,13 +1442,15 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
memcpy(ssid_info.SSID, ssids->ssid, ssids->ssid_len);
ssid_info.SSID_len = ssids->ssid_len;
+ if (wl->p2p_supported) {
+ if (p2p_on(wl) && p2p_scan(wl)) {
- if (p2p_on(wl) && p2p_scan(wl)) {
-
- err = wl_cfgp2p_enable_discovery(wl, ndev, request->ie, request->ie_len);
+ err = wl_cfgp2p_enable_discovery(wl, ndev,
+ request->ie, request->ie_len);
- if (unlikely(err)) {
- goto scan_out;
+ if (unlikely(err)) {
+ goto scan_out;
+ }
}
}
err = wl_do_escan(wl, wiphy, ndev, &ssid_info);
@@ -1386,13 +1476,13 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
passive_scan = wl->active_scan ? 0 : 1;
err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
- &passive_scan, sizeof(passive_scan), FALSE);
+ &passive_scan, sizeof(passive_scan), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
goto scan_out;
}
err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid,
- sizeof(sr->ssid), FALSE);
+ sizeof(sr->ssid), false);
if (err) {
if (err == -EBUSY) {
WL_INFO(("system busy : scan for \"%s\" "
@@ -1407,7 +1497,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
return 0;
scan_out:
- clear_bit(WL_STATUS_SCANNING, &wl->status);
+ wl_clr_drv_status(wl, SCANNING);
wl->scan_request = NULL;
return err;
}
@@ -1439,7 +1529,7 @@ static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
BUG_ON(unlikely(!len));
- err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, FALSE);
+ err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
}
@@ -1461,7 +1551,7 @@ wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
len = bcm_mkiovar(name, (char *)(&data_null), 0,
(char *)(&var), sizeof(var.buf));
BUG_ON(unlikely(!len));
- err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, FALSE);
+ err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
}
@@ -1500,7 +1590,7 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
retry = htod32(retry);
- err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), FALSE);
+ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), false);
if (unlikely(err)) {
WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
return err;
@@ -1612,7 +1702,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
- sizeof(join_params), FALSE);
+ sizeof(join_params), false);
if (unlikely(err)) {
WL_ERR(("Error (%d)\n", err));
return err;
@@ -1985,12 +2075,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
join_params.ssid.SSID_len));
}
- err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, FALSE);
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
}
- set_bit(WL_STATUS_CONNECTING, &wl->status);
+ wl_set_drv_status(wl, CONNECTING);
return err;
}
@@ -2012,7 +2102,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
memcpy(&scbval.ea, &wl->bssid, ETHER_ADDR_LEN);
scbval.val = htod32(scbval.val);
err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
- sizeof(scb_val_t), FALSE);
+ sizeof(scb_val_t), false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -2053,7 +2143,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
/* Make sure radio is off or on as far as software is concerned */
disable = WL_RADIO_SW_DISABLE << 16;
disable = htod32(disable);
- err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
return err;
@@ -2116,7 +2206,7 @@ wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
index = (u32) key_idx;
index = htod32(index);
err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
- sizeof(index), FALSE);
+ sizeof(index), false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
}
@@ -2132,7 +2222,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
struct wl_wsec_key key;
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
-
+ s32 mode = get_mode_by_netdev(wl, dev);
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -2155,11 +2245,11 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("Invalid key length (%d)\n", key.len));
return -EINVAL;
}
-
WL_DBG(("Setting the key index %d\n", key.index));
memcpy(key.data, params->key, key.len);
- if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
+ if ((mode == WL_MODE_BSS) &&
+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
u8 keybuf[8];
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
@@ -2225,10 +2315,10 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
s32 val = 0;
s32 wsec = 0;
s32 err = 0;
- uint8 keybuf[8];
+ u8 keybuf[8];
s32 bssidx = 0;
struct wl_priv *wl = WL_PRIV_GET();
-
+ s32 mode = get_mode_by_netdev(wl, dev);
WL_DBG(("key index (%d)\n", key_idx));
CHECK_SYS_UP();
@@ -2264,10 +2354,12 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
case WLAN_CIPHER_SUITE_TKIP:
key.algo = CRYPTO_ALGO_TKIP;
val = TKIP_ENABLED;
- /* wpa_supplicant switches the third and fourth quarters of the TKIP key, linm */
- bcopy(&key.data[24], keybuf, sizeof(keybuf));
- bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
- bcopy(keybuf, &key.data[16], sizeof(keybuf));
+ /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
+ if (mode == WL_MODE_BSS) {
+ bcopy(&key.data[24], keybuf, sizeof(keybuf));
+ bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
+ bcopy(keybuf, &key.data[16], sizeof(keybuf));
+ }
WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
@@ -2312,7 +2404,7 @@ exit:
/* TODO: Removed in P2P, check later --lm */
val = 1; /* assume shared key. otherwise 0 */
val = htod32(val);
- err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), FALSE);
+ err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
return err;
@@ -2359,7 +2451,7 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
/* TODO: Removed in P2P twig, check later --lin */
val = 0; /* assume open key. otherwise 1 */
val = htod32(val);
- err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), FALSE);
+ err = wldev_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_AUTH error (%d)\n", err));
return err;
@@ -2395,28 +2487,28 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
return err;
}
- switch (wsec) {
- case WEP_ENABLED:
- sec = wl_read_prof(wl, WL_PROF_SEC);
- if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
- params.cipher = WLAN_CIPHER_SUITE_WEP40;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
- } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
- params.cipher = WLAN_CIPHER_SUITE_WEP104;
- WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
- }
- break;
- case TKIP_ENABLED:
- params.cipher = WLAN_CIPHER_SUITE_TKIP;
- WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
- break;
- case AES_ENABLED:
- params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
- WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
- break;
- default:
- WL_ERR(("Invalid algo (0x%x)\n", wsec));
- return -EINVAL;
+ switch (wsec & ~SES_OW_ENABLED) {
+ case WEP_ENABLED:
+ sec = wl_read_prof(wl, WL_PROF_SEC);
+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ }
+ break;
+ case TKIP_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case AES_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ default:
+ WL_ERR(("Invalid algo (0x%x)\n", wsec));
+ return -EINVAL;
}
callback(cookie, &params);
@@ -2450,7 +2542,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
}
/* Report the current tx rate */
- err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), FALSE);
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
if (err) {
WL_ERR(("Could not get rate (%d)\n", err));
} else {
@@ -2460,11 +2552,11 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
WL_DBG(("Rate %d Mbps\n", (rate / 2)));
}
- if (test_bit(WL_STATUS_CONNECTED, &wl->status)) {
+ if (wl_get_drv_status(wl, CONNECTED)) {
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);
+ sizeof(scb_val_t), false);
if (unlikely(err)) {
WL_ERR(("Could not get rssi (%d)\n", err));
return err;
@@ -2476,7 +2568,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
}
#if defined(ANDROID_WIRELESS_PATCH)
- err = wldev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed), FALSE);
+ err = wldev_ioctl(dev, WLC_GET_RATE, &sinfo->link_speed, sizeof(sinfo->link_speed), false);
sinfo->link_speed = sinfo->link_speed / 2; /* Convert internal 500Kbps to Mpbs */
if (!err)
sinfo->filled |= STATION_LINK_SPEED;
@@ -2498,7 +2590,7 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
pm = enabled ? PM_FAST : PM_OFF;
pm = htod32(pm);
WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
- err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE);
+ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), false);
if (unlikely(err)) {
if (err == -ENODEV)
WL_DBG(("net_device is not ready yet\n"));
@@ -2553,7 +2645,7 @@ wl_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
/* addr param is always NULL. ignore it */
/* Get current rateset */
err = wldev_ioctl(dev, WLC_GET_CURR_RATESET, &rateset,
- sizeof(rateset), FALSE);
+ sizeof(rateset), false);
if (unlikely(err)) {
WL_ERR(("could not get current rateset (%d)\n", err));
return err;
@@ -2623,14 +2715,14 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
return 0;
}
- set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ wl_set_drv_status(wl, SCAN_ABORTING);
wl_term_iscan(wl);
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
wl->scan_request = NULL;
}
- clear_bit(WL_STATUS_SCANNING, &wl->status);
- clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ wl_clr_drv_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCAN_ABORTING);
return err;
}
@@ -2640,6 +2732,18 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
s32 err)
{
int i, j;
+ struct wl_priv *wl = WL_PRIV_GET();
+ struct net_device *primary_dev = wl_to_prmry_ndev(wl);
+
+ /* Firmware is supporting pmk list only for STA interface i.e. primary interface
+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+ * Do we really need to support PMK cache in P2P in firmware?
+ */
+ if (primary_dev != dev) {
+ WL_ERR(("Not supporting Flushing pmklist on virtual"
+ " interfaces than primary interface\n"));
+ return err;
+ }
WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
@@ -2745,7 +2849,6 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
{
struct wl_priv *wl = WL_PRIV_GET();
s32 err = 0;
-
CHECK_SYS_UP();
memset(wl->pmk_list, 0, sizeof(*wl->pmk_list));
err = wl_update_pmklist(dev, wl->pmk_list, err);
@@ -2806,20 +2909,11 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
err = -ENOMEM;
}
/* Do a scan abort to stop the driver's scan engine */
- err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, FALSE);
+ err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, false);
if (err < 0) {
WL_ERR(("scan abort failed \n"));
}
- /* Report the scan abort to CFG driver too
- * We will report it from the thread context, not from this context.
- */
- {
- wl_event_msg_t msg;
- msg.event_type = hton32(WLC_E_ESCAN_RESULT);
- msg.status = WLC_E_STATUS_ABORT;
- wl_cfg80211_event(ndev, &msg, NULL);
- }
return err;
}
static s32
@@ -2834,7 +2928,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
struct wl_priv *wl = WL_PRIV_GET();
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
- if (likely(test_bit(WL_STATUS_SCANNING, &wl->status))) {
+ if (likely(wl_get_drv_status(wl, SCANNING))) {
wl_cfg80211_scan_abort(wl, dev);
}
@@ -2845,7 +2939,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
cfg80211_ready_on_channel(dev, *cookie, channel,
channel_type, duration, GFP_KERNEL);
if (!p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr);
+ wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
/* In case of p2p_listen command, supplicant send remain_on_channel
* without turning on P2P
@@ -2867,13 +2961,11 @@ exit:
}
static s32
-wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, u64 cookie)
+wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
+ u64 cookie)
{
-
s32 err = 0;
WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex));
-
-
return err;
}
@@ -2896,7 +2988,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
u32 p2pie_len = 0;
u32 wpsie_len = 0;
u16 fc;
- bool ack = FALSE;
+ bool ack = false;
WL_DBG(("Enter \n"));
/* find bssidx based on ndev */
bssidx = wl_cfgp2p_find_idx(wl, dev);
@@ -2909,24 +3001,20 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
return -ENODEV;
}
if (p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr);
-
+ wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
/* Suspend P2P discovery search-listen to prevent it from changing the
* channel.
*/
- wl_cfgp2p_discover_enable_search(wl, FALSE);
- /* Abort the dwell time of any previous off-channel action frame that may
- * be still in effect. Sending off-channel action frames relies on the
- * driver's scan engine. If a previous off-channel action frame 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);
+ if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ return -EFAULT;
+ }
}
+
mgmt = (const struct ieee80211_mgmt *) buf;
fc = mgmt->frame_control;
if (fc != IEEE80211_STYPE_ACTION) {
- if (p2p_on(wl) && (fc == IEEE80211_STYPE_PROBE_RESP)) {
+ if (fc == IEEE80211_STYPE_PROBE_RESP) {
s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
s32 ie_len = len - ie_offset;
if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
@@ -2953,12 +3041,23 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
wl_cfgp2p_set_managment_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
(u8 *)wps_ie, wpsie_len + p2pie_len);
-
+ /* remove WLC_E_PROBREQ_MSG event to prevent HOSTAPD
+ * from responding many probe request
+ */
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
}
}
cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
goto exit;
+ } else {
+ /* Abort the dwell time of any previous off-channel action frame that may
+ * be still in effect. Sending off-channel action frames relies on the
+ * driver's scan engine. If a previous off-channel action frame 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);
}
af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
@@ -2993,7 +3092,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
- if (wl->p2p.vif_created) {
+ if (wl->p2p->vif_created) {
wifi_p2p_pub_act_frame_t *act_frm =
(wifi_p2p_pub_act_frame_t *) (action_frame->data);
/*
@@ -3017,7 +3116,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
}
}
- ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? FALSE : TRUE;
+ ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL);
kfree(af_params);
@@ -3077,28 +3176,31 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
channel = ieee80211_frequency_to_channel(chan->center_freq);
WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
dev->ifindex, channel_type, channel));
- wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), FALSE);
+ wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), false);
return err;
}
static s32
-wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
+wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
{
- s32 len = wpa2ie->len;
+ s32 len = 0;
s32 err = BCME_OK;
u16 auth = 0; /* d11 open authentication */
- u16 wpa_auth = 0;
u16 count;
u32 wsec;
u32 pval = 0;
u32 gval = 0;
+ u32 wpa_auth = 0;
u8* tmp;
wpa_suite_mcast_t *mcast;
wpa_suite_ucast_t *ucast;
wpa_suite_auth_key_mgmt_t *mgmt;
if (wpa2ie == NULL)
goto exit;
+
+ WL_DBG(("Enter \n"));
+ len = wpa2ie->len;
/* check the mcast cipher */
mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
tmp = mcast->oui;
@@ -3141,7 +3243,6 @@ wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
break;
default:
WL_ERR(("No Security Info\n"));
- break;
}
/* FOR WPS , set SEC_OW_ENABLED */
wsec = (pval | gval | SES_OW_ENABLED);
@@ -3161,33 +3262,171 @@ wl_check_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
break;
default:
WL_ERR(("No Key Mgmt Info\n"));
- break;
}
/* set auth */
err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
if (err < 0) {
WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
}
/* set wsec */
err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
if (err < 0) {
WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
}
/* set upper-layer auth */
err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
if (err < 0) {
WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
}
exit:
return 0;
}
static s32
-wl_check_wpaie(struct net_device *dev, bcm_tlv_t *wpaie, s32 bssidx)
+wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
{
+ wpa_suite_mcast_t *mcast;
+ wpa_suite_ucast_t *ucast;
+ wpa_suite_auth_key_mgmt_t *mgmt;
+ u16 auth = 0; /* d11 open authentication */
+ u16 count;
+ s32 err = BCME_OK;
+ s32 len = 0;
+ u32 i;
+ u32 wsec;
+ u32 pval = 0;
+ u32 gval = 0;
+ u32 wpa_auth = 0;
+ u32 tmp = 0;
+
if (wpaie == NULL)
goto exit;
+ WL_DBG(("Enter \n"));
+ len = wpaie->length; /* value length */
+ len -= WPA_IE_TAG_FIXED_LEN;
+ /* check for multicast cipher suite */
+ if (len < WPA_SUITE_LEN) {
+ WL_INFO(("no multicast cipher suite\n"));
+ goto exit;
+ }
+ /* pick up multicast cipher */
+ mcast = (wpa_suite_mcast_t *)&wpaie[1];
+ len -= WPA_SUITE_LEN;
+ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_CIPHER(mcast->type)) {
+ tmp = 0;
+ switch (mcast->type) {
+ case WPA_CIPHER_NONE:
+ tmp = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ tmp = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ tmp = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ tmp = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ gval |= tmp;
+ }
+ }
+ /* Check for unicast suite(s) */
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
+ WL_INFO(("no unicast suite\n"));
+ goto exit;
+ }
+ /* walk thru unicast cipher list and pick up what we recognize */
+ ucast = (wpa_suite_ucast_t *)&mcast[1];
+ count = ltoh16_ua(&ucast->count);
+ len -= WPA_IE_SUITE_COUNT_LEN;
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
+ i++, len -= WPA_SUITE_LEN) {
+ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_CIPHER(ucast->list[i].type)) {
+ tmp = 0;
+ switch (ucast->list[i].type) {
+ case WPA_CIPHER_NONE:
+ tmp = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ tmp = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ tmp = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ tmp = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ pval |= tmp;
+ }
+ }
+ }
+ len -= (count - i) * WPA_SUITE_LEN;
+ /* Check for auth key management suite(s) */
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
+ WL_INFO((" no auth key mgmt suite\n"));
+ goto exit;
+ }
+ /* walk thru auth management suite list and pick up what we recognize */
+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
+ count = ltoh16_ua(&mgmt->count);
+ len -= WPA_IE_SUITE_COUNT_LEN;
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
+ i++, len -= WPA_SUITE_LEN) {
+ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_AKM(mgmt->list[i].type)) {
+ tmp = 0;
+ switch (mgmt->list[i].type) {
+ case RSN_AKM_NONE:
+ tmp = WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ tmp = WPA_AUTH_UNSPECIFIED;
+ break;
+ case RSN_AKM_PSK:
+ tmp = WPA_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("No Key Mgmt Info\n"));
+ }
+ wpa_auth |= tmp;
+ }
+ }
+
+ }
+ /* FOR WPS , set SEC_OW_ENABLED */
+ wsec = (pval | gval | SES_OW_ENABLED);
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
exit:
return 0;
}
@@ -3198,27 +3437,29 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
{
s32 err = BCME_OK;
bcm_tlv_t *ssid_ie;
+ wlc_ssid_t ssid;
+ struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_join_params join_params;
wpa_ie_fixed_t *wps_ie;
wpa_ie_fixed_t *wpa_ie;
bcm_tlv_t *wpa2_ie;
wifi_p2p_ie_t *p2p_ie;
- struct wl_priv *wl = WL_PRIV_GET();
bool is_bssup = false;
+ bool update_bss = false;
u16 wpsie_len = 0;
u16 p2pie_len = 0;
u8 beacon_ie[IE_MAX_LEN];
s32 ie_offset = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
s32 infra = 1;
-
- memset(beacon_ie, 0, sizeof(beacon_ie));
-
+ s32 join_params_size = 0;
+ s32 ap = 0;
WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
info->interval, info->dtim_period, info->head_len, info->tail_len));
-
-
- if (p2p_on(wl) && (bssidx >= wl_to_p2p_bss_bssidx(wl,
+ if (wl->p2p_supported && p2p_on(wl) &&
+ (bssidx >= wl_to_p2p_bss_bssidx(wl,
P2PAPI_BSSCFG_CONNECTION))) {
+ memset(beacon_ie, 0, sizeof(beacon_ie));
/* We don't need to set beacon for P2P_GO,
* but need to parse ssid from beacon_parameters
* because there is no way to set ssid
@@ -3228,8 +3469,8 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
info->head_len - ie_offset,
DOT11_MNG_SSID_ID)) != NULL) {
- memcpy(wl->p2p.ssid.SSID, ssid_ie->data, ssid_ie->len);
- wl->p2p.ssid.SSID_len = ssid_ie->len;
+ memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len);
+ wl->p2p->ssid.SSID_len = ssid_ie->len;
WL_DBG(("SSID (%s) in Head \n", ssid_ie->data));
} else {
@@ -3238,7 +3479,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
/* find the WPSIE */
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
- wpsie_len = wps_ie->length + sizeof(wps_ie->tag) + sizeof(wps_ie->length);
+ wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
/*
* Should be compared with saved ie before saving it
*/
@@ -3269,10 +3510,7 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
beacon_ie, wpsie_len + p2pie_len);
wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_ASSOCRSP_FLAG,
beacon_ie, wpsie_len + p2pie_len);
- /* find the WPA_IE */
- if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail, info->tail_len)) != NULL) {
- WL_DBG((" WPA IE is found\n"));
- }
+
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
DOT11_MNG_RSN_ID)) != NULL) {
@@ -3280,19 +3518,209 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
}
is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
- if (!is_bssup && (wpa_ie != NULL || wpa2_ie != NULL)) {
- wl_check_wpa2ie(dev, wpa2_ie, bssidx);
- wl_check_wpaie(dev, (bcm_tlv_t *)wpa_ie, bssidx);
-
- err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), FALSE);
+ if (!is_bssup && (wpa2_ie != NULL)) {
+ if ((err = wl_validate_wpa2ie(dev, wpa2_ie, bssidx)) < 0) {
+ WL_ERR(("WPA2 IE parsing error"));
+ return BCME_ERROR;
+ }
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false);
if (err < 0) {
WL_ERR(("SET INFRA error %d\n", err));
+ return err;
}
-
- err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p.ssid,
- sizeof(wl->p2p.ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
-
- wl_cfgp2p_bss(dev, bssidx, 1);
+ err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
+ sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
+ if (err < 0) {
+ WL_ERR(("GO SSID setting error %d\n", err));
+ return err;
+ }
+ if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
+ WL_ERR(("GO Bring up error %d\n", err));
+ return err;
+ }
+ }
+ } else if (wl_get_drv_status(wl, AP_CREATING)) {
+ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
+ ap = 1;
+ /* find the SSID */
+ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
+ info->head_len - ie_offset,
+ DOT11_MNG_SSID_ID)) != NULL) {
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ memcpy(ssid.SSID, ssid_ie->data, ssid_ie->len);
+ WL_DBG(("SSID is (%s) in Head \n", ssid.SSID));
+ ssid.SSID_len = ssid_ie->len;
+ wldev_iovar_setint(dev, "mpc", 0);
+ wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), false);
+ wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), false);
+ wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), false);
+ /* find the RSN_IE */
+ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
+ DOT11_MNG_RSN_ID)) != NULL) {
+ WL_DBG((" WPA2 IE is found\n"));
+ }
+ /* find the WPA_IE */
+ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail,
+ info->tail_len)) != NULL) {
+ WL_DBG((" WPA IE is found\n"));
+ }
+ if ((wpa_ie != NULL || wpa2_ie != NULL)) {
+ if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
+ wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
+ wl->ap_info->security_mode = false;
+ return BCME_ERROR;
+ }
+ wl->ap_info->security_mode = true;
+ kfree(wl->ap_info->rsn_ie);
+ kfree(wl->ap_info->wpa_ie);
+ kfree(wl->ap_info->wps_ie);
+ if (wpa_ie != NULL) {
+ /* WPAIE */
+ wl->ap_info->rsn_ie = NULL;
+ wl->ap_info->wpa_ie = kmemdup(wpa_ie,
+ wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else {
+ /* RSNIE */
+ wl->ap_info->wpa_ie = NULL;
+ wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
+ wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ }
+ } else
+ wl->ap_info->security_mode = false;
+ /* find the WPSIE */
+ if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail,
+ info->tail_len)) != NULL) {
+ wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
+ /*
+ * Should be compared with saved ie before saving it
+ */
+ if (wl_dbg_level & WL_DBG_INFO)
+ wl_dbg_dump_wps_ie((char *) wps_ie);
+ memcpy(beacon_ie, wps_ie, wpsie_len);
+ wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
+ beacon_ie, wpsie_len);
+ 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_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ } else {
+ WL_ERR(("No WPSIE in beacon \n"));
+ }
+ wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), false);
+
+ memset(&join_params, 0, sizeof(join_params));
+ /* join parameters starts with ssid */
+ join_params_size = sizeof(join_params.ssid);
+ memcpy(join_params.ssid.SSID, ssid.SSID, ssid.SSID_len);
+ join_params.ssid.SSID_len = htod32(ssid.SSID_len);
+ /* create softap */
+ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
+ join_params_size, false)) == 0) {
+ wl_clr_drv_status(wl, AP_CREATING);
+ wl_set_drv_status(wl, AP_CREATED);
+ }
+ }
+ } else if (wl_get_drv_status(wl, AP_CREATED)) {
+ ap = 1;
+ /* find the WPSIE */
+ if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
+ wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
+ /*
+ * Should be compared with saved ie before saving it
+ */
+ if (wl_dbg_level & WL_DBG_INFO)
+ wl_dbg_dump_wps_ie((char *) wps_ie);
+ memcpy(beacon_ie, wps_ie, wpsie_len);
+ wl_cfgp2p_set_managment_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
+ beacon_ie, wpsie_len);
+ if (wl->ap_info->wps_ie &&
+ 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);
+ /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ } 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);
+ /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
+ wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ }
+ /* find the RSN_IE */
+ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
+ DOT11_MNG_RSN_ID)) != NULL) {
+ WL_DBG((" WPA2 IE is found\n"));
+ }
+ /* find the WPA_IE */
+ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail,
+ info->tail_len)) != NULL) {
+ WL_DBG((" WPA IE is found\n"));
+ }
+ if ((wpa_ie != NULL || wpa2_ie != NULL)) {
+ if (!wl->ap_info->security_mode) {
+ /* change from open mode to security mode */
+ update_bss = true;
+ if (wpa_ie != NULL) {
+ wl->ap_info->wpa_ie = kmemdup(wpa_ie,
+ wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else {
+ wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
+ wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ }
+ } else if (wl->ap_info->wpa_ie) {
+ /* change from WPA mode to WPA2 mode */
+ if (wpa2_ie != NULL) {
+ update_bss = true;
+ kfree(wl->ap_info->wpa_ie);
+ wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
+ wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ wl->ap_info->wpa_ie = NULL;
+ }
+ else if (memcmp(wl->ap_info->wpa_ie,
+ wpa_ie, wpa_ie->length +
+ WPA_RSN_IE_TAG_FIXED_LEN)) {
+ kfree(wl->ap_info->wpa_ie);
+ update_bss = true;
+ wl->ap_info->wpa_ie = kmemdup(wpa_ie,
+ wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ wl->ap_info->rsn_ie = NULL;
+ }
+ } else {
+ /* change from WPA2 mode to WPA mode */
+ if (wpa_ie != NULL) {
+ update_bss = true;
+ kfree(wl->ap_info->rsn_ie);
+ wl->ap_info->rsn_ie = NULL;
+ wl->ap_info->wpa_ie = kmemdup(wpa_ie,
+ wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else if (memcmp(wl->ap_info->rsn_ie,
+ wpa2_ie, wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
+ update_bss = true;
+ kfree(wl->ap_info->rsn_ie);
+ wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
+ wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ wl->ap_info->wpa_ie = NULL;
+ }
+ }
+ if (update_bss) {
+ wl->ap_info->security_mode = true;
+ wl_cfgp2p_bss(dev, bssidx, 0);
+ if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
+ wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
+ return BCME_ERROR;
+ }
+ wl_cfgp2p_bss(dev, bssidx, 1);
+ }
+ }
+ } else {
+ WL_ERR(("No WPSIE in beacon \n"));
}
}
return 0;
@@ -3400,7 +3828,8 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
wdev->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
+ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
+ | 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;
@@ -3455,6 +3884,7 @@ static void wl_free_wdev(struct wl_priv *wl)
wiphy_unregister(wdev->wiphy);
wiphy_free(wdev->wiphy);
kfree(wdev);
+ wl_to_wdev(wl) = NULL;
}
static s32 wl_inform_bss(struct wl_priv *wl)
@@ -3465,13 +3895,11 @@ static s32 wl_inform_bss(struct wl_priv *wl)
s32 i;
bss_list = wl->bss_list;
- /*
if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) {
- WL_ERR(("Version %d != %d\n",
- bss_list->version, WL_BSS_INFO_VERSION));
+ WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n",
+ bss_list->version));
return -EOPNOTSUPP;
}
- */
WL_DBG(("scanned AP count (%d)\n", bss_list->count));
bi = next_bss(bss_list, bi);
for_each_bss(bss_list, bi, i) {
@@ -3618,7 +4046,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
bool act;
- bool isfree = FALSE;
+ bool isfree = false;
s32 err = 0;
s32 freq;
s32 channel;
@@ -3642,7 +4070,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
memcpy(body, data, len);
wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
&da, sizeof(struct ether_addr), ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
- wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE);
+ wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
switch (event) {
case WLC_E_ASSOC_IND:
fc = FC_ASSOC_REQ;
@@ -3663,7 +4091,7 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
fc = 0;
goto exit;
}
- if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), FALSE)))
+ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
return err;
channel = dtoh32(ci.hw_channel);
@@ -3682,14 +4110,14 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
&mgmt_frame, &len, body);
if (err < 0)
goto exit;
- isfree = TRUE;
+ isfree = true;
if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ cfg80211_send_rx_assoc(ndev, mgmt_frame, len);
} else if (event == WLC_E_DISASSOC_IND) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ cfg80211_send_disassoc(ndev, mgmt_frame, len);
} else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
- cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+ cfg80211_send_deauth(ndev, mgmt_frame, len);
}
} else {
@@ -3712,16 +4140,16 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
act = true;
wl_update_prof(wl, e, &act, WL_PROF_ACT);
} else if (wl_is_linkdown(wl, e)) {
- if (test_bit(WL_STATUS_CONNECTED, &wl->status)) {
+ if (wl_get_drv_status(wl, CONNECTED)) {
printk("link down, call cfg80211_disconnected ");
cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
- clear_bit(WL_STATUS_CONNECTED, &wl->status);
+ wl_clr_drv_status(wl, CONNECTED);
wl_link_down(wl);
wl_init_prof(wl->profile);
}
} else if (wl_is_nonetwork(wl, e)) {
printk("connect failed e->status 0x%x", (int)ntoh32(e->status));
- if (test_bit(WL_STATUS_CONNECTING, &wl->status))
+ if (wl_get_drv_status(wl, CONNECTING))
wl_bss_connect_done(wl, ndev, e, data, false);
} else {
printk("%s nothing\n", __FUNCTION__);
@@ -3758,7 +4186,7 @@ wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
BUG_ON(unlikely(!buflen));
- return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, FALSE);
+ return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, false);
}
static s32
@@ -3772,7 +4200,7 @@ wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
BUG_ON(unlikely(!len));
err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
- WL_IOCTL_LEN_MAX, FALSE);
+ WL_IOCTL_LEN_MAX, false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -3897,7 +4325,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
WL_DBG(("Could not find the AP\n"));
*(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BSS_INFO,
- wl->extra_buf, WL_EXTRA_BUF_MAX, FALSE);
+ wl->extra_buf, WL_EXTRA_BUF_MAX, false);
if (unlikely(err)) {
WL_ERR(("Could not get bss info %d\n", err));
goto update_bss_info_out;
@@ -3932,7 +4360,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
* so we speficially query dtim information to dongle.
*/
err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_DTIMPRD,
- &dtim_period, sizeof(dtim_period), FALSE);
+ &dtim_period, sizeof(dtim_period), false);
if (unlikely(err)) {
WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
goto update_bss_info_out;
@@ -3966,7 +4394,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
WL_DBG(("Report roaming result\n"));
- set_bit(WL_STATUS_CONNECTED, &wl->status);
+ wl_set_drv_status(wl, CONNECTED);
return err;
}
@@ -3982,7 +4410,8 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
wl_get_assoc_ies(wl, ndev);
memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
wl_update_bss_info(wl, ndev);
- if (test_and_clear_bit(WL_STATUS_CONNECTING, &wl->status)) {
+ if (wl_get_drv_status(wl, CONNECTING)) {
+ wl_clr_drv_status(wl, CONNECTING);
cfg80211_connect_result(ndev,
(u8 *)&wl->bssid,
conn_info->req_ie,
@@ -3994,6 +4423,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
WL_DBG(("Report connect result - connection %s\n",
completed ? "succeeded" : "failed"));
} else {
+ wl_clr_drv_status(wl, CONNECTING);
cfg80211_roamed(ndev,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
NULL,
@@ -4004,7 +4434,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
GFP_KERNEL);
WL_DBG(("Report roaming result\n"));
}
- set_bit(WL_STATUS_CONNECTED, &wl->status);
+ wl_set_drv_status(wl, CONNECTED);
return err;
}
@@ -4038,20 +4468,21 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
u32 len = WL_SCAN_BUF_MAX;
s32 err = 0;
-
WL_DBG(("Enter \n"));
if (wl->iscan_on && wl->iscan_kickstart)
return wl_wakeup_iscan(wl_to_iscan(wl));
- if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
+ if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
+ wl_clr_drv_status(wl, SCANNING);
WL_DBG(("Scan complete while device not scanning\n"));
return -EINVAL;
}
+ wl_clr_drv_status(wl, SCANNING);
if (unlikely(!wl->scan_request)) {
}
rtnl_lock();
err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
- sizeof(channel_inform), FALSE);
+ sizeof(channel_inform), false);
if (unlikely(err)) {
WL_ERR(("scan busy (%d)\n", err));
goto scan_done_out;
@@ -4066,7 +4497,7 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
bss_list = wl->bss_list;
memset(bss_list, 0, len);
bss_list->buflen = htod32(len);
- err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, FALSE);
+ err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
if (unlikely(err)) {
WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
err = -EINVAL;
@@ -4138,7 +4569,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
struct wiphy *wiphy = wl_to_wiphy(wl);
struct ether_addr da;
struct ether_addr bssid;
- bool isfree = FALSE;
+ bool isfree = false;
s32 err = 0;
s32 freq;
wl_event_rx_frame_data_t *rxframe =
@@ -4152,6 +4583,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
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);
#else
@@ -4160,7 +4592,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
if (event == WLC_E_ACTION_FRAME_RX) {
wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
&da, sizeof(struct ether_addr), ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
- wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, FALSE);
+ wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
&mgmt_frame, &mgmt_frame_len,
(u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
@@ -4169,7 +4601,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
__func__, mgmt_frame_len, channel, freq));
goto exit;
}
- isfree = TRUE;
+ isfree = true;
} else {
mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
}
@@ -4221,6 +4653,7 @@ static void wl_init_event_handler(struct wl_priv *wl)
wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
+ wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
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;
@@ -4320,6 +4753,13 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
wl->fw = NULL;
kfree(wl->pmk_list);
wl->pmk_list = NULL;
+ 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;
+ }
}
static s32 wl_create_event_handler(struct wl_priv *wl)
@@ -4352,7 +4792,7 @@ static void wl_term_iscan(struct wl_priv *wl)
iscan->state = WL_ISCAN_STATE_IDLE;
WL_INFO(("SIGTERM\n"));
send_sig(SIGTERM, iscan->tsk, 1);
- printk("kthread_stop\n");
+ WL_DBG(("kthread_stop\n"));
kthread_stop(iscan->tsk);
iscan->tsk = NULL;
}
@@ -4363,10 +4803,12 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
struct wl_priv *wl = iscan_to_wl(iscan);
WL_DBG(("Enter \n"));
- if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
+ if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
+ wl_clr_drv_status(wl, SCANNING);
WL_ERR(("Scan complete while device not scanning\n"));
return;
}
+ wl_clr_drv_status(wl, SCANNING);
if (likely(wl->scan_request)) {
cfg80211_scan_done(wl->scan_request, aborted);
wl->scan_request = NULL;
@@ -4556,11 +4998,13 @@ static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan)
static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
{
WL_DBG(("Enter \n"));
- if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING, &wl->status))) {
+ if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
+ wl_clr_drv_status(wl, SCANNING);
WL_ERR(("Scan complete while device not scanning\n"));
return;
}
- if (p2p_on(wl))
+ wl_clr_drv_status(wl, SCANNING);
+ if (wl->p2p_supported && p2p_on(wl))
wl_clr_p2p_status(wl, SCANNING);
if (likely(wl->scan_request)) {
@@ -4584,7 +5028,7 @@ static s32 wl_escan_handler(struct wl_priv *wl,
WL_DBG((" enter event type : %d, status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
if (!wl->escan_on &&
- !test_bit(WL_STATUS_SCANNING, &wl->status)) {
+ !wl_get_drv_status(wl, SCANNING)) {
WL_ERR(("escan is not ready \n"));
return err;
}
@@ -4733,7 +5177,6 @@ static s32 wl_init_priv(struct wl_priv *wl)
wl_init_conf(wl->conf);
wl_init_prof(wl->profile);
wl_link_down(wl);
- wl_cfgp2p_init_priv(wl);
return err;
}
@@ -4757,10 +5200,10 @@ s32 wl_cfg80211_sysctl_export_devaddr(void *data)
dhd_pub_t *dhd = (dhd_pub_t *)data;
struct wl_priv *wl = WL_PRIV_GET();
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr);
+ wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
- sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p.dev_addr.octet));
- sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p.int_addr.octet));
+ sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet));
+ sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet));
return 0;
}
@@ -4776,18 +5219,24 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev)
return -ENODEV;
}
wl = WL_PRIV_GET();
- if (wl && !test_bit(WL_STATUS_READY, &wl->status)) {
+ if (wl && !wl_get_drv_status(wl, READY)) {
if (wl->wdev &&
wl_cfgp2p_supported(wl, ndev)) {
- WL_INFO(("P2P is supported on Firmware \n"));
wl->wdev->wiphy->interface_modes |=
(BIT(NL80211_IFTYPE_P2P_CLIENT)|
BIT(NL80211_IFTYPE_P2P_GO));
+ if ((err = wl_cfgp2p_init_priv(wl)) != 0)
+ goto fail;
+#ifdef CONFIG_SYSCTL
+ wl_cfg80211_sysctl_export_devaddr(wl->pub);
+#endif
+ wl->p2p_supported = true;
}
} else
return -ENODEV;
- set_bit(WL_STATUS_READY, &wl->status);
+ wl_set_drv_status(wl, READY);
+fail:
return err;
}
s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
@@ -4864,7 +5313,8 @@ void wl_cfg80211_detach(void)
#endif
rfkill_unregister(wl->rfkill);
rfkill_destroy(wl->rfkill);
-
+ if (wl->p2p_supported)
+ wl_cfgp2p_deinit_priv(wl);
wl_deinit_priv(wl);
wl_free_wdev(wl);
wl_set_drvdata(wl_cfg80211_dev, NULL);
@@ -5001,9 +5451,6 @@ static void wl_put_event(struct wl_event_q *e)
kfree(e);
}
-/* TODO: this has been changed to wl_cfg80211_set_sdio_func in FALCON
- * Keep is as-is in P2P Twig
- */
void wl_cfg80211_set_sdio_func(void *func)
{
cfg80211_sdio_func = (struct sdio_func *)func;
@@ -5035,16 +5482,22 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp
mode = WL_MODE_IBSS;
break;
case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
mode = WL_MODE_BSS;
infra = 1;
break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ mode = WL_MODE_AP;
+ infra = 1;
+ break;
default:
err = -EINVAL;
WL_ERR(("invalid type (%d)\n", iftype));
return err;
}
infra = htod32(infra);
- err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
return err;
@@ -5054,6 +5507,39 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp
return 0;
}
+static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+{
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+ s8 eventmask[WL_EVENTING_MASK_LEN];
+ s32 err = 0;
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(err)) {
+ WL_ERR(("Get event_msgs error (%d)\n", err));
+ goto dongle_eventmsg_out;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+ if (add) {
+ setbit(eventmask, event);
+ } else {
+ clrbit(eventmask, event);
+ }
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(err)) {
+ WL_ERR(("Set event_msgs error (%d)\n", err));
+ goto dongle_eventmsg_out;
+ }
+
+dongle_eventmsg_out:
+ return err;
+
+}
static s32 wl_dongle_eventmsg(struct net_device *ndev)
{
@@ -5065,7 +5551,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev)
/* Setup event_msgs */
bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("Get event_msgs error (%d)\n", err));
goto dongle_eventmsg_out;
@@ -5099,7 +5585,7 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev)
setbit(eventmask, WLC_E_ESCAN_RESULT);
bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("Set event_msgs error (%d)\n", err));
goto dongle_eventmsg_out;
@@ -5122,7 +5608,7 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up)
{
s32 err = 0;
- err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), FALSE);
+ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), false);
if (unlikely(err)) {
WL_ERR(("WLC_UP error (%d)\n", err));
}
@@ -5134,7 +5620,7 @@ static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
s32 err = 0;
WL_TRACE(("In\n"));
- err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), false);
if (unlikely(err)) {
WL_ERR(("WLC_SET_PM error (%d)\n", err));
}
@@ -5151,14 +5637,14 @@ wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
/* Match Host and Dongle rx alignment */
bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("txglomalign error (%d)\n", err));
goto dongle_glom_out;
}
/* disable glom option per default */
bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("txglom error (%d)\n", err));
goto dongle_glom_out;
@@ -5178,7 +5664,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
if (roamvar) {
bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("bcn_timeout error (%d)\n", err));
goto dongle_rom_out;
@@ -5186,7 +5672,7 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
}
/* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (unlikely(err)) {
WL_ERR(("roam_off error (%d)\n", err));
goto dongle_rom_out;
@@ -5202,7 +5688,7 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
s32 err = 0;
err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
- sizeof(scan_assoc_time), FALSE);
+ sizeof(scan_assoc_time), false);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("Scan assoc time is not supported\n"));
@@ -5212,7 +5698,7 @@ wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
goto dongle_scantime_out;
}
err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
- sizeof(scan_unassoc_time), FALSE);
+ sizeof(scan_unassoc_time), false);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("Scan unassoc time is not supported\n"));
@@ -5236,7 +5722,7 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
/* Set ARP offload */
bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO(("arpoe is not supported\n"));
@@ -5246,7 +5732,7 @@ wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
goto dongle_offload_out;
}
bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO(("arp_ol is not supported\n"));
@@ -5345,7 +5831,7 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
memcpy((char *)pkt_filterp, &pkt_filter,
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
- err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, false);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("filter not supported\n"));
@@ -5358,7 +5844,7 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
/* set mode to allow pattern */
bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
sizeof(iovbuf));
- err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), FALSE);
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), false);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFO(("filter_mode not supported\n"));
@@ -5445,7 +5931,7 @@ static s32 wl_update_wiphybands(struct wl_priv *wl)
s32 err = 0;
err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list,
- sizeof(phy_list), FALSE);
+ sizeof(phy_list), false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
@@ -5473,7 +5959,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl)
return err;
wl_invoke_iscan(wl);
- set_bit(WL_STATUS_READY, &wl->status);
+ wl_set_drv_status(wl, READY);
return err;
}
@@ -5483,25 +5969,32 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
WL_TRACE(("In\n"));
/* Check if cfg80211 interface is already down */
- if (!test_bit(WL_STATUS_READY, &wl->status))
+ if (!wl_get_drv_status(wl, READY))
return err; /* it is even not ready */
- set_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
+ wl_set_drv_status(wl, SCAN_ABORTING);
+
wl_term_iscan(wl);
if (wl->scan_request) {
cfg80211_scan_done(wl->scan_request, true);
-
wl->scan_request = NULL;
}
- clear_bit(WL_STATUS_READY, &wl->status);
- clear_bit(WL_STATUS_SCANNING, &wl->status);
- clear_bit(WL_STATUS_SCAN_ABORTING, &wl->status);
- clear_bit(WL_STATUS_CONNECTED, &wl->status);
-
+ wl_clr_drv_status(wl, READY);
+ wl_clr_drv_status(wl, SCANNING);
+ wl_clr_drv_status(wl, SCAN_ABORTING);
+ wl_clr_drv_status(wl, CONNECTED);
+ if (wl_get_drv_status(wl, AP_CREATED)) {
+ wl_clr_drv_status(wl, AP_CREATED);
+ wl_clr_drv_status(wl, AP_CREATING);
+ wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
+ NL80211_IFTYPE_STATION;
+ }
wl->dongle_up = false;
wl_flush_eq(wl);
wl_link_down(wl);
- wl_cfgp2p_down(wl);
+ if (wl->p2p_supported)
+ wl_cfgp2p_down(wl);
+
wl_debugfs_remove_netdev(wl);
return err;
@@ -5833,6 +6326,47 @@ s8 *wl_cfg80211_get_nvramname(void)
return wl->fw->nvram_name;
}
+s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
+{
+ struct wl_priv *wl;
+ dhd_pub_t *dhd_pub;
+ struct ether_addr p2pif_addr;
+
+ wl = WL_PRIV_GET();
+ dhd_pub = (dhd_pub_t *)wl->pub;
+ wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
+
+ return 0;
+}
+
+static __used void wl_dongle_poweron(struct wl_priv *wl)
+{
+
+ WL_DBG(("Enter \n"));
+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
+
+#if defined(BCMLXSDMMC)
+ sdioh_start(NULL, 0);
+#endif
+#if defined(BCMLXSDMMC)
+ sdioh_start(NULL, 1);
+#endif
+ wl_cfg80211_resume(wl_to_wiphy(wl));
+}
+
+static __used void wl_dongle_poweroff(struct wl_priv *wl)
+{
+
+
+ WL_DBG(("Enter \n"));
+ wl_cfg80211_suspend(wl_to_wiphy(wl));
+
+#if defined(BCMLXSDMMC)
+ sdioh_stop(NULL);
+#endif
+ /* clean up dtim_skip setting */
+ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
+}
static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
{
char buf[10+IFNAMSIZ];
@@ -5872,6 +6406,13 @@ static const struct rfkill_ops wl_rfkill_ops = {
static int wl_rfkill_set(void *data, bool blocked)
{
+ struct wl_priv *wl = (struct wl_priv *)data;
+
+ WL_DBG(("Enter \n"));
+ WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
+
+ wl->rf_blocked = blocked;
+
return 0;
}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index 4c05987ce2a..f9de60f0ca3 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -114,12 +114,6 @@ do { \
*/
#define WL_FILE_NAME_MAX 256
#define WL_DWELL_TIME 200
-
-/* WiFi Direct */
-#define WL_P2P_WILDCARD_SSID "DIRECT-"
-#define WL_P2P_WILDCARD_SSID_LEN 7
-#define WL_P2P_INTERFACE_PREFIX "p2p"
-#define WL_P2P_TEMP_CHAN "11"
#define VWDEV_CNT 3
/* dongle status */
enum wl_status {
@@ -127,7 +121,9 @@ enum wl_status {
WL_STATUS_SCANNING,
WL_STATUS_SCAN_ABORTING,
WL_STATUS_CONNECTING,
- WL_STATUS_CONNECTED
+ WL_STATUS_CONNECTED,
+ WL_STATUS_AP_CREATING,
+ WL_STATUS_AP_CREATED
};
/* wi-fi mode */
@@ -315,6 +311,17 @@ struct escan_info {
struct wiphy *wiphy;
};
+struct ap_info {
+/* Structure to hold WPS, WPA IEs for a AP */
+ u8 probe_res_ie[IE_MAX_LEN];
+ u8 beacon_ie[IE_MAX_LEN];
+ u32 probe_res_ie_len;
+ u32 beacon_ie_len;
+ u8 *wpa_ie;
+ u8 *rsn_ie;
+ u8 *wps_ie;
+ bool security_mode;
+};
/* dongle private data of cfg80211 interface */
struct wl_priv {
struct wireless_dev *wdev; /* representing wl cfg80211 device */
@@ -373,12 +380,13 @@ struct wl_priv {
struct dentry *debugfsdir;
struct rfkill *rfkill;
bool rf_blocked;
-
struct ieee80211_channel remain_on_chan;
enum nl80211_channel_type remain_on_chan_type;
u64 cache_cookie;
wait_queue_head_t dongle_event_wait;
- struct p2p_info p2p;
+ struct ap_info *ap_info;
+ struct p2p_info *p2p;
+ bool p2p_supported;
s8 last_eventmask[WL_EVENTING_MASK_LEN];
u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN)));
};
@@ -398,6 +406,10 @@ struct wl_priv {
#define wl_to_iscan(w) (w->iscan)
#define wl_to_conn(w) (&w->conn_info)
#define wiphy_from_scan(w) (w->escan_info.wiphy)
+#define wl_get_drv_status(wl, stat) (test_bit(WL_STATUS_ ## stat, &(wl)->status))
+#define wl_set_drv_status(wl, stat) (set_bit(WL_STATUS_ ## stat, &(wl)->status))
+#define wl_clr_drv_status(wl, stat) (clear_bit(WL_STATUS_ ## stat, &(wl)->status))
+#define wl_chg_drv_status(wl, stat) (change_bit(WL_STATUS_ ## stat, &(wl)->status))
static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
{
@@ -488,6 +500,7 @@ extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function i
extern s32 wl_cfg80211_up(void); /* dongle up */
extern s32 wl_cfg80211_down(void); /* dongle down */
extern s32 wl_cfg80211_notify_ifadd(struct net_device *net);
+extern s32 wl_cfg80211_ifdel_ops(struct net_device *net);
extern s32 wl_cfg80211_notify_ifdel(struct net_device *net);
extern s32 wl_cfg80211_is_progress_ifadd(void);
extern s32 wl_cfg80211_is_progress_ifchange(void);
@@ -499,6 +512,7 @@ extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size);
extern void wl_cfg80211_release_fw(void);
extern s8 *wl_cfg80211_get_fwname(void);
extern s8 *wl_cfg80211_get_nvramname(void);
+extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
#ifdef CONFIG_SYSCTL
extern s32 wl_cfg80211_sysctl_export_devaddr(void *data);
#endif
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
index 0a5a8a8f109..fa88d4b4cf8 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -65,14 +65,13 @@ wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
* Initialize variables related to P2P
*
*/
-void
+s32
wl_cfgp2p_init_priv(struct wl_priv *wl)
{
- wl->p2p.on = 0;
- wl->p2p.scan = 0; /* by default , legacy scan */
- wl->p2p.status = 0;
- wl->p2p.listen_timer = NULL;
-
+ if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
+ CFGP2P_ERR(("struct p2p_info allocation failed\n"));
+ return -ENOMEM;
+ }
#define INIT_IE(IE_TYPE, BSS_TYPE) \
do { \
memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
@@ -103,17 +102,38 @@ wl_cfgp2p_init_priv(struct wl_priv *wl)
wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
-}
+ return BCME_OK;
+}
+/*
+ * Deinitialize variables related to P2P
+ *
+ */
+void
+wl_cfgp2p_deinit_priv(struct wl_priv *wl)
+{
+ if (wl->p2p) {
+ kfree(wl->p2p);
+ }
+ wl->p2p_supported = 0;
+}
/*
* Set P2P functions into firmware
*/
s32
wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
{
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 ret = BCME_OK;
-
- /* TODO : Do we have to check whether APSTA is enabled or not ? */
+ s32 val = 0;
+ /* Do we have to check whether APSTA is enabled or not ? */
+ wldev_iovar_getint(ndev, "apsta", &val);
+ if (val == 0) {
+ val = 1;
+ wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), false);
+ wldev_iovar_setint(ndev, "apsta", val);
+ wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), false);
+ }
return ret;
}
@@ -130,7 +150,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 *netdev = wl_to_prmry_ndev(wl);
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
ifreq.type = if_type;
ifreq.chspec = chspec;
@@ -142,7 +162,7 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
(if_type == WL_P2P_IF_GO) ? "go" : "client",
(chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
- err = wldev_iovar_setbuf(netdev, "p2p_ifadd", &ifreq, sizeof(ifreq),
+ err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
ioctlbuf, sizeof(ioctlbuf));
return err;
}
@@ -571,21 +591,21 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
/* Check whether the given IE looks like WFA P2P IE. */
#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
(const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
-/* Delete and Set a management ie to firmware
+/* Delete and Set a management vndr ie to firmware
* Parameters:
* @wl : wl_private data
* @ndev : net device for bssidx
* @bssidx : bssidx for BSS
* @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
* VNDR_IE_ASSOCREQ_FLAG)
- * @ie : probe request ie (WPS IE + P2P IE)
- * @ie_len : probe request ie length
+ * @ie : VNDR IE (such as P2P IE , WPS IE)
+ * @ie_len : VNDR IE Length
* Returns 0 if success.
*/
s32
wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
- s32 pktflag, const u8 *p2p_ie, u32 p2p_ie_len)
+ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
{
/* Vendor-specific Information Element ID */
#define VNDR_SPEC_ELEMENT_ID 0xdd
@@ -601,50 +621,70 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi
#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
if (bssidx == -1)
return BCME_BADARG;
- if (bssidx == P2PAPI_BSSCFG_PRIMARY)
- bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
- switch (pktflag) {
- case VNDR_IE_PRBREQ_FLAG :
- mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
- break;
- case VNDR_IE_PRBRSP_FLAG :
- mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
- break;
- case VNDR_IE_ASSOCREQ_FLAG :
- mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
- break;
- case VNDR_IE_ASSOCRSP_FLAG :
- mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
- break;
- case VNDR_IE_BEACON_FLAG :
- mgmt_ie_buf = IE_TYPE(beacon, bssidx);
- mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
- mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
- break;
- default:
- mgmt_ie_buf = NULL;
- mgmt_ie_len = NULL;
- CFGP2P_ERR(("not suitable type\n"));
- return -1;
+ if (wl->p2p_supported && p2p_on(wl)) {
+ if (bssidx == P2PAPI_BSSCFG_PRIMARY)
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+ switch (pktflag) {
+ case VNDR_IE_PRBREQ_FLAG :
+ mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
+ mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
+ break;
+ case VNDR_IE_PRBRSP_FLAG :
+ mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
+ mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
+ break;
+ case VNDR_IE_ASSOCREQ_FLAG :
+ mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
+ mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
+ break;
+ case VNDR_IE_ASSOCRSP_FLAG :
+ mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
+ mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
+ break;
+ case VNDR_IE_BEACON_FLAG :
+ mgmt_ie_buf = IE_TYPE(beacon, bssidx);
+ mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
+ mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
+ break;
+ default:
+ mgmt_ie_buf = NULL;
+ mgmt_ie_len = NULL;
+ CFGP2P_ERR(("not suitable type\n"));
+ return -1;
+ }
+ } else {
+ switch (pktflag) {
+ case VNDR_IE_PRBRSP_FLAG :
+ mgmt_ie_buf = wl->ap_info->probe_res_ie;
+ mgmt_ie_len = &wl->ap_info->probe_res_ie_len;
+ mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie);
+ break;
+ case VNDR_IE_BEACON_FLAG :
+ mgmt_ie_buf = wl->ap_info->beacon_ie;
+ mgmt_ie_len = &wl->ap_info->beacon_ie_len;
+ mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie);
+ break;
+ default:
+ mgmt_ie_buf = NULL;
+ mgmt_ie_len = NULL;
+ CFGP2P_ERR(("not suitable type\n"));
+ return -1;
+ }
}
/* Add if there is any extra IE */
- if (p2p_ie && p2p_ie_len) {
- CFGP2P_INFO(("Request has extra IE"));
- if (p2p_ie_len > mgmt_ie_buf_len) {
+ if (vndr_ie && vndr_ie_len) {
+ CFGP2P_ERR(("Request has extra IE"));
+ if (vndr_ie_len > mgmt_ie_buf_len) {
CFGP2P_ERR(("extra IE size too big\n"));
ret = -ENOMEM;
} else {
if (mgmt_ie_buf != NULL) {
- if ((p2p_ie_len == *mgmt_ie_len) &&
- (memcmp(mgmt_ie_buf, p2p_ie, p2p_ie_len) == 0)) {
+ if ((vndr_ie_len == *mgmt_ie_len) &&
+ (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
goto exit;
}
@@ -666,12 +706,12 @@ wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssi
}
/* save the current IE in wl struct */
- memcpy(mgmt_ie_buf, p2p_ie, p2p_ie_len);
- *mgmt_ie_len = p2p_ie_len;
+ memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
+ *mgmt_ie_len = vndr_ie_len;
pos = 0;
- ie_buf = (u8 *) p2p_ie;
+ ie_buf = (u8 *) vndr_ie;
delete = 0;
- while (pos < p2p_ie_len) {
+ while (pos < vndr_ie_len) {
ie_id = ie_buf[pos++];
ie_len = ie_buf[pos++];
if ((ie_id == DOT11_MNG_VS_ID) &&
@@ -719,8 +759,6 @@ wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
INIT_IE(assoc_req, bssidx);
INIT_IE(assoc_res, bssidx);
INIT_IE(beacon, bssidx);
-
-
return BCME_OK;
}
@@ -749,6 +787,7 @@ wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u
return FALSE;
}
+
wpa_ie_fixed_t *
wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
{
@@ -855,12 +894,17 @@ wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
CFGP2P_ERR((" ndev is NULL\n"));
goto exit;
}
+ if (!wl->p2p_supported) {
+ return P2PAPI_BSSCFG_PRIMARY;
+ }
for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
index = wl_to_p2p_bss_bssidx(wl, i);
break;
}
}
+ if (index == -1)
+ return P2PAPI_BSSCFG_PRIMARY;
exit:
return index;
}
@@ -874,12 +918,11 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
s32 ret = BCME_OK;
CFGP2P_DBG((" Enter\n"));
- /* TODO : have to acquire bottom half lock ? */
if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
wl_set_p2p_status(wl, LISTEN_EXPIRED);
- if (wl->p2p.listen_timer)
- del_timer_sync(wl->p2p.listen_timer);
+ if (wl->p2p->listen_timer)
+ del_timer_sync(wl->p2p->listen_timer);
cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
wl->remain_on_chan_type, GFP_KERNEL);
@@ -944,12 +987,12 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms)
wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
- if (wl->p2p.listen_timer)
- del_timer_sync(wl->p2p.listen_timer);
+ if (wl->p2p->listen_timer)
+ del_timer_sync(wl->p2p->listen_timer);
- wl->p2p.listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
+ wl->p2p->listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
- if (wl->p2p.listen_timer == NULL) {
+ if (wl->p2p->listen_timer == NULL) {
CFGP2P_ERR(("listen_timer allocation failed\n"));
return -ENOMEM;
}
@@ -957,7 +1000,7 @@ wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms)
/* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
* otherwise we will wait up to duration_ms + 10ms
*/
- INIT_TIMER(wl->p2p.listen_timer, wl_cfgp2p_listen_expired, duration_ms, 20);
+ INIT_TIMER(wl->p2p->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 20);
#undef INIT_TIMER
exit:
@@ -986,7 +1029,7 @@ wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable)
*/
if (!enable) {
wl_clr_p2p_status(wl, SCANNING);
- (void) wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
+ ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
}
@@ -1214,16 +1257,19 @@ wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
CFGP2P_ERR(("wl p2p error %d\n", ret));
return 0;
}
- if (p2p_supported)
+ if (p2p_supported == 1) {
CFGP2P_INFO(("p2p is supported\n"));
-
+ } else {
+ CFGP2P_INFO(("p2p is unsupported\n"));
+ p2p_supported = 0;
+ }
return p2p_supported;
}
/* Cleanup P2P resources */
s32
wl_cfgp2p_down(struct wl_priv *wl)
{
- if (wl->p2p.listen_timer)
- del_timer_sync(wl->p2p.listen_timer);
+ if (wl->p2p->listen_timer)
+ del_timer_sync(wl->p2p->listen_timer);
return 0;
}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index 27aef59201a..1b28fa9b80a 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -91,16 +91,20 @@ enum wl_cfgp2p_status {
};
-#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p.bss_idx[type].dev)
-#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p.bss_idx[type].bssidx)
-#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p.bss_idx[type].saved_ie)
-#define wl_to_p2p_bss(wl, type) ((wl)->p2p.bss_idx[type])
-#define wl_get_p2p_status(wl, stat) (test_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status))
-#define wl_set_p2p_status(wl, stat) (set_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status))
-#define wl_clr_p2p_status(wl, stat) (clear_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status))
-#define wl_chg_p2p_status(wl, stat) (change_bit(WLP2P_STATUS_ ## stat, &(wl)->p2p.status))
-#define p2p_on(wl) ((wl)->p2p.on)
-#define p2p_scan(wl) ((wl)->p2p.scan)
+#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p->bss_idx[type].dev)
+#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p->bss_idx[type].bssidx)
+#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie)
+#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
+#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
+ &(wl)->p2p->status))
+#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : set_bit(WLP2P_STATUS_ ## stat, \
+ &(wl)->p2p->status))
+#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : clear_bit(WLP2P_STATUS_ ## stat, \
+ &(wl)->p2p->status))
+#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : change_bit(WLP2P_STATUS_ ## stat, \
+ &(wl)->p2p->status))
+#define p2p_on(wl) ((wl)->p2p->on)
+#define p2p_scan(wl) ((wl)->p2p->scan)
/* dword align allocation */
@@ -131,8 +135,10 @@ enum wl_cfgp2p_status {
} while (0)
-extern void
+extern s32
wl_cfgp2p_init_priv(struct wl_priv *wl);
+extern void
+wl_cfgp2p_deinit_priv(struct wl_priv *wl);
extern s32
wl_cfgp2p_set_firm_p2p(struct wl_priv *wl);
extern s32
@@ -171,7 +177,7 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
extern s32
wl_cfgp2p_set_managment_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
- s32 pktflag, const u8 *p2p_ie, u32 p2p_ie_len);
+ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len);
extern s32
wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx);
@@ -220,5 +226,7 @@ wl_cfgp2p_down(struct wl_priv *wl);
#define SOCIAL_CHAN_3 11
#define WL_P2P_WILDCARD_SSID "DIRECT-"
#define WL_P2P_WILDCARD_SSID_LEN 7
+#define WL_P2P_INTERFACE_PREFIX "p2p"
+#define WL_P2P_TEMP_CHAN "11"
#define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0)
#endif /* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
index 1f811a90ae5..75022a4b017 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -1889,6 +1889,12 @@ iwpriv_set_ap_config(struct net_device *dev,
info->cmd, info->flags,
wrqu->data.pointer, wrqu->data.length));
+ if (!ap_fw_loaded) {
+ WL_ERROR(("Can't execute %s(), SOFTAP fw is not Loaded\n",
+ __FUNCTION__));
+ return -1;
+ }
+
if (wrqu->data.length != 0) {
char *str_ptr;
@@ -1955,13 +1961,14 @@ static int iwpriv_get_assoc_list(struct net_device *dev,
iw = *(wl_iw_t **)netdev_priv(dev);
- MUTEX_LOCK_SOFTAP_SET(iw->pub);
- DHD_OS_WAKE_LOCK(iw->pub);
+ net_os_wake_lock(dev);
+ DHD_OS_MUTEX_LOCK(&wl_softap_lock);
WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d,"
"iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags,
extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags));
+
memset(sta_maclist, 0, sizeof(mac_buf));
sta_maclist->count = 8;
@@ -2028,8 +2035,9 @@ static int iwpriv_get_assoc_list(struct net_device *dev,
}
func_exit:
- DHD_OS_WAKE_UNLOCK(iw->pub);
- MUTEX_UNLOCK_SOFTAP_SET(iw->pub);
+
+ DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
+ net_os_wake_unlock(dev);
WL_SOFTAP(("%s: Exited\n", __FUNCTION__));
return ret;
@@ -4320,6 +4328,10 @@ wl_iw_iscan_get_scan(
WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
+
+ if (!dwrq->length)
+ return -EAGAIN;
+
return 0;
}
#endif
@@ -6266,7 +6278,7 @@ thr_wait_for_2nd_eth_dev(void *data)
}
DHD_OS_WAKE_LOCK(iw->pub);
complete(&tsk_ctl->completed);
- if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(5000)) != 0) {
+ if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) {
#else
if (down_interruptible(&tsk_ctl->sema) != 0) {
#endif
@@ -6289,7 +6301,7 @@ thr_wait_for_2nd_eth_dev(void *data)
goto fail;
}
- WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n",
+ WL_SOFTAP(("\n>%s: Thread:'softap ethdev IF:%s is detected!'\n\n",
__FUNCTION__, ap_net_dev->name));
ap_cfg_running = TRUE;
@@ -6304,7 +6316,7 @@ fail:
DHD_OS_WAKE_UNLOCK(iw->pub);
- WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__));
+ WL_SOFTAP(("\n>%s, thread completed\n", __FUNCTION__));
complete_and_exit(&tsk_ctl->completed, 0);
return ret;