aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-sta.c
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-05-29 04:35:02 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-03 15:00:23 -0400
commit7a999bf0c5eb19b20ac6ab0f21f6e5013400fa51 (patch)
tree4879bb2ebc4a6170ea423f2e3e1775ced5cef8c9 /drivers/net/wireless/iwlwifi/iwl-sta.c
parentb3bbacb78bc688707ac312158c5bbc6bbbb55b23 (diff)
iwlwifi: add remove station functionality
This patch adds remove station functionality, which is required for 5000 and AP mode. There are still some gaps in managment that need to be closed but it provides sufficient functionality for 5000 HW. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 99ee1e14e29e..11ec408f99c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -37,6 +37,10 @@
37#include "iwl-io.h" 37#include "iwl-io.h"
38#include "iwl-helpers.h" 38#include "iwl-helpers.h"
39 39
40
41#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */
42#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */
43
40u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) 44u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
41{ 45{
42 int i; 46 int i;
@@ -241,6 +245,152 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
241} 245}
242EXPORT_SYMBOL(iwl_add_station_flags); 246EXPORT_SYMBOL(iwl_add_station_flags);
243 247
248
249static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
250{
251 unsigned long flags;
252 u8 sta_id;
253 DECLARE_MAC_BUF(mac);
254
255 sta_id = iwl_find_station(priv, addr);
256 if (sta_id != IWL_INVALID_STATION) {
257 IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
258 print_mac(mac, addr));
259 spin_lock_irqsave(&priv->sta_lock, flags);
260 priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
261 memset(&priv->stations[sta_id], 0,
262 sizeof(struct iwl_station_entry));
263 spin_unlock_irqrestore(&priv->sta_lock, flags);
264 return 0;
265 }
266 return -EINVAL;
267}
268
269static int iwl_remove_sta_callback(struct iwl_priv *priv,
270 struct iwl_cmd *cmd, struct sk_buff *skb)
271{
272 struct iwl_rx_packet *res = NULL;
273 const char *addr = cmd->cmd.rm_sta.addr;
274
275 if (!skb) {
276 IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n");
277 return 1;
278 }
279
280 res = (struct iwl_rx_packet *)skb->data;
281 if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
282 IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
283 res->hdr.flags);
284 return 1;
285 }
286
287 switch (res->u.rem_sta.status) {
288 case REM_STA_SUCCESS_MSK:
289 iwl_sta_ucode_deactivate(priv, addr);
290 break;
291 default:
292 break;
293 }
294
295 /* We didn't cache the SKB; let the caller free it */
296 return 1;
297}
298
299static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
300 u8 flags)
301{
302 struct iwl_rx_packet *res = NULL;
303 int ret;
304
305 struct iwl_rem_sta_cmd rm_sta_cmd;
306
307 struct iwl_host_cmd cmd = {
308 .id = REPLY_REMOVE_STA,
309 .len = sizeof(struct iwl_rem_sta_cmd),
310 .meta.flags = flags,
311 .data = &rm_sta_cmd,
312 };
313
314 memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
315 rm_sta_cmd.num_sta = 1;
316 memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
317
318 if (flags & CMD_ASYNC)
319 cmd.meta.u.callback = iwl_remove_sta_callback;
320 else
321 cmd.meta.flags |= CMD_WANT_SKB;
322 ret = iwl_send_cmd(priv, &cmd);
323
324 if (ret || (flags & CMD_ASYNC))
325 return ret;
326
327 res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
328 if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
329 IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n",
330 res->hdr.flags);
331 ret = -EIO;
332 }
333
334 if (!ret) {
335 switch (res->u.rem_sta.status) {
336 case REM_STA_SUCCESS_MSK:
337 iwl_sta_ucode_deactivate(priv, addr);
338 IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n");
339 break;
340 default:
341 ret = -EIO;
342 IWL_ERROR("REPLY_REMOVE_STA failed\n");
343 break;
344 }
345 }
346
347 priv->alloc_rxb_skb--;
348 dev_kfree_skb_any(cmd.meta.u.skb);
349
350 return ret;
351}
352/**
353 * iwl_remove_station - Remove driver's knowledge of station.
354 *
355 */
356u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
357{
358 int index = IWL_INVALID_STATION;
359 int i;
360 unsigned long flags;
361
362 spin_lock_irqsave(&priv->sta_lock, flags);
363
364 if (is_ap)
365 index = IWL_AP_ID;
366 else if (is_broadcast_ether_addr(addr))
367 index = priv->hw_params.bcast_sta_id;
368 else
369 for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
370 if (priv->stations[i].used &&
371 !compare_ether_addr(priv->stations[i].sta.sta.addr,
372 addr)) {
373 index = i;
374 break;
375 }
376
377 if (unlikely(index == IWL_INVALID_STATION))
378 goto out;
379
380 if (priv->stations[index].used) {
381 priv->stations[index].used = 0;
382 priv->num_stations--;
383 }
384
385 BUG_ON(priv->num_stations < 0);
386 spin_unlock_irqrestore(&priv->sta_lock, flags);
387 iwl_send_remove_station(priv, addr, CMD_ASYNC);
388 return index;
389out:
390 spin_unlock_irqrestore(&priv->sta_lock, flags);
391 return 0;
392}
393EXPORT_SYMBOL(iwl_remove_station);
244int iwl_get_free_ucode_key_index(struct iwl_priv *priv) 394int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
245{ 395{
246 int i; 396 int i;