diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/dvm/sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/dvm/sta.c | 1479 |
1 files changed, 1479 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c new file mode 100644 index 000000000000..c6b343fdf5f9 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -0,0 +1,1479 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved. | ||
4 | * | ||
5 | * Portions of this file are derived from the ipw3945 project, as well | ||
6 | * as portions of the ieee80211 subsystem header files. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of version 2 of the GNU General Public License as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution in the | ||
22 | * file called LICENSE. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | * | ||
28 | *****************************************************************************/ | ||
29 | #include <linux/etherdevice.h> | ||
30 | #include <net/mac80211.h> | ||
31 | #include "iwl-trans.h" | ||
32 | #include "dev.h" | ||
33 | #include "agn.h" | ||
34 | |||
35 | const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
36 | |||
37 | static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) | ||
38 | { | ||
39 | lockdep_assert_held(&priv->sta_lock); | ||
40 | |||
41 | if (sta_id >= IWLAGN_STATION_COUNT) { | ||
42 | IWL_ERR(priv, "invalid sta_id %u", sta_id); | ||
43 | return -EINVAL; | ||
44 | } | ||
45 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) | ||
46 | IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u " | ||
47 | "addr %pM\n", | ||
48 | sta_id, priv->stations[sta_id].sta.sta.addr); | ||
49 | |||
50 | if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) { | ||
51 | IWL_DEBUG_ASSOC(priv, | ||
52 | "STA id %u addr %pM already present in uCode " | ||
53 | "(according to driver)\n", | ||
54 | sta_id, priv->stations[sta_id].sta.sta.addr); | ||
55 | } else { | ||
56 | priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; | ||
57 | IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n", | ||
58 | sta_id, priv->stations[sta_id].sta.sta.addr); | ||
59 | } | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int iwl_process_add_sta_resp(struct iwl_priv *priv, | ||
64 | struct iwl_addsta_cmd *addsta, | ||
65 | struct iwl_rx_packet *pkt) | ||
66 | { | ||
67 | struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; | ||
68 | u8 sta_id = addsta->sta.sta_id; | ||
69 | int ret = -EIO; | ||
70 | |||
71 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
72 | IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", | ||
73 | pkt->hdr.flags); | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | ||
78 | sta_id); | ||
79 | |||
80 | spin_lock(&priv->sta_lock); | ||
81 | |||
82 | switch (add_sta_resp->status) { | ||
83 | case ADD_STA_SUCCESS_MSK: | ||
84 | IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); | ||
85 | ret = iwl_sta_ucode_activate(priv, sta_id); | ||
86 | break; | ||
87 | case ADD_STA_NO_ROOM_IN_TABLE: | ||
88 | IWL_ERR(priv, "Adding station %d failed, no room in table.\n", | ||
89 | sta_id); | ||
90 | break; | ||
91 | case ADD_STA_NO_BLOCK_ACK_RESOURCE: | ||
92 | IWL_ERR(priv, "Adding station %d failed, no block ack " | ||
93 | "resource.\n", sta_id); | ||
94 | break; | ||
95 | case ADD_STA_MODIFY_NON_EXIST_STA: | ||
96 | IWL_ERR(priv, "Attempting to modify non-existing station %d\n", | ||
97 | sta_id); | ||
98 | break; | ||
99 | default: | ||
100 | IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", | ||
101 | add_sta_resp->status); | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", | ||
106 | priv->stations[sta_id].sta.mode == | ||
107 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | ||
108 | sta_id, priv->stations[sta_id].sta.sta.addr); | ||
109 | |||
110 | /* | ||
111 | * XXX: The MAC address in the command buffer is often changed from | ||
112 | * the original sent to the device. That is, the MAC address | ||
113 | * written to the command buffer often is not the same MAC address | ||
114 | * read from the command buffer when the command returns. This | ||
115 | * issue has not yet been resolved and this debugging is left to | ||
116 | * observe the problem. | ||
117 | */ | ||
118 | IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", | ||
119 | priv->stations[sta_id].sta.mode == | ||
120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | ||
121 | addsta->sta.addr); | ||
122 | spin_unlock(&priv->sta_lock); | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | ||
128 | struct iwl_device_cmd *cmd) | ||
129 | { | ||
130 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
131 | struct iwl_addsta_cmd *addsta = | ||
132 | (struct iwl_addsta_cmd *) cmd->payload; | ||
133 | |||
134 | return iwl_process_add_sta_resp(priv, addsta, pkt); | ||
135 | } | ||
136 | |||
137 | int iwl_send_add_sta(struct iwl_priv *priv, | ||
138 | struct iwl_addsta_cmd *sta, u8 flags) | ||
139 | { | ||
140 | int ret = 0; | ||
141 | struct iwl_host_cmd cmd = { | ||
142 | .id = REPLY_ADD_STA, | ||
143 | .flags = flags, | ||
144 | .data = { sta, }, | ||
145 | .len = { sizeof(*sta), }, | ||
146 | }; | ||
147 | u8 sta_id __maybe_unused = sta->sta.sta_id; | ||
148 | |||
149 | IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", | ||
150 | sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); | ||
151 | |||
152 | if (!(flags & CMD_ASYNC)) { | ||
153 | cmd.flags |= CMD_WANT_SKB; | ||
154 | might_sleep(); | ||
155 | } | ||
156 | |||
157 | ret = iwl_dvm_send_cmd(priv, &cmd); | ||
158 | |||
159 | if (ret || (flags & CMD_ASYNC)) | ||
160 | return ret; | ||
161 | /*else the command was successfully sent in SYNC mode, need to free | ||
162 | * the reply page */ | ||
163 | |||
164 | iwl_free_resp(&cmd); | ||
165 | |||
166 | if (cmd.handler_status) | ||
167 | IWL_ERR(priv, "%s - error in the CMD response %d", __func__, | ||
168 | cmd.handler_status); | ||
169 | |||
170 | return cmd.handler_status; | ||
171 | } | ||
172 | |||
173 | bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, | ||
174 | struct iwl_rxon_context *ctx, | ||
175 | struct ieee80211_sta_ht_cap *ht_cap) | ||
176 | { | ||
177 | if (!ctx->ht.enabled || !ctx->ht.is_40mhz) | ||
178 | return false; | ||
179 | |||
180 | /* | ||
181 | * We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
182 | * the bit will not set if it is pure 40MHz case | ||
183 | */ | ||
184 | if (ht_cap && !ht_cap->ht_supported) | ||
185 | return false; | ||
186 | |||
187 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
188 | if (priv->disable_ht40) | ||
189 | return false; | ||
190 | #endif | ||
191 | |||
192 | return true; | ||
193 | } | ||
194 | |||
195 | static void iwl_sta_calc_ht_flags(struct iwl_priv *priv, | ||
196 | struct ieee80211_sta *sta, | ||
197 | struct iwl_rxon_context *ctx, | ||
198 | __le32 *flags, __le32 *mask) | ||
199 | { | ||
200 | struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; | ||
201 | u8 mimo_ps_mode; | ||
202 | |||
203 | *mask = STA_FLG_RTS_MIMO_PROT_MSK | | ||
204 | STA_FLG_MIMO_DIS_MSK | | ||
205 | STA_FLG_HT40_EN_MSK | | ||
206 | STA_FLG_MAX_AGG_SIZE_MSK | | ||
207 | STA_FLG_AGG_MPDU_DENSITY_MSK; | ||
208 | *flags = 0; | ||
209 | |||
210 | if (!sta || !sta_ht_inf->ht_supported) | ||
211 | return; | ||
212 | |||
213 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; | ||
214 | |||
215 | IWL_DEBUG_INFO(priv, "STA %pM SM PS mode: %s\n", | ||
216 | sta->addr, | ||
217 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? | ||
218 | "static" : | ||
219 | (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? | ||
220 | "dynamic" : "disabled"); | ||
221 | |||
222 | switch (mimo_ps_mode) { | ||
223 | case WLAN_HT_CAP_SM_PS_STATIC: | ||
224 | *flags |= STA_FLG_MIMO_DIS_MSK; | ||
225 | break; | ||
226 | case WLAN_HT_CAP_SM_PS_DYNAMIC: | ||
227 | *flags |= STA_FLG_RTS_MIMO_PROT_MSK; | ||
228 | break; | ||
229 | case WLAN_HT_CAP_SM_PS_DISABLED: | ||
230 | break; | ||
231 | default: | ||
232 | IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode); | ||
233 | break; | ||
234 | } | ||
235 | |||
236 | *flags |= cpu_to_le32( | ||
237 | (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); | ||
238 | |||
239 | *flags |= cpu_to_le32( | ||
240 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | ||
241 | |||
242 | if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) | ||
243 | *flags |= STA_FLG_HT40_EN_MSK; | ||
244 | } | ||
245 | |||
246 | int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||
247 | struct ieee80211_sta *sta) | ||
248 | { | ||
249 | u8 sta_id = iwl_sta_id(sta); | ||
250 | __le32 flags, mask; | ||
251 | struct iwl_addsta_cmd cmd; | ||
252 | |||
253 | if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) | ||
254 | return -EINVAL; | ||
255 | |||
256 | iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask); | ||
257 | |||
258 | spin_lock_bh(&priv->sta_lock); | ||
259 | priv->stations[sta_id].sta.station_flags &= ~mask; | ||
260 | priv->stations[sta_id].sta.station_flags |= flags; | ||
261 | spin_unlock_bh(&priv->sta_lock); | ||
262 | |||
263 | memset(&cmd, 0, sizeof(cmd)); | ||
264 | cmd.mode = STA_CONTROL_MODIFY_MSK; | ||
265 | cmd.station_flags_msk = mask; | ||
266 | cmd.station_flags = flags; | ||
267 | cmd.sta.sta_id = sta_id; | ||
268 | |||
269 | return iwl_send_add_sta(priv, &cmd, CMD_SYNC); | ||
270 | } | ||
271 | |||
272 | static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||
273 | struct ieee80211_sta *sta, | ||
274 | struct iwl_rxon_context *ctx) | ||
275 | { | ||
276 | __le32 flags, mask; | ||
277 | |||
278 | iwl_sta_calc_ht_flags(priv, sta, ctx, &flags, &mask); | ||
279 | |||
280 | lockdep_assert_held(&priv->sta_lock); | ||
281 | priv->stations[index].sta.station_flags &= ~mask; | ||
282 | priv->stations[index].sta.station_flags |= flags; | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * iwl_prep_station - Prepare station information for addition | ||
287 | * | ||
288 | * should be called with sta_lock held | ||
289 | */ | ||
290 | u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||
291 | const u8 *addr, bool is_ap, struct ieee80211_sta *sta) | ||
292 | { | ||
293 | struct iwl_station_entry *station; | ||
294 | int i; | ||
295 | u8 sta_id = IWL_INVALID_STATION; | ||
296 | |||
297 | if (is_ap) | ||
298 | sta_id = ctx->ap_sta_id; | ||
299 | else if (is_broadcast_ether_addr(addr)) | ||
300 | sta_id = ctx->bcast_sta_id; | ||
301 | else | ||
302 | for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) { | ||
303 | if (ether_addr_equal(priv->stations[i].sta.sta.addr, | ||
304 | addr)) { | ||
305 | sta_id = i; | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | if (!priv->stations[i].used && | ||
310 | sta_id == IWL_INVALID_STATION) | ||
311 | sta_id = i; | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * These two conditions have the same outcome, but keep them | ||
316 | * separate | ||
317 | */ | ||
318 | if (unlikely(sta_id == IWL_INVALID_STATION)) | ||
319 | return sta_id; | ||
320 | |||
321 | /* | ||
322 | * uCode is not able to deal with multiple requests to add a | ||
323 | * station. Keep track if one is in progress so that we do not send | ||
324 | * another. | ||
325 | */ | ||
326 | if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { | ||
327 | IWL_DEBUG_INFO(priv, "STA %d already in process of being " | ||
328 | "added.\n", sta_id); | ||
329 | return sta_id; | ||
330 | } | ||
331 | |||
332 | if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && | ||
333 | (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) && | ||
334 | ether_addr_equal(priv->stations[sta_id].sta.sta.addr, addr)) { | ||
335 | IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not " | ||
336 | "adding again.\n", sta_id, addr); | ||
337 | return sta_id; | ||
338 | } | ||
339 | |||
340 | station = &priv->stations[sta_id]; | ||
341 | station->used = IWL_STA_DRIVER_ACTIVE; | ||
342 | IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", | ||
343 | sta_id, addr); | ||
344 | priv->num_stations++; | ||
345 | |||
346 | /* Set up the REPLY_ADD_STA command to send to device */ | ||
347 | memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); | ||
348 | memcpy(station->sta.sta.addr, addr, ETH_ALEN); | ||
349 | station->sta.mode = 0; | ||
350 | station->sta.sta.sta_id = sta_id; | ||
351 | station->sta.station_flags = ctx->station_flags; | ||
352 | station->ctxid = ctx->ctxid; | ||
353 | |||
354 | if (sta) { | ||
355 | struct iwl_station_priv *sta_priv; | ||
356 | |||
357 | sta_priv = (void *)sta->drv_priv; | ||
358 | sta_priv->ctx = ctx; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * OK to call unconditionally, since local stations (IBSS BSSID | ||
363 | * STA and broadcast STA) pass in a NULL sta, and mac80211 | ||
364 | * doesn't allow HT IBSS. | ||
365 | */ | ||
366 | iwl_set_ht_add_station(priv, sta_id, sta, ctx); | ||
367 | |||
368 | return sta_id; | ||
369 | |||
370 | } | ||
371 | |||
372 | #define STA_WAIT_TIMEOUT (HZ/2) | ||
373 | |||
374 | /** | ||
375 | * iwl_add_station_common - | ||
376 | */ | ||
377 | int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||
378 | const u8 *addr, bool is_ap, | ||
379 | struct ieee80211_sta *sta, u8 *sta_id_r) | ||
380 | { | ||
381 | int ret = 0; | ||
382 | u8 sta_id; | ||
383 | struct iwl_addsta_cmd sta_cmd; | ||
384 | |||
385 | *sta_id_r = 0; | ||
386 | spin_lock_bh(&priv->sta_lock); | ||
387 | sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta); | ||
388 | if (sta_id == IWL_INVALID_STATION) { | ||
389 | IWL_ERR(priv, "Unable to prepare station %pM for addition\n", | ||
390 | addr); | ||
391 | spin_unlock_bh(&priv->sta_lock); | ||
392 | return -EINVAL; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * uCode is not able to deal with multiple requests to add a | ||
397 | * station. Keep track if one is in progress so that we do not send | ||
398 | * another. | ||
399 | */ | ||
400 | if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { | ||
401 | IWL_DEBUG_INFO(priv, "STA %d already in process of being " | ||
402 | "added.\n", sta_id); | ||
403 | spin_unlock_bh(&priv->sta_lock); | ||
404 | return -EEXIST; | ||
405 | } | ||
406 | |||
407 | if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && | ||
408 | (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { | ||
409 | IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not " | ||
410 | "adding again.\n", sta_id, addr); | ||
411 | spin_unlock_bh(&priv->sta_lock); | ||
412 | return -EEXIST; | ||
413 | } | ||
414 | |||
415 | priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS; | ||
416 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, | ||
417 | sizeof(struct iwl_addsta_cmd)); | ||
418 | spin_unlock_bh(&priv->sta_lock); | ||
419 | |||
420 | /* Add station to device's station table */ | ||
421 | ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
422 | if (ret) { | ||
423 | spin_lock_bh(&priv->sta_lock); | ||
424 | IWL_ERR(priv, "Adding station %pM failed.\n", | ||
425 | priv->stations[sta_id].sta.sta.addr); | ||
426 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
427 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
428 | spin_unlock_bh(&priv->sta_lock); | ||
429 | } | ||
430 | *sta_id_r = sta_id; | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * iwl_sta_ucode_deactivate - deactivate ucode status for a station | ||
436 | */ | ||
437 | static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) | ||
438 | { | ||
439 | lockdep_assert_held(&priv->sta_lock); | ||
440 | |||
441 | /* Ucode must be active and driver must be non active */ | ||
442 | if ((priv->stations[sta_id].used & | ||
443 | (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != | ||
444 | IWL_STA_UCODE_ACTIVE) | ||
445 | IWL_ERR(priv, "removed non active STA %u\n", sta_id); | ||
446 | |||
447 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; | ||
448 | |||
449 | memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); | ||
450 | IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id); | ||
451 | } | ||
452 | |||
453 | static int iwl_send_remove_station(struct iwl_priv *priv, | ||
454 | const u8 *addr, int sta_id, | ||
455 | bool temporary) | ||
456 | { | ||
457 | struct iwl_rx_packet *pkt; | ||
458 | int ret; | ||
459 | struct iwl_rem_sta_cmd rm_sta_cmd; | ||
460 | |||
461 | struct iwl_host_cmd cmd = { | ||
462 | .id = REPLY_REMOVE_STA, | ||
463 | .len = { sizeof(struct iwl_rem_sta_cmd), }, | ||
464 | .flags = CMD_SYNC, | ||
465 | .data = { &rm_sta_cmd, }, | ||
466 | }; | ||
467 | |||
468 | memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); | ||
469 | rm_sta_cmd.num_sta = 1; | ||
470 | memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN); | ||
471 | |||
472 | cmd.flags |= CMD_WANT_SKB; | ||
473 | |||
474 | ret = iwl_dvm_send_cmd(priv, &cmd); | ||
475 | |||
476 | if (ret) | ||
477 | return ret; | ||
478 | |||
479 | pkt = cmd.resp_pkt; | ||
480 | if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
481 | IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", | ||
482 | pkt->hdr.flags); | ||
483 | ret = -EIO; | ||
484 | } | ||
485 | |||
486 | if (!ret) { | ||
487 | struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data; | ||
488 | switch (rem_sta_resp->status) { | ||
489 | case REM_STA_SUCCESS_MSK: | ||
490 | if (!temporary) { | ||
491 | spin_lock_bh(&priv->sta_lock); | ||
492 | iwl_sta_ucode_deactivate(priv, sta_id); | ||
493 | spin_unlock_bh(&priv->sta_lock); | ||
494 | } | ||
495 | IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); | ||
496 | break; | ||
497 | default: | ||
498 | ret = -EIO; | ||
499 | IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | iwl_free_resp(&cmd); | ||
504 | |||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * iwl_remove_station - Remove driver's knowledge of station. | ||
510 | */ | ||
511 | int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, | ||
512 | const u8 *addr) | ||
513 | { | ||
514 | u8 tid; | ||
515 | |||
516 | if (!iwl_is_ready(priv)) { | ||
517 | IWL_DEBUG_INFO(priv, | ||
518 | "Unable to remove station %pM, device not ready.\n", | ||
519 | addr); | ||
520 | /* | ||
521 | * It is typical for stations to be removed when we are | ||
522 | * going down. Return success since device will be down | ||
523 | * soon anyway | ||
524 | */ | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", | ||
529 | sta_id, addr); | ||
530 | |||
531 | if (WARN_ON(sta_id == IWL_INVALID_STATION)) | ||
532 | return -EINVAL; | ||
533 | |||
534 | spin_lock_bh(&priv->sta_lock); | ||
535 | |||
536 | if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { | ||
537 | IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n", | ||
538 | addr); | ||
539 | goto out_err; | ||
540 | } | ||
541 | |||
542 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { | ||
543 | IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n", | ||
544 | addr); | ||
545 | goto out_err; | ||
546 | } | ||
547 | |||
548 | if (priv->stations[sta_id].used & IWL_STA_LOCAL) { | ||
549 | kfree(priv->stations[sta_id].lq); | ||
550 | priv->stations[sta_id].lq = NULL; | ||
551 | } | ||
552 | |||
553 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) | ||
554 | memset(&priv->tid_data[sta_id][tid], 0, | ||
555 | sizeof(priv->tid_data[sta_id][tid])); | ||
556 | |||
557 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
558 | |||
559 | priv->num_stations--; | ||
560 | |||
561 | if (WARN_ON(priv->num_stations < 0)) | ||
562 | priv->num_stations = 0; | ||
563 | |||
564 | spin_unlock_bh(&priv->sta_lock); | ||
565 | |||
566 | return iwl_send_remove_station(priv, addr, sta_id, false); | ||
567 | out_err: | ||
568 | spin_unlock_bh(&priv->sta_lock); | ||
569 | return -EINVAL; | ||
570 | } | ||
571 | |||
572 | void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id, | ||
573 | const u8 *addr) | ||
574 | { | ||
575 | u8 tid; | ||
576 | |||
577 | if (!iwl_is_ready(priv)) { | ||
578 | IWL_DEBUG_INFO(priv, | ||
579 | "Unable to remove station %pM, device not ready.\n", | ||
580 | addr); | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id); | ||
585 | |||
586 | if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) | ||
587 | return; | ||
588 | |||
589 | spin_lock_bh(&priv->sta_lock); | ||
590 | |||
591 | WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)); | ||
592 | |||
593 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) | ||
594 | memset(&priv->tid_data[sta_id][tid], 0, | ||
595 | sizeof(priv->tid_data[sta_id][tid])); | ||
596 | |||
597 | priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; | ||
598 | |||
599 | priv->num_stations--; | ||
600 | |||
601 | if (WARN_ON_ONCE(priv->num_stations < 0)) | ||
602 | priv->num_stations = 0; | ||
603 | |||
604 | spin_unlock_bh(&priv->sta_lock); | ||
605 | } | ||
606 | |||
607 | static void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||
608 | u8 sta_id, struct iwl_link_quality_cmd *link_cmd) | ||
609 | { | ||
610 | int i, r; | ||
611 | u32 rate_flags = 0; | ||
612 | __le32 rate_n_flags; | ||
613 | |||
614 | lockdep_assert_held(&priv->mutex); | ||
615 | |||
616 | memset(link_cmd, 0, sizeof(*link_cmd)); | ||
617 | |||
618 | /* Set up the rate scaling to start at selected rate, fall back | ||
619 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
620 | if (priv->band == IEEE80211_BAND_5GHZ) | ||
621 | r = IWL_RATE_6M_INDEX; | ||
622 | else if (ctx && ctx->vif && ctx->vif->p2p) | ||
623 | r = IWL_RATE_6M_INDEX; | ||
624 | else | ||
625 | r = IWL_RATE_1M_INDEX; | ||
626 | |||
627 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
628 | rate_flags |= RATE_MCS_CCK_MSK; | ||
629 | |||
630 | rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << | ||
631 | RATE_MCS_ANT_POS; | ||
632 | rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
633 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) | ||
634 | link_cmd->rs_table[i].rate_n_flags = rate_n_flags; | ||
635 | |||
636 | link_cmd->general_params.single_stream_ant_msk = | ||
637 | first_antenna(priv->hw_params.valid_tx_ant); | ||
638 | |||
639 | link_cmd->general_params.dual_stream_ant_msk = | ||
640 | priv->hw_params.valid_tx_ant & | ||
641 | ~first_antenna(priv->hw_params.valid_tx_ant); | ||
642 | if (!link_cmd->general_params.dual_stream_ant_msk) { | ||
643 | link_cmd->general_params.dual_stream_ant_msk = ANT_AB; | ||
644 | } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { | ||
645 | link_cmd->general_params.dual_stream_ant_msk = | ||
646 | priv->hw_params.valid_tx_ant; | ||
647 | } | ||
648 | |||
649 | link_cmd->agg_params.agg_dis_start_th = | ||
650 | LINK_QUAL_AGG_DISABLE_START_DEF; | ||
651 | link_cmd->agg_params.agg_time_limit = | ||
652 | cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); | ||
653 | |||
654 | link_cmd->sta_id = sta_id; | ||
655 | } | ||
656 | |||
657 | /** | ||
658 | * iwl_clear_ucode_stations - clear ucode station table bits | ||
659 | * | ||
660 | * This function clears all the bits in the driver indicating | ||
661 | * which stations are active in the ucode. Call when something | ||
662 | * other than explicit station management would cause this in | ||
663 | * the ucode, e.g. unassociated RXON. | ||
664 | */ | ||
665 | void iwl_clear_ucode_stations(struct iwl_priv *priv, | ||
666 | struct iwl_rxon_context *ctx) | ||
667 | { | ||
668 | int i; | ||
669 | bool cleared = false; | ||
670 | |||
671 | IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n"); | ||
672 | |||
673 | spin_lock_bh(&priv->sta_lock); | ||
674 | for (i = 0; i < IWLAGN_STATION_COUNT; i++) { | ||
675 | if (ctx && ctx->ctxid != priv->stations[i].ctxid) | ||
676 | continue; | ||
677 | |||
678 | if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { | ||
679 | IWL_DEBUG_INFO(priv, | ||
680 | "Clearing ucode active for station %d\n", i); | ||
681 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
682 | cleared = true; | ||
683 | } | ||
684 | } | ||
685 | spin_unlock_bh(&priv->sta_lock); | ||
686 | |||
687 | if (!cleared) | ||
688 | IWL_DEBUG_INFO(priv, | ||
689 | "No active stations found to be cleared\n"); | ||
690 | } | ||
691 | |||
692 | /** | ||
693 | * iwl_restore_stations() - Restore driver known stations to device | ||
694 | * | ||
695 | * All stations considered active by driver, but not present in ucode, is | ||
696 | * restored. | ||
697 | * | ||
698 | * Function sleeps. | ||
699 | */ | ||
700 | void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) | ||
701 | { | ||
702 | struct iwl_addsta_cmd sta_cmd; | ||
703 | struct iwl_link_quality_cmd lq; | ||
704 | int i; | ||
705 | bool found = false; | ||
706 | int ret; | ||
707 | bool send_lq; | ||
708 | |||
709 | if (!iwl_is_ready(priv)) { | ||
710 | IWL_DEBUG_INFO(priv, | ||
711 | "Not ready yet, not restoring any stations.\n"); | ||
712 | return; | ||
713 | } | ||
714 | |||
715 | IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); | ||
716 | spin_lock_bh(&priv->sta_lock); | ||
717 | for (i = 0; i < IWLAGN_STATION_COUNT; i++) { | ||
718 | if (ctx->ctxid != priv->stations[i].ctxid) | ||
719 | continue; | ||
720 | if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && | ||
721 | !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { | ||
722 | IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", | ||
723 | priv->stations[i].sta.sta.addr); | ||
724 | priv->stations[i].sta.mode = 0; | ||
725 | priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; | ||
726 | found = true; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | for (i = 0; i < IWLAGN_STATION_COUNT; i++) { | ||
731 | if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { | ||
732 | memcpy(&sta_cmd, &priv->stations[i].sta, | ||
733 | sizeof(struct iwl_addsta_cmd)); | ||
734 | send_lq = false; | ||
735 | if (priv->stations[i].lq) { | ||
736 | if (priv->wowlan) | ||
737 | iwl_sta_fill_lq(priv, ctx, i, &lq); | ||
738 | else | ||
739 | memcpy(&lq, priv->stations[i].lq, | ||
740 | sizeof(struct iwl_link_quality_cmd)); | ||
741 | send_lq = true; | ||
742 | } | ||
743 | spin_unlock_bh(&priv->sta_lock); | ||
744 | ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
745 | if (ret) { | ||
746 | spin_lock_bh(&priv->sta_lock); | ||
747 | IWL_ERR(priv, "Adding station %pM failed.\n", | ||
748 | priv->stations[i].sta.sta.addr); | ||
749 | priv->stations[i].used &= | ||
750 | ~IWL_STA_DRIVER_ACTIVE; | ||
751 | priv->stations[i].used &= | ||
752 | ~IWL_STA_UCODE_INPROGRESS; | ||
753 | continue; | ||
754 | } | ||
755 | /* | ||
756 | * Rate scaling has already been initialized, send | ||
757 | * current LQ command | ||
758 | */ | ||
759 | if (send_lq) | ||
760 | iwl_send_lq_cmd(priv, ctx, &lq, | ||
761 | CMD_SYNC, true); | ||
762 | spin_lock_bh(&priv->sta_lock); | ||
763 | priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | spin_unlock_bh(&priv->sta_lock); | ||
768 | if (!found) | ||
769 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... " | ||
770 | "no stations to be restored.\n"); | ||
771 | else | ||
772 | IWL_DEBUG_INFO(priv, "Restoring all known stations .... " | ||
773 | "complete.\n"); | ||
774 | } | ||
775 | |||
776 | int iwl_get_free_ucode_key_offset(struct iwl_priv *priv) | ||
777 | { | ||
778 | int i; | ||
779 | |||
780 | for (i = 0; i < priv->sta_key_max_num; i++) | ||
781 | if (!test_and_set_bit(i, &priv->ucode_key_table)) | ||
782 | return i; | ||
783 | |||
784 | return WEP_INVALID_OFFSET; | ||
785 | } | ||
786 | |||
787 | void iwl_dealloc_bcast_stations(struct iwl_priv *priv) | ||
788 | { | ||
789 | int i; | ||
790 | |||
791 | spin_lock_bh(&priv->sta_lock); | ||
792 | for (i = 0; i < IWLAGN_STATION_COUNT; i++) { | ||
793 | if (!(priv->stations[i].used & IWL_STA_BCAST)) | ||
794 | continue; | ||
795 | |||
796 | priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; | ||
797 | priv->num_stations--; | ||
798 | if (WARN_ON(priv->num_stations < 0)) | ||
799 | priv->num_stations = 0; | ||
800 | kfree(priv->stations[i].lq); | ||
801 | priv->stations[i].lq = NULL; | ||
802 | } | ||
803 | spin_unlock_bh(&priv->sta_lock); | ||
804 | } | ||
805 | |||
806 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
807 | static void iwl_dump_lq_cmd(struct iwl_priv *priv, | ||
808 | struct iwl_link_quality_cmd *lq) | ||
809 | { | ||
810 | int i; | ||
811 | IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id); | ||
812 | IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n", | ||
813 | lq->general_params.single_stream_ant_msk, | ||
814 | lq->general_params.dual_stream_ant_msk); | ||
815 | |||
816 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) | ||
817 | IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n", | ||
818 | i, lq->rs_table[i].rate_n_flags); | ||
819 | } | ||
820 | #else | ||
821 | static inline void iwl_dump_lq_cmd(struct iwl_priv *priv, | ||
822 | struct iwl_link_quality_cmd *lq) | ||
823 | { | ||
824 | } | ||
825 | #endif | ||
826 | |||
827 | /** | ||
828 | * is_lq_table_valid() - Test one aspect of LQ cmd for validity | ||
829 | * | ||
830 | * It sometimes happens when a HT rate has been in use and we | ||
831 | * loose connectivity with AP then mac80211 will first tell us that the | ||
832 | * current channel is not HT anymore before removing the station. In such a | ||
833 | * scenario the RXON flags will be updated to indicate we are not | ||
834 | * communicating HT anymore, but the LQ command may still contain HT rates. | ||
835 | * Test for this to prevent driver from sending LQ command between the time | ||
836 | * RXON flags are updated and when LQ command is updated. | ||
837 | */ | ||
838 | static bool is_lq_table_valid(struct iwl_priv *priv, | ||
839 | struct iwl_rxon_context *ctx, | ||
840 | struct iwl_link_quality_cmd *lq) | ||
841 | { | ||
842 | int i; | ||
843 | |||
844 | if (ctx->ht.enabled) | ||
845 | return true; | ||
846 | |||
847 | IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n", | ||
848 | ctx->active.channel); | ||
849 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
850 | if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & | ||
851 | RATE_MCS_HT_MSK) { | ||
852 | IWL_DEBUG_INFO(priv, | ||
853 | "index %d of LQ expects HT channel\n", | ||
854 | i); | ||
855 | return false; | ||
856 | } | ||
857 | } | ||
858 | return true; | ||
859 | } | ||
860 | |||
861 | /** | ||
862 | * iwl_send_lq_cmd() - Send link quality command | ||
863 | * @init: This command is sent as part of station initialization right | ||
864 | * after station has been added. | ||
865 | * | ||
866 | * The link quality command is sent as the last step of station creation. | ||
867 | * This is the special case in which init is set and we call a callback in | ||
868 | * this case to clear the state indicating that station creation is in | ||
869 | * progress. | ||
870 | */ | ||
871 | int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||
872 | struct iwl_link_quality_cmd *lq, u8 flags, bool init) | ||
873 | { | ||
874 | int ret = 0; | ||
875 | struct iwl_host_cmd cmd = { | ||
876 | .id = REPLY_TX_LINK_QUALITY_CMD, | ||
877 | .len = { sizeof(struct iwl_link_quality_cmd), }, | ||
878 | .flags = flags, | ||
879 | .data = { lq, }, | ||
880 | }; | ||
881 | |||
882 | if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) | ||
883 | return -EINVAL; | ||
884 | |||
885 | |||
886 | spin_lock_bh(&priv->sta_lock); | ||
887 | if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) { | ||
888 | spin_unlock_bh(&priv->sta_lock); | ||
889 | return -EINVAL; | ||
890 | } | ||
891 | spin_unlock_bh(&priv->sta_lock); | ||
892 | |||
893 | iwl_dump_lq_cmd(priv, lq); | ||
894 | if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) | ||
895 | return -EINVAL; | ||
896 | |||
897 | if (is_lq_table_valid(priv, ctx, lq)) | ||
898 | ret = iwl_dvm_send_cmd(priv, &cmd); | ||
899 | else | ||
900 | ret = -EINVAL; | ||
901 | |||
902 | if (cmd.flags & CMD_ASYNC) | ||
903 | return ret; | ||
904 | |||
905 | if (init) { | ||
906 | IWL_DEBUG_INFO(priv, "init LQ command complete, " | ||
907 | "clearing sta addition status for sta %d\n", | ||
908 | lq->sta_id); | ||
909 | spin_lock_bh(&priv->sta_lock); | ||
910 | priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; | ||
911 | spin_unlock_bh(&priv->sta_lock); | ||
912 | } | ||
913 | return ret; | ||
914 | } | ||
915 | |||
916 | |||
917 | static struct iwl_link_quality_cmd * | ||
918 | iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | ||
919 | u8 sta_id) | ||
920 | { | ||
921 | struct iwl_link_quality_cmd *link_cmd; | ||
922 | |||
923 | link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); | ||
924 | if (!link_cmd) { | ||
925 | IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); | ||
926 | return NULL; | ||
927 | } | ||
928 | |||
929 | iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd); | ||
930 | |||
931 | return link_cmd; | ||
932 | } | ||
933 | |||
934 | /* | ||
935 | * iwlagn_add_bssid_station - Add the special IBSS BSSID station | ||
936 | * | ||
937 | * Function sleeps. | ||
938 | */ | ||
939 | int iwlagn_add_bssid_station(struct iwl_priv *priv, | ||
940 | struct iwl_rxon_context *ctx, | ||
941 | const u8 *addr, u8 *sta_id_r) | ||
942 | { | ||
943 | int ret; | ||
944 | u8 sta_id; | ||
945 | struct iwl_link_quality_cmd *link_cmd; | ||
946 | |||
947 | if (sta_id_r) | ||
948 | *sta_id_r = IWL_INVALID_STATION; | ||
949 | |||
950 | ret = iwl_add_station_common(priv, ctx, addr, 0, NULL, &sta_id); | ||
951 | if (ret) { | ||
952 | IWL_ERR(priv, "Unable to add station %pM\n", addr); | ||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | if (sta_id_r) | ||
957 | *sta_id_r = sta_id; | ||
958 | |||
959 | spin_lock_bh(&priv->sta_lock); | ||
960 | priv->stations[sta_id].used |= IWL_STA_LOCAL; | ||
961 | spin_unlock_bh(&priv->sta_lock); | ||
962 | |||
963 | /* Set up default rate scaling table in device's station table */ | ||
964 | link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); | ||
965 | if (!link_cmd) { | ||
966 | IWL_ERR(priv, | ||
967 | "Unable to initialize rate scaling for station %pM.\n", | ||
968 | addr); | ||
969 | return -ENOMEM; | ||
970 | } | ||
971 | |||
972 | ret = iwl_send_lq_cmd(priv, ctx, link_cmd, CMD_SYNC, true); | ||
973 | if (ret) | ||
974 | IWL_ERR(priv, "Link quality command failed (%d)\n", ret); | ||
975 | |||
976 | spin_lock_bh(&priv->sta_lock); | ||
977 | priv->stations[sta_id].lq = link_cmd; | ||
978 | spin_unlock_bh(&priv->sta_lock); | ||
979 | |||
980 | return 0; | ||
981 | } | ||
982 | |||
983 | /* | ||
984 | * static WEP keys | ||
985 | * | ||
986 | * For each context, the device has a table of 4 static WEP keys | ||
987 | * (one for each key index) that is updated with the following | ||
988 | * commands. | ||
989 | */ | ||
990 | |||
991 | static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, | ||
992 | struct iwl_rxon_context *ctx, | ||
993 | bool send_if_empty) | ||
994 | { | ||
995 | int i, not_empty = 0; | ||
996 | u8 buff[sizeof(struct iwl_wep_cmd) + | ||
997 | sizeof(struct iwl_wep_key) * WEP_KEYS_MAX]; | ||
998 | struct iwl_wep_cmd *wep_cmd = (struct iwl_wep_cmd *)buff; | ||
999 | size_t cmd_size = sizeof(struct iwl_wep_cmd); | ||
1000 | struct iwl_host_cmd cmd = { | ||
1001 | .id = ctx->wep_key_cmd, | ||
1002 | .data = { wep_cmd, }, | ||
1003 | .flags = CMD_SYNC, | ||
1004 | }; | ||
1005 | |||
1006 | might_sleep(); | ||
1007 | |||
1008 | memset(wep_cmd, 0, cmd_size + | ||
1009 | (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX)); | ||
1010 | |||
1011 | for (i = 0; i < WEP_KEYS_MAX ; i++) { | ||
1012 | wep_cmd->key[i].key_index = i; | ||
1013 | if (ctx->wep_keys[i].key_size) { | ||
1014 | wep_cmd->key[i].key_offset = i; | ||
1015 | not_empty = 1; | ||
1016 | } else { | ||
1017 | wep_cmd->key[i].key_offset = WEP_INVALID_OFFSET; | ||
1018 | } | ||
1019 | |||
1020 | wep_cmd->key[i].key_size = ctx->wep_keys[i].key_size; | ||
1021 | memcpy(&wep_cmd->key[i].key[3], ctx->wep_keys[i].key, | ||
1022 | ctx->wep_keys[i].key_size); | ||
1023 | } | ||
1024 | |||
1025 | wep_cmd->global_key_type = WEP_KEY_WEP_TYPE; | ||
1026 | wep_cmd->num_keys = WEP_KEYS_MAX; | ||
1027 | |||
1028 | cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX; | ||
1029 | |||
1030 | cmd.len[0] = cmd_size; | ||
1031 | |||
1032 | if (not_empty || send_if_empty) | ||
1033 | return iwl_dvm_send_cmd(priv, &cmd); | ||
1034 | else | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | int iwl_restore_default_wep_keys(struct iwl_priv *priv, | ||
1039 | struct iwl_rxon_context *ctx) | ||
1040 | { | ||
1041 | lockdep_assert_held(&priv->mutex); | ||
1042 | |||
1043 | return iwl_send_static_wepkey_cmd(priv, ctx, false); | ||
1044 | } | ||
1045 | |||
1046 | int iwl_remove_default_wep_key(struct iwl_priv *priv, | ||
1047 | struct iwl_rxon_context *ctx, | ||
1048 | struct ieee80211_key_conf *keyconf) | ||
1049 | { | ||
1050 | int ret; | ||
1051 | |||
1052 | lockdep_assert_held(&priv->mutex); | ||
1053 | |||
1054 | IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", | ||
1055 | keyconf->keyidx); | ||
1056 | |||
1057 | memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0])); | ||
1058 | if (iwl_is_rfkill(priv)) { | ||
1059 | IWL_DEBUG_WEP(priv, | ||
1060 | "Not sending REPLY_WEPKEY command due to RFKILL.\n"); | ||
1061 | /* but keys in device are clear anyway so return success */ | ||
1062 | return 0; | ||
1063 | } | ||
1064 | ret = iwl_send_static_wepkey_cmd(priv, ctx, 1); | ||
1065 | IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n", | ||
1066 | keyconf->keyidx, ret); | ||
1067 | |||
1068 | return ret; | ||
1069 | } | ||
1070 | |||
1071 | int iwl_set_default_wep_key(struct iwl_priv *priv, | ||
1072 | struct iwl_rxon_context *ctx, | ||
1073 | struct ieee80211_key_conf *keyconf) | ||
1074 | { | ||
1075 | int ret; | ||
1076 | |||
1077 | lockdep_assert_held(&priv->mutex); | ||
1078 | |||
1079 | if (keyconf->keylen != WEP_KEY_LEN_128 && | ||
1080 | keyconf->keylen != WEP_KEY_LEN_64) { | ||
1081 | IWL_DEBUG_WEP(priv, | ||
1082 | "Bad WEP key length %d\n", keyconf->keylen); | ||
1083 | return -EINVAL; | ||
1084 | } | ||
1085 | |||
1086 | keyconf->hw_key_idx = IWLAGN_HW_KEY_DEFAULT; | ||
1087 | |||
1088 | ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; | ||
1089 | memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key, | ||
1090 | keyconf->keylen); | ||
1091 | |||
1092 | ret = iwl_send_static_wepkey_cmd(priv, ctx, false); | ||
1093 | IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n", | ||
1094 | keyconf->keylen, keyconf->keyidx, ret); | ||
1095 | |||
1096 | return ret; | ||
1097 | } | ||
1098 | |||
1099 | /* | ||
1100 | * dynamic (per-station) keys | ||
1101 | * | ||
1102 | * The dynamic keys are a little more complicated. The device has | ||
1103 | * a key cache of up to STA_KEY_MAX_NUM/STA_KEY_MAX_NUM_PAN keys. | ||
1104 | * These are linked to stations by a table that contains an index | ||
1105 | * into the key table for each station/key index/{mcast,unicast}, | ||
1106 | * i.e. it's basically an array of pointers like this: | ||
1107 | * key_offset_t key_mapping[NUM_STATIONS][4][2]; | ||
1108 | * (it really works differently, but you can think of it as such) | ||
1109 | * | ||
1110 | * The key uploading and linking happens in the same command, the | ||
1111 | * add station command with STA_MODIFY_KEY_MASK. | ||
1112 | */ | ||
1113 | |||
1114 | static u8 iwlagn_key_sta_id(struct iwl_priv *priv, | ||
1115 | struct ieee80211_vif *vif, | ||
1116 | struct ieee80211_sta *sta) | ||
1117 | { | ||
1118 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
1119 | |||
1120 | if (sta) | ||
1121 | return iwl_sta_id(sta); | ||
1122 | |||
1123 | /* | ||
1124 | * The device expects GTKs for station interfaces to be | ||
1125 | * installed as GTKs for the AP station. If we have no | ||
1126 | * station ID, then use the ap_sta_id in that case. | ||
1127 | */ | ||
1128 | if (vif->type == NL80211_IFTYPE_STATION && vif_priv->ctx) | ||
1129 | return vif_priv->ctx->ap_sta_id; | ||
1130 | |||
1131 | return IWL_INVALID_STATION; | ||
1132 | } | ||
1133 | |||
1134 | static int iwlagn_send_sta_key(struct iwl_priv *priv, | ||
1135 | struct ieee80211_key_conf *keyconf, | ||
1136 | u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, | ||
1137 | u32 cmd_flags) | ||
1138 | { | ||
1139 | __le16 key_flags; | ||
1140 | struct iwl_addsta_cmd sta_cmd; | ||
1141 | int i; | ||
1142 | |||
1143 | spin_lock_bh(&priv->sta_lock); | ||
1144 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); | ||
1145 | spin_unlock_bh(&priv->sta_lock); | ||
1146 | |||
1147 | key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | ||
1148 | key_flags |= STA_KEY_FLG_MAP_KEY_MSK; | ||
1149 | |||
1150 | switch (keyconf->cipher) { | ||
1151 | case WLAN_CIPHER_SUITE_CCMP: | ||
1152 | key_flags |= STA_KEY_FLG_CCMP; | ||
1153 | memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen); | ||
1154 | break; | ||
1155 | case WLAN_CIPHER_SUITE_TKIP: | ||
1156 | key_flags |= STA_KEY_FLG_TKIP; | ||
1157 | sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32; | ||
1158 | for (i = 0; i < 5; i++) | ||
1159 | sta_cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); | ||
1160 | memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen); | ||
1161 | break; | ||
1162 | case WLAN_CIPHER_SUITE_WEP104: | ||
1163 | key_flags |= STA_KEY_FLG_KEY_SIZE_MSK; | ||
1164 | /* fall through */ | ||
1165 | case WLAN_CIPHER_SUITE_WEP40: | ||
1166 | key_flags |= STA_KEY_FLG_WEP; | ||
1167 | memcpy(&sta_cmd.key.key[3], keyconf->key, keyconf->keylen); | ||
1168 | break; | ||
1169 | default: | ||
1170 | WARN_ON(1); | ||
1171 | return -EINVAL; | ||
1172 | } | ||
1173 | |||
1174 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
1175 | key_flags |= STA_KEY_MULTICAST_MSK; | ||
1176 | |||
1177 | /* key pointer (offset) */ | ||
1178 | sta_cmd.key.key_offset = keyconf->hw_key_idx; | ||
1179 | |||
1180 | sta_cmd.key.key_flags = key_flags; | ||
1181 | sta_cmd.mode = STA_CONTROL_MODIFY_MSK; | ||
1182 | sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; | ||
1183 | |||
1184 | return iwl_send_add_sta(priv, &sta_cmd, cmd_flags); | ||
1185 | } | ||
1186 | |||
1187 | void iwl_update_tkip_key(struct iwl_priv *priv, | ||
1188 | struct ieee80211_vif *vif, | ||
1189 | struct ieee80211_key_conf *keyconf, | ||
1190 | struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) | ||
1191 | { | ||
1192 | u8 sta_id = iwlagn_key_sta_id(priv, vif, sta); | ||
1193 | |||
1194 | if (sta_id == IWL_INVALID_STATION) | ||
1195 | return; | ||
1196 | |||
1197 | if (iwl_scan_cancel(priv)) { | ||
1198 | /* cancel scan failed, just live w/ bad key and rely | ||
1199 | briefly on SW decryption */ | ||
1200 | return; | ||
1201 | } | ||
1202 | |||
1203 | iwlagn_send_sta_key(priv, keyconf, sta_id, | ||
1204 | iv32, phase1key, CMD_ASYNC); | ||
1205 | } | ||
1206 | |||
1207 | int iwl_remove_dynamic_key(struct iwl_priv *priv, | ||
1208 | struct iwl_rxon_context *ctx, | ||
1209 | struct ieee80211_key_conf *keyconf, | ||
1210 | struct ieee80211_sta *sta) | ||
1211 | { | ||
1212 | struct iwl_addsta_cmd sta_cmd; | ||
1213 | u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta); | ||
1214 | __le16 key_flags; | ||
1215 | |||
1216 | /* if station isn't there, neither is the key */ | ||
1217 | if (sta_id == IWL_INVALID_STATION) | ||
1218 | return -ENOENT; | ||
1219 | |||
1220 | spin_lock_bh(&priv->sta_lock); | ||
1221 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); | ||
1222 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) | ||
1223 | sta_id = IWL_INVALID_STATION; | ||
1224 | spin_unlock_bh(&priv->sta_lock); | ||
1225 | |||
1226 | if (sta_id == IWL_INVALID_STATION) | ||
1227 | return 0; | ||
1228 | |||
1229 | lockdep_assert_held(&priv->mutex); | ||
1230 | |||
1231 | ctx->key_mapping_keys--; | ||
1232 | |||
1233 | IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n", | ||
1234 | keyconf->keyidx, sta_id); | ||
1235 | |||
1236 | if (!test_and_clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table)) | ||
1237 | IWL_ERR(priv, "offset %d not used in uCode key table.\n", | ||
1238 | keyconf->hw_key_idx); | ||
1239 | |||
1240 | key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | ||
1241 | key_flags |= STA_KEY_FLG_MAP_KEY_MSK | STA_KEY_FLG_NO_ENC | | ||
1242 | STA_KEY_FLG_INVALID; | ||
1243 | |||
1244 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
1245 | key_flags |= STA_KEY_MULTICAST_MSK; | ||
1246 | |||
1247 | sta_cmd.key.key_flags = key_flags; | ||
1248 | sta_cmd.key.key_offset = WEP_INVALID_OFFSET; | ||
1249 | sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; | ||
1250 | sta_cmd.mode = STA_CONTROL_MODIFY_MSK; | ||
1251 | |||
1252 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
1253 | } | ||
1254 | |||
1255 | int iwl_set_dynamic_key(struct iwl_priv *priv, | ||
1256 | struct iwl_rxon_context *ctx, | ||
1257 | struct ieee80211_key_conf *keyconf, | ||
1258 | struct ieee80211_sta *sta) | ||
1259 | { | ||
1260 | struct ieee80211_key_seq seq; | ||
1261 | u16 p1k[5]; | ||
1262 | int ret; | ||
1263 | u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta); | ||
1264 | const u8 *addr; | ||
1265 | |||
1266 | if (sta_id == IWL_INVALID_STATION) | ||
1267 | return -EINVAL; | ||
1268 | |||
1269 | lockdep_assert_held(&priv->mutex); | ||
1270 | |||
1271 | keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv); | ||
1272 | if (keyconf->hw_key_idx == WEP_INVALID_OFFSET) | ||
1273 | return -ENOSPC; | ||
1274 | |||
1275 | ctx->key_mapping_keys++; | ||
1276 | |||
1277 | switch (keyconf->cipher) { | ||
1278 | case WLAN_CIPHER_SUITE_TKIP: | ||
1279 | if (sta) | ||
1280 | addr = sta->addr; | ||
1281 | else /* station mode case only */ | ||
1282 | addr = ctx->active.bssid_addr; | ||
1283 | |||
1284 | /* pre-fill phase 1 key into device cache */ | ||
1285 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
1286 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
1287 | ret = iwlagn_send_sta_key(priv, keyconf, sta_id, | ||
1288 | seq.tkip.iv32, p1k, CMD_SYNC); | ||
1289 | break; | ||
1290 | case WLAN_CIPHER_SUITE_CCMP: | ||
1291 | case WLAN_CIPHER_SUITE_WEP40: | ||
1292 | case WLAN_CIPHER_SUITE_WEP104: | ||
1293 | ret = iwlagn_send_sta_key(priv, keyconf, sta_id, | ||
1294 | 0, NULL, CMD_SYNC); | ||
1295 | break; | ||
1296 | default: | ||
1297 | IWL_ERR(priv, "Unknown cipher %x\n", keyconf->cipher); | ||
1298 | ret = -EINVAL; | ||
1299 | } | ||
1300 | |||
1301 | if (ret) { | ||
1302 | ctx->key_mapping_keys--; | ||
1303 | clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table); | ||
1304 | } | ||
1305 | |||
1306 | IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", | ||
1307 | keyconf->cipher, keyconf->keylen, keyconf->keyidx, | ||
1308 | sta ? sta->addr : NULL, ret); | ||
1309 | |||
1310 | return ret; | ||
1311 | } | ||
1312 | |||
1313 | /** | ||
1314 | * iwlagn_alloc_bcast_station - add broadcast station into driver's station table. | ||
1315 | * | ||
1316 | * This adds the broadcast station into the driver's station table | ||
1317 | * and marks it driver active, so that it will be restored to the | ||
1318 | * device at the next best time. | ||
1319 | */ | ||
1320 | int iwlagn_alloc_bcast_station(struct iwl_priv *priv, | ||
1321 | struct iwl_rxon_context *ctx) | ||
1322 | { | ||
1323 | struct iwl_link_quality_cmd *link_cmd; | ||
1324 | u8 sta_id; | ||
1325 | |||
1326 | spin_lock_bh(&priv->sta_lock); | ||
1327 | sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); | ||
1328 | if (sta_id == IWL_INVALID_STATION) { | ||
1329 | IWL_ERR(priv, "Unable to prepare broadcast station\n"); | ||
1330 | spin_unlock_bh(&priv->sta_lock); | ||
1331 | |||
1332 | return -EINVAL; | ||
1333 | } | ||
1334 | |||
1335 | priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; | ||
1336 | priv->stations[sta_id].used |= IWL_STA_BCAST; | ||
1337 | spin_unlock_bh(&priv->sta_lock); | ||
1338 | |||
1339 | link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); | ||
1340 | if (!link_cmd) { | ||
1341 | IWL_ERR(priv, | ||
1342 | "Unable to initialize rate scaling for bcast station.\n"); | ||
1343 | return -ENOMEM; | ||
1344 | } | ||
1345 | |||
1346 | spin_lock_bh(&priv->sta_lock); | ||
1347 | priv->stations[sta_id].lq = link_cmd; | ||
1348 | spin_unlock_bh(&priv->sta_lock); | ||
1349 | |||
1350 | return 0; | ||
1351 | } | ||
1352 | |||
1353 | /** | ||
1354 | * iwl_update_bcast_station - update broadcast station's LQ command | ||
1355 | * | ||
1356 | * Only used by iwlagn. Placed here to have all bcast station management | ||
1357 | * code together. | ||
1358 | */ | ||
1359 | int iwl_update_bcast_station(struct iwl_priv *priv, | ||
1360 | struct iwl_rxon_context *ctx) | ||
1361 | { | ||
1362 | struct iwl_link_quality_cmd *link_cmd; | ||
1363 | u8 sta_id = ctx->bcast_sta_id; | ||
1364 | |||
1365 | link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); | ||
1366 | if (!link_cmd) { | ||
1367 | IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n"); | ||
1368 | return -ENOMEM; | ||
1369 | } | ||
1370 | |||
1371 | spin_lock_bh(&priv->sta_lock); | ||
1372 | if (priv->stations[sta_id].lq) | ||
1373 | kfree(priv->stations[sta_id].lq); | ||
1374 | else | ||
1375 | IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n"); | ||
1376 | priv->stations[sta_id].lq = link_cmd; | ||
1377 | spin_unlock_bh(&priv->sta_lock); | ||
1378 | |||
1379 | return 0; | ||
1380 | } | ||
1381 | |||
1382 | int iwl_update_bcast_stations(struct iwl_priv *priv) | ||
1383 | { | ||
1384 | struct iwl_rxon_context *ctx; | ||
1385 | int ret = 0; | ||
1386 | |||
1387 | for_each_context(priv, ctx) { | ||
1388 | ret = iwl_update_bcast_station(priv, ctx); | ||
1389 | if (ret) | ||
1390 | break; | ||
1391 | } | ||
1392 | |||
1393 | return ret; | ||
1394 | } | ||
1395 | |||
1396 | /** | ||
1397 | * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table | ||
1398 | */ | ||
1399 | int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) | ||
1400 | { | ||
1401 | struct iwl_addsta_cmd sta_cmd; | ||
1402 | |||
1403 | lockdep_assert_held(&priv->mutex); | ||
1404 | |||
1405 | /* Remove "disable" flag, to enable Tx for this TID */ | ||
1406 | spin_lock_bh(&priv->sta_lock); | ||
1407 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; | ||
1408 | priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); | ||
1409 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
1410 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | ||
1411 | spin_unlock_bh(&priv->sta_lock); | ||
1412 | |||
1413 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
1414 | } | ||
1415 | |||
1416 | int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, | ||
1417 | int tid, u16 ssn) | ||
1418 | { | ||
1419 | int sta_id; | ||
1420 | struct iwl_addsta_cmd sta_cmd; | ||
1421 | |||
1422 | lockdep_assert_held(&priv->mutex); | ||
1423 | |||
1424 | sta_id = iwl_sta_id(sta); | ||
1425 | if (sta_id == IWL_INVALID_STATION) | ||
1426 | return -ENXIO; | ||
1427 | |||
1428 | spin_lock_bh(&priv->sta_lock); | ||
1429 | priv->stations[sta_id].sta.station_flags_msk = 0; | ||
1430 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; | ||
1431 | priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; | ||
1432 | priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); | ||
1433 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
1434 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | ||
1435 | spin_unlock_bh(&priv->sta_lock); | ||
1436 | |||
1437 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
1438 | } | ||
1439 | |||
1440 | int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, | ||
1441 | int tid) | ||
1442 | { | ||
1443 | int sta_id; | ||
1444 | struct iwl_addsta_cmd sta_cmd; | ||
1445 | |||
1446 | lockdep_assert_held(&priv->mutex); | ||
1447 | |||
1448 | sta_id = iwl_sta_id(sta); | ||
1449 | if (sta_id == IWL_INVALID_STATION) { | ||
1450 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | ||
1451 | return -ENXIO; | ||
1452 | } | ||
1453 | |||
1454 | spin_lock_bh(&priv->sta_lock); | ||
1455 | priv->stations[sta_id].sta.station_flags_msk = 0; | ||
1456 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; | ||
1457 | priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; | ||
1458 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
1459 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | ||
1460 | spin_unlock_bh(&priv->sta_lock); | ||
1461 | |||
1462 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | ||
1463 | } | ||
1464 | |||
1465 | |||
1466 | |||
1467 | void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) | ||
1468 | { | ||
1469 | struct iwl_addsta_cmd cmd = { | ||
1470 | .mode = STA_CONTROL_MODIFY_MSK, | ||
1471 | .station_flags = STA_FLG_PWR_SAVE_MSK, | ||
1472 | .station_flags_msk = STA_FLG_PWR_SAVE_MSK, | ||
1473 | .sta.sta_id = sta_id, | ||
1474 | .sta.modify_mask = STA_MODIFY_SLEEP_TX_COUNT_MSK, | ||
1475 | .sleep_tx_count = cpu_to_le16(cnt), | ||
1476 | }; | ||
1477 | |||
1478 | iwl_send_add_sta(priv, &cmd, CMD_ASYNC); | ||
1479 | } | ||