mutex_unlock(&ar->conf_mutex);
 }
 
+static void ath10k_mac_handle_beacon_iter(void *data, u8 *mac,
+                                         struct ieee80211_vif *vif)
+{
+       struct sk_buff *skb = data;
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+       if (vif->type != NL80211_IFTYPE_STATION)
+               return;
+
+       if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid))
+               return;
+
+       cancel_delayed_work(&arvif->connection_loss_work);
+}
+
+void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb)
+{
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath10k_mac_handle_beacon_iter,
+                                                  skb);
+}
+
+static void ath10k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
+                                              struct ieee80211_vif *vif)
+{
+       u32 *vdev_id = data;
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       struct ath10k *ar = arvif->ar;
+       struct ieee80211_hw *hw = ar->hw;
+
+       if (arvif->vdev_id != *vdev_id)
+               return;
+
+       if (!arvif->is_up)
+               return;
+
+       ieee80211_beacon_loss(vif);
+
+       /* Firmware doesn't report beacon loss events repeatedly. If AP probe
+        * (done by mac80211) succeeds but beacons do not resume then it
+        * doesn't make sense to continue operation. Queue connection loss work
+        * which can be cancelled when beacon is received.
+        */
+       ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work,
+                                    ATH10K_CONNECTION_LOSS_HZ);
+}
+
+void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id)
+{
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath10k_mac_handle_beacon_miss_iter,
+                                                  &vdev_id);
+}
+
+static void ath10k_mac_vif_sta_connection_loss_work(struct work_struct *work)
+{
+       struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
+                                               connection_loss_work.work);
+       struct ieee80211_vif *vif = arvif->vif;
+
+       if (!arvif->is_up)
+               return;
+
+       ieee80211_connection_loss(vif);
+}
+
 /**********************/
 /* Station management */
 /**********************/
        }
 
        arvif->is_up = false;
+
+       cancel_delayed_work_sync(&arvif->connection_loss_work);
 }
 
 static int ath10k_station_assoc(struct ath10k *ar,
 
        INIT_LIST_HEAD(&arvif->list);
        INIT_WORK(&arvif->ap_csa_work, ath10k_mac_vif_ap_csa_work);
+       INIT_DELAYED_WORK(&arvif->connection_loss_work,
+                         ath10k_mac_vif_sta_connection_loss_work);
 
        if (ar->free_vdev_map == 0) {
                ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
        int ret;
 
        cancel_work_sync(&arvif->ap_csa_work);
+       cancel_delayed_work_sync(&arvif->connection_loss_work);
 
        mutex_lock(&ar->conf_mutex);
 
                        IEEE80211_HW_HAS_RATE_CONTROL |
                        IEEE80211_HW_AP_LINK_PS |
                        IEEE80211_HW_SPECTRUM_MGMT |
-                       IEEE80211_HW_SW_CRYPTO_CONTROL;
+                       IEEE80211_HW_SW_CRYPTO_CONTROL |
+                       IEEE80211_HW_CONNECTION_MONITOR;
 
        ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
 
 
                }
        }
 
+       if (ieee80211_is_beacon(hdr->frame_control))
+               ath10k_mac_handle_beacon(ar, skb);
+
        ath10k_dbg(ar, ATH10K_DBG_MGMT,
                   "event mgmt rx skb %p len %d ftype %02x stype %02x\n",
                   skb, skb->len,
                            reason, vdev_id);
 
        switch (reason) {
-       case WMI_ROAM_REASON_BETTER_AP:
        case WMI_ROAM_REASON_BEACON_MISS:
+               ath10k_mac_handle_beacon_miss(ar, vdev_id);
+               break;
+       case WMI_ROAM_REASON_BETTER_AP:
        case WMI_ROAM_REASON_LOW_RSSI:
        case WMI_ROAM_REASON_SUITABLE_AP_FOUND:
        case WMI_ROAM_REASON_HO_FAILED: