if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
                    !test_sta_flag(sta, WLAN_STA_AUTH)) {
-                       ret = sta_info_move_state_checked(sta,
-                                       IEEE80211_STA_AUTH);
+                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
                        if (ret)
                                return ret;
-                       ret = sta_info_move_state_checked(sta,
-                                       IEEE80211_STA_ASSOC);
+                       ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
                        if (ret)
                                return ret;
                }
 
        if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
                if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
-                       ret = sta_info_move_state_checked(sta,
-                                       IEEE80211_STA_AUTHORIZED);
+                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
                else if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-                       ret = sta_info_move_state_checked(sta,
-                                       IEEE80211_STA_ASSOC);
+                       ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
                if (ret)
                        return ret;
        }
 
                if (!(set & BIT(NL80211_STA_FLAG_AUTHENTICATED)) &&
                    test_sta_flag(sta, WLAN_STA_AUTH)) {
-                       ret = sta_info_move_state_checked(sta,
-                                       IEEE80211_STA_AUTH);
+                       ret = sta_info_move_state(sta, IEEE80211_STA_AUTH);
                        if (ret)
                                return ret;
-                       ret = sta_info_move_state_checked(sta,
-                                       IEEE80211_STA_NONE);
+                       ret = sta_info_move_state(sta, IEEE80211_STA_NONE);
                        if (ret)
                                return ret;
                }
        if (!sta)
                return -ENOMEM;
 
-       sta_info_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+       sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
 
        err = sta_apply_parameters(local, sta, params);
        if (err) {
 
        test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
 
        int res = scnprintf(buf, sizeof(buf),
-                           "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                           "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                            TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
                            TEST(PS_DRIVER), TEST(AUTHORIZED),
                            TEST(SHORT_PREAMBLE),
                            TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
                            TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
                            TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
-                           TEST(TDLS_PEER_AUTH));
+                           TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
+                           TEST(INSERTED));
 #undef TEST
        return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
 
                    addr, sdata->name);
 #endif
 
-       sta_info_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-       sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+       sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
 
        rate_control_rate_init(sta);
 
 
                        goto err_del_interface;
                }
 
-               sta_info_move_state(sta, IEEE80211_STA_AUTH);
-               sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-               sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+               sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+               sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+               sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
 
                res = sta_info_insert(sta);
                if (res) {
 
        if (!sta)
                return NULL;
 
-       sta_info_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-       sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+       sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+       sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
 
        set_sta_flag(sta, WLAN_STA_WME);
 
 
                return false;
        }
 
-       sta_info_move_state(sta, IEEE80211_STA_AUTH);
-       sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-       if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-               sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+       err = sta_info_move_state(sta, IEEE80211_STA_AUTH);
+       if (!err)
+               err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+       if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+               err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+       if (err) {
+               printk(KERN_DEBUG
+                      "%s: failed to move station %pM to desired state\n",
+                      sdata->name, sta->sta.addr);
+               WARN_ON(__sta_info_destroy(sta));
+               mutex_unlock(&sdata->local->sta_mtx);
+               return false;
+       }
 
        rates = 0;
        basic_rates = 0;
 
                sta_info_hash_add(local, sta);
 
                list_add(&sta->list, &local->sta_list);
+
+               set_sta_flag(sta, WLAN_STA_INSERTED);
        } else {
                sta->dummy = false;
        }
        return have_buffered;
 }
 
-static int __must_check __sta_info_destroy(struct sta_info *sta)
+int __must_check __sta_info_destroy(struct sta_info *sta)
 {
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        local = sta->local;
        sdata = sta->sdata;
 
+       lockdep_assert_held(&local->sta_mtx);
+
        /*
         * Before removing the station from the driver and
         * rate control, it might still start new aggregation
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
 
-       while (sta->sta_state > IEEE80211_STA_NONE)
-               sta_info_move_state(sta, sta->sta_state - 1);
+       while (sta->sta_state > IEEE80211_STA_NONE) {
+               int err = sta_info_move_state(sta, sta->sta_state - 1);
+               if (err) {
+                       WARN_ON_ONCE(1);
+                       break;
+               }
+       }
 
        if (sta->uploaded) {
                if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 }
 EXPORT_SYMBOL(ieee80211_sta_set_buffered);
 
-int sta_info_move_state_checked(struct sta_info *sta,
-                               enum ieee80211_sta_state new_state)
+int sta_info_move_state(struct sta_info *sta,
+                       enum ieee80211_sta_state new_state)
 {
        might_sleep();
 
 
  * @WLAN_STA_SP: Station is in a service period, so don't try to
  *     reply to other uAPSD trigger frames or PS-Poll.
  * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
+ * @WLAN_STA_INSERTED: This station is inserted into the hash table.
  */
 enum ieee80211_sta_info_flags {
        WLAN_STA_AUTH,
        WLAN_STA_UAPSD,
        WLAN_STA_SP,
        WLAN_STA_4ADDR_EVENT,
+       WLAN_STA_INSERTED,
 };
 
 enum ieee80211_sta_state {
        return test_and_set_bit(flag, &sta->_flags);
 }
 
-int sta_info_move_state_checked(struct sta_info *sta,
-                               enum ieee80211_sta_state new_state);
+int sta_info_move_state(struct sta_info *sta,
+                       enum ieee80211_sta_state new_state);
 
-static inline void sta_info_move_state(struct sta_info *sta,
-                                      enum ieee80211_sta_state new_state)
+static inline void sta_info_pre_move_state(struct sta_info *sta,
+                                          enum ieee80211_sta_state new_state)
 {
-       int ret = sta_info_move_state_checked(sta, new_state);
+       int ret;
+
+       WARN_ON_ONCE(test_sta_flag(sta, WLAN_STA_INSERTED));
+
+       ret = sta_info_move_state(sta, new_state);
        WARN_ON_ONCE(ret);
 }
 
 int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
 int sta_info_reinsert(struct sta_info *sta);
 
+int __must_check __sta_info_destroy(struct sta_info *sta);
 int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
                          const u8 *addr);
 int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,