From 594a0bc85e3c2ffb17fc8c64a5121fa441c2d096 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Sun, 14 Aug 2011 17:08:35 +0530 Subject: ath6kl: Cleanup ath6kl_wmi_data_hdr_remove() Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f5aa33dd4c4..13b1a20cef0 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -376,16 +376,6 @@ int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) return 0; } -int ath6kl_wmi_data_hdr_remove(struct wmi *wmi, struct sk_buff *skb) -{ - if (WARN_ON(skb == NULL)) - return -EINVAL; - - skb_pull(skb, sizeof(struct wmi_data_hdr)); - - return 0; -} - static void ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(struct sk_buff *skb, u8 *datap) { -- cgit v1.2.3-70-g09d2 From 3ce6ff501c92e15314f450edc2e93653a7325780 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 22 Aug 2011 20:40:21 +0530 Subject: ath6kl: Add wmi meta data information only it is available Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 13b1a20cef0..d116d0e337d 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -167,9 +167,11 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, if (WARN_ON(skb == NULL)) return -EINVAL; - ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info); - if (ret) - return ret; + if (tx_meta_info) { + ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info); + if (ret) + return ret; + } skb_push(skb, sizeof(struct wmi_data_hdr)); -- cgit v1.2.3-70-g09d2 From 6a7c9badab158086b6162c661a47c4f1a4a68e92 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:57:50 +0300 Subject: ath6kl: Add functionality for starting AP mode Use cfg80211 add/del_beacon callbacks for starting/stopping AP mode and set_beacon to update AP configuration (mainly, to update Beacon and Probe Response IEs). Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 179 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 2 + drivers/net/wireless/ath/ath6kl/wmi.c | 45 ++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 20 ++++ 4 files changed, 246 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 9128aa3c2b6..4752a76e13c 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1435,6 +1435,181 @@ static int ar6k_cfg80211_suspend(struct wiphy *wiphy, } #endif +static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", + __func__, chan->center_freq, chan->hw_value); + ar->next_chan = chan->center_freq; + + return 0; +} + +static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info, bool add) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ieee80211_mgmt *mgmt; + u8 *ies; + int ies_len; + struct wmi_connect_cmd p; + int res; + int i; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (ar->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + if (info->beacon_ies) { + res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON, + info->beacon_ies, + info->beacon_ies_len); + if (res) + return res; + } + if (info->proberesp_ies) { + res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP, + info->proberesp_ies, + info->proberesp_ies_len); + if (res) + return res; + } + if (info->assocresp_ies) { + res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP, + info->assocresp_ies, + info->assocresp_ies_len); + if (res) + return res; + } + + if (!add) + return 0; + + /* TODO: + * info->interval + * info->dtim_period + */ + + if (info->head == NULL) + return -EINVAL; + mgmt = (struct ieee80211_mgmt *) info->head; + ies = mgmt->u.beacon.variable; + if (ies > info->head + info->head_len) + return -EINVAL; + ies_len = info->head + info->head_len - ies; + + if (info->ssid == NULL) + return -EINVAL; + memcpy(ar->ssid, info->ssid, info->ssid_len); + ar->ssid_len = info->ssid_len; + if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) + return -EOPNOTSUPP; /* TODO */ + + ar->dot11_auth_mode = OPEN_AUTH; + + memset(&p, 0, sizeof(p)); + + for (i = 0; i < info->crypto.n_akm_suites; i++) { + switch (info->crypto.akm_suites[i]) { + case WLAN_AKM_SUITE_8021X: + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) + p.auth_mode |= WPA_AUTH; + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) + p.auth_mode |= WPA2_AUTH; + break; + case WLAN_AKM_SUITE_PSK: + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) + p.auth_mode |= WPA_PSK_AUTH; + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) + p.auth_mode |= WPA2_PSK_AUTH; + break; + } + } + if (p.auth_mode == 0) + p.auth_mode = NONE_AUTH; + ar->auth_mode = p.auth_mode; + + for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) { + switch (info->crypto.ciphers_pairwise[i]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + p.prwise_crypto_type |= WEP_CRYPT; + break; + case WLAN_CIPHER_SUITE_TKIP: + p.prwise_crypto_type |= TKIP_CRYPT; + break; + case WLAN_CIPHER_SUITE_CCMP: + p.prwise_crypto_type |= AES_CRYPT; + break; + } + } + if (p.prwise_crypto_type == 0) + p.prwise_crypto_type = NONE_CRYPT; + + switch (info->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + p.grp_crypto_type = WEP_CRYPT; + break; + case WLAN_CIPHER_SUITE_TKIP: + p.grp_crypto_type = TKIP_CRYPT; + break; + case WLAN_CIPHER_SUITE_CCMP: + p.grp_crypto_type = AES_CRYPT; + break; + default: + p.grp_crypto_type = NONE_CRYPT; + break; + } + + p.nw_type = AP_NETWORK; + ar->nw_type = ar->next_mode; + + p.ssid_len = ar->ssid_len; + memcpy(p.ssid, ar->ssid, ar->ssid_len); + p.dot11_auth_mode = ar->dot11_auth_mode; + p.ch = cpu_to_le16(ar->next_chan); + + return ath6kl_wmi_ap_profile_commit(ar->wmi, &p); +} + +static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + return ath6kl_ap_beacon(wiphy, dev, info, true); +} + +static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + return ath6kl_ap_beacon(wiphy, dev, info, false); +} + +static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (ar->nw_type != AP_NETWORK) + return -EOPNOTSUPP; + if (!test_bit(CONNECTED, &ar->flag)) + return -ENOTCONN; + + ath6kl_wmi_disconnect_cmd(ar->wmi); + clear_bit(CONNECTED, &ar->flag); + + return 0; +} + static struct cfg80211_ops ath6kl_cfg80211_ops = { .change_virtual_intf = ath6kl_cfg80211_change_iface, .scan = ath6kl_cfg80211_scan, @@ -1457,6 +1632,10 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { #ifdef CONFIG_PM .suspend = ar6k_cfg80211_suspend, #endif + .set_channel = ath6kl_set_channel, + .add_beacon = ath6kl_add_beacon, + .set_beacon = ath6kl_set_beacon, + .del_beacon = ath6kl_del_beacon, }; struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c5537b3f77c..00d0add2ab4 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -468,6 +468,8 @@ struct ath6kl { struct ath6kl_node_table scan_table; struct dentry *debugfs_phy; + + u16 next_chan; }; static inline void *ath6kl_priv(struct net_device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index d116d0e337d..0114a713697 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1399,6 +1399,8 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, enum htc_endpoint_id ep_id = wmi->ep_id; int ret; + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: cmd_id=%d\n", __func__, cmd_id); + if (WARN_ON(skb == NULL)) return -EINVAL; @@ -2392,6 +2394,29 @@ static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len) } /* AP mode functions */ + +int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p) +{ + struct sk_buff *skb; + struct wmi_connect_cmd *cm; + int res; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cm)); + if (!skb) + return -ENOMEM; + + cm = (struct wmi_connect_cmd *) skb->data; + memcpy(cm, p, sizeof(*cm)); + + res = ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_CONFIG_COMMIT_CMDID, + NO_SYNC_WMIFLAG); + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u " + "ctrl_flags=0x%x-> res=%d\n", + __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch), + le32_to_cpu(p->ctrl_flags), res); + return res; +} + static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_pspoll_event *ev; @@ -2456,6 +2481,26 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver, return ret; } +int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, + u8 ie_len) +{ + struct sk_buff *skb; + struct wmi_set_appie_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u " + "ie_len=%u\n", mgmt_frm_type, ie_len); + p = (struct wmi_set_appie_cmd *) skb->data; + p->mgmt_frm_type = mgmt_frm_type; + p->ie_len = ie_len; + memcpy(p->ie_info, ie, ie_len); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_APPIE_CMDID, + NO_SYNC_WMIFLAG); +} + static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) { struct wmix_cmd_hdr *cmd; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 8fa5d6e46f0..6bdfd4a8611 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -503,6 +503,15 @@ enum wmi_cmd_id { WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, }; +enum wmi_mgmt_frame_type { + WMI_FRAME_BEACON = 0, + WMI_FRAME_PROBE_REQ, + WMI_FRAME_PROBE_RESP, + WMI_FRAME_ASSOC_REQ, + WMI_FRAME_ASSOC_RESP, + WMI_NUM_MGMT_FRAME +}; + /* WMI_CONNECT_CMDID */ enum network_type { INFRA_NETWORK = 0x01, @@ -1642,6 +1651,12 @@ struct wmi_get_keepalive_cmd { u8 keep_alive_intvl; } __packed; +struct wmi_set_appie_cmd { + u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ + u8 ie_len; + u8 ie_info[0]; +} __packed; + /* Notify the WSC registration status to the target */ #define WSC_REG_ACTIVE 1 #define WSC_REG_INACTIVE 0 @@ -2006,11 +2021,16 @@ struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid, void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss); /* AP mode */ +int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p); + int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, bool rx_dot11_hdr, bool defrag_on_host); +int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, + u8 ie_len); + void *ath6kl_wmi_init(struct ath6kl *devt); void ath6kl_wmi_shutdown(struct wmi *wmi); -- cgit v1.2.3-70-g09d2 From 9a5b13182cc10d693c55a5c02d753e54514b9bfc Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:57:52 +0300 Subject: ath6kl: Delay initial group key setup in AP mode The target is not ready to accept addkey commands until the connect event has been delivered, so delay these operations for the initial GTK. In addition, properly set interface connected and mark netdev ready when the AP mode setup has been completed. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 31 ++++++++++++++++++++++++- drivers/net/wireless/ath/ath6kl/core.h | 25 +++++---------------- drivers/net/wireless/ath/ath6kl/main.c | 36 +++++++++++++++++------------- drivers/net/wireless/ath/ath6kl/wmi.c | 4 ++++ 4 files changed, 60 insertions(+), 36 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 4752a76e13c..faefc23750d 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -888,6 +888,26 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, key_usage, key->seq_len); ar->def_txkey_index = key_index; + + if (ar->nw_type == AP_NETWORK && !pairwise && + (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) { + ar->ap_mode_bkey.valid = true; + ar->ap_mode_bkey.key_index = key_index; + ar->ap_mode_bkey.key_type = key_type; + ar->ap_mode_bkey.key_len = key->key_len; + memcpy(ar->ap_mode_bkey.key, key->key, key->key_len); + if (!test_bit(CONNECTED, &ar->flag)) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group " + "key configuration until AP mode has been " + "started\n"); + /* + * The key will be set in ath6kl_connect_ap_mode() once + * the connected event is received from the target. + */ + return 0; + } + } + status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, key_type, key_usage, key->key_len, key->seq, key->key, KEY_OP_INIT_VAL, @@ -997,6 +1017,9 @@ static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, if (ar->prwise_crypto == WEP_CRYPT) key_usage |= TX_USAGE; + if (ar->nw_type == AP_NETWORK && !test_bit(CONNECTED, &ar->flag)) + return 0; /* Delay until AP mode has been started */ + status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, ar->prwise_crypto, key_usage, key->key_len, key->seq, key->key, @@ -1495,6 +1518,8 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, if (!add) return 0; + ar->ap_mode_bkey.valid = false; + /* TODO: * info->interval * info->dtim_period @@ -1580,7 +1605,11 @@ static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, p.dot11_auth_mode = ar->dot11_auth_mode; p.ch = cpu_to_le16(ar->next_chan); - return ath6kl_wmi_ap_profile_commit(ar->wmi, &p); + res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p); + if (res < 0) + return res; + + return 0; } static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 00d0add2ab4..f0b1dff1ce0 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -335,26 +335,13 @@ struct ath6kl_mbox_info { #define ATH6KL_KEY_RECV 0x02 #define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */ -/* - * WPA/RSN get/set key request. Specify the key/cipher - * type and whether the key is to be used for sending and/or - * receiving. The key index should be set only when working - * with global keys (use IEEE80211_KEYIX_NONE for ``no index''). - * Otherwise a unicast/pairwise key is specified by the bssid - * (on a station) or mac address (on an ap). They key length - * must include any MIC key data; otherwise it should be no - * more than ATH6KL_KEYBUF_SIZE. - */ +/* Initial group key for AP mode */ struct ath6kl_req_key { - u8 ik_type; /* key/cipher type */ - u8 ik_pad; - u16 ik_keyix; /* key index */ - u8 ik_keylen; /* key length in bytes */ - u8 ik_flags; - u8 ik_macaddr[ETH_ALEN]; - u64 ik_keyrsc; /* key receive sequence counter */ - u64 ik_keytsc; /* key transmit sequence counter */ - u8 ik_keydata[ATH6KL_KEYBUF_SIZE + ATH6KL_MICBUF_SIZE]; + bool valid; + u8 key_index; + int key_type; + u8 key[WLAN_MAX_KEY_LEN]; + u8 key_len; }; /* Flag info */ diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 89e29ead254..a19caecdfde 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -437,11 +437,15 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, size_t ies_len = 0; struct station_info sinfo; struct ath6kl_req_key *ik; - enum crypto_type keyType = NONE_CRYPT; + int res; + u8 key_rsc[ATH6KL_KEY_SEQ_LEN]; if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) { ik = &ar->ap_mode_bkey; + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", + channel); + switch (ar->auth_mode) { case NONE_AUTH: if (ar->prwise_crypto == WEP_CRYPT) @@ -450,26 +454,26 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, case WPA_PSK_AUTH: case WPA2_PSK_AUTH: case (WPA_PSK_AUTH|WPA2_PSK_AUTH): - switch (ik->ik_type) { - case ATH6KL_CIPHER_TKIP: - keyType = TKIP_CRYPT; - break; - case ATH6KL_CIPHER_AES_CCM: - keyType = AES_CRYPT; + if (!ik->valid) break; - default: - goto skip_key; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " + "the initial group key for AP mode\n"); + memset(key_rsc, 0, sizeof(key_rsc)); + res = ath6kl_wmi_addkey_cmd( + ar->wmi, ik->key_index, ik->key_type, + GROUP_USAGE, ik->key_len, key_rsc, ik->key, + KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); + if (res) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " + "addkey failed: %d\n", res); } - ath6kl_wmi_addkey_cmd(ar->wmi, ik->ik_keyix, keyType, - GROUP_USAGE, ik->ik_keylen, - (u8 *)&ik->ik_keyrsc, - ik->ik_keydata, - KEY_OP_INIT_VAL, ik->ik_macaddr, - SYNC_BOTH_WMIFLAG); break; } -skip_key: + + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); set_bit(CONNECTED, &ar->flag); + netif_carrier_on(ar->net_dev); return; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 0114a713697..d587f84b41c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1764,6 +1764,10 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, struct wmi_add_cipher_key_cmd *cmd; int ret; + ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d " + "key_usage=%d key_len=%d key_op_ctrl=%d\n", + key_index, key_type, key_usage, key_len, key_op_ctrl); + if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || (key_material == NULL)) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 238751365a1c42b1d66beb03dd81ca5d0fd12833 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:57:53 +0300 Subject: ath6kl: Use change_station() to authorize/unauthorize STAs Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 20 ++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index faefc23750d..f7176d203be 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1639,6 +1639,25 @@ static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) return 0; } +static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (ar->nw_type != AP_NETWORK) + return -EOPNOTSUPP; + + /* Use this only for authorizing/unauthorizing a station */ + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) + return -EOPNOTSUPP; + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) + return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE, + mac, 0); + return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac, + 0); +} + static struct cfg80211_ops ath6kl_cfg80211_ops = { .change_virtual_intf = ath6kl_cfg80211_change_iface, .scan = ath6kl_cfg80211_scan, @@ -1665,6 +1684,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .add_beacon = ath6kl_add_beacon, .set_beacon = ath6kl_set_beacon, .del_beacon = ath6kl_del_beacon, + .change_station = ath6kl_change_station, }; struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index d587f84b41c..1a3991ce8cf 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2421,6 +2421,24 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p) return res; } +int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason) +{ + struct sk_buff *skb; + struct wmi_ap_set_mlme_cmd *cm; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cm)); + if (!skb) + return -ENOMEM; + + cm = (struct wmi_ap_set_mlme_cmd *) skb->data; + memcpy(cm->mac, mac, ETH_ALEN); + cm->reason = cpu_to_le16(reason); + cm->cmd = cmd; + + return ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_SET_MLME_CMDID, + NO_SYNC_WMIFLAG); +} + static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_pspoll_event *ev; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 6bdfd4a8611..eb6bfcd879e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1804,6 +1804,23 @@ struct wmi_tx_complete_event { /* Used with WMI_AP_SET_NUM_STA_CMDID */ +/* + * Used with WMI_AP_SET_MLME_CMDID + */ + +/* MLME Commands */ +#define WMI_AP_MLME_ASSOC 1 /* associate station */ +#define WMI_AP_DISASSOC 2 /* disassociate station */ +#define WMI_AP_DEAUTH 3 /* deauthenticate station */ +#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */ +#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */ + +struct wmi_ap_set_mlme_cmd { + u8 mac[ETH_ALEN]; + __le16 reason; /* 802.11 reason code */ + u8 cmd; /* operation to perform (WMI_AP_*) */ +} __packed; + struct wmi_ap_set_pvb_cmd { __le32 flag; __le16 aid; @@ -2023,6 +2040,8 @@ void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss); /* AP mode */ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p); +int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason); + int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, -- cgit v1.2.3-70-g09d2 From 6465ddcf6c1e06d3fde870624be4418e747f0e8b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:57:54 +0300 Subject: ath6kl: Add new WMI commands and events for P2P Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 294 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 184 ++++++++++++++++++++- 2 files changed, 470 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 1a3991ce8cf..261ccff0a64 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -425,6 +425,148 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) return 0; } +static int ath6kl_wmi_remain_on_chnl_event_rx(u8 *datap, int len) +{ + struct wmi_remain_on_chnl_event *ev; + u32 freq; + u32 dur; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_remain_on_chnl_event *) datap; + freq = le32_to_cpu(ev->freq); + dur = le32_to_cpu(ev->duration); + ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n", + freq, dur); + + return 0; +} + +static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(u8 *datap, int len) +{ + struct wmi_cancel_remain_on_chnl_event *ev; + u32 freq; + u32 dur; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_cancel_remain_on_chnl_event *) datap; + freq = le32_to_cpu(ev->freq); + dur = le32_to_cpu(ev->duration); + ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u " + "status=%u\n", freq, dur, ev->status); + + return 0; +} + +static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len) +{ + struct wmi_tx_status_event *ev; + u32 id; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_tx_status_event *) datap; + id = le32_to_cpu(ev->id); + ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", + id, ev->ack_status); + + return 0; +} + +static int ath6kl_wmi_rx_probe_req_event_rx(u8 *datap, int len) +{ + struct wmi_p2p_rx_probe_req_event *ev; + u16 dlen; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_p2p_rx_probe_req_event *) datap; + dlen = le16_to_cpu(ev->len); + ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u\n", + dlen); + + return 0; +} + +static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len) +{ + struct wmi_p2p_capabilities_event *ev; + u16 dlen; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_p2p_capabilities_event *) datap; + dlen = le16_to_cpu(ev->len); + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen); + + return 0; +} + +static int ath6kl_wmi_rx_action_event_rx(u8 *datap, int len) +{ + struct wmi_rx_action_event *ev; + u16 dlen; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_rx_action_event *) datap; + dlen = le16_to_cpu(ev->len); + ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u\n", dlen); + + return 0; +} + +static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len) +{ + struct wmi_p2p_info_event *ev; + u32 flags; + u16 dlen; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_p2p_info_event *) datap; + flags = le32_to_cpu(ev->info_req_flags); + dlen = le16_to_cpu(ev->len); + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen); + + if (flags & P2P_FLAG_CAPABILITIES_REQ) { + struct wmi_p2p_capabilities *cap; + if (dlen < sizeof(*cap)) + return -EINVAL; + cap = (struct wmi_p2p_capabilities *) ev->data; + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n", + cap->go_power_save); + } + + if (flags & P2P_FLAG_MACADDR_REQ) { + struct wmi_p2p_macaddr *mac; + if (dlen < sizeof(*mac)) + return -EINVAL; + mac = (struct wmi_p2p_macaddr *) ev->data; + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n", + mac->mac_addr); + } + + if (flags & P2P_FLAG_HMODEL_REQ) { + struct wmi_p2p_hmodel *mod; + if (dlen < sizeof(*mod)) + return -EINVAL; + mod = (struct wmi_p2p_hmodel *) ev->data; + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n", + mod->p2p_model, + mod->p2p_model ? "host" : "firmware"); + } + return 0; +} + static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size) { struct sk_buff *skb; @@ -2523,6 +2665,129 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) +{ + struct sk_buff *skb; + struct wmi_disable_11b_rates_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n", + disable); + cmd = (struct wmi_disable_11b_rates_cmd *) skb->data; + cmd->disable = disable ? 1 : 0; + + return ath6kl_wmi_cmd_send(wmi, skb, WMI_DISABLE_11B_RATES_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur) +{ + struct sk_buff *skb; + struct wmi_remain_on_chnl_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n", + freq, dur); + p = (struct wmi_remain_on_chnl_cmd *) skb->data; + p->freq = cpu_to_le32(freq); + p->duration = cpu_to_le32(dur); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_REMAIN_ON_CHNL_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, + const u8 *data, u16 data_len) +{ + struct sk_buff *skb; + struct wmi_send_action_cmd *p; + + if (wait) + return -EINVAL; /* Offload for wait not supported */ + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " + "len=%u\n", id, freq, wait, data_len); + p = (struct wmi_send_action_cmd *) skb->data; + p->id = cpu_to_le32(id); + p->freq = cpu_to_le32(freq); + p->wait = cpu_to_le32(wait); + p->len = cpu_to_le16(data_len); + memcpy(p->data, data, data_len); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_ACTION_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq, + const u8 *dst, + const u8 *data, u16 data_len) +{ + struct sk_buff *skb; + struct wmi_p2p_probe_response_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM " + "len=%u\n", freq, dst, data_len); + p = (struct wmi_p2p_probe_response_cmd *) skb->data; + p->freq = cpu_to_le32(freq); + memcpy(p->destination_addr, dst, ETH_ALEN); + p->len = cpu_to_le16(data_len); + memcpy(p->data, data, data_len); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_PROBE_RESPONSE_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable) +{ + struct sk_buff *skb; + struct wmi_probe_req_report_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n", + enable); + p = (struct wmi_probe_req_report_cmd *) skb->data; + p->enable = enable ? 1 : 0; + return ath6kl_wmi_cmd_send(wmi, skb, WMI_PROBE_REQ_REPORT_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags) +{ + struct sk_buff *skb; + struct wmi_get_p2p_info *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n", + info_req_flags); + p = (struct wmi_get_p2p_info *) skb->data; + p->info_req_flags = cpu_to_le32(info_req_flags); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_GET_P2P_INFO_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi) +{ + ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n"); + return ath6kl_wmi_simple_cmd(wmi, WMI_CANCEL_REMAIN_ON_CHNL_CMDID); +} + static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) { struct wmix_cmd_hdr *cmd; @@ -2742,6 +3007,35 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); ret = ath6kl_wmi_tx_complete_event_rx(datap, len); break; + case WMI_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); + ret = ath6kl_wmi_remain_on_chnl_event_rx(datap, len); + break; + case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); + ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(datap, len); + break; + case WMI_TX_STATUS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); + ret = ath6kl_wmi_tx_status_event_rx(datap, len); + break; + case WMI_RX_PROBE_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); + ret = ath6kl_wmi_rx_probe_req_event_rx(datap, len); + break; + case WMI_P2P_CAPABILITIES_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); + ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); + break; + case WMI_RX_ACTION_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); + ret = ath6kl_wmi_rx_action_event_rx(datap, len); + break; + case WMI_P2P_INFO_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); + ret = ath6kl_wmi_p2p_info_event_rx(datap, len); + break; default: ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); wmi->stat.cmd_id_err++; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index eb6bfcd879e..5e2f6ce41ba 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -490,17 +490,52 @@ enum wmi_cmd_id { WMI_SET_PASSPHRASE_CMDID, WMI_SEND_ASSOC_RES_CMDID, WMI_SET_ASSOC_REQ_RELAY_CMDID, - WMI_GET_RFKILL_MODE_CMDID, /* ACS command, consists of sub-commands */ WMI_ACS_CTRL_CMDID, + WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, + WMI_SET_TBD_TIME_CMDID, /*added for wmiconfig command for TBD */ + + /* Pktlog cmds */ + WMI_PKTLOG_ENABLE_CMDID, + WMI_PKTLOG_DISABLE_CMDID, + + /* More P2P Cmds */ + WMI_P2P_GO_NEG_REQ_RSP_CMDID, + WMI_P2P_GRP_INIT_CMDID, + WMI_P2P_GRP_FORMATION_DONE_CMDID, + WMI_P2P_INVITE_CMDID, + WMI_P2P_INVITE_REQ_RSP_CMDID, + WMI_P2P_PROV_DISC_REQ_CMDID, + WMI_P2P_SET_CMDID, + WMI_GET_RFKILL_MODE_CMDID, + WMI_SET_RFKILL_MODE_CMDID, + WMI_AP_SET_APSD_CMDID, + WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID, + + WMI_P2P_SDPD_TX_CMDID, /* F05C */ + WMI_P2P_STOP_SDPD_CMDID, + WMI_P2P_CANCEL_CMDID, /* Ultra low power store / recall commands */ WMI_STORERECALL_CONFIGURE_CMDID, WMI_STORERECALL_RECALL_CMDID, WMI_STORERECALL_HOST_READY_CMDID, WMI_FORCE_TARGET_ASSERT_CMDID, - WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, + + WMI_SET_PROBED_SSID_EX_CMDID, + WMI_SET_NETWORK_LIST_OFFLOAD_CMDID, + WMI_SET_ARP_NS_OFFLOAD_CMDID, + WMI_ADD_WOW_EXT_PATTERN_CMDID, + WMI_GTK_OFFLOAD_OP_CMDID, + WMI_REMAIN_ON_CHNL_CMDID, + WMI_CANCEL_REMAIN_ON_CHNL_CMDID, + WMI_SEND_ACTION_CMDID, + WMI_PROBE_REQ_REPORT_CMDID, + WMI_DISABLE_11B_RATES_CMDID, + WMI_SEND_PROBE_RESPONSE_CMDID, + WMI_GET_P2P_INFO_CMDID, + WMI_AP_JOIN_BSS_CMDID, }; enum wmi_mgmt_frame_type { @@ -1188,15 +1223,26 @@ enum wmi_event_id { WMI_WAC_START_WPS_EVENTID, WMI_WAC_CTRL_REQ_REPLY_EVENTID, + WMI_REPORT_WMM_PARAMS_EVENTID, + WMI_WAC_REJECT_WPS_EVENTID, + + /* More P2P Events */ + WMI_P2P_GO_NEG_REQ_EVENTID, + WMI_P2P_INVITE_REQ_EVENTID, + WMI_P2P_INVITE_RCVD_RESULT_EVENTID, + WMI_P2P_INVITE_SENT_RESULT_EVENTID, + WMI_P2P_PROV_DISC_RESP_EVENTID, + WMI_P2P_PROV_DISC_REQ_EVENTID, + /* RFKILL Events */ WMI_RFKILL_STATE_CHANGE_EVENTID, WMI_RFKILL_GET_MODE_CMD_EVENTID, - WMI_THIN_RESERVED_START_EVENTID = 0x8000, - /* - * Events in this range are reserved for thinmode - * See wmi_thin.h for actual definitions - */ + WMI_P2P_START_SDPD_EVENTID, + WMI_P2P_SDPD_RX_EVENTID, + + WMI_THIN_RESERVED_START_EVENTID = 0x8000, + /* Events in this range are reserved for thinmode */ WMI_THIN_RESERVED_END_EVENTID = 0x8fff, WMI_SET_CHANNEL_EVENTID, @@ -1204,7 +1250,17 @@ enum wmi_event_id { /* Generic ACS event */ WMI_ACS_EVENTID, - WMI_REPORT_WMM_PARAMS_EVENTID + WMI_STORERECALL_STORE_EVENTID, + WMI_WOW_EXT_WAKE_EVENTID, + WMI_GTK_OFFLOAD_STATUS_EVENTID, + WMI_NETWORK_LIST_OFFLOAD_EVENTID, + WMI_REMAIN_ON_CHNL_EVENTID, + WMI_CANCEL_REMAIN_ON_CHNL_EVENTID, + WMI_TX_STATUS_EVENTID, + WMI_RX_PROBE_REQ_EVENTID, + WMI_P2P_CAPABILITIES_EVENTID, + WMI_RX_ACTION_EVENTID, + WMI_P2P_INFO_EVENTID, }; struct wmi_ready_event_2 { @@ -1872,6 +1928,100 @@ struct wmi_ap_mode_stat { /* End of AP mode definitions */ +struct wmi_remain_on_chnl_cmd { + __le32 freq; + __le32 duration; +} __packed; + +struct wmi_send_action_cmd { + __le32 id; + __le32 freq; + __le32 wait; + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_tx_status_event { + __le32 id; + u8 ack_status; +} __packed; + +struct wmi_probe_req_report_cmd { + u8 enable; +} __packed; + +struct wmi_disable_11b_rates_cmd { + u8 disable; +} __packed; + +struct wmi_set_appie_extended_cmd { + u8 role_id; + u8 mgmt_frm_type; + u8 ie_len; + u8 ie_info[0]; +} __packed; + +struct wmi_remain_on_chnl_event { + __le32 freq; + __le32 duration; +} __packed; + +struct wmi_cancel_remain_on_chnl_event { + __le32 freq; + __le32 duration; + u8 status; +} __packed; + +struct wmi_rx_action_event { + __le32 freq; + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_p2p_capabilities_event { + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_p2p_rx_probe_req_event { + __le32 freq; + __le16 len; + u8 data[0]; +} __packed; + +#define P2P_FLAG_CAPABILITIES_REQ (0x00000001) +#define P2P_FLAG_MACADDR_REQ (0x00000002) +#define P2P_FLAG_HMODEL_REQ (0x00000002) + +struct wmi_get_p2p_info { + __le32 info_req_flags; +} __packed; + +struct wmi_p2p_info_event { + __le32 info_req_flags; + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_p2p_capabilities { + u8 go_power_save; +} __packed; + +struct wmi_p2p_macaddr { + u8 mac_addr[ETH_ALEN]; +} __packed; + +struct wmi_p2p_hmodel { + u8 p2p_model; +} __packed; + +struct wmi_p2p_probe_response_cmd { + __le32 freq; + u8 destination_addr[ETH_ALEN]; + __le16 len; + u8 data[0]; +} __packed; + /* Extended WMI (WMIX) * * Extended WMIX commands are encapsulated in a WMI message with @@ -2050,6 +2200,24 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, u8 ie_len); +/* P2P */ +int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); + +int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur); + +int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, + const u8 *data, u16 data_len); + +int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq, + const u8 *dst, + const u8 *data, u16 data_len); + +int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable); + +int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags); + +int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi); + void *ath6kl_wmi_init(struct ath6kl *devt); void ath6kl_wmi_shutdown(struct wmi *wmi); -- cgit v1.2.3-70-g09d2 From f9e5f05cb9c944696def27618215216df59c7c33 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:57:58 +0300 Subject: ath6kl: Add cfg80211 calls for remain-on-channel events Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 261ccff0a64..2d80bdb2d91 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -425,11 +425,14 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) return 0; } -static int ath6kl_wmi_remain_on_chnl_event_rx(u8 *datap, int len) +static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, + int len) { struct wmi_remain_on_chnl_event *ev; u32 freq; u32 dur; + struct ieee80211_channel *chan; + struct ath6kl *ar = wmi->parent_dev; if (len < sizeof(*ev)) return -EINVAL; @@ -439,15 +442,26 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(u8 *datap, int len) dur = le32_to_cpu(ev->duration); ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n", freq, dur); + chan = ieee80211_get_channel(ar->wdev->wiphy, freq); + if (!chan) { + ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel " + "(freq=%u)\n", freq); + return -EINVAL; + } + cfg80211_ready_on_channel(ar->net_dev, 1, chan, NL80211_CHAN_NO_HT, + dur, GFP_ATOMIC); return 0; } -static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(u8 *datap, int len) +static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, + u8 *datap, int len) { struct wmi_cancel_remain_on_chnl_event *ev; u32 freq; u32 dur; + struct ieee80211_channel *chan; + struct ath6kl *ar = wmi->parent_dev; if (len < sizeof(*ev)) return -EINVAL; @@ -457,6 +471,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(u8 *datap, int len) dur = le32_to_cpu(ev->duration); ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u " "status=%u\n", freq, dur, ev->status); + chan = ieee80211_get_channel(ar->wdev->wiphy, freq); + if (!chan) { + ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown " + "channel (freq=%u)\n", freq); + return -EINVAL; + } + cfg80211_remain_on_channel_expired(ar->net_dev, 1, chan, + NL80211_CHAN_NO_HT, GFP_ATOMIC); return 0; } @@ -3009,12 +3031,13 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_REMAIN_ON_CHNL_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); - ret = ath6kl_wmi_remain_on_chnl_event_rx(datap, len); + ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len); break; case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); - ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(datap, len); + ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, + len); break; case WMI_TX_STATUS_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); -- cgit v1.2.3-70-g09d2 From 1276c9ef6db2bc856579bc7f02e4cc710b089f0d Mon Sep 17 00:00:00 2001 From: Edward Lu Date: Tue, 30 Aug 2011 21:58:00 +0300 Subject: ath6kl: Support channel set request for startscan command Signed-off-by: Edward Lu Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 22 +++++++++++++++++++++- drivers/net/wireless/ath/ath6kl/wmi.c | 6 +++--- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 56a60c7f53c..78b178892ed 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -748,6 +748,8 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) { struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); + s8 n_channels = 0; + u16 *channels = NULL; int ret = 0; if (!ath6kl_cfg80211_ready(ar)) @@ -786,14 +788,32 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } } + if (request->n_channels > 0) { + u8 i; + + n_channels = min(127U, request->n_channels); + + channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); + if (channels == NULL) { + ath6kl_warn("failed to set scan channels, " + "scan all channels"); + n_channels = 0; + } + + for (i = 0; i < n_channels; i++) + channels[i] = request->channels[i]->center_freq; + } + if (ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, - false, 0, 0, 0, NULL) != 0) { + false, 0, 0, n_channels, channels) != 0) { ath6kl_err("wmi_startscan_cmd failed\n"); ret = -EIO; } ar->scan_req = request; + kfree(channels); + return ret; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 2d80bdb2d91..bbe3e8d214c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1709,7 +1709,7 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, struct sk_buff *skb; struct wmi_start_scan_cmd *sc; s8 size; - int ret; + int i, ret; size = sizeof(struct wmi_start_scan_cmd); @@ -1734,8 +1734,8 @@ int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, sc->force_scan_intvl = cpu_to_le32(force_scan_interval); sc->num_ch = num_chan; - if (num_chan) - memcpy(sc->ch_list, ch_list, num_chan * sizeof(u16)); + for (i = 0; i < num_chan; i++) + sc->ch_list[i] = cpu_to_le16(ch_list[i]); ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID, NO_SYNC_WMIFLAG); -- cgit v1.2.3-70-g09d2 From ae32c30a6ec991088e5346036015be1a9f9cf14b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:58:01 +0300 Subject: ath6kl: Report received Probe Request frames to cfg80211 Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 19 +++++++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/init.c | 7 +++++++ drivers/net/wireless/ath/ath6kl/wmi.c | 20 ++++++++++++++++---- 4 files changed, 43 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 78b178892ed..60339598ad2 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1740,6 +1740,24 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, buf, len); } +static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, + struct net_device *dev, + u16 frame_type, bool reg) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", + __func__, frame_type, reg); + if (frame_type == IEEE80211_STYPE_PROBE_REQ) { + /* + * Note: This notification callback is not allowed to sleep, so + * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we + * hardcode target to report Probe Request frames all the time. + */ + ar->probe_req_report = reg; + } +} + static struct cfg80211_ops ath6kl_cfg80211_ops = { .change_virtual_intf = ath6kl_cfg80211_change_iface, .scan = ath6kl_cfg80211_scan, @@ -1770,6 +1788,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .remain_on_channel = ath6kl_remain_on_channel, .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, .mgmt_tx = ath6kl_mgmt_tx, + .mgmt_frame_register = ath6kl_mgmt_frame_register, }; struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 3872edbe059..99cabd251ca 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -457,6 +457,7 @@ struct ath6kl { struct dentry *debugfs_phy; u32 send_action_id; + bool probe_req_report; u16 next_chan; }; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 48c82e9561b..3b99ae2dfb1 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -471,6 +471,13 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar) ret); } + /* Enable Probe Request reporting for P2P */ + ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true); + if (ret) { + ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe Request " + "reporting (%d)\n", ret); + } + return status; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index bbe3e8d214c..9b2a1829776 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -499,18 +499,30 @@ static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len) return 0; } -static int ath6kl_wmi_rx_probe_req_event_rx(u8 *datap, int len) +static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_p2p_rx_probe_req_event *ev; + u32 freq; u16 dlen; + struct ath6kl *ar = wmi->parent_dev; if (len < sizeof(*ev)) return -EINVAL; ev = (struct wmi_p2p_rx_probe_req_event *) datap; + freq = le32_to_cpu(ev->freq); dlen = le16_to_cpu(ev->len); - ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u\n", - dlen); + if (datap + len < ev->data + dlen) { + ath6kl_err("invalid wmi_p2p_rx_probe_req_event: " + "len=%d dlen=%u\n", len, dlen); + return -EINVAL; + } + ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u " + "probe_req_report=%d\n", + dlen, freq, ar->probe_req_report); + + if (ar->probe_req_report || ar->nw_type == AP_NETWORK) + cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC); return 0; } @@ -3045,7 +3057,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_RX_PROBE_REQ_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); - ret = ath6kl_wmi_rx_probe_req_event_rx(datap, len); + ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len); break; case WMI_P2P_CAPABILITIES_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); -- cgit v1.2.3-70-g09d2 From a0df5db15b432cd49319254132fda80cb3081ad6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:58:02 +0300 Subject: ath6kl: Notify cfg80211 of TX status of mgmt_tx frames Use WMI_TX_STATUS_EVENTID event to generate cfg80211_mgmt_tx_frame() calls. Since we support only a single pending frame for now, use the hardcoded cookie value 1 and store a copy of the pending frame in the driver. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 28 +++++++++++++++++++++++++--- drivers/net/wireless/ath/ath6kl/wmi.h | 3 +++ 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 9b2a1829776..d098cbd07fa 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -483,10 +483,11 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, return 0; } -static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len) +static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_tx_status_event *ev; u32 id; + struct ath6kl *ar = wmi->parent_dev; if (len < sizeof(*ev)) return -EINVAL; @@ -495,6 +496,15 @@ static int ath6kl_wmi_tx_status_event_rx(u8 *datap, int len) id = le32_to_cpu(ev->id); ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", id, ev->ack_status); + if (wmi->last_mgmt_tx_frame) { + cfg80211_mgmt_tx_status(ar->net_dev, id, + wmi->last_mgmt_tx_frame, + wmi->last_mgmt_tx_frame_len, + !!ev->ack_status, GFP_ATOMIC); + kfree(wmi->last_mgmt_tx_frame); + wmi->last_mgmt_tx_frame = NULL; + wmi->last_mgmt_tx_frame_len = 0; + } return 0; } @@ -2740,13 +2750,24 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, { struct sk_buff *skb; struct wmi_send_action_cmd *p; + u8 *buf; if (wait) return -EINVAL; /* Offload for wait not supported */ + buf = kmalloc(data_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); - if (!skb) + if (!skb) { + kfree(buf); return -ENOMEM; + } + + kfree(wmi->last_mgmt_tx_frame); + wmi->last_mgmt_tx_frame = buf; + wmi->last_mgmt_tx_frame_len = data_len; ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " "len=%u\n", id, freq, wait, data_len); @@ -3053,7 +3074,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_TX_STATUS_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); - ret = ath6kl_wmi_tx_status_event_rx(datap, len); + ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len); break; case WMI_RX_PROBE_REQ_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); @@ -3127,5 +3148,6 @@ void ath6kl_wmi_shutdown(struct wmi *wmi) if (!wmi) return; + kfree(wmi->last_mgmt_tx_frame); kfree(wmi); } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 83af518fcaf..cb3d27afcc6 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -129,6 +129,9 @@ struct wmi { u8 ht_allowed[A_NUM_BANDS]; u8 traffic_class; bool is_probe_ssid; + + u8 *last_mgmt_tx_frame; + size_t last_mgmt_tx_frame_len; }; struct host_app_area { -- cgit v1.2.3-70-g09d2 From 9809d8ef274bb53f47998bbc401efcbb10226893 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 30 Aug 2011 21:58:03 +0300 Subject: ath6kl: Report received Action frames to cfg80211 Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index d098cbd07fa..dec869790c1 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -552,17 +552,26 @@ static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len) return 0; } -static int ath6kl_wmi_rx_action_event_rx(u8 *datap, int len) +static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_rx_action_event *ev; + u32 freq; u16 dlen; + struct ath6kl *ar = wmi->parent_dev; if (len < sizeof(*ev)) return -EINVAL; ev = (struct wmi_rx_action_event *) datap; + freq = le32_to_cpu(ev->freq); dlen = le16_to_cpu(ev->len); - ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u\n", dlen); + if (datap + len < ev->data + dlen) { + ath6kl_err("invalid wmi_rx_action_event: " + "len=%d dlen=%u\n", len, dlen); + return -EINVAL; + } + ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); + cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC); return 0; } @@ -3086,7 +3095,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_RX_ACTION_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); - ret = ath6kl_wmi_rx_action_event_rx(datap, len); + ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len); break; case WMI_P2P_INFO_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); -- cgit v1.2.3-70-g09d2 From 003353b0d27489228eff79447d0731687cea0207 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Thu, 1 Sep 2011 10:14:21 +0300 Subject: ath6kl: add testmode support This is port from the staging version of ath6kl. The interface to user space is exactly same. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/Makefile | 1 + drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 + drivers/net/wireless/ath/ath6kl/core.h | 8 ++ drivers/net/wireless/ath/ath6kl/init.c | 26 +++++ drivers/net/wireless/ath/ath6kl/main.c | 5 +- drivers/net/wireless/ath/ath6kl/testmode.c | 167 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/testmode.h | 20 ++++ drivers/net/wireless/ath/ath6kl/wmi.c | 29 +++++ drivers/net/wireless/ath/ath6kl/wmi.h | 1 + 9 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 drivers/net/wireless/ath/ath6kl/testmode.c create mode 100644 drivers/net/wireless/ath/ath6kl/testmode.h (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index b64a6f52983..5fe092046d3 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -33,5 +33,6 @@ ath6kl-y += txrx.o ath6kl-y += wmi.o ath6kl-y += node.o ath6kl-y += sdio.o +ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index e867a7a5c91..7db66589ee0 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -18,6 +18,7 @@ #include "cfg80211.h" #include "debug.h" #include "hif-ops.h" +#include "testmode.h" #define RATETAB_ENT(_rate, _rateid, _flags) { \ .bitrate = (_rate), \ @@ -1907,6 +1908,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .set_pmksa = ath6kl_set_pmksa, .del_pmksa = ath6kl_del_pmksa, .flush_pmksa = ath6kl_flush_pmksa, + CFG80211_TESTMODE_CMD(ath6kl_tm_cmd) #ifdef CONFIG_PM .suspend = ar6k_cfg80211_suspend, #endif diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 60e2291fecc..cfbbad9feb9 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -64,6 +64,7 @@ #define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910 #define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" #define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" +#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin" #define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" #define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" #define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin" @@ -72,6 +73,7 @@ #define AR6003_REV3_VERSION 0x30000582 #define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" #define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" +#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin" #define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" #define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" #define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \ @@ -358,6 +360,7 @@ struct ath6kl_req_key { #define NETDEV_REGISTERED 10 #define SKIP_SCAN 11 #define WLAN_ENABLED 12 +#define TESTMODE 13 struct ath6kl { struct device *dev; @@ -431,6 +434,11 @@ struct ath6kl { #define AR_MCAST_FILTER_MAC_ADDR_SIZE 4 u8 auto_auth_stage; + struct { + void *rx_report; + size_t rx_report_len; + } tm; + u16 conf_flags; wait_queue_head_t event_wq; struct ath6kl_mbox_info mbox_info; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 32b7ef5e2ac..f348357279a 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -23,8 +23,10 @@ #include "hif-ops.h" unsigned int debug_mask; +static unsigned int testmode; module_param(debug_mask, uint, 0644); +module_param(testmode, uint, 0644); /* * Include definitions here that can be used to tune the WLAN module @@ -901,6 +903,28 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) u32 address; int ret; + if (testmode) { + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_TCMD_FIRMWARE_FILE; + break; + case AR6003_REV3_VERSION: + filename = AR6003_REV3_TCMD_FIRMWARE_FILE; + break; + case AR6004_REV1_VERSION: + ath6kl_warn("testmode not supported with ar6004\n"); + return -EOPNOTSUPP; + default: + ath6kl_warn("unknown target version: 0x%x\n", + ar->version.target_ver); + return -EINVAL; + } + + set_bit(TESTMODE, &ar->flag); + + goto get_fw; + } + switch (ar->version.target_ver) { case AR6003_REV2_VERSION: filename = AR6003_REV2_FIRMWARE_FILE; @@ -913,6 +937,8 @@ static int ath6kl_upload_firmware(struct ath6kl *ar) break; } +get_fw: + if (ar->fw == NULL) { ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); if (ret) { diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 69a1b45179c..0c4f39c6c44 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -915,9 +915,10 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) set_bit(WMI_READY, &ar->flag); wake_up(&ar->event_wq); - ath6kl_info("hw %s fw %s\n", + ath6kl_info("hw %s fw %s%s\n", get_hw_id_string(ar->wdev->wiphy->hw_version), - ar->wdev->wiphy->fw_version); + ar->wdev->wiphy->fw_version, + test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); } void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c new file mode 100644 index 00000000000..381eb66a605 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "testmode.h" + +#include + +enum ath6kl_tm_attr { + __ATH6KL_TM_ATTR_INVALID = 0, + ATH6KL_TM_ATTR_CMD = 1, + ATH6KL_TM_ATTR_DATA = 2, + + /* keep last */ + __ATH6KL_TM_ATTR_AFTER_LAST, + ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1, +}; + +enum ath6kl_tm_cmd { + ATH6KL_TM_CMD_TCMD = 0, + ATH6KL_TM_CMD_RX_REPORT = 1, +}; + +#define ATH6KL_TM_DATA_MAX_LEN 5000 + +static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { + [ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 }, + [ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY, + .len = ATH6KL_TM_DATA_MAX_LEN }, +}; + +void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len) +{ + if (down_interruptible(&ar->sem)) + return; + + kfree(ar->tm.rx_report); + + ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL); + ar->tm.rx_report_len = buf_len; + + up(&ar->sem); + + wake_up(&ar->event_wq); +} + +static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len, + struct sk_buff *skb) +{ + int ret = 0; + long left; + + if (down_interruptible(&ar->sem)) + return -ERESTARTSYS; + + if (!test_bit(WMI_READY, &ar->flag)) { + ret = -EIO; + goto out; + } + + if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { + ret = -EBUSY; + goto out; + } + + if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) { + up(&ar->sem); + return -EIO; + } + + left = wait_event_interruptible_timeout(ar->event_wq, + ar->tm.rx_report != NULL, + WMI_TIMEOUT); + + if (left == 0) { + ret = -ETIMEDOUT; + goto out; + } else if (left < 0) { + ret = left; + goto out; + } + + if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) { + ret = -EINVAL; + goto out; + } + + NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len, + ar->tm.rx_report); + + kfree(ar->tm.rx_report); + ar->tm.rx_report = NULL; + +out: + up(&ar->sem); + + return ret; + +nla_put_failure: + ret = -ENOBUFS; + goto out; +} + +int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) +{ + struct ath6kl *ar = wiphy_priv(wiphy); + struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; + int err, buf_len, reply_len; + struct sk_buff *skb; + void *buf; + + err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, + ath6kl_tm_policy); + if (err) + return err; + + if (!tb[ATH6KL_TM_ATTR_CMD]) + return -EINVAL; + + switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) { + case ATH6KL_TM_CMD_TCMD: + if (!tb[ATH6KL_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); + buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); + + ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len); + + return 0; + + break; + case ATH6KL_TM_CMD_RX_REPORT: + if (!tb[ATH6KL_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); + buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); + + reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN); + skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len); + if (!skb) + return -ENOMEM; + + err = ath6kl_tm_rx_report(ar, buf, buf_len, skb); + if (err < 0) { + kfree_skb(skb); + return err; + } + + return cfg80211_testmode_reply(skb); + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h new file mode 100644 index 00000000000..2e6b723d1da --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/testmode.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" + +void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len); +int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index dec869790c1..c34e36806da 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -17,6 +17,7 @@ #include #include "core.h" #include "debug.h" +#include "testmode.h" static int ath6kl_wmi_sync_point(struct wmi *wmi); @@ -1136,6 +1137,13 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) return 0; } +static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len) +{ + ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len); + + return 0; +} + static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len) { if (len < sizeof(struct wmi_fix_rates_reply)) @@ -2509,6 +2517,23 @@ int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl) return ret; } +int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) +{ + struct sk_buff *skb; + int ret; + + skb = ath6kl_wmi_get_new_buf(len); + if (!skb) + return -ENOMEM; + + memcpy(skb->data, buf, len); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG); + + return ret; +} + + s32 ath6kl_wmi_get_rate(s8 rate_index) { if (rate_index == RATE_AUTO) @@ -3007,6 +3032,10 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) case WMI_REPORT_ROAM_DATA_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n"); break; + case WMI_TEST_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n"); + ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len); + break; case WMI_GET_FIXRATES_CMDID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index cb3d27afcc6..5d68d8f2032 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2179,6 +2179,7 @@ int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi); int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg); int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl); +int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); s32 ath6kl_wmi_get_rate(s8 rate_index); -- cgit v1.2.3-70-g09d2 From bdf5396be177b689c00ae6ebed00d13fafaed36e Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 2 Sep 2011 10:32:04 +0300 Subject: ath6kl: add firmware log support Firmware sends binary logs with WMIX_DBGLOG_EVENTID event. Create a buffer which stores the latest logs and which can be copied from fwlog debugfs file with cp command. To save memory firmware log support is enabled only when CONFIG_ATH6KL_DEBUG is enabled. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 9 ++ drivers/net/wireless/ath/ath6kl/debug.c | 154 ++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath6kl/debug.h | 13 +++ drivers/net/wireless/ath/ath6kl/init.c | 2 + drivers/net/wireless/ath/ath6kl/target.h | 3 + drivers/net/wireless/ath/ath6kl/wmi.c | 1 + 6 files changed, 181 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index cfbbad9feb9..319e768d9ad 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "htc.h" #include "wmi.h" @@ -467,6 +468,14 @@ struct ath6kl { u32 send_action_id; bool probe_req_report; u16 next_chan; + +#ifdef CONFIG_ATH6KL_DEBUG + struct { + struct circ_buf fwlog_buf; + spinlock_t fwlog_lock; + void *fwlog_tmp; + } debug; +#endif /* CONFIG_ATH6KL_DEBUG */ }; static inline void *ath6kl_priv(struct net_device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 2b462876cec..b2706da5814 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -15,7 +15,23 @@ */ #include "core.h" + +#include + #include "debug.h" +#include "target.h" + +struct ath6kl_fwlog_slot { + __le32 timestamp; + __le32 length; + + /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ + u8 payload[0]; +}; + +#define ATH6KL_FWLOG_SIZE 32768 +#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ + ATH6KL_FWLOG_PAYLOAD_SIZE) int ath6kl_printk(const char *level, const char *fmt, ...) { @@ -153,6 +169,117 @@ static int ath6kl_debugfs_open(struct inode *inode, struct file *file) return 0; } +static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, + size_t buf_len) +{ + struct circ_buf *fwlog = &ar->debug.fwlog_buf; + size_t space; + int i; + + /* entries must all be equal size */ + if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) + return; + + space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); + if (space < buf_len) + /* discard oldest slot */ + fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & + (ATH6KL_FWLOG_SIZE - 1); + + for (i = 0; i < buf_len; i += space) { + space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, + ATH6KL_FWLOG_SIZE); + + if ((size_t) space > buf_len - i) + space = buf_len - i; + + memcpy(&fwlog->buf[fwlog->head], buf, space); + fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); + } + +} + +void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) +{ + struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; + size_t slot_len; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return; + + spin_lock_bh(&ar->debug.fwlog_lock); + + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + memcpy(slot->payload, buf, len); + + slot_len = sizeof(*slot) + len; + + if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) + memset(slot->payload + len, 0, + ATH6KL_FWLOG_SLOT_SIZE - slot_len); + + ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); + + spin_unlock_bh(&ar->debug.fwlog_lock); +} + +static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) +{ + return CIRC_CNT(ar->debug.fwlog_buf.head, + ar->debug.fwlog_buf.tail, + ATH6KL_FWLOG_SLOT_SIZE) == 0; +} + +static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct circ_buf *fwlog = &ar->debug.fwlog_buf; + size_t len = 0, buf_len = count; + ssize_t ret_cnt; + char *buf; + int ccnt; + + buf = vmalloc(buf_len); + if (!buf) + return -ENOMEM; + + spin_lock_bh(&ar->debug.fwlog_lock); + + while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { + ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, + ATH6KL_FWLOG_SIZE); + + if ((size_t) ccnt > buf_len - len) + ccnt = buf_len - len; + + memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); + len += ccnt; + + fwlog->tail = (fwlog->tail + ccnt) & + (ATH6KL_FWLOG_SIZE - 1); + } + + spin_unlock_bh(&ar->debug.fwlog_lock); + + if (WARN_ON(len > buf_len)) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + + vfree(buf); + + return ret_cnt; +} + +static const struct file_operations fops_fwlog = { + .open = ath6kl_debugfs_open, + .read = ath6kl_fwlog_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -358,10 +485,25 @@ static const struct file_operations fops_credit_dist_stats = { int ath6kl_debug_init(struct ath6kl *ar) { + ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); + if (ar->debug.fwlog_buf.buf == NULL) + return -ENOMEM; + + ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); + if (ar->debug.fwlog_tmp == NULL) { + vfree(ar->debug.fwlog_buf.buf); + return -ENOMEM; + } + + spin_lock_init(&ar->debug.fwlog_lock); + ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->wdev->wiphy->debugfsdir); - if (!ar->debugfs_phy) + if (!ar->debugfs_phy) { + vfree(ar->debug.fwlog_buf.buf); + kfree(ar->debug.fwlog_tmp); return -ENOMEM; + } debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, &fops_tgt_stats); @@ -369,6 +511,16 @@ int ath6kl_debug_init(struct ath6kl *ar) debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar, &fops_credit_dist_stats); + debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, + &fops_fwlog); + return 0; } + +void ath6kl_debug_cleanup(struct ath6kl *ar) +{ + vfree(ar->debug.fwlog_buf.buf); + kfree(ar->debug.fwlog_tmp); +} + #endif diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index e8c9ea9ce02..f0d64711b41 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -78,7 +78,10 @@ void ath6kl_dump_registers(struct ath6kl_device *dev, struct ath6kl_irq_proc_registers *irq_proc_reg, struct ath6kl_irq_enable_reg *irq_en_reg); void dump_cred_dist_stats(struct htc_target *target); +void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len); int ath6kl_debug_init(struct ath6kl *ar); +void ath6kl_debug_cleanup(struct ath6kl *ar); + #else static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, const char *fmt, ...) @@ -101,9 +104,19 @@ static inline void ath6kl_dump_registers(struct ath6kl_device *dev, static inline void dump_cred_dist_stats(struct htc_target *target) { } + +void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) +{ +} + static inline int ath6kl_debug_init(struct ath6kl *ar) { return 0; } + +void ath6kl_debug_cleanup(struct ath6kl *ar) +{ +} + #endif #endif diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 96953be5cd7..a638c3c9b79 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1389,6 +1389,8 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) ath6kl_bmi_cleanup(ar); + ath6kl_debug_cleanup(ar); + if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { unregister_netdev(dev); clear_bit(NETDEV_REGISTERED, &ar->flag); diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 53e2c786f8e..6c66a08e179 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -340,4 +340,7 @@ struct host_interest { #define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400 #define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000 #define AR6004_REV1_RAM_RESERVE_SIZE 11264 + +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + #endif diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c34e36806da..954d5e18e88 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2903,6 +2903,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) case WMIX_HB_CHALLENGE_RESP_EVENTID: break; case WMIX_DBGLOG_EVENTID: + ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len); break; default: ath6kl_err("unknown cmd id 0x%x\n", id); -- cgit v1.2.3-70-g09d2 From 939f1ccec80bd2dad5638de2a6819c66d4cb6f32 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 2 Sep 2011 10:32:04 +0300 Subject: ath6kl: implement support to set firmware log parameters Firmware log parameters can be controlled now with help of fwlog_mask debugfs file. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/debug.c | 51 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.c | 19 ++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 6 ++++ 4 files changed, 77 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 319e768d9ad..58c810acdbf 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -474,6 +474,7 @@ struct ath6kl { struct circ_buf fwlog_buf; spinlock_t fwlog_lock; void *fwlog_tmp; + u32 fwlog_mask; } debug; #endif /* CONFIG_ATH6KL_DEBUG */ }; diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index b2706da5814..239c092d3e1 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -17,6 +17,7 @@ #include "core.h" #include +#include #include "debug.h" #include "target.h" @@ -32,6 +33,7 @@ struct ath6kl_fwlog_slot { #define ATH6KL_FWLOG_SIZE 32768 #define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ ATH6KL_FWLOG_PAYLOAD_SIZE) +#define ATH6KL_FWLOG_VALID_MASK 0x1ffff int ath6kl_printk(const char *level, const char *fmt, ...) { @@ -280,6 +282,46 @@ static const struct file_operations fops_fwlog = { .llseek = default_llseek, }; +static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + char buf[16]; + int len; + + len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath6kl_fwlog_mask_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + int ret; + + ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); + if (ret) + return ret; + + ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, + ATH6KL_FWLOG_VALID_MASK, + ar->debug.fwlog_mask); + if (ret) + return ret; + + return count; +} + +static const struct file_operations fops_fwlog_mask = { + .open = ath6kl_debugfs_open, + .read = ath6kl_fwlog_mask_read, + .write = ath6kl_fwlog_mask_write, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -497,6 +539,12 @@ int ath6kl_debug_init(struct ath6kl *ar) spin_lock_init(&ar->debug.fwlog_lock); + /* + * Actually we are lying here but don't know how to read the mask + * value from the firmware. + */ + ar->debug.fwlog_mask = 0; + ar->debugfs_phy = debugfs_create_dir("ath6kl", ar->wdev->wiphy->debugfsdir); if (!ar->debugfs_phy) { @@ -514,6 +562,9 @@ int ath6kl_debug_init(struct ath6kl *ar) debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, &fops_fwlog); + debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, + ar, &fops_fwlog_mask); + return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 954d5e18e88..7201a72ac1b 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2412,6 +2412,25 @@ int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source) return ret; } +int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config) +{ + struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data; + cmd->valid = cpu_to_le32(valid); + cmd->config = cpu_to_le32(config); + + ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + int ath6kl_wmi_get_stats_cmd(struct wmi *wmi) { return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 5d68d8f2032..1c565816f62 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2083,6 +2083,11 @@ struct wmix_hb_challenge_resp_cmd { __le32 source; } __packed; +struct ath6kl_wmix_dbglog_cfg_module_cmd { + __le32 valid; + __le32 config; +} __packed; + /* End of Extended WMI (WMIX) */ enum wmi_sync_flag { @@ -2162,6 +2167,7 @@ int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy); int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); +int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config); int ath6kl_wmi_get_stats_cmd(struct wmi *wmi); int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, -- cgit v1.2.3-70-g09d2 From e5090444be811ce45653969363be8fcb4c52d597 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Wed, 31 Aug 2011 15:02:19 +0530 Subject: ath6kl: Add debugfs entry to modify roaming parameters. Firmware initiates roaming only after it reaches a rssi of 20. This lower rssi threshold can be modified through a wmi command to modify the roaming behavior. kvalo: rename debugfs functions and move comment about rssi units next to ath6kl_wmi_set_roam_lrssi_cmd() Signed-off-by: Vivek Natarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/debug.c | 47 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/init.c | 1 + drivers/net/wireless/ath/ath6kl/wmi.c | 29 ++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 41 ++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index de5308727b6..faf80157121 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -394,6 +394,7 @@ struct ath6kl { u16 bss_ch; u16 listen_intvl_b; u16 listen_intvl_t; + u8 lrssi_roam_threshold; struct ath6kl_version version; u32 target_type; u8 tx_pwr; diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index cb89776f948..8bc47537637 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -714,6 +714,51 @@ static const struct file_operations fops_reg_dump = { .llseek = default_llseek, }; +static ssize_t ath6kl_lrssi_roam_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + unsigned long lrssi_roam_threshold; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (strict_strtoul(buf, 0, &lrssi_roam_threshold)) + return -EINVAL; + + ar->lrssi_roam_threshold = lrssi_roam_threshold; + + ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold); + + return count; +} + +static ssize_t ath6kl_lrssi_roam_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_lrssi_roam_threshold = { + .read = ath6kl_lrssi_roam_read, + .write = ath6kl_lrssi_roam_write, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath6kl_debug_init(struct ath6kl *ar) { ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); @@ -760,6 +805,8 @@ int ath6kl_debug_init(struct ath6kl *ar) debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, &fops_reg_dump); + debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, + ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index d234dc22e70..3d67025b72c 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -280,6 +280,7 @@ static void ath6kl_init_control_info(struct ath6kl *ar) memset(&ar->sc_params, 0, sizeof(ar->sc_params)); ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; + ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; memset((u8 *)ar->sta_list, 0, AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 7201a72ac1b..c9ec6303db7 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -666,6 +666,35 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len) return 0; } +/* + * Mechanism to modify the roaming behavior in the firmware. The lower rssi + * at which the station has to roam can be passed with + * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level + * in dBm. + */ +int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi) +{ + struct sk_buff *skb; + struct roam_ctrl_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct roam_ctrl_cmd *) skb->data; + + cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD); + cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi + + DEF_SCAN_FOR_ROAM_INTVL); + cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi); + cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR; + cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS; + + ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_ROAM_CTRL_CMDID, NO_SYNC_WMIFLAG); + + return 0; +} + static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_connect_event *ev; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 1c565816f62..a78e21b9177 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1333,6 +1333,46 @@ enum wmi_bi_ftype { PROBEREQ_FTYPE, }; +#define DEF_LRSSI_SCAN_PERIOD 5 +#define DEF_LRSSI_ROAM_THRESHOLD 20 +#define DEF_LRSSI_ROAM_FLOOR 60 +#define DEF_SCAN_FOR_ROAM_INTVL 2 + +enum wmi_roam_ctrl { + WMI_FORCE_ROAM = 1, + WMI_SET_ROAM_MODE, + WMI_SET_HOST_BIAS, + WMI_SET_LRSSI_SCAN_PARAMS, +}; + +struct bss_bias { + u8 bssid[ETH_ALEN]; + u8 bias; +} __packed; + +struct bss_bias_info { + u8 num_bss; + struct bss_bias bss_bias[1]; +} __packed; + +struct low_rssi_scan_params { + __le16 lrssi_scan_period; + a_sle16 lrssi_scan_threshold; + a_sle16 lrssi_roam_threshold; + u8 roam_rssi_floor; + u8 reserved[1]; +} __packed; + +struct roam_ctrl_cmd { + union { + u8 bssid[ETH_ALEN]; + u8 roam_mode; + struct bss_bias_info bss; + struct low_rssi_scan_params params; + } __packed info; + u8 roam_ctrl; +} __packed; + struct wmi_bss_info_hdr { __le16 ch; @@ -2190,6 +2230,7 @@ int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); s32 ath6kl_wmi_get_rate(s8 rate_index); int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); +int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid, u32 ssid_len, bool is_wpa2, -- cgit v1.2.3-70-g09d2 From d6e51e6a0cc50b6dd8d9f3a733427cca3f9afdee Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 5 Sep 2011 17:38:44 +0300 Subject: ath6kl: Fix WMI message structure for AP_SET_PVB There is a 2-octet reserved field between the flag and aid fields. Fix that to make the target actually behave as requested. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 1 + drivers/net/wireless/ath/ath6kl/wmi.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index c9ec6303db7..b2c5c40727f 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2740,6 +2740,7 @@ int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag) cmd = (struct wmi_ap_set_pvb_cmd *) skb->data; cmd->aid = cpu_to_le16(aid); + cmd->rsvd = cpu_to_le16(0); cmd->flag = cpu_to_le32(flag); ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index a78e21b9177..e86b81d326e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1922,6 +1922,7 @@ struct wmi_ap_set_mlme_cmd { struct wmi_ap_set_pvb_cmd { __le32 flag; + __le16 rsvd; __le16 aid; } __packed; -- cgit v1.2.3-70-g09d2 From 572e27c00c9d1250ae2b4951eae7e73992174138 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 5 Sep 2011 17:38:45 +0300 Subject: ath6kl: Fix AP mode connect event parsing and TIM updates This cleans up the connect event parsing by defining a union in struct wmi_connect_event to match with the three possible sets of fields that the target uses depending on which type of connect event is being indicated. In addition, two AP cases are now separated from ath6kl_connect_event() so that correct field names can be used to make it actually possible to understand what the code is doing. The bug hiding in the previous mess was in parsing the AID incorrectly when processing the new station connecting event in AP mode. The fix here for that is also fixing TIM updates for PS buffering to use the correct AID. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/core.h | 4 ++ drivers/net/wireless/ath/ath6kl/main.c | 92 +++++++++++++++------------------- drivers/net/wireless/ath/ath6kl/wmi.c | 44 ++++++++++++++-- drivers/net/wireless/ath/ath6kl/wmi.h | 29 +++++++++-- 4 files changed, 107 insertions(+), 62 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index fdb796fe79b..054da13ce48 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -560,6 +560,10 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u16 beacon_int, enum network_type net_type, u8 beacon_ie_len, u8 assoc_req_len, u8 assoc_resp_len, u8 *assoc_info); +void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel); +void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr, + u8 keymgmt, u8 ucipher, u8 auth, + u8 assoc_req_len, u8 *assoc_info); void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, u8 assoc_resp_len, u8 *assoc_info, u16 prot_reason_status); diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 3cefca65fc0..d510046c99d 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -519,57 +519,55 @@ static void ath6kl_install_static_wep_keys(struct ath6kl *ar) } } -static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, - u16 listen_int, u16 beacon_int, - u8 assoc_req_len, u8 *assoc_info) +void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel) { - struct net_device *dev = ar->net_dev; - u8 *ies = NULL, *wpa_ie = NULL, *pos; - size_t ies_len = 0; - struct station_info sinfo; struct ath6kl_req_key *ik; int res; u8 key_rsc[ATH6KL_KEY_SEQ_LEN]; - if (memcmp(dev->dev_addr, bssid, ETH_ALEN) == 0) { - ik = &ar->ap_mode_bkey; + ik = &ar->ap_mode_bkey; - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", - channel); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel); - switch (ar->auth_mode) { - case NONE_AUTH: - if (ar->prwise_crypto == WEP_CRYPT) - ath6kl_install_static_wep_keys(ar); + switch (ar->auth_mode) { + case NONE_AUTH: + if (ar->prwise_crypto == WEP_CRYPT) + ath6kl_install_static_wep_keys(ar); + break; + case WPA_PSK_AUTH: + case WPA2_PSK_AUTH: + case (WPA_PSK_AUTH | WPA2_PSK_AUTH): + if (!ik->valid) break; - case WPA_PSK_AUTH: - case WPA2_PSK_AUTH: - case (WPA_PSK_AUTH|WPA2_PSK_AUTH): - if (!ik->valid) - break; - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " - "the initial group key for AP mode\n"); - memset(key_rsc, 0, sizeof(key_rsc)); - res = ath6kl_wmi_addkey_cmd( - ar->wmi, ik->key_index, ik->key_type, - GROUP_USAGE, ik->key_len, key_rsc, ik->key, - KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); - if (res) { - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " - "addkey failed: %d\n", res); - } - break; + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " + "the initial group key for AP mode\n"); + memset(key_rsc, 0, sizeof(key_rsc)); + res = ath6kl_wmi_addkey_cmd( + ar->wmi, ik->key_index, ik->key_type, + GROUP_USAGE, ik->key_len, key_rsc, ik->key, + KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); + if (res) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " + "addkey failed: %d\n", res); } - - ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); - set_bit(CONNECTED, &ar->flag); - netif_carrier_on(ar->net_dev); - return; + break; } - ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", - bssid, channel); + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + set_bit(CONNECTED, &ar->flag); + netif_carrier_on(ar->net_dev); +} + +void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr, + u8 keymgmt, u8 ucipher, u8 auth, + u8 assoc_req_len, u8 *assoc_info) +{ + u8 *ies = NULL, *wpa_ie = NULL, *pos; + size_t ies_len = 0; + struct station_info sinfo; + + ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { struct ieee80211_mgmt *mgmt = @@ -606,10 +604,9 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, pos += 2 + pos[1]; } - ath6kl_add_new_sta(ar, bssid, channel, wpa_ie, + ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie, wpa_ie ? 2 + wpa_ie[1] : 0, - listen_int & 0xFF, beacon_int, - (listen_int >> 8) & 0xFF); + keymgmt, ucipher, auth); /* send event to application */ memset(&sinfo, 0, sizeof(sinfo)); @@ -620,11 +617,9 @@ static void ath6kl_connect_ap_mode(struct ath6kl *ar, u16 channel, u8 *bssid, sinfo.assoc_req_ies_len = ies_len; sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; - cfg80211_new_sta(ar->net_dev, bssid, &sinfo, GFP_KERNEL); + cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL); netif_wake_queue(ar->net_dev); - - return; } /* Functions for Tx credit handling */ @@ -1030,13 +1025,6 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, { unsigned long flags; - if (ar->nw_type == AP_NETWORK) { - ath6kl_connect_ap_mode(ar, channel, bssid, listen_int, - beacon_int, assoc_req_len, - assoc_info + beacon_ie_len); - return; - } - ath6kl_cfg80211_connect_event(ar, channel, bssid, listen_int, beacon_int, net_type, beacon_ie_len, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b2c5c40727f..b56830f6d47 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -699,14 +699,47 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_connect_event *ev; u8 *pie, *peie; + struct ath6kl *ar = wmi->parent_dev; if (len < sizeof(struct wmi_connect_event)) return -EINVAL; ev = (struct wmi_connect_event *) datap; + if (ar->nw_type == AP_NETWORK) { + /* AP mode start/STA connected event */ + struct net_device *dev = ar->net_dev; + if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) { + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM " + "(AP started)\n", + __func__, le16_to_cpu(ev->u.ap_bss.ch), + ev->u.ap_bss.bssid); + ath6kl_connect_ap_mode_bss( + ar, le16_to_cpu(ev->u.ap_bss.ch)); + } else { + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM " + "auth=%u keymgmt=%u cipher=%u apsd_info=%u " + "(STA connected)\n", + __func__, ev->u.ap_sta.aid, + ev->u.ap_sta.mac_addr, + ev->u.ap_sta.auth, + ev->u.ap_sta.keymgmt, + le16_to_cpu(ev->u.ap_sta.cipher), + ev->u.ap_sta.apsd_info); + ath6kl_connect_ap_mode_sta( + ar, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, + ev->u.ap_sta.keymgmt, + le16_to_cpu(ev->u.ap_sta.cipher), + ev->u.ap_sta.auth, ev->assoc_req_len, + ev->assoc_info + ev->beacon_ie_len); + } + return 0; + } + + /* STA/IBSS mode connection event */ + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM\n", - __func__, ev->ch, ev->bssid); + __func__, le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid); /* Start of assoc rsp IEs */ pie = ev->assoc_info + ev->beacon_ie_len + @@ -735,10 +768,11 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) pie += pie[1] + 2; } - ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->ch), ev->bssid, - le16_to_cpu(ev->listen_intvl), - le16_to_cpu(ev->beacon_intvl), - le32_to_cpu(ev->nw_type), + ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->u.sta.ch), + ev->u.sta.bssid, + le16_to_cpu(ev->u.sta.listen_intvl), + le16_to_cpu(ev->u.sta.beacon_intvl), + le32_to_cpu(ev->u.sta.nw_type), ev->beacon_ie_len, ev->assoc_req_len, ev->assoc_resp_len, ev->assoc_info); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index e86b81d326e..5ca8c8e904c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1275,11 +1275,30 @@ struct wmi_ready_event_2 { /* Connect Event */ struct wmi_connect_event { - __le16 ch; - u8 bssid[ETH_ALEN]; - __le16 listen_intvl; - __le16 beacon_intvl; - __le32 nw_type; + union { + struct { + __le16 ch; + u8 bssid[ETH_ALEN]; + __le16 listen_intvl; + __le16 beacon_intvl; + __le32 nw_type; + } sta; + struct { + u8 phymode; + u8 aid; + u8 mac_addr[ETH_ALEN]; + u8 auth; + u8 keymgmt; + __le16 cipher; + u8 apsd_info; + u8 unused[3]; + } ap_sta; + struct { + __le16 ch; + u8 bssid[ETH_ALEN]; + u8 unused[8]; + } ap_bss; + } u; u8 beacon_ie_len; u8 assoc_req_len; u8 assoc_resp_len; -- cgit v1.2.3-70-g09d2 From 060337604577e55c5bf3246bcaf161929c603d54 Mon Sep 17 00:00:00 2001 From: Vivek Natarajan Date: Tue, 6 Sep 2011 13:01:36 +0530 Subject: ath6kl: Process regulatory requests from firmware. Process the regulatory code from eeprom and pass the country information to cfg80211. kvalo: add space between struct name and * Signed-off-by: Vivek Natarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 78 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 6 +++ 2 files changed, 84 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b56830f6d47..dbddb91389d 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -18,6 +18,8 @@ #include "core.h" #include "debug.h" #include "testmode.h" +#include "../regd.h" +#include "../regd_common.h" static int ath6kl_wmi_sync_point(struct wmi *wmi); @@ -779,6 +781,81 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) return 0; } +static struct country_code_to_enum_rd * +ath6kl_regd_find_country(u16 countryCode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].countryCode == countryCode) + return &allCountries[i]; + } + + return NULL; +} + +static struct reg_dmn_pair_mapping * +ath6kl_get_regpair(u16 regdmn) +{ + int i; + + if (regdmn == NO_ENUMRD) + return NULL; + + for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { + if (regDomainPairs[i].regDmnEnum == regdmn) + return ®DomainPairs[i]; + } + + return NULL; +} + +static struct country_code_to_enum_rd * +ath6kl_regd_find_country_by_rd(u16 regdmn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].regDmnEnum == regdmn) + return &allCountries[i]; + } + + return NULL; +} + +static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) +{ + + struct ath6kl_wmi_regdomain *ev; + struct country_code_to_enum_rd *country = NULL; + struct reg_dmn_pair_mapping *regpair = NULL; + char alpha2[2]; + u32 reg_code; + + ev = (struct ath6kl_wmi_regdomain *) datap; + reg_code = le32_to_cpu(ev->reg_code); + + if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) + country = ath6kl_regd_find_country((u16) reg_code); + else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { + + regpair = ath6kl_get_regpair((u16) reg_code); + country = ath6kl_regd_find_country_by_rd((u16) reg_code); + ath6kl_dbg(ATH6KL_DBG_WMI, "ath6kl: Regpair used: 0x%0x\n", + regpair->regDmnEnum); + } + + if (country) { + alpha2[0] = country->isoName[0]; + alpha2[1] = country->isoName[1]; + + regulatory_hint(wmi->parent_dev->wdev->wiphy, alpha2); + + ath6kl_dbg(ATH6KL_DBG_WMI, "ath6kl: Country alpha2 being used: %c%c\n", + alpha2[0], alpha2[1]); + } +} + static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) { struct wmi_disconnect_event *ev; @@ -3068,6 +3145,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_REGDOMAIN_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); + ath6kl_wmi_regdomain_event(wmi, datap, len); break; case WMI_PSTREAM_TIMEOUT_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 5ca8c8e904c..dc49ef86c1c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1325,6 +1325,12 @@ enum wmi_disconnect_reason { IBSS_MERGE = 0xe, }; +#define ATH6KL_COUNTRY_RD_SHIFT 16 + +struct ath6kl_wmi_regdomain { + __le32 reg_code; +}; + struct wmi_disconnect_event { /* reason code, see 802.11 spec. */ __le16 proto_reason_status; -- cgit v1.2.3-70-g09d2 From f195d5076a734c6d96a0dd80fe2a3b1e608e7979 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 19 Sep 2011 19:15:00 +0300 Subject: ath6kl: Remove deprecated WMI_OPT_RX_FRAME_EVENTID processing This event has been deprecated and there is no need for ath6kl to include code for processing it. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 40 +---------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index dbddb91389d..24f0e3eb421 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1185,44 +1185,6 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) return 0; } -static int ath6kl_wmi_opt_frame_event_rx(struct wmi *wmi, u8 *datap, int len) -{ - struct bss *bss; - struct wmi_opt_rx_info_hdr *bih; - u8 *buf; - - if (len <= sizeof(struct wmi_opt_rx_info_hdr)) - return -EINVAL; - - bih = (struct wmi_opt_rx_info_hdr *) datap; - buf = datap + sizeof(struct wmi_opt_rx_info_hdr); - len -= sizeof(struct wmi_opt_rx_info_hdr); - - ath6kl_dbg(ATH6KL_DBG_WMI, "opt frame event %2.2x:%2.2x\n", - bih->bssid[4], bih->bssid[5]); - - bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid); - if (bss != NULL) { - /* Free up the node. We are about to allocate a new node. */ - wlan_node_reclaim(&wmi->parent_dev->scan_table, bss); - } - - bss = wlan_node_alloc(len); - if (!bss) - return -ENOMEM; - - bss->ni_snr = bih->snr; - bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); - - if (WARN_ON(!bss->ni_buf)) - return -EINVAL; - - memcpy(bss->ni_buf, buf, len); - wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); - - return 0; -} - /* Inactivity timeout of a fatpipe(pstream) at the target */ static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap, int len) @@ -3175,7 +3137,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_OPT_RX_FRAME_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n"); - ret = ath6kl_wmi_opt_frame_event_rx(wmi, datap, len); + /* this event has been deprecated */ break; case WMI_REPORT_ROAM_TBL_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n"); -- cgit v1.2.3-70-g09d2 From 1aaa8c7469db14c3cbb0776afda0fb007eb43f46 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 19 Sep 2011 19:15:03 +0300 Subject: ath6kl: Replace internal node table with cfg80211 BSS table The internal node table in ath6kl was not really used for any useful purpose. It was just used to collect scan results during a scan and then provide them in a burst to cfg80211 at the completion of the scan. There is no point in doing this since cfg80211 is perfectly capable of maintaining the BSS table and the BSS inform messages are sent in separate function calls anyway. This provides more complete information in the cfg80211 BSS table since this allows Beacon and Probe Response frames to be distinguished and IEs from them reported separately. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 296 ++++++---------------------------- 1 file changed, 45 insertions(+), 251 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 24f0e3eb421..ff13e0bc646 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -910,277 +910,74 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len) return 0; } -static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len, - struct ath6kl_common_ie *cie) -{ - u8 *frm, *efrm; - u8 elemid_ssid = false; - - frm = buf; - efrm = (u8 *) (frm + frame_len); - - /* - * beacon/probe response frame format - * [8] time stamp - * [2] beacon interval - * [2] capability information - * [tlv] ssid - * [tlv] supported rates - * [tlv] country information - * [tlv] parameter set (FH/DS) - * [tlv] erp information - * [tlv] extended supported rates - * [tlv] WMM - * [tlv] WPA or RSN - * [tlv] Atheros Advanced Capabilities - */ - if ((efrm - frm) < 12) - return -EINVAL; - - memset(cie, 0, sizeof(*cie)); - - cie->ie_tstamp = frm; - frm += 8; - cie->ie_beaconInt = *(u16 *) frm; - frm += 2; - cie->ie_capInfo = *(u16 *) frm; - frm += 2; - cie->ie_chan = 0; - - while (frm < efrm) { - switch (*frm) { - case WLAN_EID_SSID: - if (!elemid_ssid) { - cie->ie_ssid = frm; - elemid_ssid = true; - } - break; - case WLAN_EID_SUPP_RATES: - cie->ie_rates = frm; - break; - case WLAN_EID_COUNTRY: - cie->ie_country = frm; - break; - case WLAN_EID_FH_PARAMS: - break; - case WLAN_EID_DS_PARAMS: - cie->ie_chan = frm[2]; - break; - case WLAN_EID_TIM: - cie->ie_tim = frm; - break; - case WLAN_EID_IBSS_PARAMS: - break; - case WLAN_EID_EXT_SUPP_RATES: - cie->ie_xrates = frm; - break; - case WLAN_EID_ERP_INFO: - if (frm[1] != 1) - return -EINVAL; - - cie->ie_erp = frm[2]; - break; - case WLAN_EID_RSN: - cie->ie_rsn = frm; - break; - case WLAN_EID_HT_CAPABILITY: - cie->ie_htcap = frm; - break; - case WLAN_EID_HT_INFORMATION: - cie->ie_htop = frm; - break; - case WLAN_EID_VENDOR_SPECIFIC: - if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 && - frm[4] == 0xf2) { - /* OUT Type (00:50:F2) */ - - if (frm[5] == WPA_OUI_TYPE) { - /* WPA OUT */ - cie->ie_wpa = frm; - } else if (frm[5] == WMM_OUI_TYPE) { - /* WMM OUT */ - cie->ie_wmm = frm; - } else if (frm[5] == WSC_OUT_TYPE) { - /* WSC OUT */ - cie->ie_wsc = frm; - } - - } else if (frm[1] > 3 && frm[2] == 0x00 - && frm[3] == 0x03 && frm[4] == 0x7f - && frm[5] == ATH_OUI_TYPE) { - /* Atheros OUI (00:03:7f) */ - cie->ie_ath = frm; - } - break; - default: - break; - } - frm += frm[1] + 2; - } - - if ((cie->ie_rates == NULL) - || (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE)) - return -EINVAL; - - if ((cie->ie_ssid == NULL) - || (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN)) - return -EINVAL; - - return 0; -} - static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) { - struct bss *bss = NULL; struct wmi_bss_info_hdr *bih; - u8 cached_ssid_len = 0; - u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 }; - u8 beacon_ssid_len = 0; - u8 *buf, *ie_ssid; - u8 *ni_buf; - int buf_len; - - int ret; + u8 *buf; + struct ieee80211_channel *channel; + struct ath6kl *ar = wmi->parent_dev; + struct ieee80211_mgmt *mgmt; + struct cfg80211_bss *bss; if (len <= sizeof(struct wmi_bss_info_hdr)) return -EINVAL; bih = (struct wmi_bss_info_hdr *) datap; - bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid); - - if (a_sle16_to_cpu(bih->rssi) > 0) { - if (bss == NULL) - return 0; - else - bih->rssi = a_cpu_to_sle16(bss->ni_rssi); - } - buf = datap + sizeof(struct wmi_bss_info_hdr); len -= sizeof(struct wmi_bss_info_hdr); ath6kl_dbg(ATH6KL_DBG_WMI, - "bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n", - bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid); - - if (bss != NULL) { - /* - * Free up the node. We are about to allocate a new node. - * In case of hidden AP, beacon will not have ssid, - * but a directed probe response will have it, - * so cache the probe-resp-ssid if already present. - */ - if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) { - ie_ssid = bss->ni_cie.ie_ssid; - if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && - (ie_ssid[2] != 0)) { - cached_ssid_len = ie_ssid[1]; - memcpy(cached_ssid, ie_ssid + 2, - cached_ssid_len); - } - } - - /* - * Use the current average rssi of associated AP base on - * assumption - * 1. Most os with GUI will update RSSI by - * ath6kl_wmi_get_stats_cmd() periodically. - * 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling - * ath6kl_wmi_startscan_cmd(...) - * The average value of RSSI give end-user better feeling for - * instance value of scan result. It also sync up RSSI info - * in GUI between scan result and RSSI signal icon. - */ - if (memcmp(wmi->parent_dev->bssid, bih->bssid, ETH_ALEN) == 0) { - bih->rssi = a_cpu_to_sle16(bss->ni_rssi); - bih->snr = bss->ni_snr; - } - - wlan_node_reclaim(&wmi->parent_dev->scan_table, bss); - } - - /* - * beacon/probe response frame format - * [8] time stamp - * [2] beacon interval - * [2] capability information - * [tlv] ssid - */ - beacon_ssid_len = buf[SSID_IE_LEN_INDEX]; - - /* - * If ssid is cached for this hidden AP, then change - * buffer len accordingly. - */ - if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && - (cached_ssid_len != 0) && - (beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len && - buf[SSID_IE_LEN_INDEX + 1] == 0))) { - - len += (cached_ssid_len - beacon_ssid_len); - } + "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" " + "frame_type=%d\n", + bih->ch, bih->snr, a_sle16_to_cpu(bih->rssi), bih->bssid, + bih->frame_type); - bss = wlan_node_alloc(len); - if (!bss) - return -ENOMEM; + if (bih->frame_type != BEACON_FTYPE && + bih->frame_type != PROBERESP_FTYPE) + return 0; /* Only update BSS table for now */ - bss->ni_snr = bih->snr; - bss->ni_rssi = a_sle16_to_cpu(bih->rssi); + channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch)); + if (channel == NULL) + return -EINVAL; - if (WARN_ON(!bss->ni_buf)) + if (len < 8 + 2 + 2) return -EINVAL; /* - * In case of hidden AP, beacon will not have ssid, - * but a directed probe response will have it, - * so place the cached-ssid(probe-resp) in the bss info. + * In theory, use of cfg80211_inform_bss() would be more natural here + * since we do not have the full frame. However, at least for now, + * cfg80211 can only distinguish Beacon and Probe Response frames from + * each other when using cfg80211_inform_bss_frame(), so let's build a + * fake IEEE 802.11 header to be able to take benefit of this. */ - if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && - (cached_ssid_len != 0) && - (beacon_ssid_len == 0 || (beacon_ssid_len && - buf[SSID_IE_LEN_INDEX + 1] == 0))) { - ni_buf = bss->ni_buf; - buf_len = len; - - /* - * Copy the first 14 bytes: - * time-stamp(8), beacon-interval(2), - * cap-info(2), ssid-id(1), ssid-len(1). - */ - memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1); - - ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len; - ni_buf += (SSID_IE_LEN_INDEX + 1); - - buf += (SSID_IE_LEN_INDEX + 1); - buf_len -= (SSID_IE_LEN_INDEX + 1); - - memcpy(ni_buf, cached_ssid, cached_ssid_len); - ni_buf += cached_ssid_len; - - buf += beacon_ssid_len; - buf_len -= beacon_ssid_len; - - if (cached_ssid_len > beacon_ssid_len) - buf_len -= (cached_ssid_len - beacon_ssid_len); - - memcpy(ni_buf, buf, buf_len); - } else - memcpy(bss->ni_buf, buf, len); + mgmt = kmalloc(24 + len, GFP_ATOMIC); + if (mgmt == NULL) + return -EINVAL; - bss->ni_framelen = len; + if (bih->frame_type == BEACON_FTYPE) { + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + } else { + struct net_device *dev = ar->net_dev; - ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie); - if (ret) { - wlan_node_free(bss); - return -EINVAL; + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + memcpy(mgmt->da, dev->dev_addr, ETH_ALEN); } + mgmt->duration = cpu_to_le16(0); + memcpy(mgmt->sa, bih->bssid, ETH_ALEN); + memcpy(mgmt->bssid, bih->bssid, ETH_ALEN); + mgmt->seq_ctrl = cpu_to_le16(0); - /* - * Update the frequency in ie_chan, overwriting of channel number - * which is done in ath6kl_wlan_parse_beacon - */ - bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); - wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); + memcpy(&mgmt->u.beacon, buf, len); + + bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt, + 24 + len, bih->snr * 100, GFP_ATOMIC); + kfree(mgmt); + if (bss == NULL) + return -ENOMEM; + cfg80211_put_bss(bss); return 0; } @@ -1295,9 +1092,6 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len) ev = (struct wmi_scan_complete_event *) datap; - if (a_sle32_to_cpu(ev->status) == 0) - wlan_refresh_inactive_nodes(wmi->parent_dev); - ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status)); wmi->is_probe_ssid = false; -- cgit v1.2.3-70-g09d2 From 457fb0415a887b6389854b850e9815cf0ec44178 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 19 Sep 2011 19:15:04 +0300 Subject: ath6kl: Remove the unused node table implementation Now that the scan results are reported directly to the cfg80211 BSS table there is no need for maintaining this internal node table implementation for scan results. Remove the definitions and node table functions. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/Makefile | 1 - drivers/net/wireless/ath/ath6kl/cfg80211.c | 52 ------- drivers/net/wireless/ath/ath6kl/common.h | 83 ---------- drivers/net/wireless/ath/ath6kl/core.h | 2 - drivers/net/wireless/ath/ath6kl/init.c | 5 - drivers/net/wireless/ath/ath6kl/node.c | 234 ----------------------------- drivers/net/wireless/ath/ath6kl/wmi.c | 37 ----- drivers/net/wireless/ath/ath6kl/wmi.h | 8 - 8 files changed, 422 deletions(-) delete mode 100644 drivers/net/wireless/ath/ath6kl/node.c (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile index 5fe092046d3..8f7a0d1c290 100644 --- a/drivers/net/wireless/ath/ath6kl/Makefile +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -31,7 +31,6 @@ ath6kl-y += init.o ath6kl-y += main.o ath6kl-y += txrx.o ath6kl-y += wmi.o -ath6kl-y += node.o ath6kl-y += sdio.o ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 5ede3d2f1f2..b32843779c5 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -626,55 +626,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, ar->sme_state = SME_DISCONNECTED; } -static inline bool is_ch_11a(u16 ch) -{ - return (!((ch >= 2412) && (ch <= 2484))); -} - -/* struct ath6kl_node_table::nt_nodelock is locked when calling this */ -void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni) -{ - struct ieee80211_mgmt *mgmt; - struct ieee80211_channel *channel; - struct ieee80211_supported_band *band; - struct ath6kl_common_ie *cie; - s32 signal; - int freq; - - cie = &ni->ni_cie; - - if (is_ch_11a(cie->ie_chan)) - band = wiphy->bands[IEEE80211_BAND_5GHZ]; /* 11a */ - else if ((cie->ie_erp) || (cie->ie_xrates)) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11g */ - else - band = wiphy->bands[IEEE80211_BAND_2GHZ]; /* 11b */ - - freq = cie->ie_chan; - channel = ieee80211_get_channel(wiphy, freq); - signal = ni->ni_snr * 100; - - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, - "%s: bssid %pM ch %d freq %d size %d\n", __func__, - ni->ni_macaddr, channel->hw_value, freq, ni->ni_framelen); - /* - * Both Beacon and Probe Response frames have same payload structure, - * so it is fine to share the parser for both. - */ - if (ni->ni_framelen < 8 + 2 + 2) - return; - mgmt = (struct ieee80211_mgmt *) (ni->ni_buf - - offsetof(struct ieee80211_mgmt, u)); - cfg80211_inform_bss(wiphy, channel, ni->ni_macaddr, - le64_to_cpu(mgmt->u.beacon.timestamp), - le16_to_cpu(mgmt->u.beacon.capab_info), - le16_to_cpu(mgmt->u.beacon.beacon_int), - mgmt->u.beacon.variable, - ni->ni_buf + ni->ni_framelen - - mgmt->u.beacon.variable, - signal, GFP_ATOMIC); -} - static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) { @@ -768,9 +719,6 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status) goto out; } - /* Translate data to cfg80211 mgmt format */ - wlan_iterate_nodes(&ar->scan_table, ar->wdev->wiphy); - cfg80211_scan_done(ar->scan_req, false); if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index 6b0d45642fe..b92f0e5d233 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -75,94 +75,11 @@ enum crypto_type { AES_CRYPT = 0x08, }; -#define ATH6KL_NODE_HASHSIZE 32 -/* simple hash is enough for variation of macaddr */ -#define ATH6KL_NODE_HASH(addr) \ - (((const u8 *)(addr))[ETH_ALEN - 1] % \ - ATH6KL_NODE_HASHSIZE) - -/* - * Table of ath6kl_node instances. Each ieee80211com - * has at least one for holding the scan candidates. - * When operating as an access point or in ibss mode there - * is a second table for associated stations or neighbors. - */ -struct ath6kl_node_table { - spinlock_t nt_nodelock; /* on node table */ - struct bss *nt_node_first; /* information of all nodes */ - struct bss *nt_node_last; /* information of all nodes */ - struct bss *nt_hash[ATH6KL_NODE_HASHSIZE]; - const char *nt_name; /* for debugging */ - u32 nt_node_age; /* node aging time */ -}; - -#define WLAN_NODE_INACT_TIMEOUT_MSEC 120000 -#define WLAN_NODE_INACT_CNT 4 - -struct ath6kl_common_ie { - u16 ie_chan; - u8 *ie_tstamp; - u8 *ie_ssid; - u8 *ie_rates; - u8 *ie_xrates; - u8 *ie_country; - u8 *ie_wpa; - u8 *ie_rsn; - u8 *ie_wmm; - u8 *ie_ath; - u16 ie_capInfo; - u16 ie_beaconInt; - u8 *ie_tim; - u8 *ie_chswitch; - u8 ie_erp; - u8 *ie_wsc; - u8 *ie_htcap; - u8 *ie_htop; -}; - -struct bss { - u8 ni_macaddr[ETH_ALEN]; - u8 ni_snr; - s16 ni_rssi; - struct bss *ni_list_next; - struct bss *ni_list_prev; - struct bss *ni_hash_next; - struct bss *ni_hash_prev; - struct ath6kl_common_ie ni_cie; - u8 *ni_buf; - u16 ni_framelen; - struct ath6kl_node_table *ni_table; - u32 ni_refcnt; - - u32 ni_tstamp; - u32 ni_actcnt; -}; - struct htc_endpoint_credit_dist; struct ath6kl; enum htc_credit_dist_reason; struct htc_credit_state_info; -struct bss *wlan_node_alloc(int wh_size); -void wlan_node_free(struct bss *ni); -void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni, - const u8 *mac_addr); -struct bss *wlan_find_node(struct ath6kl_node_table *nt, - const u8 *mac_addr); -void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni); -void wlan_free_allnodes(struct ath6kl_node_table *nt); -void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg); - -void wlan_node_table_init(struct ath6kl_node_table *nt); -void wlan_node_table_cleanup(struct ath6kl_node_table *nt); - -void wlan_refresh_inactive_nodes(struct ath6kl *ar); - -struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 *ssid, - u32 ssid_len, bool is_wpa2, bool match_ssid); - -void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni); - int ath6k_setup_credit_dist(void *htc_handle, struct htc_credit_state_info *cred_info); void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf, diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index a9b3b17ef3e..9e6abb85fc5 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -503,7 +503,6 @@ struct ath6kl { struct workqueue_struct *ath6kl_wq; - struct ath6kl_node_table scan_table; struct dentry *debugfs_phy; u32 send_action_id; @@ -626,5 +625,4 @@ void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, void ath6kl_wakeup_event(void *dev); void ath6kl_target_failure(struct ath6kl *ar); -void ath6kl_cfg80211_scan_node(struct wiphy *wiphy, struct bss *ni); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 1834e9af579..7e10f712ae4 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1418,8 +1418,6 @@ static int ath6kl_init(struct net_device *dev) ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); - wlan_node_table_init(&ar->scan_table); - /* * The reason we have to wait for the target here is that the * driver layer has to init BMI in order to set the host block @@ -1501,7 +1499,6 @@ err_rxbuf_cleanup: err_cleanup_scatter: ath6kl_hif_cleanup_scatter(ar); err_node_cleanup: - wlan_node_table_cleanup(&ar->scan_table); ath6kl_wmi_shutdown(ar->wmi); clear_bit(WMI_ENABLED, &ar->flag); ar->wmi = NULL; @@ -1658,8 +1655,6 @@ void ath6kl_destroy(struct net_device *dev, unsigned int unregister) free_netdev(dev); - wlan_node_table_cleanup(&ar->scan_table); - kfree(ar->fw_board); kfree(ar->fw_otp); kfree(ar->fw); diff --git a/drivers/net/wireless/ath/ath6kl/node.c b/drivers/net/wireless/ath/ath6kl/node.c deleted file mode 100644 index 131205c610b..00000000000 --- a/drivers/net/wireless/ath/ath6kl/node.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2004-2011 Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "htc.h" -#include "wmi.h" -#include "debug.h" - -struct bss *wlan_node_alloc(int wh_size) -{ - struct bss *ni; - - ni = kzalloc(sizeof(struct bss), GFP_ATOMIC); - - if ((ni != NULL) && wh_size) { - ni->ni_buf = kmalloc(wh_size, GFP_ATOMIC); - if (ni->ni_buf == NULL) { - kfree(ni); - return NULL; - } - } - - return ni; -} - -void wlan_node_free(struct bss *ni) -{ - kfree(ni->ni_buf); - kfree(ni); -} - -void wlan_setup_node(struct ath6kl_node_table *nt, struct bss *ni, - const u8 *mac_addr) -{ - int hash; - - memcpy(ni->ni_macaddr, mac_addr, ETH_ALEN); - hash = ATH6KL_NODE_HASH(mac_addr); - ni->ni_refcnt = 1; - - ni->ni_tstamp = jiffies_to_msecs(jiffies); - ni->ni_actcnt = WLAN_NODE_INACT_CNT; - - spin_lock_bh(&nt->nt_nodelock); - - /* insert at the end of the node list */ - ni->ni_list_next = NULL; - ni->ni_list_prev = nt->nt_node_last; - if (nt->nt_node_last != NULL) - nt->nt_node_last->ni_list_next = ni; - - nt->nt_node_last = ni; - if (nt->nt_node_first == NULL) - nt->nt_node_first = ni; - - /* insert into the hash list */ - ni->ni_hash_next = nt->nt_hash[hash]; - if (ni->ni_hash_next != NULL) - nt->nt_hash[hash]->ni_hash_prev = ni; - - ni->ni_hash_prev = NULL; - nt->nt_hash[hash] = ni; - - spin_unlock_bh(&nt->nt_nodelock); -} - -struct bss *wlan_find_node(struct ath6kl_node_table *nt, - const u8 *mac_addr) -{ - struct bss *ni, *found_ni = NULL; - int hash; - - spin_lock_bh(&nt->nt_nodelock); - - hash = ATH6KL_NODE_HASH(mac_addr); - for (ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { - if (memcmp(ni->ni_macaddr, mac_addr, ETH_ALEN) == 0) { - ni->ni_refcnt++; - found_ni = ni; - break; - } - } - - spin_unlock_bh(&nt->nt_nodelock); - - return found_ni; -} - -void wlan_node_reclaim(struct ath6kl_node_table *nt, struct bss *ni) -{ - int hash; - - spin_lock_bh(&nt->nt_nodelock); - - if (ni->ni_list_prev == NULL) - /* fix list head */ - nt->nt_node_first = ni->ni_list_next; - else - ni->ni_list_prev->ni_list_next = ni->ni_list_next; - - if (ni->ni_list_next == NULL) - /* fix list tail */ - nt->nt_node_last = ni->ni_list_prev; - else - ni->ni_list_next->ni_list_prev = ni->ni_list_prev; - - if (ni->ni_hash_prev == NULL) { - /* first in list so fix the list head */ - hash = ATH6KL_NODE_HASH(ni->ni_macaddr); - nt->nt_hash[hash] = ni->ni_hash_next; - } else { - ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; - } - - if (ni->ni_hash_next != NULL) - ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; - - wlan_node_free(ni); - - spin_unlock_bh(&nt->nt_nodelock); -} - -static void wlan_node_dec_free(struct bss *ni) -{ - if ((ni->ni_refcnt--) == 1) - wlan_node_free(ni); -} - -void wlan_free_allnodes(struct ath6kl_node_table *nt) -{ - struct bss *ni; - - while ((ni = nt->nt_node_first) != NULL) - wlan_node_reclaim(nt, ni); -} - -void wlan_iterate_nodes(struct ath6kl_node_table *nt, void *arg) -{ - struct bss *ni; - - spin_lock_bh(&nt->nt_nodelock); - for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { - ni->ni_refcnt++; - ath6kl_cfg80211_scan_node(arg, ni); - wlan_node_dec_free(ni); - } - spin_unlock_bh(&nt->nt_nodelock); -} - -void wlan_node_table_init(struct ath6kl_node_table *nt) -{ - ath6kl_dbg(ATH6KL_DBG_WLAN_NODE, "node table = 0x%lx\n", - (unsigned long)nt); - - memset(nt, 0, sizeof(struct ath6kl_node_table)); - - spin_lock_init(&nt->nt_nodelock); - - nt->nt_node_age = WLAN_NODE_INACT_TIMEOUT_MSEC; -} - -void wlan_refresh_inactive_nodes(struct ath6kl *ar) -{ - struct ath6kl_node_table *nt = &ar->scan_table; - struct bss *bss; - u32 now; - - now = jiffies_to_msecs(jiffies); - bss = nt->nt_node_first; - while (bss != NULL) { - /* refresh all nodes except the current bss */ - if (memcmp(ar->bssid, bss->ni_macaddr, ETH_ALEN) != 0) { - if (((now - bss->ni_tstamp) > nt->nt_node_age) - || --bss->ni_actcnt == 0) { - wlan_node_reclaim(nt, bss); - } - } - bss = bss->ni_list_next; - } -} - -void wlan_node_table_cleanup(struct ath6kl_node_table *nt) -{ - wlan_free_allnodes(nt); -} - -struct bss *wlan_find_ssid_node(struct ath6kl_node_table *nt, u8 * ssid, - u32 ssid_len, bool is_wpa2, bool match_ssid) -{ - struct bss *ni, *found_ni = NULL; - u8 *ie_ssid; - - spin_lock_bh(&nt->nt_nodelock); - - for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { - - ie_ssid = ni->ni_cie.ie_ssid; - - if ((ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) && - (memcmp(ssid, &ie_ssid[2], ssid_len) == 0)) { - - if (match_ssid || - (is_wpa2 && ni->ni_cie.ie_rsn != NULL) || - (!is_wpa2 && ni->ni_cie.ie_wpa != NULL)) { - ni->ni_refcnt++; - found_ni = ni; - break; - } - } - } - - spin_unlock_bh(&nt->nt_nodelock); - - return found_ni; -} - -void wlan_node_return(struct ath6kl_node_table *nt, struct bss *ni) -{ - spin_lock_bh(&nt->nt_nodelock); - wlan_node_dec_free(ni); - spin_unlock_bh(&nt->nt_nodelock); -} diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index ff13e0bc646..3ade9a17c0e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2457,43 +2457,6 @@ s32 ath6kl_wmi_get_rate(s8 rate_index) return wmi_rate_tbl[(u32) rate_index][0]; } -void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss) -{ - if (bss) - wlan_node_return(&wmi->parent_dev->scan_table, bss); -} - -struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 * ssid, - u32 ssid_len, bool is_wpa2, - bool match_ssid) -{ - struct bss *node = NULL; - - node = wlan_find_ssid_node(&wmi->parent_dev->scan_table, ssid, - ssid_len, is_wpa2, match_ssid); - return node; -} - -struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 * mac_addr) -{ - struct bss *ni = NULL; - - ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr); - - return ni; -} - -void ath6kl_wmi_node_free(struct wmi *wmi, const u8 * mac_addr) -{ - struct bss *ni = NULL; - - ni = wlan_find_node(&wmi->parent_dev->scan_table, mac_addr); - if (ni != NULL) - wlan_node_reclaim(&wmi->parent_dev->scan_table, ni); - - return; -} - static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, u32 len) { diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index f036e78522a..f65bc0d6dbe 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2181,8 +2181,6 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, u8 *ac); int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb); -struct bss *ath6kl_wmi_find_node(struct wmi *wmi, const u8 *mac_addr); -void ath6kl_wmi_node_free(struct wmi *wmi, const u8 *mac_addr); int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag); @@ -2253,12 +2251,6 @@ s32 ath6kl_wmi_get_rate(s8 rate_index); int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); -struct bss *ath6kl_wmi_find_ssid_node(struct wmi *wmi, u8 *ssid, - u32 ssid_len, bool is_wpa2, - bool match_ssid); - -void ath6kl_wmi_node_return(struct wmi *wmi, struct bss *bss); - /* AP mode */ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p); -- cgit v1.2.3-70-g09d2 From 82e14f56f7408cb13c47eef9fd6922f22e88109a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 19 Sep 2011 19:15:05 +0300 Subject: ath6kl: Remove unnecessary bssinfo event header conversion There is no point in unconditionally converting the bssinfo header to the old version since only the new header is being used and the driver can as well read the values from it when needed. Leaving out the conversion saves some extra memory copying. In addition, use the calculated "rssi" value snr - 95 dBm to get the proper value in cfg80211 BSS table (i.e., something that more or less matches with the value used in STA info). Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 37 +++++++++-------------------------- drivers/net/wireless/ath/ath6kl/wmi.h | 25 +++-------------------- 2 files changed, 12 insertions(+), 50 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 3ade9a17c0e..72cf78c1ca6 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -381,25 +381,6 @@ int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) return 0; } -static void ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(struct sk_buff *skb, - u8 *datap) -{ - struct wmi_bss_info_hdr2 bih2; - struct wmi_bss_info_hdr *bih; - - memcpy(&bih2, datap, sizeof(struct wmi_bss_info_hdr2)); - - skb_push(skb, 4); - bih = (struct wmi_bss_info_hdr *) skb->data; - - bih->ch = bih2.ch; - bih->frame_type = bih2.frame_type; - bih->snr = bih2.snr; - bih->rssi = a_cpu_to_sle16(bih2.snr - 95); - bih->ie_mask = cpu_to_le32(le16_to_cpu(bih2.ie_mask)); - memcpy(bih->bssid, bih2.bssid, ETH_ALEN); -} - static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) { struct tx_complete_msg_v1 *msg_v1; @@ -912,24 +893,24 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len) static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) { - struct wmi_bss_info_hdr *bih; + struct wmi_bss_info_hdr2 *bih; u8 *buf; struct ieee80211_channel *channel; struct ath6kl *ar = wmi->parent_dev; struct ieee80211_mgmt *mgmt; struct cfg80211_bss *bss; - if (len <= sizeof(struct wmi_bss_info_hdr)) + if (len <= sizeof(struct wmi_bss_info_hdr2)) return -EINVAL; - bih = (struct wmi_bss_info_hdr *) datap; - buf = datap + sizeof(struct wmi_bss_info_hdr); - len -= sizeof(struct wmi_bss_info_hdr); + bih = (struct wmi_bss_info_hdr2 *) datap; + buf = datap + sizeof(struct wmi_bss_info_hdr2); + len -= sizeof(struct wmi_bss_info_hdr2); ath6kl_dbg(ATH6KL_DBG_WMI, "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" " "frame_type=%d\n", - bih->ch, bih->snr, a_sle16_to_cpu(bih->rssi), bih->bssid, + bih->ch, bih->snr, bih->snr - 95, bih->bssid, bih->frame_type); if (bih->frame_type != BEACON_FTYPE && @@ -973,7 +954,8 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) memcpy(&mgmt->u.beacon, buf, len); bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt, - 24 + len, bih->snr * 100, GFP_ATOMIC); + 24 + len, (bih->snr - 95) * 100, + GFP_ATOMIC); kfree(mgmt); if (bss == NULL) return -ENOMEM; @@ -2859,8 +2841,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_BSSINFO_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); - ath6kl_wmi_convert_bssinfo_hdr2_to_hdr(skb, datap); - ret = ath6kl_wmi_bssinfo_event_rx(wmi, skb->data, skb->len); + ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len); break; case WMI_REGDOMAIN_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index f65bc0d6dbe..d458d6d3a27 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1393,33 +1393,14 @@ struct roam_ctrl_cmd { u8 roam_ctrl; } __packed; -struct wmi_bss_info_hdr { - __le16 ch; - - /* see, enum wmi_bi_ftype */ - u8 frame_type; - - u8 snr; - a_sle16 rssi; - u8 bssid[ETH_ALEN]; - __le32 ie_mask; -} __packed; - -/* - * BSS INFO HDR version 2.0 - * With 6 bytes HTC header and 6 bytes of WMI header - * WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management - * header space. - * - Reduce the ie_mask to 2 bytes as only two bit flags are used - * - Remove rssi and compute it on the host. rssi = snr - 95 - */ +/* BSS INFO HDR version 2.0 */ struct wmi_bss_info_hdr2 { - __le16 ch; + __le16 ch; /* frequency in MHz */ /* see, enum wmi_bi_ftype */ u8 frame_type; - u8 snr; + u8 snr; /* note: rssi = snr - 95 dBm */ u8 bssid[ETH_ALEN]; __le16 ie_mask; } __packed; -- cgit v1.2.3-70-g09d2 From 551185ca0a97a11917edc3ad8e11d68912795902 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 19 Sep 2011 19:15:06 +0300 Subject: ath6kl: Update BSS information after connection Since we may end up using a dummy BSS entry when roaming, allow one Beacon frame -based bssinfo from the current BSS to be processed prior to starting to filter all bssinfo events. This allows cfg80211 BSS table to be filled with proper data in the roaming case where the full Beacon data may not have been present at the time of roamed event. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 2 ++ drivers/net/wireless/ath/ath6kl/core.h | 1 + drivers/net/wireless/ath/ath6kl/main.c | 10 +++++++--- drivers/net/wireless/ath/ath6kl/wmi.c | 6 ++++++ 4 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index b32843779c5..0bdd837d612 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -360,6 +360,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } if (!ar->usr_bss_filter) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { ath6kl_err("couldn't set bss filtering\n"); up(&ar->sem); @@ -638,6 +639,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return -EIO; if (!ar->usr_bss_filter) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); ret = ath6kl_wmi_bssfilter_cmd( ar->wmi, (test_bit(CONNECTED, &ar->flag) ? diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 9e6abb85fc5..c14bb75d361 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -394,6 +394,7 @@ struct ath6kl_req_key { #define SKIP_SCAN 11 #define WLAN_ENABLED 12 #define TESTMODE 13 +#define CLEAR_BSSFILTER_ON_BEACON 14 struct ath6kl { struct device *dev; diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 55d3331bed8..30b5a53db9e 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -1011,8 +1011,10 @@ void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) { ath6kl_cfg80211_scan_complete_event(ar, status); - if (!ar->usr_bss_filter) + if (!ar->usr_bss_filter) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + } ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); } @@ -1056,8 +1058,10 @@ void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, ar->next_ep_id = ENDPOINT_2; } - if (!ar->usr_bss_filter) - ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + if (!ar->usr_bss_filter) { + set_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + ath6kl_wmi_bssfilter_cmd(ar->wmi, CURRENT_BSS_FILTER, 0); + } } void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 72cf78c1ca6..f7dcb56ab35 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -917,6 +917,12 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) bih->frame_type != PROBERESP_FTYPE) return 0; /* Only update BSS table for now */ + if (bih->frame_type == BEACON_FTYPE && + test_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag)) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + } + channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch)); if (channel == NULL) return -EINVAL; -- cgit v1.2.3-70-g09d2 From 32c1087460626f9cfa2b397eafd247bf039bacac Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 19 Sep 2011 19:15:07 +0300 Subject: ath6kl: Export beacon interval and DTIM period through STA info Now that we allow the first Beacon frame after each connection to be processed at the host, we can figure out the DTIM period and expose it with Beacon interval through STA info BSS parameters to user space. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 16 ++++++++++++++++ drivers/net/wireless/ath/ath6kl/core.h | 3 +++ drivers/net/wireless/ath/ath6kl/wmi.c | 11 +++++++++++ 3 files changed, 30 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 0bdd837d612..c3540bbfcac 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -483,6 +483,13 @@ void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, assoc_req_len -= assoc_req_ie_offset; assoc_resp_len -= assoc_resp_ie_offset; + /* + * Store Beacon interval here; DTIM period will be available only once + * a Beacon frame from the AP is seen. + */ + ar->assoc_bss_beacon_int = beacon_intvl; + clear_bit(DTIM_PERIOD_AVAIL, &ar->flag); + if (nw_type & ADHOC_NETWORK) { if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, @@ -1366,6 +1373,15 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, sinfo->filled |= STATION_INFO_TX_BITRATE; + if (test_bit(CONNECTED, &ar->flag) && + test_bit(DTIM_PERIOD_AVAIL, &ar->flag) && + ar->nw_type == INFRA_NETWORK) { + sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->bss_param.flags = 0; + sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period; + sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int; + } + return 0; } diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index c14bb75d361..82be42f5edc 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -395,6 +395,7 @@ struct ath6kl_req_key { #define WLAN_ENABLED 12 #define TESTMODE 13 #define CLEAR_BSSFILTER_ON_BEACON 14 +#define DTIM_PERIOD_AVAIL 15 struct ath6kl { struct device *dev; @@ -511,6 +512,8 @@ struct ath6kl { u16 next_chan; bool p2p; + u16 assoc_bss_beacon_int; + u8 assoc_bss_dtim_period; #ifdef CONFIG_ATH6KL_DEBUG struct { diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f7dcb56ab35..b90d116c018 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -930,6 +930,17 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) if (len < 8 + 2 + 2) return -EINVAL; + if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &ar->flag) && + memcmp(bih->bssid, ar->bssid, ETH_ALEN) == 0) { + const u8 *tim; + tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, + len - 8 - 2 - 2); + if (tim && tim[1] >= 2) { + ar->assoc_bss_dtim_period = tim[3]; + set_bit(DTIM_PERIOD_AVAIL, &ar->flag); + } + } + /* * In theory, use of cfg80211_inform_bss() would be more natural here * since we do not have the full frame. However, at least for now, -- cgit v1.2.3-70-g09d2 From 865121361f0be55555c540c3df444ed06e090b33 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 21 Sep 2011 16:57:29 +0300 Subject: ath6kl: Report PMKSA candidate events through cfg80211 This allows RSN pre-authentication to be used when roaming decisions are done in the target. Signed-off-by: Jouni Malinen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 10 ++++++++++ 2 files changed, 40 insertions(+) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b90d116c018..47fbb8e7686 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1097,6 +1097,35 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len) return 0; } +static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmi_neighbor_report_event *ev; + u8 i; + + if (len < sizeof(*ev)) + return -EINVAL; + ev = (struct wmi_neighbor_report_event *) datap; + if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info) + > len) { + ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event " + "(num=%d len=%d)\n", ev->num_neighbors, len); + return -EINVAL; + } + for (i = 0; i < ev->num_neighbors; i++) { + ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n", + i + 1, ev->num_neighbors, ev->neighbor[i].bssid, + ev->neighbor[i].bss_flags); + cfg80211_pmksa_candidate_notify(wmi->parent_dev->net_dev, i, + ev->neighbor[i].bssid, + !!(ev->neighbor[i].bss_flags & + WMI_PREAUTH_CAPABLE_BSS), + GFP_ATOMIC); + } + + return 0; +} + /* * Target is reporting a programming error. This is for * developer aid only. Target only checks a few common violations @@ -2870,6 +2899,7 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) break; case WMI_NEIGHBOR_REPORT_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); + ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len); break; case WMI_SCAN_COMPLETE_EVENTID: ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index d458d6d3a27..f8e644d54aa 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -1439,6 +1439,16 @@ enum wmi_bss_flags { WMI_PMKID_VALID_BSS = 0x02, }; +struct wmi_neighbor_info { + u8 bssid[ETH_ALEN]; + u8 bss_flags; /* enum wmi_bss_flags */ +} __packed; + +struct wmi_neighbor_report_event { + u8 num_neighbors; + struct wmi_neighbor_info neighbor[0]; +} __packed; + /* TKIP MIC Error Event */ struct wmi_tkip_micerr_event { u8 key_id; -- cgit v1.2.3-70-g09d2 From ef094103233344271990d15045d6a776386c3784 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 27 Sep 2011 14:30:45 +0300 Subject: ath6kl: add prefix parameter to ath6kl_dbg_dump() Makes it easier to recognise longs dumps. Obligatory screenshot using "rx" prefix: ath6kl: ath6kl_rx rx 00000000: 10 10 00 00 00 00 08 30 00 00 00 00 00 00 f9 0b .......0........ rx 00000010: 2c 44 08 30 00 00 f9 0b 0c a4 02 00 00 00 73 d2 ,D.0..........s. rx 00000020: 94 00 f9 0b 04 8c 01 00 02 00 07 02 02 00 f9 0b ................ Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/debug.h | 14 ++++++++------ drivers/net/wireless/ath/ath6kl/htc.c | 27 ++++++++++++++------------- drivers/net/wireless/ath/ath6kl/txrx.c | 6 ++++-- drivers/net/wireless/ath/ath6kl/wmi.c | 3 ++- 4 files changed, 28 insertions(+), 22 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 91f4bc35f96..9f906c2d3f6 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -69,12 +69,14 @@ enum ath6kl_war { }) static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, - const char *msg, const void *buf, - size_t len) + const char *msg, const char *prefix, + const void *buf, size_t len) { if (debug_mask & mask) { - ath6kl_dbg(mask, "%s\n", msg); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, len); + if (msg) + ath6kl_dbg(mask, "%s\n", msg); + + print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); } } @@ -95,8 +97,8 @@ static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, } static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, - const char *msg, const void *buf, - size_t len) + const char *msg, const char *prefix, + const void *buf, size_t len) { } diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c index feed98535c9..f88a7c9e414 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.c +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -1192,9 +1192,9 @@ static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) packets->act_len + HTC_HDR_LENGTH); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, - "Unexpected ENDPOINT 0 Message", - packets->buf - HTC_HDR_LENGTH, - packets->act_len + HTC_HDR_LENGTH); + "Unexpected ENDPOINT 0 Message", "", + packets->buf - HTC_HDR_LENGTH, + packets->act_len + HTC_HDR_LENGTH); } htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); @@ -1328,7 +1328,7 @@ static int htc_parse_trailer(struct htc_target *target, memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead", - next_lk_ahds, 4); + "", next_lk_ahds, 4); *n_lk_ahds = 1; } @@ -1347,7 +1347,7 @@ static int htc_parse_trailer(struct htc_target *target, (struct htc_bundle_lkahd_rpt *) record_buf; ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd", - record_buf, record->len); + "", record_buf, record->len); for (i = 0; i < len; i++) { memcpy((u8 *)&next_lk_ahds[i], @@ -1380,7 +1380,8 @@ static int htc_proc_trailer(struct htc_target *target, ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len); - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", buf, len); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", "", + buf, len); orig_buf = buf; orig_len = len; @@ -1418,7 +1419,7 @@ static int htc_proc_trailer(struct htc_target *target, if (status) ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer", - orig_buf, orig_len); + "", orig_buf, orig_len); return status; } @@ -1435,8 +1436,8 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target, if (n_lkahds != NULL) *n_lkahds = 0; - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", packet->buf, - packet->act_len); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", "htc ", + packet->buf, packet->act_len); /* * NOTE: we cannot assume the alignment of buf, so we use the safe @@ -1480,9 +1481,9 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target, ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", __func__, packet, packet->info.rx.rx_flags); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd", - &packet->info.rx.exp_hdr, 4); + "", &packet->info.rx.exp_hdr, 4); ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header", - (u8 *)&lk_ahd, sizeof(lk_ahd)); + "", (u8 *)&lk_ahd, sizeof(lk_ahd)); status = -ENOMEM; goto fail_rx; } @@ -1518,12 +1519,12 @@ static int ath6kl_htc_rx_process_hdr(struct htc_target *target, fail_rx: if (status) ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT", - packet->buf, + "", packet->buf, packet->act_len < 256 ? packet->act_len : 256); else { if (packet->act_len > 0) ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, - "HTC - Application Msg", + "HTC - Application Msg", "", packet->buf, packet->act_len); } diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 0869ff396b5..a7117074f81 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -340,7 +340,8 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, eid, htc_tag); - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ", + skb->data, skb->len); /* * HTC interface is asynchronous, if this fails, cleanup will @@ -1068,7 +1069,8 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) skb_put(skb, packet->act_len + HTC_HDR_LENGTH); skb_pull(skb, HTC_HDR_LENGTH); - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, skb->data, skb->len); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", + skb->data, skb->len); skb->dev = ar->net_dev; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 47fbb8e7686..785a8c72541 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2850,7 +2850,8 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) len = skb->len; ath6kl_dbg(ATH6KL_DBG_WMI, "%s: wmi id: %d\n", __func__, id); - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", datap, len); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", "wmi rx ", + datap, len); switch (id) { case WMI_GET_BITRATE_CMDID: -- cgit v1.2.3-70-g09d2 From b9b6ee603923be45c4022a0dce5fa8ccf4284524 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 27 Sep 2011 14:31:21 +0300 Subject: ath6kl: improve wmi debug messages Add a new debug level ATH6KL_DBG_WMI_DUMP and other minor improvements to the wmi debug messages. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/debug.h | 3 ++- drivers/net/wireless/ath/ath6kl/wmi.c | 44 ++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c') diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index 0fbb0ac2de2..9288a3ce1e3 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -34,11 +34,12 @@ enum ATH6K_DEBUG_MASK { ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */ ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */ ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */ - ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx and wmi frames */ + ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx frames */ ATH6KL_DBG_AGGR = BIT(15), /* aggregation */ ATH6KL_DBG_SDIO = BIT(16), ATH6KL_DBG_SDIO_DUMP = BIT(17), ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */ + ATH6KL_DBG_WMI_DUMP = BIT(19), ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ }; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 785a8c72541..a7de23cbd2c 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -721,8 +721,12 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) /* STA/IBSS mode connection event */ - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM\n", - __func__, le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid); + ath6kl_dbg(ATH6KL_DBG_WMI, + "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n", + le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid, + le16_to_cpu(ev->u.sta.listen_intvl), + le16_to_cpu(ev->u.sta.beacon_intvl), + le32_to_cpu(ev->u.sta.nw_type)); /* Start of assoc rsp IEs */ pie = ev->assoc_info + ev->beacon_ie_len + @@ -822,7 +826,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) regpair = ath6kl_get_regpair((u16) reg_code); country = ath6kl_regd_find_country_by_rd((u16) reg_code); - ath6kl_dbg(ATH6KL_DBG_WMI, "ath6kl: Regpair used: 0x%0x\n", + ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", regpair->regDmnEnum); } @@ -832,7 +836,7 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) regulatory_hint(wmi->parent_dev->wdev->wiphy, alpha2); - ath6kl_dbg(ATH6KL_DBG_WMI, "ath6kl: Country alpha2 being used: %c%c\n", + ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", alpha2[0], alpha2[1]); } } @@ -847,6 +851,11 @@ static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) ev = (struct wmi_disconnect_event *) datap; + ath6kl_dbg(ATH6KL_DBG_WMI, + "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n", + le16_to_cpu(ev->proto_reason_status), ev->bssid, + ev->disconn_reason, ev->assoc_resp_len); + wmi->is_wmm_enabled = false; wmi->pair_crypto_type = NONE_CRYPT; wmi->grp_crypto_type = NONE_CRYPT; @@ -1526,11 +1535,14 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, enum htc_endpoint_id ep_id = wmi->ep_id; int ret; - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: cmd_id=%d\n", __func__, cmd_id); - if (WARN_ON(skb == NULL)) return -EINVAL; + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", + cmd_id, skb->len, sync_flag); + ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ", + skb->data, skb->len); + if (sync_flag >= END_WMIFLAG) { dev_kfree_skb(skb); return -EINVAL; @@ -1589,6 +1601,13 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type, struct wmi_connect_cmd *cc; int ret; + ath6kl_dbg(ATH6KL_DBG_WMI, + "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d " + "type %d dot11_auth %d auth %d pairwise %d group %d\n", + bssid, channel, ctrl_flags, ssid_len, nw_type, + dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto); + ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len); + wmi->traffic_class = 100; if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT)) @@ -1634,6 +1653,9 @@ int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel) struct wmi_reconnect_cmd *cc; int ret; + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n", + bssid, channel); + wmi->traffic_class = 100; skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd)); @@ -1656,6 +1678,8 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi) { int ret; + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n"); + wmi->traffic_class = 100; /* Disconnect command does not need to do a SYNC before. */ @@ -2808,12 +2832,14 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) switch (id) { case WMIX_HB_CHALLENGE_RESP_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); break; case WMIX_DBGLOG_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len); break; default: - ath6kl_err("unknown cmd id 0x%x\n", id); + ath6kl_warn("unknown cmd id 0x%x\n", id); wmi->stat.cmd_id_err++; ret = -EINVAL; break; @@ -2849,8 +2875,8 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) datap = skb->data; len = skb->len; - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: wmi id: %d\n", __func__, id); - ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "msg payload ", "wmi rx ", + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len); + ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", datap, len); switch (id) { -- cgit v1.2.3-70-g09d2