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