aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)