2017-06-09 12:09:00

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 0/9] nl80211: add support for PTK/GTK handshake offload


This patch series add support for offloading the PTK/GTK handshakes for
WPA/WPA2-Personal and 802.1X in nl80211. The nl80211 patches have been
posted as RFC. Compared to that RFC this series also adds a new flag
ATTR_PORT_AUTHORIZED used in both CONNECT and ROAM notifications to
indicate the driver has completed the offloads successfully and the
encryption keys for the connection are applied. Another change is the
addition of the flag ATTR_WANT_1X_4WAY_HS that user-space has to pass
in CONNECT request. Some drivers may need to be aware before the PMK
is programmed through SET_PMK request.

This series also comes with driver implementation in brcmfmac although
it does not use the authorized flag in the ROAM event (yet).

The series applies to the master branch of the mac80211-next repository.

V2:
- changed patch 2/9 addressing comments from Johannes.
V3:
- added documentation section in nl80211.h.

Arend van Spriel (6):
nl80211: add authorized flag to CONNECT event
nl80211: remove desciption about request from NL80211_CMD_ROAM
brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK
brcmfmac: support 4-way handshake offloading for 802.1X
brcmfmac: switch to using cfg80211_connect_done()
brcmfmac: provide port authorized state in CONNECT event

Avraham Stern (2):
cfg80211: support 4-way handshake offloading for 802.1X
nl80211: add authorized flag to ROAM event

Eliad Peller (1):
cfg80211: support 4-way handshake offloading for WPA/WPA2-PSK

.../broadcom/brcm80211/brcmfmac/cfg80211.c | 159 +++++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/cfg80211.h | 15 +-
.../wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 +
.../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +-
.../wireless/broadcom/brcm80211/brcmfmac/fweh.h | 30 ++++
.../wireless/broadcom/brcm80211/brcmfmac/fwil.h | 1 +
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 16 +++
include/linux/ieee80211.h | 4 +
include/net/cfg80211.h | 41 ++++++
include/uapi/linux/nl80211.h | 73 +++++++++-
net/wireless/core.c | 5 +
net/wireless/nl80211.c | 120 +++++++++++++++-
net/wireless/rdev-ops.h | 25 ++++
net/wireless/sme.c | 2 +
net/wireless/trace.h | 60 ++++++++
15 files changed, 533 insertions(+), 23 deletions(-)

--
1.9.1


2017-06-13 09:02:06

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH V3 3/9] nl80211: add authorized flag to CONNECT event

On Fri, 2017-06-09 at 13:08 +0100, Arend van Spriel wrote:
> When the driver supports offloading of the PTK/GTK handshakes
> completion of that during connect changes the layer 2 control
> port state to authorized. This patch allows the driver to pass
> that state in cfg80211_connect_done() resulting in adding the
> new flag NL80211_ATTR_PORT_AUTHORIZED in the NL80211_CMD_CONNECT
> notification. For 802.1X the driver is expected to issue the
> NL80211_CMD_CONNECT notification twice. First without the new
> attribute to inform user-space that 802.1X authentication can
> start and a second one with the new attribute to indicate the
> completion of the handshakes.

So I was going to apply this, but now I'm no longer sure.

First of all, I'm concerned it could confuse older tools that don't
expect to see the notification twice. OTOH, they'd get the connected
notification now and not really know whether or not data can be passed,
so it seems unlikely they'd rely on it - but are we really sure about
that?

Additionally, I just discussed this with Avi, and it's not clear to us
what the second notification is actually useful for? If you were going
to say maybe it makes sense for when you can't send ROAMED, but still
connected again to the same network so you've already done the 4-way-HS
at the time of the first notification - that I think makes sense.

But it seems that wpa_s moves all state machines to COMPLETE when it
sends the PMK to the device for offload, so it won't really care about
when that finished?

However, I think this might actually be a BAD thing, because it would
leave higher layers trying to do DHCP when the link isn't actually
ready yet.

(This, btw, is another problem we can solve with the EAPOL-over-nl80211
since then we can set the carrier later when the port is authorized.)

So - I have no objections to this patch, but I think the double
notification needs to be revised, and if needed a separate notification
for "4-way-HS is done now" can be added.

johannes

2017-06-09 12:09:02

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 5/9] nl80211: remove desciption about request from NL80211_CMD_ROAM

The description of NL80211_CMD_ROAM indicated possibility for a
request to roam issued by user-space. However, it also states that
as not being implemented right now. This has been so since commit
b23aa676ab9d ("cfg80211: connect/disconnect API") added in 2009.
So it seems safe to assume it will not be added any time soon and
thus remove it.

Signed-off-by: Arend van Spriel <[email protected]>
---
include/uapi/linux/nl80211.h | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c792234..c931263 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -569,14 +569,13 @@
* authentication/association or not receiving a response from the AP.
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
* well to remain backwards compatible.
- * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
- * sent as an event when the card/driver roamed by itself.
- * When used as an event, and the driver roamed in a network that requires
- * 802.1X authentication, %NL80211_ATTR_PORT_AUTHORIZED should be set
- * if the 802.1X authentication was done by the driver or if roaming was
- * done using Fast Transition protocol (in which case 802.1X authentication
- * is not needed). If %NL80211_ATTR_PORT_AUTHORIZED is not set, user space
- * is responsible for the 802.1X authentication.
+ * @NL80211_CMD_ROAM: notifcation indicating the card/driver roamed by itself.
+ * When the driver roamed in a network that requires 802.1X authentication,
+ * %NL80211_ATTR_PORT_AUTHORIZED should be set if the 802.1X authentication
+ * was done by the driver or if roaming was done using Fast Transition
+ * protocol (in which case 802.1X authentication is not needed). If
+ * %NL80211_ATTR_PORT_AUTHORIZED is not set, user space is responsible for
+ * the 802.1X authentication.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
--
1.9.1

2017-06-09 12:09:02

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 9/9] brcmfmac: provide port authorized state in CONNECT event

Fill struct cfg80211_connection_params::authorized field according
the supplicant state received from the device.

Signed-off-by: Arend van Spriel <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 27 +++++++++++++---------
1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 9d345c7..0e45993 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5327,10 +5327,12 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
u32 event = e->event_code;
u32 status = e->status;

- if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
- event == BRCMF_E_PSK_SUP &&
- status == BRCMF_E_STATUS_FWSUP_COMPLETED)
+ if (event == BRCMF_E_PSK_SUP &&
+ status == BRCMF_E_STATUS_FWSUP_COMPLETED) {
set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
+ if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_1X)
+ return true;
+ }
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
brcmf_dbg(CONN, "Processing set ssid\n");
memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
@@ -5341,11 +5343,9 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
}

if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
- test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
- clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
- clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
+ test_and_clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state))
return true;
- }
+
return false;
}

@@ -5542,22 +5542,27 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(TRACE, "Enter\n");

if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
- &ifp->vif->sme_state)) {
+ &ifp->vif->sme_state) ||
+ e->event_code == BRCMF_E_PSK_SUP) {
memset(&conn_params, 0, sizeof(conn_params));
- if (completed) {
+ if (e->event_code != BRCMF_E_PSK_SUP && completed) {
brcmf_get_assoc_ies(cfg, ifp);
brcmf_update_bss_info(cfg, ifp);
set_bit(BRCMF_VIF_STATUS_CONNECTED,
&ifp->vif->sme_state);
+ }
+ if (completed)
conn_params.status = WLAN_STATUS_SUCCESS;
- } else {
+ else
conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
- }
conn_params.bssid = profile->bssid;
conn_params.req_ie = conn_info->req_ie;
conn_params.req_ie_len = conn_info->req_ie_len;
conn_params.resp_ie = conn_info->resp_ie;
conn_params.resp_ie_len = conn_info->resp_ie_len;
+ conn_params.authorized =
+ test_and_clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS,
+ &ifp->vif->sme_state);
cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
brcmf_dbg(CONN, "Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
--
1.9.1

2017-06-09 12:09:00

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 3/9] nl80211: add authorized flag to CONNECT event

