diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-06-30 05:23:03 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-30 17:37:38 -0400 |
commit | 24e5c40130c29bed0fbfbcc9c23613ae6ffc4c0a (patch) | |
tree | 0aa928342fc8fe0eb10e8ef8a40f0dd8e74ab6cf /drivers/net/wireless/iwlwifi/iwl-sta.c | |
parent | f236a2657794b6f10b582bf6ccfbca7bf0d5ec82 (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.c | 146 |
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 | ||
42 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | 42 | u8 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 | } |
84 | EXPORT_SYMBOL(iwl_get_ra_sta_id); | 84 | EXPORT_SYMBOL(iwl_get_ra_sta_id); |
85 | 85 | ||
86 | static 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 | |||
86 | static int iwl_add_sta_callback(struct iwl_priv *priv, | 103 | static 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 | } |
280 | EXPORT_SYMBOL(iwl_add_station_flags); | 299 | EXPORT_SYMBOL(iwl_add_station_flags); |
281 | 300 | ||
282 | static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) | 301 | static 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 | ||
302 | static int iwl_remove_sta_callback(struct iwl_priv *priv, | 325 | static 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 | */ |
389 | u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | 413 | int 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; | ||
422 | out: | 464 | out: |
423 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 465 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
424 | return 0; | 466 | return ret; |
425 | } | 467 | } |
426 | EXPORT_SYMBOL(iwl_remove_station); | 468 | EXPORT_SYMBOL(iwl_remove_station); |
469 | |||
427 | static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 470 | static 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 | * |