2016-10-25 22:43:10

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 0/8] cfg80211/mac80211: Fast Initial Link Setup (IEEE 802.11ai)

This series adds support for using mac80211-based drivers with Fast
Initial Link Setup as defined in IEEE 802.11ai (to be published early
next year; no more technical changes are expected at this point). The
fils branch in git://w1.fi/hostap.git includes matching commits for
hostapd and wpa_supplicant to use this functionality and initial set of
mac80211_hwsim test cases for the functionality. Actually, most of the
commits are already in the master branch, i.e., only the changes
depending on the nl80211.h changes from this kernel patchset are waiting
in the fils branch.

This series covers only the FILS authentication/association
functionality from IEEE 802.11ai, i.e., the other changes like scanning
optimizations are not included.

Jouni Malinen (8):
cfg80211: Rename SAE_DATA to more generic AUTH_DATA
mac80211: Allow AUTH_DATA to be used for FILS
cfg80211: Add feature flag for Fast Initial Link Setup (FILS)
cfg80211: Add Fast Initial Link Setup (FILS) auth algs
cfg80211: Add KEK/nonces for FILS association frames
mac80211: Add FILS auth alg mapping
mac80211: FILS AEAD protection for station mode association frames
mac80211: Claim Fast Initial Link Setup (FILS) support

include/linux/ieee80211.h | 6 +
include/net/cfg80211.h | 19 ++-
include/uapi/linux/nl80211.h | 26 +++-
net/mac80211/Makefile | 1 +
net/mac80211/aes_cmac.c | 8 +-
net/mac80211/aes_cmac.h | 4 +
net/mac80211/fils_aead.c | 354 +++++++++++++++++++++++++++++++++++++++++++
net/mac80211/fils_aead.h | 19 +++
net/mac80211/ieee80211_i.h | 5 +
net/mac80211/main.c | 1 +
net/mac80211/mlme.c | 64 ++++++--
net/wireless/core.h | 2 +-
net/wireless/mlme.c | 6 +-
net/wireless/nl80211.c | 56 +++++--
14 files changed, 535 insertions(+), 36 deletions(-)
create mode 100644 net/mac80211/fils_aead.c
create mode 100644 net/mac80211/fils_aead.h

--
1.9.1


2016-10-25 22:45:23

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 4/8] cfg80211: Add Fast Initial Link Setup (FILS) auth algs

This defines authentication algorithms for FILS (IEEE 802.11ai).

