Loading drivers/net/wireless/ath/ath6kl/Makefile +2 −1 Original line number Original line Diff line number Diff line #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Copyright (c) 2004-2010 Atheros Communications Inc. # Copyright (c) 2004-2011 Atheros Communications Inc. # Copyright (c) 2011-2012 Qualcomm Atheros, Inc. # All rights reserved. # All rights reserved. # # # # Loading drivers/net/wireless/ath/ath6kl/bmi.c +4 −3 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading drivers/net/wireless/ath/ath6kl/bmi.h +24 −0 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info { __le32 type; /* target type */ __le32 type; /* target type */ } __packed; } __packed; #define ath6kl_bmi_write_hi32(ar, item, val) \ ({ \ u32 addr; \ __le32 v; \ \ addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ v = cpu_to_le32(val); \ ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \ }) #define ath6kl_bmi_read_hi32(ar, item, val) \ ({ \ u32 addr, *check_type = val; \ __le32 tmp; \ int ret; \ \ (void) (check_type == val); \ addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ *val = le32_to_cpu(tmp); \ ret; \ }) int ath6kl_bmi_init(struct ath6kl *ar); int ath6kl_bmi_init(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar); Loading drivers/net/wireless/ath/ath6kl/cfg80211.c +262 −80 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 #define ath6kl_g_rates_size 12 #define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_40) static struct ieee80211_channel ath6kl_2ghz_channels[] = { static struct ieee80211_channel ath6kl_2ghz_channels[] = { CHAN2G(1, 2412, 0), CHAN2G(1, 2412, 0), CHAN2G(2, 2417, 0), CHAN2G(2, 2417, 0), Loading Loading @@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { .channels = ath6kl_2ghz_channels, .channels = ath6kl_2ghz_channels, .n_bitrates = ath6kl_g_rates_size, .n_bitrates = ath6kl_g_rates_size, .bitrates = ath6kl_g_rates, .bitrates = ath6kl_g_rates, .ht_cap.cap = ath6kl_g_htcap, .ht_cap.ht_supported = true, }; }; static struct ieee80211_supported_band ath6kl_band_5ghz = { static struct ieee80211_supported_band ath6kl_band_5ghz = { Loading @@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, .bitrates = ath6kl_a_rates, .ht_cap.cap = ath6kl_g_htcap, .ht_cap.ht_supported = true, }; }; #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ Loading Loading @@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, return false; return false; } } static bool ath6kl_is_tx_pending(struct ath6kl *ar) { return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; } static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) struct cfg80211_connect_params *sme) { { Loading @@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); int status; int status; u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; u16 interval; ath6kl_cfg80211_sscan_disable(vif); ath6kl_cfg80211_sscan_disable(vif); Loading Loading @@ -450,7 +466,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * sleep until the command queue drains * sleep until the command queue drains */ */ wait_event_interruptible_timeout(ar->event_wq, wait_event_interruptible_timeout(ar->event_wq, ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, ath6kl_is_tx_pending(ar), WMI_TIMEOUT); WMI_TIMEOUT); if (signal_pending(current)) { if (signal_pending(current)) { ath6kl_err("cmd queue drain timeout\n"); ath6kl_err("cmd queue drain timeout\n"); Loading Loading @@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->grp_crypto_len, vif->ch_hint); vif->grp_crypto_len, vif->ch_hint); vif->reconnect_flag = 0; vif->reconnect_flag = 0; if (vif->nw_type == INFRA_NETWORK) { interval = max_t(u16, vif->listen_intvl_t, ATH6KL_MAX_WOW_LISTEN_INTL); status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, interval, 0); if (status) { ath6kl_err("couldn't set listen intervel\n"); up(&ar->sem); return status; } } status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, vif->dot11_auth_mode, vif->auth_mode, vif->dot11_auth_mode, vif->auth_mode, vif->prwise_crypto, vif->prwise_crypto, Loading @@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } } if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && ((vif->auth_mode == WPA_PSK_AUTH) ((vif->auth_mode == WPA_PSK_AUTH) || || (vif->auth_mode == WPA2_PSK_AUTH))) { (vif->auth_mode == WPA2_PSK_AUTH))) { mod_timer(&vif->disconnect_timer, mod_timer(&vif->disconnect_timer, jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); } } Loading Loading @@ -876,11 +906,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, request->ssids[i].ssid); request->ssids[i].ssid); } } /* /* this also clears IE in fw if it's not set */ * FIXME: we should clear the IE in fw if it's not set so just * remove the check altogether */ if (request->ie) { ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_REQ, WMI_FRAME_PROBE_REQ, request->ie, request->ie_len); request->ie, request->ie_len); Loading @@ -889,7 +915,6 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, "scan"); "scan"); return ret; return ret; } } } /* /* * Scan only the requested channels if the request specifies a set of * Scan only the requested channels if the request specifies a set of Loading Loading @@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, */ */ ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, WMI_LONG_SCAN, force_fg_scan, false, 0, 0, n_channels, false, 0, channels, request->no_cck, ATH6KL_FG_SCAN_INTERVAL, n_channels, channels, request->no_cck, request->rates); request->rates); } else { } else { ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, WMI_LONG_SCAN, force_fg_scan, false, 0, 0, n_channels, false, 0, channels); ATH6KL_FG_SCAN_INTERVAL, n_channels, channels); } } if (ret) if (ret) ath6kl_err("wmi_startscan_cmd failed\n"); ath6kl_err("wmi_startscan_cmd failed\n"); Loading Loading @@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return -ENOTSUPP; return -ENOTSUPP; } } if (((vif->auth_mode == WPA_PSK_AUTH) if (((vif->auth_mode == WPA_PSK_AUTH) || || (vif->auth_mode == WPA2_PSK_AUTH)) (vif->auth_mode == WPA2_PSK_AUTH)) && && (key_usage & GROUP_USAGE)) (key_usage & GROUP_USAGE)) del_timer(&vif->disconnect_timer); del_timer(&vif->disconnect_timer); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, Loading @@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (vif->nw_type == AP_NETWORK && !pairwise && if (vif->nw_type == AP_NETWORK && !pairwise && (key_type == TKIP_CRYPT || key_type == AES_CRYPT || (key_type == TKIP_CRYPT || key_type == AES_CRYPT || key_type == WAPI_CRYPT) && params) { key_type == WAPI_CRYPT)) { ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_type = key_type; ar->ap_mode_bkey.key_type = key_type; Loading Loading @@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, { { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; struct ath6kl_vif *vif; u8 ath6kl_dbm; int dbm = MBM_TO_DBM(mbm); int dbm = MBM_TO_DBM(mbm); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, Loading @@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, case NL80211_TX_POWER_AUTOMATIC: case NL80211_TX_POWER_AUTOMATIC: return 0; return 0; case NL80211_TX_POWER_LIMITED: case NL80211_TX_POWER_LIMITED: ar->tx_pwr = ath6kl_dbm = dbm; ar->tx_pwr = dbm; break; break; default: default: ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", Loading @@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, return -EOPNOTSUPP; return -EOPNOTSUPP; } } ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm); return 0; return 0; } } Loading Loading @@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) struct ath6kl_vif *vif; struct ath6kl_vif *vif; int ret, left; int ret, left; u32 filter = 0; u32 filter = 0; u16 i; u16 i, bmiss_time; u8 index = 0; u8 index = 0; __be32 ips[MAX_IP_ADDRS]; __be32 ips[MAX_IP_ADDRS]; Loading Loading @@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) if (ret) return ret; return ret; netif_stop_queue(vif->ndev); if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_MAX_WOW_LISTEN_INTL, 0); if (ret) return ret; /* Set listen interval x 15 times as bmiss time */ bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15; if (bmiss_time > ATH6KL_MAX_BMISS_TIME) bmiss_time = ATH6KL_MAX_BMISS_TIME; ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, bmiss_time, 0); if (ret) return ret; ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0, 0, 0); if (ret) return ret; } ar->state = ATH6KL_STATE_SUSPENDING; /* Setup own IP addr for ARP agent. */ /* Setup own IP addr for ARP agent. */ in_dev = __in_dev_get_rtnl(vif->ndev); in_dev = __in_dev_get_rtnl(vif->ndev); if (!in_dev) if (!in_dev) Loading Loading @@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar) if (!vif) if (!vif) return -EIO; return -EIO; ar->state = ATH6KL_STATE_RESUMING; ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); ATH6KL_HOST_MODE_AWAKE); if (ret) { ath6kl_warn("Failed to configure host sleep mode for " "wow resume: %d\n", ret); ar->state = ATH6KL_STATE_WOW; return ret; } if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); if (ret) return ret; ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, vif->listen_intvl_t, 0); if (ret) return ret; ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, vif->bmiss_time_t, 0); if (ret) return ret; return ret; } } ar->state = ATH6KL_STATE_ON; netif_wake_queue(vif->ndev); return 0; } int ath6kl_cfg80211_suspend(struct ath6kl *ar, int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) struct cfg80211_wowlan *wow) { { enum ath6kl_state prev_state; int ret; int ret; switch (mode) { switch (mode) { Loading @@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, /* Flush all non control pkts in TX path */ /* Flush all non control pkts in TX path */ ath6kl_tx_data_cleanup(ar); ath6kl_tx_data_cleanup(ar); prev_state = ar->state; ret = ath6kl_wow_suspend(ar, wow); ret = ath6kl_wow_suspend(ar, wow); if (ret) { if (ret) { ath6kl_err("wow suspend failed: %d\n", ret); ar->state = prev_state; return ret; return ret; } } ar->state = ATH6KL_STATE_WOW; ar->state = ATH6KL_STATE_WOW; break; break; Loading Loading @@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) return ret; return ret; } } ar->state = ATH6KL_STATE_ON; break; break; case ATH6KL_STATE_DEEPSLEEP: case ATH6KL_STATE_DEEPSLEEP: Loading Loading @@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) */ */ void ath6kl_check_wow_status(struct ath6kl *ar) void ath6kl_check_wow_status(struct ath6kl *ar) { { if (ar->state == ATH6KL_STATE_SUSPENDING) return; if (ar->state == ATH6KL_STATE_WOW) if (ar->state == ATH6KL_STATE_WOW) ath6kl_cfg80211_resume(ar); ath6kl_cfg80211_resume(ar); } } Loading Loading @@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, struct ath6kl *ar = vif->ar; struct ath6kl *ar = vif->ar; int res; int res; if (info->beacon_ies) { /* this also clears IE in fw if it's not set */ res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_BEACON, WMI_FRAME_BEACON, info->beacon_ies, info->beacon_ies, info->beacon_ies_len); info->beacon_ies_len); if (res) if (res) return res; return res; } if (info->proberesp_ies) { /* this also clears IE in fw if it's not set */ res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, info->proberesp_ies_len); info->proberesp_ies_len); if (res) if (res) return res; return res; } if (info->assocresp_ies) { /* this also clears IE in fw if it's not set */ res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_ASSOC_RESP, WMI_FRAME_ASSOC_RESP, info->assocresp_ies, info->assocresp_ies, info->assocresp_ies_len); info->assocresp_ies_len); if (res) if (res) return res; return res; } return 0; return 0; } } Loading @@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt; bool hidden = false; u8 *ies; u8 *ies; int ies_len; int ies_len; struct wmi_connect_cmd p; struct wmi_connect_cmd p; Loading Loading @@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, memcpy(vif->ssid, info->ssid, info->ssid_len); memcpy(vif->ssid, info->ssid, info->ssid_len); vif->ssid_len = info->ssid_len; vif->ssid_len = info->ssid_len; if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) return -EOPNOTSUPP; /* TODO */ hidden = true; res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden); if (res) return res; ret = ath6kl_set_auth_type(vif, info->auth_type); ret = ath6kl_set_auth_type(vif, info->auth_type); if (ret) if (ret) Loading Loading @@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, return ret; return ret; } } static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, u32 id, u32 freq, u32 wait, const u8 *buf, size_t len, bool *more_data, bool no_cck) { struct ieee80211_mgmt *mgmt; struct ath6kl_sta *conn; bool is_psq_empty = false; struct ath6kl_mgmt_buff *mgmt_buf; size_t mgmt_buf_size; struct ath6kl *ar = vif->ar; mgmt = (struct ieee80211_mgmt *) buf; if (is_multicast_ether_addr(mgmt->da)) return false; conn = ath6kl_find_sta(vif, mgmt->da); if (!conn) return false; if (conn->sta_flags & STA_PS_SLEEP) { if (!(conn->sta_flags & STA_PS_POLLED)) { /* Queue the frames if the STA is sleeping */ mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff); mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL); if (!mgmt_buf) return false; INIT_LIST_HEAD(&mgmt_buf->list); mgmt_buf->id = id; mgmt_buf->freq = freq; mgmt_buf->wait = wait; mgmt_buf->len = len; mgmt_buf->no_cck = no_cck; memcpy(mgmt_buf->buf, buf, len); spin_lock_bh(&conn->psq_lock); is_psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); list_add_tail(&mgmt_buf->list, &conn->mgmt_psq); conn->mgmt_psq_len++; spin_unlock_bh(&conn->psq_lock); /* * If this is the first pkt getting queued * for this STA, update the PVB for this * STA. */ if (is_psq_empty) ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, conn->aid, 1); return true; } /* * This tx is because of a PsPoll. * Determine if MoreData bit has to be set. */ spin_lock_bh(&conn->psq_lock); if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0)) *more_data = true; spin_unlock_bh(&conn->psq_lock); } return false; } static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type, Loading @@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); u32 id; u32 id; const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt; bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; mgmt = (const struct ieee80211_mgmt *) buf; if (buf + len >= mgmt->u.probe_resp.variable && if (buf + len >= mgmt->u.probe_resp.variable && Loading @@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, *cookie = id; *cookie = id; if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, /* AP mode Power saving processing */ ar->fw_capabilities)) { if (vif->nw_type == AP_NETWORK) { /* queued = ath6kl_mgmt_powersave_ap(vif, * If capable of doing P2P mgmt operations using id, chan->center_freq, * station interface, send additional information like wait, buf, * supported rates to advertise and xmit rates for len, &more_data, no_cck); * probe requests if (queued) */ return 0; } return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, chan->center_freq, wait, chan->center_freq, wait, buf, len, no_cck); buf, len, no_cck); } else { return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id, chan->center_freq, wait, buf, len); } } } static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, Loading Loading @@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->wdev.netdev = ndev; vif->wdev.netdev = ndev; vif->wdev.iftype = type; vif->wdev.iftype = type; vif->fw_vif_idx = fw_vif_idx; vif->fw_vif_idx = fw_vif_idx; vif->nw_type = vif->next_mode = nw_type; vif->nw_type = nw_type; vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) if (fw_vif_idx != 0) Loading Loading @@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) wiphy->max_sched_scan_ssids = 10; wiphy->max_sched_scan_ssids = 10; ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; ret = wiphy_register(wiphy); ret = wiphy_register(wiphy); if (ret < 0) { if (ret < 0) { ath6kl_err("couldn't register wiphy device\n"); ath6kl_err("couldn't register wiphy device\n"); return ret; return ret; } } ar->wiphy_registered = true; return 0; return 0; } } void ath6kl_cfg80211_cleanup(struct ath6kl *ar) void ath6kl_cfg80211_cleanup(struct ath6kl *ar) { { wiphy_unregister(ar->wiphy); wiphy_unregister(ar->wiphy); ar->wiphy_registered = false; } } struct ath6kl *ath6kl_cfg80211_create(void) struct ath6kl *ath6kl_cfg80211_create(void) Loading drivers/net/wireless/ath/ath6kl/cfg80211.h +1 −0 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading Loading
drivers/net/wireless/ath/ath6kl/Makefile +2 −1 Original line number Original line Diff line number Diff line #------------------------------------------------------------------------------ #------------------------------------------------------------------------------ # Copyright (c) 2004-2010 Atheros Communications Inc. # Copyright (c) 2004-2011 Atheros Communications Inc. # Copyright (c) 2011-2012 Qualcomm Atheros, Inc. # All rights reserved. # All rights reserved. # # # # Loading
drivers/net/wireless/ath/ath6kl/bmi.c +4 −3 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading
drivers/net/wireless/ath/ath6kl/bmi.h +24 −0 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -222,6 +223,29 @@ struct ath6kl_bmi_target_info { __le32 type; /* target type */ __le32 type; /* target type */ } __packed; } __packed; #define ath6kl_bmi_write_hi32(ar, item, val) \ ({ \ u32 addr; \ __le32 v; \ \ addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ v = cpu_to_le32(val); \ ath6kl_bmi_write(ar, addr, (u8 *) &v, sizeof(v)); \ }) #define ath6kl_bmi_read_hi32(ar, item, val) \ ({ \ u32 addr, *check_type = val; \ __le32 tmp; \ int ret; \ \ (void) (check_type == val); \ addr = ath6kl_get_hi_item_addr(ar, HI_ITEM(item)); \ ret = ath6kl_bmi_read(ar, addr, (u8 *) &tmp, 4); \ *val = le32_to_cpu(tmp); \ ret; \ }) int ath6kl_bmi_init(struct ath6kl *ar); int ath6kl_bmi_init(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_cleanup(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar); void ath6kl_bmi_reset(struct ath6kl *ar); Loading
drivers/net/wireless/ath/ath6kl/cfg80211.c +262 −80 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2004-2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading Loading @@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates (ath6kl_rates + 0) #define ath6kl_g_rates_size 12 #define ath6kl_g_rates_size 12 #define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ IEEE80211_HT_CAP_SGI_20 | \ IEEE80211_HT_CAP_SGI_40) static struct ieee80211_channel ath6kl_2ghz_channels[] = { static struct ieee80211_channel ath6kl_2ghz_channels[] = { CHAN2G(1, 2412, 0), CHAN2G(1, 2412, 0), CHAN2G(2, 2417, 0), CHAN2G(2, 2417, 0), Loading Loading @@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { .channels = ath6kl_2ghz_channels, .channels = ath6kl_2ghz_channels, .n_bitrates = ath6kl_g_rates_size, .n_bitrates = ath6kl_g_rates_size, .bitrates = ath6kl_g_rates, .bitrates = ath6kl_g_rates, .ht_cap.cap = ath6kl_g_htcap, .ht_cap.ht_supported = true, }; }; static struct ieee80211_supported_band ath6kl_band_5ghz = { static struct ieee80211_supported_band ath6kl_band_5ghz = { Loading @@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { .channels = ath6kl_5ghz_a_channels, .channels = ath6kl_5ghz_a_channels, .n_bitrates = ath6kl_a_rates_size, .n_bitrates = ath6kl_a_rates_size, .bitrates = ath6kl_a_rates, .bitrates = ath6kl_a_rates, .ht_cap.cap = ath6kl_g_htcap, .ht_cap.ht_supported = true, }; }; #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ Loading Loading @@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, return false; return false; } } static bool ath6kl_is_tx_pending(struct ath6kl *ar) { return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; } static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) struct cfg80211_connect_params *sme) { { Loading @@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); int status; int status; u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; u16 interval; ath6kl_cfg80211_sscan_disable(vif); ath6kl_cfg80211_sscan_disable(vif); Loading Loading @@ -450,7 +466,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * sleep until the command queue drains * sleep until the command queue drains */ */ wait_event_interruptible_timeout(ar->event_wq, wait_event_interruptible_timeout(ar->event_wq, ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, ath6kl_is_tx_pending(ar), WMI_TIMEOUT); WMI_TIMEOUT); if (signal_pending(current)) { if (signal_pending(current)) { ath6kl_err("cmd queue drain timeout\n"); ath6kl_err("cmd queue drain timeout\n"); Loading Loading @@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->grp_crypto_len, vif->ch_hint); vif->grp_crypto_len, vif->ch_hint); vif->reconnect_flag = 0; vif->reconnect_flag = 0; if (vif->nw_type == INFRA_NETWORK) { interval = max_t(u16, vif->listen_intvl_t, ATH6KL_MAX_WOW_LISTEN_INTL); status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, interval, 0); if (status) { ath6kl_err("couldn't set listen intervel\n"); up(&ar->sem); return status; } } status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, vif->dot11_auth_mode, vif->auth_mode, vif->dot11_auth_mode, vif->auth_mode, vif->prwise_crypto, vif->prwise_crypto, Loading @@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } } if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && ((vif->auth_mode == WPA_PSK_AUTH) ((vif->auth_mode == WPA_PSK_AUTH) || || (vif->auth_mode == WPA2_PSK_AUTH))) { (vif->auth_mode == WPA2_PSK_AUTH))) { mod_timer(&vif->disconnect_timer, mod_timer(&vif->disconnect_timer, jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); } } Loading Loading @@ -876,11 +906,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, request->ssids[i].ssid); request->ssids[i].ssid); } } /* /* this also clears IE in fw if it's not set */ * FIXME: we should clear the IE in fw if it's not set so just * remove the check altogether */ if (request->ie) { ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_REQ, WMI_FRAME_PROBE_REQ, request->ie, request->ie_len); request->ie, request->ie_len); Loading @@ -889,7 +915,6 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, "scan"); "scan"); return ret; return ret; } } } /* /* * Scan only the requested channels if the request specifies a set of * Scan only the requested channels if the request specifies a set of Loading Loading @@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, */ */ ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, WMI_LONG_SCAN, force_fg_scan, false, 0, 0, n_channels, false, 0, channels, request->no_cck, ATH6KL_FG_SCAN_INTERVAL, n_channels, channels, request->no_cck, request->rates); request->rates); } else { } else { ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, WMI_LONG_SCAN, force_fg_scan, WMI_LONG_SCAN, force_fg_scan, false, 0, 0, n_channels, false, 0, channels); ATH6KL_FG_SCAN_INTERVAL, n_channels, channels); } } if (ret) if (ret) ath6kl_err("wmi_startscan_cmd failed\n"); ath6kl_err("wmi_startscan_cmd failed\n"); Loading Loading @@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, return -ENOTSUPP; return -ENOTSUPP; } } if (((vif->auth_mode == WPA_PSK_AUTH) if (((vif->auth_mode == WPA_PSK_AUTH) || || (vif->auth_mode == WPA2_PSK_AUTH)) (vif->auth_mode == WPA2_PSK_AUTH)) && && (key_usage & GROUP_USAGE)) (key_usage & GROUP_USAGE)) del_timer(&vif->disconnect_timer); del_timer(&vif->disconnect_timer); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, Loading @@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, if (vif->nw_type == AP_NETWORK && !pairwise && if (vif->nw_type == AP_NETWORK && !pairwise && (key_type == TKIP_CRYPT || key_type == AES_CRYPT || (key_type == TKIP_CRYPT || key_type == AES_CRYPT || key_type == WAPI_CRYPT) && params) { key_type == WAPI_CRYPT)) { ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.valid = true; ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_index = key_index; ar->ap_mode_bkey.key_type = key_type; ar->ap_mode_bkey.key_type = key_type; Loading Loading @@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, { { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; struct ath6kl_vif *vif; u8 ath6kl_dbm; int dbm = MBM_TO_DBM(mbm); int dbm = MBM_TO_DBM(mbm); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, Loading @@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, case NL80211_TX_POWER_AUTOMATIC: case NL80211_TX_POWER_AUTOMATIC: return 0; return 0; case NL80211_TX_POWER_LIMITED: case NL80211_TX_POWER_LIMITED: ar->tx_pwr = ath6kl_dbm = dbm; ar->tx_pwr = dbm; break; break; default: default: ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", Loading @@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, return -EOPNOTSUPP; return -EOPNOTSUPP; } } ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm); return 0; return 0; } } Loading Loading @@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) struct ath6kl_vif *vif; struct ath6kl_vif *vif; int ret, left; int ret, left; u32 filter = 0; u32 filter = 0; u16 i; u16 i, bmiss_time; u8 index = 0; u8 index = 0; __be32 ips[MAX_IP_ADDRS]; __be32 ips[MAX_IP_ADDRS]; Loading Loading @@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (ret) if (ret) return ret; return ret; netif_stop_queue(vif->ndev); if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_MAX_WOW_LISTEN_INTL, 0); if (ret) return ret; /* Set listen interval x 15 times as bmiss time */ bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15; if (bmiss_time > ATH6KL_MAX_BMISS_TIME) bmiss_time = ATH6KL_MAX_BMISS_TIME; ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, bmiss_time, 0); if (ret) return ret; ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0, 0, 0); if (ret) return ret; } ar->state = ATH6KL_STATE_SUSPENDING; /* Setup own IP addr for ARP agent. */ /* Setup own IP addr for ARP agent. */ in_dev = __in_dev_get_rtnl(vif->ndev); in_dev = __in_dev_get_rtnl(vif->ndev); if (!in_dev) if (!in_dev) Loading Loading @@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar) if (!vif) if (!vif) return -EIO; return -EIO; ar->state = ATH6KL_STATE_RESUMING; ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); ATH6KL_HOST_MODE_AWAKE); if (ret) { ath6kl_warn("Failed to configure host sleep mode for " "wow resume: %d\n", ret); ar->state = ATH6KL_STATE_WOW; return ret; } if (vif->nw_type != AP_NETWORK) { ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); if (ret) return ret; ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, vif->listen_intvl_t, 0); if (ret) return ret; ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, vif->bmiss_time_t, 0); if (ret) return ret; return ret; } } ar->state = ATH6KL_STATE_ON; netif_wake_queue(vif->ndev); return 0; } int ath6kl_cfg80211_suspend(struct ath6kl *ar, int ath6kl_cfg80211_suspend(struct ath6kl *ar, enum ath6kl_cfg_suspend_mode mode, enum ath6kl_cfg_suspend_mode mode, struct cfg80211_wowlan *wow) struct cfg80211_wowlan *wow) { { enum ath6kl_state prev_state; int ret; int ret; switch (mode) { switch (mode) { Loading @@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, /* Flush all non control pkts in TX path */ /* Flush all non control pkts in TX path */ ath6kl_tx_data_cleanup(ar); ath6kl_tx_data_cleanup(ar); prev_state = ar->state; ret = ath6kl_wow_suspend(ar, wow); ret = ath6kl_wow_suspend(ar, wow); if (ret) { if (ret) { ath6kl_err("wow suspend failed: %d\n", ret); ar->state = prev_state; return ret; return ret; } } ar->state = ATH6KL_STATE_WOW; ar->state = ATH6KL_STATE_WOW; break; break; Loading Loading @@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) return ret; return ret; } } ar->state = ATH6KL_STATE_ON; break; break; case ATH6KL_STATE_DEEPSLEEP: case ATH6KL_STATE_DEEPSLEEP: Loading Loading @@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) */ */ void ath6kl_check_wow_status(struct ath6kl *ar) void ath6kl_check_wow_status(struct ath6kl *ar) { { if (ar->state == ATH6KL_STATE_SUSPENDING) return; if (ar->state == ATH6KL_STATE_WOW) if (ar->state == ATH6KL_STATE_WOW) ath6kl_cfg80211_resume(ar); ath6kl_cfg80211_resume(ar); } } Loading Loading @@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, struct ath6kl *ar = vif->ar; struct ath6kl *ar = vif->ar; int res; int res; if (info->beacon_ies) { /* this also clears IE in fw if it's not set */ res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_BEACON, WMI_FRAME_BEACON, info->beacon_ies, info->beacon_ies, info->beacon_ies_len); info->beacon_ies_len); if (res) if (res) return res; return res; } if (info->proberesp_ies) { /* this also clears IE in fw if it's not set */ res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, info->proberesp_ies_len); info->proberesp_ies_len); if (res) if (res) return res; return res; } if (info->assocresp_ies) { /* this also clears IE in fw if it's not set */ res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_ASSOC_RESP, WMI_FRAME_ASSOC_RESP, info->assocresp_ies, info->assocresp_ies, info->assocresp_ies_len); info->assocresp_ies_len); if (res) if (res) return res; return res; } return 0; return 0; } } Loading @@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt; bool hidden = false; u8 *ies; u8 *ies; int ies_len; int ies_len; struct wmi_connect_cmd p; struct wmi_connect_cmd p; Loading Loading @@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, memcpy(vif->ssid, info->ssid, info->ssid_len); memcpy(vif->ssid, info->ssid, info->ssid_len); vif->ssid_len = info->ssid_len; vif->ssid_len = info->ssid_len; if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) return -EOPNOTSUPP; /* TODO */ hidden = true; res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden); if (res) return res; ret = ath6kl_set_auth_type(vif, info->auth_type); ret = ath6kl_set_auth_type(vif, info->auth_type); if (ret) if (ret) Loading Loading @@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, return ret; return ret; } } static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, u32 id, u32 freq, u32 wait, const u8 *buf, size_t len, bool *more_data, bool no_cck) { struct ieee80211_mgmt *mgmt; struct ath6kl_sta *conn; bool is_psq_empty = false; struct ath6kl_mgmt_buff *mgmt_buf; size_t mgmt_buf_size; struct ath6kl *ar = vif->ar; mgmt = (struct ieee80211_mgmt *) buf; if (is_multicast_ether_addr(mgmt->da)) return false; conn = ath6kl_find_sta(vif, mgmt->da); if (!conn) return false; if (conn->sta_flags & STA_PS_SLEEP) { if (!(conn->sta_flags & STA_PS_POLLED)) { /* Queue the frames if the STA is sleeping */ mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff); mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL); if (!mgmt_buf) return false; INIT_LIST_HEAD(&mgmt_buf->list); mgmt_buf->id = id; mgmt_buf->freq = freq; mgmt_buf->wait = wait; mgmt_buf->len = len; mgmt_buf->no_cck = no_cck; memcpy(mgmt_buf->buf, buf, len); spin_lock_bh(&conn->psq_lock); is_psq_empty = skb_queue_empty(&conn->psq) && (conn->mgmt_psq_len == 0); list_add_tail(&mgmt_buf->list, &conn->mgmt_psq); conn->mgmt_psq_len++; spin_unlock_bh(&conn->psq_lock); /* * If this is the first pkt getting queued * for this STA, update the PVB for this * STA. */ if (is_psq_empty) ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, conn->aid, 1); return true; } /* * This tx is because of a PsPoll. * Determine if MoreData bit has to be set. */ spin_lock_bh(&conn->psq_lock); if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0)) *more_data = true; spin_unlock_bh(&conn->psq_lock); } return false; } static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel *chan, bool offchan, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type, Loading @@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, struct ath6kl_vif *vif = netdev_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); u32 id; u32 id; const struct ieee80211_mgmt *mgmt; const struct ieee80211_mgmt *mgmt; bool more_data, queued; mgmt = (const struct ieee80211_mgmt *) buf; mgmt = (const struct ieee80211_mgmt *) buf; if (buf + len >= mgmt->u.probe_resp.variable && if (buf + len >= mgmt->u.probe_resp.variable && Loading @@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, *cookie = id; *cookie = id; if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, /* AP mode Power saving processing */ ar->fw_capabilities)) { if (vif->nw_type == AP_NETWORK) { /* queued = ath6kl_mgmt_powersave_ap(vif, * If capable of doing P2P mgmt operations using id, chan->center_freq, * station interface, send additional information like wait, buf, * supported rates to advertise and xmit rates for len, &more_data, no_cck); * probe requests if (queued) */ return 0; } return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, chan->center_freq, wait, chan->center_freq, wait, buf, len, no_cck); buf, len, no_cck); } else { return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id, chan->center_freq, wait, buf, len); } } } static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, Loading Loading @@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->wdev.netdev = ndev; vif->wdev.netdev = ndev; vif->wdev.iftype = type; vif->wdev.iftype = type; vif->fw_vif_idx = fw_vif_idx; vif->fw_vif_idx = fw_vif_idx; vif->nw_type = vif->next_mode = nw_type; vif->nw_type = nw_type; vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) if (fw_vif_idx != 0) Loading Loading @@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) wiphy->max_sched_scan_ssids = 10; wiphy->max_sched_scan_ssids = 10; ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; ret = wiphy_register(wiphy); ret = wiphy_register(wiphy); if (ret < 0) { if (ret < 0) { ath6kl_err("couldn't register wiphy device\n"); ath6kl_err("couldn't register wiphy device\n"); return ret; return ret; } } ar->wiphy_registered = true; return 0; return 0; } } void ath6kl_cfg80211_cleanup(struct ath6kl *ar) void ath6kl_cfg80211_cleanup(struct ath6kl *ar) { { wiphy_unregister(ar->wiphy); wiphy_unregister(ar->wiphy); ar->wiphy_registered = false; } } struct ath6kl *ath6kl_cfg80211_create(void) struct ath6kl *ath6kl_cfg80211_create(void) Loading
drivers/net/wireless/ath/ath6kl/cfg80211.h +1 −0 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011 Atheros Communications Inc. * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. * * * Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above Loading