When the driver supports offloading of the PTK/GTK handshakes
completion of that during connect changes the layer 2 control
port state to authorized. This patch allows the driver to pass
that state in cfg80211_connect_done() resulting in adding the
new flag NL80211_ATTR_PORT_AUTHORIZED in the NL80211_CMD_CONNECT
notification. For 802.1X the driver is expected to issue the
NL80211_CMD_CONNECT notification twice. First without the new
attribute to inform user-space that 802.1X authentication can
start and a second one with the new attribute to indicate the
completion of the handshakes.

Signed-off-by: Arend van Spriel <[email protected]>
---
include/net/cfg80211.h | 3 +++
include/uapi/linux/nl80211.h | 4 ++++
net/wireless/nl80211.c | 2 ++
net/wireless/sme.c | 1 +
4 files changed, 10 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 2174e51..7097310 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5280,6 +5280,8 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
* not known. This value is used only if @status < 0 to indicate that the
* failure is due to a timeout and not due to explicit rejection by the AP.
* This value is ignored in other cases (@status >= 0).
+ * @authorized: Indicates whether the connection is ready to transport
+ * data packets.
*/
struct cfg80211_connect_resp_params {
int status;
@@ -5297,6 +5299,7 @@ struct cfg80211_connect_resp_params {
size_t pmk_len;
const u8 *pmkid;
enum nl80211_timeout_reason timeout_reason;
+ bool authorized;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 2f49275..6f139a3 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2130,6 +2130,9 @@ enum nl80211_commands {
* in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it
* wants to use the supported offload of the 4-way handshake.
* @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
+ * @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_CONNECT
+ * notification indicating that PTK/GTK handshakes for 802.1X have been
+ * completed successfully.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2555,6 +2558,7 @@ enum nl80211_attrs {

NL80211_ATTR_WANT_1X_4WAY_HS,
NL80211_ATTR_PMKR0_NAME,
+ NL80211_ATTR_PORT_AUTHORIZED,

/* add attributes here, update the policy in nl80211.c */

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8148b01..d0bf6bd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13745,6 +13745,8 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
(nla_put_flag(msg, NL80211_ATTR_TIMED_OUT) ||
nla_put_u32(msg, NL80211_ATTR_TIMEOUT_REASON,
cr->timeout_reason))) ||
+ (cr->authorized &&
+ nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)) ||
(cr->req_ie &&
nla_put(msg, NL80211_ATTR_REQ_IE, cr->req_ie_len, cr->req_ie)) ||
(cr->resp_ie &&
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 532a000..a46eda8 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -861,6 +861,7 @@ void cfg80211_connect_done(struct net_device *dev,
ev->cr.bss = params->bss;
ev->cr.status = params->status;
ev->cr.timeout_reason = params->timeout_reason;
+ ev->cr.authorized = params->authorized;

spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
--
1.9.1

2017-06-30 06:42:54

by Kalle Valo

[permalink] [raw]
Subject: Re: [V3, 6/9] brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK

Arend Van Spriel <[email protected]> wrote:

> From: Arend van Spriel <[email protected]>
>
> The firmware may have supplicant code built-in. This is detected
> by the driver and indicated in the wiphy features flags. User-space
> can use this flag to determine whether or not to provide the
> pre-shared key material in the nl80211 CONNECT command.
>
> Reviewed-by: Gautam (Gautam Kumar) Shukla <[email protected]>
> Reviewed-by: Hante Meuleman <[email protected]>
> Reviewed-by: Pieter-Paul Giesberts <[email protected]>
> Signed-off-by: Arend van Spriel <[email protected]>

Manually applied to wireless-drivers-next, thanks.

b8a64f0e96c2 brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK
2526ff21aa77 brcmfmac: support 4-way handshake offloading for 802.1X
123fef3fd4ae brcmfmac: switch to using cfg80211_connect_done()

There was a simple conflict in feature.h on patch 1 and git was also
auto-merging quite a lot. So please check the resolution in
wireless-drivers-next and let me know if there are any problems.

--
https://patchwork.kernel.org/patch/9778339/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2017-06-09 12:09:02

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 8/9] brcmfmac: switch to using cfg80211_connect_done()

The driver used cfg80211_connect_result() which is basically a wrapper
around cfg80211_connect_done() passing a subset of the information that
can be passed. For upcoming functionality this is not sufficient so
switching to use cfg80211_connect_done().

Reviewed-by: Hante Meuleman <[email protected]>
Reviewed-by: Pieter-Paul Giesberts <[email protected]>
Reviewed-by: Franky Lin <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
.../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index cc5b8ba..9d345c7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5537,26 +5537,28 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
+ struct cfg80211_connect_resp_params conn_params;

brcmf_dbg(TRACE, "Enter\n");

if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING,
&ifp->vif->sme_state)) {
+ memset(&conn_params, 0, sizeof(conn_params));
if (completed) {
brcmf_get_assoc_ies(cfg, ifp);
brcmf_update_bss_info(cfg, ifp);
set_bit(BRCMF_VIF_STATUS_CONNECTED,
&ifp->vif->sme_state);
+ conn_params.status = WLAN_STATUS_SUCCESS;
+ } else {
+ conn_params.status = WLAN_STATUS_AUTH_TIMEOUT;
}
- cfg80211_connect_result(ndev,
- (u8 *)profile->bssid,
- conn_info->req_ie,
- conn_info->req_ie_len,
- conn_info->resp_ie,
- conn_info->resp_ie_len,
- completed ? WLAN_STATUS_SUCCESS :
- WLAN_STATUS_AUTH_TIMEOUT,
- GFP_KERNEL);
+ conn_params.bssid = profile->bssid;
+ conn_params.req_ie = conn_info->req_ie;
+ conn_params.req_ie_len = conn_info->req_ie_len;
+ conn_params.resp_ie = conn_info->resp_ie;
+ conn_params.resp_ie_len = conn_info->resp_ie_len;
+ cfg80211_connect_done(ndev, &conn_params, GFP_KERNEL);
brcmf_dbg(CONN, "Report connect result - connection %s\n",
completed ? "succeeded" : "failed");
}
--
1.9.1

2017-06-09 12:09:03

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 7/9] brcmfmac: support 4-way handshake offloading for 802.1X

Adding callbacks for PMK provisioning. If firmware supports offloading
it is indicated to user-space that 802.1X offload is supported.

Signed-off-by: Arend van Spriel <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 61 ++++++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/cfg80211.h | 3 +-
2 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 27a89dc..cc5b8ba 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1704,6 +1704,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
{
struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
s32 val;
s32 err;
const struct brcmf_tlv *rsn_ie;
@@ -1714,6 +1715,8 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
u32 mfp;
u16 count;

+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
+
if (!sme->crypto.n_akm_suites)
return 0;

@@ -1726,6 +1729,8 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA_AUTH_UNSPECIFIED;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
break;
case WLAN_AKM_SUITE_PSK:
val = WPA_AUTH_PSK;
@@ -1739,9 +1744,13 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA2_AUTH_UNSPECIFIED;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
break;
case WLAN_AKM_SUITE_8021X_SHA256:
val = WPA2_AUTH_1X_SHA256;
+ if (sme->want_1x)
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X;
break;
case WLAN_AKM_SUITE_PSK_SHA256:
val = WPA2_AUTH_PSK_SHA256;
@@ -1756,6 +1765,9 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
}
}

+ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X)
+ brcmf_dbg(INFO, "using 1X offload\n");
+
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
goto skip_mfp_config;
/* The MFP mode (1 or 2) needs to be determined, parse IEs. The
@@ -1928,6 +1940,7 @@ static void brcmf_set_join_pref(struct brcmf_if *ifp,
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
struct ieee80211_channel *chan = sme->channel;
struct brcmf_join_params join_params;
size_t join_params_size;
@@ -2025,16 +2038,24 @@ static void brcmf_set_join_pref(struct brcmf_if *ifp,
}

if (sme->crypto.psk) {
+ if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) {
+ err = -EINVAL;
+ goto done;
+ }
brcmf_dbg(INFO, "using PSK offload\n");
+ profile->use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
+ }

+ if (profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
/* enable firmware supplicant for this interface */
err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
if (err < 0) {
brcmf_err("failed to enable fw supplicant\n");
goto done;
}
- ifp->vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
+ }

+ if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) {
err = brcmf_set_pmk(ifp, sme->crypto.psk,
BRCMF_WSEC_MAX_PSK_LEN);
if (err)
@@ -5173,6 +5194,34 @@ static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
}
#endif

+static int brcmf_cfg80211_set_pmk(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_pmk_conf *conf)
+{
+ struct brcmf_if *ifp;
+
+ brcmf_dbg(TRACE, "enter\n");
+
+ /* expect using firmware supplicant for 1X */
+ ifp = netdev_priv(dev);
+ if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
+ return -EINVAL;
+
+ return brcmf_set_pmk(ifp, conf->pmk, conf->pmk_len);
+}
+
+static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *aa)
+{
+ struct brcmf_if *ifp;
+
+ brcmf_dbg(TRACE, "enter\n");
+ ifp = netdev_priv(dev);
+ if (WARN_ON(ifp->vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_1X))
+ return -EINVAL;
+
+ return brcmf_set_pmk(ifp, NULL, 0);
+}
+
static struct cfg80211_ops brcmf_cfg80211_ops = {
.add_virtual_intf = brcmf_cfg80211_add_iface,
.del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -5216,6 +5265,8 @@ static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
.crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
.tdls_oper = brcmf_cfg80211_tdls_oper,
.update_connect_params = brcmf_cfg80211_update_conn_params,
+ .set_pmk = brcmf_cfg80211_set_pmk,
+ .del_pmk = brcmf_cfg80211_del_pmk,
};

struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
@@ -5276,7 +5327,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
u32 event = e->event_code;
u32 status = e->status;

