diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/main.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 137 |
1 files changed, 82 insertions, 55 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index b771106c0a1..8569ac3760d 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) | |||
4233 | wl->active_sta_count--; | 4233 | wl->active_sta_count--; |
4234 | } | 4234 | } |
4235 | 4235 | ||
4236 | static int wl1271_op_sta_add(struct ieee80211_hw *hw, | 4236 | static int wl12xx_sta_add(struct wl1271 *wl, |
4237 | struct ieee80211_vif *vif, | 4237 | struct wl12xx_vif *wlvif, |
4238 | struct ieee80211_sta *sta) | 4238 | struct ieee80211_sta *sta) |
4239 | { | 4239 | { |
4240 | struct wl1271 *wl = hw->priv; | ||
4241 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4242 | struct wl1271_station *wl_sta; | 4240 | struct wl1271_station *wl_sta; |
4243 | int ret = 0; | 4241 | int ret = 0; |
4244 | u8 hlid; | 4242 | u8 hlid; |
4245 | 4243 | ||
4246 | mutex_lock(&wl->mutex); | ||
4247 | |||
4248 | if (unlikely(wl->state == WL1271_STATE_OFF)) | ||
4249 | goto out; | ||
4250 | |||
4251 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) | ||
4252 | goto out; | ||
4253 | |||
4254 | wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); | 4244 | wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid); |
4255 | 4245 | ||
4256 | ret = wl1271_allocate_sta(wl, wlvif, sta); | 4246 | ret = wl1271_allocate_sta(wl, wlvif, sta); |
4257 | if (ret < 0) | 4247 | if (ret < 0) |
4258 | goto out; | 4248 | return ret; |
4259 | 4249 | ||
4260 | wl_sta = (struct wl1271_station *)sta->drv_priv; | 4250 | wl_sta = (struct wl1271_station *)sta->drv_priv; |
4261 | hlid = wl_sta->hlid; | 4251 | hlid = wl_sta->hlid; |
4262 | 4252 | ||
4263 | ret = wl1271_ps_elp_wakeup(wl); | ||
4264 | if (ret < 0) | ||
4265 | goto out_free_sta; | ||
4266 | |||
4267 | ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); | 4253 | ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid); |
4268 | if (ret < 0) | 4254 | if (ret < 0) |
4269 | goto out_sleep; | 4255 | wl1271_free_sta(wl, wlvif, hlid); |
4270 | 4256 | ||
4271 | ret = wl12xx_cmd_set_peer_state(wl, hlid); | 4257 | return ret; |
4272 | if (ret < 0) | 4258 | } |
4273 | goto out_sleep; | ||
4274 | 4259 | ||
4275 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid); | 4260 | static int wl12xx_sta_remove(struct wl1271 *wl, |
4276 | if (ret < 0) | 4261 | struct wl12xx_vif *wlvif, |
4277 | goto out_sleep; | 4262 | struct ieee80211_sta *sta) |
4263 | { | ||
4264 | struct wl1271_station *wl_sta; | ||
4265 | int ret = 0, id; | ||
4278 | 4266 | ||
4279 | out_sleep: | 4267 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); |
4280 | wl1271_ps_elp_sleep(wl); | 4268 | |
4269 | wl_sta = (struct wl1271_station *)sta->drv_priv; | ||
4270 | id = wl_sta->hlid; | ||
4271 | if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) | ||
4272 | return -EINVAL; | ||
4281 | 4273 | ||
4282 | out_free_sta: | 4274 | ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); |
4283 | if (ret < 0) | 4275 | if (ret < 0) |
4284 | wl1271_free_sta(wl, wlvif, hlid); | 4276 | return ret; |
4285 | 4277 | ||
4286 | out: | 4278 | wl1271_free_sta(wl, wlvif, wl_sta->hlid); |
4287 | mutex_unlock(&wl->mutex); | ||
4288 | return ret; | 4279 | return ret; |
4289 | } | 4280 | } |
4290 | 4281 | ||
4291 | static int wl1271_op_sta_remove(struct ieee80211_hw *hw, | 4282 | static int wl12xx_update_sta_state(struct wl1271 *wl, |
4292 | struct ieee80211_vif *vif, | 4283 | struct wl12xx_vif *wlvif, |
4293 | struct ieee80211_sta *sta) | 4284 | struct ieee80211_sta *sta, |
4285 | enum ieee80211_sta_state old_state, | ||
4286 | enum ieee80211_sta_state new_state) | ||
4294 | { | 4287 | { |
4295 | struct wl1271 *wl = hw->priv; | ||
4296 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4297 | struct wl1271_station *wl_sta; | 4288 | struct wl1271_station *wl_sta; |
4298 | int ret = 0, id; | 4289 | u8 hlid; |
4290 | bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS; | ||
4291 | bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS; | ||
4292 | int ret; | ||
4299 | 4293 | ||
4300 | mutex_lock(&wl->mutex); | 4294 | wl_sta = (struct wl1271_station *)sta->drv_priv; |
4295 | hlid = wl_sta->hlid; | ||
4301 | 4296 | ||
4302 | if (unlikely(wl->state == WL1271_STATE_OFF)) | 4297 | /* Add station (AP mode) */ |
4303 | goto out; | 4298 | if (is_ap && |
4299 | old_state == IEEE80211_STA_NOTEXIST && | ||
4300 | new_state == IEEE80211_STA_NONE) | ||
4301 | return wl12xx_sta_add(wl, wlvif, sta); | ||
4302 | |||
4303 | /* Remove station (AP mode) */ | ||
4304 | if (is_ap && | ||
4305 | old_state == IEEE80211_STA_NONE && | ||
4306 | new_state == IEEE80211_STA_NOTEXIST) { | ||
4307 | /* must not fail */ | ||
4308 | wl12xx_sta_remove(wl, wlvif, sta); | ||
4309 | return 0; | ||
4310 | } | ||
4304 | 4311 | ||
4305 | if (wlvif->bss_type != BSS_TYPE_AP_BSS) | 4312 | /* Authorize station (AP mode) */ |
4306 | goto out; | 4313 | if (is_ap && |
4314 | new_state == IEEE80211_STA_AUTHORIZED) { | ||
4315 | ret = wl12xx_cmd_set_peer_state(wl, hlid); | ||
4316 | if (ret < 0) | ||
4317 | return ret; | ||
4307 | 4318 | ||
4308 | wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid); | 4319 | ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, |
4320 | hlid); | ||
4321 | return ret; | ||
4322 | } | ||
4309 | 4323 | ||
4310 | wl_sta = (struct wl1271_station *)sta->drv_priv; | 4324 | return 0; |
4311 | id = wl_sta->hlid; | 4325 | } |
4312 | if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map))) | 4326 | |
4327 | static int wl12xx_op_sta_state(struct ieee80211_hw *hw, | ||
4328 | struct ieee80211_vif *vif, | ||
4329 | struct ieee80211_sta *sta, | ||
4330 | enum ieee80211_sta_state old_state, | ||
4331 | enum ieee80211_sta_state new_state) | ||
4332 | { | ||
4333 | struct wl1271 *wl = hw->priv; | ||
4334 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | ||
4335 | int ret; | ||
4336 | |||
4337 | wl1271_debug(DEBUG_MAC80211, "mac80211 sta %d state=%d->%d", | ||
4338 | sta->aid, old_state, new_state); | ||
4339 | |||
4340 | mutex_lock(&wl->mutex); | ||
4341 | |||
4342 | if (unlikely(wl->state == WL1271_STATE_OFF)) { | ||
4343 | ret = -EBUSY; | ||
4313 | goto out; | 4344 | goto out; |
4345 | } | ||
4314 | 4346 | ||
4315 | ret = wl1271_ps_elp_wakeup(wl); | 4347 | ret = wl1271_ps_elp_wakeup(wl); |
4316 | if (ret < 0) | 4348 | if (ret < 0) |
4317 | goto out; | 4349 | goto out; |
4318 | 4350 | ||
4319 | ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); | 4351 | ret = wl12xx_update_sta_state(wl, wlvif, sta, old_state, new_state); |
4320 | if (ret < 0) | ||
4321 | goto out_sleep; | ||
4322 | 4352 | ||
4323 | wl1271_free_sta(wl, wlvif, wl_sta->hlid); | ||
4324 | |||
4325 | out_sleep: | ||
4326 | wl1271_ps_elp_sleep(wl); | 4353 | wl1271_ps_elp_sleep(wl); |
4327 | |||
4328 | out: | 4354 | out: |
4329 | mutex_unlock(&wl->mutex); | 4355 | mutex_unlock(&wl->mutex); |
4356 | if (new_state < old_state) | ||
4357 | return 0; | ||
4330 | return ret; | 4358 | return ret; |
4331 | } | 4359 | } |
4332 | 4360 | ||
@@ -4795,8 +4823,7 @@ static const struct ieee80211_ops wl1271_ops = { | |||
4795 | .conf_tx = wl1271_op_conf_tx, | 4823 | .conf_tx = wl1271_op_conf_tx, |
4796 | .get_tsf = wl1271_op_get_tsf, | 4824 | .get_tsf = wl1271_op_get_tsf, |
4797 | .get_survey = wl1271_op_get_survey, | 4825 | .get_survey = wl1271_op_get_survey, |
4798 | .sta_add = wl1271_op_sta_add, | 4826 | .sta_state = wl12xx_op_sta_state, |
4799 | .sta_remove = wl1271_op_sta_remove, | ||
4800 | .ampdu_action = wl1271_op_ampdu_action, | 4827 | .ampdu_action = wl1271_op_ampdu_action, |
4801 | .tx_frames_pending = wl1271_tx_frames_pending, | 4828 | .tx_frames_pending = wl1271_tx_frames_pending, |
4802 | .set_bitrate_mask = wl12xx_set_bitrate_mask, | 4829 | .set_bitrate_mask = wl12xx_set_bitrate_mask, |