Signed-off-by: Jouni Malinen <[email protected]>
---
include/linux/ieee80211.h | 3 +++
include/uapi/linux/nl80211.h | 6 ++++++
net/wireless/nl80211.c | 21 +++++++++++++++++++--
3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a80516f..9a523d9 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1576,6 +1576,9 @@ struct ieee80211_vht_operation {
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3
+#define WLAN_AUTH_FILS_SK 4
+#define WLAN_AUTH_FILS_SK_PFS 5
+#define WLAN_AUTH_FILS_PK 6
#define WLAN_AUTH_LEAP 128

#define WLAN_AUTH_CHALLENGE_LEN 128
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 39e1647..5d36e83 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3663,6 +3663,9 @@ enum nl80211_bss_status {
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
* @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
+ * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key
+ * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS
+ * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key
* @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -3675,6 +3678,9 @@ enum nl80211_auth_type {
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
NL80211_AUTHTYPE_SAE,
+ NL80211_AUTHTYPE_FILS_SK,
+ NL80211_AUTHTYPE_FILS_SK_PFS,
+ NL80211_AUTHTYPE_FILS_PK,

/* keep last */
__NL80211_AUTHTYPE_NUM,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 36dd300..ebd7eaf 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3762,12 +3762,23 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
auth_type == NL80211_AUTHTYPE_SAE)
return false;
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS) &&
+ (auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK))
+ return false;
return true;
case NL80211_CMD_CONNECT:
case NL80211_CMD_START_AP:
/* SAE not supported yet */
if (auth_type == NL80211_AUTHTYPE_SAE)
return false;
+ /* FILS not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK)
+ return false;
return true;
default:
return false;
@@ -7796,12 +7807,18 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
return -EINVAL;

- if (auth_type == NL80211_AUTHTYPE_SAE &&
+ if ((auth_type == NL80211_AUTHTYPE_SAE ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK) &&
!info->attrs[NL80211_ATTR_AUTH_DATA])
return -EINVAL;

if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
- if (auth_type != NL80211_AUTHTYPE_SAE)
+ if (auth_type != NL80211_AUTHTYPE_SAE &&
+ auth_type != NL80211_AUTHTYPE_FILS_SK &&
+ auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
+ auth_type != NL80211_AUTHTYPE_FILS_PK)
return -EINVAL;
auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
--
1.9.1

2016-10-26 16:10:15

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/8] mac80211: Allow AUTH_DATA to be used for FILS


> This is admittedly a bit strange design with that special case needed
> for SAE. If we were to design the SAE case now in combination with
> FILS, I guess this would be quite different (e.g., separate
> attributes for Authentication transaction sequence number and Status
> code). Unlike the mesh use case with SAE, FILS is only between an AP
> and a station and as such, there would not really be a case where the
> station would send an Authentication frame with non-zero Status code.
>
> A future amendment might define a new authentication algorithm that
> ends up using more than a single Authentication frame exchange. In
> such a case, we would actually have need for Authentication
> transaction sequence number even though FILS doesn't need it.
>
> I think I'd rather maintain a consistent attribute design for all
> authentication algorithms and leave this as-is now. Another option
> would be to not apply the rename SAE attributes patch and define
> something new as a more generic solution, but I'm not sure there is
> sufficient justification for the added complexity since we cannot
> really get rid of the current SAE design any time soon.

Yes, fair point.

Maybe you can clarify the nl80211 attribute documentation wrt. this? It
just states that it starts with the Authentication transaction sequence
field, but afaict that's not true, it also has the status code field,
which is also ignored here.

johannes

2016-10-25 22:43:30

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 2/8] mac80211: Allow AUTH_DATA to be used for FILS

The special SAE case should be limited only for SAE since the more
generic AUTH_DATA can now be used with other authentication algorithms
as well.

Signed-off-by: Jouni Malinen <[email protected]>
---
net/mac80211/mlme.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 32fd295..b6222f2 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4491,9 +4491,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
auth_data->bss = req->bss;

if (req->auth_data_len >= 4) {
- __le16 *pos = (__le16 *) req->auth_data;
- auth_data->sae_trans = le16_to_cpu(pos[0]);
- auth_data->sae_status = le16_to_cpu(pos[1]);
+ if (req->auth_type == NL80211_AUTHTYPE_SAE) {
+ __le16 *pos = (__le16 *) req->auth_data;
+ auth_data->sae_trans = le16_to_cpu(pos[0]);
+ auth_data->sae_status = le16_to_cpu(pos[1]);
+ }
memcpy(auth_data->data, req->auth_data + 4,
req->auth_data_len - 4);
auth_data->data_len += req->auth_data_len - 4;
--
1.9.1

2016-10-26 05:30:07

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 2/8] mac80211: Allow AUTH_DATA to be used for FILS


>   if (req->auth_data_len >= 4) {
> - __le16 *pos = (__le16 *) req->auth_data;
> - auth_data->sae_trans = le16_to_cpu(pos[0]);
> - auth_data->sae_status = le16_to_cpu(pos[1]);
> + if (req->auth_type == NL80211_AUTHTYPE_SAE) {
> + __le16 *pos = (__le16 *) req->auth_data;
> + auth_data->sae_trans = le16_to_cpu(pos[0]);
> + auth_data->sae_status = le16_to_cpu(pos[1]);
> + }
>   memcpy(auth_data->data, req->auth_data + 4,
>          req->auth_data_len - 4);
>   auth_data->data_len += req->auth_data_len - 4;

Hmm. Do we really want to still skip the first four bytes of the data
userspace passed? That seems a bit strange to me. The docs in nl80211.h
do say it that way now, but should we really include a dummy
Authentication transaction sequence number field?

johannes

2016-10-25 22:43:20

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 1/8] cfg80211: Rename SAE_DATA to more generic AUTH_DATA

This adds defines and nl80211 extensions to allow FILS Authentication to
be implemented similarly to SAE. FILS does not need the special rules
for Authentication transaction number, but it does need to add non-IE
fields. The previously used NL80211_ATTR_SAE_DATA can be reused for this
to avoid having to duplicate that implementation. Rename that attribute
to more generic NL80211_ATTR_AUTH_DATA (with backwards compatibility
define for NL80211_SAE_DATA).

Signed-off-by: Jouni Malinen <[email protected]>
---
include/net/cfg80211.h | 10 +++++-----
include/uapi/linux/nl80211.h | 9 ++++++---
net/mac80211/mlme.c | 12 ++++++------
net/wireless/core.h | 2 +-
net/wireless/mlme.c | 6 +++---
net/wireless/nl80211.c | 18 +++++++++---------
6 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ec39f89..2667917 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1789,9 +1789,9 @@ struct cfg80211_bss {
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
- * @sae_data: Non-IE data to use with SAE or %NULL. This starts with
- * Authentication transaction sequence number field.
- * @sae_data_len: Length of sae_data buffer in octets
+ * @auth_data: IE and non-IE data to use with SAE/FILS or %NULL. This starts
+ * with Authentication transaction sequence number field.
+ * @auth_data_len: Length of auth_data buffer in octets
*/
struct cfg80211_auth_request {
struct cfg80211_bss *bss;
@@ -1800,8 +1800,8 @@ struct cfg80211_auth_request {
enum nl80211_auth_type auth_type;
const u8 *key;
u8 key_len, key_idx;
- const u8 *sae_data;
- size_t sae_data_len;
+ const u8 *auth_data;
+ size_t auth_data_len;
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 1362d24..528aa48 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1638,8 +1638,10 @@ enum nl80211_commands {
* the connection request from a station. nl80211_connect_failed_reason
* enum has different reasons of connection failure.
*
- * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
- * with the Authentication transaction sequence number field.
+ * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames. This
+ * starts with the Authentication transaction sequence number field and is
+ * used with authentication algorithms that need special fields to be added
+ * into the frames (SAE and FILS).
*
* @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION)
@@ -2195,7 +2197,7 @@ enum nl80211_attrs {

NL80211_ATTR_CONN_FAILED_REASON,

- NL80211_ATTR_SAE_DATA,
+ NL80211_ATTR_AUTH_DATA,

NL80211_ATTR_VHT_CAPABILITY,

@@ -2347,6 +2349,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
+#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA

/*
* Allow user space programs to use #ifdef on new attributes by defining them
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c8d3a9b..32fd295 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4483,20 +4483,20 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
return -EOPNOTSUPP;
}

- auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len +
+ auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
req->ie_len, GFP_KERNEL);
if (!auth_data)
return -ENOMEM;

auth_data->bss = req->bss;

- if (req->sae_data_len >= 4) {
- __le16 *pos = (__le16 *) req->sae_data;
+ if (req->auth_data_len >= 4) {
+ __le16 *pos = (__le16 *) req->auth_data;
auth_data->sae_trans = le16_to_cpu(pos[0]);
auth_data->sae_status = le16_to_cpu(pos[1]);
- memcpy(auth_data->data, req->sae_data + 4,
- req->sae_data_len - 4);
- auth_data->data_len += req->sae_data_len - 4;
+ memcpy(auth_data->data, req->auth_data + 4,
+ req->auth_data_len - 4);
+ auth_data->data_len += req->auth_data_len - 4;
}

if (req->ie && req->ie_len) {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 21e3188..fb2fcd5 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -345,7 +345,7 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *sae_data, int sae_data_len);
+ const u8 *auth_data, int auth_data_len);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index cbb48e2..bd1f7a1 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -204,14 +204,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *sae_data, int sae_data_len)
+ const u8 *auth_data, int auth_data_len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req = {
.ie = ie,
.ie_len = ie_len,
- .sae_data = sae_data,
- .sae_data_len = sae_data_len,
+ .auth_data = auth_data,
+ .auth_data_len = auth_data_len,
.auth_type = auth_type,
.key = key,
.key_len = key_len,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 46cd489..36dd300 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -357,7 +357,7 @@ enum nl80211_multicast_groups {
[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_SAE_DATA] = { .type = NLA_BINARY, },
+ [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
@@ -7715,8 +7715,8 @@ static int nl80211_authenticate(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 ieee80211_channel *chan;
- const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
- int err, ssid_len, ie_len = 0, sae_data_len = 0;
+ const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
+ int err, ssid_len, ie_len = 0, auth_data_len = 0;
enum nl80211_auth_type auth_type;
struct key_parse key;
bool local_state_change;
@@ -7797,16 +7797,16 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;

if (auth_type == NL80211_AUTHTYPE_SAE &&
- !info->attrs[NL80211_ATTR_SAE_DATA])
+ !info->attrs[NL80211_ATTR_AUTH_DATA])
return -EINVAL;

- if (info->attrs[NL80211_ATTR_SAE_DATA]) {
+ if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
if (auth_type != NL80211_AUTHTYPE_SAE)
return -EINVAL;
- sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
- sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
+ auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
+ auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
/* need to include at least Auth Transaction and Status Code */
- if (sae_data_len < 4)
+ if (auth_data_len < 4)
return -EINVAL;
}

@@ -7823,7 +7823,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx,
- sae_data, sae_data_len);
+ auth_data, auth_data_len);
wdev_unlock(dev->ieee80211_ptr);
return err;
}
--
1.9.1