- if (event == BRCMF_E_PSK_SUP &&
+ if (vif->profile.use_fwsup == BRCMF_PROFILE_FWSUP_PSK &&
+ event == BRCMF_E_PSK_SUP &&
status == BRCMF_E_STATUS_FWSUP_COMPLETED)
set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
@@ -6545,9 +6597,12 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
if (!ifp->drvr->settings->roamoff)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP))
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP)) {
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X);
+ }
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 779e9b5..c6b6fbb 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -115,7 +115,8 @@ struct brcmf_cfg80211_security {

enum brcmf_profile_fwsup {
BRCMF_PROFILE_FWSUP_NONE,
- BRCMF_PROFILE_FWSUP_PSK
+ BRCMF_PROFILE_FWSUP_PSK,
+ BRCMF_PROFILE_FWSUP_1X
};

/**
--
1.9.1

2017-06-14 09:14:48

by Arend Van Spriel

[permalink] [raw]
Subject: Re: [PATCH V3 3/9] nl80211: add authorized flag to CONNECT event



On 6/13/2017 11:02 AM, Johannes Berg wrote:
> On Fri, 2017-06-09 at 13:08 +0100, Arend van Spriel wrote:
>> When the driver supports offloading of the PTK/GTK handshakes
>> completion of that during connect changes the layer 2 control
>> port state to authorized. This patch allows the driver to pass
>> that state in cfg80211_connect_done() resulting in adding the
>> new flag NL80211_ATTR_PORT_AUTHORIZED in the NL80211_CMD_CONNECT
>> notification. For 802.1X the driver is expected to issue the
>> NL80211_CMD_CONNECT notification twice. First without the new
>> attribute to inform user-space that 802.1X authentication can
>> start and a second one with the new attribute to indicate the
>> completion of the handshakes.
>
> So I was going to apply this, but now I'm no longer sure.

Not sure if this means you can be convinced, but let me try anyway ;-)

> First of all, I'm concerned it could confuse older tools that don't
> expect to see the notification twice. OTOH, they'd get the connected
> notification now and not really know whether or not data can be passed,
> so it seems unlikely they'd rely on it - but are we really sure about
> that?

Not sure what should be considered under the term "older tools". For
what it is worth, in wpa_supplicant both nl80211 CONNECT and ROAMED
event result in wpa_supplicant ASSOC event handled in
wpa_supplicant/events.c. This event already deals with authorized flag
to support QCA vendor stuff which typed it as u8 attribute iso flag.

> Additionally, I just discussed this with Avi, and it's not clear to us
> what the second notification is actually useful for? If you were going
> to say maybe it makes sense for when you can't send ROAMED, but still
> connected again to the same network so you've already done the 4-way-HS
> at the time of the first notification - that I think makes sense.
>
> But it seems that wpa_s moves all state machines to COMPLETE when it
> sends the PMK to the device for offload, so it won't really care about
> when that finished?
>
> However, I think this might actually be a BAD thing, because it would
> leave higher layers trying to do DHCP when the link isn't actually
> ready yet.

Indeed. It introduces a window where the link is not ready. When I
stumbled on that in wpa_s it made sense to me to have the second
notification.

> (This, btw, is another problem we can solve with the EAPOL-over-nl80211
> since then we can set the carrier later when the port is authorized.)

Agree. I did see that thread. However I kinda missed the whole
EAPOL-over-nl80211 idea. Was that result of summit discussion?

> So - I have no objections to this patch, but I think the double
> notification needs to be revised, and if needed a separate notification
> for "4-way-HS is done now" can be added.

The separate notification was suggested, but as you guys already added a
flag in the ROAMED event we decided to do the same for CONNECT event. If
you still have concerns about the double CONNECT we can revisit that or
leave it for now and deal with it through carrier state with
EAPOL-over-nl80211.

Regards,
Arend

2017-06-09 12:09:00

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 2/9] cfg80211: support 4-way handshake offloading for 802.1X

From: Avraham Stern <[email protected]>

Add API for setting the PMK to the driver. For FT support, allow
setting also the PMK-R0 Name.

This can be used by drivers that support 4-Way handshake offload
while IEEE802.1X authentication is managed by upper layers.

Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
[[email protected]: add WANT_1X_4WAY_HS attribute]
Signed-off-by: Arend van Spriel <[email protected]>
---
V2:
- rename ATTR_WANT_1X_OFFLOAD to ATTR_WANT_1X_4WAY_HS.
- add remarks about driver dealing with PMK clearing upon disconnect.
V3:
- - added documentation about EAPOL handshake offload for 802.1X.
---
include/linux/ieee80211.h | 3 ++
include/net/cfg80211.h | 32 +++++++++++++
include/uapi/linux/nl80211.h | 38 +++++++++++++++-
net/wireless/core.c | 5 +++
net/wireless/nl80211.c | 105 +++++++++++++++++++++++++++++++++++++++++++
net/wireless/rdev-ops.h | 25 +++++++++++
net/wireless/trace.h | 60 +++++++++++++++++++++++++
7 files changed, 267 insertions(+), 1 deletion(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index e97ca3a..34e1bcd 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2400,8 +2400,11 @@ enum ieee80211_sa_query_action {

#define WLAN_MAX_KEY_LEN 32

+#define WLAN_PMK_NAME_LEN 16
#define WLAN_PMKID_LEN 16
+#define WLAN_PMK_LEN_EAP_LEAP 16
#define WLAN_PMK_LEN 32
+#define WLAN_PMK_LEN_SUITE_B_192 48

#define WLAN_OUI_WFA 0x506f9a
#define WLAN_OUI_TYPE_WFA_P2P 9
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1b288ba..2174e51 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2112,6 +2112,8 @@ struct cfg80211_bss_selection {
* @fils_erp_rrk: ERP re-authentication Root Key (rRK) used to derive additional
* keys in FILS or %NULL if not specified.
* @fils_erp_rrk_len: Length of @fils_erp_rrk in octets.
+ * @want_1x: indicates user-space supports and wants to use 802.1X driver
+ * offload of 4-way handshake.
*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
@@ -2144,6 +2146,7 @@ struct cfg80211_connect_params {
u16 fils_erp_next_seq_num;
const u8 *fils_erp_rrk;
size_t fils_erp_rrk_len;
+ bool want_1x;
};

/**
@@ -2566,6 +2569,23 @@ struct cfg80211_nan_func {
};

/**
+ * struct cfg80211_pmk_conf - PMK configuration
+ *
+ * @aa: authenticator address
+ * @pmk_len: PMK length in bytes.
+ * @pmk: the PMK material
+ * @pmk_r0_name: PMK-R0 Name. NULL if not applicable (i.e., the PMK
+ * is not PMK-R0). When pmk_r0_name is not NULL, the pmk field
+ * holds PMK-R0.
+ */
+struct cfg80211_pmk_conf {
+ const u8 *aa;
+ u8 pmk_len;
+ const u8 *pmk;
+ const u8 *pmk_r0_name;
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2881,6 +2901,13 @@ struct cfg80211_nan_func {
* All other parameters must be ignored.
*
* @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ *
+ * @set_pmk: configure the PMK to be used for offloaded 802.1X 4-Way handshake.
+ * If not deleted through @del_pmk the PMK remains valid until disconnect
+ * upon which the driver should clear it.
+ * (invoked with the wireless_dev mutex held)
+ * @del_pmk: delete the previously configured PMK for the given authenticator.
+ * (invoked with the wireless_dev mutex held)
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3169,6 +3196,11 @@ struct cfg80211_ops {
int (*set_multicast_to_unicast)(struct wiphy *wiphy,
struct net_device *dev,
const bool enabled);
+
+ int (*set_pmk)(struct wiphy *wiphy, struct net_device *dev,
+ const struct cfg80211_pmk_conf *conf);
+ int (*del_pmk)(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *aa);
};

/*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index fc244c3..2f49275 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -182,6 +182,17 @@
* this offload may reject the %NL80211_CMD_CONNECT when no preshared
* key material is provided, for example when that driver does not
* support setting the temporal keys through %CMD_NEW_KEY.
+ *
+ * Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be
+ * set by drivers indicating offload support of the PTK/GTK EAPOL
+ * handshakes during 802.1X authentication. In order to use the offload
+ * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS
+ * attribute flag. Drivers supporting this offload may reject the
+ * %NL80211_CMD_CONNECT when the attribute flag is not present.
+ *
+ * For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK
+ * using %NL80211_CMD_SET_PMK. For offloaded FT support also
+ * %NL80211_ATTR_PMKR0_NAME must be provided.
*/

/**
@@ -959,6 +970,14 @@
* does not result in a change for the current association. Currently,
* only the %NL80211_ATTR_IE data is used and updated with this command.
*
+ * @NL80211_CMD_SET_PMK: For offloaded 4-Way handshake, set the PMK or PMK-R0
+ * for the given authenticator address (specified with &NL80211_ATTR_MAC).
+ * When &NL80211_ATTR_PMKR0_NAME is set, &NL80211_ATTR_PMK specifies the
+ * PMK-R0, otherwise it specifies the PMK.
+ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
+ * configured PMK for the authenticator address identified by
+ * &NL80211_ATTR_MAC.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1158,6 +1177,9 @@ enum nl80211_commands {

NL80211_CMD_UPDATE_CONNECT_PARAMS,

+ NL80211_CMD_SET_PMK,
+ NL80211_CMD_DEL_PMK,
+
/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
@@ -2095,13 +2117,20 @@ enum nl80211_commands {
* @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
* %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
* For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
- * handshake for WPA/WPA2-PSK networks.
+ * handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is
+ * used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute
+ * specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well.
*
* @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
* indicate that it supports multiple active scheduled scan requests.
* @NL80211_ATTR_SCHED_SCAN_MAX_REQS: indicates maximum number of scheduled
* scan request that may be active for the device (u32).
*
+ * @NL80211_ATTR_WANT_1X_4WAY_HS: flag attribute which user-space can include
+ * in %NL80211_CMD_CONNECT to indicate that for 802.1X authentication it
+ * wants to use the supported offload of the 4-way handshake.
+ * @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2524,6 +2553,9 @@ enum nl80211_attrs {
NL80211_ATTR_SCHED_SCAN_MULTI,
NL80211_ATTR_SCHED_SCAN_MAX_REQS,

+ NL80211_ATTR_WANT_1X_4WAY_HS,
+ NL80211_ATTR_PMKR0_NAME,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -4869,6 +4901,9 @@ enum nl80211_feature_flags {
* @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device supports doing 4-way
* handshake with PSK in station mode (PSK is passed as part of the connect
* and associate commands).
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X: Device supports doing 4-way
+ * handshake with 802.1X in station mode (needs to pass EAP frames to
+ * the host and accept the set_pmk/del_pmk commands).
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4890,6 +4925,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_CQM_RSSI_LIST,
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,

/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 83ea164..7b33e8c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -711,6 +711,11 @@ int wiphy_register(struct wiphy *wiphy)
(wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2))))
return -EINVAL;

+ if (WARN_ON(wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X) &&
+ (!rdev->ops->set_pmk || !rdev->ops->del_pmk)))
+ return -EINVAL;
+
if (wiphy->addresses)
memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2c6863a..8148b01 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8881,6 +8881,12 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)

connect.privacy = info->attrs[NL80211_ATTR_PRIVACY];

+ if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] &&
+ !wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+ return -EINVAL;
+ connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS];
+
err = nl80211_crypto_settings(rdev, info, &connect.crypto,
NL80211_MAX_NR_CIPHER_SUITES);
if (err)
@@ -12265,6 +12271,90 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
return rdev_set_multicast_to_unicast(rdev, dev, enabled);
}

+static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_pmk_conf pmk_conf = {};
+ int ret;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
+
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK])
+ return -EINVAL;
+
+ wdev_lock(wdev);
+ if (!wdev->current_bss) {
+ ret = -ENOTCONN;
+ goto out;
+ }
+
+ pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+ pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]);
+ if (pmk_conf.pmk_len != WLAN_PMK_LEN &&
+ pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (info->attrs[NL80211_ATTR_PMKR0_NAME]) {
+ int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]);
+
+ if (r0_name_len != WLAN_PMK_NAME_LEN) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pmk_conf.pmk_r0_name =
+ nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]);
+ }
+
+ ret = rdev_set_pmk(rdev, dev, &pmk_conf);
+out:
+ wdev_unlock(wdev);
+ return ret;
+}
+
+static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ const u8 *aa;
+ int ret;
+
+ if (wdev->iftype != NL80211_IFTYPE_STATION &&
+ wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+ return -EOPNOTSUPP;
+
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X))
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ wdev_lock(wdev);
+ aa = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ ret = rdev_del_pmk(rdev, dev, aa);
+ wdev_unlock(wdev);
+
+ return ret;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -13140,6 +13230,21 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_SET_PMK,
+ .doit = nl80211_set_pmk,
+ .policy = nl80211_policy,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_PMK,
+ .doit = nl80211_del_pmk,
+ .policy = nl80211_policy,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+
};

static struct genl_family nl80211_fam __ro_after_init = {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 0598c1e..ce23d7d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1164,4 +1164,29 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
+
+static inline int rdev_set_pmk(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_pmk_conf *pmk_conf)
+{
+ int ret = -EOPNOTSUPP;
+
+ trace_rdev_set_pmk(&rdev->wiphy, dev, pmk_conf);
+ if (rdev->ops->set_pmk)
+ ret = rdev->ops->set_pmk(&rdev->wiphy, dev, pmk_conf);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *aa)
+{
+ int ret = -EOPNOTSUPP;
+
+ trace_rdev_del_pmk(&rdev->wiphy, dev, aa);
+ if (rdev->ops->del_pmk)
+ ret = rdev->ops->del_pmk(&rdev->wiphy, dev, aa);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ca8b205..0f8db41 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2258,6 +2258,66 @@
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(addr))
);

+TRACE_EVENT(rdev_set_pmk,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_pmk_conf *pmk_conf),
+
+ TP_ARGS(wiphy, netdev, pmk_conf),
+
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(aa)
+ __field(u8, pmk_len)
+ __field(u8, pmk_r0_name_len)
+ __dynamic_array(u8, pmk, pmk_conf->pmk_len)
+ __dynamic_array(u8, pmk_r0_name, WLAN_PMK_NAME_LEN)
+ ),
+
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(aa, pmk_conf->aa);
+ __entry->pmk_len = pmk_conf->pmk_len;
+ __entry->pmk_r0_name_len =
+ pmk_conf->pmk_r0_name ? WLAN_PMK_NAME_LEN : 0;
+ memcpy(__get_dynamic_array(pmk), pmk_conf->pmk,
+ pmk_conf->pmk_len);
+ memcpy(__get_dynamic_array(pmk_r0_name), pmk_conf->pmk_r0_name,
+ pmk_conf->pmk_r0_name ? WLAN_PMK_NAME_LEN : 0);
+ ),
+
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT
+ "pmk_len=%u, pmk: %s pmk_r0_name: %s", WIPHY_PR_ARG,
+ NETDEV_PR_ARG, MAC_PR_ARG(aa), __entry->pmk_len,
+ __print_array(__get_dynamic_array(pmk),
+ __get_dynamic_array_len(pmk), 1),
+ __entry->pmk_r0_name_len ?
+ __print_array(__get_dynamic_array(pmk_r0_name),
+ __get_dynamic_array_len(pmk_r0_name), 1) : "")
+);
+
+TRACE_EVENT(rdev_del_pmk,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *aa),
+
+ TP_ARGS(wiphy, netdev, aa),
+
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ MAC_ENTRY(aa)
+ ),
+
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ MAC_ASSIGN(aa, aa);
+ ),
+
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(aa))
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
--
1.9.1

2017-06-14 20:28:48

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH V3 3/9] nl80211: add authorized flag to CONNECT event


> > So I was going to apply this, but now I'm no longer sure.
>
> Not sure if this means you can be convinced, but let me try anyway ;-)

:-)

> > First of all, I'm concerned it could confuse older tools that don't
> > expect to see the notification twice. OTOH, they'd get the
> > connected
> > notification now and not really know whether or not data can be
> > passed,
> > so it seems unlikely they'd rely on it - but are we really sure
> > about
> > that?
>
> Not sure what should be considered under the term "older tools". For 
> what it is worth, in wpa_supplicant both nl80211 CONNECT and ROAMED 
> event result in wpa_supplicant ASSOC event handled in 
> wpa_supplicant/events.c. This event already deals with authorized
> flag  to support QCA vendor stuff which typed it as u8 attribute iso
> flag.

Yeah, I guess wpa_s would deal with it just fine. I'm a little
concerned there might be other tools, and we'd only find out in a long
time when all of this comes together for enough users.

OTOH, most tools that aren't already quite broken will hopefully use
wpa_supplicant events.

> > But it seems that wpa_s moves all state machines to COMPLETE when
> > it sends the PMK to the device for offload, so it won't really care
> > about when that finished?
> >
> > However, I think this might actually be a BAD thing, because it
> > would leave higher layers trying to do DHCP when the link isn't
> > actually ready yet.
>
> Indeed. It introduces a window where the link is not ready. When I 
> stumbled on that in wpa_s it made sense to me to have the second 
> notification.

Right.

> > (This, btw, is another problem we can solve with the EAPOL-over-
> > nl80211 since then we can set the carrier later when the port is
> > authorized.)
>
> Agree. I did see that thread. However I kinda missed the whole 
> EAPOL-over-nl80211 idea. Was that result of summit discussion?

Yeah it came up a few times and we finally decided it's worth doing,
but so far nobody had stepped up yet. Looks like Denis decided it might
be worth doing.

> > So - I have no objections to this patch, but I think the double
> > notification needs to be revised, and if needed a separate
> > notification for "4-way-HS is done now" can be added.
>
> The separate notification was suggested, but as you guys already
> added a flag in the ROAMED event we decided to do the same for
> CONNECT event. If you still have concerns about the double CONNECT we
> can revisit that or leave it for now and deal with it through carrier
> state with EAPOL-over-nl80211.

For ROAMED the case is clearer: it can either happen with or without
the attribute, but it'll never happen twice because of the attribute.
Also, if the attribute is ignored by some tool, it's pretty harmless
since it'll still know that it was roaming, it just won't know that no
EAP authentication is needed.

I think I'd be OK with adding a new notification, but EAPOL-over-
nl80211 seems like it'd solve this, and then we don't need the extra
notification since we can just set the carrier after it's all
complete... I don't really know. If we can wait a bit for this, I think
it'd be the nicer thing, and it looks like the currently existing code
has the race and is still working OK for people.

johannes

2017-06-13 09:06:01

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH V3 0/9] nl80211: add support for PTK/GTK handshake offload

On Fri, 2017-06-09 at 13:08 +0100, Arend van Spriel wrote:
>
> Arend van Spriel (6):
>   nl80211: add authorized flag to CONNECT event

I skipped this.

>   nl80211: remove desciption about request from NL80211_CMD_ROAM

applied

>   brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK
>   brcmfmac: support 4-way handshake offloading for 802.1X
>   brcmfmac: switch to using cfg80211_connect_done()
>   brcmfmac: provide port authorized state in CONNECT event

For Kalle later.

> Avraham Stern (2):
>   cfg80211: support 4-way handshake offloading for 802.1X
>   nl80211: add authorized flag to ROAM event
>
> Eliad Peller (1):
>   cfg80211: support 4-way handshake offloading for WPA/WPA2-PSK

Applied.

Thanks a lot Arend for taking care of all this!

johannes

2017-06-09 12:09:00

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 4/9] nl80211: add authorized flag to ROAM event

From: Avraham Stern <[email protected]>

Drivers that initiate roaming while being connected to a network that
uses 802.1X authentication need to inform user space if 802.1X
authentication is further required after roaming.
For example, when using the Fast transition protocol, roaming within
the mobility domain does not require new 802.1X authentication, but
roaming to another mobility domain does.
In addition, some drivers may not support 802.1X authentication
(so it has to be done in user space), while other drivers do.

Add a flag to the roaming notification to indicate if user space is
required to do 802.1X authentication after the roaming or not.
This flag will only be used for networks that use 802.1X
authentication. For networks that do not use 802.1X authentication it
is assumed that no further action is required from user space after
the roaming notification.

Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
[[email protected] reuse NL80211_ATTR_PORT_AUTHORIZED]
Signed-off-by: Arend van Spriel <[email protected]>
---
include/net/cfg80211.h | 4 ++++
include/uapi/linux/nl80211.h | 10 +++++++++-
net/wireless/nl80211.c | 4 +++-
net/wireless/sme.c | 1 +
4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7097310..6160c49 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5444,6 +5444,9 @@ void cfg80211_connect_done(struct net_device *dev,
* @req_ie_len: association request IEs length
* @resp_ie: association response IEs (may be %NULL)
* @resp_ie_len: assoc response IEs length
+ * @authorized: true if the 802.1X authentication was done by the driver or is
+ * not needed (e.g., when Fast Transition protocol was used), false
+ * otherwise. Ignored for networks that don't use 802.1X authentication.
*/
struct cfg80211_roam_info {
struct ieee80211_channel *channel;
@@ -5453,6 +5456,7 @@ struct cfg80211_roam_info {
size_t req_ie_len;
const u8 *resp_ie;
size_t resp_ie_len;
+ bool authorized;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6f139a3..c792234 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -571,6 +571,12 @@
* well to remain backwards compatible.
* @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
* sent as an event when the card/driver roamed by itself.
+ * When used as an event, and the driver roamed in a network that requires
+ * 802.1X authentication, %NL80211_ATTR_PORT_AUTHORIZED should be set
+ * if the 802.1X authentication was done by the driver or if roaming was
+ * done using Fast Transition protocol (in which case 802.1X authentication
+ * is not needed). If %NL80211_ATTR_PORT_AUTHORIZED is not set, user space
+ * is responsible for the 802.1X authentication.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
* userspace that a connection was dropped by the AP or due to other
* reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
@@ -2132,7 +2138,9 @@ enum nl80211_commands {
* @NL80211_ATTR_PMKR0_NAME: PMK-R0 Name for offloaded FT.
* @NL80211_ATTR_PORT_AUTHORIZED: flag attribute used in %NL80211_CMD_CONNECT
* notification indicating that PTK/GTK handshakes for 802.1X have been
- * completed successfully.
+ * completed successfully. Also used in %NL80211_CMD_ROAM to indicate
+ * that 802.1X authentication was done by the driver or is not needed
+ * (because roaming used the Fast Transition protocol).
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0bf6bd..4bcc8d3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13802,7 +13802,9 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
info->req_ie)) ||
(info->resp_ie &&
nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len,
- info->resp_ie)))
+ info->resp_ie)) ||
+ (info->authorized &&
+ nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))
goto nla_put_failure;

