diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/main.c | 104 |
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 | ||
544 | void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) | 551 | void 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 | ||
596 | static 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 | |||
614 | static 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 | |||
587 | void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, | 635 | void 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, | |||
1090 | static void ath6kl_set_multicast_list(struct net_device *ndev) | 1145 | static 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) { |