diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 501 |
1 files changed, 486 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index f2267047d102..983f10760fb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
@@ -37,6 +37,10 @@ | |||
37 | #include "iwl-io.h" | 37 | #include "iwl-io.h" |
38 | #include "iwl-helpers.h" | 38 | #include "iwl-helpers.h" |
39 | 39 | ||
40 | |||
41 | #define IWL_STA_DRIVER_ACTIVE 0x1 /* ucode entry is active */ | ||
42 | #define IWL_STA_UCODE_ACTIVE 0x2 /* ucode entry is active */ | ||
43 | |||
40 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | 44 | u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) |
41 | { | 45 | { |
42 | int i; | 46 | int i; |
@@ -70,6 +74,39 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) | |||
70 | } | 74 | } |
71 | EXPORT_SYMBOL(iwl_find_station); | 75 | EXPORT_SYMBOL(iwl_find_station); |
72 | 76 | ||
77 | static int iwl_add_sta_callback(struct iwl_priv *priv, | ||
78 | struct iwl_cmd *cmd, struct sk_buff *skb) | ||
79 | { | ||
80 | struct iwl_rx_packet *res = NULL; | ||
81 | |||
82 | if (!skb) { | ||
83 | IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); | ||
84 | return 1; | ||
85 | } | ||
86 | |||
87 | res = (struct iwl_rx_packet *)skb->data; | ||
88 | if (res->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
89 | IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", | ||
90 | res->hdr.flags); | ||
91 | return 1; | ||
92 | } | ||
93 | |||
94 | switch (res->u.add_sta.status) { | ||
95 | case ADD_STA_SUCCESS_MSK: | ||
96 | /* FIXME: implement iwl_sta_ucode_activate(priv, addr); */ | ||
97 | /* fail through */ | ||
98 | default: | ||
99 | IWL_DEBUG_HC("Received REPLY_ADD_STA:(0x%08X)\n", | ||
100 | res->u.add_sta.status); | ||
101 | break; | ||
102 | } | ||
103 | |||
104 | /* We didn't cache the SKB; let the caller free it */ | ||
105 | return 1; | ||
106 | } | ||
107 | |||
108 | |||
109 | |||
73 | int iwl_send_add_sta(struct iwl_priv *priv, | 110 | int iwl_send_add_sta(struct iwl_priv *priv, |
74 | struct iwl_addsta_cmd *sta, u8 flags) | 111 | struct iwl_addsta_cmd *sta, u8 flags) |
75 | { | 112 | { |
@@ -82,7 +119,9 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
82 | .data = data, | 119 | .data = data, |
83 | }; | 120 | }; |
84 | 121 | ||
85 | if (!(flags & CMD_ASYNC)) | 122 | if (flags & CMD_ASYNC) |
123 | cmd.meta.u.callback = iwl_add_sta_callback; | ||
124 | else | ||
86 | cmd.meta.flags |= CMD_WANT_SKB; | 125 | cmd.meta.flags |= CMD_WANT_SKB; |
87 | 126 | ||
88 | cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); | 127 | cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data); |
@@ -117,6 +156,276 @@ int iwl_send_add_sta(struct iwl_priv *priv, | |||
117 | } | 156 | } |
118 | EXPORT_SYMBOL(iwl_send_add_sta); | 157 | EXPORT_SYMBOL(iwl_send_add_sta); |
119 | 158 | ||
159 | #ifdef CONFIG_IWL4965_HT | ||
160 | |||
161 | static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||
162 | struct ieee80211_ht_info *sta_ht_inf) | ||
163 | { | ||
164 | __le32 sta_flags; | ||
165 | u8 mimo_ps_mode; | ||
166 | |||
167 | if (!sta_ht_inf || !sta_ht_inf->ht_supported) | ||
168 | goto done; | ||
169 | |||
170 | mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2; | ||
171 | |||
172 | sta_flags = priv->stations[index].sta.station_flags; | ||
173 | |||
174 | sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); | ||
175 | |||
176 | switch (mimo_ps_mode) { | ||
177 | case WLAN_HT_CAP_MIMO_PS_STATIC: | ||
178 | sta_flags |= STA_FLG_MIMO_DIS_MSK; | ||
179 | break; | ||
180 | case WLAN_HT_CAP_MIMO_PS_DYNAMIC: | ||
181 | sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; | ||
182 | break; | ||
183 | case WLAN_HT_CAP_MIMO_PS_DISABLED: | ||
184 | break; | ||
185 | default: | ||
186 | IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode); | ||
187 | break; | ||
188 | } | ||
189 | |||
190 | sta_flags |= cpu_to_le32( | ||
191 | (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); | ||
192 | |||
193 | sta_flags |= cpu_to_le32( | ||
194 | (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); | ||
195 | |||
196 | if (iwl_is_fat_tx_allowed(priv, sta_ht_inf)) | ||
197 | sta_flags |= STA_FLG_FAT_EN_MSK; | ||
198 | else | ||
199 | sta_flags &= ~STA_FLG_FAT_EN_MSK; | ||
200 | |||
201 | priv->stations[index].sta.station_flags = sta_flags; | ||
202 | done: | ||
203 | return; | ||
204 | } | ||
205 | #else | ||
206 | static inline void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, | ||
207 | struct ieee80211_ht_info *sta_ht_info) | ||
208 | { | ||
209 | } | ||
210 | #endif | ||
211 | |||
212 | /** | ||
213 | * iwl_add_station_flags - Add station to tables in driver and device | ||
214 | */ | ||
215 | u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, | ||
216 | u8 flags, struct ieee80211_ht_info *ht_info) | ||
217 | { | ||
218 | int i; | ||
219 | int index = IWL_INVALID_STATION; | ||
220 | struct iwl_station_entry *station; | ||
221 | unsigned long flags_spin; | ||
222 | DECLARE_MAC_BUF(mac); | ||
223 | |||
224 | spin_lock_irqsave(&priv->sta_lock, flags_spin); | ||
225 | if (is_ap) | ||
226 | index = IWL_AP_ID; | ||
227 | else if (is_broadcast_ether_addr(addr)) | ||
228 | index = priv->hw_params.bcast_sta_id; | ||
229 | else | ||
230 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { | ||
231 | if (!compare_ether_addr(priv->stations[i].sta.sta.addr, | ||
232 | addr)) { | ||
233 | index = i; | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | if (!priv->stations[i].used && | ||
238 | index == IWL_INVALID_STATION) | ||
239 | index = i; | ||
240 | } | ||
241 | |||
242 | |||
243 | /* These two conditions have the same outcome, but keep them separate | ||
244 | since they have different meanings */ | ||
245 | if (unlikely(index == IWL_INVALID_STATION)) { | ||
246 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
247 | return index; | ||
248 | } | ||
249 | |||
250 | if (priv->stations[index].used && | ||
251 | !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) { | ||
252 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
253 | return index; | ||
254 | } | ||
255 | |||
256 | |||
257 | IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); | ||
258 | station = &priv->stations[index]; | ||
259 | station->used = 1; | ||
260 | priv->num_stations++; | ||
261 | |||
262 | /* Set up the REPLY_ADD_STA command to send to device */ | ||
263 | memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); | ||
264 | memcpy(station->sta.sta.addr, addr, ETH_ALEN); | ||
265 | station->sta.mode = 0; | ||
266 | station->sta.sta.sta_id = index; | ||
267 | station->sta.station_flags = 0; | ||
268 | |||
269 | /* BCAST station and IBSS stations do not work in HT mode */ | ||
270 | if (index != priv->hw_params.bcast_sta_id && | ||
271 | priv->iw_mode != IEEE80211_IF_TYPE_IBSS) | ||
272 | iwl_set_ht_add_station(priv, index, ht_info); | ||
273 | |||
274 | spin_unlock_irqrestore(&priv->sta_lock, flags_spin); | ||
275 | |||
276 | /* Add station to device's station table */ | ||
277 | iwl_send_add_sta(priv, &station->sta, flags); | ||
278 | return index; | ||
279 | |||
280 | } | ||
281 | EXPORT_SYMBOL(iwl_add_station_flags); | ||
282 | |||
283 | |||
284 | static int iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) | ||
285 | { | ||
286 | unsigned long flags; | ||
287 | u8 sta_id; | ||
288 | DECLARE_MAC_BUF(mac); | ||
289 | |||
290 | sta_id = iwl_find_station(priv, addr); | ||
291 | if (sta_id != IWL_INVALID_STATION) { | ||
292 | IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", | ||
293 | print_mac(mac, addr)); | ||
294 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
295 | priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; | ||
296 | memset(&priv->stations[sta_id], 0, | ||
297 | sizeof(struct iwl_station_entry)); | ||
298 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
299 | return 0; | ||
300 | } | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | |||
304 | static int iwl_remove_sta_callback(struct iwl_priv *priv, | ||
305 | struct iwl_cmd *cmd, struct sk_buff *skb) | ||
306 | { | ||
307 | struct iwl_rx_packet *res = NULL; | ||
308 | const char *addr = cmd->cmd.rm_sta.addr; | ||
309 | |||
310 | if (!skb) { | ||
311 | IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n"); | ||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | res = (struct iwl_rx_packet *)skb->data; | ||
316 | if (res->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
317 | IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n", | ||
318 | res->hdr.flags); | ||
319 | return 1; | ||
320 | } | ||
321 | |||
322 | switch (res->u.rem_sta.status) { | ||
323 | case REM_STA_SUCCESS_MSK: | ||
324 | iwl_sta_ucode_deactivate(priv, addr); | ||
325 | break; | ||
326 | default: | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | /* We didn't cache the SKB; let the caller free it */ | ||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr, | ||
335 | u8 flags) | ||
336 | { | ||
337 | struct iwl_rx_packet *res = NULL; | ||
338 | int ret; | ||
339 | |||
340 | struct iwl_rem_sta_cmd rm_sta_cmd; | ||
341 | |||
342 | struct iwl_host_cmd cmd = { | ||
343 | .id = REPLY_REMOVE_STA, | ||
344 | .len = sizeof(struct iwl_rem_sta_cmd), | ||
345 | .meta.flags = flags, | ||
346 | .data = &rm_sta_cmd, | ||
347 | }; | ||
348 | |||
349 | memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); | ||
350 | rm_sta_cmd.num_sta = 1; | ||
351 | memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN); | ||
352 | |||
353 | if (flags & CMD_ASYNC) | ||
354 | cmd.meta.u.callback = iwl_remove_sta_callback; | ||
355 | else | ||
356 | cmd.meta.flags |= CMD_WANT_SKB; | ||
357 | ret = iwl_send_cmd(priv, &cmd); | ||
358 | |||
359 | if (ret || (flags & CMD_ASYNC)) | ||
360 | return ret; | ||
361 | |||
362 | res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; | ||
363 | if (res->hdr.flags & IWL_CMD_FAILED_MSK) { | ||
364 | IWL_ERROR("Bad return from REPLY_REMOVE_STA (0x%08X)\n", | ||
365 | res->hdr.flags); | ||
366 | ret = -EIO; | ||
367 | } | ||
368 | |||
369 | if (!ret) { | ||
370 | switch (res->u.rem_sta.status) { | ||
371 | case REM_STA_SUCCESS_MSK: | ||
372 | iwl_sta_ucode_deactivate(priv, addr); | ||
373 | IWL_DEBUG_ASSOC("REPLY_REMOVE_STA PASSED\n"); | ||
374 | break; | ||
375 | default: | ||
376 | ret = -EIO; | ||
377 | IWL_ERROR("REPLY_REMOVE_STA failed\n"); | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | priv->alloc_rxb_skb--; | ||
383 | dev_kfree_skb_any(cmd.meta.u.skb); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | /** | ||
388 | * iwl_remove_station - Remove driver's knowledge of station. | ||
389 | * | ||
390 | */ | ||
391 | u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||
392 | { | ||
393 | int index = IWL_INVALID_STATION; | ||
394 | int i; | ||
395 | unsigned long flags; | ||
396 | |||
397 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
398 | |||
399 | if (is_ap) | ||
400 | index = IWL_AP_ID; | ||
401 | else if (is_broadcast_ether_addr(addr)) | ||
402 | index = priv->hw_params.bcast_sta_id; | ||
403 | else | ||
404 | for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) | ||
405 | if (priv->stations[i].used && | ||
406 | !compare_ether_addr(priv->stations[i].sta.sta.addr, | ||
407 | addr)) { | ||
408 | index = i; | ||
409 | break; | ||
410 | } | ||
411 | |||
412 | if (unlikely(index == IWL_INVALID_STATION)) | ||
413 | goto out; | ||
414 | |||
415 | if (priv->stations[index].used) { | ||
416 | priv->stations[index].used = 0; | ||
417 | priv->num_stations--; | ||
418 | } | ||
419 | |||
420 | BUG_ON(priv->num_stations < 0); | ||
421 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
422 | iwl_send_remove_station(priv, addr, CMD_ASYNC); | ||
423 | return index; | ||
424 | out: | ||
425 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
426 | return 0; | ||
427 | } | ||
428 | EXPORT_SYMBOL(iwl_remove_station); | ||
120 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) | 429 | int iwl_get_free_ucode_key_index(struct iwl_priv *priv) |
121 | { | 430 | { |
122 | int i; | 431 | int i; |
@@ -200,7 +509,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
200 | unsigned long flags; | 509 | unsigned long flags; |
201 | 510 | ||
202 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 511 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; |
203 | keyconf->hw_key_idx = keyconf->keyidx; | 512 | keyconf->hw_key_idx = HW_KEY_DEFAULT; |
204 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; | 513 | priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP; |
205 | 514 | ||
206 | spin_lock_irqsave(&priv->sta_lock, flags); | 515 | spin_lock_irqsave(&priv->sta_lock, flags); |
@@ -230,7 +539,6 @@ static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, | |||
230 | int ret; | 539 | int ret; |
231 | 540 | ||
232 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 541 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; |
233 | keyconf->hw_key_idx = keyconf->keyidx; | ||
234 | 542 | ||
235 | key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); | 543 | key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); |
236 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | 544 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); |
@@ -287,7 +595,6 @@ static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
287 | key_flags |= STA_KEY_MULTICAST_MSK; | 595 | key_flags |= STA_KEY_MULTICAST_MSK; |
288 | 596 | ||
289 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 597 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
290 | keyconf->hw_key_idx = keyconf->keyidx; | ||
291 | 598 | ||
292 | spin_lock_irqsave(&priv->sta_lock, flags); | 599 | spin_lock_irqsave(&priv->sta_lock, flags); |
293 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; | 600 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; |
@@ -325,12 +632,10 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | |||
325 | 632 | ||
326 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 633 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; |
327 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 634 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
328 | keyconf->hw_key_idx = keyconf->keyidx; | ||
329 | 635 | ||
330 | spin_lock_irqsave(&priv->sta_lock, flags); | 636 | spin_lock_irqsave(&priv->sta_lock, flags); |
331 | 637 | ||
332 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; | 638 | priv->stations[sta_id].keyinfo.alg = keyconf->alg; |
333 | priv->stations[sta_id].keyinfo.conf = keyconf; | ||
334 | priv->stations[sta_id].keyinfo.keylen = 16; | 639 | priv->stations[sta_id].keyinfo.keylen = 16; |
335 | 640 | ||
336 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | 641 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) |
@@ -359,7 +664,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
359 | u16 key_flags; | 664 | u16 key_flags; |
360 | u8 keyidx; | 665 | u8 keyidx; |
361 | 666 | ||
362 | priv->key_mapping_key = 0; | 667 | priv->key_mapping_key--; |
363 | 668 | ||
364 | spin_lock_irqsave(&priv->sta_lock, flags); | 669 | spin_lock_irqsave(&priv->sta_lock, flags); |
365 | key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); | 670 | key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); |
@@ -390,31 +695,32 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, | |||
390 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | 695 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; |
391 | 696 | ||
392 | IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); | 697 | IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); |
393 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0); | 698 | ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); |
394 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 699 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
395 | return ret; | 700 | return ret; |
396 | } | 701 | } |
397 | EXPORT_SYMBOL(iwl_remove_dynamic_key); | 702 | EXPORT_SYMBOL(iwl_remove_dynamic_key); |
398 | 703 | ||
399 | int iwl_set_dynamic_key(struct iwl_priv *priv, | 704 | int iwl_set_dynamic_key(struct iwl_priv *priv, |
400 | struct ieee80211_key_conf *key, u8 sta_id) | 705 | struct ieee80211_key_conf *keyconf, u8 sta_id) |
401 | { | 706 | { |
402 | int ret; | 707 | int ret; |
403 | 708 | ||
404 | priv->key_mapping_key = 1; | 709 | priv->key_mapping_key++; |
710 | keyconf->hw_key_idx = HW_KEY_DYNAMIC; | ||
405 | 711 | ||
406 | switch (key->alg) { | 712 | switch (keyconf->alg) { |
407 | case ALG_CCMP: | 713 | case ALG_CCMP: |
408 | ret = iwl_set_ccmp_dynamic_key_info(priv, key, sta_id); | 714 | ret = iwl_set_ccmp_dynamic_key_info(priv, keyconf, sta_id); |
409 | break; | 715 | break; |
410 | case ALG_TKIP: | 716 | case ALG_TKIP: |
411 | ret = iwl_set_tkip_dynamic_key_info(priv, key, sta_id); | 717 | ret = iwl_set_tkip_dynamic_key_info(priv, keyconf, sta_id); |
412 | break; | 718 | break; |
413 | case ALG_WEP: | 719 | case ALG_WEP: |
414 | ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id); | 720 | ret = iwl_set_wep_dynamic_key_info(priv, keyconf, sta_id); |
415 | break; | 721 | break; |
416 | default: | 722 | default: |
417 | IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg); | 723 | IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, keyconf->alg); |
418 | ret = -EINVAL; | 724 | ret = -EINVAL; |
419 | } | 725 | } |
420 | 726 | ||
@@ -470,3 +776,168 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, | |||
470 | } | 776 | } |
471 | EXPORT_SYMBOL(iwl_send_lq_cmd); | 777 | EXPORT_SYMBOL(iwl_send_lq_cmd); |
472 | 778 | ||
779 | /** | ||
780 | * iwl_sta_init_lq - Initialize a station's hardware rate table | ||
781 | * | ||
782 | * The uCode's station table contains a table of fallback rates | ||
783 | * for automatic fallback during transmission. | ||
784 | * | ||
785 | * NOTE: This sets up a default set of values. These will be replaced later | ||
786 | * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of | ||
787 | * rc80211_simple. | ||
788 | * | ||
789 | * NOTE: Run REPLY_ADD_STA command to set up station table entry, before | ||
790 | * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, | ||
791 | * which requires station table entry to exist). | ||
792 | */ | ||
793 | static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||
794 | { | ||
795 | int i, r; | ||
796 | struct iwl_link_quality_cmd link_cmd = { | ||
797 | .reserved1 = 0, | ||
798 | }; | ||
799 | u16 rate_flags; | ||
800 | |||
801 | /* Set up the rate scaling to start at selected rate, fall back | ||
802 | * all the way down to 1M in IEEE order, and then spin on 1M */ | ||
803 | if (is_ap) | ||
804 | r = IWL_RATE_54M_INDEX; | ||
805 | else if (priv->band == IEEE80211_BAND_5GHZ) | ||
806 | r = IWL_RATE_6M_INDEX; | ||
807 | else | ||
808 | r = IWL_RATE_1M_INDEX; | ||
809 | |||
810 | for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { | ||
811 | rate_flags = 0; | ||
812 | if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) | ||
813 | rate_flags |= RATE_MCS_CCK_MSK; | ||
814 | |||
815 | /* Use Tx antenna B only */ | ||
816 | rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ | ||
817 | |||
818 | link_cmd.rs_table[i].rate_n_flags = | ||
819 | iwl4965_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); | ||
820 | r = iwl4965_get_prev_ieee_rate(r); | ||
821 | } | ||
822 | |||
823 | link_cmd.general_params.single_stream_ant_msk = 2; | ||
824 | link_cmd.general_params.dual_stream_ant_msk = 3; | ||
825 | link_cmd.agg_params.agg_dis_start_th = 3; | ||
826 | link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); | ||
827 | |||
828 | /* Update the rate scaling for control frame Tx to AP */ | ||
829 | link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id; | ||
830 | |||
831 | iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD, | ||
832 | sizeof(link_cmd), &link_cmd, NULL); | ||
833 | } | ||
834 | /** | ||
835 | * iwl_rxon_add_station - add station into station table. | ||
836 | * | ||
837 | * there is only one AP station with id= IWL_AP_ID | ||
838 | * NOTE: mutex must be held before calling this fnction | ||
839 | */ | ||
840 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | ||
841 | { | ||
842 | u8 sta_id; | ||
843 | |||
844 | /* Add station to device's station table */ | ||
845 | #ifdef CONFIG_IWL4965_HT | ||
846 | struct ieee80211_conf *conf = &priv->hw->conf; | ||
847 | struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; | ||
848 | |||
849 | if ((is_ap) && | ||
850 | (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && | ||
851 | (priv->iw_mode == IEEE80211_IF_TYPE_STA)) | ||
852 | sta_id = iwl_add_station_flags(priv, addr, is_ap, | ||
853 | 0, cur_ht_config); | ||
854 | else | ||
855 | #endif /* CONFIG_IWL4965_HT */ | ||
856 | sta_id = iwl_add_station_flags(priv, addr, is_ap, | ||
857 | 0, NULL); | ||
858 | |||
859 | /* Set up default rate scaling table in device's station table */ | ||
860 | iwl_sta_init_lq(priv, addr, is_ap); | ||
861 | |||
862 | return sta_id; | ||
863 | } | ||
864 | EXPORT_SYMBOL(iwl_rxon_add_station); | ||
865 | |||
866 | |||
867 | /** | ||
868 | * iwl_get_sta_id - Find station's index within station table | ||
869 | * | ||
870 | * If new IBSS station, create new entry in station table | ||
871 | */ | ||
872 | int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) | ||
873 | { | ||
874 | int sta_id; | ||
875 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
876 | DECLARE_MAC_BUF(mac); | ||
877 | |||
878 | /* If this frame is broadcast or management, use broadcast station id */ | ||
879 | if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || | ||
880 | is_multicast_ether_addr(hdr->addr1)) | ||
881 | return priv->hw_params.bcast_sta_id; | ||
882 | |||
883 | switch (priv->iw_mode) { | ||
884 | |||
885 | /* If we are a client station in a BSS network, use the special | ||
886 | * AP station entry (that's the only station we communicate with) */ | ||
887 | case IEEE80211_IF_TYPE_STA: | ||
888 | return IWL_AP_ID; | ||
889 | |||
890 | /* If we are an AP, then find the station, or use BCAST */ | ||
891 | case IEEE80211_IF_TYPE_AP: | ||
892 | sta_id = iwl_find_station(priv, hdr->addr1); | ||
893 | if (sta_id != IWL_INVALID_STATION) | ||
894 | return sta_id; | ||
895 | return priv->hw_params.bcast_sta_id; | ||
896 | |||
897 | /* If this frame is going out to an IBSS network, find the station, | ||
898 | * or create a new station table entry */ | ||
899 | case IEEE80211_IF_TYPE_IBSS: | ||
900 | sta_id = iwl_find_station(priv, hdr->addr1); | ||
901 | if (sta_id != IWL_INVALID_STATION) | ||
902 | return sta_id; | ||
903 | |||
904 | /* Create new station table entry */ | ||
905 | sta_id = iwl_add_station_flags(priv, hdr->addr1, | ||
906 | 0, CMD_ASYNC, NULL); | ||
907 | |||
908 | if (sta_id != IWL_INVALID_STATION) | ||
909 | return sta_id; | ||
910 | |||
911 | IWL_DEBUG_DROP("Station %s not in station map. " | ||
912 | "Defaulting to broadcast...\n", | ||
913 | print_mac(mac, hdr->addr1)); | ||
914 | iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); | ||
915 | return priv->hw_params.bcast_sta_id; | ||
916 | |||
917 | default: | ||
918 | IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); | ||
919 | return priv->hw_params.bcast_sta_id; | ||
920 | } | ||
921 | } | ||
922 | EXPORT_SYMBOL(iwl_get_sta_id); | ||
923 | |||
924 | |||
925 | /** | ||
926 | * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table | ||
927 | */ | ||
928 | void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) | ||
929 | { | ||
930 | unsigned long flags; | ||
931 | |||
932 | /* Remove "disable" flag, to enable Tx for this TID */ | ||
933 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
934 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; | ||
935 | priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); | ||
936 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
937 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
938 | |||
939 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | ||
940 | } | ||
941 | EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); | ||
942 | |||
943 | |||