genlmsg_end(msg, hdr);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index a46eda8..9eb9234 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -961,6 +961,7 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
ev->rm.resp_ie_len = info->resp_ie_len;
memcpy((void *)ev->rm.resp_ie, info->resp_ie, info->resp_ie_len);
ev->rm.bss = info->bss;
+ ev->rm.authorized = info->authorized;

spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
--
1.9.1

2017-06-30 06:24:04

by Kalle Valo

[permalink] [raw]
Subject: Re: [V3, 6/9] brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK

Arend Van Spriel <[email protected]> wrote:

> From: Arend van Spriel <[email protected]>
>
> The firmware may have supplicant code built-in. This is detected
> by the driver and indicated in the wiphy features flags. User-space
> can use this flag to determine whether or not to provide the
> pre-shared key material in the nl80211 CONNECT command.
>
> Reviewed-by: Gautam (Gautam Kumar) Shukla <[email protected]>
> Reviewed-by: Hante Meuleman <[email protected]>
> Reviewed-by: Pieter-Paul Giesberts <[email protected]>
> Signed-off-by: Arend van Spriel <[email protected]>

Really sorry, I forgot to include this in today's pull request. My excuse this
time is that I'm on vacation and not really at full speed :)

--
https://patchwork.kernel.org/patch/9778339/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2017-06-09 12:09:00

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 1/9] cfg80211: support 4-way handshake offloading for WPA/WPA2-PSK

