From 5146ac8a430f625daf77cbb8bb2f5c6a8cb6473f Mon Sep 17 00:00:00 2001
From: Javier Cardona <javier@cozybit.com>
Date: Wed, 10 Sep 2008 19:37:41 -0700
Subject: [PATCH] libertas: Reduce the WPA key installation time.
WPA requires that the PTK is installed immediately after the 4-way handshake
in order to properly decrypt the subsequent incoming EAPOL-GTK frame. If the
PTK is not enabled by the time the EAPOL-GTK frame arrives, the frame is
dropped and the supplicant does not receive the group key.
This will happen with fast Access Points that send the EAPOL-GTK frame before
the suplicant has successfully installed and enabled the PTK. To mitigate
this situation, this patch simplifies and accelerates the SIOCSIWENCODEEXT
execution.
---
drivers/net/wireless/libertas/assoc.c | 12 +-----
drivers/net/wireless/libertas/cmd.c | 64 +++++++++++-------------------
drivers/net/wireless/libertas/cmd.h | 1 +
drivers/net/wireless/libertas/hostcmd.h | 2 +
drivers/net/wireless/libertas/wext.c | 16 ++++++-
5 files changed, 42 insertions(+), 53 deletions(-)
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index 4d27de3..2238e04 100644
|
a
|
b
|
|
| 358 | 358 | |
| 359 | 359 | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { |
| 360 | 360 | clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); |
| 361 | | ret = lbs_prepare_and_send_command(priv, |
| 362 | | CMD_802_11_KEY_MATERIAL, |
| 363 | | CMD_ACT_SET, |
| 364 | | CMD_OPTION_WAITFORRSP, |
| 365 | | 0, assoc_req); |
| | 361 | ret = lbs_set_key_material(priv, &assoc_req->wpa_unicast_key); |
| 366 | 362 | assoc_req->flags = flags; |
| 367 | 363 | } |
| 368 | 364 | |
| … |
… |
|
| 372 | 368 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { |
| 373 | 369 | clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); |
| 374 | 370 | |
| 375 | | ret = lbs_prepare_and_send_command(priv, |
| 376 | | CMD_802_11_KEY_MATERIAL, |
| 377 | | CMD_ACT_SET, |
| 378 | | CMD_OPTION_WAITFORRSP, |
| 379 | | 0, assoc_req); |
| | 371 | ret = lbs_set_key_material(priv, &assoc_req->wpa_mcast_key); |
| 380 | 372 | assoc_req->flags = flags; |
| 381 | 373 | } |
| 382 | 374 | |
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 41f51a2..ac7c0c7 100644
|
a
|
b
|
|
| 419 | 419 | lbs_deb_leave(LBS_DEB_CMD); |
| 420 | 420 | } |
| 421 | 421 | |
| 422 | | static int lbs_cmd_802_11_key_material(struct lbs_private *priv, |
| 423 | | struct cmd_ds_command *cmd, |
| 424 | | u16 cmd_action, |
| 425 | | u32 cmd_oid, void *pdata_buf) |
| | 422 | /** |
| | 423 | * @brief Set key material |
| | 424 | * |
| | 425 | * @param priv A pointer to struct lbs_private structure |
| | 426 | * @param key A pointer to key material |
| | 427 | * |
| | 428 | * @return 0 on success, error on failure |
| | 429 | */ |
| | 430 | int lbs_set_key_material(struct lbs_private *priv, struct enc_key *key) |
| 426 | 431 | { |
| 427 | | struct cmd_ds_802_11_key_material *pkeymaterial = |
| 428 | | &cmd->params.keymaterial; |
| 429 | | struct assoc_request * assoc_req = pdata_buf; |
| | 432 | struct cmd_ds_802_11_key_material cmd; |
| 430 | 433 | int ret = 0; |
| 431 | | int index = 0; |
| 432 | 434 | |
| 433 | 435 | lbs_deb_enter(LBS_DEB_CMD); |
| 434 | 436 | |
| 435 | | cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL); |
| 436 | | pkeymaterial->action = cpu_to_le16(cmd_action); |
| 437 | | |
| 438 | | if (cmd_action == CMD_ACT_GET) { |
| 439 | | cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action)); |
| 440 | | ret = 0; |
| 441 | | goto done; |
| 442 | | } |
| 443 | | |
| 444 | | memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet)); |
| 445 | | |
| 446 | | if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { |
| 447 | | set_one_wpa_key(&pkeymaterial->keyParamSet[index], |
| 448 | | &assoc_req->wpa_unicast_key); |
| 449 | | index++; |
| 450 | | } |
| 451 | | |
| 452 | | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { |
| 453 | | set_one_wpa_key(&pkeymaterial->keyParamSet[index], |
| 454 | | &assoc_req->wpa_mcast_key); |
| 455 | | index++; |
| 456 | | } |
| | 437 | memset(&cmd, 0, sizeof(cmd)); |
| | 438 | cmd.hdr.size = cpu_to_le16(sizeof(cmd)); |
| | 439 | cmd.action = cpu_to_le16(CMD_ACT_SET); |
| 457 | 440 | |
| 458 | | cmd->size = cpu_to_le16( S_DS_GEN |
| 459 | | + sizeof (pkeymaterial->action) |
| 460 | | + (index * sizeof(struct MrvlIEtype_keyParamSet))); |
| | 441 | memset(cmd.keyParamSet, 0, sizeof(cmd.keyParamSet)); |
| | 442 | set_one_wpa_key(&cmd.keyParamSet[0], key); |
| 461 | 443 | |
| 462 | | ret = 0; |
| | 444 | ret = lbs_cmd_with_response(priv, CMD_802_11_KEY_MATERIAL, &cmd); |
| | 445 | if (ret) |
| | 446 | goto out; |
| 463 | 447 | |
| 464 | | done: |
| | 448 | if (key->flags & KEY_INFO_WPA_ENABLED) |
| | 449 | lbs_deb_cmd("SET_WPA_KEY: %s%s installed\n", |
| | 450 | key->flags & KEY_INFO_WPA_UNICAST ? "PTK" : "", |
| | 451 | key->flags & KEY_INFO_WPA_MCAST ? "GTK" : ""); |
| | 452 | out: |
| 465 | 453 | lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); |
| 466 | 454 | return ret; |
| 467 | 455 | } |
| … |
… |
|
| 1501 | 1489 | ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr); |
| 1502 | 1490 | break; |
| 1503 | 1491 | |
| 1504 | | case CMD_802_11_KEY_MATERIAL: |
| 1505 | | ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action, |
| 1506 | | cmd_oid, pdata_buf); |
| 1507 | | break; |
| 1508 | | |
| 1509 | 1492 | case CMD_802_11_PAIRWISE_TSC: |
| 1510 | 1493 | break; |
| | 1494 | |
| 1511 | 1495 | case CMD_802_11_GROUP_TSC: |
| 1512 | 1496 | break; |
| 1513 | 1497 | |
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 12cb089..ef93697 100644
|
a
|
b
|
|
| 36 | 36 | |
| 37 | 37 | int lbs_get_data_rate(struct lbs_private *priv); |
| 38 | 38 | int lbs_set_data_rate(struct lbs_private *priv, u8 rate); |
| | 39 | int lbs_set_key_material(struct lbs_private *priv, struct enc_key *key); |
| 39 | 40 | |
| 40 | 41 | int lbs_get_channel(struct lbs_private *priv); |
| 41 | 42 | int lbs_set_channel(struct lbs_private *priv, u8 channel); |
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index f2dad51..63dc8e8 100644
|
a
|
b
|
|
| 599 | 599 | |
| 600 | 600 | |
| 601 | 601 | struct cmd_ds_802_11_key_material { |
| | 602 | struct cmd_header hdr; |
| | 603 | |
| 602 | 604 | __le16 action; |
| 603 | 605 | struct MrvlIEtype_keyParamSet keyParamSet[2]; |
| 604 | 606 | } __attribute__ ((packed)); |
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 0bd2fbf..fc67718 100644
|
a
|
b
|
|
| 30 | 30 | queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); |
| 31 | 31 | } |
| 32 | 32 | |
| | 33 | static inline void lbs_do_association_work(struct lbs_private *priv) |
| | 34 | { |
| | 35 | if (priv->surpriseremoved) |
| | 36 | return; |
| | 37 | cancel_delayed_work(&priv->assoc_work); |
| | 38 | queue_delayed_work(priv->work_thread, &priv->assoc_work, 0); |
| | 39 | } |
| | 40 | |
| 33 | 41 | static inline void lbs_cancel_association_work(struct lbs_private *priv) |
| 34 | 42 | { |
| 35 | 43 | cancel_delayed_work(&priv->assoc_work); |
| … |
… |
|
| 1608 | 1616 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); |
| 1609 | 1617 | } |
| 1610 | 1618 | |
| 1611 | | disable_wep (assoc_req); |
| | 1619 | /* Only disable wep if necessary: can't waste time here. */ |
| | 1620 | if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE) |
| | 1621 | disable_wep(assoc_req); |
| 1612 | 1622 | } |
| 1613 | 1623 | |
| 1614 | 1624 | out: |
| 1615 | | if (ret == 0) { |
| 1616 | | lbs_postpone_association_work(priv); |
| | 1625 | if (ret == 0) { /* key installation is time critical: postpone not! */ |
| | 1626 | lbs_do_association_work(priv); |
| 1617 | 1627 | } else { |
| 1618 | 1628 | lbs_cancel_association_work(priv); |
| 1619 | 1629 | } |