Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / mac.c
index c6c09c1..c400567 100644 (file)
@@ -136,7 +136,9 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
                if (ret)
                        return ret;
 
+               spin_lock_bh(&ar->data_lock);
                peer->keys[i] = arvif->wep_keys[i];
+               spin_unlock_bh(&ar->data_lock);
        }
 
        return 0;
@@ -173,7 +175,9 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
                        ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
                                    i, ret);
 
+               spin_lock_bh(&ar->data_lock);
                peer->keys[i] = NULL;
+               spin_unlock_bh(&ar->data_lock);
        }
 
        return first_errno;
@@ -351,6 +355,9 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       if (ar->num_peers >= ar->max_num_peers)
+               return -ENOBUFS;
+
        ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
        if (ret) {
                ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
@@ -364,9 +371,8 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
                            addr, vdev_id, ret);
                return ret;
        }
-       spin_lock_bh(&ar->data_lock);
+
        ar->num_peers++;
-       spin_unlock_bh(&ar->data_lock);
 
        return 0;
 }
@@ -416,15 +422,11 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        return 0;
 }
 
-static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
+static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
 {
        struct ath10k *ar = arvif->ar;
        u32 vdev_param;
 
-       if (value != 0xFFFFFFFF)
-               value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,
-                             ATH10K_RTS_MAX);
-
        vdev_param = ar->wmi.vdev_param->rts_threshold;
        return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
 }
@@ -457,9 +459,7 @@ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
        if (ret)
                return ret;
 
-       spin_lock_bh(&ar->data_lock);
        ar->num_peers--;
-       spin_unlock_bh(&ar->data_lock);
 
        return 0;
 }
@@ -496,8 +496,10 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
                list_del(&peer->list);
                kfree(peer);
        }
-       ar->num_peers = 0;
        spin_unlock_bh(&ar->data_lock);
+
+       ar->num_peers = 0;
+       ar->num_stations = 0;
 }
 
 /************************/
@@ -3097,10 +3099,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        int ret;
 
-       mutex_lock(&ar->conf_mutex);
-
        cancel_work_sync(&arvif->wep_key_work);
 
+       mutex_lock(&ar->conf_mutex);
+
        spin_lock_bh(&ar->data_lock);
        ath10k_mac_vif_beacon_cleanup(arvif);
        spin_unlock_bh(&ar->data_lock);
@@ -3594,6 +3596,37 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
        mutex_unlock(&ar->conf_mutex);
 }
 
+static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+           arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+               return 0;
+
+       if (ar->num_stations >= ar->max_num_stations)
+               return -ENOBUFS;
+
+       ar->num_stations++;
+
+       return 0;
+}
+
+static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+           arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
+               return;
+
+       ar->num_stations--;
+}
+
 static int ath10k_sta_state(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta,
@@ -3603,7 +3636,6 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
-       int max_num_peers;
        int ret = 0;
 
        if (old_state == IEEE80211_STA_NOTEXIST &&
@@ -3625,26 +3657,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                /*
                 * New station addition.
                 */
-               if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-                       max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
-               else
-                       max_num_peers = TARGET_NUM_PEERS;
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
+                          "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
+                          arvif->vdev_id, sta->addr,
+                          ar->num_stations + 1, ar->max_num_stations,
+                          ar->num_peers + 1, ar->max_num_peers);
 
-               if (ar->num_peers >= max_num_peers) {
-                       ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
-                                   ar->num_peers, max_num_peers);
-                       ret = -ENOBUFS;
+               ret = ath10k_mac_inc_num_stations(arvif);
+               if (ret) {
+                       ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
+                                   ar->max_num_stations);
                        goto exit;
                }
 
-               ath10k_dbg(ar, ATH10K_DBG_MAC,
-                          "mac vdev %d peer create %pM (new sta) num_peers %d\n",
-                          arvif->vdev_id, sta->addr, ar->num_peers);
-
                ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
-               if (ret)
+               if (ret) {
                        ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
+                       ath10k_mac_dec_num_stations(arvif);
+                       goto exit;
+               }
 
                if (vif->type == NL80211_IFTYPE_STATION) {
                        WARN_ON(arvif->is_started);
@@ -3655,6 +3687,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                                            arvif->vdev_id, ret);
                                WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
                                                           sta->addr));
+                               ath10k_mac_dec_num_stations(arvif);
                                goto exit;
                        }
 
@@ -3685,6 +3718,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                        ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
 
+               ath10k_mac_dec_num_stations(arvif);
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC &&
                   (vif->type == NL80211_IFTYPE_AP ||