diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 23 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 150 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl4965-base.c | 44 |
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 | */ |
931 | struct iwl4965_add_sta_resp { | 931 | struct 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 | */ | ||
939 | struct iwl_rem_sta_resp { | ||
940 | u8 status; | ||
941 | } __attribute__ ((packed)); | ||
942 | |||
943 | /* | ||
944 | * REPLY_REM_STA = 0x19 (command) | ||
945 | */ | ||
946 | struct 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 | |||
40 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | 44 | u8 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 | } |
242 | EXPORT_SYMBOL(iwl_add_station_flags); | 246 | EXPORT_SYMBOL(iwl_add_station_flags); |
243 | 247 | ||
248 | |||
249 | static 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 | |||
269 | static 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 | |||
299 | static 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 | */ | ||
356 | u8 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; | ||
389 | out: | ||
390 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
391 | return 0; | ||
392 | } | ||
393 | EXPORT_SYMBOL(iwl_remove_station); | ||
244 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 394 | int 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, | |||
43 | int iwl_remove_dynamic_key(struct iwl_priv *priv, | 43 | int 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); |
45 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); | 45 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); |
46 | u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); | ||
46 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); | 47 | int 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 | */ | ||
149 | static 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 | |||
180 | out: | ||
181 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
182 | return 0; | ||
183 | } | ||
184 | #endif | ||
185 | |||
186 | 143 | ||
187 | 144 | ||
188 | static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) | 145 | static 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) |