aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
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
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')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c150
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c44
5 files changed, 174 insertions, 45 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index afd0f7d5b14..a637abe6efe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -928,10 +928,28 @@ struct iwl_addsta_cmd {
928/* 928/*
929 * REPLY_ADD_STA = 0x18 (response) 929 * REPLY_ADD_STA = 0x18 (response)
930 */ 930 */
931struct iwl4965_add_sta_resp { 931struct iwl_add_sta_resp {
932 u8 status; /* ADD_STA_* */ 932 u8 status; /* ADD_STA_* */
933} __attribute__ ((packed)); 933} __attribute__ ((packed));
934 934
935#define REM_STA_SUCCESS_MSK 0x1
936/*
937 * REPLY_REM_STA = 0x19 (response)
938 */
939struct iwl_rem_sta_resp {
940 u8 status;
941} __attribute__ ((packed));
942
943/*
944 * REPLY_REM_STA = 0x19 (command)
945 */
946struct iwl_rem_sta_cmd {
947 u8 num_sta; /* number of removed stations */
948 u8 reserved[3];
949 u8 addr[ETH_ALEN]; /* MAC addr of the first station */
950 u8 reserved2[2];
951} __attribute__ ((packed));
952
935/* 953/*
936 * REPLY_WEP_KEY = 0x20 954 * REPLY_WEP_KEY = 0x20
937 */ 955 */
@@ -2869,7 +2887,8 @@ struct iwl_rx_packet {
2869 struct iwl_error_resp err_resp; 2887 struct iwl_error_resp err_resp;
2870 struct iwl4965_card_state_notif card_state_notif; 2888 struct iwl4965_card_state_notif card_state_notif;
2871 struct iwl4965_beacon_notif beacon_status; 2889 struct iwl4965_beacon_notif beacon_status;
2872 struct iwl4965_add_sta_resp add_sta; 2890 struct iwl_add_sta_resp add_sta;
2891 struct iwl_rem_sta_resp rem_sta;
2873 struct iwl4965_sleep_notification sleep_notif; 2892 struct iwl4965_sleep_notification sleep_notif;
2874 struct iwl4965_spectrum_resp spectrum; 2893 struct iwl4965_spectrum_resp spectrum;
2875 struct iwl4965_notif_statistics stats; 2894 struct iwl4965_notif_statistics stats;
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 5291f1a3aeb..2c92e55850c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -333,6 +333,7 @@ struct iwl_cmd {
333 struct iwl_tx_cmd tx; 333 struct iwl_tx_cmd tx;
334 struct iwl4965_tx_beacon_cmd tx_beacon; 334 struct iwl4965_tx_beacon_cmd tx_beacon;
335 struct iwl4965_rxon_assoc_cmd rxon_assoc; 335 struct iwl4965_rxon_assoc_cmd rxon_assoc;
336 struct iwl_rem_sta_cmd rm_sta;
336 u8 *indirect; 337 u8 *indirect;
337 u8 payload[IWL_CMD_MAX_PAYLOAD]; 338 u8 payload[IWL_CMD_MAX_PAYLOAD];
338 } __attribute__ ((packed)) cmd; 339 } __attribute__ ((packed)) cmd;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 99ee1e14e29..11ec408f99c 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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index b643546961f..500e1df9c0e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -43,5 +43,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv,
43int iwl_remove_dynamic_key(struct iwl_priv *priv, 43int iwl_remove_dynamic_key(struct iwl_priv *priv,
44 struct ieee80211_key_conf *key, u8 sta_id); 44 struct ieee80211_key_conf *key, u8 sta_id);
45int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); 45int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
46u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
46int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); 47int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
47#endif /* __iwl_sta_h__ */ 48#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 985876b3eeb..185d667fc71 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -140,49 +140,6 @@ static const char *iwl4965_escape_essid(const char *essid, u8 essid_len)
140 140
141/**************************************************************/ 141/**************************************************************/
142 142
143#if 0 /* temporary disable till we add real remove station */
144/**
145 * iwl4965_remove_station - Remove driver's knowledge of station.
146 *
147 * NOTE: This does not remove station from device's station table.
148 */
149static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
150{
151 int index = IWL_INVALID_STATION;
152 int i;
153 unsigned long flags;
154
155 spin_lock_irqsave(&priv->sta_lock, flags);
156
157 if (is_ap)
158 index = IWL_AP_ID;
159 else if (is_broadcast_ether_addr(addr))
160 index = priv->hw_params.bcast_sta_id;
161 else
162 for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
163 if (priv->stations[i].used &&
164 !compare_ether_addr(priv->stations[i].sta.sta.addr,
165 addr)) {
166 index = i;
167 break;
168 }
169
170 if (unlikely(index == IWL_INVALID_STATION))
171 goto out;
172
173 if (priv->stations[index].used) {
174 priv->stations[index].used = 0;
175 priv->num_stations--;
176 }
177
178 BUG_ON(priv->num_stations < 0);
179
180out:
181 spin_unlock_irqrestore(&priv->sta_lock, flags);
182 return 0;
183}
184#endif
185
186 143
187 144
188static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) 145static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
@@ -404,6 +361,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
404 return rc; 361 return rc;
405 } 362 }
406 363
364 iwl_remove_station(priv, iwl_bcast_addr, 0);
407 iwlcore_clear_stations_table(priv); 365 iwlcore_clear_stations_table(priv);
408 366
409 if (!priv->error_recovering) 367 if (!priv->error_recovering)