aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/main.c')
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c104
1 files changed, 88 insertions, 16 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 4d818f96c415..e5524470529c 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -421,8 +421,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
421 if (!ik->valid) 421 if (!ik->valid)
422 break; 422 break;
423 423
424 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " 424 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
425 "the initial group key for AP mode\n"); 425 "Delayed addkey for the initial group key for AP mode\n");
426 memset(key_rsc, 0, sizeof(key_rsc)); 426 memset(key_rsc, 0, sizeof(key_rsc));
427 res = ath6kl_wmi_addkey_cmd( 427 res = ath6kl_wmi_addkey_cmd(
428 ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type, 428 ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type,
@@ -430,12 +430,19 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
430 ik->key, 430 ik->key,
431 KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); 431 KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
432 if (res) { 432 if (res) {
433 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " 433 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
434 "addkey failed: %d\n", res); 434 "Delayed addkey failed: %d\n", res);
435 } 435 }
436 break; 436 break;
437 } 437 }
438 438
439 if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
440 ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
441 /* we actually don't know the phymode, default to HT20 */
442 ath6kl_cfg80211_ch_switch_notify(vif, channel,
443 WMI_11G_HT20);
444 }
445
439 ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); 446 ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
440 set_bit(CONNECTED, &vif->flags); 447 set_bit(CONNECTED, &vif->flags);
441 netif_carrier_on(vif->ndev); 448 netif_carrier_on(vif->ndev);
@@ -541,7 +548,8 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
541 548
542/* WMI Event handlers */ 549/* WMI Event handlers */
543 550
544void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) 551void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
552 enum wmi_phy_cap cap)
545{ 553{
546 struct ath6kl *ar = devt; 554 struct ath6kl *ar = devt;
547 555
@@ -551,6 +559,7 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
551 559
552 ar->version.wlan_ver = sw_ver; 560 ar->version.wlan_ver = sw_ver;
553 ar->version.abi_ver = abi_ver; 561 ar->version.abi_ver = abi_ver;
562 ar->hw.cap = cap;
554 563
555 snprintf(ar->wiphy->fw_version, 564 snprintf(ar->wiphy->fw_version,
556 sizeof(ar->wiphy->fw_version), 565 sizeof(ar->wiphy->fw_version),
@@ -584,6 +593,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
584 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status); 593 ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status);
585} 594}
586 595
596static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
597{
598
599 struct ath6kl *ar = vif->ar;
600
601 vif->next_chan = channel;
602 vif->profile.ch = cpu_to_le16(channel);
603
604 switch (vif->nw_type) {
605 case AP_NETWORK:
606 return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
607 &vif->profile);
608 default:
609 ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type);
610 return -ENOTSUPP;
611 }
612}
613
614static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
615{
616
617 struct ath6kl_vif *vif;
618 int res = 0;
619
620 if (!ar->want_ch_switch)
621 return;
622
623 spin_lock_bh(&ar->list_lock);
624 list_for_each_entry(vif, &ar->vif_list, list) {
625 if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
626 res = ath6kl_commit_ch_switch(vif, channel);
627
628 if (res)
629 ath6kl_err("channel switch failed nw_type %d res %d\n",
630 vif->nw_type, res);
631 }
632 spin_unlock_bh(&ar->list_lock);
633}
634
587void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, 635void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
588 u16 listen_int, u16 beacon_int, 636 u16 listen_int, u16 beacon_int,
589 enum network_type net_type, u8 beacon_ie_len, 637 enum network_type net_type, u8 beacon_ie_len,
@@ -601,9 +649,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
601 memcpy(vif->bssid, bssid, sizeof(vif->bssid)); 649 memcpy(vif->bssid, bssid, sizeof(vif->bssid));
602 vif->bss_ch = channel; 650 vif->bss_ch = channel;
603 651
604 if ((vif->nw_type == INFRA_NETWORK)) 652 if ((vif->nw_type == INFRA_NETWORK)) {
605 ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, 653 ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
606 vif->listen_intvl_t, 0); 654 vif->listen_intvl_t, 0);
655 ath6kl_check_ch_switch(ar, channel);
656 }
607 657
608 netif_wake_queue(vif->ndev); 658 netif_wake_queue(vif->ndev);
609 659
@@ -926,6 +976,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
926 struct ath6kl *ar = vif->ar; 976 struct ath6kl *ar = vif->ar;
927 977
928 if (vif->nw_type == AP_NETWORK) { 978 if (vif->nw_type == AP_NETWORK) {
979 /* disconnect due to other STA vif switching channels */
980 if (reason == BSS_DISCONNECTED &&
981 prot_reason_status == WMI_AP_REASON_STA_ROAM)
982 ar->want_ch_switch |= 1 << vif->fw_vif_idx;
983
929 if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) 984 if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
930 return; 985 return;
931 986
@@ -1090,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev,
1090static void ath6kl_set_multicast_list(struct net_device *ndev) 1145static void ath6kl_set_multicast_list(struct net_device *ndev)
1091{ 1146{
1092 struct ath6kl_vif *vif = netdev_priv(ndev); 1147 struct ath6kl_vif *vif = netdev_priv(ndev);
1093 bool mc_all_on = false, mc_all_off = false; 1148 bool mc_all_on = false;
1094 int mc_count = netdev_mc_count(ndev); 1149 int mc_count = netdev_mc_count(ndev);
1095 struct netdev_hw_addr *ha; 1150 struct netdev_hw_addr *ha;
1096 bool found; 1151 bool found;
@@ -1102,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
1102 !test_bit(WLAN_ENABLED, &vif->flags)) 1157 !test_bit(WLAN_ENABLED, &vif->flags))
1103 return; 1158 return;
1104 1159
1160 /* Enable multicast-all filter. */
1105 mc_all_on = !!(ndev->flags & IFF_PROMISC) || 1161 mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
1106 !!(ndev->flags & IFF_ALLMULTI) || 1162 !!(ndev->flags & IFF_ALLMULTI) ||
1107 !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); 1163 !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
1108 1164
1109 mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; 1165 if (mc_all_on)
1166 set_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
1167 else
1168 clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
1169
1170 mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
1110 1171
1111 if (mc_all_on || mc_all_off) { 1172 if (!(ndev->flags & IFF_MULTICAST)) {
1112 /* Enable/disable all multicast */ 1173 mc_all_on = false;
1113 ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", 1174 set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
1114 mc_all_on ? "enabling" : "disabling"); 1175 } else {
1115 ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, 1176 clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
1177 }
1178
1179 /* Enable/disable "multicast-all" filter*/
1180 ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n",
1181 mc_all_on ? "enabling" : "disabling");
1182
1183 ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
1116 mc_all_on); 1184 mc_all_on);
1117 if (ret) 1185 if (ret) {
1118 ath6kl_warn("Failed to %s multicast receive\n", 1186 ath6kl_warn("Failed to %s multicast-all receive\n",
1119 mc_all_on ? "enable" : "disable"); 1187 mc_all_on ? "enable" : "disable");
1120 return; 1188 return;
1121 } 1189 }
1122 1190
1191 if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags))
1192 return;
1193
1194 /* Keep the driver and firmware mcast list in sync. */
1123 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { 1195 list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
1124 found = false; 1196 found = false;
1125 netdev_for_each_mc_addr(ha, ndev) { 1197 netdev_for_each_mc_addr(ha, ndev) {