* interface, since firmware only records BSSID when the entry is new
         */
        if (vif->type != NL80211_IFTYPE_STATION)
-               mt7996_mcu_add_sta(dev, vif, NULL, true, true);
+               mt7996_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, true);
        rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
 
 out:
        struct mt7996_phy *phy = mt7996_hw_phy(hw);
        int idx = msta->wcid.idx;
 
-       mt7996_mcu_add_sta(dev, vif, NULL, false, false);
+       mt7996_mcu_add_sta(dev, vif, NULL, CONN_STATE_DISCONNECT, false);
        mt7996_mcu_add_bss_info(phy, vif, false);
        mt7996_mcu_add_dev_info(phy, vif, false);
 
            !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
                return -EOPNOTSUPP;
 
+       if (sta && !wcid->sta)
+               return -EOPNOTSUPP;
+
        /* fall back to sw encryption for unsupported ciphers */
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
            (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||
            (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) {
                mt7996_mcu_add_bss_info(phy, vif, true);
-               mt7996_mcu_add_sta(dev, vif, NULL, true,
+               mt7996_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE,
                                   !!(changed & BSS_CHANGED_BSSID));
        }
 
        struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
        struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
        u8 band_idx = mvif->phy->mt76->band_idx;
-       int ret, idx;
+       int idx;
 
        idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
        if (idx < 0)
        msta->wcid.sta = 1;
        msta->wcid.idx = idx;
        msta->wcid.phy_idx = band_idx;
-       msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
 
        ewma_avg_signal_init(&msta->avg_ack_signal);
 
        mt7996_mac_wtbl_update(dev, idx,
                               MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+       mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, true);
 
-       ret = mt7996_mcu_add_sta(dev, vif, sta, true, true);
-       if (ret)
-               return ret;
+       return 0;
+}
+
+int mt7996_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+                        struct ieee80211_sta *sta, enum mt76_sta_event ev)
+{
+       struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+       struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+       int i, ret;
+
+       switch (ev) {
+       case MT76_STA_EVENT_ASSOC:
+               ret = mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_CONNECT, true);
+               if (ret)
+                       return ret;
+
+               ret = mt7996_mcu_add_rate_ctrl(dev, vif, sta, false);
+               if (ret)
+                       return ret;
+
+               msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+               msta->wcid.sta = 1;
+
+               return 0;
+
+       case MT76_STA_EVENT_AUTHORIZE:
+               return mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false);
+
+       case MT76_STA_EVENT_DISASSOC:
+               for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
+                       mt7996_mac_twt_teardown_flow(dev, msta, i);
 
-       return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false);
+               mt7996_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false);
+               msta->wcid.sta_disabled = 1;
+               msta->wcid.sta = 0;
+
+               return 0;
+       }
+
+       return 0;
 }
 
 void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
 {
        struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
        struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
-       int i;
-
-       mt7996_mcu_add_sta(dev, vif, sta, false, false);
 
        mt7996_mac_wtbl_update(dev, msta->wcid.idx,
                               MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
 
-       for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
-               mt7996_mac_twt_teardown_flow(dev, msta, i);
-
        spin_lock_bh(&mdev->sta_poll_lock);
        if (!list_empty(&msta->wcid.poll_list))
                list_del_init(&msta->wcid.poll_list);
        return ret;
 }
 
-static int
-mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-              struct ieee80211_sta *sta)
-{
-       return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST,
-                             IEEE80211_STA_NONE);
-}
-
-static int
-mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                 struct ieee80211_sta *sta)
-{
-       return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE,
-                             IEEE80211_STA_NOTEXIST);
-}
-
 static int
 mt7996_get_stats(struct ieee80211_hw *hw,
                 struct ieee80211_low_level_stats *stats)
        else
                clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
 
+       if (!msta->wcid.sta)
+               return;
+
        mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta);
 }
 
        else
                clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
 
+       if (!msta->wcid.sta)
+               return;
+
        mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta);
 }
 
        if (!mtk_wed_device_active(wed))
                return -ENODEV;
 
-       if (msta->wcid.idx > MT7996_WTBL_STA)
+       if (!msta->wcid.sta || msta->wcid.idx > MT7996_WTBL_STA)
                return -EIO;
 
        path->type = DEV_PATH_MTK_WDMA;
        .conf_tx = mt7996_conf_tx,
        .configure_filter = mt7996_configure_filter,
        .bss_info_changed = mt7996_bss_info_changed,
-       .sta_add = mt7996_sta_add,
-       .sta_remove = mt7996_sta_remove,
+       .sta_state = mt76_sta_state,
        .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
        .link_sta_rc_update = mt7996_sta_rc_update,
        .set_key = mt7996_set_key,