aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwl8k.c
diff options
context:
space:
mode:
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 2b76bbc5e61..809f2bf2795 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,