aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/wl12xx/main.c137
1 files changed, 82 insertions, 55 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index b771106c0a1e..8569ac3760df 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -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,