aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-sta.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2008-06-30 05:23:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-30 17:37:38 -0400
commit24e5c40130c29bed0fbfbcc9c23613ae6ffc4c0a (patch)
tree0aa928342fc8fe0eb10e8ef8a40f0dd8e74ab6cf /drivers/net/wireless/iwlwifi/iwl-sta.c
parentf236a2657794b6f10b582bf6ccfbca7bf0d5ec82 (diff)
iwlwifi: better station table maintenance
This patch makes the station table maintenance safer. Two flags are maintained: 1) if station is present in driver 2) if station is present in uCode This will allow us in the future to deal with more stations than the firmware allows. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Zhu Yi <yi.zhu@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.c146
1 files changed, 95 insertions, 51 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index f874e7d7b225..c81ab5f9830f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -36,8 +36,8 @@
36#include "iwl-helpers.h" 36#include "iwl-helpers.h"
37 37
38 38
39#define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */ 39#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
40#define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */ 40#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */
41 41
42u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) 42u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
43{ 43{
@@ -83,10 +83,28 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
83} 83}
84EXPORT_SYMBOL(iwl_get_ra_sta_id); 84EXPORT_SYMBOL(iwl_get_ra_sta_id);
85 85
86static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
87{
88 unsigned long flags;
89 DECLARE_MAC_BUF(mac);
90
91 spin_lock_irqsave(&priv->sta_lock, flags);
92
93 if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
94 IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id);
95
96 priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE;
97 IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n",
98 print_mac(mac, priv->stations[sta_id].sta.sta.addr));
99
100 spin_unlock_irqrestore(&priv->sta_lock, flags);
101}
102
86static int iwl_add_sta_callback(struct iwl_priv *priv, 103static int iwl_add_sta_callback(struct iwl_priv *priv,
87 struct iwl_cmd *cmd, struct sk_buff *skb) 104 struct iwl_cmd *cmd, struct sk_buff *skb)
88{ 105{
89 struct iwl_rx_packet *res = NULL; 106 struct iwl_rx_packet *res = NULL;
107 u8 sta_id = cmd->cmd.addsta.sta.sta_id;
90 108
91 if (!skb) { 109 if (!skb) {
92 IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); 110 IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
@@ -102,8 +120,8 @@ static int iwl_add_sta_callback(struct iwl_priv *priv,
102 120
103 switch (res->u.add_sta.status) { 121 switch (res->u.add_sta.status) {
104 case ADD_STA_SUCCESS_MSK: 122 case ADD_STA_SUCCESS_MSK:
105 /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */ 123 iwl_sta_ucode_activate(priv, sta_id);
106 /* fail through */ 124 /* fall through */
107 default: 125 default:
108 IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n", 126 IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n",
109 res->u.add_sta.status); 127 res->u.add_sta.status);
@@ -147,6 +165,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
147 if (ret == 0) { 165 if (ret == 0) {
148 switch (res->u.add_sta.status) { 166 switch (res->u.add_sta.status) {
149 case ADD_STA_SUCCESS_MSK: 167 case ADD_STA_SUCCESS_MSK:
168 iwl_sta_ucode_activate(priv, sta->sta.sta_id);
150 IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n"); 169 IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
151 break; 170 break;
152 default: 171 default:
@@ -215,88 +234,92 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
215 u8 flags, struct ieee80211_ht_info *ht_info) 234 u8 flags, struct ieee80211_ht_info *ht_info)
216{ 235{
217 int i; 236 int i;
218 int index = IWL_INVALID_STATION; 237 int sta_id = IWL_INVALID_STATION;
219 struct iwl_station_entry *station; 238 struct iwl_station_entry *station;
220 unsigned long flags_spin; 239 unsigned long flags_spin;
221 DECLARE_MAC_BUF(mac); 240 DECLARE_MAC_BUF(mac);
222 241
223 spin_lock_irqsave(&priv->sta_lock, flags_spin); 242 spin_lock_irqsave(&priv->sta_lock, flags_spin);
224 if (is_ap) 243 if (is_ap)
225 index = IWL_AP_ID; 244 sta_id = IWL_AP_ID;
226 else if (is_broadcast_ether_addr(addr)) 245 else if (is_broadcast_ether_addr(addr))
227 index = priv->hw_params.bcast_sta_id; 246 sta_id = priv->hw_params.bcast_sta_id;
228 else 247 else
229 for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { 248 for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
230 if (!compare_ether_addr(priv->stations[i].sta.sta.addr, 249 if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
231 addr)) { 250 addr)) {
232 index = i; 251 sta_id = i;
233 break; 252 break;
234 } 253 }
235 254
236 if (!priv->stations[i].used && 255 if (!priv->stations[i].used &&
237 index == IWL_INVALID_STATION) 256 sta_id == IWL_INVALID_STATION)
238 index = i; 257 sta_id = i;
239 } 258 }
240 259
241
242 /* These two conditions have the same outcome, but keep them separate 260 /* These two conditions have the same outcome, but keep them separate
243 since they have different meanings */ 261 since they have different meanings */
244 if (unlikely(index == IWL_INVALID_STATION)) { 262 if (unlikely(sta_id == IWL_INVALID_STATION)) {
245 spin_unlock_irqrestore(&priv->sta_lock, flags_spin); 263 spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
246 return index; 264 return sta_id;
247 } 265 }
248 266
249 if (priv->stations[index].used && 267 if (priv->stations[sta_id].used &&
250 !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { 268 !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) {
251 spin_unlock_irqrestore(&priv->sta_lock, flags_spin); 269 spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
252 return index; 270 return sta_id;
253 } 271 }
254 272
255 273
256 IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); 274 station = &priv->stations[sta_id];
257 station = &priv->stations[index]; 275 station->used = IWL_STA_DRIVER_ACTIVE;
258 station->used = 1; 276 IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n",
277 sta_id, print_mac(mac, addr));
259 priv->num_stations++; 278 priv->num_stations++;
260 279
261 /* Set up the REPLY_ADD_STA command to send to device */ 280 /* Set up the REPLY_ADD_STA command to send to device */
262 memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); 281 memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
263 memcpy(station->sta.sta.addr, addr, ETH_ALEN); 282 memcpy(station->sta.sta.addr, addr, ETH_ALEN);
264 station->sta.mode = 0; 283 station->sta.mode = 0;
265 station->sta.sta.sta_id = index; 284 station->sta.sta.sta_id = sta_id;
266 station->sta.station_flags = 0; 285 station->sta.station_flags = 0;
267 286
268 /* BCAST station and IBSS stations do not work in HT mode */ 287 /* BCAST station and IBSS stations do not work in HT mode */
269 if (index != priv->hw_params.bcast_sta_id && 288 if (sta_id != priv->hw_params.bcast_sta_id &&
270 priv->iw_mode != IEEE80211_IF_TYPE_IBSS) 289 priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
271 iwl_set_ht_add_station(priv, index, ht_info); 290 iwl_set_ht_add_station(priv, sta_id, ht_info);
272 291
273 spin_unlock_irqrestore(&priv->sta_lock, flags_spin); 292 spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
274 293
275 /* Add station to device's station table */ 294 /* Add station to device's station table */
276 iwl_send_add_sta(priv, &station->sta, flags); 295 iwl_send_add_sta(priv, &station->sta, flags);
277 return index; 296 return sta_id;
278 297
279} 298}
280EXPORT_SYMBOL(iwl_add_station_flags); 299EXPORT_SYMBOL(iwl_add_station_flags);
281 300
282static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) 301static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
283{ 302{
284 unsigned long flags; 303 unsigned long flags;
285 u8 sta_id;
286 DECLARE_MAC_BUF(mac); 304 DECLARE_MAC_BUF(mac);
287 305
288 sta_id = iwl_find_station(priv, addr); 306 u8 sta_id = iwl_find_station(priv, addr);
289 if (sta_id != IWL_INVALID_STATION) { 307
290 IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", 308 BUG_ON(sta_id == IWL_INVALID_STATION);
291 print_mac(mac, addr)); 309
292 spin_lock_irqsave(&priv->sta_lock, flags); 310 IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n",
293 priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; 311 print_mac(mac, addr));
294 memset(&priv->stations[sta_id], 0, 312
295 sizeof(struct iwl_station_entry)); 313 spin_lock_irqsave(&priv->sta_lock, flags);
296 spin_unlock_irqrestore(&priv->sta_lock, flags); 314
297 return 0; 315 /* Ucode must be active and driver must be non active */
298 } 316 if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE)
299 return -EINVAL; 317 IWL_ERROR("removed non active STA %d\n", sta_id);
318
319 priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
320
321 memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
322 spin_unlock_irqrestore(&priv->sta_lock, flags);
300} 323}
301 324
302static int iwl_remove_sta_callback(struct iwl_priv *priv, 325static int iwl_remove_sta_callback(struct iwl_priv *priv,
@@ -322,6 +345,7 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv,
322 iwl_sta_ucode_deactivate(priv, addr); 345 iwl_sta_ucode_deactivate(priv, addr);
323 break; 346 break;
324 default: 347 default:
348 IWL_ERROR("REPLY_REMOVE_STA failed\n");
325 break; 349 break;
326 } 350 }
327 351
@@ -386,44 +410,63 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
386/** 410/**
387 * iwl_remove_station - Remove driver's knowledge of station. 411 * iwl_remove_station - Remove driver's knowledge of station.
388 */ 412 */
389u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) 413int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
390{ 414{
391 int index = IWL_INVALID_STATION; 415 int sta_id = IWL_INVALID_STATION;
392 int i; 416 int i, ret = -EINVAL;
393 unsigned long flags; 417 unsigned long flags;
418 DECLARE_MAC_BUF(mac);
394 419
395 spin_lock_irqsave(&priv->sta_lock, flags); 420 spin_lock_irqsave(&priv->sta_lock, flags);
396 421
397 if (is_ap) 422 if (is_ap)
398 index = IWL_AP_ID; 423 sta_id = IWL_AP_ID;
399 else if (is_broadcast_ether_addr(addr)) 424 else if (is_broadcast_ether_addr(addr))
400 index = priv->hw_params.bcast_sta_id; 425 sta_id = priv->hw_params.bcast_sta_id;
401 else 426 else
402 for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) 427 for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
403 if (priv->stations[i].used && 428 if (priv->stations[i].used &&
404 !compare_ether_addr(priv->stations[i].sta.sta.addr, 429 !compare_ether_addr(priv->stations[i].sta.sta.addr,
405 addr)) { 430 addr)) {
406 index = i; 431 sta_id = i;
407 break; 432 break;
408 } 433 }
409 434
410 if (unlikely(index == IWL_INVALID_STATION)) 435 if (unlikely(sta_id == IWL_INVALID_STATION))
411 goto out; 436 goto out;
412 437
413 if (priv->stations[index].used) { 438 IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n",
414 priv->stations[index].used = 0; 439 sta_id, print_mac(mac, addr));
415 priv->num_stations--; 440
441 if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
442 IWL_ERROR("Removing %s but non DRIVER active\n",
443 print_mac(mac, addr));
444 goto out;
445 }
446
447 if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
448 IWL_ERROR("Removing %s but non UCODE active\n",
449 print_mac(mac, addr));
450 goto out;
416 } 451 }
417 452
453
454 priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
455
456 priv->num_stations--;
457
418 BUG_ON(priv->num_stations < 0); 458 BUG_ON(priv->num_stations < 0);
459
419 spin_unlock_irqrestore(&priv->sta_lock, flags); 460 spin_unlock_irqrestore(&priv->sta_lock, flags);
420 iwl_send_remove_station(priv, addr, CMD_ASYNC); 461
421 return index; 462 ret = iwl_send_remove_station(priv, addr, CMD_ASYNC);
463 return ret;
422out: 464out:
423 spin_unlock_irqrestore(&priv->sta_lock, flags); 465 spin_unlock_irqrestore(&priv->sta_lock, flags);
424 return 0; 466 return ret;
425} 467}
426EXPORT_SYMBOL(iwl_remove_station); 468EXPORT_SYMBOL(iwl_remove_station);
469
427static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) 470static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
428{ 471{
429 int i; 472 int i;
@@ -845,6 +888,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
845 iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, 888 iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
846 sizeof(link_cmd), &link_cmd, NULL); 889 sizeof(link_cmd), &link_cmd, NULL);
847} 890}
891
848/** 892/**
849 * iwl_rxon_add_station - add station into station table. 893 * iwl_rxon_add_station - add station into station table.
850 * 894 *