From 93f379e6cfadfded0d262192ca69d1abc096d90e Mon Sep 17 00:00:00 2001 From: Benn Pörscke Date: Fri, 16 Dec 2011 15:04:55 +0100 Subject: Squash Change-Id: I2fcf46d1fc4b0cd4c61e5be3654c43b80db86015 --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 805 ++++++++++++++++-------------- 1 file changed, 427 insertions(+), 378 deletions(-) (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c') 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 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); @@ -364,12 +360,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 */ @@ -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 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(¶ms->bssid, ðer_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(¶ms->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(¶ms->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(¶ms->params, ssid); + if (request != NULL) + wl_scan_prep(¶ms->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(¶ms->params.bssid, ðer_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(¶ms->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, ðer_bcast, ETHER_ADDR_LEN); + if (sme->bssid) + memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); + else + memcpy(&join_params.params.bssid, ðer_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, ¶m); - 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); -- cgit v1.2.3