summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2011-07-21 18:10:54 -0700
committerJohn Stultz <john.stultz@linaro.org>2011-07-21 18:10:54 -0700
commit0e4ec5c1011bf87326168a9b51bf22852747bf93 (patch)
tree847f9364b5ba711d4949a54d9657d60294799a00
parentd6348a53b9f9d776358b7261dfcdab06ffeafc78 (diff)
parent5d89db9f307306cae7a356c8af44e12fefdc87e9 (diff)
Merge branch 'upstream/android-3.0' into linaro-android-3.0
-rw-r--r--drivers/net/wireless/bcm4329/dhd_linux.c3
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile2
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c14
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c77
-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/include/epivers.h8
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h26
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c23
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c1193
-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.c22
-rw-r--r--drivers/usb/gadget/f_accessory.c9
-rw-r--r--include/linux/usb/f_accessory.h2
-rw-r--r--kernel/power/earlysuspend.c15
17 files changed, 1602 insertions, 496 deletions
diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c
index c2d6587f30a..5c1384bdc21 100644
--- a/drivers/net/wireless/bcm4329/dhd_linux.c
+++ b/drivers/net/wireless/bcm4329/dhd_linux.c
@@ -1941,6 +1941,9 @@ dhd_open(struct net_device *net)
ifidx = dhd_net2idx(dhd, net);
DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
+ if (ifidx == DHD_BAD_IF)
+ return -1;
+
if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) {
DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
return -1;
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
index 9f17fa7f25c..9984363f11d 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -22,7 +22,7 @@ bcmdhd-objs += wl_iw.o
DHDCFLAGS += -DSOFTAP
endif
ifneq ($(CONFIG_CFG80211),)
-bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o
+bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o
DHDCFLAGS += -DWL_CFG80211
endif
EXTRA_CFLAGS = $(DHDCFLAGS)
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index 1fbc2839d15..2e6a53ed9ca 100644
--- a/drivers/net/wireless/bcmdhd/dhd_common.c
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -1994,7 +1994,7 @@ dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
results->version = dtoh32(results->version);
*scan_count = results->count = dtoh32(results->count);
status = dtoh32(list_buf->status);
- DHD_ISCAN(("%s: Got %d resuls\n", __FUNCTION__, results->count));
+ DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__, results->count, status));
dhd_iscan_unlock();
@@ -2178,6 +2178,7 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
return err;
}
+ memset(iovbuf, 0, sizeof(iovbuf));
memset(&pfn_param, 0, sizeof(pfn_param));
memset(&pfn_element, 0, sizeof(pfn_element));
@@ -2188,8 +2189,8 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
/* check and set extra pno params */
if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) {
pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
- pfn_param.repeat = htod32(pno_repeat);
- pfn_param.exp = htod32(pno_freq_expo_max);
+ pfn_param.repeat = (uchar) (pno_repeat);
+ pfn_param.exp = (uchar) (pno_freq_expo_max);
}
/* set up pno scan fr */
if (scan_fr != 0)
@@ -2203,8 +2204,13 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
return err;
}
+
len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
- dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0);
+ if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s pfn_set failed for error=%d\n",
+ __FUNCTION__, err));
+ return err;
+ }
/* set all pfn ssid */
for (i = 0; i < nssid; i++) {
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index e952ee1ccc2..e318017ff80 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 */
@@ -289,7 +290,7 @@ module_param(dhd_sysioc, uint, 0);
module_param(dhd_msg_level, int, 0);
/* load firmware and/or nvram values from the filesystem */
-module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0);
+module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
/* Watchdog interval */
@@ -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 {
@@ -2205,6 +2223,13 @@ dhd_open(struct net_device *net)
int ifidx;
int32 ret = 0;
+ /* Update FW path if it was changed */
+ if ((firmware_path != NULL) && (firmware_path[0] != '\0')) {
+ if (firmware_path[strlen(firmware_path)-1] == '\n')
+ firmware_path[strlen(firmware_path)-1] = '\0';
+ strcpy(fw_path, firmware_path);
+ firmware_path[0] = '\0';
+ }
#if !defined(WL_CFG80211)
/** Force start if ifconfig_up gets called before START command
* We keep WEXT's wl_control_wl_start to provide backward compatibility
@@ -2363,7 +2388,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 +2493,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 +2589,6 @@ fail:
dhd_free(&dhd->pub);
}
-
return NULL;
}
@@ -2665,7 +2690,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 +2723,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 +2749,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 +2874,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 +2951,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 +2985,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 +3140,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 +3156,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/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index f8623f01ade..3dfcc150301 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -33,17 +33,17 @@
#define EPI_RC_NUMBER 125
-#define EPI_INCREMENTAL_NUMBER 33
+#define EPI_INCREMENTAL_NUMBER 48
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 5, 90, 125, 33
+#define EPI_VERSION 5, 90, 125, 48
-#define EPI_VERSION_NUM 0x055a7d21
+#define EPI_VERSION_NUM 0x055a7d30
#define EPI_VERSION_DEV 5.90.125
-#define EPI_VERSION_STR "5.90.125.33"
+#define EPI_VERSION_STR "5.90.125.48"
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index 2f5e9e1fec5..f1af5b1841b 100644
--- a/drivers/net/wireless/bcmdhd/include/wlioctl.h
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -1238,6 +1238,12 @@ typedef struct wl_po {
#define WL_CHAN_FREQ_RANGE_5GMH_VER2 7
#define WL_CHAN_FREQ_RANGE_5GH_VER2 8
+#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4
+#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5
+#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6
+#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7
+#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8
+
#define WLC_PHY_TYPE_A 0
#define WLC_PHY_TYPE_B 1
@@ -1765,7 +1771,8 @@ enum {
enum {
OFF_ADAPT,
SMART_ADAPT,
- STRICT_ADAPT
+ STRICT_ADAPT,
+ SLOW_ADAPT
};
#define SORT_CRITERIA_BIT 0
@@ -1775,14 +1782,16 @@ enum {
#define AUTO_CONNECT_BIT 4
#define ENABLE_BD_SCAN_BIT 5
#define ENABLE_ADAPTSCAN_BIT 6
+#define IMMEDIATE_EVENT_BIT 8
-#define SORT_CRITERIA_MASK 0x01
-#define AUTO_NET_SWITCH_MASK 0x02
-#define ENABLE_BKGRD_SCAN_MASK 0x04
-#define IMMEDIATE_SCAN_MASK 0x08
-#define AUTO_CONNECT_MASK 0x10
-#define ENABLE_BD_SCAN_MASK 0x20
-#define ENABLE_ADAPTSCAN_MASK 0xc0
+#define SORT_CRITERIA_MASK 0x0001
+#define AUTO_NET_SWITCH_MASK 0x0002
+#define ENABLE_BKGRD_SCAN_MASK 0x0004
+#define IMMEDIATE_SCAN_MASK 0x0008
+#define AUTO_CONNECT_MASK 0x0010
+#define ENABLE_BD_SCAN_MASK 0x0020
+#define ENABLE_ADAPTSCAN_MASK 0x00c0
+#define IMMEDIATE_EVENT_MASK 0x0100
#define PFN_VERSION 2
#define PFN_SCANRESULT_VERSION 1
@@ -1828,6 +1837,7 @@ typedef struct wl_pfn_param {
uint8 mscan;
uint8 repeat;
uint8 exp;
+ int32 slow_freq;
} wl_pfn_param_t;
typedef struct wl_pfn_bssid {
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
index 432e2539ab0..876fc080ac1 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,11 @@ 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);
+#ifdef WL_CFG80211
+int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
+#else
+int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { return 0; }
+#endif
extern bool ap_fw_loaded;
#ifdef CUSTOMER_HW2
@@ -276,6 +282,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 +457,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 +468,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..201cb618844 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
@@ -120,6 +125,44 @@ static ctl_table wl_sysctl_table[] = {
static struct ctl_table_header *wl_sysctl_hdr;
#endif /* CONFIG_SYSCTL */
+/* This is to override regulatory domains defined in cfg80211 module (reg.c)
+ * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
+ * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
+ * All the chnages in world regulatory domain are to be done here.
+ */
+static const struct ieee80211_regdomain brcm_regdom = {
+ .n_reg_rules = 5,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
+ /* IEEE 802.11b/g, channels 12..13. No HT40
+ * channel fits here. */
+ REG_RULE(2467-10, 2472+10, 20, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS),
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20,
+ NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS |
+ NL80211_RRF_NO_OFDM),
+ /* IEEE 802.11a, channel 36..48 */
+ REG_RULE(5180-10, 5240+10, 40, 6, 20, 0
+ /*NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS*/),
+
+ /* NB: 5260 MHz - 5700 MHz requies DFS */
+
+ /* IEEE 802.11a, channel 149..165 */
+ REG_RULE(5745-10, 5825+10, 40, 6, 20, 0
+ /*NL80211_RRF_PASSIVE_SCAN |
+ NL80211_RRF_NO_IBSS*/),
+ }
+};
+
+
/* Data Element Definitions */
#define WPS_ID_CONFIG_METHODS 0x1008
#define WPS_ID_REQ_TYPE 0x103A
@@ -189,6 +232,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 +375,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 +398,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 +451,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 +471,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 +830,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 +847,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 +865,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 +886,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 +925,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 +942,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 +952,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 +974,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 +1015,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 +1043,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 +1088,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 +1112,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 +1153,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 +1266,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 +1293,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 +1377,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 +1406,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 +1427,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 +1467,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 +1480,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 +1514,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 +1535,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 +1567,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 +1589,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 +1628,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 +1740,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;
@@ -1931,7 +2059,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
}
} else {
- WL_ERR(("No P2PIE in beacon \n"));
+ WL_INFO(("No P2PIE in beacon \n"));
}
if (unlikely(!sme->ssid)) {
@@ -1982,15 +2110,15 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_DBG(("join_param_size %d\n", join_params_size));
if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
- WL_ERR(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
+ WL_INFO(("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 +2140,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 +2181,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 +2244,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 +2260,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 +2283,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 +2353,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 +2392,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 +2442,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 +2489,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 +2525,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 +2580,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 +2590,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 +2606,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 +2628,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 +2683,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 +2753,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 +2770,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 +2887,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 +2947,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 +2966,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 +2977,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 +2999,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 +3026,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);
@@ -2908,25 +3038,21 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
return -ENODEV;
}
- if (p2p_on(wl)) {
- wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p.dev_addr, &wl->p2p.int_addr);
-
+ if (wl->p2p_supported && p2p_on(wl)) {
+ 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 +3079,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 +3130,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 +3154,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 +3214,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 +3281,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 +3300,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 +3475,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 +3507,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 +3517,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 +3548,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 +3556,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);
+ 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);
}
-
- err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p.ssid,
- sizeof(wl->p2p.ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
-
- wl_cfgp2p_bss(dev, bssidx, 1);
+ }
+ } 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 +3866,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;
@@ -3420,6 +3887,11 @@ static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
#endif
WIPHY_FLAG_4ADDR_STATION;
+
+ WL_DBG(("Registering custom regulatory)\n"));
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
+ /* Now we can register wiphy with cfg80211 module */
err = wiphy_register(wdev->wiphy);
if (unlikely(err < 0)) {
WL_ERR(("Couldn not register wiphy device (%d)\n", err));
@@ -3455,6 +3927,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 +3938,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 +4089,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 +4113,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 +4134,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 +4153,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 +4183,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 +4229,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 +4243,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 +4368,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 +4403,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 +4437,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 +4453,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 +4466,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 +4477,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 +4511,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 +4540,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 +4612,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 +4626,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 +4635,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 +4644,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 +4696,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 +4796,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 +4835,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 +4846,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 +5041,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 +5071,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 +5220,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 +5243,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 +5262,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 +5356,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 +5494,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 +5525,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 +5550,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 +5594,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 +5628,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 +5651,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 +5663,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 +5680,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 +5707,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 +5715,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 +5731,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 +5741,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 +5765,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 +5775,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 +5874,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 +5887,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 +5974,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 +6002,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 +6012,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 +6369,48 @@ 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"));
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
+ wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
+#else
+ wl_cfg80211_suspend(wl_to_wiphy(wl));
+#endif
+
+#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 +6450,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..494538cea18 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;
@@ -6266,7 +6274,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 +6297,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 +6312,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;
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 873ab2ed991..05e65e5cd70 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -75,6 +75,9 @@ struct acc_dev {
/* for acc_complete_set_string */
int string_index;
+ /* set to 1 if we have a pending start request */
+ int start_requested;
+
/* synchronize access to our device file */
atomic_t open_excl;
@@ -505,6 +508,8 @@ static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)
case ACCESSORY_GET_STRING_SERIAL:
src = dev->serial;
break;
+ case ACCESSORY_IS_START_REQUESTED:
+ return dev->start_requested;
}
if (!src)
return -EINVAL;
@@ -572,6 +577,7 @@ static int acc_ctrlrequest(struct usb_composite_dev *cdev,
if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) {
if (b_request == ACCESSORY_START) {
+ dev->start_requested = 1;
schedule_delayed_work(
&dev->work, msecs_to_jiffies(10));
value = 0;
@@ -593,6 +599,7 @@ static int acc_ctrlrequest(struct usb_composite_dev *cdev,
memset(dev->version, 0, sizeof(dev->version));
memset(dev->uri, 0, sizeof(dev->uri));
memset(dev->serial, 0, sizeof(dev->serial));
+ dev->start_requested = 0;
}
}
@@ -624,6 +631,8 @@ acc_function_bind(struct usb_configuration *c, struct usb_function *f)
DBG(cdev, "acc_function_bind dev: %p\n", dev);
+ dev->start_requested = 0;
+
/* allocate interface ID(s) */
id = usb_interface_id(c, f);
if (id < 0)
diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h
index ebcc5f34f55..5b2dcf9728e 100644
--- a/include/linux/usb/f_accessory.h
+++ b/include/linux/usb/f_accessory.h
@@ -77,5 +77,7 @@
#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256])
#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256])
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
+/* returns 1 if there is a start request pending */
+#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
#endif /* __LINUX_USB_F_ACCESSORY_H */
diff --git a/kernel/power/earlysuspend.c b/kernel/power/earlysuspend.c
index 84bed51dcdc..b15f02eba45 100644
--- a/kernel/power/earlysuspend.c
+++ b/kernel/power/earlysuspend.c
@@ -26,6 +26,7 @@
enum {
DEBUG_USER_STATE = 1U << 0,
DEBUG_SUSPEND = 1U << 2,
+ DEBUG_VERBOSE = 1U << 3,
};
static int debug_mask = DEBUG_USER_STATE;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
@@ -94,8 +95,11 @@ static void early_suspend(struct work_struct *work)
if (debug_mask & DEBUG_SUSPEND)
pr_info("early_suspend: call handlers\n");
list_for_each_entry(pos, &early_suspend_handlers, link) {
- if (pos->suspend != NULL)
+ if (pos->suspend != NULL) {
+ if (debug_mask & DEBUG_VERBOSE)
+ pr_info("early_suspend: calling %pf\n", pos->suspend);
pos->suspend(pos);
+ }
}
mutex_unlock(&early_suspend_lock);
@@ -131,9 +135,14 @@ static void late_resume(struct work_struct *work)
}
if (debug_mask & DEBUG_SUSPEND)
pr_info("late_resume: call handlers\n");
- list_for_each_entry_reverse(pos, &early_suspend_handlers, link)
- if (pos->resume != NULL)
+ list_for_each_entry_reverse(pos, &early_suspend_handlers, link) {
+ if (pos->resume != NULL) {
+ if (debug_mask & DEBUG_VERBOSE)
+ pr_info("late_resume: calling %pf\n", pos->resume);
+
pos->resume(pos);
+ }
+ }
if (debug_mask & DEBUG_SUSPEND)
pr_info("late_resume: done\n");
abort: