Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mwl8k: Enable HW encryption for AP mode

set_key callback is defined for mac80211 to install keys for HW crypto in AP
mode. Driver currently falls back to SW crypto in STA mode. Add support to
configure the keys appropriately in the hardware after the set_key routine is
called.

Signed-off-by: Nishant Sarmukadam <nishants@marvell.com>
Signed-off-by: Pradeep Nemavat <pnemavat@marvell.com>
Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Nishant Sarmukadam and committed by
John W. Linville
fcdc403c d9a07d49

+277 -3
+277 -3
drivers/net/wireless/mwl8k.c
··· 259 259 bool is_hw_crypto_enabled; 260 260 }; 261 261 #define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv)) 262 + #define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8)) 262 263 263 264 struct mwl8k_sta { 264 265 /* Index into station database. Returned by UPDATE_STADB. */ ··· 353 352 #define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203 354 353 #define MWL8K_CMD_BSS_START 0x1100 /* per-vif */ 355 354 #define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */ 355 + #define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */ 356 356 #define MWL8K_CMD_UPDATE_STADB 0x1123 357 357 358 358 static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize) ··· 392 390 MWL8K_CMDNAME(SET_RATEADAPT_MODE); 393 391 MWL8K_CMDNAME(BSS_START); 394 392 MWL8K_CMDNAME(SET_NEW_STN); 393 + MWL8K_CMDNAME(UPDATE_ENCRYPTION); 395 394 MWL8K_CMDNAME(UPDATE_STADB); 396 395 default: 397 396 snprintf(buf, bufsize, "0x%x", cmd); ··· 3244 3241 } 3245 3242 3246 3243 /* 3244 + * CMD_UPDATE_ENCRYPTION. 3245 + */ 3246 + 3247 + #define MAX_ENCR_KEY_LENGTH 16 3248 + #define MIC_KEY_LENGTH 8 3249 + 3250 + struct mwl8k_cmd_update_encryption { 3251 + struct mwl8k_cmd_pkt header; 3252 + 3253 + __le32 action; 3254 + __le32 reserved; 3255 + __u8 mac_addr[6]; 3256 + __u8 encr_type; 3257 + 3258 + } __attribute__((packed)); 3259 + 3260 + struct mwl8k_cmd_set_key { 3261 + struct mwl8k_cmd_pkt header; 3262 + 3263 + __le32 action; 3264 + __le32 reserved; 3265 + __le16 length; 3266 + __le16 key_type_id; 3267 + __le32 key_info; 3268 + __le32 key_id; 3269 + __le16 key_len; 3270 + __u8 key_material[MAX_ENCR_KEY_LENGTH]; 3271 + __u8 tkip_tx_mic_key[MIC_KEY_LENGTH]; 3272 + __u8 tkip_rx_mic_key[MIC_KEY_LENGTH]; 3273 + __le16 tkip_rsc_low; 3274 + __le32 tkip_rsc_high; 3275 + __le16 tkip_tsc_low; 3276 + __le32 tkip_tsc_high; 3277 + __u8 mac_addr[6]; 3278 + } __attribute__((packed)); 3279 + 3280 + enum { 3281 + MWL8K_ENCR_ENABLE, 3282 + MWL8K_ENCR_SET_KEY, 3283 + MWL8K_ENCR_REMOVE_KEY, 3284 + MWL8K_ENCR_SET_GROUP_KEY, 3285 + }; 3286 + 3287 + #define MWL8K_UPDATE_ENCRYPTION_TYPE_WEP 0 3288 + #define MWL8K_UPDATE_ENCRYPTION_TYPE_DISABLE 1 3289 + #define MWL8K_UPDATE_ENCRYPTION_TYPE_TKIP 4 3290 + #define MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED 7 3291 + #define MWL8K_UPDATE_ENCRYPTION_TYPE_AES 8 3292 + 3293 + enum { 3294 + MWL8K_ALG_WEP, 3295 + MWL8K_ALG_TKIP, 3296 + MWL8K_ALG_CCMP, 3297 + }; 3298 + 3299 + #define MWL8K_KEY_FLAG_TXGROUPKEY 0x00000004 3300 + #define MWL8K_KEY_FLAG_PAIRWISE 0x00000008 3301 + #define MWL8K_KEY_FLAG_TSC_VALID 0x00000040 3302 + #define MWL8K_KEY_FLAG_WEP_TXKEY 0x01000000 3303 + #define MWL8K_KEY_FLAG_MICKEY_VALID 0x02000000 3304 + 3305 + static int mwl8k_cmd_update_encryption_enable(struct ieee80211_hw *hw, 3306 + struct ieee80211_vif *vif, 3307 + u8 *addr, 3308 + u8 encr_type) 3309 + { 3310 + struct mwl8k_cmd_update_encryption *cmd; 3311 + int rc; 3312 + 3313 + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3314 + if (cmd == NULL) 3315 + return -ENOMEM; 3316 + 3317 + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 3318 + cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3319 + cmd->action = cpu_to_le32(MWL8K_ENCR_ENABLE); 3320 + memcpy(cmd->mac_addr, addr, ETH_ALEN); 3321 + cmd->encr_type = encr_type; 3322 + 3323 + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3324 + kfree(cmd); 3325 + 3326 + return rc; 3327 + } 3328 + 3329 + static int mwl8k_encryption_set_cmd_info(struct mwl8k_cmd_set_key *cmd, 3330 + u8 *addr, 3331 + struct ieee80211_key_conf *key) 3332 + { 3333 + cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_ENCRYPTION); 3334 + cmd->header.length = cpu_to_le16(sizeof(*cmd)); 3335 + cmd->length = cpu_to_le16(sizeof(*cmd) - 3336 + offsetof(struct mwl8k_cmd_set_key, length)); 3337 + cmd->key_id = cpu_to_le32(key->keyidx); 3338 + cmd->key_len = cpu_to_le16(key->keylen); 3339 + memcpy(cmd->mac_addr, addr, ETH_ALEN); 3340 + 3341 + switch (key->cipher) { 3342 + case WLAN_CIPHER_SUITE_WEP40: 3343 + case WLAN_CIPHER_SUITE_WEP104: 3344 + cmd->key_type_id = cpu_to_le16(MWL8K_ALG_WEP); 3345 + if (key->keyidx == 0) 3346 + cmd->key_info = cpu_to_le32(MWL8K_KEY_FLAG_WEP_TXKEY); 3347 + 3348 + break; 3349 + case WLAN_CIPHER_SUITE_TKIP: 3350 + cmd->key_type_id = cpu_to_le16(MWL8K_ALG_TKIP); 3351 + cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3352 + ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 3353 + : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 3354 + cmd->key_info |= cpu_to_le32(MWL8K_KEY_FLAG_MICKEY_VALID 3355 + | MWL8K_KEY_FLAG_TSC_VALID); 3356 + break; 3357 + case WLAN_CIPHER_SUITE_CCMP: 3358 + cmd->key_type_id = cpu_to_le16(MWL8K_ALG_CCMP); 3359 + cmd->key_info = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3360 + ? cpu_to_le32(MWL8K_KEY_FLAG_PAIRWISE) 3361 + : cpu_to_le32(MWL8K_KEY_FLAG_TXGROUPKEY); 3362 + break; 3363 + default: 3364 + return -ENOTSUPP; 3365 + } 3366 + 3367 + return 0; 3368 + } 3369 + 3370 + static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw, 3371 + struct ieee80211_vif *vif, 3372 + u8 *addr, 3373 + struct ieee80211_key_conf *key) 3374 + { 3375 + struct mwl8k_cmd_set_key *cmd; 3376 + int rc; 3377 + int keymlen; 3378 + u32 action; 3379 + u8 idx; 3380 + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3381 + 3382 + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3383 + if (cmd == NULL) 3384 + return -ENOMEM; 3385 + 3386 + rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 3387 + if (rc < 0) 3388 + goto done; 3389 + 3390 + idx = key->keyidx; 3391 + 3392 + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 3393 + action = MWL8K_ENCR_SET_KEY; 3394 + else 3395 + action = MWL8K_ENCR_SET_GROUP_KEY; 3396 + 3397 + switch (key->cipher) { 3398 + case WLAN_CIPHER_SUITE_WEP40: 3399 + case WLAN_CIPHER_SUITE_WEP104: 3400 + if (!mwl8k_vif->wep_key_conf[idx].enabled) { 3401 + memcpy(mwl8k_vif->wep_key_conf[idx].key, key, 3402 + sizeof(*key) + key->keylen); 3403 + mwl8k_vif->wep_key_conf[idx].enabled = 1; 3404 + } 3405 + 3406 + keymlen = 0; 3407 + action = MWL8K_ENCR_SET_KEY; 3408 + break; 3409 + case WLAN_CIPHER_SUITE_TKIP: 3410 + keymlen = MAX_ENCR_KEY_LENGTH + 2 * MIC_KEY_LENGTH; 3411 + break; 3412 + case WLAN_CIPHER_SUITE_CCMP: 3413 + keymlen = key->keylen; 3414 + break; 3415 + default: 3416 + rc = -ENOTSUPP; 3417 + goto done; 3418 + } 3419 + 3420 + memcpy(cmd->key_material, key->key, keymlen); 3421 + cmd->action = cpu_to_le32(action); 3422 + 3423 + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3424 + done: 3425 + kfree(cmd); 3426 + 3427 + return rc; 3428 + } 3429 + 3430 + static int mwl8k_cmd_encryption_remove_key(struct ieee80211_hw *hw, 3431 + struct ieee80211_vif *vif, 3432 + u8 *addr, 3433 + struct ieee80211_key_conf *key) 3434 + { 3435 + struct mwl8k_cmd_set_key *cmd; 3436 + int rc; 3437 + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3438 + 3439 + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 3440 + if (cmd == NULL) 3441 + return -ENOMEM; 3442 + 3443 + rc = mwl8k_encryption_set_cmd_info(cmd, addr, key); 3444 + if (rc < 0) 3445 + goto done; 3446 + 3447 + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || 3448 + WLAN_CIPHER_SUITE_WEP104) 3449 + mwl8k_vif->wep_key_conf[key->keyidx].enabled = 0; 3450 + 3451 + cmd->action = cpu_to_le32(MWL8K_ENCR_REMOVE_KEY); 3452 + 3453 + rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header); 3454 + done: 3455 + kfree(cmd); 3456 + 3457 + return rc; 3458 + } 3459 + 3460 + static int mwl8k_set_key(struct ieee80211_hw *hw, 3461 + enum set_key_cmd cmd_param, 3462 + struct ieee80211_vif *vif, 3463 + struct ieee80211_sta *sta, 3464 + struct ieee80211_key_conf *key) 3465 + { 3466 + int rc = 0; 3467 + u8 encr_type; 3468 + u8 *addr; 3469 + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 3470 + 3471 + if (vif->type == NL80211_IFTYPE_STATION) 3472 + return -EOPNOTSUPP; 3473 + 3474 + if (sta == NULL) 3475 + addr = hw->wiphy->perm_addr; 3476 + else 3477 + addr = sta->addr; 3478 + 3479 + if (cmd_param == SET_KEY) { 3480 + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 3481 + rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key); 3482 + if (rc) 3483 + goto out; 3484 + 3485 + if ((key->cipher == WLAN_CIPHER_SUITE_WEP40) 3486 + || (key->cipher == WLAN_CIPHER_SUITE_WEP104)) 3487 + encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_WEP; 3488 + else 3489 + encr_type = MWL8K_UPDATE_ENCRYPTION_TYPE_MIXED; 3490 + 3491 + rc = mwl8k_cmd_update_encryption_enable(hw, vif, addr, 3492 + encr_type); 3493 + if (rc) 3494 + goto out; 3495 + 3496 + mwl8k_vif->is_hw_crypto_enabled = true; 3497 + 3498 + } else { 3499 + rc = mwl8k_cmd_encryption_remove_key(hw, vif, addr, key); 3500 + 3501 + if (rc) 3502 + goto out; 3503 + 3504 + mwl8k_vif->is_hw_crypto_enabled = false; 3505 + 3506 + } 3507 + out: 3508 + return rc; 3509 + } 3510 + 3511 + /* 3247 3512 * CMD_UPDATE_STADB. 3248 3513 */ 3249 3514 struct ewc_ht_info { ··· 4281 4010 { 4282 4011 struct mwl8k_priv *priv = hw->priv; 4283 4012 int ret; 4013 + int i; 4014 + struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif); 4015 + struct ieee80211_key_conf *key; 4284 4016 4285 4017 if (!priv->ap_fw) { 4286 4018 ret = mwl8k_cmd_update_stadb_add(hw, vif, sta); 4287 4019 if (ret >= 0) { 4288 4020 MWL8K_STA(sta)->peer_id = ret; 4289 - return 0; 4021 + ret = 0; 4290 4022 } 4291 4023 4292 4024 } else { 4293 4025 ret = mwl8k_cmd_set_new_stn_add(hw, vif, sta); 4294 - return ret; 4295 4026 } 4296 4027 4297 4028 for (i = 0; i < NUM_WEP_KEYS; i++) { ··· 4301 4028 if (mwl8k_vif->wep_key_conf[i].enabled) 4302 4029 mwl8k_set_key(hw, SET_KEY, vif, sta, key); 4303 4030 } 4304 - return mwl8k_cmd_set_new_stn_add(hw, vif, sta); 4031 + return ret; 4305 4032 } 4306 4033 4307 4034 static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, ··· 4379 4106 .bss_info_changed = mwl8k_bss_info_changed, 4380 4107 .prepare_multicast = mwl8k_prepare_multicast, 4381 4108 .configure_filter = mwl8k_configure_filter, 4109 + .set_key = mwl8k_set_key, 4382 4110 .set_rts_threshold = mwl8k_set_rts_threshold, 4383 4111 .sta_add = mwl8k_sta_add, 4384 4112 .sta_remove = mwl8k_sta_remove,