2016-10-25 22:47:22

by Jouni Malinen

[permalink] [raw]
Subject: [PATCH 3/8] cfg80211: Add feature flag for Fast Initial Link Setup (FILS)

This defines a feature flag that drivers can use to indicate that they
support (IEEE 802.11ai) when using user space SME
(NL80211_CMD_AUTHENTICATE) in station mode.

Signed-off-by: Jouni Malinen <[email protected]>
---
include/uapi/linux/nl80211.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 528aa48..39e1647 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4641,6 +4641,8 @@ enum nl80211_feature_flags {
* configuration (AP/mesh) with HT rates.
* @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
* configuration (AP/mesh) with VHT rates.
+ * @NL80211_EXT_FEATURE_FILS: This driver supports Fast Initial Link Setup with
+ * user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4655,6 +4657,7 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
NL80211_EXT_FEATURE_BEACON_RATE_HT,
NL80211_EXT_FEATURE_BEACON_RATE_VHT,
+ NL80211_EXT_FEATURE_FILS,

/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
--
1.9.1

2016-10-26 15:37:04

by Jouni Malinen

[permalink] [raw]
Subject: Re: [PATCH 2/8] mac80211: Allow AUTH_DATA to be used for FILS

T24gV2VkLCBPY3QgMjYsIDIwMTYgYXQgMDc6MzA6MDBBTSArMDIwMCwgSm9oYW5uZXMgQmVyZyB3
cm90ZToNCj4gDQo+ID4gwqAJaWYgKHJlcS0+YXV0aF9kYXRhX2xlbiA+PSA0KSB7DQo+ID4gLQkJ
X19sZTE2ICpwb3MgPSAoX19sZTE2ICopIHJlcS0+YXV0aF9kYXRhOw0KPiA+IC0JCWF1dGhfZGF0
YS0+c2FlX3RyYW5zID0gbGUxNl90b19jcHUocG9zWzBdKTsNCj4gPiAtCQlhdXRoX2RhdGEtPnNh
ZV9zdGF0dXMgPSBsZTE2X3RvX2NwdShwb3NbMV0pOw0KPiA+ICsJCWlmIChyZXEtPmF1dGhfdHlw
ZSA9PSBOTDgwMjExX0FVVEhUWVBFX1NBRSkgew0KPiA+ICsJCQlfX2xlMTYgKnBvcyA9IChfX2xl
MTYgKikgcmVxLT5hdXRoX2RhdGE7DQo+ID4gKwkJCWF1dGhfZGF0YS0+c2FlX3RyYW5zID0gbGUx
Nl90b19jcHUocG9zWzBdKTsNCj4gPiArCQkJYXV0aF9kYXRhLT5zYWVfc3RhdHVzID0gbGUxNl90
b19jcHUocG9zWzFdKTsNCj4gPiArCQl9DQo+ID4gwqAJCW1lbWNweShhdXRoX2RhdGEtPmRhdGEs
IHJlcS0+YXV0aF9kYXRhICsgNCwNCj4gPiDCoAkJwqDCoMKgwqDCoMKgwqByZXEtPmF1dGhfZGF0
YV9sZW4gLSA0KTsNCj4gPiDCoAkJYXV0aF9kYXRhLT5kYXRhX2xlbiArPSByZXEtPmF1dGhfZGF0
YV9sZW4gLSA0Ow0KPiANCj4gSG1tLiBEbyB3ZSByZWFsbHkgd2FudCB0byBzdGlsbCBza2lwIHRo
ZSBmaXJzdCBmb3VyIGJ5dGVzIG9mIHRoZSBkYXRhDQo+IHVzZXJzcGFjZSBwYXNzZWQ/IFRoYXQg
c2VlbXMgYSBiaXQgc3RyYW5nZSB0byBtZS4gVGhlIGRvY3MgaW4gbmw4MDIxMS5oDQo+IGRvIHNh
eSBpdCB0aGF0IHdheSBub3csIGJ1dCBzaG91bGQgd2UgcmVhbGx5IGluY2x1ZGUgYSBkdW1teQ0K
PiBBdXRoZW50aWNhdGlvbiB0cmFuc2FjdGlvbiBzZXF1ZW5jZSBudW1iZXIgZmllbGQ/DQoNClRo
aXMgaXMgYWRtaXR0ZWRseSBhIGJpdCBzdHJhbmdlIGRlc2lnbiB3aXRoIHRoYXQgc3BlY2lhbCBj
YXNlIG5lZWRlZA0KZm9yIFNBRS4gSWYgd2Ugd2VyZSB0byBkZXNpZ24gdGhlIFNBRSBjYXNlIG5v
dyBpbiBjb21iaW5hdGlvbiB3aXRoIEZJTFMsDQpJIGd1ZXNzIHRoaXMgd291bGQgYmUgcXVpdGUg
ZGlmZmVyZW50IChlLmcuLCBzZXBhcmF0ZSBhdHRyaWJ1dGVzIGZvcg0KQXV0aGVudGljYXRpb24g
dHJhbnNhY3Rpb24gc2VxdWVuY2UgbnVtYmVyIGFuZCBTdGF0dXMgY29kZSkuIFVubGlrZSB0aGUN
Cm1lc2ggdXNlIGNhc2Ugd2l0aCBTQUUsIEZJTFMgaXMgb25seSBiZXR3ZWVuIGFuIEFQIGFuZCBh
IHN0YXRpb24gYW5kIGFzDQpzdWNoLCB0aGVyZSB3b3VsZCBub3QgcmVhbGx5IGJlIGEgY2FzZSB3
aGVyZSB0aGUgc3RhdGlvbiB3b3VsZCBzZW5kIGFuDQpBdXRoZW50aWNhdGlvbiBmcmFtZSB3aXRo
IG5vbi16ZXJvIFN0YXR1cyBjb2RlLg0KDQpBIGZ1dHVyZSBhbWVuZG1lbnQgbWlnaHQgZGVmaW5l
IGEgbmV3IGF1dGhlbnRpY2F0aW9uIGFsZ29yaXRobSB0aGF0IGVuZHMNCnVwIHVzaW5nIG1vcmUg
dGhhbiBhIHNpbmdsZSBBdXRoZW50aWNhdGlvbiBmcmFtZSBleGNoYW5nZS4gSW4gc3VjaCBhDQpj
YXNlLCB3ZSB3b3VsZCBhY3R1YWxseSBoYXZlIG5lZWQgZm9yIEF1dGhlbnRpY2F0aW9uIHRyYW5z
YWN0aW9uDQpzZXF1ZW5jZSBudW1iZXIgZXZlbiB0aG91Z2ggRklMUyBkb2Vzbid0IG5lZWQgaXQu
DQoNCkkgdGhpbmsgSSdkIHJhdGhlciBtYWludGFpbiBhIGNvbnNpc3RlbnQgYXR0cmlidXRlIGRl
c2lnbiBmb3IgYWxsDQphdXRoZW50aWNhdGlvbiBhbGdvcml0aG1zIGFuZCBsZWF2ZSB0aGlzIGFz
LWlzIG5vdy4gQW5vdGhlciBvcHRpb24gd291bGQNCmJlIHRvIG5vdCBhcHBseSB0aGUgcmVuYW1l
IFNBRSBhdHRyaWJ1dGVzIHBhdGNoIGFuZCBkZWZpbmUgc29tZXRoaW5nIG5ldw0KYXMgYSBtb3Jl
IGdlbmVyaWMgc29sdXRpb24sIGJ1dCBJJ20gbm90IHN1cmUgdGhlcmUgaXMgc3VmZmljaWVudA0K
anVzdGlmaWNhdGlvbiBmb3IgdGhlIGFkZGVkIGNvbXBsZXhpdHkgc2luY2Ugd2UgY2Fubm90IHJl
YWxseSBnZXQgcmlkIG9mDQp0aGUgY3VycmVudCBTQUUgZGVzaWduIGFueSB0aW1lIHNvb24uDQoN
Ci0tIA0KSm91bmkgTWFsaW5lbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgUEdQIGlkIEVGQzg5NUZB