summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/bcmdhd/wl_cfg80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c805
1 files changed, 427 insertions, 378 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index 366ce2224ab..09529136787 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -2,13 +2,13 @@
* Linux cfg80211 driver
*
* 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
@@ -74,7 +74,7 @@
#include <wl_cfgp2p.h>
static struct sdio_func *cfg80211_sdio_func;
-static struct wl_dev *wl_cfg80211_dev;
+static struct wl_priv *wlcfg_drv_priv;
u32 wl_dbg_level = WL_DBG_ERR;
@@ -83,7 +83,7 @@ u32 wl_dbg_level = WL_DBG_ERR;
#define WL_TRACE(a) printk("%s ", __FUNCTION__); printk a
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-#define MAX_WAIT_TIME 3000
+#define MAX_WAIT_TIME 1500
static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
@@ -148,13 +148,10 @@ static const struct ieee80211_regdomain brcm_regdom = {
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),
-
- /* NB: 5260 MHz - 5700 MHz requies DFS */
-
- /* IEEE 802.11a, channel 149..165 */
- REG_RULE(5745-10, 5825+10, 40, 6, 20, 0), }
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
};
@@ -339,8 +336,7 @@ static u32 wl_get_ielen(struct wl_priv *wl);
static s32 wl_mode_to_nl80211_iftype(s32 mode);
-static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
- struct device *dev);
+static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
static void wl_free_wdev(struct wl_priv *wl);
static s32 wl_inform_bss(struct wl_priv *wl);
@@ -365,12 +361,6 @@ static void wl_deinit_priv_mem(struct wl_priv *wl);
static void wl_delay(u32 ms);
/*
- * store/restore cfg80211 instance data
- */
-static void wl_set_drvdata(struct wl_dev *dev, void *data);
-static void *wl_get_drvdata(struct wl_dev *dev);
-
-/*
* ibss mode utilities
*/
static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev);
@@ -423,9 +413,9 @@ static void wl_iscan_timer(unsigned long data);
static void wl_term_iscan(struct wl_priv *wl);
static s32 wl_init_scan(struct wl_priv *wl);
static s32 wl_iscan_thread(void *data);
-static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid,
+static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
u16 action);
-static s32 wl_do_iscan(struct wl_priv *wl);
+static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request);
static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan);
static s32 wl_invoke_iscan(struct wl_priv *wl);
static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
@@ -474,23 +464,11 @@ int dhd_monitor_init(void *dhd_pub);
int dhd_monitor_uninit(void);
int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
-#define WL_PRIV_GET() \
- ({ \
- struct wl_iface *ci = NULL; \
- if (unlikely(!(wl_cfg80211_dev && \
- (ci = wl_get_drvdata(wl_cfg80211_dev))))) { \
- WL_ERR(("wl_cfg80211_dev is unavailable\n")); \
- BUG(); \
- } \
- ci_to_wl(ci); \
-})
-
-#define CHECK_SYS_UP() \
+#define CHECK_SYS_UP(wlpriv) \
do { \
- struct wl_priv *wl = WL_PRIV_GET(); \
- if (unlikely(!wl_get_drv_status(wl, READY))) { \
+ if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \
WL_INFO(("device is not ready : status (%d)\n", \
- (int)wl->status)); \
+ (int)wlpriv->status)); \
return -EIO; \
} \
} while (0)
@@ -609,70 +587,7 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = {
CHAN5G(132, 0), CHAN5G(136, 0),
CHAN5G(140, 0), CHAN5G(149, 0),
CHAN5G(153, 0), CHAN5G(157, 0),
- CHAN5G(161, 0), CHAN5G(165, 0),
- CHAN5G(184, 0), CHAN5G(188, 0),
- CHAN5G(192, 0), CHAN5G(196, 0),
- CHAN5G(200, 0), CHAN5G(204, 0),
- CHAN5G(208, 0), CHAN5G(212, 0),
- CHAN5G(216, 0)
-};
-
-static struct ieee80211_channel __wl_5ghz_n_channels[] = {
- CHAN5G(32, 0), CHAN5G(34, 0),
- CHAN5G(36, 0), CHAN5G(38, 0),
- CHAN5G(40, 0), CHAN5G(42, 0),
- CHAN5G(44, 0), CHAN5G(46, 0),
- CHAN5G(48, 0), CHAN5G(50, 0),
- CHAN5G(52, 0), CHAN5G(54, 0),
- CHAN5G(56, 0), CHAN5G(58, 0),
- CHAN5G(60, 0), CHAN5G(62, 0),
- CHAN5G(64, 0), CHAN5G(66, 0),
- CHAN5G(68, 0), CHAN5G(70, 0),
- CHAN5G(72, 0), CHAN5G(74, 0),
- CHAN5G(76, 0), CHAN5G(78, 0),
- CHAN5G(80, 0), CHAN5G(82, 0),
- CHAN5G(84, 0), CHAN5G(86, 0),
- CHAN5G(88, 0), CHAN5G(90, 0),
- CHAN5G(92, 0), CHAN5G(94, 0),
- CHAN5G(96, 0), CHAN5G(98, 0),
- CHAN5G(100, 0), CHAN5G(102, 0),
- CHAN5G(104, 0), CHAN5G(106, 0),
- CHAN5G(108, 0), CHAN5G(110, 0),
- CHAN5G(112, 0), CHAN5G(114, 0),
- CHAN5G(116, 0), CHAN5G(118, 0),
- CHAN5G(120, 0), CHAN5G(122, 0),
- CHAN5G(124, 0), CHAN5G(126, 0),
- CHAN5G(128, 0), CHAN5G(130, 0),
- CHAN5G(132, 0), CHAN5G(134, 0),
- CHAN5G(136, 0), CHAN5G(138, 0),
- CHAN5G(140, 0), CHAN5G(142, 0),
- CHAN5G(144, 0), CHAN5G(145, 0),
- CHAN5G(146, 0), CHAN5G(147, 0),
- CHAN5G(148, 0), CHAN5G(149, 0),
- CHAN5G(150, 0), CHAN5G(151, 0),
- CHAN5G(152, 0), CHAN5G(153, 0),
- CHAN5G(154, 0), CHAN5G(155, 0),
- CHAN5G(156, 0), CHAN5G(157, 0),
- CHAN5G(158, 0), CHAN5G(159, 0),
- CHAN5G(160, 0), CHAN5G(161, 0),
- CHAN5G(162, 0), CHAN5G(163, 0),
- CHAN5G(164, 0), CHAN5G(165, 0),
- CHAN5G(166, 0), CHAN5G(168, 0),
- CHAN5G(170, 0), CHAN5G(172, 0),
- CHAN5G(174, 0), CHAN5G(176, 0),
- CHAN5G(178, 0), CHAN5G(180, 0),
- CHAN5G(182, 0), CHAN5G(184, 0),
- CHAN5G(186, 0), CHAN5G(188, 0),
- CHAN5G(190, 0), CHAN5G(192, 0),
- CHAN5G(194, 0), CHAN5G(196, 0),
- CHAN5G(198, 0), CHAN5G(200, 0),
- CHAN5G(202, 0), CHAN5G(204, 0),
- CHAN5G(206, 0), CHAN5G(208, 0),
- CHAN5G(210, 0), CHAN5G(212, 0),
- CHAN5G(214, 0), CHAN5G(216, 0),
- CHAN5G(218, 0), CHAN5G(220, 0),
- CHAN5G(222, 0), CHAN5G(224, 0),
- CHAN5G(226, 0), CHAN5G(228, 0)
+ CHAN5G(161, 0), CHAN5G(165, 0)
};
static struct ieee80211_supported_band __wl_band_2ghz = {
@@ -691,14 +606,6 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
.n_bitrates = wl_a_rates_size
};
-static struct ieee80211_supported_band __wl_band_5ghz_n = {
- .band = IEEE80211_BAND_5GHZ,
- .channels = __wl_5ghz_n_channels,
- .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
- .bitrates = wl_a_rates,
- .n_bitrates = wl_a_rates_size
-};
-
static const u32 __wl_cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
@@ -876,11 +783,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
s32 index = 0;
s32 mode = 0;
chanspec_t chspec;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct net_device *_ndev;
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
-
WL_DBG(("if name: %s, type: %d\n", name, type));
switch (type) {
case NL80211_IFTYPE_ADHOC:
@@ -968,7 +874,8 @@ 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 memalloc done \n",
+ wl->p2p->vir_ifname));
index = alloc_idx_vwdev(wl);
wl->vwdev[index] = vwdev;
vwdev->iftype =
@@ -981,12 +888,11 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
wl_set_drv_status(wl, READY);
wl->p2p->vif_created = true;
set_mode_by_netdev(wl, _ndev, mode);
- wl = wdev_to_wl(vwdev);
net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
rtnl_unlock();
if (net_attach && !net_attach(dhd, _ndev->ifindex))
WL_DBG((" virtual interface(%s) is "
- "created\n", wl->p2p->vir_ifname));
+ "created net attach done\n", wl->p2p->vir_ifname));
else {
rtnl_lock();
goto fail;
@@ -1010,10 +916,10 @@ static s32
wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
{
struct ether_addr p2p_mac;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 timeout = -1;
s32 ret = 0;
-
+ WL_DBG(("Enter\n"));
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
if (wl->p2p->vif_created) {
@@ -1021,8 +927,17 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
wl_cfg80211_scan_abort(wl, dev);
}
- wl_cfgp2p_ifdel(wl, &p2p_mac);
+ ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
wl_set_p2p_status(wl, IF_DELETING);
+ if (ret) {
+ /* Firmware could not delete the interface so we will not get WLC_E_IF event for cleaning the dhd virtual nw interace
+ * So lets do it here. Failures from fw will ensure the application to do ifconfig <inter> down and up sequnce, which will reload the fw
+ * however we should cleanup the linux network virtual interfaces
+ */
+ dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
+ WL_ERR(("Firmware returned an error from p2p_ifdel, try to remove linux virtual network interface dev->name %s\n", dev->name));
+ dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
+ }
/* Wait for any pending scan req to get aborted from the sysioc context */
timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
@@ -1052,7 +967,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
s32 wlif_type;
s32 mode = 0;
chanspec_t chspec;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
WL_DBG(("Enter \n"));
switch (type) {
case NL80211_IFTYPE_MONITOR:
@@ -1118,10 +1033,10 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
}
s32
-wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx,
+wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
s32 ret = BCME_OK;
if (!net) {
WL_ERR(("net is NULL\n"));
@@ -1133,11 +1048,11 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
/* 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_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx;
wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach;
- wl_clr_p2p_status(wl, IF_ADD);
net->ifindex = idx;
+ wl_clr_p2p_status(wl, IF_ADD);
+
wake_up_interruptible(&wl->dongle_event_wait);
}
return ret;
@@ -1146,7 +1061,7 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
s32
wl_cfg80211_ifdel_ops(struct net_device *net)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
if (!net || !net->name) {
WL_DBG(("net is NULL\n"));
@@ -1172,14 +1087,14 @@ wl_cfg80211_ifdel_ops(struct net_device *net)
s32
wl_cfg80211_notify_ifdel(struct net_device *net)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
if (wl->p2p->vif_created) {
s32 index = 0;
- WL_DBG(("IF_DEL event called from dongle, _net name: %s, vif name: %s\n",
- net->name, wl->p2p->vir_ifname));
+ WL_DBG(("IF_DEL event called from dongle, net %x, vif name: %s\n",
+ (unsigned int)net, wl->p2p->vir_ifname));
memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
index = wl_cfgp2p_find_idx(wl, net);
@@ -1208,7 +1123,7 @@ s32
wl_cfg80211_is_progress_ifadd(void)
{
s32 is_progress = 0;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
if (wl_get_p2p_status(wl, IF_ADD))
is_progress = 1;
return is_progress;
@@ -1218,7 +1133,7 @@ s32
wl_cfg80211_is_progress_ifchange(void)
{
s32 is_progress = 0;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
if (wl_get_p2p_status(wl, IF_CHANGING))
is_progress = 1;
return is_progress;
@@ -1228,7 +1143,7 @@ wl_cfg80211_is_progress_ifchange(void)
s32
wl_cfg80211_notify_ifchange(void)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
if (wl_get_p2p_status(wl, IF_CHANGING)) {
wl_set_p2p_status(wl, IF_CHANGED);
wake_up_interruptible(&wl->dongle_event_wait);
@@ -1236,8 +1151,16 @@ wl_cfg80211_notify_ifchange(void)
return 0;
}
-static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
+static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
{
+ u32 n_ssids = request->n_ssids;
+ u32 n_channels = request->n_channels;
+ u16 channel;
+ chanspec_t chanspec;
+ s32 i, offset;
+ char *ptr;
+ wlc_ssid_t ssid;
+
memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
params->bss_type = DOT11_BSSTYPE_ANY;
params->scan_type = 0;
@@ -1246,63 +1169,142 @@ static void wl_iscan_prep(struct wl_scan_params *params, struct wlc_ssid *ssid)
params->passive_time = -1;
params->home_time = -1;
params->channel_num = 0;
+ memset(&params->ssid, 0, sizeof(wlc_ssid_t));
+
+ WL_SCAN(("Preparing Scan request\n"));
+ WL_SCAN(("nprobes=%d\n", params->nprobes));
+ WL_SCAN(("active_time=%d\n", params->active_time));
+ WL_SCAN(("passive_time=%d\n", params->passive_time));
+ WL_SCAN(("home_time=%d\n", params->home_time));
+ WL_SCAN(("scan_type=%d\n", params->scan_type));
params->nprobes = htod32(params->nprobes);
params->active_time = htod32(params->active_time);
params->passive_time = htod32(params->passive_time);
params->home_time = htod32(params->home_time);
- if (ssid && ssid->SSID_len)
- memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
+ /* Copy channel array if applicable */
+ WL_SCAN(("### List of channelspecs to scan ###\n"));
+ if (n_channels > 0) {
+ for (i = 0; i < n_channels; i++) {
+ chanspec = 0;
+ channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
+ if (request->channels[i]->band == IEEE80211_BAND_2GHZ)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40) {
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+ } else {
+ chanspec |= WL_CHANSPEC_BW_40;
+ if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
+ else
+ chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
+ }
+
+ params->channel_list[i] = channel;
+ params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK;
+ params->channel_list[i] |= chanspec;
+ WL_SCAN(("Chan : %d, Channel spec: %x \n",
+ channel, params->channel_list[i]));
+ params->channel_list[i] = htod16(params->channel_list[i]);
+ }
+ } else {
+ WL_SCAN(("Scanning all channels\n"));
+ }
+
+ /* Copy ssid array if applicable */
+ WL_SCAN(("### List of SSIDs to scan ###\n"));
+ if (n_ssids > 0) {
+ offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
+ offset = roundup(offset, sizeof(u32));
+ ptr = (char*)params + offset;
+ for (i = 0; i < n_ssids; i++) {
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ ssid.SSID_len = request->ssids[i].ssid_len;
+ memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
+ if (!ssid.SSID_len)
+ WL_SCAN(("%d: Broadcast scan\n", i));
+ else
+ WL_SCAN(("%d: scan for %s size =%d\n", i,
+ ssid.SSID, ssid.SSID_len));
+ memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
+ ptr += sizeof(wlc_ssid_t);
+ }
+ } else {
+ WL_SCAN(("Broadcast scan\n"));
+ }
+ /* Adding mask to channel numbers */
+ params->channel_num =
+ htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
}
static s32
-wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action)
+wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action)
{
+ u32 n_channels;
+ u32 n_ssids;
s32 params_size =
- (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
+ (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
struct wl_iscan_params *params;
s32 err = 0;
- if (ssid && ssid->SSID_len)
- params_size += sizeof(struct wlc_ssid);
+ if (request != NULL) {
+ n_channels = request->n_channels;
+ n_ssids = request->n_ssids;
+ /* Allocate space for populating ssids in wl_iscan_params struct */
+ if (n_channels % 2)
+ /* If n_channels is odd, add a padd of u16 */
+ params_size += sizeof(u16) * (n_channels + 1);
+ else
+ params_size += sizeof(u16) * n_channels;
+
+ /* Allocate space for populating ssids in wl_iscan_params struct */
+ params_size += sizeof(struct wlc_ssid) * n_ssids;
+ }
params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
- if (unlikely(!params))
- return -ENOMEM;
- memset(params, 0, params_size);
- BUG_ON(unlikely(params_size >= WLC_IOCTL_SMLEN));
+ if (!params) {
+ err = -ENOMEM;
+ goto done;
+ }
- wl_iscan_prep(&params->params, ssid);
+ if (request != NULL)
+ wl_scan_prep(&params->params, request);
params->version = htod32(ISCAN_REQ_VERSION);
params->action = htod16(action);
params->scan_duration = htod16(0);
- /* params_size += offsetof(wl_iscan_params_t, params); */
+ if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) {
+ WL_ERR(("ioctl buffer length is not sufficient\n"));
+ err = -ENOMEM;
+ goto done;
+ }
err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
- iscan->ioctl_buf, WLC_IOCTL_SMLEN);
+ iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
if (unlikely(err)) {
if (err == -EBUSY) {
- WL_INFO(("system busy : iscan canceled\n"));
+ WL_INFO(("system busy : iscan canceled\n"));
} else {
WL_ERR(("error (%d)\n", err));
}
}
kfree(params);
+done:
return err;
}
-static s32 wl_do_iscan(struct wl_priv *wl)
+static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request)
{
struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
struct net_device *ndev = wl_to_prmry_ndev(wl);
- struct wlc_ssid ssid;
s32 passive_scan;
s32 err = 0;
- /* Broadcast scan by default */
- memset(&ssid, 0, sizeof(ssid));
-
iscan->state = WL_ISCAN_STATE_SCANING;
passive_scan = wl->active_scan ? 0 : 1;
@@ -1313,7 +1315,7 @@ static s32 wl_do_iscan(struct wl_priv *wl)
return err;
}
wl->iscan_kickstart = true;
- wl_run_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
+ wl_run_iscan(iscan, request, WL_SCAN_ACTION_START);
mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
iscan->timer_on = 1;
@@ -1321,9 +1323,12 @@ static s32 wl_do_iscan(struct wl_priv *wl)
}
static s32
-wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint16 action)
+wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
+ struct cfg80211_scan_request *request, uint16 action)
{
s32 err = BCME_OK;
+ u32 n_channels;
+ u32 n_ssids;
s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
wl_escan_params_t *params;
struct cfg80211_scan_request *scan_request = wl->scan_request;
@@ -1337,31 +1342,37 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint
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) {
- params_size += sizeof(wlc_ssid_t);
+ WL_SCAN((" LEGACY E-SCAN START\n"));
+
+ if (request != NULL) {
+ n_channels = request->n_channels;
+ n_ssids = request->n_ssids;
+ /* Allocate space for populating ssids in wl_iscan_params struct */
+ if (n_channels % 2)
+ /* If n_channels is odd, add a padd of u16 */
+ params_size += sizeof(u16) * (n_channels + 1);
+ else
+ params_size += sizeof(u16) * n_channels;
+
+ /* Allocate space for populating ssids in wl_iscan_params struct */
+ params_size += sizeof(struct wlc_ssid) * n_ssids;
}
- params = (wl_escan_params_t *) kmalloc(params_size, GFP_KERNEL);
-
- if (params == NULL)
- return -ENOMEM;
-
- memset(params, 0, params_size);
- memcpy(&params->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
- params->params.bss_type = DOT11_BSSTYPE_ANY;
- params->params.scan_type = 0;
- params->params.nprobes = htod32(-1);
- params->params.active_time = htod32(-1);
- params->params.passive_time = htod32(-1);
- params->params.home_time = htod32(-1);
- params->params.channel_num = 0;
- if (ssid && ssid->SSID_len) {
- memcpy(params->params.ssid.SSID, ssid->SSID, ssid->SSID_len);
- params->params.ssid.SSID_len = htod32(ssid->SSID_len);
+ params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
+ if (params == NULL) {
+ err = -ENOMEM;
+ goto exit;
}
+
+ if (request != NULL)
+ wl_scan_prep(&params->params, request);
params->version = htod32(ESCAN_REQ_VERSION);
params->action = htod16(action);
params->sync_id = htod16(0x1234);
+ if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
+ WL_ERR(("ioctl buffer length not sufficient\n"));
+ err = -ENOMEM;
+ goto exit;
+ }
wldev_iovar_setbuf(ndev, "escan", params, params_size,
wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
kfree(params);
@@ -1370,7 +1381,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, wlc_ssid_t *ssid, uint
/* P2P SCAN TRIGGER */
if (scan_request && scan_request->n_channels) {
num_chans = scan_request->n_channels;
- WL_INFO((" chann number : %d\n", num_chans));
+ WL_SCAN((" chann number : %d\n", num_chans));
default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
GFP_KERNEL);
if (default_chan_list == NULL) {
@@ -1407,12 +1418,13 @@ exit:
static s32
-wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wlc_ssid_t *ssid)
+wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
{
s32 err = BCME_OK;
s32 passive_scan;
wl_scan_results_t *results;
- WL_DBG(("Enter \n"));
+ WL_SCAN(("Enter \n"));
wl->escan_info.wiphy = wiphy;
wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
@@ -1428,7 +1440,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, wl
results->count = 0;
results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
- wl_run_escan(wl, ndev, ssid, WL_SCAN_ACTION_START);
+ wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START);
return err;
}
@@ -1437,15 +1449,16 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request,
struct cfg80211_ssid *this_ssid)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_ssid *ssids;
struct wl_scan_req *sr = wl_to_sr(wl);
- wlc_ssid_t ssid_info;
s32 passive_scan;
bool iscan_req;
bool escan_req;
bool spec_scan;
+ bool p2p_ssid;
s32 err = 0;
+ s32 i;
if (unlikely(wl_get_drv_status(wl, SCANNING))) {
WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
@@ -1456,6 +1469,10 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
(int)wl->status));
return -EAGAIN;
}
+ if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
+ WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+ return -EOPNOTSUPP;
+ }
WL_DBG(("wiphy (%p)\n", wiphy));
@@ -1463,11 +1480,18 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
spec_scan = false;
if (request) { /* scan bss */
ssids = request->ssids;
- if (wl->iscan_on && (!ssids || !ssids->ssid_len)) {
+ if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
iscan_req = true;
} else if (wl->escan_on) {
escan_req = true;
- if (ssids->ssid_len && IS_P2P_SSID(ssids->ssid)) {
+ p2p_ssid = false;
+ for (i = 0; i < request->n_ssids; i++) {
+ if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid)) {
+ p2p_ssid = true;
+ break;
+ }
+ }
+ if (p2p_ssid) {
if (wl->p2p_supported) {
/* p2p scan trigger */
if (p2p_on(wl) == false) {
@@ -1477,7 +1501,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
}
p2p_scan(wl) = true;
}
-
} else {
/* legacy scan trigger
* So, we have to disable p2p discovery if p2p discovery is on
@@ -1510,17 +1533,12 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
wl->scan_request = request;
wl_set_drv_status(wl, SCANNING);
if (iscan_req) {
- err = wl_do_iscan(wl);
+ err = wl_do_iscan(wl, request);
if (likely(!err))
return err;
else
goto scan_out;
} else if (escan_req) {
- WL_DBG(("ssid \"%s\", ssid_len (%d)\n",
- ssids->ssid, ssids->ssid_len));
-
- 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)) {
@@ -1532,7 +1550,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
}
}
}
- err = wl_do_escan(wl, wiphy, ndev, &ssid_info);
+ err = wl_do_escan(wl, wiphy, ndev, request);
if (likely(!err))
return err;
else
@@ -1546,18 +1564,18 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (sr->ssid.SSID_len) {
memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
- WL_DBG(("Specific scan ssid=\"%s\" len=%d\n",
+ WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n",
sr->ssid.SSID, sr->ssid.SSID_len));
spec_scan = true;
} else {
- WL_DBG(("Broadcast scan\n"));
+ WL_SCAN(("Broadcast scan\n"));
}
- WL_DBG(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
+ WL_SCAN(("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);
if (unlikely(err)) {
- WL_ERR(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
+ WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
goto scan_out;
}
err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid,
@@ -1586,9 +1604,10 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request)
{
s32 err = 0;
+ struct wl_priv *wl = wiphy_priv(wiphy);
WL_DBG(("Enter \n"));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
if (unlikely(err)) {
WL_ERR(("scan error (%d)\n", err));
@@ -1679,11 +1698,11 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
- struct wl_priv *wl = wiphy_to_wl(wiphy);
+ struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy);
struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 err = 0;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
(wl->conf->rts_threshold != wiphy->rts_threshold)) {
wl->conf->rts_threshold = wiphy->rts_threshold;
@@ -1721,7 +1740,7 @@ static s32
wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct cfg80211_bss *bss;
struct ieee80211_channel *chan;
struct wl_join_params join_params;
@@ -1730,7 +1749,7 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
s32 err = 0;
WL_TRACE(("In\n"));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
if (params->bssid) {
WL_ERR(("Invalid bssid\n"));
return -EOPNOTSUPP;
@@ -1791,10 +1810,10 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 err = 0;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
wl_link_down(wl);
return err;
@@ -1803,7 +1822,7 @@ static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
static s32
wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
struct wl_security *sec;
s32 val = 0;
s32 err = 0;
@@ -1833,7 +1852,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
static s32
wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
struct wl_security *sec;
s32 val = 0;
s32 err = 0;
@@ -1872,7 +1891,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
static s32
wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
struct wl_security *sec;
s32 pval = 0;
s32 gval = 0;
@@ -1944,7 +1963,7 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
static s32
wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
struct wl_security *sec;
s32 val = 0;
s32 err = 0;
@@ -2002,7 +2021,7 @@ static s32
wl_set_set_sharedkey(struct net_device *dev,
struct cfg80211_connect_params *sme)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
struct wl_security *sec;
struct wl_wsec_key key;
s32 val;
@@ -2068,14 +2087,17 @@ static s32
wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct ieee80211_channel *chan = sme->channel;
struct wl_join_params join_params;
size_t join_params_size;
s32 err = 0;
-
+ wpa_ie_fixed_t *wpa_ie;
+ bcm_tlv_t *wpa2_ie;
+ u8* wpaie = 0;
+ u32 wpaie_len = 0;
WL_DBG(("In\n"));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
/*
* Cancel ongoing scan to sync up with sme state machine of cfg80211.
@@ -2107,8 +2129,28 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
}
- } else {
- WL_INFO(("No P2PIE in beacon \n"));
+ } else if (dev == wl_to_prmry_ndev(wl)) {
+ /* find the RSN_IE */
+ if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_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 *)sme->ie,
+ sme->ie_len)) != NULL) {
+ WL_DBG((" WPA IE is found\n"));
+ }
+ if (wpa_ie != NULL || wpa2_ie != NULL) {
+ wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
+ wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
+ wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
+ wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
+ ioctlbuf, sizeof(ioctlbuf));
+ } else {
+ wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
+ ioctlbuf, sizeof(ioctlbuf));
+ }
+
}
if (unlikely(!sme->ssid)) {
@@ -2119,7 +2161,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
WL_DBG(("channel (%d), center_req (%d)\n", wl->channel,
chan->center_freq));
- }
+ } else
+ wl->channel = 0;
WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len));
err = wl_set_wpa_version(dev, sme);
if (unlikely(err))
@@ -2153,7 +2196,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
- memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ if (sme->bssid)
+ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
WL_DBG(("join_param_size %d\n", join_params_size));
@@ -2162,13 +2208,13 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
join_params.ssid.SSID_len));
}
+ wl_set_drv_status(wl, CONNECTING);
err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
+ wl_clr_drv_status(wl, CONNECTING);
return err;
}
- wl_set_drv_status(wl, CONNECTING);
-
return err;
}
@@ -2176,21 +2222,29 @@ static s32
wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
u16 reason_code)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
scb_val_t scbval;
bool act = false;
s32 err = 0;
WL_ERR(("Reason %d\n\n\n", reason_code));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
if (likely(act)) {
+ /*
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+ */
+ if (wl->scan_request) {
+ wl_cfg80211_scan_abort(wl, dev);
+ }
+ wl_set_drv_status(wl, DISCONNECTING);
scbval.val = reason_code;
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);
if (unlikely(err)) {
+ wl_clr_drv_status(wl, DISCONNECTING);
WL_ERR(("error (%d)\n", err));
return err;
}
@@ -2204,13 +2258,13 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type, s32 dbm)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct net_device *ndev = wl_to_prmry_ndev(wl);
u16 txpwrmw;
s32 err = 0;
s32 disable = 0;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
break;
@@ -2253,13 +2307,13 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy,
static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct net_device *ndev = wl_to_prmry_ndev(wl);
s32 txpwrdbm;
u8 result;
s32 err = 0;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
@@ -2275,14 +2329,14 @@ static s32
wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, bool unicast, bool multicast)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
u32 index;
s32 wsec;
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
WL_DBG(("key index (%d)\n", key_idx));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
if (unlikely(err)) {
WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
@@ -2305,7 +2359,7 @@ static s32
wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, const u8 *mac_addr, struct key_params *params)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct wl_wsec_key key;
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
@@ -2404,10 +2458,10 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
s32 err = 0;
u8 keybuf[8];
s32 bssidx = 0;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 mode = get_mode_by_netdev(wl, dev);
WL_DBG(("key index (%d)\n", key_idx));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
bssidx = wl_cfgp2p_find_idx(wl, dev);
@@ -2505,12 +2559,12 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct wl_wsec_key key;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
WL_DBG(("Enter\n"));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -2554,14 +2608,14 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
{
struct key_params params;
struct wl_wsec_key key;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct wl_security *sec;
s32 wsec;
s32 err = 0;
s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
WL_DBG(("key index (%d)\n", key_idx));
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
memset(&key, 0, sizeof(key));
key.index = key_idx;
swap_key_to_BE(&key);
@@ -2607,7 +2661,6 @@ wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
struct net_device *dev, u8 key_idx)
{
WL_INFO(("Not supported\n"));
- CHECK_SYS_UP();
return -EOPNOTSUPP;
}
@@ -2615,13 +2668,13 @@ static s32
wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_info *sinfo)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
scb_val_t scb_val;
int rssi;
s32 rate;
s32 err = 0;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
if (unlikely
(memcmp(mac, wl_read_prof(wl, WL_PROF_BSSID), ETHER_ADDR_LEN))) {
WL_ERR(("Wrong Mac address\n"));
@@ -2672,9 +2725,15 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
{
s32 pm;
s32 err = 0;
+ struct wl_priv *wl = wiphy_priv(wiphy);
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
pm = enabled ? PM_FAST : PM_OFF;
+ /* Do not enable the power save after assoc if it is p2p interface */
+ if (wl->p2p && wl->p2p->vif_created) {
+ WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n"));
+ pm = 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);
@@ -2717,7 +2776,7 @@ static __used u32 wl_find_msb(u16 bit16)
static s32 wl_cfg80211_resume(struct wiphy *wiphy)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 err = 0;
if (unlikely(!wl_get_drv_status(wl, READY))) {
@@ -2737,9 +2796,8 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
#endif
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 err = 0;
-
if (unlikely(!wl_get_drv_status(wl, READY))) {
WL_INFO(("device is not ready : status (%d)\n",
(int)wl->status));
@@ -2763,7 +2821,7 @@ 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 wl_priv *wl = wlcfg_drv_priv;
struct net_device *primary_dev = wl_to_prmry_ndev(wl);
/* Firmware is supporting pmk list only for STA interface i.e. primary interface
@@ -2771,7 +2829,7 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
* Do we really need to support PMK cache in P2P in firmware?
*/
if (primary_dev != dev) {
- WL_ERR(("Not supporting Flushing pmklist on virtual"
+ WL_INFO(("Not supporting Flushing pmklist on virtual"
" interfaces than primary interface\n"));
return err;
}
@@ -2796,11 +2854,11 @@ static s32
wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 err = 0;
int i;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
ETHER_ADDR_LEN))
@@ -2816,10 +2874,10 @@ wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
err = -EINVAL;
}
WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
- &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].BSSID));
+ &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID));
for (i = 0; i < WPA2_PMKID_LEN; i++) {
WL_DBG(("%02x\n",
- wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid].
+ wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].
PMKID[i]));
}
@@ -2832,12 +2890,12 @@ static s32
wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_pmksa *pmksa)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
struct _pmkid_list pmkid;
s32 err = 0;
int i;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
@@ -2878,9 +2936,9 @@ wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
static s32
wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
s32 err = 0;
- CHECK_SYS_UP();
+ CHECK_SYS_UP(wl);
memset(wl->pmk_list, 0, sizeof(*wl->pmk_list));
err = wl_update_pmklist(dev, wl->pmk_list, err);
return err;
@@ -2956,7 +3014,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
s32 target_channel;
s32 err = BCME_OK;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
if (likely(wl_get_drv_status(wl, SCANNING))) {
@@ -2976,12 +3034,12 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
* without turning on P2P
*/
+ p2p_on(wl) = true;
err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
if (unlikely(err)) {
goto exit;
}
- p2p_on(wl) = true;
}
if (p2p_on(wl))
wl_cfgp2p_discover_listen(wl, target_channel, duration);
@@ -3012,7 +3070,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
wifi_p2p_ie_t *p2p_ie;
wpa_ie_fixed_t *wps_ie;
const struct ieee80211_mgmt *mgmt;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wiphy_priv(wiphy);
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
s32 err = BCME_OK;
s32 bssidx = 0;
@@ -3467,7 +3525,7 @@ 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_priv *wl = wiphy_priv(wiphy);
struct wl_join_params join_params;
wpa_ie_fixed_t *wps_ie;
wpa_ie_fixed_t *wpa_ie;
@@ -3582,7 +3640,10 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
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);
+ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), false)) < 0) {
+ WL_ERR(("setting AP mode failed %d \n", err));
+ return err;
+ }
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
DOT11_MNG_RSN_ID)) != NULL) {
@@ -3757,7 +3818,6 @@ wl_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
static s32
wl_cfg80211_drv_start(struct wiphy *wiphy, struct net_device *dev)
{
- /* struct wl_priv *wl = wiphy_to_wl(wiphy); */
s32 err = 0;
printk("Android driver start command\n");
@@ -3767,7 +3827,6 @@ wl_cfg80211_drv_start(struct wiphy *wiphy, struct net_device *dev)
static s32
wl_cfg80211_drv_stop(struct wiphy *wiphy, struct net_device *dev)
{
- /* struct wl_priv *wl = wiphy_to_wl(wiphy); */
s32 err = 0;
printk("Android driver stop command\n");
@@ -3830,28 +3889,26 @@ static s32 wl_mode_to_nl80211_iftype(s32 mode)
return err;
}
-static struct wireless_dev *wl_alloc_wdev(s32 sizeof_iface,
- struct device *dev)
+static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
{
struct wireless_dev *wdev;
s32 err = 0;
- struct wl_priv *wl;
wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
if (unlikely(!wdev)) {
WL_ERR(("Could not allocate wireless device\n"));
return ERR_PTR(-ENOMEM);
}
wdev->wiphy =
- wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv) + sizeof_iface);
+ wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
if (unlikely(!wdev->wiphy)) {
WL_ERR(("Couldn not allocate wiphy device\n"));
err = -ENOMEM;
goto wiphy_new_out;
}
- set_wiphy_dev(wdev->wiphy, dev);
- wl = wiphy_to_wl(wdev->wiphy);
+ set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
- wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
+ /* Report how many SSIDs Driver can support per Scan request */
+ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
wdev->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
@@ -3899,7 +3956,7 @@ wiphy_new_out:
static void wl_free_wdev(struct wl_priv *wl)
{
int i;
- struct wireless_dev *wdev = wl_to_wdev(wl);
+ struct wireless_dev *wdev = wl->wdev;
if (unlikely(!wdev)) {
WL_ERR(("wdev is invalid\n"));
@@ -3913,9 +3970,9 @@ static void wl_free_wdev(struct wl_priv *wl)
}
}
wiphy_unregister(wdev->wiphy);
+ wdev->wiphy->dev.parent = NULL;
wiphy_free(wdev->wiphy);
kfree(wdev);
- wl_to_wdev(wl) = NULL;
}
static s32 wl_inform_bss(struct wl_priv *wl)
@@ -3926,13 +3983,6 @@ static s32 wl_inform_bss(struct wl_priv *wl)
s32 i;
bss_list = wl->bss_list;
-#if 0
- if (unlikely(bss_list->version != WL_BSS_INFO_VERSION)) {
- WL_ERR(("Version %d != WL_BSS_INFO_VERSION\n",
- bss_list->version));
- return -EOPNOTSUPP;
- }
-#endif
WL_DBG(("scanned AP count (%d)\n", bss_list->count));
bi = next_bss(bss_list, bi);
for_each_bss(bss_list, bi, i) {
@@ -4165,33 +4215,42 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
ntoh32(e->event_type), ntoh32(e->status)));
if (wl_is_linkup(wl, e, ndev)) {
wl_link_up(wl);
+ act = true;
+ wl_update_prof(wl, e, &act, WL_PROF_ACT);
if (wl_is_ibssmode(wl, ndev)) {
printk("cfg80211_ibss_joined");
cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
GFP_KERNEL);
WL_DBG(("joined in IBSS network\n"));
} else {
- printk("wl_bss_connect_done succeeded");
- wl_bss_connect_done(wl, ndev, e, data, true);
- WL_DBG(("joined in BSS network \"%s\"\n",
+ if (!wl_get_drv_status(wl, DISCONNECTING)) {
+ printk("wl_bss_connect_done succeeded");
+ wl_bss_connect_done(wl, ndev, e, data, true);
+ WL_DBG(("joined in BSS network \"%s\"\n",
((struct wlc_ssid *)
wl_read_prof(wl, WL_PROF_SSID))->SSID));
+ }
}
- act = true;
- wl_update_prof(wl, e, &act, WL_PROF_ACT);
+
} else if (wl_is_linkdown(wl, e)) {
+ if (wl->scan_request) {
+ if (wl->escan_on) {
+ wl_notify_escan_complete(wl, true);
+ } else
+ wl_iscan_aborted(wl);
+ }
if (wl_get_drv_status(wl, CONNECTED)) {
printk("link down, call cfg80211_disconnected ");
- rtnl_lock();
- cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
wl_clr_drv_status(wl, CONNECTED);
+ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
wl_link_down(wl);
wl_init_prof(wl->profile);
- rtnl_unlock();
} else if (wl_get_drv_status(wl, CONNECTING)) {
printk("link down, during connecting");
wl_bss_connect_done(wl, ndev, e, data, false);
}
+ wl_clr_drv_status(wl, DISCONNECTING);
+
} else if (wl_is_nonetwork(wl, e)) {
printk("connect failed e->status 0x%x", (int)ntoh32(e->status));
if (wl_get_drv_status(wl, CONNECTING))
@@ -4215,24 +4274,22 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
s32 err = 0;
u32 event = be32_to_cpu(e->event_type);
u32 status = be32_to_cpu(e->status);
-
WL_DBG(("Enter \n"));
if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
- if (test_bit(WL_STATUS_CONNECTED, &wl->status))
+ if (wl_get_drv_status(wl, CONNECTED))
wl_bss_roaming_done(wl, ndev, e, data);
else
wl_bss_connect_done(wl, ndev, e, data, true);
act = true;
wl_update_prof(wl, e, &act, WL_PROF_ACT);
}
-
return err;
}
static __used s32
wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
u32 buflen;
buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
@@ -4245,7 +4302,7 @@ static s32
wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
s32 buf_len)
{
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
u32 len;
s32 err = 0;
@@ -4279,6 +4336,14 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
assoc_info.req_len = htod32(assoc_info.req_len);
assoc_info.resp_len = htod32(assoc_info.resp_len);
assoc_info.flags = htod32(assoc_info.flags);
+ if (conn_info->req_ie_len) {
+ conn_info->req_ie_len = 0;
+ bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
+ }
+ if (conn_info->resp_ie_len) {
+ conn_info->resp_ie_len = 0;
+ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
+ }
if (assoc_info.req_len) {
err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
WL_ASSOC_INFO_MAX);
@@ -4290,11 +4355,15 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
conn_info->req_ie_len -= ETHER_ADDR_LEN;
}
- conn_info->req_ie =
- kmemdup(wl->extra_buf, conn_info->req_ie_len, GFP_KERNEL);
+ if (conn_info->req_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len);
+ else {
+ WL_ERR(("%s IE size %d above max %d size \n",
+ __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE));
+ return err;
+ }
} else {
conn_info->req_ie_len = 0;
- conn_info->req_ie = NULL;
}
if (assoc_info.resp_len) {
err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
@@ -4304,11 +4373,15 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
return err;
}
conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
- conn_info->resp_ie =
- kmemdup(wl->extra_buf, conn_info->resp_ie_len, GFP_KERNEL);
+ if (conn_info->resp_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len);
+ else {
+ WL_ERR(("%s IE size %d above max %d size \n",
+ __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE));
+ return err;
+ }
} else {
conn_info->resp_ie_len = 0;
- conn_info->resp_ie = NULL;
}
WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
conn_info->resp_ie_len));
@@ -4437,6 +4510,7 @@ wl_bss_roaming_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);
+ wl_update_pmklist(ndev, wl->pmk_list, err);
cfg80211_roamed(ndev,
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
NULL,
@@ -4459,11 +4533,18 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
s32 err = 0;
WL_DBG((" enter\n"));
- wl_get_assoc_ies(wl, ndev);
- memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
- wl_update_bss_info(wl, ndev);
+ if (wl->scan_request) {
+ wl_cfg80211_scan_abort(wl, ndev);
+ }
if (wl_get_drv_status(wl, CONNECTING)) {
wl_clr_drv_status(wl, CONNECTING);
+ if (completed) {
+ wl_get_assoc_ies(wl, ndev);
+ memcpy(&wl->bssid, &e->addr, ETHER_ADDR_LEN);
+ wl_update_bss_info(wl, ndev);
+ wl_update_pmklist(ndev, wl->pmk_list, err);
+ wl_set_drv_status(wl, CONNECTED);
+ }
cfg80211_connect_result(ndev,
(u8 *)&wl->bssid,
conn_info->req_ie,
@@ -4475,14 +4556,6 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
WL_DBG(("Report connect result - connection %s\n",
completed ? "succeeded" : "failed"));
}
- if (completed)
- wl_set_drv_status(wl, CONNECTED);
- else {
- if (wl->scan_request) {
- wl_cfg80211_scan_abort(wl, ndev);
- }
- }
-
return err;
}
@@ -4740,7 +4813,7 @@ static s32 wl_init_priv_mem(struct wl_priv *wl)
WL_ERR(("Ioctl buf alloc failed\n"));
goto init_priv_mem_out;
}
- wl->escan_ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+ wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
if (unlikely(!wl->escan_ioctl_buf)) {
WL_ERR(("Ioctl buf alloc failed\n"));
goto init_priv_mem_out;
@@ -4809,24 +4882,20 @@ static void wl_deinit_priv_mem(struct wl_priv *wl)
static s32 wl_create_event_handler(struct wl_priv *wl)
{
+ int ret = 0;
WL_DBG(("Enter \n"));
- sema_init(&wl->event_sync, 0);
- wl->event_tsk = kthread_run(wl_event_handler, wl, "wl_event_handler");
- if (IS_ERR(wl->event_tsk)) {
- wl->event_tsk = NULL;
- WL_ERR(("failed to create event thread\n"));
- return -ENOMEM;
- }
- return 0;
+
+ wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
+ PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
+ if (wl->event_tsk.thr_pid < 0)
+ ret = -ENOMEM;
+ return ret;
}
static void wl_destroy_event_handler(struct wl_priv *wl)
{
- if (wl->event_tsk) {
- send_sig(SIGTERM, wl->event_tsk, 1);
- kthread_stop(wl->event_tsk);
- wl->event_tsk = NULL;
- }
+ if (wl->event_tsk.thr_pid >= 0)
+ PROC_STOP(&wl->event_tsk);
}
static void wl_term_iscan(struct wl_priv *wl)
@@ -5046,6 +5115,7 @@ static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
wl_clr_drv_status(wl, SCANNING);
WL_ERR(("Scan complete while device not scanning\n"));
+ wl->scan_request = NULL;
return;
}
wl_clr_drv_status(wl, SCANNING);
@@ -5152,7 +5222,9 @@ static s32 wl_escan_handler(struct wl_priv *wl,
wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
if (likely(wl->scan_request)) {
rtnl_lock();
- WL_INFO(("ESCAN COMPLETED\n"));
+ WL_INFO(("ESCAN ABORTED\n"));
+ wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
+ wl_inform_bss(wl);
wl_notify_escan_complete(wl, true);
rtnl_unlock();
}
@@ -5251,7 +5323,7 @@ s32 wl_cfg80211_sysctl_export_devaddr(void *data)
* so that wpa_supplicant can access it
*/
dhd_pub_t *dhd = (dhd_pub_t *)data;
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
@@ -5271,7 +5343,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev)
WL_ERR(("ndev is invaild\n"));
return -ENODEV;
}
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
if (wl && !wl_get_drv_status(wl, READY)) {
if (wl->wdev &&
wl_cfgp2p_supported(wl, ndev)) {
@@ -5296,7 +5368,6 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
{
struct wireless_dev *wdev;
struct wl_priv *wl;
- struct wl_iface *ci;
s32 err = 0;
WL_TRACE(("In\n"));
@@ -5304,23 +5375,16 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
WL_ERR(("ndev is invaild\n"));
return -ENODEV;
}
- wl_cfg80211_dev = kzalloc(sizeof(struct wl_dev), GFP_KERNEL);
- if (unlikely(!wl_cfg80211_dev)) {
- WL_ERR(("wl_cfg80211_dev is invalid\n"));
- return -ENOMEM;
- }
WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
- wdev = wl_alloc_wdev(sizeof(struct wl_iface), &wl_cfg80211_get_sdio_func()->dev);
+ wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev);
if (unlikely(IS_ERR(wdev)))
return -ENOMEM;
wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
- wl = wdev_to_wl(wdev);
+ wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
wl->wdev = wdev;
wl->pub = data;
- ci = (struct wl_iface *)wl_to_ci(wl);
- ci->wl = wl;
ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
@@ -5343,7 +5407,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
goto cfg80211_attach_out;
}
#endif
- wl_set_drvdata(wl_cfg80211_dev, ci);
+ wlcfg_drv_priv = wl;
return err;
cfg80211_attach_out:
@@ -5356,7 +5420,7 @@ void wl_cfg80211_detach(void)
{
struct wl_priv *wl;
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
WL_TRACE(("In\n"));
#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
@@ -5367,29 +5431,30 @@ void wl_cfg80211_detach(void)
if (wl->p2p_supported)
wl_cfgp2p_deinit_priv(wl);
wl_deinit_priv(wl);
- wl_free_wdev(wl);
- wl_set_drvdata(wl_cfg80211_dev, NULL);
- kfree(wl_cfg80211_dev);
- wl_cfg80211_dev = NULL;
+ wlcfg_drv_priv = NULL;
wl_clear_sdio_func();
+ wl_free_wdev(wl);
}
static void wl_wakeup_event(struct wl_priv *wl)
{
- up(&wl->event_sync);
+ if (wl->event_tsk.thr_pid >= 0)
+ up(&wl->event_tsk.sema);
}
static s32 wl_event_handler(void *data)
{
struct net_device *netdev;
- struct wl_priv *wl = (struct wl_priv *)data;
- struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
+ struct wl_priv *wl = NULL;
struct wl_event_q *e;
+ tsk_ctl_t *tsk = (tsk_ctl_t *)data;
- sched_setscheduler(current, SCHED_FIFO, &param);
- allow_signal(SIGTERM);
- while (likely(!down_interruptible(&wl->event_sync))) {
- if (kthread_should_stop())
+ wl = (struct wl_priv *)tsk->parent;
+ complete(&tsk->completed);
+
+ while (down_interruptible (&tsk->sema) == 0) {
+ SMP_RD_BARRIER_DEPENDS();
+ if (tsk->terminated)
break;
e = wl_deq_event(wl);
if (unlikely(!e)) {
@@ -5400,7 +5465,7 @@ static s32 wl_event_handler(void *data)
netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
if (!netdev)
netdev = wl_to_prmry_ndev(wl);
- if (wl->evt_handler[e->etype]) {
+ if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
} else {
WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
@@ -5408,6 +5473,7 @@ static s32 wl_event_handler(void *data)
wl_put_event(e);
}
WL_DBG(("%s was terminated\n", __func__));
+ complete_and_exit(&tsk->completed, 0);
return 0;
}
@@ -5415,7 +5481,7 @@ void
wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
{
u32 event_type = ntoh32(e->event_type);
- struct wl_priv *wl = WL_PRIV_GET();
+ struct wl_priv *wl = wlcfg_drv_priv;
#if (WL_DBG_LEVEL > 0)
s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
@@ -5619,14 +5685,12 @@ static s32 wl_dongle_eventmsg(struct net_device *ndev)
setbit(eventmask, WLC_E_DISASSOC_IND);
setbit(eventmask, WLC_E_DISASSOC);
setbit(eventmask, WLC_E_JOIN);
+ setbit(eventmask, WLC_E_ROAM);
setbit(eventmask, WLC_E_ASSOC_IND);
- setbit(eventmask, WLC_E_PSK_SUP);
setbit(eventmask, WLC_E_LINK);
- setbit(eventmask, WLC_E_NDIS_LINK);
setbit(eventmask, WLC_E_MIC_ERROR);
setbit(eventmask, WLC_E_PMKID_CACHE);
setbit(eventmask, WLC_E_TXFAIL);
- setbit(eventmask, WLC_E_JOIN_START);
setbit(eventmask, WLC_E_SCAN_COMPLETE);
setbit(eventmask, WLC_E_ACTION_FRAME_RX);
setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE);
@@ -5997,27 +6061,24 @@ default_conf_out:
static s32 wl_update_wiphybands(struct wl_priv *wl)
{
struct wiphy *wiphy;
- s32 phy_list;
- s8 phy;
+ s8 phylist_buf[128];
+ s8 *phy;
s32 err = 0;
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, &phy_list,
- sizeof(phy_list), false);
+ err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
+ sizeof(phylist_buf), false);
if (unlikely(err)) {
WL_ERR(("error (%d)\n", err));
return err;
}
-
- phy = ((char *)&phy_list)[1];
- WL_DBG(("%c phy\n", phy));
- if (phy == 'a') {
- wiphy = wl_to_wiphy(wl);
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
- } else if (phy == 'n') {
- wiphy = wl_to_wiphy(wl);
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ phy = phylist_buf;
+ for (; *phy; phy++) {
+ if (*phy == 'a' || *phy == 'n') {
+ wiphy = wl_to_wiphy(wl);
+ wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &__wl_band_5ghz_a;
+ }
}
-
return err;
}
@@ -6056,7 +6117,9 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl)
wl_clr_drv_status(wl, READY);
wl_clr_drv_status(wl, SCANNING);
wl_clr_drv_status(wl, SCAN_ABORTING);
+ wl_clr_drv_status(wl, CONNECTING);
wl_clr_drv_status(wl, CONNECTED);
+ wl_clr_drv_status(wl, DISCONNECTING);
if (wl_get_drv_status(wl, AP_CREATED)) {
wl_clr_drv_status(wl, AP_CREATED);
wl_clr_drv_status(wl, AP_CREATING);
@@ -6081,7 +6144,7 @@ s32 wl_cfg80211_up(void)
s32 err = 0;
WL_TRACE(("In\n"));
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
err = __wl_cfg80211_up(wl);
@@ -6098,7 +6161,7 @@ s32 wl_cfg80211_down(void)
s32 err = 0;
WL_TRACE(("In\n"));
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
mutex_lock(&wl->usr_sync);
err = __wl_cfg80211_down(wl);
mutex_unlock(&wl->usr_sync);
@@ -6266,11 +6329,7 @@ static void wl_link_down(struct wl_priv *wl)
WL_DBG(("In\n"));
wl->link_up = false;
- kfree(conn_info->req_ie);
- conn_info->req_ie = NULL;
conn_info->req_ie_len = 0;
- kfree(conn_info->resp_ie);
- conn_info->resp_ie = NULL;
conn_info->resp_ie_len = 0;
}
@@ -6299,22 +6358,12 @@ static void wl_delay(u32 ms)
}
}
-static void wl_set_drvdata(struct wl_dev *dev, void *data)
-{
- dev->driver_data = data;
-}
-
-static void *wl_get_drvdata(struct wl_dev *dev)
-{
- return dev->driver_data;
-}
-
s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
{
const struct firmware *fw_entry;
struct wl_priv *wl;
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
fw_entry = wl->fw->fw_entry;
@@ -6330,7 +6379,7 @@ void wl_cfg80211_release_fw(void)
{
struct wl_priv *wl;
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
release_firmware(wl->fw->fw_entry);
wl->fw->ptr = 0;
}
@@ -6343,7 +6392,7 @@ void *wl_cfg80211_request_fw(s8 *file_name)
WL_TRACE(("In\n"));
WL_DBG(("file name : \"%s\"\n", file_name));
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
err = request_firmware(&wl->fw->fw_entry, file_name,
@@ -6388,7 +6437,7 @@ s8 *wl_cfg80211_get_fwname(void)
{
struct wl_priv *wl;
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
return wl->fw->fw_name;
}
@@ -6397,7 +6446,7 @@ s8 *wl_cfg80211_get_nvramname(void)
{
struct wl_priv *wl;
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
return wl->fw->nvram_name;
}
@@ -6408,7 +6457,7 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd
dhd_pub_t *dhd_pub;
struct ether_addr p2pif_addr;
- wl = WL_PRIV_GET();
+ wl = wlcfg_drv_priv;
dhd_pub = (dhd_pub_t *)wl->pub;
wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);