From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.3 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 412C9C636C8 for ; Sun, 18 Jul 2021 12:37:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 19C29600D3 for ; Sun, 18 Jul 2021 12:37:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233365AbhGRMkf (ORCPT ); Sun, 18 Jul 2021 08:40:35 -0400 Received: from smtp-out2.suse.de ([195.135.220.29]:46802 "EHLO smtp-out2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232859AbhGRMke (ORCPT ); Sun, 18 Jul 2021 08:40:34 -0400 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id EC16D2014E; Sun, 18 Jul 2021 12:37:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1626611854; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=12QxCntc46zGkMjFzhnXFSG1Ib64ny5ns5DTZhrNIrk=; b=SG9Xr/Jh0oxqP3J5NHVfuR78M/oUJrCD17nHm4gY71mrrJ1Z76TqlrYrbsuS+vP7hk1Pra iuVkxo4mmvbDcZaUwemPoVR4Bq5gBXU5zbWq+uUKD2CCvF9bRKGZVooodCylUORNsqBzm2 3kWym0KLDL/YSzJdK/j17WL1i1ao6bk= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1626611854; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=12QxCntc46zGkMjFzhnXFSG1Ib64ny5ns5DTZhrNIrk=; b=yPg+dwvtnWmdxJlKXPestX6YiYGamM1vLUWHQYD0Tzp1Zda26V3XGgCoLxmKWa5M3kT7xg RWvVWIOFKWDalPDQ== Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 9D10813AD2; Sun, 18 Jul 2021 12:37:34 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id 237OJI4g9GBuPQAAGKfGzw (envelope-from ); Sun, 18 Jul 2021 12:37:34 +0000 Subject: Re: [PATCH 09/11] nvmet: Implement basic In-Band Authentication To: =?UTF-8?Q?Stephan_M=c3=bcller?= , Christoph Hellwig Cc: Sagi Grimberg , Keith Busch , linux-nvme@lists.infradead.org, Herbert Xu , "David S . Miller" , linux-crypto@vger.kernel.org References: <20210716110428.9727-1-hare@suse.de> <20210716110428.9727-10-hare@suse.de> <2510347.locV8n3378@positron.chronox.de> From: Hannes Reinecke Message-ID: Date: Sun, 18 Jul 2021 14:37:34 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: <2510347.locV8n3378@positron.chronox.de> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org On 7/17/21 6:49 PM, Stephan Müller wrote: > Am Freitag, 16. Juli 2021, 13:04:26 CEST schrieb Hannes Reinecke: > > Hi Hannes, > >> Implement support for NVMe-oF In-Band authentication. This patch >> adds two additional configfs entries 'dhchap_key' and 'dhchap_hash' >> to the 'host' configfs directory. The 'dhchap_key' needs to be >> specified in the format outlined in the base spec. >> Augmented challenge support is not implemented, and concatenation >> with TLS encryption is not supported. >> >> Signed-off-by: Hannes Reinecke >> --- >> drivers/nvme/target/Kconfig | 10 + >> drivers/nvme/target/Makefile | 1 + >> drivers/nvme/target/admin-cmd.c | 4 + >> drivers/nvme/target/auth.c | 352 +++++++++++++++++++ >> drivers/nvme/target/configfs.c | 71 +++- >> drivers/nvme/target/core.c | 8 + >> drivers/nvme/target/fabrics-cmd-auth.c | 460 +++++++++++++++++++++++++ >> drivers/nvme/target/fabrics-cmd.c | 30 +- >> drivers/nvme/target/nvmet.h | 71 ++++ >> 9 files changed, 1004 insertions(+), 3 deletions(-) >> create mode 100644 drivers/nvme/target/auth.c >> create mode 100644 drivers/nvme/target/fabrics-cmd-auth.c >> >> diff --git a/drivers/nvme/target/Kconfig b/drivers/nvme/target/Kconfig >> index 4be2ececbc45..d5656ef1559e 100644 >> --- a/drivers/nvme/target/Kconfig >> +++ b/drivers/nvme/target/Kconfig >> @@ -85,3 +85,13 @@ config NVME_TARGET_TCP >> devices over TCP. >> >> If unsure, say N. >> + >> +config NVME_TARGET_AUTH >> + bool "NVMe over Fabrics In-band Authentication support" >> + depends on NVME_TARGET >> + select CRYPTO_SHA256 >> + select CRYPTO_SHA512 >> + help >> + This enables support for NVMe over Fabrics In-band Authentication >> + >> + If unsure, say N. >> diff --git a/drivers/nvme/target/Makefile b/drivers/nvme/target/Makefile >> index 9837e580fa7e..c66820102493 100644 >> --- a/drivers/nvme/target/Makefile >> +++ b/drivers/nvme/target/Makefile >> @@ -13,6 +13,7 @@ nvmet-y += core.o configfs.o admin-cmd.o > fabrics-cmd.o \ >> discovery.o io-cmd-file.o io-cmd-bdev.o >> nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o >> nvmet-$(CONFIG_BLK_DEV_ZONED) += zns.o >> +nvmet-$(CONFIG_NVME_TARGET_AUTH) += fabrics-cmd-auth.o auth.o >> nvme-loop-y += loop.o >> nvmet-rdma-y += rdma.o >> nvmet-fc-y += fc.o >> diff --git a/drivers/nvme/target/admin-cmd.c >> b/drivers/nvme/target/admin-cmd.c index 0cb98f2bbc8c..320cefc64ee0 100644 >> --- a/drivers/nvme/target/admin-cmd.c >> +++ b/drivers/nvme/target/admin-cmd.c >> @@ -1008,6 +1008,10 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) >> >> if (nvme_is_fabrics(cmd)) >> return nvmet_parse_fabrics_cmd(req); >> + >> + if (unlikely(!nvmet_check_auth_status(req))) >> + return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR; >> + >> if (nvmet_req_subsys(req)->type == NVME_NQN_DISC) >> return nvmet_parse_discovery_cmd(req); >> >> diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c >> new file mode 100644 >> index 000000000000..00c7d051dfb1 >> --- /dev/null >> +++ b/drivers/nvme/target/auth.c >> @@ -0,0 +1,352 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * NVMe over Fabrics DH-HMAC-CHAP authentication. >> + * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions. >> + * All rights reserved. >> + */ >> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include "nvmet.h" >> +#include "../host/auth.h" >> + >> +int nvmet_auth_set_host_key(struct nvmet_host *host, const char *secret) >> +{ >> + if (sscanf(secret, "DHHC-1:%hhd:%*s", &host->dhchap_key_hash) != 1) >> + return -EINVAL; >> + if (host->dhchap_key_hash > 3) { >> + pr_warn("Invalid DH-HMAC-CHAP hash id %d\n", >> + host->dhchap_key_hash); >> + return -EINVAL; >> + } >> + if (host->dhchap_key_hash > 0) { >> + /* Validate selected hash algorithm */ >> + const char *hmac = nvme_auth_hmac_name(host->dhchap_key_hash); >> + >> + if (!crypto_has_shash(hmac, 0, 0)) { >> + pr_warn("DH-HMAC-CHAP hash %s unsupported\n", hmac); >> + host->dhchap_key_hash = -1; >> + return -EAGAIN; >> + } >> + /* Use this hash as default */ >> + if (!host->dhchap_hash_id) >> + host->dhchap_hash_id = host->dhchap_key_hash; >> + } >> + host->dhchap_secret = kstrdup(secret, GFP_KERNEL); > > Just like before - are you sure that the secret is an ASCII string and no > binary blob? > That is ensured by the transport encoding (cf NVMe Base Specification version 2.0). Also, this information is being passed in via the configfs interface, so it's bounded by PAGE_SIZE. But yes, we should be inserting a terminating 'NULL' character at the end of the page to ensure we don't incur an buffer overrun. Any other failure will be checked for during base64 decoding. >> + if (!host->dhchap_secret) >> + return -ENOMEM; >> + /* Default to SHA256 */ >> + if (!host->dhchap_hash_id) >> + host->dhchap_hash_id = NVME_AUTH_DHCHAP_HASH_SHA256; >> + >> + pr_debug("Using hash %s\n", >> + nvme_auth_hmac_name(host->dhchap_hash_id)); >> + return 0; >> +} >> + >> +int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, int dhgroup_id) >> +{ >> + int ret = -ENOTSUPP; >> + >> + if (dhgroup_id == NVME_AUTH_DHCHAP_DHGROUP_NULL) >> + return 0; >> + >> + return ret; >> +} >> + >> +int nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req) >> +{ >> + int ret = 0; >> + struct nvmet_host_link *p; >> + struct nvmet_host *host = NULL; >> + const char *hash_name; >> + >> + down_read(&nvmet_config_sem); >> + if (ctrl->subsys->type == NVME_NQN_DISC) >> + goto out_unlock; >> + >> + list_for_each_entry(p, &ctrl->subsys->hosts, entry) { >> + pr_debug("check %s\n", nvmet_host_name(p->host)); >> + if (strcmp(nvmet_host_name(p->host), ctrl->hostnqn)) >> + continue; >> + host = p->host; >> + break; >> + } >> + if (!host) { >> + pr_debug("host %s not found\n", ctrl->hostnqn); >> + ret = -EPERM; >> + goto out_unlock; >> + } >> + if (!host->dhchap_secret) { >> + pr_debug("No authentication provided\n"); >> + goto out_unlock; >> + } >> + >> + hash_name = nvme_auth_hmac_name(host->dhchap_hash_id); >> + if (!hash_name) { >> + pr_debug("Hash ID %d invalid\n", host->dhchap_hash_id); >> + ret = -EINVAL; >> + goto out_unlock; >> + } >> + ctrl->shash_tfm = crypto_alloc_shash(hash_name, 0, >> + CRYPTO_ALG_ALLOCATES_MEMORY); >> + if (IS_ERR(ctrl->shash_tfm)) { >> + pr_debug("failed to allocate shash %s\n", hash_name); >> + ret = PTR_ERR(ctrl->shash_tfm); >> + ctrl->shash_tfm = NULL; >> + goto out_unlock; >> + } >> + >> + ctrl->dhchap_key = nvme_auth_extract_secret(host->dhchap_secret, >> + &ctrl->dhchap_key_len); >> + if (IS_ERR(ctrl->dhchap_key)) { >> + pr_debug("failed to extract host key, error %d\n", ret); >> + ret = PTR_ERR(ctrl->dhchap_key); >> + ctrl->dhchap_key = NULL; >> + goto out_free_hash; >> + } >> + if (host->dhchap_key_hash) { >> + struct crypto_shash *key_tfm; >> + >> + hash_name = nvme_auth_hmac_name(host->dhchap_key_hash); >> + key_tfm = crypto_alloc_shash(hash_name, 0, 0); >> + if (IS_ERR(key_tfm)) { >> + ret = PTR_ERR(key_tfm); >> + goto out_free_hash; >> + } else { >> + SHASH_DESC_ON_STACK(shash, key_tfm); >> + >> + shash->tfm = key_tfm; >> + ret = crypto_shash_setkey(key_tfm, ctrl->dhchap_key, >> + ctrl->dhchap_key_len); >> + crypto_shash_init(shash); >> + crypto_shash_update(shash, ctrl->subsys->subsysnqn, >> + strlen(ctrl->subsys->subsysnqn)); >> + crypto_shash_update(shash, "NVMe-over-Fabrics", 17); >> + crypto_shash_final(shash, ctrl->dhchap_key); >> + crypto_free_shash(key_tfm); >> + } >> + } >> + pr_debug("%s: using key %*ph\n", __func__, >> + (int)ctrl->dhchap_key_len, ctrl->dhchap_key); >> + ret = crypto_shash_setkey(ctrl->shash_tfm, ctrl->dhchap_key, > > Is it truly necessary to keep the key around in ctrl->dhchap_key? It looks to > me that this buffer is only used here and thus could be turned into a local > variable. Keys flying around in memory is not a good idea. :-) > The key is also used when using the ffdhe algorithm. Note: I _think_ that I need to use this key for the ffdhe algorithm, because the implementation I came up with is essentially plain DH with pre-defined 'p', 'q' and 'g' values. But the DH implementation also requires a 'key', and for that I'm using this key here. It might be that I'm completely off, and don't need to use a key for our DH implementation. In that case you are correct. (And that's why I said I'll need a review of the FFDHE implementation). But for now I'll need the key for FFDHE. >> + ctrl->dhchap_key_len); >> +out_free_hash: >> + if (ret) { >> + if (ctrl->dhchap_key) { >> + kfree(ctrl->dhchap_key); > > kfree_sensitive? > Yes, will be fixing it. >> + ctrl->dhchap_key = NULL; >> + } >> + crypto_free_shash(ctrl->shash_tfm); >> + ctrl->shash_tfm = NULL; >> + } >> +out_unlock: >> + up_read(&nvmet_config_sem); >> + >> + return ret; >> +} >> + >> +void nvmet_auth_sq_free(struct nvmet_sq *sq) >> +{ >> + if (sq->dhchap_c1) >> + kfree(sq->dhchap_c1); >> + if (sq->dhchap_c2) >> + kfree(sq->dhchap_c2); >> + if (sq->dhchap_skey) >> + kfree(sq->dhchap_skey); > > kfree_sensitive? > Yes. >> +} >> + >> +void nvmet_reset_auth(struct nvmet_ctrl *ctrl) >> +{ >> + if (ctrl->shash_tfm) { >> + crypto_free_shash(ctrl->shash_tfm); >> + ctrl->shash_tfm = NULL; >> + } >> + if (ctrl->dh_tfm) { >> + crypto_free_kpp(ctrl->dh_tfm); >> + ctrl->dh_tfm = NULL; >> + } >> + if (ctrl->dhchap_key) { >> + kfree(ctrl->dhchap_key); > > kfree_sensitive? > Yes. >> + ctrl->dhchap_key = NULL; >> + } >> +} >> + >> +bool nvmet_check_auth_status(struct nvmet_req *req) >> +{ >> + if (req->sq->ctrl->shash_tfm && >> + !req->sq->authenticated) >> + return false; >> + return true; >> +} >> + >> +int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, >> + unsigned int shash_len) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + SHASH_DESC_ON_STACK(shash, ctrl->shash_tfm); >> + u8 *challenge = req->sq->dhchap_c1; >> + u8 buf[4]; >> + int ret; >> + >> + if (ctrl->dh_gid != NVME_AUTH_DHCHAP_DHGROUP_NULL) { >> + ret = -ENOTSUPP; >> + goto out; >> + } >> + >> + shash->tfm = ctrl->shash_tfm; >> + ret = crypto_shash_init(shash); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, challenge, shash_len); >> + if (ret) >> + goto out; >> + put_unaligned_le32(req->sq->dhchap_s1, buf); >> + ret = crypto_shash_update(shash, buf, 4); >> + if (ret) >> + goto out; >> + put_unaligned_le16(req->sq->dhchap_tid, buf); >> + ret = crypto_shash_update(shash, buf, 2); >> + if (ret) >> + goto out; >> + memset(buf, 0, 4); >> + ret = crypto_shash_update(shash, buf, 1); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, "HostHost", 8); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn)); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, buf, 1); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, ctrl->subsysnqn, >> + strlen(ctrl->subsysnqn)); >> + if (ret) >> + goto out; >> + ret = crypto_shash_final(shash, response); >> +out: >> + if (challenge != req->sq->dhchap_c1) >> + kfree(challenge); >> + return 0; >> +} >> + >> +int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, >> + unsigned int shash_len) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + SHASH_DESC_ON_STACK(shash, ctrl->shash_tfm); >> + u8 *challenge = req->sq->dhchap_c2; >> + u8 buf[4]; >> + int ret; >> + >> + pr_debug("%s: ctrl %d hash seq %d transaction %u\n", __func__, >> + ctrl->cntlid, req->sq->dhchap_s2, req->sq->dhchap_tid); >> + pr_debug("%s: ctrl %d challenge %*ph\n", __func__, >> + ctrl->cntlid, shash_len, req->sq->dhchap_c2); >> + pr_debug("%s: ctrl %d subsysnqn %s\n", __func__, >> + ctrl->cntlid, ctrl->subsysnqn); >> + pr_debug("%s: ctrl %d hostnqn %s\n", __func__, >> + ctrl->cntlid, ctrl->hostnqn); >> + >> + if (ctrl->dh_gid != NVME_AUTH_DHCHAP_DHGROUP_NULL) { >> + ret = -ENOTSUPP; >> + goto out; >> + } >> + >> + shash->tfm = ctrl->shash_tfm; >> + ret = crypto_shash_init(shash); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, challenge, shash_len); >> + if (ret) >> + goto out; >> + put_unaligned_le32(req->sq->dhchap_s2, buf); >> + ret = crypto_shash_update(shash, buf, 4); >> + if (ret) >> + goto out; >> + put_unaligned_le16(req->sq->dhchap_tid, buf); >> + ret = crypto_shash_update(shash, buf, 2); >> + if (ret) >> + goto out; >> + memset(buf, 0, 4); >> + ret = crypto_shash_update(shash, buf, 1); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, "Controller", 10); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, ctrl->subsysnqn, >> + strlen(ctrl->subsysnqn)); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, buf, 1); >> + if (ret) >> + goto out; >> + ret = crypto_shash_update(shash, ctrl->hostnqn, strlen(ctrl->hostnqn)); >> + if (ret) >> + goto out; >> + ret = crypto_shash_final(shash, response); >> +out: >> + if (challenge != req->sq->dhchap_c2) >> + kfree(challenge); >> + return 0; >> +} >> + >> +int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, >> + u8 *pkey, int pkey_size) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + struct kpp_request *kpp_req; >> + struct crypto_wait wait; >> + struct scatterlist src, dst; >> + int ret; >> + >> + req->sq->dhchap_skey_len = >> + nvme_auth_dhgroup_privkey_size(ctrl->dh_gid); >> + req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL); >> + if (!req->sq->dhchap_skey) >> + return -ENOMEM; >> + kpp_req = kpp_request_alloc(ctrl->dh_tfm, GFP_KERNEL); >> + if (!kpp_req) { >> + kfree(req->sq->dhchap_skey); >> + req->sq->dhchap_skey = NULL; >> + return -ENOMEM; >> + } >> + >> + pr_debug("%s: host public key %*ph\n", __func__, >> + (int)pkey_size, pkey); >> + crypto_init_wait(&wait); >> + sg_init_one(&src, pkey, pkey_size); >> + kpp_request_set_input(kpp_req, &src, pkey_size); >> + sg_init_one(&dst, req->sq->dhchap_skey, >> + req->sq->dhchap_skey_len); >> + kpp_request_set_output(kpp_req, &dst, req->sq->dhchap_skey_len); >> + kpp_request_set_callback(kpp_req, CRYPTO_TFM_REQ_MAY_BACKLOG, >> + crypto_req_done, &wait); >> + >> + ret = crypto_wait_req(crypto_kpp_compute_shared_secret(kpp_req), &wait); >> + kpp_request_free(kpp_req); >> + if (ret) >> + pr_debug("failed to compute shared secred, err %d\n", ret); >> + else >> + pr_debug("%s: shared secret %*ph\n", __func__, >> + (int)req->sq->dhchap_skey_len, >> + req->sq->dhchap_skey); >> + >> + return ret; >> +} >> diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c >> index 273555127188..e0760911a761 100644 >> --- a/drivers/nvme/target/configfs.c >> +++ b/drivers/nvme/target/configfs.c >> @@ -11,8 +11,13 @@ >> #include >> #include >> #include >> +#include >> +#include >> >> #include "nvmet.h" >> +#ifdef CONFIG_NVME_TARGET_AUTH >> +#include "../host/auth.h" >> +#endif >> >> static const struct config_item_type nvmet_host_type; >> static const struct config_item_type nvmet_subsys_type; >> @@ -1656,10 +1661,71 @@ static const struct config_item_type >> nvmet_ports_type = { static struct config_group nvmet_subsystems_group; >> static struct config_group nvmet_ports_group; >> >> -static void nvmet_host_release(struct config_item *item) >> +#ifdef CONFIG_NVME_TARGET_AUTH >> +static ssize_t nvmet_host_dhchap_key_show(struct config_item *item, >> + char *page) >> +{ >> + u8 *dhchap_secret = to_host(item)->dhchap_secret; >> + >> + if (!dhchap_secret) >> + return sprintf(page, "\n"); >> + return sprintf(page, "%s\n", dhchap_secret); >> +} >> + >> +static ssize_t nvmet_host_dhchap_key_store(struct config_item *item, >> + const char *page, size_t count) >> { >> struct nvmet_host *host = to_host(item); >> + int ret; >> >> + ret = nvmet_auth_set_host_key(host, page); >> + if (ret < 0) >> + return ret; >> + return count; >> +} >> + >> +CONFIGFS_ATTR(nvmet_host_, dhchap_key); >> + >> +static ssize_t nvmet_host_dhchap_hash_show(struct config_item *item, >> + char *page) >> +{ >> + struct nvmet_host *host = to_host(item); >> + const char *hash_name = nvme_auth_hmac_name(host->dhchap_hash_id); >> + >> + return sprintf(page, "%s\n", hash_name ? hash_name : "none"); >> +} >> + >> +static ssize_t nvmet_host_dhchap_hash_store(struct config_item *item, >> + const char *page, size_t count) >> +{ >> + struct nvmet_host *host = to_host(item); >> + int hmac_id; >> + >> + hmac_id = nvme_auth_hmac_id(page); >> + if (hmac_id < 0) >> + return -EINVAL; >> + if (!crypto_has_shash(nvme_auth_hmac_name(hmac_id), 0, 0)) >> + return -ENOTSUPP; >> + host->dhchap_hash_id = hmac_id; >> + return count; >> +} >> + >> +CONFIGFS_ATTR(nvmet_host_, dhchap_hash); >> + >> +static struct configfs_attribute *nvmet_host_attrs[] = { >> + &nvmet_host_attr_dhchap_key, >> + &nvmet_host_attr_dhchap_hash, >> + NULL, >> +}; >> +#endif /* CONFIG_NVME_TARGET_AUTH */ >> + >> +static void nvmet_host_release(struct config_item *item) >> +{ >> + struct nvmet_host *host = to_host(item); >> +#ifdef CONFIG_NVME_TARGET_AUTH >> + if (host->dhchap_secret) >> + kfree(host->dhchap_secret); >> +#endif >> kfree(host); >> } >> >> @@ -1669,6 +1735,9 @@ static struct configfs_item_operations >> nvmet_host_item_ops = { >> >> static const struct config_item_type nvmet_host_type = { >> .ct_item_ops = &nvmet_host_item_ops, >> +#ifdef CONFIG_NVME_TARGET_AUTH >> + .ct_attrs = nvmet_host_attrs, >> +#endif >> .ct_owner = THIS_MODULE, >> }; >> >> diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c >> index 163f7dc1a929..b5d7971f566b 100644 >> --- a/drivers/nvme/target/core.c >> +++ b/drivers/nvme/target/core.c >> @@ -793,6 +793,7 @@ void nvmet_sq_destroy(struct nvmet_sq *sq) >> wait_for_completion(&sq->confirm_done); >> wait_for_completion(&sq->free_done); >> percpu_ref_exit(&sq->ref); >> + nvmet_auth_sq_free(sq); >> >> if (ctrl) { >> /* >> @@ -1264,6 +1265,11 @@ u16 nvmet_check_ctrl_status(struct nvmet_req *req) >> req->cmd->common.opcode, req->sq->qid); >> return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR; >> } >> + >> + if (unlikely(!nvmet_check_auth_status(req))) { >> + pr_warn("qid %d not authenticated\n", req->sq->qid); >> + return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR; >> + } >> return 0; >> } >> >> @@ -1456,6 +1462,8 @@ static void nvmet_ctrl_free(struct kref *ref) >> flush_work(&ctrl->async_event_work); >> cancel_work_sync(&ctrl->fatal_err_work); >> >> + nvmet_reset_auth(ctrl); >> + >> ida_simple_remove(&cntlid_ida, ctrl->cntlid); >> >> nvmet_async_events_free(ctrl); >> diff --git a/drivers/nvme/target/fabrics-cmd-auth.c >> b/drivers/nvme/target/fabrics-cmd-auth.c new file mode 100644 >> index 000000000000..962f9f5e9d89 >> --- /dev/null >> +++ b/drivers/nvme/target/fabrics-cmd-auth.c >> @@ -0,0 +1,460 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * NVMe over Fabrics DH-HMAC-CHAP authentication command handling. >> + * Copyright (c) 2020 Hannes Reinecke, SUSE Software Solutions. >> + * All rights reserved. >> + */ >> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt >> +#include >> +#include >> +#include >> +#include >> +#include "nvmet.h" >> +#include "../host/auth.h" >> + >> +void nvmet_init_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req) >> +{ >> + /* Initialize in-band authentication */ >> + req->sq->authenticated = false; >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE; >> + req->cqe->result.u32 |= 0x2 << 16; >> +} >> + >> +static u16 nvmet_auth_negotiate(struct nvmet_req *req, void *d) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + struct nvmf_auth_dhchap_negotiate_data *data = d; >> + int i, hash_id, null_dh = -1; >> + >> + pr_debug("%s: ctrl %d qid %d: data sc_d %d napd %d authid %d halen %d >> dhlen %d\n", + __func__, ctrl->cntlid, req->sq->qid, >> + data->sc_c, data->napd, data->auth_protocol[0].dhchap.authid, >> + data->auth_protocol[0].dhchap.halen, >> + data->auth_protocol[0].dhchap.dhlen); >> + req->sq->dhchap_tid = le16_to_cpu(data->t_id); >> + if (data->sc_c) >> + return NVME_AUTH_DHCHAP_FAILURE_CONCAT_MISMATCH; >> + >> + if (data->napd != 1) >> + return NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE; >> + >> + if (data->auth_protocol[0].dhchap.authid != 0x01) >> + return NVME_AUTH_DHCHAP_FAILURE_INVALID_PAYLOAD; >> + >> + hash_id = nvme_auth_hmac_id(crypto_shash_alg_name(ctrl->shash_tfm)); >> + for (i = 0; i < data->auth_protocol[0].dhchap.halen; i++) { >> + pr_debug("%s: ctrl %d qid %d checking hash %d for %d\n", >> + __func__, ctrl->cntlid, req->sq->qid, >> + data->auth_protocol[0].dhchap.idlist[i], hash_id); >> + if (hash_id != data->auth_protocol[0].dhchap.idlist[i]) >> + continue; >> + req->sq->dhchap_hash_id = hash_id; >> + req->sq->dhchap_hash_len = crypto_shash_digestsize(ctrl- >> shash_tfm); >> + break; >> + } >> + if (req->sq->dhchap_hash_id == 0) { >> + pr_debug("%s: ctrl %d qid %d: no usable hash found\n", >> + __func__, ctrl->cntlid, req->sq->qid); >> + return NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE; >> + } >> + >> + for (i = data->auth_protocol[0].dhchap.halen; >> + i < data->auth_protocol[0].dhchap.halen + >> + data->auth_protocol[0].dhchap.dhlen; i++) { >> + int dhgid = data->auth_protocol[0].dhchap.idlist[i]; >> + >> + if (dhgid == NVME_AUTH_DHCHAP_DHGROUP_NULL) { >> + null_dh = dhgid; >> + continue; >> + } >> + if (nvmet_setup_dhgroup(ctrl, dhgid) == 0) >> + break; >> + } >> + if (!ctrl->dh_tfm && null_dh < 0) { >> + pr_debug("%s: ctrl %d qid %d: no DH group selected\n", >> + __func__, ctrl->cntlid, req->sq->qid); >> + return NVME_AUTH_DHCHAP_FAILURE_DHGROUP_UNUSABLE; >> + } >> + if (ctrl->dh_gid == -1) { >> + ctrl->dh_gid = null_dh; >> + ctrl->dh_tfm = NULL; >> + } >> + pr_debug("%s: ctrl %d qid %d: DH group %s (%d)\n", >> + __func__, ctrl->cntlid, req->sq->qid, >> + nvme_auth_dhgroup_name(ctrl->dh_gid), ctrl->dh_gid); >> + return 0; >> +} >> + >> +static u16 nvmet_auth_reply(struct nvmet_req *req, void *d) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + struct nvmf_auth_dhchap_reply_data *data = d; >> + u8 *response; >> + >> + pr_debug("%s: ctrl %d qid %d: data hl %d cvalid %d dhvlen %d\n", >> + __func__, ctrl->cntlid, req->sq->qid, >> + data->hl, data->cvalid, data->dhvlen); >> + if (data->hl != req->sq->dhchap_hash_len) >> + return NVME_AUTH_DHCHAP_FAILURE_INVALID_PAYLOAD; >> + >> + if (data->dhvlen) { >> + return NVME_AUTH_DHCHAP_FAILURE_INVALID_PAYLOAD; >> + } >> + >> + response = kmalloc(data->hl, GFP_KERNEL); > > Again, align to CRYPTO_MINALIGN_ATTR? > Ah, _that_ alignment. Wasn't aware that I need to align to anything. But if that's required, sure, I'll be fixing it. >> + if (!response) >> + return NVME_AUTH_DHCHAP_FAILURE_FAILED; >> + >> + if (nvmet_auth_host_hash(req, response, data->hl) < 0) { >> + pr_debug("ctrl %d qid %d DH-HMAC-CHAP hash failed\n", >> + ctrl->cntlid, req->sq->qid); >> + kfree(response); >> + return NVME_AUTH_DHCHAP_FAILURE_FAILED; >> + } >> + >> + if (memcmp(data->rval, response, data->hl)) { >> + pr_info("ctrl %d qid %d DH-HMAC-CHAP response mismatch\n", >> + ctrl->cntlid, req->sq->qid); >> + kfree(response); >> + return NVME_AUTH_DHCHAP_FAILURE_FAILED; >> + } >> + kfree(response); >> + pr_info("ctrl %d qid %d DH-HMAC-CHAP host authenticated\n", >> + ctrl->cntlid, req->sq->qid); >> + if (data->cvalid) { >> + req->sq->dhchap_c2 = kmalloc(data->hl, GFP_KERNEL); >> + if (!req->sq->dhchap_c2) >> + return NVME_AUTH_DHCHAP_FAILURE_FAILED; >> + memcpy(req->sq->dhchap_c2, data->rval + data->hl, data->hl); >> + >> + pr_debug("ctrl %d qid %d challenge %*ph\n", >> + ctrl->cntlid, req->sq->qid, data->hl, >> + req->sq->dhchap_c2); >> + req->sq->dhchap_s2 = le32_to_cpu(data->seqnum); >> + } else >> + req->sq->dhchap_c2 = NULL; >> + >> + return 0; >> +} >> + >> +static u16 nvmet_auth_failure2(struct nvmet_req *req, void *d) >> +{ >> + struct nvmf_auth_dhchap_failure_data *data = d; >> + >> + return data->reason_code_explanation; >> +} >> + >> +void nvmet_execute_auth_send(struct nvmet_req *req) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + struct nvmf_auth_dhchap_success2_data *data; >> + void *d; >> + u32 tl; >> + u16 status = 0; >> + >> + if (req->cmd->auth_send.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_send_command, secp); >> + goto done; >> + } >> + if (req->cmd->auth_send.spsp0 != 0x01) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_send_command, spsp0); >> + goto done; >> + } >> + if (req->cmd->auth_send.spsp1 != 0x01) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_send_command, spsp1); >> + goto done; >> + } >> + tl = le32_to_cpu(req->cmd->auth_send.tl); >> + if (!tl) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_send_command, tl); >> + goto done; >> + } >> + if (!nvmet_check_transfer_len(req, tl)) { >> + pr_debug("%s: transfer length mismatch (%u)\n", __func__, tl); >> + return; >> + } >> + >> + d = kmalloc(tl, GFP_KERNEL); >> + if (!d) { >> + status = NVME_SC_INTERNAL; >> + goto done; >> + } >> + >> + status = nvmet_copy_from_sgl(req, 0, d, tl); >> + if (status) { >> + kfree(d); >> + goto done; >> + } >> + >> + data = d; >> + pr_debug("%s: ctrl %d qid %d type %d id %d step %x\n", __func__, >> + ctrl->cntlid, req->sq->qid, data->auth_type, data->auth_id, >> + req->sq->dhchap_step); >> + if (data->auth_type != NVME_AUTH_COMMON_MESSAGES && >> + data->auth_type != NVME_AUTH_DHCHAP_MESSAGES) { >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = NVME_AUTH_DHCHAP_FAILURE_INVALID_MESSAGE; >> + } else if (data->auth_type == NVME_AUTH_COMMON_MESSAGES) { >> + if (data->auth_id != req->sq->dhchap_step) { >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = > NVME_AUTH_DHCHAP_FAILURE_INVALID_MESSAGE; >> + } else if (data->auth_id != NVME_AUTH_DHCHAP_MESSAGE_NEGOTIATE) { >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = > NVME_AUTH_DHCHAP_FAILURE_INVALID_MESSAGE; >> + } else { >> + /* Validate negotiation parameters */ >> + status = nvmet_auth_negotiate(req, d); >> + if (status == 0) >> + req->sq->dhchap_step = > NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE; >> + else { >> + req->sq->dhchap_step = > NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = status; >> + status = 0; >> + } >> + } >> + } else if (data->auth_type == NVME_AUTH_DHCHAP_MESSAGES) { >> + if (data->auth_id != req->sq->dhchap_step) { >> + pr_debug("%s: ctrl %d qid %d step mismatch (%d != %d)\n", >> + __func__, ctrl->cntlid, req->sq->qid, >> + data->auth_id, req->sq->dhchap_step); >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = > NVME_AUTH_DHCHAP_FAILURE_INVALID_MESSAGE; >> + } else if (le16_to_cpu(data->t_id) != req->sq->dhchap_tid) { >> + pr_debug("%s: ctrl %d qid %d invalid transaction %d > (expected %d)\n", >> + __func__, ctrl->cntlid, req->sq->qid, >> + le16_to_cpu(data->t_id), >> + req->sq->dhchap_tid); >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = > NVME_AUTH_DHCHAP_FAILURE_INVALID_PAYLOAD; >> + } else { >> + switch (data->auth_id) { >> + case NVME_AUTH_DHCHAP_MESSAGE_REPLY: >> + status = nvmet_auth_reply(req, d); >> + if (status == 0) >> + req->sq->dhchap_step = > NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1; >> + else { >> + req->sq->dhchap_step = > NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = status; >> + status = 0; >> + } >> + break; >> + case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2: >> + req->sq->authenticated = true; >> + pr_debug("%s: ctrl %d qid %d authenticated\n", >> + __func__, ctrl->cntlid, req->sq->qid); >> + break; >> + case NVME_AUTH_DHCHAP_MESSAGE_FAILURE2: >> + status = nvmet_auth_failure2(req, d); >> + if (status) { >> + pr_warn("ctrl %d qid %d: DH-HMAC-CHAP > negotiation failed (%d)\n", >> + ctrl->cntlid, req->sq->qid, >> + status); >> + req->sq->dhchap_status = status; >> + status = 0; >> + } >> + break; >> + default: >> + req->sq->dhchap_status = > NVME_AUTH_DHCHAP_FAILURE_INVALID_MESSAGE; >> + req->sq->dhchap_step = > NVME_AUTH_DHCHAP_MESSAGE_FAILURE2; >> + break; >> + } >> + } >> + } else { >> + req->sq->dhchap_status = NVME_AUTH_DHCHAP_FAILURE_INVALID_MESSAGE; >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE2; >> + } >> + kfree(d); >> +done: >> + pr_debug("%s: ctrl %d qid %d dhchap status %x step %x\n", __func__, >> + ctrl->cntlid, req->sq->qid, >> + req->sq->dhchap_status, req->sq->dhchap_step); >> + if (status) >> + pr_debug("%s: ctrl %d qid %d nvme status %x error loc %d\n", >> + __func__, ctrl->cntlid, req->sq->qid, >> + status, req->error_loc); >> + req->cqe->result.u64 = 0; >> + nvmet_req_complete(req, status); >> + if (req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2 && >> + req->sq->dhchap_step != NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) >> + return; >> + /* Final states, clear up variables */ >> + kfree(req->sq->dhchap_c1); >> + kfree(req->sq->dhchap_c2); >> + if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) >> + nvmet_ctrl_fatal_error(ctrl); >> +} >> + >> +static int nvmet_auth_challenge(struct nvmet_req *req, void *d, int al) >> +{ >> + struct nvmf_auth_dhchap_challenge_data *data = d; >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + int ret = 0; >> + int data_size = sizeof(*d) + req->sq->dhchap_hash_len; >> + >> + if (al < data_size) { >> + pr_debug("%s: buffer too small (al %d need %d)\n", __func__, >> + al, data_size); >> + return -EINVAL; >> + } >> + memset(data, 0, data_size); >> + req->sq->dhchap_s1 = ctrl->dhchap_seqnum++; >> + data->auth_type = NVME_AUTH_DHCHAP_MESSAGES; >> + data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE; >> + data->t_id = cpu_to_le16(req->sq->dhchap_tid); >> + data->hashid = req->sq->dhchap_hash_id; >> + data->hl = req->sq->dhchap_hash_len; >> + data->seqnum = cpu_to_le32(req->sq->dhchap_s1); >> + req->sq->dhchap_c1 = kmalloc(data->hl, GFP_KERNEL); >> + if (!req->sq->dhchap_c1) >> + return -ENOMEM; >> + get_random_bytes(req->sq->dhchap_c1, data->hl); >> + memcpy(data->cval, req->sq->dhchap_c1, data->hl); >> + pr_debug("%s: ctrl %d qid %d seq %d transaction %d hl %d dhvlen %d\n", >> + __func__, ctrl->cntlid, req->sq->qid, req->sq->dhchap_s1, >> + req->sq->dhchap_tid, data->hl, data->dhvlen); >> + return ret; >> +} >> + >> +static int nvmet_auth_success1(struct nvmet_req *req, void *d, int al) >> +{ >> + struct nvmf_auth_dhchap_success1_data *data = d; >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + >> + WARN_ON(al < sizeof(*data)); >> + memset(data, 0, sizeof(*data)); >> + data->auth_type = NVME_AUTH_DHCHAP_MESSAGES; >> + data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1; >> + data->t_id = cpu_to_le16(req->sq->dhchap_tid); >> + data->hl = req->sq->dhchap_hash_len; >> + if (req->sq->dhchap_c2) { >> + if (nvmet_auth_ctrl_hash(req, data->rval, data->hl)) >> + return NVME_AUTH_DHCHAP_FAILURE_HASH_UNUSABLE; >> + data->rvalid = 1; >> + pr_debug("ctrl %d qid %d response %*ph\n", >> + ctrl->cntlid, req->sq->qid, data->hl, data->rval); >> + } >> + return 0; >> +} >> + >> +static void nvmet_auth_failure1(struct nvmet_req *req, void *d, int al) >> +{ >> + struct nvmf_auth_dhchap_failure_data *data = d; >> + >> + WARN_ON(al < sizeof(*data)); >> + data->auth_type = NVME_AUTH_COMMON_MESSAGES; >> + data->auth_id = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + data->t_id = cpu_to_le32(req->sq->dhchap_tid); >> + data->reason_code = NVME_AUTH_DHCHAP_FAILURE_REASON_FAILED; >> + data->reason_code_explanation = req->sq->dhchap_status; >> +} >> + >> +void nvmet_execute_auth_receive(struct nvmet_req *req) >> +{ >> + struct nvmet_ctrl *ctrl = req->sq->ctrl; >> + void *d; >> + u32 al; >> + u16 status = 0; >> + >> + if (req->cmd->auth_receive.secp != NVME_AUTH_DHCHAP_PROTOCOL_IDENTIFIER) > { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_receive_command, secp); >> + goto done; >> + } >> + if (req->cmd->auth_receive.spsp0 != 0x01) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_receive_command, spsp0); >> + goto done; >> + } >> + if (req->cmd->auth_receive.spsp1 != 0x01) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_receive_command, spsp1); >> + goto done; >> + } >> + al = le32_to_cpu(req->cmd->auth_receive.al); >> + if (!al) { >> + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; >> + req->error_loc = >> + offsetof(struct nvmf_auth_receive_command, al); >> + goto done; >> + } >> + if (!nvmet_check_transfer_len(req, al)) { >> + pr_debug("%s: transfer length mismatch (%u)\n", __func__, al); >> + return; >> + } >> + >> + d = kmalloc(al, GFP_KERNEL); >> + if (!d) { >> + status = NVME_SC_INTERNAL; >> + goto done; >> + } >> + pr_debug("%s: ctrl %d qid %d step %x\n", __func__, >> + ctrl->cntlid, req->sq->qid, req->sq->dhchap_step); >> + switch (req->sq->dhchap_step) { >> + case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE: >> + status = nvmet_auth_challenge(req, d, al); >> + if (status < 0) { >> + pr_warn("ctrl %d qid %d: challenge error (%d)\n", >> + ctrl->cntlid, req->sq->qid, status); >> + status = NVME_SC_INTERNAL; >> + break; >> + } >> + if (status) { >> + req->sq->dhchap_status = status; >> + nvmet_auth_failure1(req, d, al); >> + pr_warn("ctrl %d qid %d: challenge status (%x)\n", >> + ctrl->cntlid, req->sq->qid, >> + req->sq->dhchap_status); >> + status = 0; >> + break; >> + } >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_REPLY; >> + break; >> + case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1: >> + status = nvmet_auth_success1(req, d, al); >> + if (status) { >> + req->sq->dhchap_status = status; >> + nvmet_auth_failure1(req, d, al); >> + pr_warn("ctrl %d qid %d: success1 status (%x)\n", >> + ctrl->cntlid, req->sq->qid, >> + req->sq->dhchap_status); >> + break; >> + } >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2; >> + break; >> + case NVME_AUTH_DHCHAP_MESSAGE_FAILURE1: >> + nvmet_auth_failure1(req, d, al); >> + pr_warn("ctrl %d qid %d failure1 (%x)\n", >> + ctrl->cntlid, req->sq->qid, req->sq->dhchap_status); >> + break; >> + default: >> + pr_warn("ctrl %d qid %d unhandled step (%d)\n", >> + ctrl->cntlid, req->sq->qid, req->sq->dhchap_step); >> + req->sq->dhchap_step = NVME_AUTH_DHCHAP_MESSAGE_FAILURE1; >> + req->sq->dhchap_status = NVME_AUTH_DHCHAP_FAILURE_FAILED; >> + nvmet_auth_failure1(req, d, al); >> + status = 0; >> + break; >> + } >> + >> + status = nvmet_copy_to_sgl(req, 0, d, al); >> + kfree(d); >> +done: >> + req->cqe->result.u64 = 0; >> + nvmet_req_complete(req, status); >> + if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) { >> + kfree(req->sq->dhchap_c1); >> + kfree(req->sq->dhchap_c2); >> + nvmet_ctrl_fatal_error(ctrl); >> + } >> +} >> diff --git a/drivers/nvme/target/fabrics-cmd.c >> b/drivers/nvme/target/fabrics-cmd.c index 7d0f3523fdab..53fb853cd8fe 100644 >> --- a/drivers/nvme/target/fabrics-cmd.c >> +++ b/drivers/nvme/target/fabrics-cmd.c >> @@ -93,6 +93,14 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req) >> case nvme_fabrics_type_property_get: >> req->execute = nvmet_execute_prop_get; >> break; >> +#ifdef CONFIG_NVME_TARGET_AUTH >> + case nvme_fabrics_type_auth_send: >> + req->execute = nvmet_execute_auth_send; >> + break; >> + case nvme_fabrics_type_auth_receive: >> + req->execute = nvmet_execute_auth_receive; >> + break; >> +#endif >> default: >> pr_debug("received unknown capsule type 0x%x\n", >> cmd->fabrics.fctype); >> @@ -155,6 +163,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req >> *req) struct nvmf_connect_data *d; >> struct nvmet_ctrl *ctrl = NULL; >> u16 status = 0; >> + int ret; >> >> if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data))) >> return; >> @@ -197,17 +206,31 @@ static void nvmet_execute_admin_connect(struct >> nvmet_req *req) >> >> uuid_copy(&ctrl->hostid, &d->hostid); >> >> + ret = nvmet_setup_auth(ctrl, req); >> + if (ret < 0) { >> + pr_err("Failed to setup authentication, error %d\n", ret); >> + nvmet_ctrl_put(ctrl); >> + if (ret == -EPERM) >> + status = (NVME_SC_CONNECT_INVALID_HOST | NVME_SC_DNR); >> + else >> + status = NVME_SC_INTERNAL; >> + goto out; >> + } >> + >> status = nvmet_install_queue(ctrl, req); >> if (status) { >> nvmet_ctrl_put(ctrl); >> goto out; >> } >> >> - pr_info("creating controller %d for subsystem %s for NQN %s%s.\n", >> + pr_info("creating controller %d for subsystem %s for NQN %s%s%s.\n", >> ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn, >> - ctrl->pi_support ? " T10-PI is enabled" : ""); >> + ctrl->pi_support ? " T10-PI is enabled" : "", >> + nvmet_has_auth(ctrl) ? " with DH-HMAC-CHAP" : ""); >> req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid); >> >> + if (nvmet_has_auth(ctrl)) >> + nvmet_init_auth(ctrl, req); >> out: >> kfree(d); >> complete: >> @@ -267,6 +290,9 @@ static void nvmet_execute_io_connect(struct nvmet_req >> *req) } >> >> pr_debug("adding queue %d to ctrl %d.\n", qid, ctrl->cntlid); >> + req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid); >> + if (nvmet_has_auth(ctrl)) >> + nvmet_init_auth(ctrl, req); >> >> out: >> kfree(d); >> diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h >> index 06dd3d537f07..ef8815e137d7 100644 >> --- a/drivers/nvme/target/nvmet.h >> +++ b/drivers/nvme/target/nvmet.h >> @@ -108,6 +108,20 @@ struct nvmet_sq { >> u16 size; >> u32 sqhd; >> bool sqhd_disabled; >> +#ifdef CONFIG_NVME_TARGET_AUTH >> + bool authenticated; >> + u16 dhchap_tid; >> + u16 dhchap_status; >> + int dhchap_step; >> + u8 dhchap_hash_id; >> + u8 dhchap_hash_len; >> + u8 *dhchap_c1; >> + u8 *dhchap_c2; >> + u32 dhchap_s1; >> + u32 dhchap_s2; >> + u8 *dhchap_skey; >> + int dhchap_skey_len; >> +#endif >> struct completion free_done; >> struct completion confirm_done; >> }; >> @@ -209,6 +223,15 @@ struct nvmet_ctrl { >> u64 err_counter; >> struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS]; >> bool pi_support; >> +#ifdef CONFIG_NVME_TARGET_AUTH >> + u32 dhchap_seqnum; >> + u8 *dhchap_key; >> + size_t dhchap_key_len; >> + struct crypto_shash *shash_tfm; >> + struct crypto_kpp *dh_tfm; >> + u32 dh_gid; >> + u32 dh_keysize; >> +#endif >> }; >> >> struct nvmet_subsys { >> @@ -270,6 +293,10 @@ static inline struct nvmet_subsys >> *namespaces_to_subsys( >> >> struct nvmet_host { >> struct config_group group; >> + u8 *dhchap_secret; >> + u8 dhchap_key_hash; >> + u8 dhchap_hash_id; >> + u8 dhchap_dhgroup_id; >> }; >> >> static inline struct nvmet_host *to_host(struct config_item *item) >> @@ -659,4 +686,48 @@ static inline void nvmet_req_bio_put(struct nvmet_req >> *req, struct bio *bio) bio_put(bio); >> } >> >> +#ifdef CONFIG_NVME_TARGET_AUTH >> +void nvmet_execute_auth_send(struct nvmet_req *req); >> +void nvmet_execute_auth_receive(struct nvmet_req *req); >> +int nvmet_auth_set_host_key(struct nvmet_host *host, const char *secret); >> +int nvmet_auth_set_host_hash(struct nvmet_host *host, const char *hash); >> +int nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req); >> +void nvmet_init_auth(struct nvmet_ctrl *ctrl, struct nvmet_req *req); >> +void nvmet_reset_auth(struct nvmet_ctrl *ctrl); >> +void nvmet_auth_sq_free(struct nvmet_sq *sq); >> +int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, int dhgroup_id); >> +bool nvmet_check_auth_status(struct nvmet_req *req); >> +int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response, >> + unsigned int hash_len); >> +int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response, >> + unsigned int hash_len); >> +static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl) >> +{ >> + return ctrl->shash_tfm != NULL; >> +} >> +int nvmet_auth_ctrl_exponential(struct nvmet_req *req, >> + u8 *buf, int buf_size); >> +int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, >> + u8 *buf, int buf_size); >> +#else >> +static inline int nvmet_setup_auth(struct nvmet_ctrl *ctrl, >> + struct nvmet_req *req) >> +{ >> + return 0; >> +} >> +static inline void nvmet_init_auth(struct nvmet_ctrl *ctrl, >> + struct nvmet_req *req) {}; >> +static inline void nvmet_reset_auth(struct nvmet_ctrl *ctrl) {}; >> +static inline void nvmet_auth_sq_free(struct nvmet_sq *sq) {}; >> +static inline bool nvmet_check_auth_status(struct nvmet_req *req) >> +{ >> + return true; >> +} >> +static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl) >> +{ >> + return false; >> +} >> +static inline const char *nvmet_dhchap_dhgroup_name(int dhgid) { return >> NULL; } +#endif >> + >> #endif /* _NVMET_H */ Thanks for the review! Cheers, Hannes -- Dr. Hannes Reinecke Kernel Storage Architect hare@suse.de +49 911 74053 688 SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg HRB 36809 (AG Nürnberg), Geschäftsführer: Felix Imendörffer From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 223F0C636C8 for ; Sun, 18 Jul 2021 12:38:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9881F600D3 for ; Sun, 18 Jul 2021 12:38:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9881F600D3 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-nvme-bounces+linux-nvme=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:Content-Type: Content-Transfer-Encoding:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:Date:Message-ID:From: References:Cc:To:Subject:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=PqsqnE5XvHikoMwiMHV5i79kSC1Ac6CbWVMm9ora2tA=; b=0bckRW1sxlmX1aQNjYKm0ISFRC DeWFtufHpNk2xTizKr3n8bWuVNJMIOz4FgUPSN4ZDq+d7JT2EFuBq68xhr6EwyLPql/Lz2cKfoXzH Fo6IeD/33L0wIJT3+nCf/qfpbHgO/LXcdRtX7lAvd5uvENNgSDo/SvLr5LdKFJGNQ8cNHT0+iFo9u I1fdnr74CZvqY5CzCAk2nmwyx629u8Gu1VJ3ujUe/r2YpHlLsaMDNM2Byb76MOI7enHuPp0DejKNn 0ePnPhMVbLDrEuX/cDjphi9NWEAGBZIaPdz8z3wQ68Yk/qHldJPSlVxbmUddPTOJWUB4QCGwYoEI2 MT8LeaTg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m563D-007hY8-TA; Sun, 18 Jul 2021 12:37:43 +0000 Received: from smtp-out2.suse.de ([195.135.220.29]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5637-007hXn-Et for linux-nvme@lists.infradead.org; Sun, 18 Jul 2021 12:37:42 +0000 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id EC16D2014E; Sun, 18 Jul 2021 12:37:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1626611854; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=12QxCntc46zGkMjFzhnXFSG1Ib64ny5ns5DTZhrNIrk=; b=SG9Xr/Jh0oxqP3J5NHVfuR78M/oUJrCD17nHm4gY71mrrJ1Z76TqlrYrbsuS+vP7hk1Pra iuVkxo4mmvbDcZaUwemPoVR4Bq5gBXU5zbWq+uUKD2CCvF9bRKGZVooodCylUORNsqBzm2 3kWym0KLDL/YSzJdK/j17WL1i1ao6bk= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1626611854; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=12QxCntc46zGkMjFzhnXFSG1Ib64ny5ns5DTZhrNIrk=; b=yPg+dwvtnWmdxJlKXPestX6YiYGamM1vLUWHQYD0Tzp1Zda26V3XGgCoLxmKWa5M3kT7xg RWvVWIOFKWDalPDQ== Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 9D10813AD2; Sun, 18 Jul 2021 12:37:34 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id 237OJI4g9GBuPQAAGKfGzw (envelope-from ); Sun, 18 Jul 2021 12:37:34 +0000 Subject: Re: [PATCH 09/11] nvmet: Implement basic In-Band Authentication To: =?UTF-8?Q?Stephan_M=c3=bcller?= , Christoph Hellwig Cc: Sagi Grimberg , Keith Busch , linux-nvme@lists.infradead.org, Herbert Xu , "David S . Miller" , linux-crypto@vger.kernel.org References: <20210716110428.9727-1-hare@suse.de> <20210716110428.9727-10-hare@suse.de> <2510347.locV8n3378@positron.chronox.de> From: Hannes Reinecke Message-ID: Date: Sun, 18 Jul 2021 14:37:34 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: <2510347.locV8n3378@positron.chronox.de> Content-Language: en-US X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210718_053738_033752_7CDB0A4C X-CRM114-Status: GOOD ( 36.81 ) X-BeenThere: linux-nvme@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: base64 Content-Type: text/plain; charset="utf-8"; Format="flowed" Sender: "Linux-nvme" Errors-To: linux-nvme-bounces+linux-nvme=archiver.kernel.org@lists.infradead.org T24gNy8xNy8yMSA2OjQ5IFBNLCBTdGVwaGFuIE3DvGxsZXIgd3JvdGU6Cj4gQW0gRnJlaXRhZywg MTYuIEp1bGkgMjAyMSwgMTM6MDQ6MjYgQ0VTVCBzY2hyaWViIEhhbm5lcyBSZWluZWNrZToKPiAK PiBIaSBIYW5uZXMsCj4gCj4+IEltcGxlbWVudCBzdXBwb3J0IGZvciBOVk1lLW9GIEluLUJhbmQg YXV0aGVudGljYXRpb24uIFRoaXMgcGF0Y2gKPj4gYWRkcyB0d28gYWRkaXRpb25hbCBjb25maWdm cyBlbnRyaWVzICdkaGNoYXBfa2V5JyBhbmQgJ2RoY2hhcF9oYXNoJwo+PiB0byB0aGUgJ2hvc3Qn IGNvbmZpZ2ZzIGRpcmVjdG9yeS4gVGhlICdkaGNoYXBfa2V5JyBuZWVkcyB0byBiZQo+PiBzcGVj aWZpZWQgaW4gdGhlIGZvcm1hdCBvdXRsaW5lZCBpbiB0aGUgYmFzZSBzcGVjLgo+PiBBdWdtZW50 ZWQgY2hhbGxlbmdlIHN1cHBvcnQgaXMgbm90IGltcGxlbWVudGVkLCBhbmQgY29uY2F0ZW5hdGlv bgo+PiB3aXRoIFRMUyBlbmNyeXB0aW9uIGlzIG5vdCBzdXBwb3J0ZWQuCj4+Cj4+IFNpZ25lZC1v ZmYtYnk6IEhhbm5lcyBSZWluZWNrZSA8aGFyZUBzdXNlLmRlPgo+PiAtLS0KPj4gICBkcml2ZXJz L252bWUvdGFyZ2V0L0tjb25maWcgICAgICAgICAgICB8ICAxMCArCj4+ICAgZHJpdmVycy9udm1l L3RhcmdldC9NYWtlZmlsZSAgICAgICAgICAgfCAgIDEgKwo+PiAgIGRyaXZlcnMvbnZtZS90YXJn ZXQvYWRtaW4tY21kLmMgICAgICAgIHwgICA0ICsKPj4gICBkcml2ZXJzL252bWUvdGFyZ2V0L2F1 dGguYyAgICAgICAgICAgICB8IDM1MiArKysrKysrKysrKysrKysrKysrCj4+ICAgZHJpdmVycy9u dm1lL3RhcmdldC9jb25maWdmcy5jICAgICAgICAgfCAgNzEgKysrLQo+PiAgIGRyaXZlcnMvbnZt ZS90YXJnZXQvY29yZS5jICAgICAgICAgICAgIHwgICA4ICsKPj4gICBkcml2ZXJzL252bWUvdGFy Z2V0L2ZhYnJpY3MtY21kLWF1dGguYyB8IDQ2MCArKysrKysrKysrKysrKysrKysrKysrKysrCj4+ ICAgZHJpdmVycy9udm1lL3RhcmdldC9mYWJyaWNzLWNtZC5jICAgICAgfCAgMzAgKy0KPj4gICBk cml2ZXJzL252bWUvdGFyZ2V0L252bWV0LmggICAgICAgICAgICB8ICA3MSArKysrCj4+ICAgOSBm aWxlcyBjaGFuZ2VkLCAxMDA0IGluc2VydGlvbnMoKyksIDMgZGVsZXRpb25zKC0pCj4+ICAgY3Jl YXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvbnZtZS90YXJnZXQvYXV0aC5jCj4+ICAgY3JlYXRlIG1v ZGUgMTAwNjQ0IGRyaXZlcnMvbnZtZS90YXJnZXQvZmFicmljcy1jbWQtYXV0aC5jCj4+Cj4+IGRp ZmYgLS1naXQgYS9kcml2ZXJzL252bWUvdGFyZ2V0L0tjb25maWcgYi9kcml2ZXJzL252bWUvdGFy Z2V0L0tjb25maWcKPj4gaW5kZXggNGJlMmVjZWNiYzQ1Li5kNTY1NmVmMTU1OWUgMTAwNjQ0Cj4+ IC0tLSBhL2RyaXZlcnMvbnZtZS90YXJnZXQvS2NvbmZpZwo+PiArKysgYi9kcml2ZXJzL252bWUv dGFyZ2V0L0tjb25maWcKPj4gQEAgLTg1LDMgKzg1LDEzIEBAIGNvbmZpZyBOVk1FX1RBUkdFVF9U Q1AKPj4gICAJICBkZXZpY2VzIG92ZXIgVENQLgo+Pgo+PiAgIAkgIElmIHVuc3VyZSwgc2F5IE4u Cj4+ICsKPj4gK2NvbmZpZyBOVk1FX1RBUkdFVF9BVVRICj4+ICsJYm9vbCAiTlZNZSBvdmVyIEZh YnJpY3MgSW4tYmFuZCBBdXRoZW50aWNhdGlvbiBzdXBwb3J0Igo+PiArCWRlcGVuZHMgb24gTlZN RV9UQVJHRVQKPj4gKwlzZWxlY3QgQ1JZUFRPX1NIQTI1Ngo+PiArCXNlbGVjdCBDUllQVE9fU0hB NTEyCj4+ICsJaGVscAo+PiArCSAgVGhpcyBlbmFibGVzIHN1cHBvcnQgZm9yIE5WTWUgb3ZlciBG YWJyaWNzIEluLWJhbmQgQXV0aGVudGljYXRpb24KPj4gKwo+PiArCSAgSWYgdW5zdXJlLCBzYXkg Ti4KPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbnZtZS90YXJnZXQvTWFrZWZpbGUgYi9kcml2ZXJz L252bWUvdGFyZ2V0L01ha2VmaWxlCj4+IGluZGV4IDk4MzdlNTgwZmE3ZS4uYzY2ODIwMTAyNDkz IDEwMDY0NAo+PiAtLS0gYS9kcml2ZXJzL252bWUvdGFyZ2V0L01ha2VmaWxlCj4+ICsrKyBiL2Ry aXZlcnMvbnZtZS90YXJnZXQvTWFrZWZpbGUKPj4gQEAgLTEzLDYgKzEzLDcgQEAgbnZtZXQteQkJ Kz0gY29yZS5vIGNvbmZpZ2ZzLm8gYWRtaW4tY21kLm8KPiBmYWJyaWNzLWNtZC5vIFwKPj4gICAJ CQlkaXNjb3ZlcnkubyBpby1jbWQtZmlsZS5vIGlvLWNtZC1iZGV2Lm8KPj4gICBudm1ldC0kKENP TkZJR19OVk1FX1RBUkdFVF9QQVNTVEhSVSkJKz0gcGFzc3RocnUubwo+PiAgIG52bWV0LSQoQ09O RklHX0JMS19ERVZfWk9ORUQpCQkrPSB6bnMubwo+PiArbnZtZXQtJChDT05GSUdfTlZNRV9UQVJH RVRfQVVUSCkJKz0gZmFicmljcy1jbWQtYXV0aC5vIGF1dGgubwo+PiAgIG52bWUtbG9vcC15CSs9 IGxvb3Aubwo+PiAgIG52bWV0LXJkbWEteQkrPSByZG1hLm8KPj4gICBudm1ldC1mYy15CSs9IGZj Lm8KPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbnZtZS90YXJnZXQvYWRtaW4tY21kLmMKPj4gYi9k cml2ZXJzL252bWUvdGFyZ2V0L2FkbWluLWNtZC5jIGluZGV4IDBjYjk4ZjJiYmM4Yy4uMzIwY2Vm YzY0ZWUwIDEwMDY0NAo+PiAtLS0gYS9kcml2ZXJzL252bWUvdGFyZ2V0L2FkbWluLWNtZC5jCj4+ ICsrKyBiL2RyaXZlcnMvbnZtZS90YXJnZXQvYWRtaW4tY21kLmMKPj4gQEAgLTEwMDgsNiArMTAw OCwxMCBAQCB1MTYgbnZtZXRfcGFyc2VfYWRtaW5fY21kKHN0cnVjdCBudm1ldF9yZXEgKnJlcSkK Pj4KPj4gICAJaWYgKG52bWVfaXNfZmFicmljcyhjbWQpKQo+PiAgIAkJcmV0dXJuIG52bWV0X3Bh cnNlX2ZhYnJpY3NfY21kKHJlcSk7Cj4+ICsKPj4gKwlpZiAodW5saWtlbHkoIW52bWV0X2NoZWNr X2F1dGhfc3RhdHVzKHJlcSkpKQo+PiArCQlyZXR1cm4gTlZNRV9TQ19BVVRIX1JFUVVJUkVEIHwg TlZNRV9TQ19ETlI7Cj4+ICsKPj4gICAJaWYgKG52bWV0X3JlcV9zdWJzeXMocmVxKS0+dHlwZSA9 PSBOVk1FX05RTl9ESVNDKQo+PiAgIAkJcmV0dXJuIG52bWV0X3BhcnNlX2Rpc2NvdmVyeV9jbWQo cmVxKTsKPj4KPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbnZtZS90YXJnZXQvYXV0aC5jIGIvZHJp dmVycy9udm1lL3RhcmdldC9hdXRoLmMKPj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPj4gaW5kZXgg MDAwMDAwMDAwMDAwLi4wMGM3ZDA1MWRmYjEKPj4gLS0tIC9kZXYvbnVsbAo+PiArKysgYi9kcml2 ZXJzL252bWUvdGFyZ2V0L2F1dGguYwo+PiBAQCAtMCwwICsxLDM1MiBAQAo+PiArLy8gU1BEWC1M aWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjAKPj4gKy8qCj4+ICsgKiBOVk1lIG92ZXIgRmFicmlj cyBESC1ITUFDLUNIQVAgYXV0aGVudGljYXRpb24uCj4+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMjAg SGFubmVzIFJlaW5lY2tlLCBTVVNFIFNvZnR3YXJlIFNvbHV0aW9ucy4KPj4gKyAqIEFsbCByaWdo dHMgcmVzZXJ2ZWQuCj4+ICsgKi8KPj4gKyNkZWZpbmUgcHJfZm10KGZtdCkgS0JVSUxEX01PRE5B TUUgIjogIiBmbXQKPj4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KPj4gKyNpbmNsdWRlIDxs aW51eC9pbml0Lmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPgo+PiArI2luY2x1ZGUgPGxp bnV4L2Vyci5oPgo+PiArI2luY2x1ZGUgPGNyeXB0by9oYXNoLmg+Cj4+ICsjaW5jbHVkZSA8Y3J5 cHRvL2twcC5oPgo+PiArI2luY2x1ZGUgPGNyeXB0by9kaC5oPgo+PiArI2luY2x1ZGUgPGNyeXB0 by9mZmRoZS5oPgo+PiArI2luY2x1ZGUgPGxpbnV4L2NyYzMyLmg+Cj4+ICsjaW5jbHVkZSA8bGlu dXgvYmFzZTY0Lmg+Cj4+ICsjaW5jbHVkZSA8bGludXgvY3R5cGUuaD4KPj4gKyNpbmNsdWRlIDxs aW51eC9yYW5kb20uaD4KPj4gKyNpbmNsdWRlIDxhc20vdW5hbGlnbmVkLmg+Cj4+ICsKPj4gKyNp bmNsdWRlICJudm1ldC5oIgo+PiArI2luY2x1ZGUgIi4uL2hvc3QvYXV0aC5oIgo+PiArCj4+ICtp bnQgbnZtZXRfYXV0aF9zZXRfaG9zdF9rZXkoc3RydWN0IG52bWV0X2hvc3QgKmhvc3QsIGNvbnN0 IGNoYXIgKnNlY3JldCkKPj4gK3sKPj4gKwlpZiAoc3NjYW5mKHNlY3JldCwgIkRISEMtMTolaGhk OiUqcyIsICZob3N0LT5kaGNoYXBfa2V5X2hhc2gpICE9IDEpCj4+ICsJCXJldHVybiAtRUlOVkFM Owo+PiArCWlmIChob3N0LT5kaGNoYXBfa2V5X2hhc2ggPiAzKSB7Cj4+ICsJCXByX3dhcm4oIklu dmFsaWQgREgtSE1BQy1DSEFQIGhhc2ggaWQgJWRcbiIsCj4+ICsJCQkgaG9zdC0+ZGhjaGFwX2tl eV9oYXNoKTsKPj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4+ICsJfQo+PiArCWlmIChob3N0LT5kaGNo YXBfa2V5X2hhc2ggPiAwKSB7Cj4+ICsJCS8qIFZhbGlkYXRlIHNlbGVjdGVkIGhhc2ggYWxnb3Jp dGhtICovCj4+ICsJCWNvbnN0IGNoYXIgKmhtYWMgPSBudm1lX2F1dGhfaG1hY19uYW1lKGhvc3Qt PmRoY2hhcF9rZXlfaGFzaCk7Cj4+ICsKPj4gKwkJaWYgKCFjcnlwdG9faGFzX3NoYXNoKGhtYWMs IDAsIDApKSB7Cj4+ICsJCQlwcl93YXJuKCJESC1ITUFDLUNIQVAgaGFzaCAlcyB1bnN1cHBvcnRl ZFxuIiwgaG1hYyk7Cj4+ICsJCQlob3N0LT5kaGNoYXBfa2V5X2hhc2ggPSAtMTsKPj4gKwkJCXJl dHVybiAtRUFHQUlOOwo+PiArCQl9Cj4+ICsJCS8qIFVzZSB0aGlzIGhhc2ggYXMgZGVmYXVsdCAq Lwo+PiArCQlpZiAoIWhvc3QtPmRoY2hhcF9oYXNoX2lkKQo+PiArCQkJaG9zdC0+ZGhjaGFwX2hh c2hfaWQgPSBob3N0LT5kaGNoYXBfa2V5X2hhc2g7Cj4+ICsJfQo+PiArCWhvc3QtPmRoY2hhcF9z ZWNyZXQgPSBrc3RyZHVwKHNlY3JldCwgR0ZQX0tFUk5FTCk7Cj4gCj4gSnVzdCBsaWtlIGJlZm9y ZSAtIGFyZSB5b3Ugc3VyZSB0aGF0IHRoZSBzZWNyZXQgaXMgYW4gQVNDSUkgc3RyaW5nIGFuZCBu bwo+IGJpbmFyeSBibG9iPwo+IAoKVGhhdCBpcyBlbnN1cmVkIGJ5IHRoZSB0cmFuc3BvcnQgZW5j b2RpbmcgKGNmIE5WTWUgQmFzZSBTcGVjaWZpY2F0aW9uIAp2ZXJzaW9uIDIuMCkuIEFsc28sIHRo aXMgaW5mb3JtYXRpb24gaXMgYmVpbmcgcGFzc2VkIGluIHZpYSB0aGUgY29uZmlnZnMgCmludGVy ZmFjZSwgc28gaXQncyBib3VuZGVkIGJ5IFBBR0VfU0laRS4gQnV0IHllcywgd2Ugc2hvdWxkIGJl IGluc2VydGluZyAKYSB0ZXJtaW5hdGluZyAnTlVMTCcgY2hhcmFjdGVyIGF0IHRoZSBlbmQgb2Yg dGhlIHBhZ2UgdG8gZW5zdXJlIHdlIGRvbid0IAppbmN1ciBhbiBidWZmZXIgb3ZlcnJ1bi4gQW55 IG90aGVyIGZhaWx1cmUgd2lsbCBiZSBjaGVja2VkIGZvciBkdXJpbmcgCmJhc2U2NCBkZWNvZGlu Zy4KCj4+ICsJaWYgKCFob3N0LT5kaGNoYXBfc2VjcmV0KQo+PiArCQlyZXR1cm4gLUVOT01FTTsK Pj4gKwkvKiBEZWZhdWx0IHRvIFNIQTI1NiAqLwo+PiArCWlmICghaG9zdC0+ZGhjaGFwX2hhc2hf aWQpCj4+ICsJCWhvc3QtPmRoY2hhcF9oYXNoX2lkID0gTlZNRV9BVVRIX0RIQ0hBUF9IQVNIX1NI QTI1NjsKPj4gKwo+PiArCXByX2RlYnVnKCJVc2luZyBoYXNoICVzXG4iLAo+PiArCQkgbnZtZV9h dXRoX2htYWNfbmFtZShob3N0LT5kaGNoYXBfaGFzaF9pZCkpOwo+PiArCXJldHVybiAwOwo+PiAr fQo+PiArCj4+ICtpbnQgbnZtZXRfc2V0dXBfZGhncm91cChzdHJ1Y3QgbnZtZXRfY3RybCAqY3Ry bCwgaW50IGRoZ3JvdXBfaWQpCj4+ICt7Cj4+ICsJaW50IHJldCA9IC1FTk9UU1VQUDsKPj4gKwo+ PiArCWlmIChkaGdyb3VwX2lkID09IE5WTUVfQVVUSF9ESENIQVBfREhHUk9VUF9OVUxMKQo+PiAr CQlyZXR1cm4gMDsKPj4gKwo+PiArCXJldHVybiByZXQ7Cj4+ICt9Cj4+ICsKPj4gK2ludCBudm1l dF9zZXR1cF9hdXRoKHN0cnVjdCBudm1ldF9jdHJsICpjdHJsLCBzdHJ1Y3QgbnZtZXRfcmVxICpy ZXEpCj4+ICt7Cj4+ICsJaW50IHJldCA9IDA7Cj4+ICsJc3RydWN0IG52bWV0X2hvc3RfbGluayAq cDsKPj4gKwlzdHJ1Y3QgbnZtZXRfaG9zdCAqaG9zdCA9IE5VTEw7Cj4+ICsJY29uc3QgY2hhciAq aGFzaF9uYW1lOwo+PiArCj4+ICsJZG93bl9yZWFkKCZudm1ldF9jb25maWdfc2VtKTsKPj4gKwlp ZiAoY3RybC0+c3Vic3lzLT50eXBlID09IE5WTUVfTlFOX0RJU0MpCj4+ICsJCWdvdG8gb3V0X3Vu bG9jazsKPj4gKwo+PiArCWxpc3RfZm9yX2VhY2hfZW50cnkocCwgJmN0cmwtPnN1YnN5cy0+aG9z dHMsIGVudHJ5KSB7Cj4+ICsJCXByX2RlYnVnKCJjaGVjayAlc1xuIiwgbnZtZXRfaG9zdF9uYW1l KHAtPmhvc3QpKTsKPj4gKwkJaWYgKHN0cmNtcChudm1ldF9ob3N0X25hbWUocC0+aG9zdCksIGN0 cmwtPmhvc3RucW4pKQo+PiArCQkJY29udGludWU7Cj4+ICsJCWhvc3QgPSBwLT5ob3N0Owo+PiAr CQlicmVhazsKPj4gKwl9Cj4+ICsJaWYgKCFob3N0KSB7Cj4+ICsJCXByX2RlYnVnKCJob3N0ICVz IG5vdCBmb3VuZFxuIiwgY3RybC0+aG9zdG5xbik7Cj4+ICsJCXJldCA9IC1FUEVSTTsKPj4gKwkJ Z290byBvdXRfdW5sb2NrOwo+PiArCX0KPj4gKwlpZiAoIWhvc3QtPmRoY2hhcF9zZWNyZXQpIHsK Pj4gKwkJcHJfZGVidWcoIk5vIGF1dGhlbnRpY2F0aW9uIHByb3ZpZGVkXG4iKTsKPj4gKwkJZ290 byBvdXRfdW5sb2NrOwo+PiArCX0KPj4gKwo+PiArCWhhc2hfbmFtZSA9IG52bWVfYXV0aF9obWFj X25hbWUoaG9zdC0+ZGhjaGFwX2hhc2hfaWQpOwo+PiArCWlmICghaGFzaF9uYW1lKSB7Cj4+ICsJ CXByX2RlYnVnKCJIYXNoIElEICVkIGludmFsaWRcbiIsIGhvc3QtPmRoY2hhcF9oYXNoX2lkKTsK Pj4gKwkJcmV0ID0gLUVJTlZBTDsKPj4gKwkJZ290byBvdXRfdW5sb2NrOwo+PiArCX0KPj4gKwlj dHJsLT5zaGFzaF90Zm0gPSBjcnlwdG9fYWxsb2Nfc2hhc2goaGFzaF9uYW1lLCAwLAo+PiArCQkJ CQkgICAgIENSWVBUT19BTEdfQUxMT0NBVEVTX01FTU9SWSk7Cj4+ICsJaWYgKElTX0VSUihjdHJs LT5zaGFzaF90Zm0pKSB7Cj4+ICsJCXByX2RlYnVnKCJmYWlsZWQgdG8gYWxsb2NhdGUgc2hhc2gg JXNcbiIsIGhhc2hfbmFtZSk7Cj4+ICsJCXJldCA9IFBUUl9FUlIoY3RybC0+c2hhc2hfdGZtKTsK Pj4gKwkJY3RybC0+c2hhc2hfdGZtID0gTlVMTDsKPj4gKwkJZ290byBvdXRfdW5sb2NrOwo+PiAr CX0KPj4gKwo+PiArCWN0cmwtPmRoY2hhcF9rZXkgPSBudm1lX2F1dGhfZXh0cmFjdF9zZWNyZXQo aG9zdC0+ZGhjaGFwX3NlY3JldCwKPj4gKwkJCQkJCSAgICAmY3RybC0+ZGhjaGFwX2tleV9sZW4p Owo+PiArCWlmIChJU19FUlIoY3RybC0+ZGhjaGFwX2tleSkpIHsKPj4gKwkJcHJfZGVidWcoImZh aWxlZCB0byBleHRyYWN0IGhvc3Qga2V5LCBlcnJvciAlZFxuIiwgcmV0KTsKPj4gKwkJcmV0ID0g UFRSX0VSUihjdHJsLT5kaGNoYXBfa2V5KTsKPj4gKwkJY3RybC0+ZGhjaGFwX2tleSA9IE5VTEw7 Cj4+ICsJCWdvdG8gb3V0X2ZyZWVfaGFzaDsKPj4gKwl9Cj4+ICsJaWYgKGhvc3QtPmRoY2hhcF9r ZXlfaGFzaCkgewo+PiArCQlzdHJ1Y3QgY3J5cHRvX3NoYXNoICprZXlfdGZtOwo+PiArCj4+ICsJ CWhhc2hfbmFtZSA9IG52bWVfYXV0aF9obWFjX25hbWUoaG9zdC0+ZGhjaGFwX2tleV9oYXNoKTsK Pj4gKwkJa2V5X3RmbSA9IGNyeXB0b19hbGxvY19zaGFzaChoYXNoX25hbWUsIDAsIDApOwo+PiAr CQlpZiAoSVNfRVJSKGtleV90Zm0pKSB7Cj4+ICsJCQlyZXQgPSBQVFJfRVJSKGtleV90Zm0pOwo+ PiArCQkJZ290byBvdXRfZnJlZV9oYXNoOwo+PiArCQl9IGVsc2Ugewo+PiArCQkJU0hBU0hfREVT Q19PTl9TVEFDSyhzaGFzaCwga2V5X3RmbSk7Cj4+ICsKPj4gKwkJCXNoYXNoLT50Zm0gPSBrZXlf dGZtOwo+PiArCQkJcmV0ID0gY3J5cHRvX3NoYXNoX3NldGtleShrZXlfdGZtLCBjdHJsLT5kaGNo YXBfa2V5LAo+PiArCQkJCQkJICBjdHJsLT5kaGNoYXBfa2V5X2xlbik7Cj4+ICsJCQljcnlwdG9f c2hhc2hfaW5pdChzaGFzaCk7Cj4+ICsJCQljcnlwdG9fc2hhc2hfdXBkYXRlKHNoYXNoLCBjdHJs LT5zdWJzeXMtPnN1YnN5c25xbiwKPj4gKwkJCQkJICAgIHN0cmxlbihjdHJsLT5zdWJzeXMtPnN1 YnN5c25xbikpOwo+PiArCQkJY3J5cHRvX3NoYXNoX3VwZGF0ZShzaGFzaCwgIk5WTWUtb3Zlci1G YWJyaWNzIiwgMTcpOwo+PiArCQkJY3J5cHRvX3NoYXNoX2ZpbmFsKHNoYXNoLCBjdHJsLT5kaGNo YXBfa2V5KTsKPj4gKwkJCWNyeXB0b19mcmVlX3NoYXNoKGtleV90Zm0pOwo+PiArCQl9Cj4+ICsJ fQo+PiArCXByX2RlYnVnKCIlczogdXNpbmcga2V5ICUqcGhcbiIsIF9fZnVuY19fLAo+PiArCQkg KGludCljdHJsLT5kaGNoYXBfa2V5X2xlbiwgY3RybC0+ZGhjaGFwX2tleSk7Cj4+ICsJcmV0ID0g Y3J5cHRvX3NoYXNoX3NldGtleShjdHJsLT5zaGFzaF90Zm0sIGN0cmwtPmRoY2hhcF9rZXksCj4g Cj4gSXMgaXQgdHJ1bHkgbmVjZXNzYXJ5IHRvIGtlZXAgdGhlIGtleSBhcm91bmQgaW4gY3RybC0+ ZGhjaGFwX2tleT8gSXQgbG9va3MgdG8KPiBtZSB0aGF0IHRoaXMgYnVmZmVyIGlzIG9ubHkgdXNl ZCBoZXJlIGFuZCB0aHVzIGNvdWxkIGJlIHR1cm5lZCBpbnRvIGEgbG9jYWwKPiB2YXJpYWJsZS4g S2V5cyBmbHlpbmcgYXJvdW5kIGluIG1lbW9yeSBpcyBub3QgYSBnb29kIGlkZWEuIDotKQo+IApU aGUga2V5IGlzIGFsc28gdXNlZCB3aGVuIHVzaW5nIHRoZSBmZmRoZSBhbGdvcml0aG0uCk5vdGU6 IEkgX3RoaW5rXyB0aGF0IEkgbmVlZCB0byB1c2UgdGhpcyBrZXkgZm9yIHRoZSBmZmRoZSBhbGdv cml0aG0sIApiZWNhdXNlIHRoZSBpbXBsZW1lbnRhdGlvbiBJIGNhbWUgdXAgd2l0aCBpcyBlc3Nl bnRpYWxseSBwbGFpbiBESCB3aXRoIApwcmUtZGVmaW5lZCAncCcsICdxJyBhbmQgJ2cnIHZhbHVl cy4gQnV0IHRoZSBESCBpbXBsZW1lbnRhdGlvbiBhbHNvIApyZXF1aXJlcyBhICdrZXknLCBhbmQg Zm9yIHRoYXQgSSdtIHVzaW5nIHRoaXMga2V5IGhlcmUuCgpJdCBtaWdodCBiZSB0aGF0IEknbSBj b21wbGV0ZWx5IG9mZiwgYW5kIGRvbid0IG5lZWQgdG8gdXNlIGEga2V5IGZvciBvdXIgCkRIIGlt cGxlbWVudGF0aW9uLiBJbiB0aGF0IGNhc2UgeW91IGFyZSBjb3JyZWN0LgooQW5kIHRoYXQncyB3 aHkgSSBzYWlkIEknbGwgbmVlZCBhIHJldmlldyBvZiB0aGUgRkZESEUgaW1wbGVtZW50YXRpb24p LgpCdXQgZm9yIG5vdyBJJ2xsIG5lZWQgdGhlIGtleSBmb3IgRkZESEUuCgo+PiArCQkJCSAgY3Ry bC0+ZGhjaGFwX2tleV9sZW4pOwo+PiArb3V0X2ZyZWVfaGFzaDoKPj4gKwlpZiAocmV0KSB7Cj4+ ICsJCWlmIChjdHJsLT5kaGNoYXBfa2V5KSB7Cj4+ICsJCQlrZnJlZShjdHJsLT5kaGNoYXBfa2V5 KTsKPiAKPiBrZnJlZV9zZW5zaXRpdmU/Cj4gCgpZZXMsIHdpbGwgYmUgZml4aW5nIGl0LgoKPj4g KwkJCWN0cmwtPmRoY2hhcF9rZXkgPSBOVUxMOwo+PiArCQl9Cj4+ICsJCWNyeXB0b19mcmVlX3No YXNoKGN0cmwtPnNoYXNoX3RmbSk7Cj4+ICsJCWN0cmwtPnNoYXNoX3RmbSA9IE5VTEw7Cj4+ICsJ fQo+PiArb3V0X3VubG9jazoKPj4gKwl1cF9yZWFkKCZudm1ldF9jb25maWdfc2VtKTsKPj4gKwo+ PiArCXJldHVybiByZXQ7Cj4+ICt9Cj4+ICsKPj4gK3ZvaWQgbnZtZXRfYXV0aF9zcV9mcmVlKHN0 cnVjdCBudm1ldF9zcSAqc3EpCj4+ICt7Cj4+ICsJaWYgKHNxLT5kaGNoYXBfYzEpCj4+ICsJCWtm cmVlKHNxLT5kaGNoYXBfYzEpOwo+PiArCWlmIChzcS0+ZGhjaGFwX2MyKQo+PiArCQlrZnJlZShz cS0+ZGhjaGFwX2MyKTsKPj4gKwlpZiAoc3EtPmRoY2hhcF9za2V5KQo+PiArCQlrZnJlZShzcS0+ ZGhjaGFwX3NrZXkpOwo+IAo+IGtmcmVlX3NlbnNpdGl2ZT8KPiAKClllcy4KCj4+ICt9Cj4+ICsK Pj4gK3ZvaWQgbnZtZXRfcmVzZXRfYXV0aChzdHJ1Y3QgbnZtZXRfY3RybCAqY3RybCkKPj4gK3sK Pj4gKwlpZiAoY3RybC0+c2hhc2hfdGZtKSB7Cj4+ICsJCWNyeXB0b19mcmVlX3NoYXNoKGN0cmwt PnNoYXNoX3RmbSk7Cj4+ICsJCWN0cmwtPnNoYXNoX3RmbSA9IE5VTEw7Cj4+ICsJfQo+PiArCWlm IChjdHJsLT5kaF90Zm0pIHsKPj4gKwkJY3J5cHRvX2ZyZWVfa3BwKGN0cmwtPmRoX3RmbSk7Cj4+ ICsJCWN0cmwtPmRoX3RmbSA9IE5VTEw7Cj4+ICsJfQo+PiArCWlmIChjdHJsLT5kaGNoYXBfa2V5 KSB7Cj4+ICsJCWtmcmVlKGN0cmwtPmRoY2hhcF9rZXkpOwo+IAo+IGtmcmVlX3NlbnNpdGl2ZT8K PiAKClllcy4KCj4+ICsJCWN0cmwtPmRoY2hhcF9rZXkgPSBOVUxMOwo+PiArCX0KPj4gK30KPj4g Kwo+PiArYm9vbCBudm1ldF9jaGVja19hdXRoX3N0YXR1cyhzdHJ1Y3QgbnZtZXRfcmVxICpyZXEp Cj4+ICt7Cj4+ICsJaWYgKHJlcS0+c3EtPmN0cmwtPnNoYXNoX3RmbSAmJgo+PiArCSAgICAhcmVx LT5zcS0+YXV0aGVudGljYXRlZCkKPj4gKwkJcmV0dXJuIGZhbHNlOwo+PiArCXJldHVybiB0cnVl Owo+PiArfQo+PiArCj4+ICtpbnQgbnZtZXRfYXV0aF9ob3N0X2hhc2goc3RydWN0IG52bWV0X3Jl cSAqcmVxLCB1OCAqcmVzcG9uc2UsCj4+ICsJCQkgdW5zaWduZWQgaW50IHNoYXNoX2xlbikKPj4g K3sKPj4gKwlzdHJ1Y3QgbnZtZXRfY3RybCAqY3RybCA9IHJlcS0+c3EtPmN0cmw7Cj4+ICsJU0hB U0hfREVTQ19PTl9TVEFDSyhzaGFzaCwgY3RybC0+c2hhc2hfdGZtKTsKPj4gKwl1OCAqY2hhbGxl bmdlID0gcmVxLT5zcS0+ZGhjaGFwX2MxOwo+PiArCXU4IGJ1Zls0XTsKPj4gKwlpbnQgcmV0Owo+ PiArCj4+ICsJaWYgKGN0cmwtPmRoX2dpZCAhPSBOVk1FX0FVVEhfREhDSEFQX0RIR1JPVVBfTlVM TCkgewo+PiArCQlyZXQgPSAtRU5PVFNVUFA7Cj4+ICsJCWdvdG8gb3V0Owo+PiArCX0KPj4gKwo+ PiArCXNoYXNoLT50Zm0gPSBjdHJsLT5zaGFzaF90Zm07Cj4+ICsJcmV0ID0gY3J5cHRvX3NoYXNo X2luaXQoc2hhc2gpOwo+PiArCWlmIChyZXQpCj4+ICsJCWdvdG8gb3V0Owo+PiArCXJldCA9IGNy eXB0b19zaGFzaF91cGRhdGUoc2hhc2gsIGNoYWxsZW5nZSwgc2hhc2hfbGVuKTsKPj4gKwlpZiAo cmV0KQo+PiArCQlnb3RvIG91dDsKPj4gKwlwdXRfdW5hbGlnbmVkX2xlMzIocmVxLT5zcS0+ZGhj aGFwX3MxLCBidWYpOwo+PiArCXJldCA9IGNyeXB0b19zaGFzaF91cGRhdGUoc2hhc2gsIGJ1Ziwg NCk7Cj4+ICsJaWYgKHJldCkKPj4gKwkJZ290byBvdXQ7Cj4+ICsJcHV0X3VuYWxpZ25lZF9sZTE2 KHJlcS0+c3EtPmRoY2hhcF90aWQsIGJ1Zik7Cj4+ICsJcmV0ID0gY3J5cHRvX3NoYXNoX3VwZGF0 ZShzaGFzaCwgYnVmLCAyKTsKPj4gKwlpZiAocmV0KQo+PiArCQlnb3RvIG91dDsKPj4gKwltZW1z ZXQoYnVmLCAwLCA0KTsKPj4gKwlyZXQgPSBjcnlwdG9fc2hhc2hfdXBkYXRlKHNoYXNoLCBidWYs IDEpOwo+PiArCWlmIChyZXQpCj4+ICsJCWdvdG8gb3V0Owo+PiArCXJldCA9IGNyeXB0b19zaGFz aF91cGRhdGUoc2hhc2gsICJIb3N0SG9zdCIsIDgpOwo+PiArCWlmIChyZXQpCj4+ICsJCWdvdG8g b3V0Owo+PiArCXJldCA9IGNyeXB0b19zaGFzaF91cGRhdGUoc2hhc2gsIGN0cmwtPmhvc3RucW4s IHN0cmxlbihjdHJsLT5ob3N0bnFuKSk7Cj4+ICsJaWYgKHJldCkKPj4gKwkJZ290byBvdXQ7Cj4+ ICsJcmV0ID0gY3J5cHRvX3NoYXNoX3VwZGF0ZShzaGFzaCwgYnVmLCAxKTsKPj4gKwlpZiAocmV0 KQo+PiArCQlnb3RvIG91dDsKPj4gKwlyZXQgPSBjcnlwdG9fc2hhc2hfdXBkYXRlKHNoYXNoLCBj dHJsLT5zdWJzeXNucW4sCj4+ICsJCQkJICBzdHJsZW4oY3RybC0+c3Vic3lzbnFuKSk7Cj4+ICsJ aWYgKHJldCkKPj4gKwkJZ290byBvdXQ7Cj4+ICsJcmV0ID0gY3J5cHRvX3NoYXNoX2ZpbmFsKHNo YXNoLCByZXNwb25zZSk7Cj4+ICtvdXQ6Cj4+ICsJaWYgKGNoYWxsZW5nZSAhPSByZXEtPnNxLT5k aGNoYXBfYzEpCj4+ICsJCWtmcmVlKGNoYWxsZW5nZSk7Cj4+ICsJcmV0dXJuIDA7Cj4+ICt9Cj4+ ICsKPj4gK2ludCBudm1ldF9hdXRoX2N0cmxfaGFzaChzdHJ1Y3QgbnZtZXRfcmVxICpyZXEsIHU4 ICpyZXNwb25zZSwKPj4gKwkJCSB1bnNpZ25lZCBpbnQgc2hhc2hfbGVuKQo+PiArewo+PiArCXN0 cnVjdCBudm1ldF9jdHJsICpjdHJsID0gcmVxLT5zcS0+Y3RybDsKPj4gKwlTSEFTSF9ERVNDX09O X1NUQUNLKHNoYXNoLCBjdHJsLT5zaGFzaF90Zm0pOwo+PiArCXU4ICpjaGFsbGVuZ2UgPSByZXEt PnNxLT5kaGNoYXBfYzI7Cj4+ICsJdTggYnVmWzRdOwo+PiArCWludCByZXQ7Cj4+ICsKPj4gKwlw cl9kZWJ1ZygiJXM6IGN0cmwgJWQgaGFzaCBzZXEgJWQgdHJhbnNhY3Rpb24gJXVcbiIsIF9fZnVu Y19fLAo+PiArCQkgY3RybC0+Y250bGlkLCByZXEtPnNxLT5kaGNoYXBfczIsIHJlcS0+c3EtPmRo Y2hhcF90aWQpOwo+PiArCXByX2RlYnVnKCIlczogY3RybCAlZCBjaGFsbGVuZ2UgJSpwaFxuIiwg X19mdW5jX18sCj4+ICsJCSBjdHJsLT5jbnRsaWQsIHNoYXNoX2xlbiwgcmVxLT5zcS0+ZGhjaGFw X2MyKTsKPj4gKwlwcl9kZWJ1ZygiJXM6IGN0cmwgJWQgc3Vic3lzbnFuICVzXG4iLCBfX2Z1bmNf XywKPj4gKwkJIGN0cmwtPmNudGxpZCwgY3RybC0+c3Vic3lzbnFuKTsKPj4gKwlwcl9kZWJ1Zygi JXM6IGN0cmwgJWQgaG9zdG5xbiAlc1xuIiwgX19mdW5jX18sCj4+ICsJCSBjdHJsLT5jbnRsaWQs IGN0cmwtPmhvc3RucW4pOwo+PiArCj4+ICsJaWYgKGN0cmwtPmRoX2dpZCAhPSBOVk1FX0FVVEhf REhDSEFQX0RIR1JPVVBfTlVMTCkgewo+PiArCQlyZXQgPSAtRU5PVFNVUFA7Cj4+ICsJCWdvdG8g b3V0Owo+PiArCX0KPj4gKwo+PiArCXNoYXNoLT50Zm0gPSBjdHJsLT5zaGFzaF90Zm07Cj4+ICsJ cmV0ID0gY3J5cHRvX3NoYXNoX2luaXQoc2hhc2gpOwo+PiArCWlmIChyZXQpCj4+ICsJCWdvdG8g b3V0Owo+PiArCXJldCA9IGNyeXB0b19zaGFzaF91cGRhdGUoc2hhc2gsIGNoYWxsZW5nZSwgc2hh c2hfbGVuKTsKPj4gKwlpZiAocmV0KQo+PiArCQlnb3RvIG91dDsKPj4gKwlwdXRfdW5hbGlnbmVk X2xlMzIocmVxLT5zcS0+ZGhjaGFwX3MyLCBidWYpOwo+PiArCXJldCA9IGNyeXB0b19zaGFzaF91 cGRhdGUoc2hhc2gsIGJ1ZiwgNCk7Cj4+ICsJaWYgKHJldCkKPj4gKwkJZ290byBvdXQ7Cj4+ICsJ cHV0X3VuYWxpZ25lZF9sZTE2KHJlcS0+c3EtPmRoY2hhcF90aWQsIGJ1Zik7Cj4+ICsJcmV0ID0g Y3J5cHRvX3NoYXNoX3VwZGF0ZShzaGFzaCwgYnVmLCAyKTsKPj4gKwlpZiAocmV0KQo+PiArCQln b3RvIG91dDsKPj4gKwltZW1zZXQoYnVmLCAwLCA0KTsKPj4gKwlyZXQgPSBjcnlwdG9fc2hhc2hf dXBkYXRlKHNoYXNoLCBidWYsIDEpOwo+PiArCWlmIChyZXQpCj4+ICsJCWdvdG8gb3V0Owo+PiAr CXJldCA9IGNyeXB0b19zaGFzaF91cGRhdGUoc2hhc2gsICJDb250cm9sbGVyIiwgMTApOwo+PiAr CWlmIChyZXQpCj4+ICsJCWdvdG8gb3V0Owo+PiArCXJldCA9IGNyeXB0b19zaGFzaF91cGRhdGUo c2hhc2gsIGN0cmwtPnN1YnN5c25xbiwKPj4gKwkJCSAgICBzdHJsZW4oY3RybC0+c3Vic3lzbnFu KSk7Cj4+ICsJaWYgKHJldCkKPj4gKwkJZ290byBvdXQ7Cj4+ICsJcmV0ID0gY3J5cHRvX3NoYXNo X3VwZGF0ZShzaGFzaCwgYnVmLCAxKTsKPj4gKwlpZiAocmV0KQo+PiArCQlnb3RvIG91dDsKPj4g KwlyZXQgPSBjcnlwdG9fc2hhc2hfdXBkYXRlKHNoYXNoLCBjdHJsLT5ob3N0bnFuLCBzdHJsZW4o Y3RybC0+aG9zdG5xbikpOwo+PiArCWlmIChyZXQpCj4+ICsJCWdvdG8gb3V0Owo+PiArCXJldCA9 IGNyeXB0b19zaGFzaF9maW5hbChzaGFzaCwgcmVzcG9uc2UpOwo+PiArb3V0Ogo+PiArCWlmIChj aGFsbGVuZ2UgIT0gcmVxLT5zcS0+ZGhjaGFwX2MyKQo+PiArCQlrZnJlZShjaGFsbGVuZ2UpOwo+ PiArCXJldHVybiAwOwo+PiArfQo+PiArCj4+ICtpbnQgbnZtZXRfYXV0aF9jdHJsX3Nlc3NrZXko c3RydWN0IG52bWV0X3JlcSAqcmVxLAo+PiArCQkJICAgIHU4ICpwa2V5LCBpbnQgcGtleV9zaXpl KQo+PiArewo+PiArCXN0cnVjdCBudm1ldF9jdHJsICpjdHJsID0gcmVxLT5zcS0+Y3RybDsKPj4g KwlzdHJ1Y3Qga3BwX3JlcXVlc3QgKmtwcF9yZXE7Cj4+ICsJc3RydWN0IGNyeXB0b193YWl0IHdh aXQ7Cj4+ICsJc3RydWN0IHNjYXR0ZXJsaXN0IHNyYywgZHN0Owo+PiArCWludCByZXQ7Cj4+ICsK Pj4gKwlyZXEtPnNxLT5kaGNoYXBfc2tleV9sZW4gPQo+PiArCQludm1lX2F1dGhfZGhncm91cF9w cml2a2V5X3NpemUoY3RybC0+ZGhfZ2lkKTsKPj4gKwlyZXEtPnNxLT5kaGNoYXBfc2tleSA9IGt6 YWxsb2MocmVxLT5zcS0+ZGhjaGFwX3NrZXlfbGVuLCBHRlBfS0VSTkVMKTsKPj4gKwlpZiAoIXJl cS0+c3EtPmRoY2hhcF9za2V5KQo+PiArCQlyZXR1cm4gLUVOT01FTTsKPj4gKwlrcHBfcmVxID0g a3BwX3JlcXVlc3RfYWxsb2MoY3RybC0+ZGhfdGZtLCBHRlBfS0VSTkVMKTsKPj4gKwlpZiAoIWtw cF9yZXEpIHsKPj4gKwkJa2ZyZWUocmVxLT5zcS0+ZGhjaGFwX3NrZXkpOwo+PiArCQlyZXEtPnNx LT5kaGNoYXBfc2tleSA9IE5VTEw7Cj4+ICsJCXJldHVybiAtRU5PTUVNOwo+PiArCX0KPj4gKwo+ PiArCXByX2RlYnVnKCIlczogaG9zdCBwdWJsaWMga2V5ICUqcGhcbiIsIF9fZnVuY19fLAo+PiAr CQkgKGludClwa2V5X3NpemUsIHBrZXkpOwo+PiArCWNyeXB0b19pbml0X3dhaXQoJndhaXQpOwo+ PiArCXNnX2luaXRfb25lKCZzcmMsIHBrZXksIHBrZXlfc2l6ZSk7Cj4+ICsJa3BwX3JlcXVlc3Rf c2V0X2lucHV0KGtwcF9yZXEsICZzcmMsIHBrZXlfc2l6ZSk7Cj4+ICsJc2dfaW5pdF9vbmUoJmRz dCwgcmVxLT5zcS0+ZGhjaGFwX3NrZXksCj4+ICsJCXJlcS0+c3EtPmRoY2hhcF9za2V5X2xlbik7 Cj4+ICsJa3BwX3JlcXVlc3Rfc2V0X291dHB1dChrcHBfcmVxLCAmZHN0LCByZXEtPnNxLT5kaGNo YXBfc2tleV9sZW4pOwo+PiArCWtwcF9yZXF1ZXN0X3NldF9jYWxsYmFjayhrcHBfcmVxLCBDUllQ VE9fVEZNX1JFUV9NQVlfQkFDS0xPRywKPj4gKwkJCQkgY3J5cHRvX3JlcV9kb25lLCAmd2FpdCk7 Cj4+ICsKPj4gKwlyZXQgPSBjcnlwdG9fd2FpdF9yZXEoY3J5cHRvX2twcF9jb21wdXRlX3NoYXJl ZF9zZWNyZXQoa3BwX3JlcSksICZ3YWl0KTsKPj4gKwlrcHBfcmVxdWVzdF9mcmVlKGtwcF9yZXEp Owo+PiArCWlmIChyZXQpCj4+ICsJCXByX2RlYnVnKCJmYWlsZWQgdG8gY29tcHV0ZSBzaGFyZWQg c2VjcmVkLCBlcnIgJWRcbiIsIHJldCk7Cj4+ICsJZWxzZQo+PiArCQlwcl9kZWJ1ZygiJXM6IHNo YXJlZCBzZWNyZXQgJSpwaFxuIiwgX19mdW5jX18sCj4+ICsJCQkgKGludClyZXEtPnNxLT5kaGNo YXBfc2tleV9sZW4sCj4+ICsJCQkgcmVxLT5zcS0+ZGhjaGFwX3NrZXkpOwo+PiArCj4+ICsJcmV0 dXJuIHJldDsKPj4gK30KPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbnZtZS90YXJnZXQvY29uZmln ZnMuYyBiL2RyaXZlcnMvbnZtZS90YXJnZXQvY29uZmlnZnMuYwo+PiBpbmRleCAyNzM1NTUxMjcx ODguLmUwNzYwOTExYTc2MSAxMDA2NDQKPj4gLS0tIGEvZHJpdmVycy9udm1lL3RhcmdldC9jb25m aWdmcy5jCj4+ICsrKyBiL2RyaXZlcnMvbnZtZS90YXJnZXQvY29uZmlnZnMuYwo+PiBAQCAtMTEs OCArMTEsMTMgQEAKPj4gICAjaW5jbHVkZSA8bGludXgvY3R5cGUuaD4KPj4gICAjaW5jbHVkZSA8 bGludXgvcGNpLmg+Cj4+ICAgI2luY2x1ZGUgPGxpbnV4L3BjaS1wMnBkbWEuaD4KPj4gKyNpbmNs dWRlIDxjcnlwdG8vaGFzaC5oPgo+PiArI2luY2x1ZGUgPGNyeXB0by9rcHAuaD4KPj4KPj4gICAj aW5jbHVkZSAibnZtZXQuaCIKPj4gKyNpZmRlZiBDT05GSUdfTlZNRV9UQVJHRVRfQVVUSAo+PiAr I2luY2x1ZGUgIi4uL2hvc3QvYXV0aC5oIgo+PiArI2VuZGlmCj4+Cj4+ICAgc3RhdGljIGNvbnN0 IHN0cnVjdCBjb25maWdfaXRlbV90eXBlIG52bWV0X2hvc3RfdHlwZTsKPj4gICBzdGF0aWMgY29u c3Qgc3RydWN0IGNvbmZpZ19pdGVtX3R5cGUgbnZtZXRfc3Vic3lzX3R5cGU7Cj4+IEBAIC0xNjU2 LDEwICsxNjYxLDcxIEBAIHN0YXRpYyBjb25zdCBzdHJ1Y3QgY29uZmlnX2l0ZW1fdHlwZQo+PiBu dm1ldF9wb3J0c190eXBlID0geyBzdGF0aWMgc3RydWN0IGNvbmZpZ19ncm91cCBudm1ldF9zdWJz eXN0ZW1zX2dyb3VwOwo+PiAgIHN0YXRpYyBzdHJ1Y3QgY29uZmlnX2dyb3VwIG52bWV0X3BvcnRz X2dyb3VwOwo+Pgo+PiAtc3RhdGljIHZvaWQgbnZtZXRfaG9zdF9yZWxlYXNlKHN0cnVjdCBjb25m aWdfaXRlbSAqaXRlbSkKPj4gKyNpZmRlZiBDT05GSUdfTlZNRV9UQVJHRVRfQVVUSAo+PiArc3Rh dGljIHNzaXplX3QgbnZtZXRfaG9zdF9kaGNoYXBfa2V5X3Nob3coc3RydWN0IGNvbmZpZ19pdGVt ICppdGVtLAo+PiArCQljaGFyICpwYWdlKQo+PiArewo+PiArCXU4ICpkaGNoYXBfc2VjcmV0ID0g dG9faG9zdChpdGVtKS0+ZGhjaGFwX3NlY3JldDsKPj4gKwo+PiArCWlmICghZGhjaGFwX3NlY3Jl dCkKPj4gKwkJcmV0dXJuIHNwcmludGYocGFnZSwgIlxuIik7Cj4+ICsJcmV0dXJuIHNwcmludGYo cGFnZSwgIiVzXG4iLCBkaGNoYXBfc2VjcmV0KTsKPj4gK30KPj4gKwo+PiArc3RhdGljIHNzaXpl X3QgbnZtZXRfaG9zdF9kaGNoYXBfa2V5X3N0b3JlKHN0cnVjdCBjb25maWdfaXRlbSAqaXRlbSwK Pj4gKwkJY29uc3QgY2hhciAqcGFnZSwgc2l6ZV90IGNvdW50KQo+PiAgIHsKPj4gICAJc3RydWN0 IG52bWV0X2hvc3QgKmhvc3QgPSB0b19ob3N0KGl0ZW0pOwo+PiArCWludCByZXQ7Cj4+Cj4+ICsJ cmV0ID0gbnZtZXRfYXV0aF9zZXRfaG9zdF9rZXkoaG9zdCwgcGFnZSk7Cj4+ICsJaWYgKHJldCA8 IDApCj4+ICsJCXJldHVybiByZXQ7Cj4+ICsJcmV0dXJuIGNvdW50Owo+PiArfQo+PiArCj4+ICtD T05GSUdGU19BVFRSKG52bWV0X2hvc3RfLCBkaGNoYXBfa2V5KTsKPj4gKwo+PiArc3RhdGljIHNz aXplX3QgbnZtZXRfaG9zdF9kaGNoYXBfaGFzaF9zaG93KHN0cnVjdCBjb25maWdfaXRlbSAqaXRl bSwKPj4gKwkJY2hhciAqcGFnZSkKPj4gK3sKPj4gKwlzdHJ1Y3QgbnZtZXRfaG9zdCAqaG9zdCA9 IHRvX2hvc3QoaXRlbSk7Cj4+ICsJY29uc3QgY2hhciAqaGFzaF9uYW1lID0gbnZtZV9hdXRoX2ht YWNfbmFtZShob3N0LT5kaGNoYXBfaGFzaF9pZCk7Cj4+ICsKPj4gKwlyZXR1cm4gc3ByaW50Zihw YWdlLCAiJXNcbiIsIGhhc2hfbmFtZSA/IGhhc2hfbmFtZSA6ICJub25lIik7Cj4+ICt9Cj4+ICsK Pj4gK3N0YXRpYyBzc2l6ZV90IG52bWV0X2hvc3RfZGhjaGFwX2hhc2hfc3RvcmUoc3RydWN0IGNv bmZpZ19pdGVtICppdGVtLAo+PiArCQljb25zdCBjaGFyICpwYWdlLCBzaXplX3QgY291bnQpCj4+ ICt7Cj4+ICsJc3RydWN0IG52bWV0X2hvc3QgKmhvc3QgPSB0b19ob3N0KGl0ZW0pOwo+PiArCWlu dCBobWFjX2lkOwo+PiArCj4+ICsJaG1hY19pZCA9IG52bWVfYXV0aF9obWFjX2lkKHBhZ2UpOwo+ PiArCWlmIChobWFjX2lkIDwgMCkKPj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4+ICsJaWYgKCFjcnlw dG9faGFzX3NoYXNoKG52bWVfYXV0aF9obWFjX25hbWUoaG1hY19pZCksIDAsIDApKQo+PiArCQly ZXR1cm4gLUVOT1RTVVBQOwo+PiArCWhvc3QtPmRoY2hhcF9oYXNoX2lkID0gaG1hY19pZDsKPj4g KwlyZXR1cm4gY291bnQ7Cj4+ICt9Cj4+ICsKPj4gK0NPTkZJR0ZTX0FUVFIobnZtZXRfaG9zdF8s IGRoY2hhcF9oYXNoKTsKPj4gKwo+PiArc3RhdGljIHN0cnVjdCBjb25maWdmc19hdHRyaWJ1dGUg Km52bWV0X2hvc3RfYXR0cnNbXSA9IHsKPj4gKwkmbnZtZXRfaG9zdF9hdHRyX2RoY2hhcF9rZXks Cj4+ICsJJm52bWV0X2hvc3RfYXR0cl9kaGNoYXBfaGFzaCwKPj4gKwlOVUxMLAo+PiArfTsKPj4g KyNlbmRpZiAvKiBDT05GSUdfTlZNRV9UQVJHRVRfQVVUSCAqLwo+PiArCj4+ICtzdGF0aWMgdm9p ZCBudm1ldF9ob3N0X3JlbGVhc2Uoc3RydWN0IGNvbmZpZ19pdGVtICppdGVtKQo+PiArewo+PiAr CXN0cnVjdCBudm1ldF9ob3N0ICpob3N0ID0gdG9faG9zdChpdGVtKTsKPj4gKyNpZmRlZiBDT05G SUdfTlZNRV9UQVJHRVRfQVVUSAo+PiArCWlmIChob3N0LT5kaGNoYXBfc2VjcmV0KQo+PiArCQlr ZnJlZShob3N0LT5kaGNoYXBfc2VjcmV0KTsKPj4gKyNlbmRpZgo+PiAgIAlrZnJlZShob3N0KTsK Pj4gICB9Cj4+Cj4+IEBAIC0xNjY5LDYgKzE3MzUsOSBAQCBzdGF0aWMgc3RydWN0IGNvbmZpZ2Zz X2l0ZW1fb3BlcmF0aW9ucwo+PiBudm1ldF9ob3N0X2l0ZW1fb3BzID0gewo+Pgo+PiAgIHN0YXRp YyBjb25zdCBzdHJ1Y3QgY29uZmlnX2l0ZW1fdHlwZSBudm1ldF9ob3N0X3R5cGUgPSB7Cj4+ICAg CS5jdF9pdGVtX29wcwkJPSAmbnZtZXRfaG9zdF9pdGVtX29wcywKPj4gKyNpZmRlZiBDT05GSUdf TlZNRV9UQVJHRVRfQVVUSAo+PiArCS5jdF9hdHRycwkJPSBudm1ldF9ob3N0X2F0dHJzLAo+PiAr I2VuZGlmCj4+ICAgCS5jdF9vd25lcgkJPSBUSElTX01PRFVMRSwKPj4gICB9Owo+Pgo+PiBkaWZm IC0tZ2l0IGEvZHJpdmVycy9udm1lL3RhcmdldC9jb3JlLmMgYi9kcml2ZXJzL252bWUvdGFyZ2V0 L2NvcmUuYwo+PiBpbmRleCAxNjNmN2RjMWE5MjkuLmI1ZDc5NzFmNTY2YiAxMDA2NDQKPj4gLS0t IGEvZHJpdmVycy9udm1lL3RhcmdldC9jb3JlLmMKPj4gKysrIGIvZHJpdmVycy9udm1lL3Rhcmdl dC9jb3JlLmMKPj4gQEAgLTc5Myw2ICs3OTMsNyBAQCB2b2lkIG52bWV0X3NxX2Rlc3Ryb3koc3Ry dWN0IG52bWV0X3NxICpzcSkKPj4gICAJd2FpdF9mb3JfY29tcGxldGlvbigmc3EtPmNvbmZpcm1f ZG9uZSk7Cj4+ICAgCXdhaXRfZm9yX2NvbXBsZXRpb24oJnNxLT5mcmVlX2RvbmUpOwo+PiAgIAlw ZXJjcHVfcmVmX2V4aXQoJnNxLT5yZWYpOwo+PiArCW52bWV0X2F1dGhfc3FfZnJlZShzcSk7Cj4+ Cj4+ICAgCWlmIChjdHJsKSB7Cj4+ICAgCQkvKgo+PiBAQCAtMTI2NCw2ICsxMjY1LDExIEBAIHUx NiBudm1ldF9jaGVja19jdHJsX3N0YXR1cyhzdHJ1Y3QgbnZtZXRfcmVxICpyZXEpCj4+ICAgCQkg ICAgICAgcmVxLT5jbWQtPmNvbW1vbi5vcGNvZGUsIHJlcS0+c3EtPnFpZCk7Cj4+ICAgCQlyZXR1 cm4gTlZNRV9TQ19DTURfU0VRX0VSUk9SIHwgTlZNRV9TQ19ETlI7Cj4+ICAgCX0KPj4gKwo+PiAr CWlmICh1bmxpa2VseSghbnZtZXRfY2hlY2tfYXV0aF9zdGF0dXMocmVxKSkpIHsKPj4gKwkJcHJf d2FybigicWlkICVkIG5vdCBhdXRoZW50aWNhdGVkXG4iLCByZXEtPnNxLT5xaWQpOwo+PiArCQly ZXR1cm4gTlZNRV9TQ19BVVRIX1JFUVVJUkVEIHwgTlZNRV9TQ19ETlI7Cj4+ICsJfQo+PiAgIAly ZXR1cm4gMDsKPj4gICB9Cj4+Cj4+IEBAIC0xNDU2LDYgKzE0NjIsOCBAQCBzdGF0aWMgdm9pZCBu dm1ldF9jdHJsX2ZyZWUoc3RydWN0IGtyZWYgKnJlZikKPj4gICAJZmx1c2hfd29yaygmY3RybC0+ YXN5bmNfZXZlbnRfd29yayk7Cj4+ICAgCWNhbmNlbF93b3JrX3N5bmMoJmN0cmwtPmZhdGFsX2Vy cl93b3JrKTsKPj4KPj4gKwludm1ldF9yZXNldF9hdXRoKGN0cmwpOwo+PiArCj4+ICAgCWlkYV9z aW1wbGVfcmVtb3ZlKCZjbnRsaWRfaWRhLCBjdHJsLT5jbnRsaWQpOwo+Pgo+PiAgIAludm1ldF9h c3luY19ldmVudHNfZnJlZShjdHJsKTsKPj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbnZtZS90YXJn ZXQvZmFicmljcy1jbWQtYXV0aC5jCj4+IGIvZHJpdmVycy9udm1lL3RhcmdldC9mYWJyaWNzLWNt ZC1hdXRoLmMgbmV3IGZpbGUgbW9kZSAxMDA2NDQKPj4gaW5kZXggMDAwMDAwMDAwMDAwLi45NjJm OWY1ZTlkODkKPj4gLS0tIC9kZXYvbnVsbAo+PiArKysgYi9kcml2ZXJzL252bWUvdGFyZ2V0L2Zh YnJpY3MtY21kLWF1dGguYwo+PiBAQCAtMCwwICsxLDQ2MCBAQAo+PiArLy8gU1BEWC1MaWNlbnNl LUlkZW50aWZpZXI6IEdQTC0yLjAKPj4gKy8qCj4+ICsgKiBOVk1lIG92ZXIgRmFicmljcyBESC1I TUFDLUNIQVAgYXV0aGVudGljYXRpb24gY29tbWFuZCBoYW5kbGluZy4KPj4gKyAqIENvcHlyaWdo dCAoYykgMjAyMCBIYW5uZXMgUmVpbmVja2UsIFNVU0UgU29mdHdhcmUgU29sdXRpb25zLgo+PiAr ICogQWxsIHJpZ2h0cyByZXNlcnZlZC4KPj4gKyAqLwo+PiArI2RlZmluZSBwcl9mbXQoZm10KSBL QlVJTERfTU9ETkFNRSAiOiAiIGZtdAo+PiArI2luY2x1ZGUgPGxpbnV4L2Jsa2Rldi5oPgo+PiAr I2luY2x1ZGUgPGxpbnV4L3JhbmRvbS5oPgo+PiArI2luY2x1ZGUgPGNyeXB0by9oYXNoLmg+Cj4+ ICsjaW5jbHVkZSA8Y3J5cHRvL2twcC5oPgo+PiArI2luY2x1ZGUgIm52bWV0LmgiCj4+ICsjaW5j bHVkZSAiLi4vaG9zdC9hdXRoLmgiCj4+ICsKPj4gK3ZvaWQgbnZtZXRfaW5pdF9hdXRoKHN0cnVj dCBudm1ldF9jdHJsICpjdHJsLCBzdHJ1Y3QgbnZtZXRfcmVxICpyZXEpCj4+ICt7Cj4+ICsJLyog SW5pdGlhbGl6ZSBpbi1iYW5kIGF1dGhlbnRpY2F0aW9uICovCj4+ICsJcmVxLT5zcS0+YXV0aGVu dGljYXRlZCA9IGZhbHNlOwo+PiArCXJlcS0+c3EtPmRoY2hhcF9zdGVwID0gTlZNRV9BVVRIX0RI Q0hBUF9NRVNTQUdFX05FR09USUFURTsKPj4gKwlyZXEtPmNxZS0+cmVzdWx0LnUzMiB8PSAweDIg PDwgMTY7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyB1MTYgbnZtZXRfYXV0aF9uZWdvdGlhdGUoc3Ry dWN0IG52bWV0X3JlcSAqcmVxLCB2b2lkICpkKQo+PiArewo+PiArCXN0cnVjdCBudm1ldF9jdHJs ICpjdHJsID0gcmVxLT5zcS0+Y3RybDsKPj4gKwlzdHJ1Y3QgbnZtZl9hdXRoX2RoY2hhcF9uZWdv dGlhdGVfZGF0YSAqZGF0YSA9IGQ7Cj4+ICsJaW50IGksIGhhc2hfaWQsIG51bGxfZGggPSAtMTsK Pj4gKwo+PiArCXByX2RlYnVnKCIlczogY3RybCAlZCBxaWQgJWQ6IGRhdGEgc2NfZCAlZCBuYXBk ICVkIGF1dGhpZCAlZCBoYWxlbiAlZAo+PiBkaGxlbiAlZFxuIiwgKwkJIF9fZnVuY19fLCBjdHJs LT5jbnRsaWQsIHJlcS0+c3EtPnFpZCwKPj4gKwkJIGRhdGEtPnNjX2MsIGRhdGEtPm5hcGQsIGRh dGEtPmF1dGhfcHJvdG9jb2xbMF0uZGhjaGFwLmF1dGhpZCwKPj4gKwkJIGRhdGEtPmF1dGhfcHJv dG9jb2xbMF0uZGhjaGFwLmhhbGVuLAo+PiArCQkgZGF0YS0+YXV0aF9wcm90b2NvbFswXS5kaGNo YXAuZGhsZW4pOwo+PiArCXJlcS0+c3EtPmRoY2hhcF90aWQgPSBsZTE2X3RvX2NwdShkYXRhLT50 X2lkKTsKPj4gKwlpZiAoZGF0YS0+c2NfYykKPj4gKwkJcmV0dXJuIE5WTUVfQVVUSF9ESENIQVBf RkFJTFVSRV9DT05DQVRfTUlTTUFUQ0g7Cj4+ICsKPj4gKwlpZiAoZGF0YS0+bmFwZCAhPSAxKQo+ PiArCQlyZXR1cm4gTlZNRV9BVVRIX0RIQ0hBUF9GQUlMVVJFX0hBU0hfVU5VU0FCTEU7Cj4+ICsK Pj4gKwlpZiAoZGF0YS0+YXV0aF9wcm90b2NvbFswXS5kaGNoYXAuYXV0aGlkICE9IDB4MDEpCj4+ ICsJCXJldHVybiBOVk1FX0FVVEhfREhDSEFQX0ZBSUxVUkVfSU5WQUxJRF9QQVlMT0FEOwo+PiAr Cj4+ICsJaGFzaF9pZCA9IG52bWVfYXV0aF9obWFjX2lkKGNyeXB0b19zaGFzaF9hbGdfbmFtZShj dHJsLT5zaGFzaF90Zm0pKTsKPj4gKwlmb3IgKGkgPSAwOyBpIDwgZGF0YS0+YXV0aF9wcm90b2Nv bFswXS5kaGNoYXAuaGFsZW47IGkrKykgewo+PiArCQlwcl9kZWJ1ZygiJXM6IGN0cmwgJWQgcWlk ICVkIGNoZWNraW5nIGhhc2ggJWQgZm9yICVkXG4iLAo+PiArCQkJIF9fZnVuY19fLCBjdHJsLT5j bnRsaWQsIHJlcS0+c3EtPnFpZCwKPj4gKwkJCSBkYXRhLT5hdXRoX3Byb3RvY29sWzBdLmRoY2hh cC5pZGxpc3RbaV0sIGhhc2hfaWQpOwo+PiArCQlpZiAoaGFzaF9pZCAhPSBkYXRhLT5hdXRoX3By b3RvY29sWzBdLmRoY2hhcC5pZGxpc3RbaV0pCj4+ICsJCQljb250aW51ZTsKPj4gKwkJcmVxLT5z cS0+ZGhjaGFwX2hhc2hfaWQgPSBoYXNoX2lkOwo+PiArCQlyZXEtPnNxLT5kaGNoYXBfaGFzaF9s ZW4gPSBjcnlwdG9fc2hhc2hfZGlnZXN0c2l6ZShjdHJsLQo+PiBzaGFzaF90Zm0pOwo+PiArCQli cmVhazsKPj4gKwl9Cj4+ICsJaWYgKHJlcS0+c3EtPmRoY2hhcF9oYXNoX2lkID09IDApIHsKPj4g KwkJcHJfZGVidWcoIiVzOiBjdHJsICVkIHFpZCAlZDogbm8gdXNhYmxlIGhhc2ggZm91bmRcbiIs Cj4+ICsJCQkgX19mdW5jX18sIGN0cmwtPmNudGxpZCwgcmVxLT5zcS0+cWlkKTsKPj4gKwkJcmV0 dXJuIE5WTUVfQVVUSF9ESENIQVBfRkFJTFVSRV9IQVNIX1VOVVNBQkxFOwo+PiArCX0KPj4gKwo+ PiArCWZvciAoaSA9IGRhdGEtPmF1dGhfcHJvdG9jb2xbMF0uZGhjaGFwLmhhbGVuOwo+PiArCSAg ICAgaSA8IGRhdGEtPmF1dGhfcHJvdG9jb2xbMF0uZGhjaGFwLmhhbGVuICsKPj4gKwkJICAgICBk YXRhLT5hdXRoX3Byb3RvY29sWzBdLmRoY2hhcC5kaGxlbjsgaSsrKSB7Cj4+ICsJCWludCBkaGdp ZCA9IGRhdGEtPmF1dGhfcHJvdG9jb2xbMF0uZGhjaGFwLmlkbGlzdFtpXTsKPj4gKwo+PiArCQlp ZiAoZGhnaWQgPT0gTlZNRV9BVVRIX0RIQ0hBUF9ESEdST1VQX05VTEwpIHsKPj4gKwkJCW51bGxf ZGggPSBkaGdpZDsKPj4gKwkJCWNvbnRpbnVlOwo+PiArCQl9Cj4+ICsJCWlmIChudm1ldF9zZXR1 cF9kaGdyb3VwKGN0cmwsIGRoZ2lkKSA9PSAwKQo+PiArCQkJYnJlYWs7Cj4+ICsJfQo+PiArCWlm ICghY3RybC0+ZGhfdGZtICYmIG51bGxfZGggPCAwKSB7Cj4+ICsJCXByX2RlYnVnKCIlczogY3Ry bCAlZCBxaWQgJWQ6IG5vIERIIGdyb3VwIHNlbGVjdGVkXG4iLAo+PiArCQkJIF9fZnVuY19fLCBj dHJsLT5jbnRsaWQsIHJlcS0+c3EtPnFpZCk7Cj4+ICsJCXJldHVybiBOVk1FX0FVVEhfREhDSEFQ X0ZBSUxVUkVfREhHUk9VUF9VTlVTQUJMRTsKPj4gKwl9Cj4+ICsJaWYgKGN0cmwtPmRoX2dpZCA9 PSAtMSkgewo+PiArCQljdHJsLT5kaF9naWQgPSBudWxsX2RoOwo+PiArCQljdHJsLT5kaF90Zm0g PSBOVUxMOwo+PiArCX0KPj4gKwlwcl9kZWJ1ZygiJXM6IGN0cmwgJWQgcWlkICVkOiBESCBncm91 cCAlcyAoJWQpXG4iLAo+PiArCQkgX19mdW5jX18sIGN0cmwtPmNudGxpZCwgcmVxLT5zcS0+cWlk LAo+PiArCQkgbnZtZV9hdXRoX2RoZ3JvdXBfbmFtZShjdHJsLT5kaF9naWQpLCBjdHJsLT5kaF9n aWQpOwo+PiArCXJldHVybiAwOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgdTE2IG52bWV0X2F1dGhf cmVwbHkoc3RydWN0IG52bWV0X3JlcSAqcmVxLCB2b2lkICpkKQo+PiArewo+PiArCXN0cnVjdCBu dm1ldF9jdHJsICpjdHJsID0gcmVxLT5zcS0+Y3RybDsKPj4gKwlzdHJ1Y3QgbnZtZl9hdXRoX2Ro Y2hhcF9yZXBseV9kYXRhICpkYXRhID0gZDsKPj4gKwl1OCAqcmVzcG9uc2U7Cj4+ICsKPj4gKwlw cl9kZWJ1ZygiJXM6IGN0cmwgJWQgcWlkICVkOiBkYXRhIGhsICVkIGN2YWxpZCAlZCBkaHZsZW4g JWRcbiIsCj4+ICsJCSBfX2Z1bmNfXywgY3RybC0+Y250bGlkLCByZXEtPnNxLT5xaWQsCj4+ICsJ CSBkYXRhLT5obCwgZGF0YS0+Y3ZhbGlkLCBkYXRhLT5kaHZsZW4pOwo+PiArCWlmIChkYXRhLT5o bCAhPSByZXEtPnNxLT5kaGNoYXBfaGFzaF9sZW4pCj4+ICsJCXJldHVybiBOVk1FX0FVVEhfREhD SEFQX0ZBSUxVUkVfSU5WQUxJRF9QQVlMT0FEOwo+PiArCj4+ICsJaWYgKGRhdGEtPmRodmxlbikg ewo+PiArCQlyZXR1cm4gTlZNRV9BVVRIX0RIQ0hBUF9GQUlMVVJFX0lOVkFMSURfUEFZTE9BRDsK Pj4gKwl9Cj4+ICsKPj4gKwlyZXNwb25zZSA9IGttYWxsb2MoZGF0YS0+aGwsIEdGUF9LRVJORUwp Owo+IAo+IEFnYWluLCBhbGlnbiB0byBDUllQVE9fTUlOQUxJR05fQVRUUj8KPiAKCkFoLCBfdGhh dF8gYWxpZ25tZW50LgpXYXNuJ3QgYXdhcmUgdGhhdCBJIG5lZWQgdG8gYWxpZ24gdG8gYW55dGhp bmcuCkJ1dCBpZiB0aGF0J3MgcmVxdWlyZWQsIHN1cmUsIEknbGwgYmUgZml4aW5nIGl0LgoKPj4g KwlpZiAoIXJlc3BvbnNlKQo+PiArCQlyZXR1cm4gTlZNRV9BVVRIX0RIQ0hBUF9GQUlMVVJFX0ZB SUxFRDsKPj4gKwo+PiArCWlmIChudm1ldF9hdXRoX2hvc3RfaGFzaChyZXEsIHJlc3BvbnNlLCBk YXRhLT5obCkgPCAwKSB7Cj4+ICsJCXByX2RlYnVnKCJjdHJsICVkIHFpZCAlZCBESC1ITUFDLUNI QVAgaGFzaCBmYWlsZWRcbiIsCj4+ICsJCQkgY3RybC0+Y250bGlkLCByZXEtPnNxLT5xaWQpOwo+ PiArCQlrZnJlZShyZXNwb25zZSk7Cj4+ICsJCXJldHVybiBOVk1FX0FVVEhfREhDSEFQX0ZBSUxV UkVfRkFJTEVEOwo+PiArCX0KPj4gKwo+PiArCWlmIChtZW1jbXAoZGF0YS0+cnZhbCwgcmVzcG9u c2UsIGRhdGEtPmhsKSkgewo+PiArCQlwcl9pbmZvKCJjdHJsICVkIHFpZCAlZCBESC1ITUFDLUNI QVAgcmVzcG9uc2UgbWlzbWF0Y2hcbiIsCj4+ICsJCQljdHJsLT5jbnRsaWQsIHJlcS0+c3EtPnFp ZCk7Cj4+ICsJCWtmcmVlKHJlc3BvbnNlKTsKPj4gKwkJcmV0dXJuIE5WTUVfQVVUSF9ESENIQVBf RkFJTFVSRV9GQUlMRUQ7Cj4+ICsJfQo+PiArCWtmcmVlKHJlc3BvbnNlKTsKPj4gKwlwcl9pbmZv KCJjdHJsICVkIHFpZCAlZCBESC1ITUFDLUNIQVAgaG9zdCBhdXRoZW50aWNhdGVkXG4iLAo+PiAr CQljdHJsLT5jbnRsaWQsIHJlcS0+c3EtPnFpZCk7Cj4+ICsJaWYgKGRhdGEtPmN2YWxpZCkgewo+ PiArCQlyZXEtPnNxLT5kaGNoYXBfYzIgPSBrbWFsbG9jKGRhdGEtPmhsLCBHRlBfS0VSTkVMKTsK Pj4gKwkJaWYgKCFyZXEtPnNxLT5kaGNoYXBfYzIpCj4+ICsJCQlyZXR1cm4gTlZNRV9BVVRIX0RI Q0hBUF9GQUlMVVJFX0ZBSUxFRDsKPj4gKwkJbWVtY3B5KHJlcS0+c3EtPmRoY2hhcF9jMiwgZGF0 YS0+cnZhbCArIGRhdGEtPmhsLCBkYXRhLT5obCk7Cj4+ICsKPj4gKwkJcHJfZGVidWcoImN0cmwg JWQgcWlkICVkIGNoYWxsZW5nZSAlKnBoXG4iLAo+PiArCQkJIGN0cmwtPmNudGxpZCwgcmVxLT5z cS0+cWlkLCBkYXRhLT5obCwKPj4gKwkJCSByZXEtPnNxLT5kaGNoYXBfYzIpOwo+PiArCQlyZXEt PnNxLT5kaGNoYXBfczIgPSBsZTMyX3RvX2NwdShkYXRhLT5zZXFudW0pOwo+PiArCX0gZWxzZQo+ PiArCQlyZXEtPnNxLT5kaGNoYXBfYzIgPSBOVUxMOwo+PiArCj4+ICsJcmV0dXJuIDA7Cj4+ICt9 Cj4+ICsKPj4gK3N0YXRpYyB1MTYgbnZtZXRfYXV0aF9mYWlsdXJlMihzdHJ1Y3QgbnZtZXRfcmVx ICpyZXEsIHZvaWQgKmQpCj4+ICt7Cj4+ICsJc3RydWN0IG52bWZfYXV0aF9kaGNoYXBfZmFpbHVy ZV9kYXRhICpkYXRhID0gZDsKPj4gKwo+PiArCXJldHVybiBkYXRhLT5yZWFzb25fY29kZV9leHBs YW5hdGlvbjsKPj4gK30KPj4gKwo+PiArdm9pZCBudm1ldF9leGVjdXRlX2F1dGhfc2VuZChzdHJ1 Y3QgbnZtZXRfcmVxICpyZXEpCj4+ICt7Cj4+ICsJc3RydWN0IG52bWV0X2N0cmwgKmN0cmwgPSBy ZXEtPnNxLT5jdHJsOwo+PiArCXN0cnVjdCBudm1mX2F1dGhfZGhjaGFwX3N1Y2Nlc3MyX2RhdGEg KmRhdGE7Cj4+ICsJdm9pZCAqZDsKPj4gKwl1MzIgdGw7Cj4+ICsJdTE2IHN0YXR1cyA9IDA7Cj4+ ICsKPj4gKwlpZiAocmVxLT5jbWQtPmF1dGhfc2VuZC5zZWNwICE9IE5WTUVfQVVUSF9ESENIQVBf UFJPVE9DT0xfSURFTlRJRklFUikgewo+PiArCQlzdGF0dXMgPSBOVk1FX1NDX0lOVkFMSURfRklF TEQgfCBOVk1FX1NDX0ROUjsKPj4gKwkJcmVxLT5lcnJvcl9sb2MgPQo+PiArCQkJb2Zmc2V0b2Yo c3RydWN0IG52bWZfYXV0aF9zZW5kX2NvbW1hbmQsIHNlY3ApOwo+PiArCQlnb3RvIGRvbmU7Cj4+ ICsJfQo+PiArCWlmIChyZXEtPmNtZC0+YXV0aF9zZW5kLnNwc3AwICE9IDB4MDEpIHsKPj4gKwkJ c3RhdHVzID0gTlZNRV9TQ19JTlZBTElEX0ZJRUxEIHwgTlZNRV9TQ19ETlI7Cj4+ICsJCXJlcS0+ ZXJyb3JfbG9jID0KPj4gKwkJCW9mZnNldG9mKHN0cnVjdCBudm1mX2F1dGhfc2VuZF9jb21tYW5k LCBzcHNwMCk7Cj4+ICsJCWdvdG8gZG9uZTsKPj4gKwl9Cj4+ICsJaWYgKHJlcS0+Y21kLT5hdXRo X3NlbmQuc3BzcDEgIT0gMHgwMSkgewo+PiArCQlzdGF0dXMgPSBOVk1FX1NDX0lOVkFMSURfRklF TEQgfCBOVk1FX1NDX0ROUjsKPj4gKwkJcmVxLT5lcnJvcl9sb2MgPQo+PiArCQkJb2Zmc2V0b2Yo c3RydWN0IG52bWZfYXV0aF9zZW5kX2NvbW1hbmQsIHNwc3AxKTsKPj4gKwkJZ290byBkb25lOwo+ PiArCX0KPj4gKwl0bCA9IGxlMzJfdG9fY3B1KHJlcS0+Y21kLT5hdXRoX3NlbmQudGwpOwo+PiAr CWlmICghdGwpIHsKPj4gKwkJc3RhdHVzID0gTlZNRV9TQ19JTlZBTElEX0ZJRUxEIHwgTlZNRV9T Q19ETlI7Cj4+ICsJCXJlcS0+ZXJyb3JfbG9jID0KPj4gKwkJCW9mZnNldG9mKHN0cnVjdCBudm1m X2F1dGhfc2VuZF9jb21tYW5kLCB0bCk7Cj4+ICsJCWdvdG8gZG9uZTsKPj4gKwl9Cj4+ICsJaWYg KCFudm1ldF9jaGVja190cmFuc2Zlcl9sZW4ocmVxLCB0bCkpIHsKPj4gKwkJcHJfZGVidWcoIiVz OiB0cmFuc2ZlciBsZW5ndGggbWlzbWF0Y2ggKCV1KVxuIiwgX19mdW5jX18sIHRsKTsKPj4gKwkJ cmV0dXJuOwo+PiArCX0KPj4gKwo+PiArCWQgPSBrbWFsbG9jKHRsLCBHRlBfS0VSTkVMKTsKPj4g KwlpZiAoIWQpIHsKPj4gKwkJc3RhdHVzID0gTlZNRV9TQ19JTlRFUk5BTDsKPj4gKwkJZ290byBk b25lOwo+PiArCX0KPj4gKwo+PiArCXN0YXR1cyA9IG52bWV0X2NvcHlfZnJvbV9zZ2wocmVxLCAw LCBkLCB0bCk7Cj4+ICsJaWYgKHN0YXR1cykgewo+PiArCQlrZnJlZShkKTsKPj4gKwkJZ290byBk b25lOwo+PiArCX0KPj4gKwo+PiArCWRhdGEgPSBkOwo+PiArCXByX2RlYnVnKCIlczogY3RybCAl ZCBxaWQgJWQgdHlwZSAlZCBpZCAlZCBzdGVwICV4XG4iLCBfX2Z1bmNfXywKPj4gKwkJIGN0cmwt PmNudGxpZCwgcmVxLT5zcS0+cWlkLCBkYXRhLT5hdXRoX3R5cGUsIGRhdGEtPmF1dGhfaWQsCj4+ ICsJCSByZXEtPnNxLT5kaGNoYXBfc3RlcCk7Cj4+ICsJaWYgKGRhdGEtPmF1dGhfdHlwZSAhPSBO Vk1FX0FVVEhfQ09NTU9OX01FU1NBR0VTICYmCj4+ICsJICAgIGRhdGEtPmF1dGhfdHlwZSAhPSBO Vk1FX0FVVEhfREhDSEFQX01FU1NBR0VTKSB7Cj4+ICsJCXJlcS0+c3EtPmRoY2hhcF9zdGVwID0g TlZNRV9BVVRIX0RIQ0hBUF9NRVNTQUdFX0ZBSUxVUkUxOwo+PiArCQlyZXEtPnNxLT5kaGNoYXBf c3RhdHVzID0gTlZNRV9BVVRIX0RIQ0hBUF9GQUlMVVJFX0lOVkFMSURfTUVTU0FHRTsKPj4gKwl9 IGVsc2UgaWYgKGRhdGEtPmF1dGhfdHlwZSA9PSBOVk1FX0FVVEhfQ09NTU9OX01FU1NBR0VTKSB7 Cj4+ICsJCWlmIChkYXRhLT5hdXRoX2lkICE9IHJlcS0+c3EtPmRoY2hhcF9zdGVwKSB7Cj4+ICsJ CQlyZXEtPnNxLT5kaGNoYXBfc3RlcCA9IE5WTUVfQVVUSF9ESENIQVBfTUVTU0FHRV9GQUlMVVJF MTsKPj4gKwkJCXJlcS0+c3EtPmRoY2hhcF9zdGF0dXMgPQo+IE5WTUVfQVVUSF9ESENIQVBfRkFJ TFVSRV9JTlZBTElEX01FU1NBR0U7Cj4+ICsJCX0gZWxzZSBpZiAoZGF0YS0+YXV0aF9pZCAhPSBO Vk1FX0FVVEhfREhDSEFQX01FU1NBR0VfTkVHT1RJQVRFKSB7Cj4+ICsJCQlyZXEtPnNxLT5kaGNo YXBfc3RlcCA9IE5WTUVfQVVUSF9ESENIQVBfTUVTU0FHRV9GQUlMVVJFMTsKPj4gKwkJCXJlcS0+ c3EtPmRoY2hhcF9zdGF0dXMgPQo+IE5WTUVfQVVUSF9ESENIQVBfRkFJTFVSRV9JTlZBTElEX01F U1NBR0U7Cj4+ICsJCX0gZWxzZSB7Cj4+ICsJCQkvKiBWYWxpZGF0ZSBuZWdvdGlhdGlvbiBwYXJh bWV0ZXJzICovCj4+ICsJCQlzdGF0dXMgPSBudm1ldF9hdXRoX25lZ290aWF0ZShyZXEsIGQpOwo+ PiArCQkJaWYgKHN0YXR1cyA9PSAwKQo+PiArCQkJCXJlcS0+c3EtPmRoY2hhcF9zdGVwID0KPiBO Vk1FX0FVVEhfREhDSEFQX01FU1NBR0VfQ0hBTExFTkdFOwo+PiArCQkJZWxzZSB7Cj4+ICsJCQkJ cmVxLT5zcS0+ZGhjaGFwX3N0ZXAgPQo+IE5WTUVfQVVUSF9ESENIQVBfTUVTU0FHRV9GQUlMVVJF MTsKPj4gKwkJCQlyZXEtPnNxLT5kaGNoYXBfc3RhdHVzID0gc3RhdHVzOwo+PiArCQkJCXN0YXR1 cyA9IDA7Cj4+ICsJCQl9Cj4+ICsJCX0KPj4gKwl9IGVsc2UgaWYgKGRhdGEtPmF1dGhfdHlwZSA9 PSBOVk1FX0FVVEhfREhDSEFQX01FU1NBR0VTKSB7Cj4+ICsJCWlmIChkYXRhLT5hdXRoX2lkICE9 IHJlcS0+c3EtPmRoY2hhcF9zdGVwKSB7Cj4+ICsJCQlwcl9kZWJ1ZygiJXM6IGN0cmwgJWQgcWlk ICVkIHN0ZXAgbWlzbWF0Y2ggKCVkICE9ICVkKVxuIiwKPj4gKwkJCQkgX19mdW5jX18sIGN0cmwt PmNudGxpZCwgcmVxLT5zcS0+cWlkLAo+PiArCQkJCSBkYXRhLT5hdXRoX2lkLCByZXEtPnNxLT5k aGNoYXBfc3RlcCk7Cj4+ICsJCQlyZXEtPnNxLT5kaGNoYXBfc3RlcCA9IE5WTUVfQVVUSF9ESENI QVBfTUVTU0FHRV9GQUlMVVJFMTsKPj4gKwkJCXJlcS0+c3EtPmRoY2hhcF9zdGF0dXMgPQo+IE5W TUVfQVVUSF9ESENIQVBfRkFJTFVSRV9JTlZBTElEX01FU1NBR0U7Cj4+ICsJCX0gZWxzZSBpZiAo bGUxNl90b19jcHUoZGF0YS0+dF9pZCkgIT0gcmVxLT5zcS0+ZGhjaGFwX3RpZCkgewo+PiArCQkJ cHJfZGVidWcoIiVzOiBjdHJsICVkIHFpZCAlZCBpbnZhbGlkIHRyYW5zYWN0aW9uICVkCj4gKGV4 cGVjdGVkICVkKVxuIiwKPj4gKwkJCQkgX19mdW5jX18sIGN0cmwtPmNudGxpZCwgcmVxLT5zcS0+ cWlkLAo+PiArCQkJCSBsZTE2X3RvX2NwdShkYXRhLT50X2lkKSwKPj4gKwkJCQkgcmVxLT5zcS0+ ZGhjaGFwX3RpZCk7Cj4+ICsJCQlyZXEtPnNxLT5kaGNoYXBfc3RlcCA9IE5WTUVfQVVUSF9ESENI QVBfTUVTU0FHRV9GQUlMVVJFMTsKPj4gKwkJCXJlcS0+c3EtPmRoY2hhcF9zdGF0dXMgPQo+IE5W TUVfQVVUSF9ESENIQVBfRkFJTFVSRV9JTlZBTElEX1BBWUxPQUQ7Cj4+ICsJCX0gZWxzZSB7Cj4+ ICsJCQlzd2l0Y2ggKGRhdGEtPmF1dGhfaWQpIHsKPj4gKwkJCWNhc2UgTlZNRV9BVVRIX0RIQ0hB UF9NRVNTQUdFX1JFUExZOgo+PiArCQkJCXN0YXR1cyA9IG52bWV0X2F1dGhfcmVwbHkocmVxLCBk KTsKPj4gKwkJCQlpZiAoc3RhdHVzID09IDApCj4+ICsJCQkJCXJlcS0+c3EtPmRoY2hhcF9zdGVw ID0KPiBOVk1FX0FVVEhfREhDSEFQX01FU1NBR0VfU1VDQ0VTUzE7Cj4+ICsJCQkJZWxzZSB7Cj4+ ICsJCQkJCXJlcS0+c3EtPmRoY2hhcF9zdGVwID0KPiBOVk1FX0FVVEhfREhDSEFQX01FU1NBR0Vf RkFJTFVSRTE7Cj4+ICsJCQkJCXJlcS0+c3EtPmRoY2hhcF9zdGF0dXMgPSBzdGF0dXM7Cj4+ICsJ CQkJCXN0YXR1cyA9IDA7Cj4+ICsJCQkJfQo+PiArCQkJCWJyZWFrOwo+PiArCQkJY2FzZSBOVk1F X0FVVEhfREhDSEFQX01FU1NBR0VfU1VDQ0VTUzI6Cj4+ICsJCQkJcmVxLT5zcS0+YXV0aGVudGlj YXRlZCA9IHRydWU7Cj4+ICsJCQkJcHJfZGVidWcoIiVzOiBjdHJsICVkIHFpZCAlZCBhdXRoZW50 aWNhdGVkXG4iLAo+PiArCQkJCQkgX19mdW5jX18sIGN0cmwtPmNudGxpZCwgcmVxLT5zcS0+cWlk KTsKPj4gKwkJCQlicmVhazsKPj4gKwkJCWNhc2UgTlZNRV9BVVRIX0RIQ0hBUF9NRVNTQUdFX0ZB SUxVUkUyOgo+PiArCQkJCXN0YXR1cyA9IG52bWV0X2F1dGhfZmFpbHVyZTIocmVxLCBkKTsKPj4g KwkJCQlpZiAoc3RhdHVzKSB7Cj4+ICsJCQkJCXByX3dhcm4oImN0cmwgJWQgcWlkICVkOiBESC1I TUFDLUNIQVAKPiBuZWdvdGlhdGlvbiBmYWlsZWQgKCVkKVxuIiwKPj4gKwkJCQkJCWN0cmwtPmNu dGxpZCwgcmVxLT5zcS0+cWlkLAo+PiArCQkJCQkJc3RhdHVzKTsKPj4gKwkJCQkJcmVxLT5zcS0+ ZGhjaGFwX3N0YXR1cyA9IHN0YXR1czsKPj4gKwkJCQkJc3RhdHVzID0gMDsKPj4gKwkJCQl9Cj4+ ICsJCQkJYnJlYWs7Cj4+ICsJCQlkZWZhdWx0Ogo+PiArCQkJCXJlcS0+c3EtPmRoY2hhcF9zdGF0 dXMgPQo+IE5WTUVfQVVUSF9ESENIQVBfRkFJTFVSRV9JTlZBTElEX01FU1NBR0U7Cj4+ICsJCQkJ cmVxLT5zcS0+ZGhjaGFwX3N0ZXAgPQo+IE5WTUVfQVVUSF9ESENIQVBfTUVTU0FHRV9GQUlMVVJF MjsKPj4gKwkJCQlicmVhazsKPj4gKwkJCX0KPj4gKwkJfQo+PiArCX0gZWxzZSB7Cj4+ICsJCXJl cS0+c3EtPmRoY2hhcF9zdGF0dXMgPSBOVk1FX0FVVEhfREhDSEFQX0ZBSUxVUkVfSU5WQUxJRF9N RVNTQUdFOwo+PiArCQlyZXEtPnNxLT5kaGNoYXBfc3RlcCA9IE5WTUVfQVVUSF9ESENIQVBfTUVT U0FHRV9GQUlMVVJFMjsKPj4gKwl9Cj4+ICsJa2ZyZWUoZCk7Cj4+ICtkb25lOgo+PiArCXByX2Rl YnVnKCIlczogY3RybCAlZCBxaWQgJWQgZGhjaGFwIHN0YXR1cyAleCBzdGVwICV4XG4iLCBfX2Z1 bmNfXywKPj4gKwkJIGN0cmwtPmNudGxpZCwgcmVxLT5zcS0+cWlkLAo+PiArCQkgcmVxLT5zcS0+ ZGhjaGFwX3N0YXR1cywgcmVxLT5zcS0+ZGhjaGFwX3N0ZXApOwo+PiArCWlmIChzdGF0dXMpCj4+ ICsJCXByX2RlYnVnKCIlczogY3RybCAlZCBxaWQgJWQgbnZtZSBzdGF0dXMgJXggZXJyb3IgbG9j ICVkXG4iLAo+PiArCQkJIF9fZnVuY19fLCBjdHJsLT5jbnRsaWQsIHJlcS0+c3EtPnFpZCwKPj4g KwkJCSBzdGF0dXMsIHJlcS0+ZXJyb3JfbG9jKTsKPj4gKwlyZXEtPmNxZS0+cmVzdWx0LnU2NCA9 IDA7Cj4+ICsJbnZtZXRfcmVxX2NvbXBsZXRlKHJlcSwgc3RhdHVzKTsKPj4gKwlpZiAocmVxLT5z cS0+ZGhjaGFwX3N0ZXAgIT0gTlZNRV9BVVRIX0RIQ0hBUF9NRVNTQUdFX1NVQ0NFU1MyICYmCj4+ ICsJICAgIHJlcS0+c3EtPmRoY2hhcF9zdGVwICE9IE5WTUVfQVVUSF9ESENIQVBfTUVTU0FHRV9G QUlMVVJFMikKPj4gKwkJcmV0dXJuOwo+PiArCS8qIEZpbmFsIHN0YXRlcywgY2xlYXIgdXAgdmFy aWFibGVzICovCj4+ICsJa2ZyZWUocmVxLT5zcS0+ZGhjaGFwX2MxKTsKPj4gKwlrZnJlZShyZXEt PnNxLT5kaGNoYXBfYzIpOwo+PiArCWlmIChyZXEtPnNxLT5kaGNoYXBfc3RlcCA9PSBOVk1FX0FV VEhfREhDSEFQX01FU1NBR0VfRkFJTFVSRTIpCj4+ICsJCW52bWV0X2N0cmxfZmF0YWxfZXJyb3Io Y3RybCk7Cj4+ICt9Cj4+ICsKPj4gK3N0YXRpYyBpbnQgbnZtZXRfYXV0aF9jaGFsbGVuZ2Uoc3Ry dWN0IG52bWV0X3JlcSAqcmVxLCB2b2lkICpkLCBpbnQgYWwpCj4+ICt7Cj4+ICsJc3RydWN0IG52 bWZfYXV0aF9kaGNoYXBfY2hhbGxlbmdlX2RhdGEgKmRhdGEgPSBkOwo+PiArCXN0cnVjdCBudm1l dF9jdHJsICpjdHJsID0gcmVxLT5zcS0+Y3RybDsKPj4gKwlpbnQgcmV0ID0gMDsKPj4gKwlpbnQg ZGF0YV9zaXplID0gc2l6ZW9mKCpkKSArIHJlcS0+c3EtPmRoY2hhcF9oYXNoX2xlbjsKPj4gKwo+ PiArCWlmIChhbCA8IGRhdGFfc2l6ZSkgewo+PiArCQlwcl9kZWJ1ZygiJXM6IGJ1ZmZlciB0b28g c21hbGwgKGFsICVkIG5lZWQgJWQpXG4iLCBfX2Z1bmNfXywKPj4gKwkJCSBhbCwgZGF0YV9zaXpl KTsKPj4gKwkJcmV0dXJuIC1FSU5WQUw7Cj4+ICsJfQo+PiArCW1lbXNldChkYXRhLCAwLCBkYXRh X3NpemUpOwo+PiArCXJlcS0+c3EtPmRoY2hhcF9zMSA9IGN0cmwtPmRoY2hhcF9zZXFudW0rKzsK Pj4gKwlkYXRhLT5hdXRoX3R5cGUgPSBOVk1FX0FVVEhfREhDSEFQX01FU1NBR0VTOwo+PiArCWRh dGEtPmF1dGhfaWQgPSBOVk1FX0FVVEhfREhDSEFQX01FU1NBR0VfQ0hBTExFTkdFOwo+PiArCWRh dGEtPnRfaWQgPSBjcHVfdG9fbGUxNihyZXEtPnNxLT5kaGNoYXBfdGlkKTsKPj4gKwlkYXRhLT5o YXNoaWQgPSByZXEtPnNxLT5kaGNoYXBfaGFzaF9pZDsKPj4gKwlkYXRhLT5obCA9IHJlcS0+c3Et PmRoY2hhcF9oYXNoX2xlbjsKPj4gKwlkYXRhLT5zZXFudW0gPSBjcHVfdG9fbGUzMihyZXEtPnNx LT5kaGNoYXBfczEpOwo+PiArCXJlcS0+c3EtPmRoY2hhcF9jMSA9IGttYWxsb2MoZGF0YS0+aGws IEdGUF9LRVJORUwpOwo+PiArCWlmICghcmVxLT5zcS0+ZGhjaGFwX2MxKQo+PiArCQlyZXR1cm4g LUVOT01FTTsKPj4gKwlnZXRfcmFuZG9tX2J5dGVzKHJlcS0+c3EtPmRoY2hhcF9jMSwgZGF0YS0+ aGwpOwo+PiArCW1lbWNweShkYXRhLT5jdmFsLCByZXEtPnNxLT5kaGNoYXBfYzEsIGRhdGEtPmhs KTsKPj4gKwlwcl9kZWJ1ZygiJXM6IGN0cmwgJWQgcWlkICVkIHNlcSAlZCB0cmFuc2FjdGlvbiAl ZCBobCAlZCBkaHZsZW4gJWRcbiIsCj4+ICsJCSBfX2Z1bmNfXywgY3RybC0+Y250bGlkLCByZXEt PnNxLT5xaWQsIHJlcS0+c3EtPmRoY2hhcF9zMSwKPj4gKwkJIHJlcS0+c3EtPmRoY2hhcF90aWQs IGRhdGEtPmhsLCBkYXRhLT5kaHZsZW4pOwo+PiArCXJldHVybiByZXQ7Cj4+ICt9Cj4+ICsKPj4g K3N0YXRpYyBpbnQgbnZtZXRfYXV0aF9zdWNjZXNzMShzdHJ1Y3QgbnZtZXRfcmVxICpyZXEsIHZv aWQgKmQsIGludCBhbCkKPj4gK3sKPj4gKwlzdHJ1Y3QgbnZtZl9hdXRoX2RoY2hhcF9zdWNjZXNz MV9kYXRhICpkYXRhID0gZDsKPj4gKwlzdHJ1Y3QgbnZtZXRfY3RybCAqY3RybCA9IHJlcS0+c3Et PmN0cmw7Cj4+ICsKPj4gKwlXQVJOX09OKGFsIDwgc2l6ZW9mKCpkYXRhKSk7Cj4+ICsJbWVtc2V0 KGRhdGEsIDAsIHNpemVvZigqZGF0YSkpOwo+PiArCWRhdGEtPmF1dGhfdHlwZSA9IE5WTUVfQVVU SF9ESENIQVBfTUVTU0FHRVM7Cj4+ICsJZGF0YS0+YXV0aF9pZCA9IE5WTUVfQVVUSF9ESENIQVBf TUVTU0FHRV9TVUNDRVNTMTsKPj4gKwlkYXRhLT50X2lkID0gY3B1X3RvX2xlMTYocmVxLT5zcS0+ ZGhjaGFwX3RpZCk7Cj4+ICsJZGF0YS0+aGwgPSByZXEtPnNxLT5kaGNoYXBfaGFzaF9sZW47Cj4+ ICsJaWYgKHJlcS0+c3EtPmRoY2hhcF9jMikgewo+PiArCQlpZiAobnZtZXRfYXV0aF9jdHJsX2hh c2gocmVxLCBkYXRhLT5ydmFsLCBkYXRhLT5obCkpCj4+ICsJCQlyZXR1cm4gTlZNRV9BVVRIX0RI Q0hBUF9GQUlMVVJFX0hBU0hfVU5VU0FCTEU7Cj4+ICsJCWRhdGEtPnJ2YWxpZCA9IDE7Cj4+ICsJ CXByX2RlYnVnKCJjdHJsICVkIHFpZCAlZCByZXNwb25zZSAlKnBoXG4iLAo+PiArCQkJIGN0cmwt PmNudGxpZCwgcmVxLT5zcS0+cWlkLCBkYXRhLT5obCwgZGF0YS0+cnZhbCk7Cj4+ICsJfQo+PiAr CXJldHVybiAwOwo+PiArfQo+PiArCj4+ICtzdGF0aWMgdm9pZCBudm1ldF9hdXRoX2ZhaWx1cmUx KHN0cnVjdCBudm1ldF9yZXEgKnJlcSwgdm9pZCAqZCwgaW50IGFsKQo+PiArewo+PiArCXN0cnVj dCBudm1mX2F1dGhfZGhjaGFwX2ZhaWx1cmVfZGF0YSAqZGF0YSA9IGQ7Cj4+ICsKPj4gKwlXQVJO X09OKGFsIDwgc2l6ZW9mKCpkYXRhKSk7Cj4+ICsJZGF0YS0+YXV0aF90eXBlID0gTlZNRV9BVVRI X0NPTU1PTl9NRVNTQUdFUzsKPj4gKwlkYXRhLT5hdXRoX2lkID0gTlZNRV9BVVRIX0RIQ0hBUF9N RVNTQUdFX0ZBSUxVUkUxOwo+PiArCWRhdGEtPnRfaWQgPSBjcHVfdG9fbGUzMihyZXEtPnNxLT5k aGNoYXBfdGlkKTsKPj4gKwlkYXRhLT5yZWFzb25fY29kZSA9IE5WTUVfQVVUSF9ESENIQVBfRkFJ TFVSRV9SRUFTT05fRkFJTEVEOwo+PiArCWRhdGEtPnJlYXNvbl9jb2RlX2V4cGxhbmF0aW9uID0g cmVxLT5zcS0+ZGhjaGFwX3N0YXR1czsKPj4gK30KPj4gKwo+PiArdm9pZCBudm1ldF9leGVjdXRl X2F1dGhfcmVjZWl2ZShzdHJ1Y3QgbnZtZXRfcmVxICpyZXEpCj4+ICt7Cj4+ICsJc3RydWN0IG52 bWV0X2N0cmwgKmN0cmwgPSByZXEtPnNxLT5jdHJsOwo+PiArCXZvaWQgKmQ7Cj4+ICsJdTMyIGFs Owo+PiArCXUxNiBzdGF0dXMgPSAwOwo+PiArCj4+ICsJaWYgKHJlcS0+Y21kLT5hdXRoX3JlY2Vp dmUuc2VjcCAhPSBOVk1FX0FVVEhfREhDSEFQX1BST1RPQ09MX0lERU5USUZJRVIpCj4gewo+PiAr CQlzdGF0dXMgPSBOVk1FX1NDX0lOVkFMSURfRklFTEQgfCBOVk1FX1NDX0ROUjsKPj4gKwkJcmVx LT5lcnJvcl9sb2MgPQo+PiArCQkJb2Zmc2V0b2Yoc3RydWN0IG52bWZfYXV0aF9yZWNlaXZlX2Nv bW1hbmQsIHNlY3ApOwo+PiArCQlnb3RvIGRvbmU7Cj4+ICsJfQo+PiArCWlmIChyZXEtPmNtZC0+ YXV0aF9yZWNlaXZlLnNwc3AwICE9IDB4MDEpIHsKPj4gKwkJc3RhdHVzID0gTlZNRV9TQ19JTlZB TElEX0ZJRUxEIHwgTlZNRV9TQ19ETlI7Cj4+ICsJCXJlcS0+ZXJyb3JfbG9jID0KPj4gKwkJCW9m ZnNldG9mKHN0cnVjdCBudm1mX2F1dGhfcmVjZWl2ZV9jb21tYW5kLCBzcHNwMCk7Cj4+ICsJCWdv dG8gZG9uZTsKPj4gKwl9Cj4+ICsJaWYgKHJlcS0+Y21kLT5hdXRoX3JlY2VpdmUuc3BzcDEgIT0g MHgwMSkgewo+PiArCQlzdGF0dXMgPSBOVk1FX1NDX0lOVkFMSURfRklFTEQgfCBOVk1FX1NDX0RO UjsKPj4gKwkJcmVxLT5lcnJvcl9sb2MgPQo+PiArCQkJb2Zmc2V0b2Yoc3RydWN0IG52bWZfYXV0 aF9yZWNlaXZlX2NvbW1hbmQsIHNwc3AxKTsKPj4gKwkJZ290byBkb25lOwo+PiArCX0KPj4gKwlh bCA9IGxlMzJfdG9fY3B1KHJlcS0+Y21kLT5hdXRoX3JlY2VpdmUuYWwpOwo+PiArCWlmICghYWwp IHsKPj4gKwkJc3RhdHVzID0gTlZNRV9TQ19JTlZBTElEX0ZJRUxEIHwgTlZNRV9TQ19ETlI7Cj4+ ICsJCXJlcS0+ZXJyb3JfbG9jID0KPj4gKwkJCW9mZnNldG9mKHN0cnVjdCBudm1mX2F1dGhfcmVj ZWl2ZV9jb21tYW5kLCBhbCk7Cj4+ICsJCWdvdG8gZG9uZTsKPj4gKwl9Cj4+ICsJaWYgKCFudm1l dF9jaGVja190cmFuc2Zlcl9sZW4ocmVxLCBhbCkpIHsKPj4gKwkJcHJfZGVidWcoIiVzOiB0cmFu c2ZlciBsZW5ndGggbWlzbWF0Y2ggKCV1KVxuIiwgX19mdW5jX18sIGFsKTsKPj4gKwkJcmV0dXJu Owo+PiArCX0KPj4gKwo+PiArCWQgPSBrbWFsbG9jKGFsLCBHRlBfS0VSTkVMKTsKPj4gKwlpZiAo IWQpIHsKPj4gKwkJc3RhdHVzID0gTlZNRV9TQ19JTlRFUk5BTDsKPj4gKwkJZ290byBkb25lOwo+ PiArCX0KPj4gKwlwcl9kZWJ1ZygiJXM6IGN0cmwgJWQgcWlkICVkIHN0ZXAgJXhcbiIsIF9fZnVu Y19fLAo+PiArCQkgY3RybC0+Y250bGlkLCByZXEtPnNxLT5xaWQsIHJlcS0+c3EtPmRoY2hhcF9z dGVwKTsKPj4gKwlzd2l0Y2ggKHJlcS0+c3EtPmRoY2hhcF9zdGVwKSB7Cj4+ICsJY2FzZSBOVk1F X0FVVEhfREhDSEFQX01FU1NBR0VfQ0hBTExFTkdFOgo+PiArCQlzdGF0dXMgPSBudm1ldF9hdXRo X2NoYWxsZW5nZShyZXEsIGQsIGFsKTsKPj4gKwkJaWYgKHN0YXR1cyA8IDApIHsKPj4gKwkJCXBy X3dhcm4oImN0cmwgJWQgcWlkICVkOiBjaGFsbGVuZ2UgZXJyb3IgKCVkKVxuIiwKPj4gKwkJCQlj dHJsLT5jbnRsaWQsIHJlcS0+c3EtPnFpZCwgc3RhdHVzKTsKPj4gKwkJCXN0YXR1cyA9IE5WTUVf U0NfSU5URVJOQUw7Cj4+ICsJCQlicmVhazsKPj4gKwkJfQo+PiArCQlpZiAoc3RhdHVzKSB7Cj4+ ICsJCQlyZXEtPnNxLT5kaGNoYXBfc3RhdHVzID0gc3RhdHVzOwo+PiArCQkJbnZtZXRfYXV0aF9m YWlsdXJlMShyZXEsIGQsIGFsKTsKPj4gKwkJCXByX3dhcm4oImN0cmwgJWQgcWlkICVkOiBjaGFs bGVuZ2Ugc3RhdHVzICgleClcbiIsCj4+ICsJCQkJY3RybC0+Y250bGlkLCByZXEtPnNxLT5xaWQs Cj4+ICsJCQkJcmVxLT5zcS0+ZGhjaGFwX3N0YXR1cyk7Cj4+ICsJCQlzdGF0dXMgPSAwOwo+PiAr CQkJYnJlYWs7Cj4+ICsJCX0KPj4gKwkJcmVxLT5zcS0+ZGhjaGFwX3N0ZXAgPSBOVk1FX0FVVEhf REhDSEFQX01FU1NBR0VfUkVQTFk7Cj4+ICsJCWJyZWFrOwo+PiArCWNhc2UgTlZNRV9BVVRIX0RI Q0hBUF9NRVNTQUdFX1NVQ0NFU1MxOgo+PiArCQlzdGF0dXMgPSBudm1ldF9hdXRoX3N1Y2Nlc3Mx KHJlcSwgZCwgYWwpOwo+PiArCQlpZiAoc3RhdHVzKSB7Cj4+ICsJCQlyZXEtPnNxLT5kaGNoYXBf c3RhdHVzID0gc3RhdHVzOwo+PiArCQkJbnZtZXRfYXV0aF9mYWlsdXJlMShyZXEsIGQsIGFsKTsK Pj4gKwkJCXByX3dhcm4oImN0cmwgJWQgcWlkICVkOiBzdWNjZXNzMSBzdGF0dXMgKCV4KVxuIiwK Pj4gKwkJCQljdHJsLT5jbnRsaWQsIHJlcS0+c3EtPnFpZCwKPj4gKwkJCQlyZXEtPnNxLT5kaGNo YXBfc3RhdHVzKTsKPj4gKwkJCWJyZWFrOwo+PiArCQl9Cj4+ICsJCXJlcS0+c3EtPmRoY2hhcF9z dGVwID0gTlZNRV9BVVRIX0RIQ0hBUF9NRVNTQUdFX1NVQ0NFU1MyOwo+PiArCQlicmVhazsKPj4g KwljYXNlIE5WTUVfQVVUSF9ESENIQVBfTUVTU0FHRV9GQUlMVVJFMToKPj4gKwkJbnZtZXRfYXV0 aF9mYWlsdXJlMShyZXEsIGQsIGFsKTsKPj4gKwkJcHJfd2FybigiY3RybCAlZCBxaWQgJWQgZmFp bHVyZTEgKCV4KVxuIiwKPj4gKwkJCWN0cmwtPmNudGxpZCwgcmVxLT5zcS0+cWlkLCByZXEtPnNx LT5kaGNoYXBfc3RhdHVzKTsKPj4gKwkJYnJlYWs7Cj4+ICsJZGVmYXVsdDoKPj4gKwkJcHJfd2Fy bigiY3RybCAlZCBxaWQgJWQgdW5oYW5kbGVkIHN0ZXAgKCVkKVxuIiwKPj4gKwkJCWN0cmwtPmNu dGxpZCwgcmVxLT5zcS0+cWlkLCByZXEtPnNxLT5kaGNoYXBfc3RlcCk7Cj4+ICsJCXJlcS0+c3Et PmRoY2hhcF9zdGVwID0gTlZNRV9BVVRIX0RIQ0hBUF9NRVNTQUdFX0ZBSUxVUkUxOwo+PiArCQly ZXEtPnNxLT5kaGNoYXBfc3RhdHVzID0gTlZNRV9BVVRIX0RIQ0hBUF9GQUlMVVJFX0ZBSUxFRDsK Pj4gKwkJbnZtZXRfYXV0aF9mYWlsdXJlMShyZXEsIGQsIGFsKTsKPj4gKwkJc3RhdHVzID0gMDsK Pj4gKwkJYnJlYWs7Cj4+ICsJfQo+PiArCj4+ICsJc3RhdHVzID0gbnZtZXRfY29weV90b19zZ2wo cmVxLCAwLCBkLCBhbCk7Cj4+ICsJa2ZyZWUoZCk7Cj4+ICtkb25lOgo+PiArCXJlcS0+Y3FlLT5y ZXN1bHQudTY0ID0gMDsKPj4gKwludm1ldF9yZXFfY29tcGxldGUocmVxLCBzdGF0dXMpOwo+PiAr CWlmIChyZXEtPnNxLT5kaGNoYXBfc3RlcCA9PSBOVk1FX0FVVEhfREhDSEFQX01FU1NBR0VfRkFJ TFVSRTEpIHsKPj4gKwkJa2ZyZWUocmVxLT5zcS0+ZGhjaGFwX2MxKTsKPj4gKwkJa2ZyZWUocmVx LT5zcS0+ZGhjaGFwX2MyKTsKPj4gKwkJbnZtZXRfY3RybF9mYXRhbF9lcnJvcihjdHJsKTsKPj4g Kwl9Cj4+ICt9Cj4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL252bWUvdGFyZ2V0L2ZhYnJpY3MtY21k LmMKPj4gYi9kcml2ZXJzL252bWUvdGFyZ2V0L2ZhYnJpY3MtY21kLmMgaW5kZXggN2QwZjM1MjNm ZGFiLi41M2ZiODUzY2Q4ZmUgMTAwNjQ0Cj4+IC0tLSBhL2RyaXZlcnMvbnZtZS90YXJnZXQvZmFi cmljcy1jbWQuYwo+PiArKysgYi9kcml2ZXJzL252bWUvdGFyZ2V0L2ZhYnJpY3MtY21kLmMKPj4g QEAgLTkzLDYgKzkzLDE0IEBAIHUxNiBudm1ldF9wYXJzZV9mYWJyaWNzX2NtZChzdHJ1Y3QgbnZt ZXRfcmVxICpyZXEpCj4+ICAgCWNhc2UgbnZtZV9mYWJyaWNzX3R5cGVfcHJvcGVydHlfZ2V0Ogo+ PiAgIAkJcmVxLT5leGVjdXRlID0gbnZtZXRfZXhlY3V0ZV9wcm9wX2dldDsKPj4gICAJCWJyZWFr Owo+PiArI2lmZGVmIENPTkZJR19OVk1FX1RBUkdFVF9BVVRICj4+ICsJY2FzZSBudm1lX2ZhYnJp Y3NfdHlwZV9hdXRoX3NlbmQ6Cj4+ICsJCXJlcS0+ZXhlY3V0ZSA9IG52bWV0X2V4ZWN1dGVfYXV0 aF9zZW5kOwo+PiArCQlicmVhazsKPj4gKwljYXNlIG52bWVfZmFicmljc190eXBlX2F1dGhfcmVj ZWl2ZToKPj4gKwkJcmVxLT5leGVjdXRlID0gbnZtZXRfZXhlY3V0ZV9hdXRoX3JlY2VpdmU7Cj4+ ICsJCWJyZWFrOwo+PiArI2VuZGlmCj4+ICAgCWRlZmF1bHQ6Cj4+ICAgCQlwcl9kZWJ1ZygicmVj ZWl2ZWQgdW5rbm93biBjYXBzdWxlIHR5cGUgMHgleFxuIiwKPj4gICAJCQljbWQtPmZhYnJpY3Mu ZmN0eXBlKTsKPj4gQEAgLTE1NSw2ICsxNjMsNyBAQCBzdGF0aWMgdm9pZCBudm1ldF9leGVjdXRl X2FkbWluX2Nvbm5lY3Qoc3RydWN0IG52bWV0X3JlcQo+PiAqcmVxKSBzdHJ1Y3QgbnZtZl9jb25u ZWN0X2RhdGEgKmQ7Cj4+ICAgCXN0cnVjdCBudm1ldF9jdHJsICpjdHJsID0gTlVMTDsKPj4gICAJ dTE2IHN0YXR1cyA9IDA7Cj4+ICsJaW50IHJldDsKPj4KPj4gICAJaWYgKCFudm1ldF9jaGVja190 cmFuc2Zlcl9sZW4ocmVxLCBzaXplb2Yoc3RydWN0IG52bWZfY29ubmVjdF9kYXRhKSkpCj4+ICAg CQlyZXR1cm47Cj4+IEBAIC0xOTcsMTcgKzIwNiwzMSBAQCBzdGF0aWMgdm9pZCBudm1ldF9leGVj dXRlX2FkbWluX2Nvbm5lY3Qoc3RydWN0Cj4+IG52bWV0X3JlcSAqcmVxKQo+Pgo+PiAgIAl1dWlk X2NvcHkoJmN0cmwtPmhvc3RpZCwgJmQtPmhvc3RpZCk7Cj4+Cj4+ICsJcmV0ID0gbnZtZXRfc2V0 dXBfYXV0aChjdHJsLCByZXEpOwo+PiArCWlmIChyZXQgPCAwKSB7Cj4+ICsJCXByX2VycigiRmFp bGVkIHRvIHNldHVwIGF1dGhlbnRpY2F0aW9uLCBlcnJvciAlZFxuIiwgcmV0KTsKPj4gKwkJbnZt ZXRfY3RybF9wdXQoY3RybCk7Cj4+ICsJCWlmIChyZXQgPT0gLUVQRVJNKQo+PiArCQkJc3RhdHVz ID0gKE5WTUVfU0NfQ09OTkVDVF9JTlZBTElEX0hPU1QgfCBOVk1FX1NDX0ROUik7Cj4+ICsJCWVs c2UKPj4gKwkJCXN0YXR1cyA9IE5WTUVfU0NfSU5URVJOQUw7Cj4+ICsJCWdvdG8gb3V0Owo+PiAr CX0KPj4gKwo+PiAgIAlzdGF0dXMgPSBudm1ldF9pbnN0YWxsX3F1ZXVlKGN0cmwsIHJlcSk7Cj4+ ICAgCWlmIChzdGF0dXMpIHsKPj4gICAJCW52bWV0X2N0cmxfcHV0KGN0cmwpOwo+PiAgIAkJZ290 byBvdXQ7Cj4+ICAgCX0KPj4KPj4gLQlwcl9pbmZvKCJjcmVhdGluZyBjb250cm9sbGVyICVkIGZv ciBzdWJzeXN0ZW0gJXMgZm9yIE5RTiAlcyVzLlxuIiwKPj4gKwlwcl9pbmZvKCJjcmVhdGluZyBj b250cm9sbGVyICVkIGZvciBzdWJzeXN0ZW0gJXMgZm9yIE5RTiAlcyVzJXMuXG4iLAo+PiAgIAkJ Y3RybC0+Y250bGlkLCBjdHJsLT5zdWJzeXMtPnN1YnN5c25xbiwgY3RybC0+aG9zdG5xbiwKPj4g LQkJY3RybC0+cGlfc3VwcG9ydCA/ICIgVDEwLVBJIGlzIGVuYWJsZWQiIDogIiIpOwo+PiArCQlj dHJsLT5waV9zdXBwb3J0ID8gIiBUMTAtUEkgaXMgZW5hYmxlZCIgOiAiIiwKPj4gKwkJbnZtZXRf aGFzX2F1dGgoY3RybCkgPyAiIHdpdGggREgtSE1BQy1DSEFQIiA6ICIiKTsKPj4gICAJcmVxLT5j cWUtPnJlc3VsdC51MTYgPSBjcHVfdG9fbGUxNihjdHJsLT5jbnRsaWQpOwo+Pgo+PiArCWlmIChu dm1ldF9oYXNfYXV0aChjdHJsKSkKPj4gKwkJbnZtZXRfaW5pdF9hdXRoKGN0cmwsIHJlcSk7Cj4+ ICAgb3V0Ogo+PiAgIAlrZnJlZShkKTsKPj4gICBjb21wbGV0ZToKPj4gQEAgLTI2Nyw2ICsyOTAs OSBAQCBzdGF0aWMgdm9pZCBudm1ldF9leGVjdXRlX2lvX2Nvbm5lY3Qoc3RydWN0IG52bWV0X3Jl cQo+PiAqcmVxKSB9Cj4+Cj4+ICAgCXByX2RlYnVnKCJhZGRpbmcgcXVldWUgJWQgdG8gY3RybCAl ZC5cbiIsIHFpZCwgY3RybC0+Y250bGlkKTsKPj4gKwlyZXEtPmNxZS0+cmVzdWx0LnUxNiA9IGNw dV90b19sZTE2KGN0cmwtPmNudGxpZCk7Cj4+ICsJaWYgKG52bWV0X2hhc19hdXRoKGN0cmwpKQo+ PiArCQludm1ldF9pbml0X2F1dGgoY3RybCwgcmVxKTsKPj4KPj4gICBvdXQ6Cj4+ICAgCWtmcmVl KGQpOwo+PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9udm1lL3RhcmdldC9udm1ldC5oIGIvZHJpdmVy cy9udm1lL3RhcmdldC9udm1ldC5oCj4+IGluZGV4IDA2ZGQzZDUzN2YwNy4uZWY4ODE1ZTEzN2Q3 IDEwMDY0NAo+PiAtLS0gYS9kcml2ZXJzL252bWUvdGFyZ2V0L252bWV0LmgKPj4gKysrIGIvZHJp dmVycy9udm1lL3RhcmdldC9udm1ldC5oCj4+IEBAIC0xMDgsNiArMTA4LDIwIEBAIHN0cnVjdCBu dm1ldF9zcSB7Cj4+ICAgCXUxNgkJCXNpemU7Cj4+ICAgCXUzMgkJCXNxaGQ7Cj4+ICAgCWJvb2wJ CQlzcWhkX2Rpc2FibGVkOwo+PiArI2lmZGVmIENPTkZJR19OVk1FX1RBUkdFVF9BVVRICj4+ICsJ Ym9vbAkJCWF1dGhlbnRpY2F0ZWQ7Cj4+ICsJdTE2CQkJZGhjaGFwX3RpZDsKPj4gKwl1MTYJCQlk aGNoYXBfc3RhdHVzOwo+PiArCWludAkJCWRoY2hhcF9zdGVwOwo+PiArCXU4CQkJZGhjaGFwX2hh c2hfaWQ7Cj4+ICsJdTgJCQlkaGNoYXBfaGFzaF9sZW47Cj4+ICsJdTgJCQkqZGhjaGFwX2MxOwo+ PiArCXU4CQkJKmRoY2hhcF9jMjsKPj4gKwl1MzIJCQlkaGNoYXBfczE7Cj4+ICsJdTMyCQkJZGhj aGFwX3MyOwo+PiArCXU4CQkJKmRoY2hhcF9za2V5Owo+PiArCWludAkJCWRoY2hhcF9za2V5X2xl bjsKPj4gKyNlbmRpZgo+PiAgIAlzdHJ1Y3QgY29tcGxldGlvbglmcmVlX2RvbmU7Cj4+ICAgCXN0 cnVjdCBjb21wbGV0aW9uCWNvbmZpcm1fZG9uZTsKPj4gICB9Owo+PiBAQCAtMjA5LDYgKzIyMywx NSBAQCBzdHJ1Y3QgbnZtZXRfY3RybCB7Cj4+ICAgCXU2NAkJCWVycl9jb3VudGVyOwo+PiAgIAlz dHJ1Y3QgbnZtZV9lcnJvcl9zbG90CXNsb3RzW05WTUVUX0VSUk9SX0xPR19TTE9UU107Cj4+ICAg CWJvb2wJCQlwaV9zdXBwb3J0Owo+PiArI2lmZGVmIENPTkZJR19OVk1FX1RBUkdFVF9BVVRICj4+ ICsJdTMyCQkJZGhjaGFwX3NlcW51bTsKPj4gKwl1OAkJCSpkaGNoYXBfa2V5Owo+PiArCXNpemVf dAkJCWRoY2hhcF9rZXlfbGVuOwo+PiArCXN0cnVjdCBjcnlwdG9fc2hhc2gJKnNoYXNoX3RmbTsK Pj4gKwlzdHJ1Y3QgY3J5cHRvX2twcAkqZGhfdGZtOwo+PiArCXUzMgkJCWRoX2dpZDsKPj4gKwl1 MzIJCQlkaF9rZXlzaXplOwo+PiArI2VuZGlmCj4+ICAgfTsKPj4KPj4gICBzdHJ1Y3QgbnZtZXRf c3Vic3lzIHsKPj4gQEAgLTI3MCw2ICsyOTMsMTAgQEAgc3RhdGljIGlubGluZSBzdHJ1Y3QgbnZt ZXRfc3Vic3lzCj4+ICpuYW1lc3BhY2VzX3RvX3N1YnN5cygKPj4KPj4gICBzdHJ1Y3QgbnZtZXRf aG9zdCB7Cj4+ICAgCXN0cnVjdCBjb25maWdfZ3JvdXAJZ3JvdXA7Cj4+ICsJdTgJCQkqZGhjaGFw X3NlY3JldDsKPj4gKwl1OAkJCWRoY2hhcF9rZXlfaGFzaDsKPj4gKwl1OAkJCWRoY2hhcF9oYXNo X2lkOwo+PiArCXU4CQkJZGhjaGFwX2RoZ3JvdXBfaWQ7Cj4+ICAgfTsKPj4KPj4gICBzdGF0aWMg aW5saW5lIHN0cnVjdCBudm1ldF9ob3N0ICp0b19ob3N0KHN0cnVjdCBjb25maWdfaXRlbSAqaXRl bSkKPj4gQEAgLTY1OSw0ICs2ODYsNDggQEAgc3RhdGljIGlubGluZSB2b2lkIG52bWV0X3JlcV9i aW9fcHV0KHN0cnVjdCBudm1ldF9yZXEKPj4gKnJlcSwgc3RydWN0IGJpbyAqYmlvKSBiaW9fcHV0 KGJpbyk7Cj4+ICAgfQo+Pgo+PiArI2lmZGVmIENPTkZJR19OVk1FX1RBUkdFVF9BVVRICj4+ICt2 b2lkIG52bWV0X2V4ZWN1dGVfYXV0aF9zZW5kKHN0cnVjdCBudm1ldF9yZXEgKnJlcSk7Cj4+ICt2 b2lkIG52bWV0X2V4ZWN1dGVfYXV0aF9yZWNlaXZlKHN0cnVjdCBudm1ldF9yZXEgKnJlcSk7Cj4+ ICtpbnQgbnZtZXRfYXV0aF9zZXRfaG9zdF9rZXkoc3RydWN0IG52bWV0X2hvc3QgKmhvc3QsIGNv bnN0IGNoYXIgKnNlY3JldCk7Cj4+ICtpbnQgbnZtZXRfYXV0aF9zZXRfaG9zdF9oYXNoKHN0cnVj dCBudm1ldF9ob3N0ICpob3N0LCBjb25zdCBjaGFyICpoYXNoKTsKPj4gK2ludCBudm1ldF9zZXR1 cF9hdXRoKHN0cnVjdCBudm1ldF9jdHJsICpjdHJsLCBzdHJ1Y3QgbnZtZXRfcmVxICpyZXEpOwo+ PiArdm9pZCBudm1ldF9pbml0X2F1dGgoc3RydWN0IG52bWV0X2N0cmwgKmN0cmwsIHN0cnVjdCBu dm1ldF9yZXEgKnJlcSk7Cj4+ICt2b2lkIG52bWV0X3Jlc2V0X2F1dGgoc3RydWN0IG52bWV0X2N0 cmwgKmN0cmwpOwo+PiArdm9pZCBudm1ldF9hdXRoX3NxX2ZyZWUoc3RydWN0IG52bWV0X3NxICpz cSk7Cj4+ICtpbnQgbnZtZXRfc2V0dXBfZGhncm91cChzdHJ1Y3QgbnZtZXRfY3RybCAqY3RybCwg aW50IGRoZ3JvdXBfaWQpOwo+PiArYm9vbCBudm1ldF9jaGVja19hdXRoX3N0YXR1cyhzdHJ1Y3Qg bnZtZXRfcmVxICpyZXEpOwo+PiAraW50IG52bWV0X2F1dGhfaG9zdF9oYXNoKHN0cnVjdCBudm1l dF9yZXEgKnJlcSwgdTggKnJlc3BvbnNlLAo+PiArCQkJIHVuc2lnbmVkIGludCBoYXNoX2xlbik7 Cj4+ICtpbnQgbnZtZXRfYXV0aF9jdHJsX2hhc2goc3RydWN0IG52bWV0X3JlcSAqcmVxLCB1OCAq cmVzcG9uc2UsCj4+ICsJCQkgdW5zaWduZWQgaW50IGhhc2hfbGVuKTsKPj4gK3N0YXRpYyBpbmxp bmUgYm9vbCBudm1ldF9oYXNfYXV0aChzdHJ1Y3QgbnZtZXRfY3RybCAqY3RybCkKPj4gK3sKPj4g KwlyZXR1cm4gY3RybC0+c2hhc2hfdGZtICE9IE5VTEw7Cj4+ICt9Cj4+ICtpbnQgbnZtZXRfYXV0 aF9jdHJsX2V4cG9uZW50aWFsKHN0cnVjdCBudm1ldF9yZXEgKnJlcSwKPj4gKwkJCQl1OCAqYnVm LCBpbnQgYnVmX3NpemUpOwo+PiAraW50IG52bWV0X2F1dGhfY3RybF9zZXNza2V5KHN0cnVjdCBu dm1ldF9yZXEgKnJlcSwKPj4gKwkJCSAgICB1OCAqYnVmLCBpbnQgYnVmX3NpemUpOwo+PiArI2Vs c2UKPj4gK3N0YXRpYyBpbmxpbmUgaW50IG52bWV0X3NldHVwX2F1dGgoc3RydWN0IG52bWV0X2N0 cmwgKmN0cmwsCj4+ICsJCQkJICAgc3RydWN0IG52bWV0X3JlcSAqcmVxKQo+PiArewo+PiArCXJl dHVybiAwOwo+PiArfQo+PiArc3RhdGljIGlubGluZSB2b2lkIG52bWV0X2luaXRfYXV0aChzdHJ1 Y3QgbnZtZXRfY3RybCAqY3RybCwKPj4gKwkJCQkgICBzdHJ1Y3QgbnZtZXRfcmVxICpyZXEpIHt9 Owo+PiArc3RhdGljIGlubGluZSB2b2lkIG52bWV0X3Jlc2V0X2F1dGgoc3RydWN0IG52bWV0X2N0 cmwgKmN0cmwpIHt9Owo+PiArc3RhdGljIGlubGluZSB2b2lkIG52bWV0X2F1dGhfc3FfZnJlZShz dHJ1Y3QgbnZtZXRfc3EgKnNxKSB7fTsKPj4gK3N0YXRpYyBpbmxpbmUgYm9vbCBudm1ldF9jaGVj a19hdXRoX3N0YXR1cyhzdHJ1Y3QgbnZtZXRfcmVxICpyZXEpCj4+ICt7Cj4+ICsJcmV0dXJuIHRy dWU7Cj4+ICt9Cj4+ICtzdGF0aWMgaW5saW5lIGJvb2wgbnZtZXRfaGFzX2F1dGgoc3RydWN0IG52 bWV0X2N0cmwgKmN0cmwpCj4+ICt7Cj4+ICsJcmV0dXJuIGZhbHNlOwo+PiArfQo+PiArc3RhdGlj IGlubGluZSBjb25zdCBjaGFyICpudm1ldF9kaGNoYXBfZGhncm91cF9uYW1lKGludCBkaGdpZCkg eyByZXR1cm4KPj4gTlVMTDsgfSArI2VuZGlmCj4+ICsKPj4gICAjZW5kaWYgLyogX05WTUVUX0gg Ki8KClRoYW5rcyBmb3IgdGhlIHJldmlldyEKCkNoZWVycywKCkhhbm5lcwotLSAKRHIuIEhhbm5l cyBSZWluZWNrZSAgICAgICAgICAgICAgICBLZXJuZWwgU3RvcmFnZSBBcmNoaXRlY3QKaGFyZUBz dXNlLmRlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKzQ5IDkxMSA3NDA1MyA2ODgKU1VT RSBTb2Z0d2FyZSBTb2x1dGlvbnMgR21iSCwgTWF4ZmVsZHN0ci4gNSwgOTA0MDkgTsO8cm5iZXJn CkhSQiAzNjgwOSAoQUcgTsO8cm5iZXJnKSwgR2VzY2jDpGZ0c2bDvGhyZXI6IEZlbGl4IEltZW5k w7ZyZmZlcgoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18K TGludXgtbnZtZSBtYWlsaW5nIGxpc3QKTGludXgtbnZtZUBsaXN0cy5pbmZyYWRlYWQub3JnCmh0 dHA6Ly9saXN0cy5pbmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtbnZtZQo=