diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 901 |
1 files changed, 495 insertions, 406 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 4a6686fa6b36..85ed235ac901 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -29,57 +29,12 @@ | |||
29 | 29 | ||
30 | #include <net/mac80211.h> | 30 | #include <net/mac80211.h> |
31 | #include <linux/etherdevice.h> | 31 | #include <linux/etherdevice.h> |
32 | #include <linux/sched.h> | ||
32 | 33 | ||
33 | #include "iwl-dev.h" | 34 | #include "iwl-dev.h" |
34 | #include "iwl-core.h" | 35 | #include "iwl-core.h" |
35 | #include "iwl-sta.h" | 36 | #include "iwl-sta.h" |
36 | 37 | ||
37 | #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ | ||
38 | #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ | ||
39 | |||
40 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | ||
41 | { | ||
42 | int i; | ||
43 | int start = 0; | ||
44 | int ret = IWL_INVALID_STATION; | ||
45 | unsigned long flags; | ||
46 | |||
47 | if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || | ||
48 | (priv->iw_mode == NL80211_IFTYPE_AP)) | ||
49 | start = IWL_STA_ID; | ||
50 | |||
51 | if (is_broadcast_ether_addr(addr)) | ||
52 | return priv->hw_params.bcast_sta_id; | ||
53 | |||
54 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
55 | for (i = start; i < priv->hw_params.max_stations; i++) | ||
56 | if (priv->stations[i].used && | ||
57 | (!compare_ether_addr(priv->stations[i].sta.sta.addr, | ||
58 | addr))) { | ||
59 | ret = i; | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | IWL_DEBUG_ASSOC_LIMIT(priv, "can not find STA %pM total %d\n", | ||
64 | addr, priv->num_stations); | ||
65 | |||
66 | out: | ||
67 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
68 | return ret; | ||
69 | } | ||
70 | EXPORT_SYMBOL(iwl_find_station); | ||
71 | |||
72 | int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | ||
73 | { | ||
74 | if (priv->iw_mode == NL80211_IFTYPE_STATION) { | ||
75 | return IWL_AP_ID; | ||
76 | } else { | ||
77 | u8 *da = ieee80211_get_DA(hdr); | ||
78 | return iwl_find_station(priv, da); | ||
79 | } | ||
80 | } | ||
81 | EXPORT_SYMBOL(iwl_get_ra_sta_id); | ||
82 | |||
83 | /* priv->sta_lock must be held */ | 38 | /* priv->sta_lock must be held */ |
84 | static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) | 39 | static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) |
85 | { | 40 | { |
@@ -132,7 +87,7 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
132 | sta_id); | 87 | sta_id); |
133 | break; | 88 | break; |
134 | case ADD_STA_MODIFY_NON_EXIST_STA: | 89 | case ADD_STA_MODIFY_NON_EXIST_STA: |
135 | IWL_ERR(priv, "Attempting to modify non-existing station %d \n", | 90 | IWL_ERR(priv, "Attempting to modify non-existing station %d\n", |
136 | sta_id); | 91 | sta_id); |
137 | break; | 92 | break; |
138 | default: | 93 | default: |
@@ -158,13 +113,6 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
158 | priv->stations[sta_id].sta.mode == | 113 | priv->stations[sta_id].sta.mode == |
159 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 114 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", |
160 | addsta->sta.addr); | 115 | addsta->sta.addr); |
161 | |||
162 | /* | ||
163 | * Determine if we wanted to modify or add a station, | ||
164 | * if adding a station succeeded we have some more initialization | ||
165 | * to do when using station notification. TODO | ||
166 | */ | ||
167 | |||
168 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 116 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
169 | } | 117 | } |
170 | 118 | ||
@@ -190,6 +138,10 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
190 | .flags = flags, | 138 | .flags = flags, |
191 | .data = data, | 139 | .data = data, |
192 | }; | 140 | }; |
141 | u8 sta_id __maybe_unused = sta->sta.sta_id; | ||
142 | |||
143 | IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", | ||
144 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); | ||
193 | 145 | ||
194 | if (flags & CMD_ASYNC) | 146 | if (flags & CMD_ASYNC) |
195 | cmd.callback = iwl_add_sta_callback; | 147 | cmd.callback = iwl_add_sta_callback; |
@@ -263,18 +215,19 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | |||
263 | } | 215 | } |
264 | 216 | ||
265 | /** | 217 | /** |
266 | * iwl_add_station - Add station to tables in driver and device | 218 | * iwl_prep_station - Prepare station information for addition |
219 | * | ||
220 | * should be called with sta_lock held | ||
267 | */ | 221 | */ |
268 | u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | 222 | static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr, |
269 | struct ieee80211_sta_ht_cap *ht_info) | 223 | bool is_ap, |
224 | struct ieee80211_sta_ht_cap *ht_info) | ||
270 | { | 225 | { |
271 | struct iwl_station_entry *station; | 226 | struct iwl_station_entry *station; |
272 | unsigned long flags_spin; | ||
273 | int i; | 227 | int i; |
274 | int sta_id = IWL_INVALID_STATION; | 228 | u8 sta_id = IWL_INVALID_STATION; |
275 | u16 rate; | 229 | u16 rate; |
276 | 230 | ||
277 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
278 | if (is_ap) | 231 | if (is_ap) |
279 | sta_id = IWL_AP_ID; | 232 | sta_id = IWL_AP_ID; |
280 | else if (is_broadcast_ether_addr(addr)) | 233 | else if (is_broadcast_ether_addr(addr)) |
@@ -292,20 +245,32 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | |||
292 | sta_id = i; | 245 | sta_id = i; |
293 | } | 246 | } |
294 | 247 | ||
295 | /* These two conditions have the same outcome, but keep them separate | 248 | /* |
296 | since they have different meanings */ | 249 | * These two conditions have the same outcome, but keep them |
297 | if (unlikely(sta_id == IWL_INVALID_STATION)) { | 250 | * separate |
298 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 251 | */ |
252 | if (unlikely(sta_id == IWL_INVALID_STATION)) | ||
253 | return sta_id; | ||
254 | |||
255 | /* | ||
256 | * uCode is not able to deal with multiple requests to add a | ||
257 | * station. Keep track if one is in progress so that we do not send | ||
258 | * another. | ||
259 | */ | ||
260 | if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { | ||
261 | IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n", | ||
262 | sta_id); | ||
299 | return sta_id; | 263 | return sta_id; |
300 | } | 264 | } |
301 | 265 | ||
302 | if (priv->stations[sta_id].used && | 266 | if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && |
267 | (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) && | ||
303 | !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { | 268 | !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { |
304 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 269 | IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n", |
270 | sta_id, addr); | ||
305 | return sta_id; | 271 | return sta_id; |
306 | } | 272 | } |
307 | 273 | ||
308 | |||
309 | station = &priv->stations[sta_id]; | 274 | station = &priv->stations[sta_id]; |
310 | station->used = IWL_STA_DRIVER_ACTIVE; | 275 | station->used = IWL_STA_DRIVER_ACTIVE; |
311 | IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", | 276 | IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", |
@@ -319,10 +284,12 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | |||
319 | station->sta.sta.sta_id = sta_id; | 284 | station->sta.sta.sta_id = sta_id; |
320 | station->sta.station_flags = 0; | 285 | station->sta.station_flags = 0; |
321 | 286 | ||
322 | /* BCAST station and IBSS stations do not work in HT mode */ | 287 | /* |
323 | if (sta_id != priv->hw_params.bcast_sta_id && | 288 | * OK to call unconditionally, since local stations (IBSS BSSID |
324 | priv->iw_mode != NL80211_IFTYPE_ADHOC) | 289 | * STA and broadcast STA) pass in a NULL ht_info, and mac80211 |
325 | iwl_set_ht_add_station(priv, sta_id, ht_info); | 290 | * doesn't allow HT IBSS. |
291 | */ | ||
292 | iwl_set_ht_add_station(priv, sta_id, ht_info); | ||
326 | 293 | ||
327 | /* 3945 only */ | 294 | /* 3945 only */ |
328 | rate = (priv->band == IEEE80211_BAND_5GHZ) ? | 295 | rate = (priv->band == IEEE80211_BAND_5GHZ) ? |
@@ -330,86 +297,221 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags, | |||
330 | /* Turn on both antennas for the station... */ | 297 | /* Turn on both antennas for the station... */ |
331 | station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); | 298 | station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK); |
332 | 299 | ||
300 | return sta_id; | ||
301 | |||
302 | } | ||
303 | |||
304 | #define STA_WAIT_TIMEOUT (HZ/2) | ||
305 | |||
306 | /** | ||
307 | * iwl_add_station_common - | ||
308 | */ | ||
309 | int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr, | ||
310 | bool is_ap, | ||
311 | struct ieee80211_sta_ht_cap *ht_info, | ||
312 | u8 *sta_id_r) | ||
313 | { | ||
314 | struct iwl_station_entry *station; | ||
315 | unsigned long flags_spin; | ||
316 | int ret = 0; | ||
317 | u8 sta_id; | ||
318 | |||
319 | *sta_id_r = 0; | ||
320 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
321 | sta_id = iwl_prep_station(priv, addr, is_ap, ht_info); | ||
322 | if (sta_id == IWL_INVALID_STATION) { | ||
323 | IWL_ERR(priv, "Unable to prepare station %pM for addition\n", | ||
324 | addr); | ||
325 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * uCode is not able to deal with multiple requests to add a | ||
331 | * station. Keep track if one is in progress so that we do not send | ||
332 | * another. | ||
333 | */ | ||
334 | if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { | ||
335 | IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n", | ||
336 | sta_id); | ||
337 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
338 | return -EEXIST; | ||
339 | } | ||
340 | |||
341 | if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && | ||
342 | (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { | ||
343 | IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n", | ||
344 | sta_id, addr); | ||
345 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
346 | return -EEXIST; | ||
347 | } | ||
348 | |||
349 | priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS; | ||
350 | station = &priv->stations[sta_id]; | ||
333 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | 351 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
334 | 352 | ||
335 | /* Add station to device's station table */ | 353 | /* Add station to device's station table */ |
336 | iwl_send_add_sta(priv, &station->sta, flags); | 354 | ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC); |
337 | return sta_id; | 355 | if (ret) { |
356 | IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr); | ||
357 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
358 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
359 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
360 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
361 | } | ||
362 | *sta_id_r = sta_id; | ||
363 | return ret; | ||
364 | } | ||
365 | EXPORT_SYMBOL(iwl_add_station_common); | ||
366 | |||
367 | static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv, | ||
368 | u8 sta_id) | ||
369 | { | ||
370 | int i, r; | ||
371 | struct iwl_link_quality_cmd *link_cmd; | ||
372 | u32 rate_flags; | ||
373 | |||
374 | link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); | ||
375 | if (!link_cmd) { | ||
376 | IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); | ||
377 | return NULL; | ||
378 | } | ||
379 | /* Set up the rate scaling to start at selected rate, fall back | ||
380 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
381 | if (priv->band == IEEE80211_BAND_5GHZ) | ||
382 | r = IWL_RATE_6M_INDEX; | ||
383 | else | ||
384 | r = IWL_RATE_1M_INDEX; | ||
338 | 385 | ||
386 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
387 | rate_flags = 0; | ||
388 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
389 | rate_flags |= RATE_MCS_CCK_MSK; | ||
390 | |||
391 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | ||
392 | RATE_MCS_ANT_POS; | ||
393 | |||
394 | link_cmd->rs_table[i].rate_n_flags = | ||
395 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
396 | r = iwl_get_prev_ieee_rate(r); | ||
397 | } | ||
398 | |||
399 | link_cmd->general_params.single_stream_ant_msk = | ||
400 | first_antenna(priv->hw_params.valid_tx_ant); | ||
401 | |||
402 | link_cmd->general_params.dual_stream_ant_msk = | ||
403 | priv->hw_params.valid_tx_ant & | ||
404 | ~first_antenna(priv->hw_params.valid_tx_ant); | ||
405 | if (!link_cmd->general_params.dual_stream_ant_msk) { | ||
406 | link_cmd->general_params.dual_stream_ant_msk = ANT_AB; | ||
407 | } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { | ||
408 | link_cmd->general_params.dual_stream_ant_msk = | ||
409 | priv->hw_params.valid_tx_ant; | ||
410 | } | ||
411 | |||
412 | link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
413 | link_cmd->agg_params.agg_time_limit = | ||
414 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
415 | |||
416 | link_cmd->sta_id = sta_id; | ||
417 | |||
418 | return link_cmd; | ||
339 | } | 419 | } |
340 | EXPORT_SYMBOL(iwl_add_station); | ||
341 | 420 | ||
342 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const u8 *addr) | 421 | /* |
422 | * iwl_add_bssid_station - Add the special IBSS BSSID station | ||
423 | * | ||
424 | * Function sleeps. | ||
425 | */ | ||
426 | int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs, | ||
427 | u8 *sta_id_r) | ||
343 | { | 428 | { |
429 | int ret; | ||
430 | u8 sta_id; | ||
431 | struct iwl_link_quality_cmd *link_cmd; | ||
344 | unsigned long flags; | 432 | unsigned long flags; |
345 | u8 sta_id = iwl_find_station(priv, addr); | ||
346 | 433 | ||
347 | BUG_ON(sta_id == IWL_INVALID_STATION); | 434 | if (*sta_id_r) |
435 | *sta_id_r = IWL_INVALID_STATION; | ||
348 | 436 | ||
349 | IWL_DEBUG_ASSOC(priv, "Removed STA from Ucode: %pM\n", addr); | 437 | ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id); |
438 | if (ret) { | ||
439 | IWL_ERR(priv, "Unable to add station %pM\n", addr); | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | if (sta_id_r) | ||
444 | *sta_id_r = sta_id; | ||
350 | 445 | ||
351 | spin_lock_irqsave(&priv->sta_lock, flags); | 446 | spin_lock_irqsave(&priv->sta_lock, flags); |
447 | priv->stations[sta_id].used |= IWL_STA_LOCAL; | ||
448 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
352 | 449 | ||
353 | /* Ucode must be active and driver must be non active */ | 450 | if (init_rs) { |
354 | if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE) | 451 | /* Set up default rate scaling table in device's station table */ |
355 | IWL_ERR(priv, "removed non active STA %d\n", sta_id); | 452 | link_cmd = iwl_sta_alloc_lq(priv, sta_id); |
453 | if (!link_cmd) { | ||
454 | IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", | ||
455 | addr); | ||
456 | return -ENOMEM; | ||
457 | } | ||
356 | 458 | ||
357 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; | 459 | ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true); |
460 | if (ret) | ||
461 | IWL_ERR(priv, "Link quality command failed (%d)\n", ret); | ||
358 | 462 | ||
359 | memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); | 463 | spin_lock_irqsave(&priv->sta_lock, flags); |
360 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 464 | priv->stations[sta_id].lq = link_cmd; |
465 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
466 | } | ||
467 | |||
468 | return 0; | ||
361 | } | 469 | } |
470 | EXPORT_SYMBOL(iwl_add_bssid_station); | ||
362 | 471 | ||
363 | static void iwl_remove_sta_callback(struct iwl_priv *priv, | 472 | /** |
364 | struct iwl_device_cmd *cmd, | 473 | * iwl_sta_ucode_deactivate - deactivate ucode status for a station |
365 | struct iwl_rx_packet *pkt) | 474 | * |
475 | * priv->sta_lock must be held | ||
476 | */ | ||
477 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) | ||
366 | { | 478 | { |
367 | struct iwl_rem_sta_cmd *rm_sta = | 479 | /* Ucode must be active and driver must be non active */ |
368 | (struct iwl_rem_sta_cmd *)cmd->cmd.payload; | 480 | if ((priv->stations[sta_id].used & |
369 | const u8 *addr = rm_sta->addr; | 481 | (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != IWL_STA_UCODE_ACTIVE) |
482 | IWL_ERR(priv, "removed non active STA %u\n", sta_id); | ||
370 | 483 | ||
371 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | 484 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; |
372 | IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", | ||
373 | pkt->hdr.flags); | ||
374 | return; | ||
375 | } | ||
376 | 485 | ||
377 | switch (pkt->u.rem_sta.status) { | 486 | memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); |
378 | case REM_STA_SUCCESS_MSK: | 487 | IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id); |
379 | iwl_sta_ucode_deactivate(priv, addr); | ||
380 | break; | ||
381 | default: | ||
382 | IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); | ||
383 | break; | ||
384 | } | ||
385 | } | 488 | } |
386 | 489 | ||
387 | static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | 490 | static int iwl_send_remove_station(struct iwl_priv *priv, |
388 | u8 flags) | 491 | struct iwl_station_entry *station) |
389 | { | 492 | { |
390 | struct iwl_rx_packet *pkt; | 493 | struct iwl_rx_packet *pkt; |
391 | int ret; | 494 | int ret; |
392 | 495 | ||
496 | unsigned long flags_spin; | ||
393 | struct iwl_rem_sta_cmd rm_sta_cmd; | 497 | struct iwl_rem_sta_cmd rm_sta_cmd; |
394 | 498 | ||
395 | struct iwl_host_cmd cmd = { | 499 | struct iwl_host_cmd cmd = { |
396 | .id = REPLY_REMOVE_STA, | 500 | .id = REPLY_REMOVE_STA, |
397 | .len = sizeof(struct iwl_rem_sta_cmd), | 501 | .len = sizeof(struct iwl_rem_sta_cmd), |
398 | .flags = flags, | 502 | .flags = CMD_SYNC, |
399 | .data = &rm_sta_cmd, | 503 | .data = &rm_sta_cmd, |
400 | }; | 504 | }; |
401 | 505 | ||
402 | memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); | 506 | memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); |
403 | rm_sta_cmd.num_sta = 1; | 507 | rm_sta_cmd.num_sta = 1; |
404 | memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); | 508 | memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN); |
509 | |||
510 | cmd.flags |= CMD_WANT_SKB; | ||
405 | 511 | ||
406 | if (flags & CMD_ASYNC) | ||
407 | cmd.callback = iwl_remove_sta_callback; | ||
408 | else | ||
409 | cmd.flags |= CMD_WANT_SKB; | ||
410 | ret = iwl_send_cmd(priv, &cmd); | 512 | ret = iwl_send_cmd(priv, &cmd); |
411 | 513 | ||
412 | if (ret || (flags & CMD_ASYNC)) | 514 | if (ret) |
413 | return ret; | 515 | return ret; |
414 | 516 | ||
415 | pkt = (struct iwl_rx_packet *)cmd.reply_page; | 517 | pkt = (struct iwl_rx_packet *)cmd.reply_page; |
@@ -422,7 +524,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | |||
422 | if (!ret) { | 524 | if (!ret) { |
423 | switch (pkt->u.rem_sta.status) { | 525 | switch (pkt->u.rem_sta.status) { |
424 | case REM_STA_SUCCESS_MSK: | 526 | case REM_STA_SUCCESS_MSK: |
425 | iwl_sta_ucode_deactivate(priv, addr); | 527 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
528 | iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id); | ||
529 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
426 | IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); | 530 | IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); |
427 | break; | 531 | break; |
428 | default: | 532 | default: |
@@ -439,45 +543,48 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | |||
439 | /** | 543 | /** |
440 | * iwl_remove_station - Remove driver's knowledge of station. | 544 | * iwl_remove_station - Remove driver's knowledge of station. |
441 | */ | 545 | */ |
442 | int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | 546 | int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, |
547 | const u8 *addr) | ||
443 | { | 548 | { |
444 | int sta_id = IWL_INVALID_STATION; | 549 | struct iwl_station_entry *station; |
445 | int i, ret = -EINVAL; | ||
446 | unsigned long flags; | 550 | unsigned long flags; |
447 | 551 | ||
448 | spin_lock_irqsave(&priv->sta_lock, flags); | 552 | if (!iwl_is_ready(priv)) { |
553 | IWL_DEBUG_INFO(priv, | ||
554 | "Unable to remove station %pM, device not ready.\n", | ||
555 | addr); | ||
556 | /* | ||
557 | * It is typical for stations to be removed when we are | ||
558 | * going down. Return success since device will be down | ||
559 | * soon anyway | ||
560 | */ | ||
561 | return 0; | ||
562 | } | ||
449 | 563 | ||
450 | if (is_ap) | 564 | IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", |
451 | sta_id = IWL_AP_ID; | 565 | sta_id, addr); |
452 | else if (is_broadcast_ether_addr(addr)) | ||
453 | sta_id = priv->hw_params.bcast_sta_id; | ||
454 | else | ||
455 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) | ||
456 | if (priv->stations[i].used && | ||
457 | !compare_ether_addr(priv->stations[i].sta.sta.addr, | ||
458 | addr)) { | ||
459 | sta_id = i; | ||
460 | break; | ||
461 | } | ||
462 | 566 | ||
463 | if (unlikely(sta_id == IWL_INVALID_STATION)) | 567 | if (WARN_ON(sta_id == IWL_INVALID_STATION)) |
464 | goto out; | 568 | return -EINVAL; |
465 | 569 | ||
466 | IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", | 570 | spin_lock_irqsave(&priv->sta_lock, flags); |
467 | sta_id, addr); | ||
468 | 571 | ||
469 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { | 572 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { |
470 | IWL_ERR(priv, "Removing %pM but non DRIVER active\n", | 573 | IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n", |
471 | addr); | 574 | addr); |
472 | goto out; | 575 | goto out_err; |
473 | } | 576 | } |
474 | 577 | ||
475 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { | 578 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { |
476 | IWL_ERR(priv, "Removing %pM but non UCODE active\n", | 579 | IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n", |
477 | addr); | 580 | addr); |
478 | goto out; | 581 | goto out_err; |
479 | } | 582 | } |
480 | 583 | ||
584 | if (priv->stations[sta_id].used & IWL_STA_LOCAL) { | ||
585 | kfree(priv->stations[sta_id].lq); | ||
586 | priv->stations[sta_id].lq = NULL; | ||
587 | } | ||
481 | 588 | ||
482 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | 589 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; |
483 | 590 | ||
@@ -485,47 +592,112 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | |||
485 | 592 | ||
486 | BUG_ON(priv->num_stations < 0); | 593 | BUG_ON(priv->num_stations < 0); |
487 | 594 | ||
595 | station = &priv->stations[sta_id]; | ||
488 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 596 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
489 | 597 | ||
490 | ret = iwl_send_remove_station(priv, addr, CMD_ASYNC); | 598 | return iwl_send_remove_station(priv, station); |
491 | return ret; | 599 | out_err: |
492 | out: | ||
493 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 600 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
494 | return ret; | 601 | return -EINVAL; |
495 | } | 602 | } |
603 | EXPORT_SYMBOL_GPL(iwl_remove_station); | ||
496 | 604 | ||
497 | /** | 605 | /** |
498 | * iwl_clear_stations_table - Clear the driver's station table | 606 | * iwl_clear_ucode_stations - clear ucode station table bits |
499 | * | 607 | * |
500 | * NOTE: This does not clear or otherwise alter the device's station table. | 608 | * This function clears all the bits in the driver indicating |
609 | * which stations are active in the ucode. Call when something | ||
610 | * other than explicit station management would cause this in | ||
611 | * the ucode, e.g. unassociated RXON. | ||
501 | */ | 612 | */ |
502 | void iwl_clear_stations_table(struct iwl_priv *priv) | 613 | void iwl_clear_ucode_stations(struct iwl_priv *priv) |
503 | { | 614 | { |
504 | unsigned long flags; | ||
505 | int i; | 615 | int i; |
616 | unsigned long flags_spin; | ||
617 | bool cleared = false; | ||
506 | 618 | ||
507 | spin_lock_irqsave(&priv->sta_lock, flags); | 619 | IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n"); |
508 | 620 | ||
509 | if (iwl_is_alive(priv) && | 621 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
510 | !test_bit(STATUS_EXIT_PENDING, &priv->status) && | 622 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
511 | iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) | 623 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { |
512 | IWL_ERR(priv, "Couldn't clear the station table\n"); | 624 | IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i); |
625 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
626 | cleared = true; | ||
627 | } | ||
628 | } | ||
629 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
630 | |||
631 | if (!cleared) | ||
632 | IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n"); | ||
633 | } | ||
634 | EXPORT_SYMBOL(iwl_clear_ucode_stations); | ||
635 | |||
636 | /** | ||
637 | * iwl_restore_stations() - Restore driver known stations to device | ||
638 | * | ||
639 | * All stations considered active by driver, but not present in ucode, is | ||
640 | * restored. | ||
641 | * | ||
642 | * Function sleeps. | ||
643 | */ | ||
644 | void iwl_restore_stations(struct iwl_priv *priv) | ||
645 | { | ||
646 | struct iwl_station_entry *station; | ||
647 | unsigned long flags_spin; | ||
648 | int i; | ||
649 | bool found = false; | ||
650 | int ret; | ||
513 | 651 | ||
514 | priv->num_stations = 0; | 652 | if (!iwl_is_ready(priv)) { |
515 | memset(priv->stations, 0, sizeof(priv->stations)); | 653 | IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n"); |
654 | return; | ||
655 | } | ||
516 | 656 | ||
517 | /* clean ucode key table bit map */ | 657 | IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); |
518 | priv->ucode_key_table = 0; | 658 | spin_lock_irqsave(&priv->sta_lock, flags_spin); |
659 | for (i = 0; i < priv->hw_params.max_stations; i++) { | ||
660 | if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && | ||
661 | !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { | ||
662 | IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", | ||
663 | priv->stations[i].sta.sta.addr); | ||
664 | priv->stations[i].sta.mode = 0; | ||
665 | priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; | ||
666 | found = true; | ||
667 | } | ||
668 | } | ||
519 | 669 | ||
520 | /* keep track of static keys */ | 670 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
521 | for (i = 0; i < WEP_KEYS_MAX ; i++) { | 671 | if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { |
522 | if (priv->wep_keys[i].key_size) | 672 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
523 | set_bit(i, &priv->ucode_key_table); | 673 | station = &priv->stations[i]; |
674 | ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC); | ||
675 | if (ret) { | ||
676 | IWL_ERR(priv, "Adding station %pM failed.\n", | ||
677 | station->sta.sta.addr); | ||
678 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
679 | priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
680 | priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
681 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
682 | } | ||
683 | /* | ||
684 | * Rate scaling has already been initialized, send | ||
685 | * current LQ command | ||
686 | */ | ||
687 | if (station->lq) | ||
688 | iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true); | ||
689 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
690 | priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
691 | } | ||
524 | } | 692 | } |
525 | 693 | ||
526 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 694 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); |
695 | if (!found) | ||
696 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n"); | ||
697 | else | ||
698 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... complete.\n"); | ||
527 | } | 699 | } |
528 | EXPORT_SYMBOL(iwl_clear_stations_table); | 700 | EXPORT_SYMBOL(iwl_restore_stations); |
529 | 701 | ||
530 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 702 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) |
531 | { | 703 | { |
@@ -539,7 +711,7 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | |||
539 | } | 711 | } |
540 | EXPORT_SYMBOL(iwl_get_free_ucode_key_index); | 712 | EXPORT_SYMBOL(iwl_get_free_ucode_key_index); |
541 | 713 | ||
542 | int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) | 714 | static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) |
543 | { | 715 | { |
544 | int i, not_empty = 0; | 716 | int i, not_empty = 0; |
545 | u8 buff[sizeof(struct iwl_wep_cmd) + | 717 | u8 buff[sizeof(struct iwl_wep_cmd) + |
@@ -549,9 +721,11 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) | |||
549 | struct iwl_host_cmd cmd = { | 721 | struct iwl_host_cmd cmd = { |
550 | .id = REPLY_WEPKEY, | 722 | .id = REPLY_WEPKEY, |
551 | .data = wep_cmd, | 723 | .data = wep_cmd, |
552 | .flags = CMD_ASYNC, | 724 | .flags = CMD_SYNC, |
553 | }; | 725 | }; |
554 | 726 | ||
727 | might_sleep(); | ||
728 | |||
555 | memset(wep_cmd, 0, cmd_size + | 729 | memset(wep_cmd, 0, cmd_size + |
556 | (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); | 730 | (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); |
557 | 731 | ||
@@ -581,33 +755,34 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty) | |||
581 | else | 755 | else |
582 | return 0; | 756 | return 0; |
583 | } | 757 | } |
584 | EXPORT_SYMBOL(iwl_send_static_wepkey_cmd); | 758 | |
759 | int iwl_restore_default_wep_keys(struct iwl_priv *priv) | ||
760 | { | ||
761 | WARN_ON(!mutex_is_locked(&priv->mutex)); | ||
762 | |||
763 | return iwl_send_static_wepkey_cmd(priv, 0); | ||
764 | } | ||
765 | EXPORT_SYMBOL(iwl_restore_default_wep_keys); | ||
585 | 766 | ||
586 | int iwl_remove_default_wep_key(struct iwl_priv *priv, | 767 | int iwl_remove_default_wep_key(struct iwl_priv *priv, |
587 | struct ieee80211_key_conf *keyconf) | 768 | struct ieee80211_key_conf *keyconf) |
588 | { | 769 | { |
589 | int ret; | 770 | int ret; |
590 | unsigned long flags; | ||
591 | 771 | ||
592 | spin_lock_irqsave(&priv->sta_lock, flags); | 772 | WARN_ON(!mutex_is_locked(&priv->mutex)); |
773 | |||
593 | IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", | 774 | IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", |
594 | keyconf->keyidx); | 775 | keyconf->keyidx); |
595 | 776 | ||
596 | if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table)) | ||
597 | IWL_ERR(priv, "index %d not used in uCode key table.\n", | ||
598 | keyconf->keyidx); | ||
599 | |||
600 | priv->default_wep_key--; | ||
601 | memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); | 777 | memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0])); |
602 | if (iwl_is_rfkill(priv)) { | 778 | if (iwl_is_rfkill(priv)) { |
603 | IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); | 779 | IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); |
604 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 780 | /* but keys in device are clear anyway so return success */ |
605 | return 0; | 781 | return 0; |
606 | } | 782 | } |
607 | ret = iwl_send_static_wepkey_cmd(priv, 1); | 783 | ret = iwl_send_static_wepkey_cmd(priv, 1); |
608 | IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", | 784 | IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", |
609 | keyconf->keyidx, ret); | 785 | keyconf->keyidx, ret); |
610 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
611 | 786 | ||
612 | return ret; | 787 | return ret; |
613 | } | 788 | } |
@@ -617,7 +792,8 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
617 | struct ieee80211_key_conf *keyconf) | 792 | struct ieee80211_key_conf *keyconf) |
618 | { | 793 | { |
619 | int ret; | 794 | int ret; |
620 | unsigned long flags; | 795 | |
796 | WARN_ON(!mutex_is_locked(&priv->mutex)); | ||
621 | 797 | ||
622 | if (keyconf->keylen != WEP_KEY_LEN_128 && | 798 | if (keyconf->keylen != WEP_KEY_LEN_128 && |
623 | keyconf->keylen != WEP_KEY_LEN_64) { | 799 | keyconf->keylen != WEP_KEY_LEN_64) { |
@@ -629,13 +805,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
629 | keyconf->hw_key_idx = HW_KEY_DEFAULT; | 805 | keyconf->hw_key_idx = HW_KEY_DEFAULT; |
630 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; | 806 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; |
631 | 807 | ||
632 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
633 | priv->default_wep_key++; | ||
634 | |||
635 | if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table)) | ||
636 | IWL_ERR(priv, "index %d already used in uCode key table.\n", | ||
637 | keyconf->keyidx); | ||
638 | |||
639 | priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; | 808 | priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; |
640 | memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key, | 809 | memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key, |
641 | keyconf->keylen); | 810 | keyconf->keylen); |
@@ -643,7 +812,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
643 | ret = iwl_send_static_wepkey_cmd(priv, 0); | 812 | ret = iwl_send_static_wepkey_cmd(priv, 0); |
644 | IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n", | 813 | IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n", |
645 | keyconf->keylen, keyconf->keyidx, ret); | 814 | keyconf->keylen, keyconf->keyidx, ret); |
646 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
647 | 815 | ||
648 | return ret; | 816 | return ret; |
649 | } | 817 | } |
@@ -798,18 +966,23 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | |||
798 | 966 | ||
799 | void iwl_update_tkip_key(struct iwl_priv *priv, | 967 | void iwl_update_tkip_key(struct iwl_priv *priv, |
800 | struct ieee80211_key_conf *keyconf, | 968 | struct ieee80211_key_conf *keyconf, |
801 | const u8 *addr, u32 iv32, u16 *phase1key) | 969 | struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) |
802 | { | 970 | { |
803 | u8 sta_id = IWL_INVALID_STATION; | 971 | u8 sta_id; |
804 | unsigned long flags; | 972 | unsigned long flags; |
805 | int i; | 973 | int i; |
806 | 974 | ||
807 | sta_id = iwl_find_station(priv, addr); | 975 | if (sta) { |
808 | if (sta_id == IWL_INVALID_STATION) { | 976 | sta_id = iwl_sta_id(sta); |
809 | IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n", | 977 | |
810 | addr); | 978 | if (sta_id == IWL_INVALID_STATION) { |
811 | return; | 979 | IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n", |
812 | } | 980 | sta->addr); |
981 | return; | ||
982 | } | ||
983 | } else | ||
984 | sta_id = priv->hw_params.bcast_sta_id; | ||
985 | |||
813 | 986 | ||
814 | if (iwl_scan_cancel(priv)) { | 987 | if (iwl_scan_cancel(priv)) { |
815 | /* cancel scan failed, just live w/ bad key and rely | 988 | /* cancel scan failed, just live w/ bad key and rely |
@@ -885,7 +1058,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
885 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 1058 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
886 | 1059 | ||
887 | if (iwl_is_rfkill(priv)) { | 1060 | if (iwl_is_rfkill(priv)) { |
888 | IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n"); | 1061 | IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n"); |
889 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1062 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
890 | return 0; | 1063 | return 0; |
891 | } | 1064 | } |
@@ -948,253 +1121,149 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv, | |||
948 | } | 1121 | } |
949 | #endif | 1122 | #endif |
950 | 1123 | ||
951 | int iwl_send_lq_cmd(struct iwl_priv *priv, | ||
952 | struct iwl_link_quality_cmd *lq, u8 flags) | ||
953 | { | ||
954 | struct iwl_host_cmd cmd = { | ||
955 | .id = REPLY_TX_LINK_QUALITY_CMD, | ||
956 | .len = sizeof(struct iwl_link_quality_cmd), | ||
957 | .flags = flags, | ||
958 | .data = lq, | ||
959 | }; | ||
960 | |||
961 | if ((lq->sta_id == 0xFF) && | ||
962 | (priv->iw_mode == NL80211_IFTYPE_ADHOC)) | ||
963 | return -EINVAL; | ||
964 | |||
965 | if (lq->sta_id == 0xFF) | ||
966 | lq->sta_id = IWL_AP_ID; | ||
967 | |||
968 | iwl_dump_lq_cmd(priv, lq); | ||
969 | |||
970 | if (iwl_is_associated(priv) && priv->assoc_station_added) | ||
971 | return iwl_send_cmd(priv, &cmd); | ||
972 | |||
973 | return 0; | ||
974 | } | ||
975 | EXPORT_SYMBOL(iwl_send_lq_cmd); | ||
976 | |||
977 | /** | 1124 | /** |
978 | * iwl_sta_init_lq - Initialize a station's hardware rate table | 1125 | * is_lq_table_valid() - Test one aspect of LQ cmd for validity |
979 | * | ||
980 | * The uCode's station table contains a table of fallback rates | ||
981 | * for automatic fallback during transmission. | ||
982 | * | ||
983 | * NOTE: This sets up a default set of values. These will be replaced later | ||
984 | * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of | ||
985 | * rc80211_simple. | ||
986 | * | 1126 | * |
987 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | 1127 | * It sometimes happens when a HT rate has been in use and we |
988 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | 1128 | * loose connectivity with AP then mac80211 will first tell us that the |
989 | * which requires station table entry to exist). | 1129 | * current channel is not HT anymore before removing the station. In such a |
1130 | * scenario the RXON flags will be updated to indicate we are not | ||
1131 | * communicating HT anymore, but the LQ command may still contain HT rates. | ||
1132 | * Test for this to prevent driver from sending LQ command between the time | ||
1133 | * RXON flags are updated and when LQ command is updated. | ||
990 | */ | 1134 | */ |
991 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap) | 1135 | static bool is_lq_table_valid(struct iwl_priv *priv, |
1136 | struct iwl_link_quality_cmd *lq) | ||
992 | { | 1137 | { |
993 | int i, r; | 1138 | int i; |
994 | struct iwl_link_quality_cmd link_cmd = { | 1139 | struct iwl_ht_config *ht_conf = &priv->current_ht_config; |
995 | .reserved1 = 0, | ||
996 | }; | ||
997 | u32 rate_flags; | ||
998 | 1140 | ||
999 | /* Set up the rate scaling to start at selected rate, fall back | 1141 | if (ht_conf->is_ht) |
1000 | * all the way down to 1M in IEEE order, and then spin on 1M */ | 1142 | return true; |
1001 | if (is_ap) | ||
1002 | r = IWL_RATE_54M_INDEX; | ||
1003 | else if (priv->band == IEEE80211_BAND_5GHZ) | ||
1004 | r = IWL_RATE_6M_INDEX; | ||
1005 | else | ||
1006 | r = IWL_RATE_1M_INDEX; | ||
1007 | 1143 | ||
1144 | IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n", | ||
1145 | priv->active_rxon.channel); | ||
1008 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | 1146 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { |
1009 | rate_flags = 0; | 1147 | if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) { |
1010 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | 1148 | IWL_DEBUG_INFO(priv, |
1011 | rate_flags |= RATE_MCS_CCK_MSK; | 1149 | "index %d of LQ expects HT channel\n", |
1012 | 1150 | i); | |
1013 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | 1151 | return false; |
1014 | RATE_MCS_ANT_POS; | 1152 | } |
1015 | |||
1016 | link_cmd.rs_table[i].rate_n_flags = | ||
1017 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
1018 | r = iwl_get_prev_ieee_rate(r); | ||
1019 | } | 1153 | } |
1020 | 1154 | return true; | |
1021 | link_cmd.general_params.single_stream_ant_msk = | ||
1022 | first_antenna(priv->hw_params.valid_tx_ant); | ||
1023 | link_cmd.general_params.dual_stream_ant_msk = 3; | ||
1024 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
1025 | link_cmd.agg_params.agg_time_limit = | ||
1026 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
1027 | |||
1028 | /* Update the rate scaling for control frame Tx to AP */ | ||
1029 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | ||
1030 | |||
1031 | iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, | ||
1032 | sizeof(link_cmd), &link_cmd, NULL); | ||
1033 | } | 1155 | } |
1034 | 1156 | ||
1035 | /** | 1157 | /** |
1036 | * iwl_rxon_add_station - add station into station table. | 1158 | * iwl_send_lq_cmd() - Send link quality command |
1159 | * @init: This command is sent as part of station initialization right | ||
1160 | * after station has been added. | ||
1037 | * | 1161 | * |
1038 | * there is only one AP station with id= IWL_AP_ID | 1162 | * The link quality command is sent as the last step of station creation. |
1039 | * NOTE: mutex must be held before calling this function | 1163 | * This is the special case in which init is set and we call a callback in |
1164 | * this case to clear the state indicating that station creation is in | ||
1165 | * progress. | ||
1040 | */ | 1166 | */ |
1041 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap) | 1167 | int iwl_send_lq_cmd(struct iwl_priv *priv, |
1168 | struct iwl_link_quality_cmd *lq, u8 flags, bool init) | ||
1042 | { | 1169 | { |
1043 | struct ieee80211_sta *sta; | 1170 | int ret = 0; |
1044 | struct ieee80211_sta_ht_cap ht_config; | 1171 | unsigned long flags_spin; |
1045 | struct ieee80211_sta_ht_cap *cur_ht_config = NULL; | ||
1046 | u8 sta_id; | ||
1047 | 1172 | ||
1048 | /* | 1173 | struct iwl_host_cmd cmd = { |
1049 | * Set HT capabilities. It is ok to set this struct even if not using | 1174 | .id = REPLY_TX_LINK_QUALITY_CMD, |
1050 | * HT config: the priv->current_ht_config.is_ht flag will just be false | 1175 | .len = sizeof(struct iwl_link_quality_cmd), |
1051 | */ | 1176 | .flags = flags, |
1052 | rcu_read_lock(); | 1177 | .data = lq, |
1053 | sta = ieee80211_find_sta(priv->vif, addr); | 1178 | }; |
1054 | if (sta) { | ||
1055 | memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); | ||
1056 | cur_ht_config = &ht_config; | ||
1057 | } | ||
1058 | rcu_read_unlock(); | ||
1059 | 1179 | ||
1060 | /* Add station to device's station table */ | 1180 | if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) |
1061 | sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config); | 1181 | return -EINVAL; |
1062 | 1182 | ||
1063 | /* Set up default rate scaling table in device's station table */ | 1183 | iwl_dump_lq_cmd(priv, lq); |
1064 | iwl_sta_init_lq(priv, addr, is_ap); | 1184 | BUG_ON(init && (cmd.flags & CMD_ASYNC)); |
1065 | 1185 | ||
1066 | return sta_id; | 1186 | if (is_lq_table_valid(priv, lq)) |
1187 | ret = iwl_send_cmd(priv, &cmd); | ||
1188 | else | ||
1189 | ret = -EINVAL; | ||
1190 | |||
1191 | if (cmd.flags & CMD_ASYNC) | ||
1192 | return ret; | ||
1193 | |||
1194 | if (init) { | ||
1195 | IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d\n", | ||
1196 | lq->sta_id); | ||
1197 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
1198 | priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
1199 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
1200 | } | ||
1201 | return ret; | ||
1067 | } | 1202 | } |
1068 | EXPORT_SYMBOL(iwl_rxon_add_station); | 1203 | EXPORT_SYMBOL(iwl_send_lq_cmd); |
1069 | 1204 | ||
1070 | /** | 1205 | /** |
1071 | * iwl_sta_init_bcast_lq - Initialize a bcast station's hardware rate table | 1206 | * iwl_alloc_bcast_station - add broadcast station into driver's station table. |
1072 | * | 1207 | * |
1073 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | 1208 | * This adds the broadcast station into the driver's station table |
1074 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | 1209 | * and marks it driver active, so that it will be restored to the |
1075 | * which requires station table entry to exist). | 1210 | * device at the next best time. |
1076 | */ | 1211 | */ |
1077 | static void iwl_sta_init_bcast_lq(struct iwl_priv *priv) | 1212 | int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq) |
1078 | { | 1213 | { |
1079 | int i, r; | 1214 | struct iwl_link_quality_cmd *link_cmd; |
1080 | struct iwl_link_quality_cmd link_cmd = { | 1215 | unsigned long flags; |
1081 | .reserved1 = 0, | 1216 | u8 sta_id; |
1082 | }; | ||
1083 | u32 rate_flags; | ||
1084 | |||
1085 | /* Set up the rate scaling to start at selected rate, fall back | ||
1086 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
1087 | if (priv->band == IEEE80211_BAND_5GHZ) | ||
1088 | r = IWL_RATE_6M_INDEX; | ||
1089 | else | ||
1090 | r = IWL_RATE_1M_INDEX; | ||
1091 | |||
1092 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
1093 | rate_flags = 0; | ||
1094 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
1095 | rate_flags |= RATE_MCS_CCK_MSK; | ||
1096 | 1217 | ||
1097 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | 1218 | spin_lock_irqsave(&priv->sta_lock, flags); |
1098 | RATE_MCS_ANT_POS; | 1219 | sta_id = iwl_prep_station(priv, iwl_bcast_addr, false, NULL); |
1220 | if (sta_id == IWL_INVALID_STATION) { | ||
1221 | IWL_ERR(priv, "Unable to prepare broadcast station\n"); | ||
1222 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1099 | 1223 | ||
1100 | link_cmd.rs_table[i].rate_n_flags = | 1224 | return -EINVAL; |
1101 | iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
1102 | r = iwl_get_prev_ieee_rate(r); | ||
1103 | } | 1225 | } |
1104 | 1226 | ||
1105 | link_cmd.general_params.single_stream_ant_msk = | 1227 | priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; |
1106 | first_antenna(priv->hw_params.valid_tx_ant); | 1228 | priv->stations[sta_id].used |= IWL_STA_BCAST; |
1107 | link_cmd.general_params.dual_stream_ant_msk = 3; | 1229 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1108 | link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; | ||
1109 | link_cmd.agg_params.agg_time_limit = | ||
1110 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
1111 | |||
1112 | /* Update the rate scaling for control frame Tx to AP */ | ||
1113 | link_cmd.sta_id = priv->hw_params.bcast_sta_id; | ||
1114 | |||
1115 | iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, | ||
1116 | sizeof(link_cmd), &link_cmd, NULL); | ||
1117 | } | ||
1118 | |||
1119 | 1230 | ||
1120 | /** | 1231 | if (init_lq) { |
1121 | * iwl_add_bcast_station - add broadcast station into station table. | 1232 | link_cmd = iwl_sta_alloc_lq(priv, sta_id); |
1122 | */ | 1233 | if (!link_cmd) { |
1123 | void iwl_add_bcast_station(struct iwl_priv *priv) | 1234 | IWL_ERR(priv, |
1124 | { | 1235 | "Unable to initialize rate scaling for bcast station.\n"); |
1125 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | 1236 | return -ENOMEM; |
1126 | iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); | 1237 | } |
1127 | 1238 | ||
1128 | /* Set up default rate scaling table in device's station table */ | 1239 | spin_lock_irqsave(&priv->sta_lock, flags); |
1129 | iwl_sta_init_bcast_lq(priv); | 1240 | priv->stations[sta_id].lq = link_cmd; |
1130 | } | 1241 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1131 | EXPORT_SYMBOL(iwl_add_bcast_station); | 1242 | } |
1132 | 1243 | ||
1133 | /** | 1244 | return 0; |
1134 | * iwl3945_add_bcast_station - add broadcast station into station table. | ||
1135 | */ | ||
1136 | void iwl3945_add_bcast_station(struct iwl_priv *priv) | ||
1137 | { | ||
1138 | IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n"); | ||
1139 | iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL); | ||
1140 | } | 1245 | } |
1141 | EXPORT_SYMBOL(iwl3945_add_bcast_station); | 1246 | EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station); |
1142 | 1247 | ||
1143 | /** | 1248 | void iwl_dealloc_bcast_station(struct iwl_priv *priv) |
1144 | * iwl_get_sta_id - Find station's index within station table | ||
1145 | * | ||
1146 | * If new IBSS station, create new entry in station table | ||
1147 | */ | ||
1148 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | ||
1149 | { | 1249 | { |
1150 | int sta_id; | 1250 | unsigned long flags; |
1151 | __le16 fc = hdr->frame_control; | 1251 | int i; |
1152 | |||
1153 | /* If this frame is broadcast or management, use broadcast station id */ | ||
1154 | if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) | ||
1155 | return priv->hw_params.bcast_sta_id; | ||
1156 | |||
1157 | switch (priv->iw_mode) { | ||
1158 | |||
1159 | /* If we are a client station in a BSS network, use the special | ||
1160 | * AP station entry (that's the only station we communicate with) */ | ||
1161 | case NL80211_IFTYPE_STATION: | ||
1162 | return IWL_AP_ID; | ||
1163 | |||
1164 | /* If we are an AP, then find the station, or use BCAST */ | ||
1165 | case NL80211_IFTYPE_AP: | ||
1166 | sta_id = iwl_find_station(priv, hdr->addr1); | ||
1167 | if (sta_id != IWL_INVALID_STATION) | ||
1168 | return sta_id; | ||
1169 | return priv->hw_params.bcast_sta_id; | ||
1170 | |||
1171 | /* If this frame is going out to an IBSS network, find the station, | ||
1172 | * or create a new station table entry */ | ||
1173 | case NL80211_IFTYPE_ADHOC: | ||
1174 | sta_id = iwl_find_station(priv, hdr->addr1); | ||
1175 | if (sta_id != IWL_INVALID_STATION) | ||
1176 | return sta_id; | ||
1177 | |||
1178 | /* Create new station table entry */ | ||
1179 | sta_id = iwl_add_station(priv, hdr->addr1, false, | ||
1180 | CMD_ASYNC, NULL); | ||
1181 | |||
1182 | if (sta_id != IWL_INVALID_STATION) | ||
1183 | return sta_id; | ||
1184 | |||
1185 | IWL_DEBUG_DROP(priv, "Station %pM not in station map. " | ||
1186 | "Defaulting to broadcast...\n", | ||
1187 | hdr->addr1); | ||
1188 | iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); | ||
1189 | return priv->hw_params.bcast_sta_id; | ||
1190 | 1252 | ||
1191 | default: | 1253 | spin_lock_irqsave(&priv->sta_lock, flags); |
1192 | IWL_WARN(priv, "Unknown mode of operation: %d\n", | 1254 | for (i = 0; i < priv->hw_params.max_stations; i++) { |
1193 | priv->iw_mode); | 1255 | if (!(priv->stations[i].used & IWL_STA_BCAST)) |
1194 | return priv->hw_params.bcast_sta_id; | 1256 | continue; |
1257 | |||
1258 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
1259 | priv->num_stations--; | ||
1260 | BUG_ON(priv->num_stations < 0); | ||
1261 | kfree(priv->stations[i].lq); | ||
1262 | priv->stations[i].lq = NULL; | ||
1195 | } | 1263 | } |
1264 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1196 | } | 1265 | } |
1197 | EXPORT_SYMBOL(iwl_get_sta_id); | 1266 | EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station); |
1198 | 1267 | ||
1199 | /** | 1268 | /** |
1200 | * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table | 1269 | * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table |
@@ -1214,13 +1283,13 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) | |||
1214 | } | 1283 | } |
1215 | EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); | 1284 | EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); |
1216 | 1285 | ||
1217 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, | 1286 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, |
1218 | const u8 *addr, int tid, u16 ssn) | 1287 | int tid, u16 ssn) |
1219 | { | 1288 | { |
1220 | unsigned long flags; | 1289 | unsigned long flags; |
1221 | int sta_id; | 1290 | int sta_id; |
1222 | 1291 | ||
1223 | sta_id = iwl_find_station(priv, addr); | 1292 | sta_id = iwl_sta_id(sta); |
1224 | if (sta_id == IWL_INVALID_STATION) | 1293 | if (sta_id == IWL_INVALID_STATION) |
1225 | return -ENXIO; | 1294 | return -ENXIO; |
1226 | 1295 | ||
@@ -1233,16 +1302,17 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, | |||
1233 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 1302 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
1234 | 1303 | ||
1235 | return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, | 1304 | return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, |
1236 | CMD_ASYNC); | 1305 | CMD_ASYNC); |
1237 | } | 1306 | } |
1238 | EXPORT_SYMBOL(iwl_sta_rx_agg_start); | 1307 | EXPORT_SYMBOL(iwl_sta_rx_agg_start); |
1239 | 1308 | ||
1240 | int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) | 1309 | int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, |
1310 | int tid) | ||
1241 | { | 1311 | { |
1242 | unsigned long flags; | 1312 | unsigned long flags; |
1243 | int sta_id; | 1313 | int sta_id; |
1244 | 1314 | ||
1245 | sta_id = iwl_find_station(priv, addr); | 1315 | sta_id = iwl_sta_id(sta); |
1246 | if (sta_id == IWL_INVALID_STATION) { | 1316 | if (sta_id == IWL_INVALID_STATION) { |
1247 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | 1317 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); |
1248 | return -ENXIO; | 1318 | return -ENXIO; |
@@ -1291,3 +1361,22 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) | |||
1291 | 1361 | ||
1292 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | 1362 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); |
1293 | } | 1363 | } |
1364 | EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count); | ||
1365 | |||
1366 | int iwl_mac_sta_remove(struct ieee80211_hw *hw, | ||
1367 | struct ieee80211_vif *vif, | ||
1368 | struct ieee80211_sta *sta) | ||
1369 | { | ||
1370 | struct iwl_priv *priv = hw->priv; | ||
1371 | struct iwl_station_priv_common *sta_common = (void *)sta->drv_priv; | ||
1372 | int ret; | ||
1373 | |||
1374 | IWL_DEBUG_INFO(priv, "received request to remove station %pM\n", | ||
1375 | sta->addr); | ||
1376 | ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr); | ||
1377 | if (ret) | ||
1378 | IWL_ERR(priv, "Error removing station %pM\n", | ||
1379 | sta->addr); | ||
1380 | return ret; | ||
1381 | } | ||
1382 | EXPORT_SYMBOL(iwl_mac_sta_remove); | ||