diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 342 |
1 files changed, 262 insertions, 80 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 5370333883e4..00d38952b5fb 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004-2011 Atheros Communications Inc. | 2 | * Copyright (c) 2004-2011 Atheros Communications Inc. |
3 | * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. | ||
3 | * | 4 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 6 | * purpose with or without fee is hereby granted, provided that the above |
@@ -68,6 +69,10 @@ static struct ieee80211_rate ath6kl_rates[] = { | |||
68 | #define ath6kl_g_rates (ath6kl_rates + 0) | 69 | #define ath6kl_g_rates (ath6kl_rates + 0) |
69 | #define ath6kl_g_rates_size 12 | 70 | #define ath6kl_g_rates_size 12 |
70 | 71 | ||
72 | #define ath6kl_g_htcap (IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \ | ||
73 | IEEE80211_HT_CAP_SGI_20 | \ | ||
74 | IEEE80211_HT_CAP_SGI_40) | ||
75 | |||
71 | static struct ieee80211_channel ath6kl_2ghz_channels[] = { | 76 | static struct ieee80211_channel ath6kl_2ghz_channels[] = { |
72 | CHAN2G(1, 2412, 0), | 77 | CHAN2G(1, 2412, 0), |
73 | CHAN2G(2, 2417, 0), | 78 | CHAN2G(2, 2417, 0), |
@@ -112,6 +117,8 @@ static struct ieee80211_supported_band ath6kl_band_2ghz = { | |||
112 | .channels = ath6kl_2ghz_channels, | 117 | .channels = ath6kl_2ghz_channels, |
113 | .n_bitrates = ath6kl_g_rates_size, | 118 | .n_bitrates = ath6kl_g_rates_size, |
114 | .bitrates = ath6kl_g_rates, | 119 | .bitrates = ath6kl_g_rates, |
120 | .ht_cap.cap = ath6kl_g_htcap, | ||
121 | .ht_cap.ht_supported = true, | ||
115 | }; | 122 | }; |
116 | 123 | ||
117 | static struct ieee80211_supported_band ath6kl_band_5ghz = { | 124 | static struct ieee80211_supported_band ath6kl_band_5ghz = { |
@@ -119,6 +126,8 @@ static struct ieee80211_supported_band ath6kl_band_5ghz = { | |||
119 | .channels = ath6kl_5ghz_a_channels, | 126 | .channels = ath6kl_5ghz_a_channels, |
120 | .n_bitrates = ath6kl_a_rates_size, | 127 | .n_bitrates = ath6kl_a_rates_size, |
121 | .bitrates = ath6kl_a_rates, | 128 | .bitrates = ath6kl_a_rates, |
129 | .ht_cap.cap = ath6kl_g_htcap, | ||
130 | .ht_cap.ht_supported = true, | ||
122 | }; | 131 | }; |
123 | 132 | ||
124 | #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ | 133 | #define CCKM_KRK_CIPHER_SUITE 0x004096ff /* use for KRK */ |
@@ -381,7 +390,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, | |||
381 | return false; | 390 | return false; |
382 | 391 | ||
383 | if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && | 392 | if (ar->ibss_if_active || ((type == NL80211_IFTYPE_ADHOC) && |
384 | ar->num_vif)) | 393 | ar->num_vif)) |
385 | return false; | 394 | return false; |
386 | 395 | ||
387 | if (type == NL80211_IFTYPE_STATION || | 396 | if (type == NL80211_IFTYPE_STATION || |
@@ -407,6 +416,12 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type, | |||
407 | return false; | 416 | return false; |
408 | } | 417 | } |
409 | 418 | ||
419 | static bool ath6kl_is_tx_pending(struct ath6kl *ar) | ||
420 | { | ||
421 | return ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0; | ||
422 | } | ||
423 | |||
424 | |||
410 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | 425 | static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, |
411 | struct cfg80211_connect_params *sme) | 426 | struct cfg80211_connect_params *sme) |
412 | { | 427 | { |
@@ -414,6 +429,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
414 | struct ath6kl_vif *vif = netdev_priv(dev); | 429 | struct ath6kl_vif *vif = netdev_priv(dev); |
415 | int status; | 430 | int status; |
416 | u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; | 431 | u8 nw_subtype = (ar->p2p) ? SUBTYPE_P2PDEV : SUBTYPE_NONE; |
432 | u16 interval; | ||
417 | 433 | ||
418 | ath6kl_cfg80211_sscan_disable(vif); | 434 | ath6kl_cfg80211_sscan_disable(vif); |
419 | 435 | ||
@@ -450,8 +466,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
450 | * sleep until the command queue drains | 466 | * sleep until the command queue drains |
451 | */ | 467 | */ |
452 | wait_event_interruptible_timeout(ar->event_wq, | 468 | wait_event_interruptible_timeout(ar->event_wq, |
453 | ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, | 469 | ath6kl_is_tx_pending(ar), |
454 | WMI_TIMEOUT); | 470 | WMI_TIMEOUT); |
455 | if (signal_pending(current)) { | 471 | if (signal_pending(current)) { |
456 | ath6kl_err("cmd queue drain timeout\n"); | 472 | ath6kl_err("cmd queue drain timeout\n"); |
457 | up(&ar->sem); | 473 | up(&ar->sem); |
@@ -546,7 +562,7 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
546 | if (!ar->usr_bss_filter) { | 562 | if (!ar->usr_bss_filter) { |
547 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); | 563 | clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); |
548 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, | 564 | if (ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, |
549 | ALL_BSS_FILTER, 0) != 0) { | 565 | ALL_BSS_FILTER, 0) != 0) { |
550 | ath6kl_err("couldn't set bss filtering\n"); | 566 | ath6kl_err("couldn't set bss filtering\n"); |
551 | up(&ar->sem); | 567 | up(&ar->sem); |
552 | return -EIO; | 568 | return -EIO; |
@@ -568,6 +584,20 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
568 | vif->grp_crypto_len, vif->ch_hint); | 584 | vif->grp_crypto_len, vif->ch_hint); |
569 | 585 | ||
570 | vif->reconnect_flag = 0; | 586 | vif->reconnect_flag = 0; |
587 | |||
588 | if (vif->nw_type == INFRA_NETWORK) { | ||
589 | interval = max_t(u16, vif->listen_intvl_t, | ||
590 | ATH6KL_MAX_WOW_LISTEN_INTL); | ||
591 | status = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | ||
592 | interval, | ||
593 | 0); | ||
594 | if (status) { | ||
595 | ath6kl_err("couldn't set listen intervel\n"); | ||
596 | up(&ar->sem); | ||
597 | return status; | ||
598 | } | ||
599 | } | ||
600 | |||
571 | status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, | 601 | status = ath6kl_wmi_connect_cmd(ar->wmi, vif->fw_vif_idx, vif->nw_type, |
572 | vif->dot11_auth_mode, vif->auth_mode, | 602 | vif->dot11_auth_mode, vif->auth_mode, |
573 | vif->prwise_crypto, | 603 | vif->prwise_crypto, |
@@ -590,8 +620,8 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, | |||
590 | } | 620 | } |
591 | 621 | ||
592 | if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && | 622 | if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && |
593 | ((vif->auth_mode == WPA_PSK_AUTH) | 623 | ((vif->auth_mode == WPA_PSK_AUTH) || |
594 | || (vif->auth_mode == WPA2_PSK_AUTH))) { | 624 | (vif->auth_mode == WPA2_PSK_AUTH))) { |
595 | mod_timer(&vif->disconnect_timer, | 625 | mod_timer(&vif->disconnect_timer, |
596 | jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); | 626 | jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); |
597 | } | 627 | } |
@@ -824,13 +854,13 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, | |||
824 | 854 | ||
825 | if (vif->sme_state == SME_CONNECTING) { | 855 | if (vif->sme_state == SME_CONNECTING) { |
826 | cfg80211_connect_result(vif->ndev, | 856 | cfg80211_connect_result(vif->ndev, |
827 | bssid, NULL, 0, | 857 | bssid, NULL, 0, |
828 | NULL, 0, | 858 | NULL, 0, |
829 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 859 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
830 | GFP_KERNEL); | 860 | GFP_KERNEL); |
831 | } else if (vif->sme_state == SME_CONNECTED) { | 861 | } else if (vif->sme_state == SME_CONNECTED) { |
832 | cfg80211_disconnected(vif->ndev, reason, | 862 | cfg80211_disconnected(vif->ndev, reason, |
833 | NULL, 0, GFP_KERNEL); | 863 | NULL, 0, GFP_KERNEL); |
834 | } | 864 | } |
835 | 865 | ||
836 | vif->sme_state = SME_DISCONNECTED; | 866 | vif->sme_state = SME_DISCONNECTED; |
@@ -876,19 +906,14 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
876 | request->ssids[i].ssid); | 906 | request->ssids[i].ssid); |
877 | } | 907 | } |
878 | 908 | ||
879 | /* | 909 | /* this also clears IE in fw if it's not set */ |
880 | * FIXME: we should clear the IE in fw if it's not set so just | 910 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
881 | * remove the check altogether | 911 | WMI_FRAME_PROBE_REQ, |
882 | */ | 912 | request->ie, request->ie_len); |
883 | if (request->ie) { | 913 | if (ret) { |
884 | ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 914 | ath6kl_err("failed to set Probe Request appie for " |
885 | WMI_FRAME_PROBE_REQ, | 915 | "scan"); |
886 | request->ie, request->ie_len); | 916 | return ret; |
887 | if (ret) { | ||
888 | ath6kl_err("failed to set Probe Request appie for " | ||
889 | "scan"); | ||
890 | return ret; | ||
891 | } | ||
892 | } | 917 | } |
893 | 918 | ||
894 | /* | 919 | /* |
@@ -917,7 +942,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
917 | force_fg_scan = 1; | 942 | force_fg_scan = 1; |
918 | 943 | ||
919 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | 944 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, |
920 | ar->fw_capabilities)) { | 945 | ar->fw_capabilities)) { |
921 | /* | 946 | /* |
922 | * If capable of doing P2P mgmt operations using | 947 | * If capable of doing P2P mgmt operations using |
923 | * station interface, send additional information like | 948 | * station interface, send additional information like |
@@ -926,14 +951,17 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, | |||
926 | */ | 951 | */ |
927 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, | 952 | ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx, |
928 | WMI_LONG_SCAN, force_fg_scan, | 953 | WMI_LONG_SCAN, force_fg_scan, |
929 | false, 0, 0, n_channels, | 954 | false, 0, |
930 | channels, request->no_cck, | 955 | ATH6KL_FG_SCAN_INTERVAL, |
956 | n_channels, channels, | ||
957 | request->no_cck, | ||
931 | request->rates); | 958 | request->rates); |
932 | } else { | 959 | } else { |
933 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, | 960 | ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx, |
934 | WMI_LONG_SCAN, force_fg_scan, | 961 | WMI_LONG_SCAN, force_fg_scan, |
935 | false, 0, 0, n_channels, | 962 | false, 0, |
936 | channels); | 963 | ATH6KL_FG_SCAN_INTERVAL, |
964 | n_channels, channels); | ||
937 | } | 965 | } |
938 | if (ret) | 966 | if (ret) |
939 | ath6kl_err("wmi_startscan_cmd failed\n"); | 967 | ath6kl_err("wmi_startscan_cmd failed\n"); |
@@ -1046,9 +1074,9 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1046 | return -ENOTSUPP; | 1074 | return -ENOTSUPP; |
1047 | } | 1075 | } |
1048 | 1076 | ||
1049 | if (((vif->auth_mode == WPA_PSK_AUTH) | 1077 | if (((vif->auth_mode == WPA_PSK_AUTH) || |
1050 | || (vif->auth_mode == WPA2_PSK_AUTH)) | 1078 | (vif->auth_mode == WPA2_PSK_AUTH)) && |
1051 | && (key_usage & GROUP_USAGE)) | 1079 | (key_usage & GROUP_USAGE)) |
1052 | del_timer(&vif->disconnect_timer); | 1080 | del_timer(&vif->disconnect_timer); |
1053 | 1081 | ||
1054 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, | 1082 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, |
@@ -1058,7 +1086,7 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, | |||
1058 | 1086 | ||
1059 | if (vif->nw_type == AP_NETWORK && !pairwise && | 1087 | if (vif->nw_type == AP_NETWORK && !pairwise && |
1060 | (key_type == TKIP_CRYPT || key_type == AES_CRYPT || | 1088 | (key_type == TKIP_CRYPT || key_type == AES_CRYPT || |
1061 | key_type == WAPI_CRYPT) && params) { | 1089 | key_type == WAPI_CRYPT)) { |
1062 | ar->ap_mode_bkey.valid = true; | 1090 | ar->ap_mode_bkey.valid = true; |
1063 | ar->ap_mode_bkey.key_index = key_index; | 1091 | ar->ap_mode_bkey.key_index = key_index; |
1064 | ar->ap_mode_bkey.key_type = key_type; | 1092 | ar->ap_mode_bkey.key_type = key_type; |
@@ -1263,7 +1291,6 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1263 | { | 1291 | { |
1264 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); | 1292 | struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); |
1265 | struct ath6kl_vif *vif; | 1293 | struct ath6kl_vif *vif; |
1266 | u8 ath6kl_dbm; | ||
1267 | int dbm = MBM_TO_DBM(mbm); | 1294 | int dbm = MBM_TO_DBM(mbm); |
1268 | 1295 | ||
1269 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, | 1296 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, |
@@ -1280,7 +1307,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1280 | case NL80211_TX_POWER_AUTOMATIC: | 1307 | case NL80211_TX_POWER_AUTOMATIC: |
1281 | return 0; | 1308 | return 0; |
1282 | case NL80211_TX_POWER_LIMITED: | 1309 | case NL80211_TX_POWER_LIMITED: |
1283 | ar->tx_pwr = ath6kl_dbm = dbm; | 1310 | ar->tx_pwr = dbm; |
1284 | break; | 1311 | break; |
1285 | default: | 1312 | default: |
1286 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", | 1313 | ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", |
@@ -1288,7 +1315,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, | |||
1288 | return -EOPNOTSUPP; | 1315 | return -EOPNOTSUPP; |
1289 | } | 1316 | } |
1290 | 1317 | ||
1291 | ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, ath6kl_dbm); | 1318 | ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, vif->fw_vif_idx, dbm); |
1292 | 1319 | ||
1293 | return 0; | 1320 | return 0; |
1294 | } | 1321 | } |
@@ -1349,7 +1376,7 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, | |||
1349 | } | 1376 | } |
1350 | 1377 | ||
1351 | if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, | 1378 | if (ath6kl_wmi_powermode_cmd(ar->wmi, vif->fw_vif_idx, |
1352 | mode.pwr_mode) != 0) { | 1379 | mode.pwr_mode) != 0) { |
1353 | ath6kl_err("wmi_powermode_cmd failed\n"); | 1380 | ath6kl_err("wmi_powermode_cmd failed\n"); |
1354 | return -EIO; | 1381 | return -EIO; |
1355 | } | 1382 | } |
@@ -1904,7 +1931,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1904 | struct ath6kl_vif *vif; | 1931 | struct ath6kl_vif *vif; |
1905 | int ret, left; | 1932 | int ret, left; |
1906 | u32 filter = 0; | 1933 | u32 filter = 0; |
1907 | u16 i; | 1934 | u16 i, bmiss_time; |
1908 | u8 index = 0; | 1935 | u8 index = 0; |
1909 | __be32 ips[MAX_IP_ADDRS]; | 1936 | __be32 ips[MAX_IP_ADDRS]; |
1910 | 1937 | ||
@@ -1941,6 +1968,34 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) | |||
1941 | if (ret) | 1968 | if (ret) |
1942 | return ret; | 1969 | return ret; |
1943 | 1970 | ||
1971 | netif_stop_queue(vif->ndev); | ||
1972 | |||
1973 | if (vif->nw_type != AP_NETWORK) { | ||
1974 | ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | ||
1975 | ATH6KL_MAX_WOW_LISTEN_INTL, | ||
1976 | 0); | ||
1977 | if (ret) | ||
1978 | return ret; | ||
1979 | |||
1980 | /* Set listen interval x 15 times as bmiss time */ | ||
1981 | bmiss_time = ATH6KL_MAX_WOW_LISTEN_INTL * 15; | ||
1982 | if (bmiss_time > ATH6KL_MAX_BMISS_TIME) | ||
1983 | bmiss_time = ATH6KL_MAX_BMISS_TIME; | ||
1984 | |||
1985 | ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, | ||
1986 | bmiss_time, 0); | ||
1987 | if (ret) | ||
1988 | return ret; | ||
1989 | |||
1990 | ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, | ||
1991 | 0xFFFF, 0, 0xFFFF, 0, 0, 0, | ||
1992 | 0, 0, 0, 0); | ||
1993 | if (ret) | ||
1994 | return ret; | ||
1995 | } | ||
1996 | |||
1997 | ar->state = ATH6KL_STATE_SUSPENDING; | ||
1998 | |||
1944 | /* Setup own IP addr for ARP agent. */ | 1999 | /* Setup own IP addr for ARP agent. */ |
1945 | in_dev = __in_dev_get_rtnl(vif->ndev); | 2000 | in_dev = __in_dev_get_rtnl(vif->ndev); |
1946 | if (!in_dev) | 2001 | if (!in_dev) |
@@ -2019,15 +2074,46 @@ static int ath6kl_wow_resume(struct ath6kl *ar) | |||
2019 | if (!vif) | 2074 | if (!vif) |
2020 | return -EIO; | 2075 | return -EIO; |
2021 | 2076 | ||
2077 | ar->state = ATH6KL_STATE_RESUMING; | ||
2078 | |||
2022 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, | 2079 | ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, |
2023 | ATH6KL_HOST_MODE_AWAKE); | 2080 | ATH6KL_HOST_MODE_AWAKE); |
2024 | return ret; | 2081 | if (ret) { |
2082 | ath6kl_warn("Failed to configure host sleep mode for " | ||
2083 | "wow resume: %d\n", ret); | ||
2084 | ar->state = ATH6KL_STATE_WOW; | ||
2085 | return ret; | ||
2086 | } | ||
2087 | |||
2088 | if (vif->nw_type != AP_NETWORK) { | ||
2089 | ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, | ||
2090 | 0, 0, 0, 0, 0, 0, 3, 0, 0, 0); | ||
2091 | if (ret) | ||
2092 | return ret; | ||
2093 | |||
2094 | ret = ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, | ||
2095 | vif->listen_intvl_t, 0); | ||
2096 | if (ret) | ||
2097 | return ret; | ||
2098 | |||
2099 | ret = ath6kl_wmi_bmisstime_cmd(ar->wmi, vif->fw_vif_idx, | ||
2100 | vif->bmiss_time_t, 0); | ||
2101 | if (ret) | ||
2102 | return ret; | ||
2103 | } | ||
2104 | |||
2105 | ar->state = ATH6KL_STATE_ON; | ||
2106 | |||
2107 | netif_wake_queue(vif->ndev); | ||
2108 | |||
2109 | return 0; | ||
2025 | } | 2110 | } |
2026 | 2111 | ||
2027 | int ath6kl_cfg80211_suspend(struct ath6kl *ar, | 2112 | int ath6kl_cfg80211_suspend(struct ath6kl *ar, |
2028 | enum ath6kl_cfg_suspend_mode mode, | 2113 | enum ath6kl_cfg_suspend_mode mode, |
2029 | struct cfg80211_wowlan *wow) | 2114 | struct cfg80211_wowlan *wow) |
2030 | { | 2115 | { |
2116 | enum ath6kl_state prev_state; | ||
2031 | int ret; | 2117 | int ret; |
2032 | 2118 | ||
2033 | switch (mode) { | 2119 | switch (mode) { |
@@ -2038,11 +2124,14 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar, | |||
2038 | /* Flush all non control pkts in TX path */ | 2124 | /* Flush all non control pkts in TX path */ |
2039 | ath6kl_tx_data_cleanup(ar); | 2125 | ath6kl_tx_data_cleanup(ar); |
2040 | 2126 | ||
2127 | prev_state = ar->state; | ||
2128 | |||
2041 | ret = ath6kl_wow_suspend(ar, wow); | 2129 | ret = ath6kl_wow_suspend(ar, wow); |
2042 | if (ret) { | 2130 | if (ret) { |
2043 | ath6kl_err("wow suspend failed: %d\n", ret); | 2131 | ar->state = prev_state; |
2044 | return ret; | 2132 | return ret; |
2045 | } | 2133 | } |
2134 | |||
2046 | ar->state = ATH6KL_STATE_WOW; | 2135 | ar->state = ATH6KL_STATE_WOW; |
2047 | break; | 2136 | break; |
2048 | 2137 | ||
@@ -2114,7 +2203,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar) | |||
2114 | return ret; | 2203 | return ret; |
2115 | } | 2204 | } |
2116 | 2205 | ||
2117 | ar->state = ATH6KL_STATE_ON; | ||
2118 | break; | 2206 | break; |
2119 | 2207 | ||
2120 | case ATH6KL_STATE_DEEPSLEEP: | 2208 | case ATH6KL_STATE_DEEPSLEEP: |
@@ -2188,6 +2276,9 @@ static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) | |||
2188 | */ | 2276 | */ |
2189 | void ath6kl_check_wow_status(struct ath6kl *ar) | 2277 | void ath6kl_check_wow_status(struct ath6kl *ar) |
2190 | { | 2278 | { |
2279 | if (ar->state == ATH6KL_STATE_SUSPENDING) | ||
2280 | return; | ||
2281 | |||
2191 | if (ar->state == ATH6KL_STATE_WOW) | 2282 | if (ar->state == ATH6KL_STATE_WOW) |
2192 | ath6kl_cfg80211_resume(ar); | 2283 | ath6kl_cfg80211_resume(ar); |
2193 | } | 2284 | } |
@@ -2275,30 +2366,27 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, | |||
2275 | struct ath6kl *ar = vif->ar; | 2366 | struct ath6kl *ar = vif->ar; |
2276 | int res; | 2367 | int res; |
2277 | 2368 | ||
2278 | if (info->beacon_ies) { | 2369 | /* this also clears IE in fw if it's not set */ |
2279 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 2370 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
2280 | WMI_FRAME_BEACON, | 2371 | WMI_FRAME_BEACON, |
2281 | info->beacon_ies, | 2372 | info->beacon_ies, |
2282 | info->beacon_ies_len); | 2373 | info->beacon_ies_len); |
2283 | if (res) | 2374 | if (res) |
2284 | return res; | 2375 | return res; |
2285 | } | ||
2286 | 2376 | ||
2287 | if (info->proberesp_ies) { | 2377 | /* this also clears IE in fw if it's not set */ |
2288 | res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, | 2378 | res = ath6kl_set_ap_probe_resp_ies(vif, info->proberesp_ies, |
2289 | info->proberesp_ies_len); | 2379 | info->proberesp_ies_len); |
2290 | if (res) | 2380 | if (res) |
2291 | return res; | 2381 | return res; |
2292 | } | ||
2293 | 2382 | ||
2294 | if (info->assocresp_ies) { | 2383 | /* this also clears IE in fw if it's not set */ |
2295 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, | 2384 | res = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, |
2296 | WMI_FRAME_ASSOC_RESP, | 2385 | WMI_FRAME_ASSOC_RESP, |
2297 | info->assocresp_ies, | 2386 | info->assocresp_ies, |
2298 | info->assocresp_ies_len); | 2387 | info->assocresp_ies_len); |
2299 | if (res) | 2388 | if (res) |
2300 | return res; | 2389 | return res; |
2301 | } | ||
2302 | 2390 | ||
2303 | return 0; | 2391 | return 0; |
2304 | } | 2392 | } |
@@ -2309,6 +2397,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2309 | struct ath6kl *ar = ath6kl_priv(dev); | 2397 | struct ath6kl *ar = ath6kl_priv(dev); |
2310 | struct ath6kl_vif *vif = netdev_priv(dev); | 2398 | struct ath6kl_vif *vif = netdev_priv(dev); |
2311 | struct ieee80211_mgmt *mgmt; | 2399 | struct ieee80211_mgmt *mgmt; |
2400 | bool hidden = false; | ||
2312 | u8 *ies; | 2401 | u8 *ies; |
2313 | int ies_len; | 2402 | int ies_len; |
2314 | struct wmi_connect_cmd p; | 2403 | struct wmi_connect_cmd p; |
@@ -2345,7 +2434,11 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
2345 | memcpy(vif->ssid, info->ssid, info->ssid_len); | 2434 | memcpy(vif->ssid, info->ssid, info->ssid_len); |
2346 | vif->ssid_len = info->ssid_len; | 2435 | vif->ssid_len = info->ssid_len; |
2347 | if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) | 2436 | if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) |
2348 | return -EOPNOTSUPP; /* TODO */ | 2437 | hidden = true; |
2438 | |||
2439 | res = ath6kl_wmi_ap_hidden_ssid(ar->wmi, vif->fw_vif_idx, hidden); | ||
2440 | if (res) | ||
2441 | return res; | ||
2349 | 2442 | ||
2350 | ret = ath6kl_set_auth_type(vif, info->auth_type); | 2443 | ret = ath6kl_set_auth_type(vif, info->auth_type); |
2351 | if (ret) | 2444 | if (ret) |
@@ -2584,6 +2677,76 @@ static int ath6kl_send_go_probe_resp(struct ath6kl_vif *vif, | |||
2584 | return ret; | 2677 | return ret; |
2585 | } | 2678 | } |
2586 | 2679 | ||
2680 | static bool ath6kl_mgmt_powersave_ap(struct ath6kl_vif *vif, | ||
2681 | u32 id, | ||
2682 | u32 freq, | ||
2683 | u32 wait, | ||
2684 | const u8 *buf, | ||
2685 | size_t len, | ||
2686 | bool *more_data, | ||
2687 | bool no_cck) | ||
2688 | { | ||
2689 | struct ieee80211_mgmt *mgmt; | ||
2690 | struct ath6kl_sta *conn; | ||
2691 | bool is_psq_empty = false; | ||
2692 | struct ath6kl_mgmt_buff *mgmt_buf; | ||
2693 | size_t mgmt_buf_size; | ||
2694 | struct ath6kl *ar = vif->ar; | ||
2695 | |||
2696 | mgmt = (struct ieee80211_mgmt *) buf; | ||
2697 | if (is_multicast_ether_addr(mgmt->da)) | ||
2698 | return false; | ||
2699 | |||
2700 | conn = ath6kl_find_sta(vif, mgmt->da); | ||
2701 | if (!conn) | ||
2702 | return false; | ||
2703 | |||
2704 | if (conn->sta_flags & STA_PS_SLEEP) { | ||
2705 | if (!(conn->sta_flags & STA_PS_POLLED)) { | ||
2706 | /* Queue the frames if the STA is sleeping */ | ||
2707 | mgmt_buf_size = len + sizeof(struct ath6kl_mgmt_buff); | ||
2708 | mgmt_buf = kmalloc(mgmt_buf_size, GFP_KERNEL); | ||
2709 | if (!mgmt_buf) | ||
2710 | return false; | ||
2711 | |||
2712 | INIT_LIST_HEAD(&mgmt_buf->list); | ||
2713 | mgmt_buf->id = id; | ||
2714 | mgmt_buf->freq = freq; | ||
2715 | mgmt_buf->wait = wait; | ||
2716 | mgmt_buf->len = len; | ||
2717 | mgmt_buf->no_cck = no_cck; | ||
2718 | memcpy(mgmt_buf->buf, buf, len); | ||
2719 | spin_lock_bh(&conn->psq_lock); | ||
2720 | is_psq_empty = skb_queue_empty(&conn->psq) && | ||
2721 | (conn->mgmt_psq_len == 0); | ||
2722 | list_add_tail(&mgmt_buf->list, &conn->mgmt_psq); | ||
2723 | conn->mgmt_psq_len++; | ||
2724 | spin_unlock_bh(&conn->psq_lock); | ||
2725 | |||
2726 | /* | ||
2727 | * If this is the first pkt getting queued | ||
2728 | * for this STA, update the PVB for this | ||
2729 | * STA. | ||
2730 | */ | ||
2731 | if (is_psq_empty) | ||
2732 | ath6kl_wmi_set_pvb_cmd(ar->wmi, vif->fw_vif_idx, | ||
2733 | conn->aid, 1); | ||
2734 | return true; | ||
2735 | } | ||
2736 | |||
2737 | /* | ||
2738 | * This tx is because of a PsPoll. | ||
2739 | * Determine if MoreData bit has to be set. | ||
2740 | */ | ||
2741 | spin_lock_bh(&conn->psq_lock); | ||
2742 | if (!skb_queue_empty(&conn->psq) || (conn->mgmt_psq_len != 0)) | ||
2743 | *more_data = true; | ||
2744 | spin_unlock_bh(&conn->psq_lock); | ||
2745 | } | ||
2746 | |||
2747 | return false; | ||
2748 | } | ||
2749 | |||
2587 | static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | 2750 | static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, |
2588 | struct ieee80211_channel *chan, bool offchan, | 2751 | struct ieee80211_channel *chan, bool offchan, |
2589 | enum nl80211_channel_type channel_type, | 2752 | enum nl80211_channel_type channel_type, |
@@ -2595,6 +2758,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2595 | struct ath6kl_vif *vif = netdev_priv(dev); | 2758 | struct ath6kl_vif *vif = netdev_priv(dev); |
2596 | u32 id; | 2759 | u32 id; |
2597 | const struct ieee80211_mgmt *mgmt; | 2760 | const struct ieee80211_mgmt *mgmt; |
2761 | bool more_data, queued; | ||
2598 | 2762 | ||
2599 | mgmt = (const struct ieee80211_mgmt *) buf; | 2763 | mgmt = (const struct ieee80211_mgmt *) buf; |
2600 | if (buf + len >= mgmt->u.probe_resp.variable && | 2764 | if (buf + len >= mgmt->u.probe_resp.variable && |
@@ -2620,22 +2784,19 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2620 | 2784 | ||
2621 | *cookie = id; | 2785 | *cookie = id; |
2622 | 2786 | ||
2623 | if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, | 2787 | /* AP mode Power saving processing */ |
2624 | ar->fw_capabilities)) { | 2788 | if (vif->nw_type == AP_NETWORK) { |
2625 | /* | 2789 | queued = ath6kl_mgmt_powersave_ap(vif, |
2626 | * If capable of doing P2P mgmt operations using | 2790 | id, chan->center_freq, |
2627 | * station interface, send additional information like | 2791 | wait, buf, |
2628 | * supported rates to advertise and xmit rates for | 2792 | len, &more_data, no_cck); |
2629 | * probe requests | 2793 | if (queued) |
2630 | */ | 2794 | return 0; |
2631 | return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, | ||
2632 | chan->center_freq, wait, | ||
2633 | buf, len, no_cck); | ||
2634 | } else { | ||
2635 | return ath6kl_wmi_send_action_cmd(ar->wmi, vif->fw_vif_idx, id, | ||
2636 | chan->center_freq, wait, | ||
2637 | buf, len); | ||
2638 | } | 2795 | } |
2796 | |||
2797 | return ath6kl_wmi_send_mgmt_cmd(ar->wmi, vif->fw_vif_idx, id, | ||
2798 | chan->center_freq, wait, | ||
2799 | buf, len, no_cck); | ||
2639 | } | 2800 | } |
2640 | 2801 | ||
2641 | static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, | 2802 | static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, |
@@ -2929,7 +3090,10 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, | |||
2929 | vif->wdev.netdev = ndev; | 3090 | vif->wdev.netdev = ndev; |
2930 | vif->wdev.iftype = type; | 3091 | vif->wdev.iftype = type; |
2931 | vif->fw_vif_idx = fw_vif_idx; | 3092 | vif->fw_vif_idx = fw_vif_idx; |
2932 | vif->nw_type = vif->next_mode = nw_type; | 3093 | vif->nw_type = nw_type; |
3094 | vif->next_mode = nw_type; | ||
3095 | vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; | ||
3096 | vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; | ||
2933 | 3097 | ||
2934 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); | 3098 | memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); |
2935 | if (fw_vif_idx != 0) | 3099 | if (fw_vif_idx != 0) |
@@ -3009,18 +3173,36 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) | |||
3009 | 3173 | ||
3010 | wiphy->max_sched_scan_ssids = 10; | 3174 | wiphy->max_sched_scan_ssids = 10; |
3011 | 3175 | ||
3176 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | | ||
3177 | WIPHY_FLAG_HAVE_AP_SME | | ||
3178 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | | ||
3179 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; | ||
3180 | |||
3181 | if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities)) | ||
3182 | ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | ||
3183 | |||
3184 | ar->wiphy->probe_resp_offload = | ||
3185 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | | ||
3186 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | | ||
3187 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | | ||
3188 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; | ||
3189 | |||
3012 | ret = wiphy_register(wiphy); | 3190 | ret = wiphy_register(wiphy); |
3013 | if (ret < 0) { | 3191 | if (ret < 0) { |
3014 | ath6kl_err("couldn't register wiphy device\n"); | 3192 | ath6kl_err("couldn't register wiphy device\n"); |
3015 | return ret; | 3193 | return ret; |
3016 | } | 3194 | } |
3017 | 3195 | ||
3196 | ar->wiphy_registered = true; | ||
3197 | |||
3018 | return 0; | 3198 | return 0; |
3019 | } | 3199 | } |
3020 | 3200 | ||
3021 | void ath6kl_cfg80211_cleanup(struct ath6kl *ar) | 3201 | void ath6kl_cfg80211_cleanup(struct ath6kl *ar) |
3022 | { | 3202 | { |
3023 | wiphy_unregister(ar->wiphy); | 3203 | wiphy_unregister(ar->wiphy); |
3204 | |||
3205 | ar->wiphy_registered = false; | ||
3024 | } | 3206 | } |
3025 | 3207 | ||
3026 | struct ath6kl *ath6kl_cfg80211_create(void) | 3208 | struct ath6kl *ath6kl_cfg80211_create(void) |