From: Eliad Peller <[email protected]>

Let drivers advertise support for station-mode 4-way handshake
offloading with a new NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag.

Extend use of NL80211_ATTR_PMK attribute indicating it might be passed
as part of NL80211_CMD_CONNECT command, and contain the PSK (which is
the PMK, hence the name.)

The driver/device is assumed to handle the 4-way handshake by
itself in this case (including key derivations, etc.), instead
of relying on the supplicant.

This patch is somewhat based on this one (by Vladimir Kondratiev):
https://patchwork.kernel.org/patch/1309561/.

Signed-off-by: Vladimir Kondratiev <[email protected]>
Signed-off-by: Eliad Peller <[email protected]>
Signed-off-by: Luca Coelho <[email protected]>
Signed-off-by: Johannes Berg <[email protected]>
[[email protected] rebase dealing with existing ATTR_PMK]
Signed-off-by: Arend van Spriel <[email protected]>
---
V3:
- added documentation about EAPOL handshake offload for WPA-PSK.
---
include/linux/ieee80211.h | 1 +
include/net/cfg80211.h | 2 ++
include/uapi/linux/nl80211.h | 22 ++++++++++++++++++++--
net/wireless/nl80211.c | 9 +++++++++
4 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 6903335..e97ca3a 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -2401,6 +2401,7 @@ enum ieee80211_sa_query_action {
#define WLAN_MAX_KEY_LEN 32

#define WLAN_PMKID_LEN 16
+#define WLAN_PMK_LEN 32

#define WLAN_OUI_WFA 0x506f9a
#define WLAN_OUI_TYPE_WFA_P2P 9
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index fa25fbb..1b288ba 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -649,6 +649,7 @@ struct survey_info {
* @wep_keys: static WEP keys, if not NULL points to an array of
* CFG80211_MAX_WEP_KEYS WEP keys
* @wep_tx_key: key index (0..3) of the default TX static WEP key
+ * @psk: PSK (for devices supporting 4-way-handshake offload)
*/
struct cfg80211_crypto_settings {
u32 wpa_versions;
@@ -662,6 +663,7 @@ struct cfg80211_crypto_settings {
bool control_port_no_encrypt;
struct key_params *wep_keys;
int wep_tx_key;
+ const u8 *psk;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b8c44b9..fc244c3 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -173,6 +173,18 @@
*/

/**
+ * DOC: WPA/WPA2 EAPOL handshake offload
+ *
+ * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers
+ * can indicate they support offloading EAPOL handshakes for WPA/WPA2
+ * preshared key authentication. In %NL80211_CMD_CONNECT the preshared
+ * key should be specified using %NL80211_ATTR_PMK. Drivers supporting
+ * this offload may reject the %NL80211_CMD_CONNECT when no preshared
+ * key material is provided, for example when that driver does not
+ * support setting the temporal keys through %CMD_NEW_KEY.
+ */
+
+/**
* DOC: FILS shared key authentication offload
*
* FILS shared key authentication offload can be advertized by drivers by
@@ -2080,8 +2092,10 @@ enum nl80211_commands {
* identifying the scope of PMKSAs. This is used with
* @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
*
- * @NL80211_ATTR_PMK: PMK for the PMKSA identified by %NL80211_ATTR_PMKID.
- * This is used with @NL80211_CMD_SET_PMKSA.
+ * @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with
+ * %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID.
+ * For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way
+ * handshake for WPA/WPA2-PSK networks.
*
* @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to
* indicate that it supports multiple active scheduled scan requests.
@@ -4852,6 +4866,9 @@ enum nl80211_feature_flags {
* RSSI threshold values to monitor rather than exactly one threshold.
* @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD: Driver SME supports FILS shared key
* authentication with %NL80211_CMD_CONNECT.
+ * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK: Device supports doing 4-way
+ * handshake with PSK in station mode (PSK is passed as part of the connect
+ * and associate commands).
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4872,6 +4889,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
NL80211_EXT_FEATURE_CQM_RSSI_LIST,
NL80211_EXT_FEATURE_FILS_SK_OFFLOAD,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,

/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9eb5919..2c6863a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8168,6 +8168,15 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
memcpy(settings->akm_suites, data, len);
}

+ if (info->attrs[NL80211_ATTR_PMK]) {
+ if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN)
+ return -EINVAL;
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK))
+ return -EINVAL;
+ settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]);
+ }
+
return 0;
}

--
1.9.1

2017-06-14 05:10:00

by Kalle Valo

[permalink] [raw]
Subject: Re: [V3, 6/9] brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK

Arend Van Spriel <[email protected]> wrote:

> From: Arend van Spriel <[email protected]>
>
> The firmware may have supplicant code built-in. This is detected
> by the driver and indicated in the wiphy features flags. User-space
> can use this flag to determine whether or not to provide the
> pre-shared key material in the nl80211 CONNECT command.
>
> Reviewed-by: Gautam (Gautam Kumar) Shukla <[email protected]>
> Reviewed-by: Hante Meuleman <[email protected]>
> Reviewed-by: Pieter-Paul Giesberts <[email protected]>
> Signed-off-by: Arend van Spriel <[email protected]>

Depends on:

3a00df5707b6 cfg80211: support 4-way handshake offloading for 802.1X

Currently in net-next.

--
https://patchwork.kernel.org/patch/9778339/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2017-06-09 12:09:03

by Arend Van Spriel

[permalink] [raw]
Subject: [PATCH V3 6/9] brcmfmac: support 4-way handshake offloading for WPA/WPA2-PSK

From: Arend van Spriel <[email protected]>

The firmware may have supplicant code built-in. This is detected
by the driver and indicated in the wiphy features flags. User-space
can use this flag to determine whether or not to provide the
pre-shared key material in the nl80211 CONNECT command.

Reviewed-by: Gautam (Gautam Kumar) Shukla <[email protected]>
Reviewed-by: Hante Meuleman <[email protected]>
Reviewed-by: Pieter-Paul Giesberts <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 75 ++++++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/cfg80211.h | 14 +++-
.../wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 +
.../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +-
.../wireless/broadcom/brcm80211/brcmfmac/fweh.h | 30 +++++++++
.../wireless/broadcom/brcm80211/brcmfmac/fwil.h | 1 +
.../broadcom/brcm80211/brcmfmac/fwil_types.h | 16 +++++
7 files changed, 134 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index cd1d673..27a89dc 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -1344,6 +1344,27 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
return reason;
}

+static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len)
+{
+ struct brcmf_wsec_pmk_le pmk;
+ int i, err;
+
+ /* convert to firmware key format */
+ pmk.key_len = cpu_to_le16(pmk_len << 1);
+ pmk.flags = cpu_to_le16(BRCMF_WSEC_PASSPHRASE);
+ for (i = 0; i < pmk_len; i++)
+ snprintf(&pmk.key[2 * i], 3, "%02x", pmk_data[i]);
+
+ /* store psk in firmware */
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK,
+ &pmk, sizeof(pmk));
+ if (err < 0)
+ brcmf_err("failed to change PSK in firmware (len=%u)\n",
+ pmk_len);
+
+ return err;
+}
+
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
@@ -1366,6 +1387,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
+ if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_NONE) {
+ brcmf_set_pmk(vif->ifp, NULL, 0);
+ vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_NONE;
+ }
brcmf_dbg(TRACE, "Exit\n");
}

