ath6kl: reconfigure RSN capabilities when restarting AP
[platform/kernel/linux-arm64.git] / drivers / net / wireless / ath / ath6kl / main.c
index c189e28..9533558 100644 (file)
@@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
        }
 
        address = TARG_VTOP(ar->target_type, debug_hdr_addr);
-       ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
+       ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
+       if (ret)
+               goto out;
 
        address = TARG_VTOP(ar->target_type,
                            le32_to_cpu(debug_hdr.dbuf_addr));
        firstbuf = address;
        dropped = le32_to_cpu(debug_hdr.dropped);
-       ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+       ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+       if (ret)
+               goto out;
 
        loop = 100;
 
@@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
 
                address = TARG_VTOP(ar->target_type,
                                    le32_to_cpu(debug_buf.next));
-               ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+               ret = ath6kl_diag_read(ar, address, &debug_buf,
+                                      sizeof(debug_buf));
                if (ret)
                        goto out;
 
@@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
                break;
        }
 
-       if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
-               ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
+       if (ar->last_ch != channel)
                /* we actually don't know the phymode, default to HT20 */
-               ath6kl_cfg80211_ch_switch_notify(vif, channel,
-                                                WMI_11G_HT20);
-       }
+               ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20);
 
        ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
        set_bit(CONNECTED, &vif->flags);
@@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
 
        switch (vif->nw_type) {
        case AP_NETWORK:
+               /*
+                * reconfigure any saved RSN IE capabilites in the beacon /
+                * probe response to stay in sync with the supplicant.
+                */
+               if (vif->rsn_capab &&
+                   test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
+                            ar->fw_capabilities))
+                       ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
+                                             WLAN_EID_RSN, WMI_RSN_IE_CAPB,
+                                             (const u8 *) &vif->rsn_capab,
+                                             sizeof(vif->rsn_capab));
+
                return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
                                                    &vif->profile);
        default:
@@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
                if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
                        res = ath6kl_commit_ch_switch(vif, channel);
 
+               /* if channel switch failed, oh well we tried */
+               ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
+
                if (res)
                        ath6kl_err("channel switch failed nw_type %d res %d\n",
                                   vif->nw_type, res);
@@ -981,8 +998,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
        if (vif->nw_type == AP_NETWORK) {
                /* disconnect due to other STA vif switching channels */
                if (reason == BSS_DISCONNECTED &&
-                   prot_reason_status == WMI_AP_REASON_STA_ROAM)
+                   prot_reason_status == WMI_AP_REASON_STA_ROAM) {
                        ar->want_ch_switch |= 1 << vif->fw_vif_idx;
+                       /* bail back to this channel if STA vif fails connect */
+                       ar->last_ch = le16_to_cpu(vif->profile.ch);
+               }
 
                if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
                        return;
@@ -1041,6 +1061,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
                }
        }
 
+       /* restart disconnected concurrent vifs waiting for new channel */
+       ath6kl_check_ch_switch(ar, ar->last_ch);
+
        /* update connect & link status atomically */
        spin_lock_bh(&vif->if_lock);
        clear_bit(CONNECTED, &vif->flags);