diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-sta.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 376 |
1 files changed, 161 insertions, 215 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 001622c06526..37e624095e40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c | |||
@@ -139,6 +139,14 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx | |||
139 | return 0; | 139 | return 0; |
140 | } | 140 | } |
141 | 141 | ||
142 | /* | ||
143 | * static WEP keys | ||
144 | * | ||
145 | * For each context, the device has a table of 4 static WEP keys | ||
146 | * (one for each key index) that is updated with the following | ||
147 | * commands. | ||
148 | */ | ||
149 | |||
142 | static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, | 150 | static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, |
143 | struct iwl_rxon_context *ctx, | 151 | struct iwl_rxon_context *ctx, |
144 | bool send_if_empty) | 152 | bool send_if_empty) |
@@ -181,7 +189,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, | |||
181 | cmd.len[0] = cmd_size; | 189 | cmd.len[0] = cmd_size; |
182 | 190 | ||
183 | if (not_empty || send_if_empty) | 191 | if (not_empty || send_if_empty) |
184 | return trans_send_cmd(priv, &cmd); | 192 | return trans_send_cmd(&priv->trans, &cmd); |
185 | else | 193 | else |
186 | return 0; | 194 | return 0; |
187 | } | 195 | } |
@@ -232,9 +240,7 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
232 | return -EINVAL; | 240 | return -EINVAL; |
233 | } | 241 | } |
234 | 242 | ||
235 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 243 | keyconf->hw_key_idx = IWLAGN_HW_KEY_DEFAULT; |
236 | keyconf->hw_key_idx = HW_KEY_DEFAULT; | ||
237 | priv->stations[ctx->ap_sta_id].keyinfo.cipher = keyconf->cipher; | ||
238 | 244 | ||
239 | ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; | 245 | ctx->wep_keys[keyconf->keyidx].key_size = keyconf->keylen; |
240 | memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key, | 246 | memcpy(&ctx->wep_keys[keyconf->keyidx].key, &keyconf->key, |
@@ -247,166 +253,117 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, | |||
247 | return ret; | 253 | return ret; |
248 | } | 254 | } |
249 | 255 | ||
250 | static int iwl_set_wep_dynamic_key_info(struct iwl_priv *priv, | 256 | /* |
251 | struct iwl_rxon_context *ctx, | 257 | * dynamic (per-station) keys |
252 | struct ieee80211_key_conf *keyconf, | 258 | * |
253 | u8 sta_id) | 259 | * The dynamic keys are a little more complicated. The device has |
254 | { | 260 | * a key cache of up to STA_KEY_MAX_NUM/STA_KEY_MAX_NUM_PAN keys. |
255 | unsigned long flags; | 261 | * These are linked to stations by a table that contains an index |
256 | __le16 key_flags = 0; | 262 | * into the key table for each station/key index/{mcast,unicast}, |
257 | struct iwl_addsta_cmd sta_cmd; | 263 | * i.e. it's basically an array of pointers like this: |
258 | 264 | * key_offset_t key_mapping[NUM_STATIONS][4][2]; | |
259 | lockdep_assert_held(&priv->mutex); | 265 | * (it really works differently, but you can think of it as such) |
260 | 266 | * | |
261 | keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV; | 267 | * The key uploading and linking happens in the same command, the |
262 | 268 | * add station command with STA_MODIFY_KEY_MASK. | |
263 | key_flags |= (STA_KEY_FLG_WEP | STA_KEY_FLG_MAP_KEY_MSK); | 269 | */ |
264 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | ||
265 | key_flags &= ~STA_KEY_FLG_INVALID; | ||
266 | |||
267 | if (keyconf->keylen == WEP_KEY_LEN_128) | ||
268 | key_flags |= STA_KEY_FLG_KEY_SIZE_MSK; | ||
269 | |||
270 | if (sta_id == ctx->bcast_sta_id) | ||
271 | key_flags |= STA_KEY_MULTICAST_MSK; | ||
272 | |||
273 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
274 | |||
275 | priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; | ||
276 | priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; | ||
277 | priv->stations[sta_id].keyinfo.keyidx = keyconf->keyidx; | ||
278 | |||
279 | memcpy(priv->stations[sta_id].keyinfo.key, | ||
280 | keyconf->key, keyconf->keylen); | ||
281 | |||
282 | memcpy(&priv->stations[sta_id].sta.key.key[3], | ||
283 | keyconf->key, keyconf->keylen); | ||
284 | |||
285 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | ||
286 | == STA_KEY_FLG_NO_ENC) | ||
287 | priv->stations[sta_id].sta.key.key_offset = | ||
288 | iwl_get_free_ucode_key_index(priv); | ||
289 | /* else, we are overriding an existing key => no need to allocated room | ||
290 | * in uCode. */ | ||
291 | 270 | ||
292 | WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, | 271 | static u8 iwlagn_key_sta_id(struct iwl_priv *priv, |
293 | "no space for a new key"); | 272 | struct ieee80211_vif *vif, |
273 | struct ieee80211_sta *sta) | ||
274 | { | ||
275 | struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; | ||
276 | u8 sta_id = IWL_INVALID_STATION; | ||
294 | 277 | ||
295 | priv->stations[sta_id].sta.key.key_flags = key_flags; | 278 | if (sta) |
296 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | 279 | sta_id = iwl_sta_id(sta); |
297 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
298 | 280 | ||
299 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | 281 | /* |
300 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 282 | * The device expects GTKs for station interfaces to be |
283 | * installed as GTKs for the AP station. If we have no | ||
284 | * station ID, then use the ap_sta_id in that case. | ||
285 | */ | ||
286 | if (!sta && vif && vif_priv->ctx) { | ||
287 | switch (vif->type) { | ||
288 | case NL80211_IFTYPE_STATION: | ||
289 | sta_id = vif_priv->ctx->ap_sta_id; | ||
290 | break; | ||
291 | default: | ||
292 | /* | ||
293 | * In all other cases, the key will be | ||
294 | * used either for TX only or is bound | ||
295 | * to a station already. | ||
296 | */ | ||
297 | break; | ||
298 | } | ||
299 | } | ||
301 | 300 | ||
302 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | 301 | return sta_id; |
303 | } | 302 | } |
304 | 303 | ||
305 | static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | 304 | static int iwlagn_send_sta_key(struct iwl_priv *priv, |
306 | struct iwl_rxon_context *ctx, | 305 | struct ieee80211_key_conf *keyconf, |
307 | struct ieee80211_key_conf *keyconf, | 306 | u8 sta_id, u32 tkip_iv32, u16 *tkip_p1k, |
308 | u8 sta_id) | 307 | u32 cmd_flags) |
309 | { | 308 | { |
310 | unsigned long flags; | 309 | unsigned long flags; |
311 | __le16 key_flags = 0; | 310 | __le16 key_flags; |
312 | struct iwl_addsta_cmd sta_cmd; | 311 | struct iwl_addsta_cmd sta_cmd; |
313 | 312 | int i; | |
314 | lockdep_assert_held(&priv->mutex); | ||
315 | |||
316 | key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK); | ||
317 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | ||
318 | key_flags &= ~STA_KEY_FLG_INVALID; | ||
319 | |||
320 | if (sta_id == ctx->bcast_sta_id) | ||
321 | key_flags |= STA_KEY_MULTICAST_MSK; | ||
322 | |||
323 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
324 | 313 | ||
325 | spin_lock_irqsave(&priv->sta_lock, flags); | 314 | spin_lock_irqsave(&priv->sta_lock, flags); |
326 | priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; | 315 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); |
327 | priv->stations[sta_id].keyinfo.keylen = keyconf->keylen; | ||
328 | |||
329 | memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, | ||
330 | keyconf->keylen); | ||
331 | |||
332 | memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, | ||
333 | keyconf->keylen); | ||
334 | |||
335 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | ||
336 | == STA_KEY_FLG_NO_ENC) | ||
337 | priv->stations[sta_id].sta.key.key_offset = | ||
338 | iwl_get_free_ucode_key_index(priv); | ||
339 | /* else, we are overriding an existing key => no need to allocated room | ||
340 | * in uCode. */ | ||
341 | |||
342 | WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, | ||
343 | "no space for a new key"); | ||
344 | |||
345 | priv->stations[sta_id].sta.key.key_flags = key_flags; | ||
346 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | ||
347 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
348 | |||
349 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | ||
350 | spin_unlock_irqrestore(&priv->sta_lock, flags); | 316 | spin_unlock_irqrestore(&priv->sta_lock, flags); |
351 | 317 | ||
352 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | 318 | key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); |
353 | } | 319 | key_flags |= STA_KEY_FLG_MAP_KEY_MSK; |
354 | |||
355 | static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, | ||
356 | struct iwl_rxon_context *ctx, | ||
357 | struct ieee80211_key_conf *keyconf, | ||
358 | u8 sta_id) | ||
359 | { | ||
360 | unsigned long flags; | ||
361 | int ret = 0; | ||
362 | __le16 key_flags = 0; | ||
363 | 320 | ||
364 | key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); | 321 | switch (keyconf->cipher) { |
365 | key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); | 322 | case WLAN_CIPHER_SUITE_CCMP: |
366 | key_flags &= ~STA_KEY_FLG_INVALID; | 323 | key_flags |= STA_KEY_FLG_CCMP; |
324 | memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen); | ||
325 | break; | ||
326 | case WLAN_CIPHER_SUITE_TKIP: | ||
327 | key_flags |= STA_KEY_FLG_TKIP; | ||
328 | sta_cmd.key.tkip_rx_tsc_byte2 = tkip_iv32; | ||
329 | for (i = 0; i < 5; i++) | ||
330 | sta_cmd.key.tkip_rx_ttak[i] = cpu_to_le16(tkip_p1k[i]); | ||
331 | memcpy(sta_cmd.key.key, keyconf->key, keyconf->keylen); | ||
332 | break; | ||
333 | case WLAN_CIPHER_SUITE_WEP104: | ||
334 | key_flags |= STA_KEY_FLG_KEY_SIZE_MSK; | ||
335 | /* fall through */ | ||
336 | case WLAN_CIPHER_SUITE_WEP40: | ||
337 | key_flags |= STA_KEY_FLG_WEP; | ||
338 | memcpy(&sta_cmd.key.key[3], keyconf->key, keyconf->keylen); | ||
339 | break; | ||
340 | default: | ||
341 | WARN_ON(1); | ||
342 | return -EINVAL; | ||
343 | } | ||
367 | 344 | ||
368 | if (sta_id == ctx->bcast_sta_id) | 345 | if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
369 | key_flags |= STA_KEY_MULTICAST_MSK; | 346 | key_flags |= STA_KEY_MULTICAST_MSK; |
370 | 347 | ||
371 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | 348 | /* key pointer (offset) */ |
372 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | 349 | sta_cmd.key.key_offset = keyconf->hw_key_idx; |
373 | 350 | ||
374 | spin_lock_irqsave(&priv->sta_lock, flags); | 351 | sta_cmd.key.key_flags = key_flags; |
375 | 352 | sta_cmd.mode = STA_CONTROL_MODIFY_MSK; | |
376 | priv->stations[sta_id].keyinfo.cipher = keyconf->cipher; | 353 | sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; |
377 | priv->stations[sta_id].keyinfo.keylen = 16; | ||
378 | |||
379 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | ||
380 | == STA_KEY_FLG_NO_ENC) | ||
381 | priv->stations[sta_id].sta.key.key_offset = | ||
382 | iwl_get_free_ucode_key_index(priv); | ||
383 | /* else, we are overriding an existing key => no need to allocated room | ||
384 | * in uCode. */ | ||
385 | |||
386 | WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, | ||
387 | "no space for a new key"); | ||
388 | |||
389 | priv->stations[sta_id].sta.key.key_flags = key_flags; | ||
390 | 354 | ||
391 | 355 | return iwl_send_add_sta(priv, &sta_cmd, cmd_flags); | |
392 | /* This copy is acutally not needed: we get the key with each TX */ | ||
393 | memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16); | ||
394 | |||
395 | memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16); | ||
396 | |||
397 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
398 | |||
399 | return ret; | ||
400 | } | 356 | } |
401 | 357 | ||
402 | void iwl_update_tkip_key(struct iwl_priv *priv, | 358 | void iwl_update_tkip_key(struct iwl_priv *priv, |
403 | struct iwl_rxon_context *ctx, | 359 | struct ieee80211_vif *vif, |
404 | struct ieee80211_key_conf *keyconf, | 360 | struct ieee80211_key_conf *keyconf, |
405 | struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) | 361 | struct ieee80211_sta *sta, u32 iv32, u16 *phase1key) |
406 | { | 362 | { |
407 | u8 sta_id; | 363 | u8 sta_id = iwlagn_key_sta_id(priv, vif, sta); |
408 | unsigned long flags; | 364 | |
409 | int i; | 365 | if (sta_id == IWL_INVALID_STATION) |
366 | return; | ||
410 | 367 | ||
411 | if (iwl_scan_cancel(priv)) { | 368 | if (iwl_scan_cancel(priv)) { |
412 | /* cancel scan failed, just live w/ bad key and rely | 369 | /* cancel scan failed, just live w/ bad key and rely |
@@ -414,121 +371,110 @@ void iwl_update_tkip_key(struct iwl_priv *priv, | |||
414 | return; | 371 | return; |
415 | } | 372 | } |
416 | 373 | ||
417 | sta_id = iwl_sta_id_or_broadcast(priv, ctx, sta); | 374 | iwlagn_send_sta_key(priv, keyconf, sta_id, |
418 | if (sta_id == IWL_INVALID_STATION) | 375 | iv32, phase1key, CMD_ASYNC); |
419 | return; | ||
420 | |||
421 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
422 | |||
423 | priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; | ||
424 | |||
425 | for (i = 0; i < 5; i++) | ||
426 | priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = | ||
427 | cpu_to_le16(phase1key[i]); | ||
428 | |||
429 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | ||
430 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
431 | |||
432 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | ||
433 | |||
434 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
435 | |||
436 | } | 376 | } |
437 | 377 | ||
438 | int iwl_remove_dynamic_key(struct iwl_priv *priv, | 378 | int iwl_remove_dynamic_key(struct iwl_priv *priv, |
439 | struct iwl_rxon_context *ctx, | 379 | struct iwl_rxon_context *ctx, |
440 | struct ieee80211_key_conf *keyconf, | 380 | struct ieee80211_key_conf *keyconf, |
441 | u8 sta_id) | 381 | struct ieee80211_sta *sta) |
442 | { | 382 | { |
443 | unsigned long flags; | 383 | unsigned long flags; |
444 | u16 key_flags; | ||
445 | u8 keyidx; | ||
446 | struct iwl_addsta_cmd sta_cmd; | 384 | struct iwl_addsta_cmd sta_cmd; |
385 | u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta); | ||
386 | |||
387 | /* if station isn't there, neither is the key */ | ||
388 | if (sta_id == IWL_INVALID_STATION) | ||
389 | return -ENOENT; | ||
390 | |||
391 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
392 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); | ||
393 | if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) | ||
394 | sta_id = IWL_INVALID_STATION; | ||
395 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
396 | |||
397 | if (sta_id == IWL_INVALID_STATION) | ||
398 | return 0; | ||
447 | 399 | ||
448 | lockdep_assert_held(&priv->mutex); | 400 | lockdep_assert_held(&priv->mutex); |
449 | 401 | ||
450 | ctx->key_mapping_keys--; | 402 | ctx->key_mapping_keys--; |
451 | 403 | ||
452 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
453 | key_flags = le16_to_cpu(priv->stations[sta_id].sta.key.key_flags); | ||
454 | keyidx = (key_flags >> STA_KEY_FLG_KEYID_POS) & 0x3; | ||
455 | |||
456 | IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n", | 404 | IWL_DEBUG_WEP(priv, "Remove dynamic key: idx=%d sta=%d\n", |
457 | keyconf->keyidx, sta_id); | 405 | keyconf->keyidx, sta_id); |
458 | 406 | ||
459 | if (keyconf->keyidx != keyidx) { | 407 | if (!test_and_clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table)) |
460 | /* We need to remove a key with index different that the one | 408 | IWL_ERR(priv, "offset %d not used in uCode key table.\n", |
461 | * in the uCode. This means that the key we need to remove has | 409 | keyconf->hw_key_idx); |
462 | * been replaced by another one with different index. | ||
463 | * Don't do anything and return ok | ||
464 | */ | ||
465 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | if (priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) { | ||
470 | IWL_WARN(priv, "Removing wrong key %d 0x%x\n", | ||
471 | keyconf->keyidx, key_flags); | ||
472 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
473 | return 0; | ||
474 | } | ||
475 | 410 | ||
476 | if (!test_and_clear_bit(priv->stations[sta_id].sta.key.key_offset, | 411 | sta_cmd.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; |
477 | &priv->ucode_key_table)) | 412 | sta_cmd.key.key_offset = WEP_INVALID_OFFSET; |
478 | IWL_ERR(priv, "index %d not used in uCode key table.\n", | 413 | sta_cmd.sta.modify_mask = STA_MODIFY_KEY_MASK; |
479 | priv->stations[sta_id].sta.key.key_offset); | 414 | sta_cmd.mode = STA_CONTROL_MODIFY_MSK; |
480 | memset(&priv->stations[sta_id].keyinfo, 0, | ||
481 | sizeof(struct iwl_hw_key)); | ||
482 | memset(&priv->stations[sta_id].sta.key, 0, | ||
483 | sizeof(struct iwl_keyinfo)); | ||
484 | priv->stations[sta_id].sta.key.key_flags = | ||
485 | STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; | ||
486 | priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; | ||
487 | priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; | ||
488 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
489 | |||
490 | if (iwl_is_rfkill(priv)) { | ||
491 | IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n"); | ||
492 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
493 | return 0; | ||
494 | } | ||
495 | memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); | ||
496 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
497 | 415 | ||
498 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); | 416 | return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); |
499 | } | 417 | } |
500 | 418 | ||
501 | int iwl_set_dynamic_key(struct iwl_priv *priv, struct iwl_rxon_context *ctx, | 419 | int iwl_set_dynamic_key(struct iwl_priv *priv, |
502 | struct ieee80211_key_conf *keyconf, u8 sta_id) | 420 | struct iwl_rxon_context *ctx, |
421 | struct ieee80211_key_conf *keyconf, | ||
422 | struct ieee80211_sta *sta) | ||
503 | { | 423 | { |
424 | struct ieee80211_key_seq seq; | ||
425 | u16 p1k[5]; | ||
504 | int ret; | 426 | int ret; |
427 | u8 sta_id = iwlagn_key_sta_id(priv, ctx->vif, sta); | ||
428 | const u8 *addr; | ||
429 | |||
430 | if (sta_id == IWL_INVALID_STATION) | ||
431 | return -EINVAL; | ||
505 | 432 | ||
506 | lockdep_assert_held(&priv->mutex); | 433 | lockdep_assert_held(&priv->mutex); |
507 | 434 | ||
435 | keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv); | ||
436 | if (keyconf->hw_key_idx == WEP_INVALID_OFFSET) | ||
437 | return -ENOSPC; | ||
438 | |||
508 | ctx->key_mapping_keys++; | 439 | ctx->key_mapping_keys++; |
509 | keyconf->hw_key_idx = HW_KEY_DYNAMIC; | ||
510 | 440 | ||
511 | switch (keyconf->cipher) { | 441 | switch (keyconf->cipher) { |
512 | case WLAN_CIPHER_SUITE_CCMP: | ||
513 | ret = iwl_set_ccmp_dynamic_key_info(priv, ctx, keyconf, sta_id); | ||
514 | break; | ||
515 | case WLAN_CIPHER_SUITE_TKIP: | 442 | case WLAN_CIPHER_SUITE_TKIP: |
516 | ret = iwl_set_tkip_dynamic_key_info(priv, ctx, keyconf, sta_id); | 443 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; |
444 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
445 | |||
446 | if (sta) | ||
447 | addr = sta->addr; | ||
448 | else /* station mode case only */ | ||
449 | addr = ctx->active.bssid_addr; | ||
450 | |||
451 | /* pre-fill phase 1 key into device cache */ | ||
452 | ieee80211_get_key_rx_seq(keyconf, 0, &seq); | ||
453 | ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k); | ||
454 | ret = iwlagn_send_sta_key(priv, keyconf, sta_id, | ||
455 | seq.tkip.iv32, p1k, CMD_SYNC); | ||
517 | break; | 456 | break; |
457 | case WLAN_CIPHER_SUITE_CCMP: | ||
458 | keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
459 | /* fall through */ | ||
518 | case WLAN_CIPHER_SUITE_WEP40: | 460 | case WLAN_CIPHER_SUITE_WEP40: |
519 | case WLAN_CIPHER_SUITE_WEP104: | 461 | case WLAN_CIPHER_SUITE_WEP104: |
520 | ret = iwl_set_wep_dynamic_key_info(priv, ctx, keyconf, sta_id); | 462 | ret = iwlagn_send_sta_key(priv, keyconf, sta_id, |
463 | 0, NULL, CMD_SYNC); | ||
521 | break; | 464 | break; |
522 | default: | 465 | default: |
523 | IWL_ERR(priv, | 466 | IWL_ERR(priv, "Unknown cipher %x\n", keyconf->cipher); |
524 | "Unknown alg: %s cipher = %x\n", __func__, | ||
525 | keyconf->cipher); | ||
526 | ret = -EINVAL; | 467 | ret = -EINVAL; |
527 | } | 468 | } |
528 | 469 | ||
529 | IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%d ret=%d\n", | 470 | if (ret) { |
471 | ctx->key_mapping_keys--; | ||
472 | clear_bit(keyconf->hw_key_idx, &priv->ucode_key_table); | ||
473 | } | ||
474 | |||
475 | IWL_DEBUG_WEP(priv, "Set dynamic key: cipher=%x len=%d idx=%d sta=%pM ret=%d\n", | ||
530 | keyconf->cipher, keyconf->keylen, keyconf->keyidx, | 476 | keyconf->cipher, keyconf->keylen, keyconf->keyidx, |
531 | sta_id, ret); | 477 | sta ? sta->addr : NULL, ret); |
532 | 478 | ||
533 | return ret; | 479 | return ret; |
534 | } | 480 | } |