@@ -1999,6 +2024,23 @@ static void brcmf_set_join_pref(struct brcmf_if *ifp,
goto done;
}

+ if (sme->crypto.psk) {
+ brcmf_dbg(INFO, "using PSK offload\n");
+
+ /* enable firmware supplicant for this interface */
+ err = brcmf_fil_iovar_int_set(ifp, "sup_wpa", 1);
+ if (err < 0) {
+ brcmf_err("failed to enable fw supplicant\n");
+ goto done;
+ }
+ ifp->vif->profile.use_fwsup = BRCMF_PROFILE_FWSUP_PSK;
+
+ err = brcmf_set_pmk(ifp, sme->crypto.psk,
+ BRCMF_WSEC_MAX_PSK_LEN);
+ if (err)
+ goto done;
+ }
+
/* Join with specific BSSID and cached SSID
* If SSID is zero join based on BSSID only
*/
@@ -5228,16 +5270,30 @@ void brcmf_cfg80211_free_netdev(struct net_device *ndev)
free_netdev(ndev);
}

-static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
+static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,
+ const struct brcmf_event_msg *e)
{
u32 event = e->event_code;
u32 status = e->status;

+ if (event == BRCMF_E_PSK_SUP &&
+ status == BRCMF_E_STATUS_FWSUP_COMPLETED)
+ set_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
brcmf_dbg(CONN, "Processing set ssid\n");
- return true;
+ memcpy(vif->profile.bssid, e->addr, ETH_ALEN);
+ if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK)
+ return true;
+
+ set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
}

+ if (test_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state) &&
+ test_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state)) {
+ clear_bit(BRCMF_VIF_STATUS_EAP_SUCCESS, &vif->sme_state);
+ clear_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state);
+ return true;
+ }
return false;
}

@@ -5272,6 +5328,13 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
return true;
}

+ if (event == BRCMF_E_PSK_SUP &&
+ status != BRCMF_E_STATUS_FWSUP_COMPLETED) {
+ brcmf_dbg(CONN, "Processing failed supplicant state: %u\n",
+ status);
+ return true;
+ }
+
return false;
}

@@ -5429,7 +5492,6 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,
&ifp->vif->sme_state)) {
if (completed) {
brcmf_get_assoc_ies(cfg, ifp);
- memcpy(profile->bssid, e->addr, ETH_ALEN);
brcmf_update_bss_info(cfg, ifp);
set_bit(BRCMF_VIF_STATUS_CONNECTED,
&ifp->vif->sme_state);
@@ -5508,7 +5570,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg,

if (brcmf_is_apmode(ifp->vif)) {
err = brcmf_notify_connect_status_ap(cfg, ndev, e, data);
- } else if (brcmf_is_linkup(e)) {
+ } else if (brcmf_is_linkup(ifp->vif, e)) {
brcmf_dbg(CONN, "Linkup\n");
if (brcmf_is_ibssmode(ifp->vif)) {
brcmf_inform_ibss(cfg, ndev, e->addr);
@@ -5676,6 +5738,8 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
brcmf_p2p_notify_action_tx_complete);
brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE,
brcmf_p2p_notify_action_tx_complete);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_PSK_SUP,
+ brcmf_notify_connect_status);
}

