2012-08-12 11:28:19

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH v2] 4-way handshake offloading

Rebased and fix in kerneldoc comments

Adding 4-way handshake offload support.

Intention is to support "smart" devices in P2P flow - they tend to
offload as much as possible.

This patch address WPA2-Personal - this is what P2P uses.
WPA2-Enterprise not supported yet.

Currently, ath6kl driver can use this feature (patch in works),
and wil6210 (60g) driver can work only in the offload mode -
working on security flow right now.

Corresponding patch for WPA supplicant almost ready (by Jouni).
for WPA supplicant, STA part verified; AP not finalized yet.

Vladimir Kondratiev (1):
cfg80211: Support for 4-way handshake offloading for WPA2-Personal

include/linux/ieee80211.h | 2 ++
include/linux/nl80211.h | 19 +++++++++++++++++++
include/net/cfg80211.h | 10 ++++++++++
net/wireless/nl80211.c | 16 ++++++++++++++++
4 files changed, 47 insertions(+)

--
1.7.9.5



2012-08-12 11:28:22

by Vladimir Kondratiev

[permalink] [raw]
Subject: [PATCH v2] cfg80211: Support for 4-way handshake offloading for WPA2-Personal

Traditionally, WPA supplicant handle 4-way handshake and do all key derivation.
First, PSK calculated from the passphrase and SSID.
Finally, PTK supplied to the driver with add_key()

For firmware to implement offload, it need PSK.
In case of WPA2-Personal, PSK is available on the connect()/start_ap() time.

In case of WPS2-Enterprise, the PSK will be available only after the EAP authentication,
this is not addressed with this patch.

Based on code from
Rishi Panjwani <[email protected]>

Signed-off-by: Vladimir Kondratiev <[email protected]>
---
include/linux/ieee80211.h | 2 ++
include/linux/nl80211.h | 19 +++++++++++++++++++
include/net/cfg80211.h | 10 ++++++++++
net/wireless/nl80211.c | 16 ++++++++++++++++
4 files changed, 47 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index e02fc68..95aafb3 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1787,6 +1787,8 @@ enum ieee80211_sa_query_action {

#define WLAN_PMKID_LEN 16

+#define WLAN_PSK_LEN 32
+
#define WLAN_OUI_WFA 0x506f9a
#define WLAN_OUI_TYPE_WFA_P2P 9
#define WLAN_OUI_MICROSOFT 0x0050f2
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2f38788..64f01a3 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1251,6 +1251,21 @@ enum nl80211_commands {
* was used to provide the hint. For the different types of
* allowed user regulatory hints see nl80211_user_reg_hint_type.
*
+ * @NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_STA: This is a flag that indicates to
+ * WPA supplicant that 4-way handshake has been offloaded to the firmware
+ * in the STA mode.
+ * In this case, WPA supplicant will provide driver with PSK for
+ * connect()
+ *
+ * @NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_AP: This is a flag that indicates to
+ * WPA supplicant that 4-way handshake has been offloaded to the firmware
+ * in the AP mode.
+ * In this case, WPA supplicant will provide driver with PSK for
+ * start_ap()
+ *
+ * @NL80211_ATTR_PSK: The PSK calculated by WPA supplicant
+ * length is WLAN_PSK_LEN (32) bytes
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1506,6 +1521,10 @@ enum nl80211_attrs {

NL80211_ATTR_USER_REG_HINT_TYPE,

+ NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_STA,
+ NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_AP,
+ NL80211_ATTR_PSK,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3d254e1..2b70ee2 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -438,6 +438,7 @@ struct cfg80211_beacon_data {
* @privacy: the BSS uses privacy
* @auth_type: Authentication type (algorithm)
* @inactivity_timeout: time in seconds to determine station's inactivity.
+ * @psk: The PSK that has been calculated by WPA supplicant
*/
struct cfg80211_ap_settings {
struct ieee80211_channel *channel;
@@ -453,6 +454,7 @@ struct cfg80211_ap_settings {
bool privacy;
enum nl80211_auth_type auth_type;
int inactivity_timeout;
+ const u8 *psk;
};

/**
@@ -1307,6 +1309,7 @@ struct cfg80211_ibss_params {
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
* will be used in ht_capa. Un-supported values will be ignored.
* @ht_capa_mask: The bits of ht_capa which are to be used.
+ * @psk: The PSK that has been calculated by WPA supplicant
*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
@@ -1324,6 +1327,7 @@ struct cfg80211_connect_params {
int bg_scan_period;
struct ieee80211_ht_cap ht_capa;
struct ieee80211_ht_cap ht_capa_mask;
+ const u8 *psk;
};

/**
@@ -1898,6 +1902,10 @@ struct cfg80211_ops {
* responds to probe-requests in hardware.
* @WIPHY_FLAG_OFFCHAN_TX: Device supports direct off-channel TX.
* @WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL: Device supports remain-on-channel call.
+ * @WIPHY_FLAG_4WAY_HANDSHAKE_OFFLOAD_STA: Device supports
+ * 4-way handshake offload in STA mode.
+ * @WIPHY_FLAG_4WAY_HANDSHAKE_OFFLOAD_AP: Device supports
+ * 4-way handshake offload in AP mode.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1921,6 +1929,8 @@ enum wiphy_flags {
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19),
WIPHY_FLAG_OFFCHAN_TX = BIT(20),
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21),
+ WIPHY_FLAG_4WAY_HANDSHAKE_OFFLOAD_STA = BIT(22),
+ WIPHY_FLAG_4WAY_HANDSHAKE_OFFLOAD_AP = BIT(23),
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 97026f3..c74f01f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -355,6 +355,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
+ [NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_STA] = { .type = NLA_FLAG },
+ [NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_AP] = { .type = NLA_FLAG },
+ [NL80211_ATTR_PSK] = { .type = NLA_BINARY,
+ .len = WLAN_PSK_LEN },
};

/* policy for the key attributes */
@@ -914,6 +918,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_4WAY_HANDSHAKE_OFFLOAD_STA) &&
+ nla_put_flag(msg, NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_STA))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_4WAY_HANDSHAKE_OFFLOAD_AP) &&
+ nla_put_flag(msg, NL80211_ATTR_4WAY_HANDSHAKE_OFFLOAD_AP))
+ goto nla_put_failure;

if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
sizeof(u32) * dev->wiphy.n_cipher_suites,
@@ -2576,6 +2586,9 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.channel_type))
return -EINVAL;

+ if (info->attrs[NL80211_ATTR_PSK])
+ params.psk = nla_data(info->attrs[NL80211_ATTR_PSK]);
+
mutex_lock(&rdev->devlist_mtx);
err = cfg80211_can_use_chan(rdev, wdev, params.channel,
CHAN_MODE_SHARED);
@@ -5640,6 +5653,9 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
sizeof(connect.ht_capa));
}

+ if (info->attrs[NL80211_ATTR_PSK])
+ connect.psk = nla_data(info->attrs[NL80211_ATTR_PSK]);
+
err = cfg80211_connect(rdev, dev, &connect, connkeys);
if (err)
kfree(connkeys);
--
1.7.9.5