diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfg80211.c')
-rw-r--r-- | drivers/net/wireless/bcmdhd/wl_cfg80211.c | 854 |
1 files changed, 556 insertions, 298 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 2242a7adc0c..20bbb208291 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -1,9 +1,9 @@ /* * Linux cfg80211 driver * - * Copyright (C) 1999-2011, Broadcom Corporation + * Copyright (C) 1999-2012, Broadcom Corporation * - * Unless you and Broadcom execute a separate written software license + * 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 @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + * $Id: wl_cfg80211.c 310409 2012-01-24 18:47:09Z $ */ #include <typedefs.h> @@ -60,8 +60,41 @@ #include <wl_cfg80211.h> #include <wl_cfgp2p.h> +#ifdef BCMWAPI_WPI +/* these items should evetually go into wireless.h of the linux system headfile dir */ +#ifndef IW_ENCODE_ALG_SM4 +#define IW_ENCODE_ALG_SM4 0x20 +#endif + +#ifndef IW_AUTH_WAPI_ENABLED +#define IW_AUTH_WAPI_ENABLED 0x20 +#endif + +#ifndef IW_AUTH_WAPI_VERSION_1 +#define IW_AUTH_WAPI_VERSION_1 0x00000008 +#endif + +#ifndef IW_AUTH_CIPHER_SMS4 +#define IW_AUTH_CIPHER_SMS4 0x00000020 +#endif + +#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK +#define IW_AUTH_KEY_MGMT_WAPI_PSK 4 +#endif + +#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT +#define IW_AUTH_KEY_MGMT_WAPI_CERT 8 +#endif +#endif /* BCMWAPI_WPI */ + +#ifdef BCMWAPI_WPI +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED)) +#else /* BCMWAPI_WPI */ +#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED)) +#endif /* BCMWAPI_WPI */ + + static struct device *cfg80211_parent_dev = NULL; -static int vsdb_supported = 0; struct wl_priv *wlcfg_drv_priv = NULL; u32 wl_dbg_level = WL_DBG_ERR; @@ -69,17 +102,19 @@ u32 wl_dbg_level = WL_DBG_ERR; #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 1500 -#define WL_SCAN_ACTIVE_TIME 40 -#define WL_SCAN_PASSIVE_TIME 130 +#define WL_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ +#define WL_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ + +#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL + #define DNGL_FUNC(func, parameters) func parameters; #define COEX_DHCP - /* Set this to 1 to use a seperate interface (p2p0) * for p2p operations. */ -#define ENABLE_P2P_INTERFACE 1 +#define ENABLE_P2P_INTERFACE 0 /* This is to override regulatory domains defined in cfg80211 module (reg.c) * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN @@ -220,8 +255,6 @@ static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, const wl_event_msg_t *msg, void *data); static void wl_put_event(struct wl_event_q *e); static void wl_wakeup_event(struct wl_priv *wl); -static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data); static s32 wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); @@ -236,14 +269,16 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); -static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data); /* * register/deregister parent device */ static void wl_cfg80211_clear_parent_dev(void); /* + * ioctl utilites + */ + +/* * cfg80211 set_wiphy_params utilities */ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold); @@ -271,6 +306,10 @@ static s32 wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme); static s32 wl_set_set_sharedkey(struct net_device *dev, struct cfg80211_connect_params *sme); +#ifdef BCMWAPI_WPI +static s32 wl_set_set_wapi_ie(struct net_device *dev, + struct cfg80211_connect_params *sme); +#endif static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev); static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, size_t *join_params_size); @@ -285,7 +324,7 @@ static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); +static struct wireless_dev *wl_alloc_wdev(struct device *dev); static void wl_free_wdev(struct wl_priv *wl); static s32 wl_inform_bss(struct wl_priv *wl); @@ -376,18 +415,19 @@ 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 CHECK_SYS_UP(wlpriv) \ + +#define CHECK_SYS_UP(wlpriv) \ do { \ - struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ + struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \ - WL_INFO(("device is not ready\n")); \ - return -EIO; \ + WL_INFO(("device is not ready\n")); \ + return -EIO; \ } \ } while (0) -#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ - (akm) == RSN_AKM_UNSPECIFIED || \ +#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \ + (akm) == RSN_AKM_UNSPECIFIED || \ (akm) == RSN_AKM_PSK) @@ -539,8 +579,134 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, WLAN_CIPHER_SUITE_AES_CMAC, +#ifdef BCMWAPI_WPI + WLAN_CIPHER_SUITE_SMS4 +#endif }; +/* IOCtl version read from targeted driver */ +static int ioctl_version; + +/* Return a new chanspec given a legacy chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_from_legacy(chanspec_t legacy_chspec) +{ + chanspec_t chspec; + + /* get the channel number */ + chspec = LCHSPEC_CHANNEL(legacy_chspec); + + /* convert the band */ + if (LCHSPEC_IS2G(legacy_chspec)) { + chspec |= WL_CHANSPEC_BAND_2G; + } else { + chspec |= WL_CHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (LCHSPEC_IS20(legacy_chspec)) { + chspec |= WL_CHANSPEC_BW_20; + } else { + chspec |= WL_CHANSPEC_BW_40; + if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) { + chspec |= WL_CHANSPEC_CTL_SB_L; + } else { + chspec |= WL_CHANSPEC_CTL_SB_U; + } + } + + if (wf_chspec_malformed(chspec)) { + WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + return chspec; +} + +/* Return a legacy chanspec given a new chanspec + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_to_legacy(chanspec_t chspec) +{ + chanspec_t lchspec; + + if (wf_chspec_malformed(chspec)) { + WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n", + chspec)); + return INVCHANSPEC; + } + + /* get the channel number */ + lchspec = CHSPEC_CHANNEL(chspec); + + /* convert the band */ + if (CHSPEC_IS2G(chspec)) { + lchspec |= WL_LCHANSPEC_BAND_2G; + } else { + lchspec |= WL_LCHANSPEC_BAND_5G; + } + + /* convert the bw and sideband */ + if (CHSPEC_IS20(chspec)) { + lchspec |= WL_LCHANSPEC_BW_20; + lchspec |= WL_LCHANSPEC_CTL_SB_NONE; + } else if (CHSPEC_IS40(chspec)) { + lchspec |= WL_LCHANSPEC_BW_40; + if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) { + lchspec |= WL_LCHANSPEC_CTL_SB_LOWER; + } else { + lchspec |= WL_LCHANSPEC_CTL_SB_UPPER; + } + } else { + /* cannot express the bandwidth */ + char chanbuf[CHANSPEC_STR_LEN]; + WL_ERR(( + "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) " + "to pre-11ac format\n", + wf_chspec_ntoa(chspec, chanbuf), chspec)); + return INVCHANSPEC; + } + + return lchspec; +} + +/* given a chanspec value, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_host_to_driver(chanspec_t chanspec) +{ + if (ioctl_version == 1) { + chanspec = wl_chspec_to_legacy(chanspec); + if (chanspec == INVCHANSPEC) { + return chanspec; + } + } + chanspec = htodchanspec(chanspec); + + return chanspec; +} + +/* given a chanspec value from the driver, do the endian and chanspec version conversion to + * a chanspec_t value + * Returns INVCHANSPEC on error + */ +static chanspec_t +wl_chspec_driver_to_host(chanspec_t chanspec) +{ + chanspec = dtohchanspec(chanspec); + if (ioctl_version == 1) { + chanspec = wl_chspec_from_legacy(chanspec); + } + + return chanspec; +} + /* There isn't a lot of sense in it, but you can transmit anything you like */ static const struct ieee80211_txrx_stypes wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { @@ -691,47 +857,43 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc) static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) { - if (vsdb_supported) { + chanspec_t chspec; + int err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *dev = wl_to_prmry_ndev(wl); + struct ether_addr bssid; + struct wl_bss_info *bss = NULL; + + if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { + /* STA interface is not associated. So start the new interface on a temp + * channel . Later proper channel will be applied by the above framework + * via set_channel (cfg80211 API). + */ + WL_DBG(("Not associated. Return a temp channel. \n")); return wf_chspec_aton(WL_P2P_TEMP_CHAN); } - else { - chanspec_t chspec; - int err = 0; - struct wl_priv *wl = wiphy_priv(wiphy); - struct net_device *dev = wl_to_prmry_ndev(wl); - struct ether_addr bssid; - struct wl_bss_info *bss = NULL; - if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { - /* STA interface is not associated. So start the new interface on a temp - * channel . Later proper channel will be applied by the above framework - * via set_channel (cfg80211 API). - */ - WL_DBG(("Not associated. Return a temp channel. \n")); - return wf_chspec_aton(WL_P2P_TEMP_CHAN); - } - *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); - if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, - sizeof(WL_EXTRA_BUF_MAX), false))) { - WL_ERR(("Failed to get associated bss info, use temp channel \n")); - chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); - } - else { - bss = (struct wl_bss_info *) (wl->extra_buf + 4); - chspec = bss->chanspec; - WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec)); - } - return chspec; + *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, + sizeof(WL_EXTRA_BUF_MAX), false))) { + WL_ERR(("Failed to get associated bss info, use temp channel \n")); + chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + } + else { + bss = (struct wl_bss_info *) (wl->extra_buf + 4); + chspec = bss->chanspec; + WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec)); } + + return chspec; } static struct net_device* wl_cfg80211_add_monitor_if(char *name) { - int ret = 0; struct net_device* ndev = NULL; - ret = dhd_add_monitor(name, &ndev); + dhd_add_monitor(name, &ndev); WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev)); return ndev; } @@ -752,7 +914,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, int (*net_attach)(void *dhdp, int ifidx); bool rollback_lock = false; - /* Use primary I/F for sending cmds down to firmware */ + /* Use primary I/F for to send commands down */ _ndev = wl_to_prmry_ndev(wl); WL_DBG(("if name: %s, type: %d\n", name, type)); @@ -859,7 +1021,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, } vwdev->wiphy = wl->wdev->wiphy; WL_INFO((" virtual interface(%s) is created memalloc done \n", - wl->p2p->vir_ifname)); + wl->p2p->vir_ifname)); vwdev->iftype = type; _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); _ndev->ieee80211_ptr = vwdev; @@ -909,8 +1071,8 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) WL_DBG(("Enter\n")); if (wl->p2p_net == dev) { - /* Since there is no ifidx corresponding to p2p0, cmds to - * firmware should be routed through primary I/F + /* Since there is no ifidx corresponding to p2p0, + * all commands should be routed through primary I/F */ dev = wl_to_prmry_ndev(wl); } @@ -924,6 +1086,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) wldev_iovar_setint(dev, "mpc", 1); wl_set_p2p_status(wl, IF_DELETING); ret = wl_cfgp2p_ifdel(wl, &p2p_mac); +#if defined(DONGLEHOST) /* 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 @@ -937,6 +1100,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) "HANG Notification sent to %s\n", ret, ndev->name)); wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED); } +#endif /* defined(DONGLEHOST) */ /* Wait for any pending scan req to get aborted from the sysioc context */ timeout = wait_event_interruptible_timeout(wl->netif_change_event, @@ -960,8 +1124,6 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, { s32 ap = 0; s32 infra = 0; - s32 err = BCME_OK; - s32 timeout = -1; s32 wlif_type; s32 mode = 0; chanspec_t chspec; @@ -1011,8 +1173,8 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, ndev->name, ap, infra, type)); wl_set_p2p_status(wl, IF_CHANGING); wl_clr_p2p_status(wl, IF_CHANGED); - err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); - timeout = wait_event_interruptible_timeout(wl->netif_change_event, + wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); + wait_event_interruptible_timeout(wl->netif_change_event, (wl_get_p2p_status(wl, IF_CHANGED) == true), msecs_to_jiffies(MAX_WAIT_TIME)); wl_set_mode_by_netdev(wl, ndev, mode); @@ -1037,18 +1199,16 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, } s32 -wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, - void* _net_attach) +wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, void* _net_attach) { struct wl_priv *wl = wlcfg_drv_priv; s32 ret = BCME_OK; - WL_DBG(("Enter")); if (!ndev) { WL_ERR(("net is NULL\n")); return 0; } if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) { - WL_DBG(("IF_ADD event called from dongle, old interface name: %s," + WL_DBG(("IF_ADD event received, old interface name: %s," "new name: %s\n", ndev->name, wl->p2p->vir_ifname)); /* Assign the net device to CONNECT BSSCFG */ strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1); @@ -1071,7 +1231,6 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) struct wl_priv *wl = wlcfg_drv_priv; bool rollback_lock = false; s32 index = 0; - if (!ndev || !ndev->name) { WL_ERR(("net is NULL\n")); return 0; @@ -1092,7 +1251,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) if (rollback_lock) rtnl_unlock(); } - WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n", + WL_ERR(("IF_DEL event received, net %x, vif name: %s\n", (unsigned int)ndev, wl->p2p->vir_ifname)); memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ); @@ -1146,8 +1305,8 @@ wl_cfg80211_notify_ifchange(void) static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) { - u32 n_ssids; - u32 n_channels; + u32 n_ssids = request->n_ssids; + u32 n_channels = request->n_channels; u16 channel; chanspec_t chanspec; s32 i, offset; @@ -1176,13 +1335,6 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req params->passive_time = htod32(params->passive_time); params->home_time = htod32(params->home_time); - /* if request is null just exit so it will be all channel broadcast scan */ - if (!request) - return; - - n_ssids = request->n_ssids; - n_channels = request->n_channels; - /* Copy channel array if applicable */ WL_SCAN(("### List of channelspecs to scan ###\n")); if (n_channels > 0) { @@ -1268,10 +1420,12 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, } params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL); if (!params) { - return -ENOMEM; + err = -ENOMEM; + goto done; } - wl_scan_prep(¶ms->params, request); + if (request != NULL) + wl_scan_prep(¶ms->params, request); params->version = htod32(ISCAN_REQ_VERSION); params->action = htod16(action); @@ -1291,8 +1445,8 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, WL_ERR(("error (%d)\n", err)); } } -done: kfree(params); +done: return err; } @@ -1319,7 +1473,6 @@ static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request return err; } - static s32 wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) { @@ -1338,7 +1491,6 @@ wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) return err; } - static s32 wl_run_escan(struct wl_priv *wl, struct net_device *ndev, struct cfg80211_scan_request *request, uint16 action) @@ -1385,13 +1537,13 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, goto exit; } - wl_scan_prep(¶ms->params, request); + 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")); - kfree(params); err = -ENOMEM; goto exit; } @@ -1508,7 +1660,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, wpa_ie_fixed_t *wps_ie; s32 passive_scan; bool iscan_req; - bool escan_req; + bool escan_req = false; bool p2p_ssid; s32 err = 0; s32 i; @@ -1746,7 +1898,6 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) s32 err = 0; CHECK_SYS_UP(wl); - WL_DBG(("Enter\n")); if (changed & WIPHY_PARAM_RTS_THRESHOLD && (wl->conf->rts_threshold != wiphy->rts_threshold)) { wl->conf->rts_threshold = wiphy->rts_threshold; @@ -1776,6 +1927,7 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return err; } } + return err; } @@ -1886,6 +2038,13 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) if (is_wps_conn(sme)) val = WPA_AUTH_DISABLED; +#ifdef BCMWAPI_WPI + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + WL_DBG((" * wl_set_wpa_version, set wpa_auth" + " to WPA_AUTH_WAPI 0x400")); + val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED; + } +#endif WL_DBG(("setting wpa_auth to 0x%0x\n", val)); err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); if (unlikely(err)) { @@ -1897,6 +2056,30 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) return err; } +#ifdef BCMWAPI_WPI +static s32 +wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme) +{ + struct wl_priv *wl = wlcfg_drv_priv; + s32 err = 0; + s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + + WL_DBG((" %s \n", __FUNCTION__)); + + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", sme->ie, + sme->ie_len, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + + if (unlikely(err)) { + WL_ERR(("===> set_wapi_ie Error (%d)\n", err)); + return err; + } + } else + WL_DBG((" * skip \n")); + return err; +} +#endif /* BCMWAPI_WPI */ + static s32 wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) { @@ -1944,6 +2127,9 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) s32 pval = 0; s32 gval = 0; s32 err = 0; +#ifdef BCMWAPI_WPI + s32 val = 0; +#endif s32 bssidx = wl_cfgp2p_find_idx(wl, dev); if (sme->crypto.n_ciphers_pairwise) { @@ -1961,6 +2147,12 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) case WLAN_CIPHER_SUITE_AES_CMAC: pval = AES_ENABLED; break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + val = SMS4_ENABLED; + pval = SMS4_ENABLED; + break; +#endif default: WL_ERR(("invalid cipher pairwise (%d)\n", sme->crypto.ciphers_pairwise[0])); @@ -1982,6 +2174,12 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) case WLAN_CIPHER_SUITE_AES_CMAC: gval = AES_ENABLED; break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + val = SMS4_ENABLED; + gval = SMS4_ENABLED; + break; +#endif default: WL_ERR(("invalid cipher group (%d)\n", sme->crypto.cipher_group)); @@ -1994,9 +2192,18 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) if (is_wps_conn(sme)) { err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx); } else { - WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); - err = wldev_iovar_setint_bsscfg(dev, "wsec", +#ifdef BCMWAPI_WPI + if (sme->crypto.cipher_group == WLAN_CIPHER_SUITE_SMS4) { + WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED")); + err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx); + } else { +#endif + WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC")); + err = wldev_iovar_setint_bsscfg(dev, "wsec", pval | gval, bssidx); +#ifdef BCMWAPI_WPI + } +#endif } if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); @@ -2052,6 +2259,22 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) return -EINVAL; } } +#ifdef BCMWAPI_WPI + else if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_WAPI_CERT: + val = WAPI_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_WAPI_PSK: + val = WAPI_AUTH_PSK; + break; + default: + WL_ERR(("invalid cipher group (%d)\n", + sme->crypto.cipher_group)); + return -EINVAL; + } + } +#endif WL_DBG(("setting wpa_auth to %d\n", val)); err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx); @@ -2083,9 +2306,17 @@ wl_set_set_sharedkey(struct net_device *dev, WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions, sec->cipher_pairwise)); if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | +#ifdef BCMWAPI_WPI + NL80211_WPA_VERSION_2 | NL80211_WAPI_VERSION_1)) && +#else NL80211_WPA_VERSION_2)) && +#endif (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | +#ifdef BCMWAPI_WPI + WLAN_CIPHER_SUITE_WEP104 | WLAN_CIPHER_SUITE_SMS4))) +#else WLAN_CIPHER_SUITE_WEP104))) +#endif { memset(&key, 0, sizeof(key)); key.len = (u32) sme->key_len; @@ -2103,6 +2334,11 @@ wl_set_set_sharedkey(struct net_device *dev, case WLAN_CIPHER_SUITE_WEP104: key.algo = CRYPTO_ALGO_WEP128; break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + break; +#endif default: WL_ERR(("Invalid algorithm (%d)\n", sme->crypto.ciphers_pairwise[0])); @@ -2152,7 +2388,6 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, u32 chan_cnt = 0; u8 wpsie[IE_MAX_LEN]; struct ether_addr bssid; - WL_DBG(("In\n")); CHECK_SYS_UP(wl); @@ -2240,18 +2475,37 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, chan->center_freq)); } else wl->channel = 0; +#ifdef BCMWAPI_WPI + WL_DBG(("1. enable wapi auth\n")); + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) { + WL_DBG(("2. set wapi ie \n")); + err = wl_set_set_wapi_ie(dev, sme); + if (unlikely(err)) + return err; + } else + WL_DBG(("2. Not wapi ie \n")); +#endif WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len)); + WL_DBG(("3. set wapi version \n")); err = wl_set_wpa_version(dev, sme); if (unlikely(err)) { WL_ERR(("Invalid wpa_version\n")); return err; } - - err = wl_set_auth_type(dev, sme); - if (unlikely(err)) { - WL_ERR(("Invalid auth type\n")); - return err; +#ifdef BCMWAPI_WPI + if (sme->crypto.wpa_versions & NL80211_WAPI_VERSION_1) + WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n")); + else { + WL_DBG(("4. wl_set_auth_type\n")); +#endif + err = wl_set_auth_type(dev, sme); + if (unlikely(err)) { + WL_ERR(("Invalid auth type\n")); + return err; + } +#ifdef BCMWAPI_WPI } +#endif err = wl_set_set_cipher(dev, sme); if (unlikely(err)) { @@ -2313,7 +2567,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; ext_join_params->assoc.chanspec_list[0] |= chspec; ext_join_params->assoc.chanspec_list[0] = - htodchanspec(ext_join_params->assoc.chanspec_list[0]); + wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]); } ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num); if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { @@ -2576,6 +2830,12 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, key.algo = CRYPTO_ALGO_AES_CCM; WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + break; +#endif default: WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); return -EINVAL; @@ -2660,6 +2920,13 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, val = AES_ENABLED; WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n")); break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + val = SMS4_ENABLED; + break; +#endif /* BCMWAPI_WPI */ default: WL_ERR(("Invalid cipher (0x%x)\n", params->cipher)); return -EINVAL; @@ -2773,6 +3040,12 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n")); break; +#ifdef BCMWAPI_WPI + case WLAN_CIPHER_SUITE_SMS4: + key.algo = CRYPTO_ALGO_SMS4; + WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n")); + break; +#endif default: WL_ERR(("Invalid algo (0x%x)\n", wsec)); return -EINVAL; @@ -2804,7 +3077,6 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, s8 eabuf[ETHER_ADDR_STR_LEN]; #endif dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - CHECK_SYS_UP(wl); if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, @@ -2831,42 +3103,41 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta->idle * 1000)); #endif } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { - u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); - if (!wl_get_drv_status(wl, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL) == FALSE)) { - WL_ERR(("NOT assoc\n")); - err = -ENODEV; - goto get_station_err; - } - if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { - WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", - MAC2STR(mac), MAC2STR(curmacp))); - } - - /* Report the current tx rate */ - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); - if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); - } else { - rate = dtoh32(rate); - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_DBG(("Rate %d Mbps\n", (rate / 2))); - } + u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); + if (!wl_get_drv_status(wl, CONNECTED, dev) || + (dhd_is_associated(dhd, NULL) == FALSE)) { + WL_ERR(("NOT assoc\n")); + err = -ENODEV; + goto get_station_err; + } + if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { + WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", + MAC2STR(mac), MAC2STR(curmacp))); + } - memset(&scb_val, 0, sizeof(scb_val)); - scb_val.val = 0; - err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), false); - if (err) { - WL_ERR(("Could not get rssi (%d)\n", err)); - goto get_station_err; - } + /* Report the current tx rate */ + err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); + if (err) { + WL_ERR(("Could not get rate (%d)\n", err)); + } else { + rate = dtoh32(rate); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); + } - rssi = dtoh32(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_DBG(("RSSI %d dBm\n", rssi)); + memset(&scb_val, 0, sizeof(scb_val)); + scb_val.val = 0; + err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t), false); + if (err) { + WL_ERR(("Could not get rssi (%d)\n", err)); + goto get_station_err; + } + rssi = dtoh32(scb_val.val); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); get_station_err: if (err) { @@ -2968,7 +3239,6 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); unsigned long flags; - if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { WL_INFO(("device is not ready : status (%d)\n", (int)wl->status)); @@ -3009,8 +3279,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, return -EINVAL; } /* pmk list is supported only for STA interface i.e. primary interface - * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init - */ + * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init + */ if (primary_dev != dev) { WL_INFO(("Not supporting Flushing pmklist on virtual" " interfaces than primary interface\n")); @@ -3156,7 +3426,7 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) params->active_time = htod32(-1); params->passive_time = htod32(-1); params->home_time = htod32(10); - params->channel_list[0] = htodchanspec(channel); + params->channel_list[0] = wl_chspec_host_to_driver(channel); /* Our scan params have 1 channel and 0 ssids */ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) | @@ -3165,7 +3435,6 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) *out_params_size = params_size; /* rtn size to the caller */ return params; } - s32 wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) { @@ -3200,7 +3469,6 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) kfree(params); return err; } - static s32 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel * channel, @@ -3266,7 +3534,6 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex)); return err; } - static s32 wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) { @@ -3359,14 +3626,18 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *channel, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, - const u8* buf, size_t len, bool no_cck, - bool dont_wait_for_ack, u64 *cookie) + const u8* buf, size_t len, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) + bool no_cck, bool dont_wait_for_ack, +#endif + u64 *cookie) { wl_action_frame_t *action_frame; wl_af_params_t *af_params; wifi_p2p_ie_t *p2p_ie; wpa_ie_fixed_t *wps_ie; scb_val_t scb_val; + wifi_wfd_ie_t *wfd_ie; const struct ieee80211_mgmt *mgmt; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *dev = NULL; @@ -3374,6 +3645,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, s32 bssidx = 0; u32 p2pie_len = 0; u32 wpsie_len = 0; + u32 wfdie_len = 0; u32 id; u32 retry = 0; bool ack = false; @@ -3422,6 +3694,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, /* Total length of P2P Information Element */ p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); } + if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)(buf + ie_offset), ie_len)) + != NULL) { + /* Total length of WFD Information Element */ + wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id); + } if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len)) != NULL) { /* Order of Vendor IE is 1) WPS IE + @@ -3433,7 +3710,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, sizeof(wps_ie->tag); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_PRBRSP_FLAG, - (u8 *)wps_ie, wpsie_len + p2pie_len); + (u8 *)wps_ie, wpsie_len + p2pie_len + wfdie_len); } cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -3685,6 +3962,11 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) case WPA_CIPHER_AES_CCM: gval = AES_ENABLED; break; +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + gval = SMS4_ENABLED; + break; +#endif default: WL_ERR(("No Security Info\n")); break; @@ -3708,6 +3990,11 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) case WPA_CIPHER_AES_CCM: pval = AES_ENABLED; break; +#ifdef BCMWAPI_WPI + case WAPI_CIPHER_SMS4: + pval = SMS4_ENABLED; + break; +#endif default: WL_ERR(("No Security Info\n")); } @@ -3911,11 +4198,13 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, wpa_ie_fixed_t *wpa_ie; bcm_tlv_t *wpa2_ie; wifi_p2p_ie_t *p2p_ie; + wifi_wfd_ie_t *wfd_ie; bool is_bssup = false; bool update_bss = false; bool pbc = false; u16 wpsie_len = 0; u16 p2pie_len = 0; + u32 wfdie_len = 0; u8 beacon_ie[IE_MAX_LEN]; s32 ie_offset = 0; s32 bssidx = 0; @@ -3973,10 +4262,25 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, } else { WL_ERR(("No P2PIE in beacon \n")); } + + /* find the WFD IEs */ + if ((wfd_ie = wl_cfgp2p_find_wfdie((u8 *)info->tail, info->tail_len)) != NULL) { + /* Total length of P2P Information Element */ + wfdie_len = wfd_ie->len + sizeof(wfd_ie->len) + sizeof(wfd_ie->id); + if ((wpsie_len + p2pie_len + wfdie_len) < IE_MAX_LEN) { + memcpy(&beacon_ie[wpsie_len + p2pie_len], wfd_ie, wfdie_len); + } else { + WL_ERR(("Found WFD IE but there is no space, (%d)(%d)(%d)\n", + wpsie_len, p2pie_len, wfdie_len)); + wfdie_len = 0; + } + } else { + WL_ERR(("No WFDIE in beacon \n")); + } /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, - beacon_ie, wpsie_len + p2pie_len); + beacon_ie, wpsie_len + p2pie_len + wfdie_len); /* find the RSN_IE */ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, @@ -4081,7 +4385,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcpy(beacon_ie, wps_ie, wpsie_len); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, beacon_ie, wpsie_len); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else { @@ -4134,12 +4438,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) { WL_DBG((" WPS IE is changed\n")); kfree(wl->ap_info->wps_ie); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else if (wl->ap_info->wps_ie == NULL) { WL_DBG((" WPS IE is added\n")); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } @@ -4277,17 +4581,23 @@ s32 wl_mode_to_nl80211_iftype(s32 mode) return err; } -static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev) +static struct wireless_dev *wl_alloc_wdev(struct device *dev) { + struct wireless_dev *wdev; s32 err = 0; + 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)); if (unlikely(!wdev->wiphy)) { WL_ERR(("Couldn not allocate wiphy device\n")); err = -ENOMEM; - return err; + goto wiphy_new_out; } - set_wiphy_dev(wdev->wiphy, sdiofunc_dev); + set_wiphy_dev(wdev->wiphy, dev); wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; /* Report how many SSIDs Driver can support per Scan request */ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; @@ -4314,9 +4624,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | #endif WIPHY_FLAG_4ADDR_STATION; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; -#endif + WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); @@ -4324,9 +4632,17 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev err = wiphy_register(wdev->wiphy); if (unlikely(err < 0)) { WL_ERR(("Couldn not register wiphy device (%d)\n", err)); - wiphy_free(wdev->wiphy); + goto wiphy_register_out; } - return err; + return wdev; + +wiphy_register_out: + wiphy_free(wdev->wiphy); + +wiphy_new_out: + kfree(wdev); + + return ERR_PTR(err); } static void wl_free_wdev(struct wl_priv *wl) @@ -4421,6 +4737,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) u.beacon.variable) + wl_get_ielen(wl); #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) freq = ieee80211_channel_to_frequency(notif_bss_info->channel); + (void)band->band; #else freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band); #endif @@ -4433,7 +4750,6 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) notif_bss_info->frame_len)); signal = notif_bss_info->rssi * 100; - #if defined(WLP2P) && ENABLE_P2P_INTERFACE if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) { @@ -4516,136 +4832,91 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) return false; } -/* The mainline kernel >= 3.2.0 has support for indicating new/del station - * to AP/P2P GO via events. If this change is backported to kernel for which - * this driver is being built, set CFG80211_STA_EVENT_AVAILABLE to 1. You - * should use this new/del sta event mechanism for BRCM supplicant from BRANCH - * HOSTAP_BRANCH_0_15 (ver >= 15_1). - */ -#define CFG80211_STA_EVENT_AVAILABLE 0 static s32 -wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, +wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { + bool act; + bool isfree = false; s32 err = 0; + s32 freq; + s32 channel; + u8 body[200]; u32 event = ntoh32(e->event_type); u32 reason = ntoh32(e->reason); u32 len = ntoh32(e->datalen); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE - bool isfree = false; + u16 fc = 0; u8 *mgmt_frame; u8 bsscfgidx = e->bsscfgidx; - s32 freq; - s32 channel; - u8 body[200]; - u16 fc = 0; struct ieee80211_supported_band *band; struct ether_addr da; struct ether_addr bssid; struct wiphy *wiphy = wl_to_wiphy(wl); channel_info_t ci; -#else - struct station_info sinfo; -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE memset(body, 0, sizeof(body)); memset(&bssid, 0, ETHER_ADDR_LEN); WL_DBG(("Enter \n")); if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) return WL_INVALID; - memcpy(body, data, len); - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); - memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - switch (event) { - case WLC_E_ASSOC_IND: - fc = FC_ASSOC_REQ; - break; - case WLC_E_REASSOC_IND: - fc = FC_REASSOC_REQ; - break; - case WLC_E_DISASSOC_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH: - fc = FC_DISASSOC; - break; - default: - fc = 0; - goto exit; - } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) - return err; + if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { + memcpy(body, data, len); + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); + memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); + err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + switch (event) { + case WLC_E_ASSOC_IND: + fc = FC_ASSOC_REQ; + break; + case WLC_E_REASSOC_IND: + fc = FC_REASSOC_REQ; + break; + case WLC_E_DISASSOC_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH: + fc = FC_DISASSOC; + break; + default: + fc = 0; + goto exit; + } + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) + return err; - channel = dtoh32(ci.hw_channel); - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; + channel = dtoh32(ci.hw_channel); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); + freq = ieee80211_channel_to_frequency(channel); + (void)band->band; #else - freq = ieee80211_channel_to_frequency(channel, band->band); + freq = ieee80211_channel_to_frequency(channel, band->band); #endif - err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, + err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, &mgmt_frame, &len, body); - if (err < 0) - goto exit; - isfree = true; - - if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } + if (err < 0) + goto exit; + isfree = true; -exit: - if (isfree) - kfree(mgmt_frame); - return err; -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */ - sinfo.filled = 0; - if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && - reason == DOT11_SC_SUCCESS) { - sinfo.filled = STATION_INFO_ASSOC_REQ_IES; - if (!data) { - WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); - return -EINVAL; + if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); } - sinfo.assoc_req_ies = data; - sinfo.assoc_req_ies_len = len; - cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); - } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); - } -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */ - return err; -} -static s32 -wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - bool act; - s32 err = 0; - u32 event = ntoh32(e->event_type); - - if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { - wl_notify_connect_status_ap(wl, ndev, e, data); } else { WL_DBG(("wl_notify_connect_status : event %d status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); @@ -4717,6 +4988,9 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, printk("%s nothing\n", __FUNCTION__); } } +exit: + if (isfree) + kfree(mgmt_frame); return err; } @@ -4834,7 +5108,7 @@ static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params, join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK; join_params->params.chanspec_list[0] |= chanspec; join_params->params.chanspec_list[0] = - htodchanspec(join_params->params.chanspec_list[0]); + wl_chspec_host_to_driver(join_params->params.chanspec_list[0]); join_params->params.chanspec_num = htod32(join_params->params.chanspec_num); @@ -4858,6 +5132,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) u8 *curbssid; s32 err = 0; struct wiphy *wiphy; + wiphy = wl_to_wiphy(wl); if (wl_is_ibssmode(wl, ndev)) @@ -5010,19 +5285,6 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, } static s32 -wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, - const wl_event_msg_t *e, void *data) -{ - WL_ERR((" PNO Event\n")); - - mutex_lock(&wl->usr_sync); - /* TODO: Use cfg80211_sched_scan_results(wiphy); */ - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - mutex_unlock(&wl->usr_sync); - return 0; -} - -static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { @@ -5161,6 +5423,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) freq = ieee80211_channel_to_frequency(channel); + (void)band->band; #else freq = ieee80211_channel_to_frequency(channel, band->band); #endif @@ -5258,7 +5521,7 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; - wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; + } static s32 wl_init_priv_mem(struct wl_priv *wl) @@ -5565,7 +5828,6 @@ static void wl_scan_timeout(unsigned long data) wl_notify_iscan_complete(wl_to_iscan(wl), true); } } - static void wl_iscan_timer(unsigned long data) { struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; @@ -5629,7 +5891,6 @@ wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, static struct notifier_block wl_cfg80211_netdev_notifier = { .notifier_call = wl_cfg80211_netdev_notifier_call, }; - static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted) @@ -5713,7 +5974,8 @@ static s32 wl_escan_handler(struct wl_priv *wl, p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); if (p2p_dev_addr && !memcmp(p2p_dev_addr, wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) { - s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec)); + s32 channel = CHSPEC_CHANNEL( + wl_chspec_driver_to_host(bi->chanspec)); WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel)); wl_clr_p2p_status(wl, SCANNING); wl->afx_hdl->peer_chan = channel; @@ -5951,11 +6213,9 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) if (wl && !wl_get_drv_status(wl, READY, ndev)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { -#if !ENABLE_P2P_INTERFACE wl->wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO)); -#endif if ((err = wl_cfgp2p_init_priv(wl)) != 0) goto fail; @@ -5996,17 +6256,10 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) } WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); dev = wl_cfg80211_get_parent_dev(); - - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - return -ENOMEM; - } - err = wl_setup_wiphy(wdev, dev); - if (unlikely(err)) { - kfree(wdev); + wdev = wl_alloc_wdev(dev); + if (IS_ERR(wdev)) return -ENOMEM; - } + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); wl->wdev = wdev; @@ -6061,6 +6314,7 @@ void wl_cfg80211_detach(void *para) { struct wl_priv *wl; + (void)para; wl = wlcfg_drv_priv; WL_TRACE(("In\n")); @@ -6136,9 +6390,7 @@ static s32 wl_event_handler(void *data) tsk_ctl_t *tsk = (tsk_ctl_t *)data; wl = (struct wl_priv *)tsk->parent; - - DAEMONIZE("wl_event_handler"); - + DAEMONIZE("dhd_cfg80211_event"); complete(&tsk->completed); while (down_interruptible (&tsk->sema) == 0) { @@ -6184,6 +6436,11 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); #endif /* (WL_DBG_LEVEL > 0) */ + if (event_type == WLC_E_PFN_NET_FOUND) + WL_ERR((" PNOEVENT: PNO_NET_FOUND\n")); + else if (event_type == WLC_E_PFN_NET_LOST) + WL_ERR((" PNOEVENT: PNO_NET_LOST\n")); + if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) wl_wakeup_event(wl); } @@ -6443,15 +6700,33 @@ s32 wl_cfg80211_up(void *para) { struct wl_priv *wl; s32 err = 0; + int val = 0; + (void)para; WL_TRACE(("In\n")); wl = wlcfg_drv_priv; + + if ((err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_VERSION, &val, + sizeof(int), false) < 0)) { + WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err)); + return err; + } + val = dtoh32(val); + if (val != WLC_IOCTL_VERSION && val != 1) { + WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n", + val, WLC_IOCTL_VERSION)); + return BCME_VERSION; + } + ioctl_version = val; + WL_ERR(("WLC_GET_VERSION=%d\n", ioctl_version)); + mutex_lock(&wl->usr_sync); wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); err = __wl_cfg80211_up(wl); if (err) WL_ERR(("__wl_cfg80211_up failed\n")); mutex_unlock(&wl->usr_sync); + return err; } @@ -6474,6 +6749,7 @@ s32 wl_cfg80211_down(void *para) struct wl_priv *wl; s32 err = 0; + (void)para; WL_TRACE(("In\n")); wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); @@ -6688,7 +6964,6 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd struct wl_priv *wl = wlcfg_drv_priv; struct ether_addr p2pif_addr; struct ether_addr primary_mac; - if (!wl->p2p) return -1; if (!p2p_is_on(wl)) { @@ -6699,6 +6974,7 @@ s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pd wl->p2p->dev_addr.octet, ETHER_ADDR_LEN); } + return 0; } s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) @@ -6837,21 +7113,3 @@ static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); } - -int wl_cfg80211_do_driver_init(struct net_device *net) -{ - struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); - - if (!wl || !wl->wdev) - return -EINVAL; - - if (dhd_do_driver_init(wl->wdev->netdev) < 0) - return -1; - - return 0; -} - -void wl_cfg80211_enable_trace(int level) -{ - wl_dbg_level |= WL_DBG_DBG; -} |