static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
@@ -6481,6 +6545,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
if (!ifp->drvr->settings->roamoff)
wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWSUP))
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK);
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 8f19d95..779e9b5 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -113,6 +113,11 @@ struct brcmf_cfg80211_security {
u32 cipher_group;
};

+enum brcmf_profile_fwsup {
+ BRCMF_PROFILE_FWSUP_NONE,
+ BRCMF_PROFILE_FWSUP_PSK
+};
+
/**
* struct brcmf_cfg80211_profile - profile information.
*
@@ -124,6 +129,7 @@ struct brcmf_cfg80211_profile {
u8 bssid[ETH_ALEN];
struct brcmf_cfg80211_security sec;
struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
+ enum brcmf_profile_fwsup use_fwsup;
};

/**
@@ -131,16 +137,20 @@ struct brcmf_cfg80211_profile {
*
* @BRCMF_VIF_STATUS_READY: ready for operation.
* @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress.
- * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully.
+ * @BRCMF_VIF_STATUS_CONNECTED: connected/joined successfully.
* @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress.
* @BRCMF_VIF_STATUS_AP_CREATED: AP operation started.
+ * @BRCMF_VIF_STATUS_EAP_SUCCUSS: EAPOL handshake successful.
+ * @BRCMF_VIF_STATUS_ASSOC_SUCCESS: successful SET_SSID received.
*/
enum brcmf_vif_status {
BRCMF_VIF_STATUS_READY,
BRCMF_VIF_STATUS_CONNECTING,
BRCMF_VIF_STATUS_CONNECTED,
BRCMF_VIF_STATUS_DISCONNECTING,
- BRCMF_VIF_STATUS_AP_CREATED
+ BRCMF_VIF_STATUS_AP_CREATED,
+ BRCMF_VIF_STATUS_EAP_SUCCESS,
+ BRCMF_VIF_STATUS_ASSOC_SUCCESS,
};

/**
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 62985f2..05bd939 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -175,6 +175,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
drvr->settings->feature_disable);
ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
}
+ brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");

/* set chip related quirks */
switch (drvr->bus_if->chip) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index db4733a..a0a846b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -31,6 +31,7 @@
* WOWL_GTK: (WOWL) GTK rekeying offload
* WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
* MFP: 802.11w Management Frame Protection.
+ * FWSUP: Firmware supplicant.
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@@ -44,7 +45,8 @@
BRCMF_FEAT_DEF(WOWL_ND) \
BRCMF_FEAT_DEF(WOWL_GTK) \
BRCMF_FEAT_DEF(WOWL_ARP_ND) \
- BRCMF_FEAT_DEF(MFP)
+ BRCMF_FEAT_DEF(MFP) \
+ BRCMF_FEAT_DEF(FWSUP)

/*
* Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
index 5fba4b4..816f80e 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
@@ -142,6 +142,16 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_STATUS_CS_ABORT 15
#define BRCMF_E_STATUS_ERROR 16

+/* status field values for PSK_SUP event */
+#define BRCMF_E_STATUS_FWSUP_WAIT_M1 4
+#define BRCMF_E_STATUS_FWSUP_PREP_M2 5
+#define BRCMF_E_STATUS_FWSUP_COMPLETED 6
+#define BRCMF_E_STATUS_FWSUP_TIMEOUT 7
+#define BRCMF_E_STATUS_FWSUP_WAIT_M3 8
+#define BRCMF_E_STATUS_FWSUP_PREP_M4 9
+#define BRCMF_E_STATUS_FWSUP_WAIT_G1 10
+#define BRCMF_E_STATUS_FWSUP_PREP_G2 11
+
/* reason field values in struct brcmf_event_msg */
#define BRCMF_E_REASON_INITIAL_ASSOC 0
#define BRCMF_E_REASON_LOW_RSSI 1
@@ -161,6 +171,26 @@ enum brcmf_fweh_event_code {
#define BRCMF_E_REASON_TDLS_PEER_CONNECTED 1
#define BRCMF_E_REASON_TDLS_PEER_DISCONNECTED 2

+/* reason field values for PSK_SUP event */
+#define BRCMF_E_REASON_FWSUP_OTHER 0
+#define BRCMF_E_REASON_FWSUP_DECRYPT_KEY_DATA 1
+#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP128 2
+#define BRCMF_E_REASON_FWSUP_BAD_UCAST_WEP40 3
+#define BRCMF_E_REASON_FWSUP_UNSUP_KEY_LEN 4
+#define BRCMF_E_REASON_FWSUP_PW_KEY_CIPHER 5
+#define BRCMF_E_REASON_FWSUP_MSG3_TOO_MANY_IE 6
+#define BRCMF_E_REASON_FWSUP_MSG3_IE_MISMATCH 7
+#define BRCMF_E_REASON_FWSUP_NO_INSTALL_FLAG 8
+#define BRCMF_E_REASON_FWSUP_MSG3_NO_GTK 9
+#define BRCMF_E_REASON_FWSUP_GRP_KEY_CIPHER 10
+#define BRCMF_E_REASON_FWSUP_GRP_MSG1_NO_GTK 11
+#define BRCMF_E_REASON_FWSUP_GTK_DECRYPT_FAIL 12
+#define BRCMF_E_REASON_FWSUP_SEND_FAIL 13
+#define BRCMF_E_REASON_FWSUP_DEAUTH 14
+#define BRCMF_E_REASON_FWSUP_WPA_PSK_TMO 15
+#define BRCMF_E_REASON_FWSUP_WPA_PSK_M1_TMO 16
+#define BRCMF_E_REASON_FWSUP_WPA_PSK_M3_TMO 17
+
/* action field values for brcmf_ifevent */
#define BRCMF_E_IF_ADD 1
#define BRCMF_E_IF_DEL 2
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
index 3a9a76d..63b1287 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -85,6 +85,7 @@
#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258
#define BRCMF_C_GET_VAR 262
#define BRCMF_C_SET_VAR 263
+#define BRCMF_C_SET_WSEC_PMK 268

s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
index 9a1eb5a..8b89507 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h
@@ -45,6 +45,9 @@
#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff
#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16

+#define BRCMF_WSEC_MAX_PSK_LEN 32
+#define BRCMF_WSEC_PASSPHRASE BIT(0)
+
/* primary (ie tx) key */
#define BRCMF_PRIMARY_KEY (1 << 1)
#define DOT11_BSSTYPE_ANY 2
@@ -470,6 +473,19 @@ struct brcmf_wsec_key_le {
u8 ea[ETH_ALEN]; /* per station */
};

+/**
+ * struct brcmf_wsec_pmk_le - firmware pmk material.
+ *
+ * @key_len: number of octets in key material.
+ * @flags: key handling qualifiers.
+ * @key: PMK key material.
+ */
+struct brcmf_wsec_pmk_le {
+ __le16 key_len;
+ __le16 flags;
+ u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1];
+};
+
/* Used to get specific STA parameters */
struct brcmf_scb_val_le {
__le32 val;
--
1.9.1