wl12xx: implement sta_state callback
authorEliad Peller <eliad@wizery.com>
Sun, 4 Mar 2012 08:55:47 +0000 (10:55 +0200)
committerLuciano Coelho <coelho@ti.com>
Mon, 5 Mar 2012 13:45:24 +0000 (15:45 +0200)
Implement sta_state callback instead of the
sta_add/remove callbacks.

Update the fw regarding peer state and ht caps
only after the station was authorized. Otherwise,
the fw might try establishing BA session before
the sta is authorized.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/main.c

index b771106c0a1ef48f1d3002fb1a2f8727f3acffb1..8569ac3760df1ff694bb2be7126c82e04b6e7b47 100644 (file)
@@ -4233,100 +4233,128 @@ void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
        wl->active_sta_count--;
 }
 
-static int wl1271_op_sta_add(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_sta *sta)
+static int wl12xx_sta_add(struct wl1271 *wl,
+                         struct wl12xx_vif *wlvif,
+                         struct ieee80211_sta *sta)
 {
-       struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct wl1271_station *wl_sta;
        int ret = 0;
        u8 hlid;
 
-       mutex_lock(&wl->mutex);
-
-       if (unlikely(wl->state == WL1271_STATE_OFF))
-               goto out;
-
-       if (wlvif->bss_type != BSS_TYPE_AP_BSS)
-               goto out;
-
        wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
 
        ret = wl1271_allocate_sta(wl, wlvif, sta);
        if (ret < 0)
-               goto out;
+               return ret;
 
        wl_sta = (struct wl1271_station *)sta->drv_priv;
        hlid = wl_sta->hlid;
 
-       ret = wl1271_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out_free_sta;
-
        ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
        if (ret < 0)
-               goto out_sleep;
+               wl1271_free_sta(wl, wlvif, hlid);
 
-       ret = wl12xx_cmd_set_peer_state(wl, hlid);
-       if (ret < 0)
-               goto out_sleep;
+       return ret;
+}
 
-       ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
-       if (ret < 0)
-               goto out_sleep;
+static int wl12xx_sta_remove(struct wl1271 *wl,
+                            struct wl12xx_vif *wlvif,
+                            struct ieee80211_sta *sta)
+{
+       struct wl1271_station *wl_sta;
+       int ret = 0, id;
 
-out_sleep:
-       wl1271_ps_elp_sleep(wl);
+       wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
+
+       wl_sta = (struct wl1271_station *)sta->drv_priv;
+       id = wl_sta->hlid;
+       if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
+               return -EINVAL;
 
-out_free_sta:
+       ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
        if (ret < 0)
-               wl1271_free_sta(wl, wlvif, hlid);
+               return ret;
 
-out:
-       mutex_unlock(&wl->mutex);
+       wl1271_free_sta(wl, wlvif, wl_sta->hlid);
        return ret;
 }
 
-static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               struct ieee80211_sta *sta)
+static int wl12xx_update_sta_state(struct wl1271 *wl,
+                                  struct wl12xx_vif *wlvif,
+                                  struct ieee80211_sta *sta,
+                                  enum ieee80211_sta_state old_state,
+                                  enum ieee80211_sta_state new_state)
 {
-       struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        struct wl1271_station *wl_sta;
-       int ret = 0, id;
+       u8 hlid;
+       bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
+       bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
+       int ret;
 
-       mutex_lock(&wl->mutex);
+       wl_sta = (struct wl1271_station *)sta->drv_priv;
+       hlid = wl_sta->hlid;
 
-       if (unlikely(wl->state == WL1271_STATE_OFF))
-               goto out;
+       /* Add station (AP mode) */
+       if (is_ap &&
+           old_state == IEEE80211_STA_NOTEXIST &&
+           new_state == IEEE80211_STA_NONE)
+               return wl12xx_sta_add(wl, wlvif, sta);
+
+       /* Remove station (AP mode) */
+       if (is_ap &&
+           old_state == IEEE80211_STA_NONE &&
+           new_state == IEEE80211_STA_NOTEXIST) {
+               /* must not fail */
+               wl12xx_sta_remove(wl, wlvif, sta);
+               return 0;
+       }
 
-       if (wlvif->bss_type != BSS_TYPE_AP_BSS)
-               goto out;
+       /* Authorize station (AP mode) */
+       if (is_ap &&
+           new_state == IEEE80211_STA_AUTHORIZED) {
+               ret = wl12xx_cmd_set_peer_state(wl, hlid);
+               if (ret < 0)
+                       return ret;
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
+               ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
+                                                    hlid);
+               return ret;
+       }
 
-       wl_sta = (struct wl1271_station *)sta->drv_priv;
-       id = wl_sta->hlid;
-       if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
+       return 0;
+}
+
+static int wl12xx_op_sta_state(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              enum ieee80211_sta_state old_state,
+                              enum ieee80211_sta_state new_state)
+{
+       struct wl1271 *wl = hw->priv;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       int ret;
+
+       wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d",
+                    sta->aid, old_state, new_state);
+
+       mutex_lock(&wl->mutex);
+
+       if (unlikely(wl->state == WL1271_STATE_OFF)) {
+               ret = -EBUSY;
                goto out;
+       }
 
        ret = wl1271_ps_elp_wakeup(wl);
        if (ret < 0)
                goto out;
 
-       ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
-       if (ret < 0)
-               goto out_sleep;
+       ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state);
 
-       wl1271_free_sta(wl, wlvif, wl_sta->hlid);
-
-out_sleep:
        wl1271_ps_elp_sleep(wl);
-
 out:
        mutex_unlock(&wl->mutex);
+       if (new_state < old_state)
+               return 0;
        return ret;
 }
 
@@ -4795,8 +4823,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .conf_tx = wl1271_op_conf_tx,
        .get_tsf = wl1271_op_get_tsf,
        .get_survey = wl1271_op_get_survey,
-       .sta_add = wl1271_op_sta_add,
-       .sta_remove = wl1271_op_sta_remove,
+       .sta_state = wl12xx_op_sta_state,
        .ampdu_action = wl1271_op_ampdu_action,
        .tx_frames_pending = wl1271_tx_frames_pending,
        .set_bitrate_mask = wl12xx_set_bitrate_mask,