From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: From: Scott Bauer To: linux-nvme@lists.infradead.org Subject: [PATCH v2 2/4] block: Add Sed-opal library Date: Tue, 29 Nov 2016 14:52:00 -0700 Message-Id: <1480456322-27339-3-git-send-email-scott.bauer@intel.com> In-Reply-To: <1480456322-27339-1-git-send-email-scott.bauer@intel.com> References: <1480456322-27339-1-git-send-email-scott.bauer@intel.com> MIME-Version: 1.0 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: keith.busch@intel.com, sagi@grimberg.me, hch@infradead.org, Rafael.Antognolli@intel.com, axboe@fb.com, linux-block@vger.kernel.org, Scott Bauer , jonathan.derrick@intel.com, j.naumann@fu-berlin.de Content-Type: text/plain; charset="utf-8" Sender: "Linux-nvme" Errors-To: linux-nvme-bounces+axboe=kernel.dk@lists.infradead.org List-ID: VGhpcyBwYXRjaCBpbXBsZW1lbnRzIHRoZSBuZWNlc3NhcnkgbG9naWMgdG8gYnJpbmcgYW4gT3Bh bAplbmFibGVkIGRyaXZlIG91dCBvZiBhIGZhY3RvcnktZW5hYmxlZCBpbnRvIGEgd29ya2luZwpP cGFsIHN0YXRlLgoKVGhpcyBwYXRjaCBzZXQgYWxzbyBlbmFibGVzIGxvZ2ljIHRvIHNhdmUgYSBw YXNzd29yZCB0bwpiZSByZXBsYXllZCBkdXJpbmcgYSByZXN1bWUgZnJvbSBzdXNwZW5kLiBUaGUg a2V5IGNhbiBiZQpzYXZlZCBpbiB0aGUgZHJpdmVyIG9yIGluIHRoZSBLZXJuZWwncyBLZXkgbWFu YWdtZW50LgoKU2lnbmVkLW9mZi1ieTogU2NvdHQgQmF1ZXIgPHNjb3R0LmJhdWVyQGludGVsLmNv bT4KU2lnbmVkLW9mZi1ieTogUmFmYWVsIEFudG9nbm9sbGkgPFJhZmFlbC5BbnRvZ25vbGxpQGlu dGVsLmNvbT4KLS0tCiBibG9jay9NYWtlZmlsZSAgICAgICAgICAgIHwgICAgMiArLQogYmxvY2sv c2VkLW9wYWwuYyAgICAgICAgICB8IDMxNTcgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKysrCiBibG9jay9zZWQtb3BhbF9pbnRlcm5hbC5oIHwgIDYwMSArKysrKysr KysKIGJsb2NrL3NlZC5jICAgICAgICAgICAgICAgfCAgMjA3ICsrKwogNCBmaWxlcyBjaGFuZ2Vk LCAzOTY2IGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24oLSkKIGNyZWF0ZSBtb2RlIDEwMDY0NCBi bG9jay9zZWQtb3BhbC5jCiBjcmVhdGUgbW9kZSAxMDA2NDQgYmxvY2svc2VkLW9wYWxfaW50ZXJu YWwuaAogY3JlYXRlIG1vZGUgMTAwNjQ0IGJsb2NrL3NlZC5jCgpkaWZmIC0tZ2l0IGEvYmxvY2sv TWFrZWZpbGUgYi9ibG9jay9NYWtlZmlsZQppbmRleCAzNmFjZGQ3Li42NjMyZDQyIDEwMDY0NAot LS0gYS9ibG9jay9NYWtlZmlsZQorKysgYi9ibG9jay9NYWtlZmlsZQpAQCAtOCw3ICs4LDcgQEAg b2JqLSQoQ09ORklHX0JMT0NLKSA6PSBiaW8ubyBlbGV2YXRvci5vIGJsay1jb3JlLm8gYmxrLXRh Zy5vIGJsay1zeXNmcy5vIFwKIAkJCWJsay1saWIubyBibGstbXEubyBibGstbXEtdGFnLm8gXAog CQkJYmxrLW1xLXN5c2ZzLm8gYmxrLW1xLWNwdW1hcC5vIGlvY3RsLm8gXAogCQkJZ2VuaGQubyBz Y3NpX2lvY3RsLm8gcGFydGl0aW9uLWdlbmVyaWMubyBpb3ByaW8ubyBcCi0JCQliYWRibG9ja3Mu byBwYXJ0aXRpb25zLworCQkJYmFkYmxvY2tzLm8gc2VkLm8gc2VkLW9wYWwubyBwYXJ0aXRpb25z LwogCiBvYmotJChDT05GSUdfQk9VTkNFKQkrPSBib3VuY2Uubwogb2JqLSQoQ09ORklHX0JMS19E RVZfQlNHKQkrPSBic2cubwpkaWZmIC0tZ2l0IGEvYmxvY2svc2VkLW9wYWwuYyBiL2Jsb2NrL3Nl ZC1vcGFsLmMKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNTM2MDJhYQotLS0g L2Rldi9udWxsCisrKyBiL2Jsb2NrL3NlZC1vcGFsLmMKQEAgLTAsMCArMSwzMTU3IEBACisvKgor ICogQ29weXJpZ2h0IMKpIDIwMTYgSW50ZWwgQ29ycG9yYXRpb24KKyAqCisgKiBBdXRob3JzOgor ICogICAgUmFmYWVsIEFudG9nbm9sbGkgPHJhZmFlbC5hbnRvZ25vbGxpQGludGVsLmNvbT4KKyAq ICAgIFNjb3R0ICBCYXVlciAgICAgIDxzY290dC5iYXVlckBpbnRlbC5jb20+CisgKgorICogVGhp cyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9v ciBtb2RpZnkgaXQKKyAqIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0aGUgR05V IEdlbmVyYWwgUHVibGljIExpY2Vuc2UsCisgKiB2ZXJzaW9uIDIsIGFzIHB1Ymxpc2hlZCBieSB0 aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0 cmlidXRlZCBpbiB0aGUgaG9wZSBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVQKKyAqIEFO WSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5U QUJJTElUWSBvcgorICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhl IEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvcgorICogbW9yZSBkZXRhaWxzLgorICovCisK KyNkZWZpbmUgcHJfZm10KGZtdCkgS0JVSUxEX01PRE5BTUUgIjpPUEFMOiAiIGZtdAorCisjaW5j bHVkZSA8bGludXgvZGVsYXkuaD4KKyNpbmNsdWRlIDxsaW51eC9kZXZpY2UuaD4KKyNpbmNsdWRl IDxsaW51eC9rZXJuZWwuaD4KKyNpbmNsdWRlIDxsaW51eC9saXN0Lmg+CisjaW5jbHVkZSA8bGlu dXgvZ2VuaGQuaD4KKyNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CisjaW5jbHVkZSA8bGludXgvdWFj Y2Vzcy5oPgorI2luY2x1ZGUgPHVhcGkvbGludXgvc2VkLW9wYWwuaD4KKyNpbmNsdWRlIDxsaW51 eC9zZWQuaD4KKyNpbmNsdWRlIDxsaW51eC9zZWQtb3BhbC5oPgorI2luY2x1ZGUgPGxpbnV4L3N0 cmluZy5oPgorI2luY2x1ZGUgPGxpbnV4L2tkZXZfdC5oPgorI2luY2x1ZGUgPGxpbnV4L2tleS5o PgorCisjaW5jbHVkZSAic2VkLW9wYWxfaW50ZXJuYWwuaCIKKworI2RlZmluZSBJT19CVUZGRVJf TEVOR1RIIDIwNDgKKworI2RlZmluZSBNQVhfVE9LUyA2NAorCit0eXBlZGVmIGludCAoY29udF9m bikodm9pZCAqZGF0YSk7CisKK3N0cnVjdCBvcGFsX2NtZCB7CisJc3RydWN0IGJsb2NrX2Rldmlj ZSAqYmRldjsKKwljb250X2ZuICpjYjsKKwl2b2lkICpjYl9kYXRhOworCisJc2l6ZV90IHBvczsK Kwl1OCBjbWRfYnVmW0lPX0JVRkZFUl9MRU5HVEggKiAyXTsKKwl1OCByZXNwX2J1ZltJT19CVUZG RVJfTEVOR1RIICogMl07CisJdTggKmNtZDsKKwl1OCAqcmVzcDsKK307CisKKy8qCisgKiBPbiB0 aGUgcGFyc2VkIHJlc3BvbnNlLCB3ZSBkb24ndCBzdG9yZSBhZ2FpbiB0aGUgdG9rcyB0aGF0IGFy ZSBhbHJlYWR5CisgKiBzdG9yZWQgaW4gdGhlIHJlc3BvbnNlIGJ1ZmZlci4gSW5zdGVhZCwgZm9y IGVhY2ggdG9rZW4sIHdlIGp1c3Qgc3RvcmUgYQorICogcG9pbnRlciB0byB0aGUgcG9zaXRpb24g aW4gdGhlIGJ1ZmZlciB3aGVyZSB0aGUgdG9rZW4gc3RhcnRzLCBhbmQgdGhlIHNpemUKKyAqIG9m IHRoZSB0b2tlbiBpbiBieXRlcy4KKyAqLworc3RydWN0IG9wYWxfcmVzcF90b2sgeworCWNvbnN0 IHU4ICpwb3M7CisJc2l6ZV90IGxlbjsKKwllbnVtIE9QQUxfUkVTUE9OU0VfVE9LRU4gdHlwZTsK KwllbnVtIE9QQUxfQVRPTV9XSURUSCB3aWR0aDsKKwl1bmlvbiB7CisJCXU2NCB1OworCQlzNjQg czsKKwl9IHN0b3JlZDsKK307CisKKy8qCisgKiBGcm9tIHRoZSByZXNwb25zZSBoZWFkZXIgaXQn cyBub3QgcG9zc2libGUgdG8ga25vdyBob3cgbWFueSB0b2tlbnMgdGhlcmUgYXJlCisgKiBvbiB0 aGUgcGF5bG9hZC4gU28gd2UgaGFyZGNvZGUgdGhhdCB0aGUgbWF4aW11bSB3aWxsIGJlIE1BWF9U T0tTLCBhbmQgbGF0ZXIKKyAqIGlmIHdlIHN0YXJ0IGRlYWxpbmcgd2l0aCBtZXNzYWdlcyB0aGF0 IGhhdmUgbW9yZSB0aGFuIHRoYXQsIHdlIGNhbiBpbmNyZWFzZQorICogdGhpcyBudW1iZXIuIFRo aXMgaXMgZG9uZSB0byBhdm9pZCBoYXZpbmcgdG8gbWFrZSB0d28gcGFzc2VzIHRocm91Z2ggdGhl CisgKiByZXNwb25zZSwgdGhlIGZpcnN0IG9uZSBjb3VudGluZyBob3cgbWFueSB0b2tlbnMgd2Ug aGF2ZSBhbmQgdGhlIHNlY29uZCBvbmUKKyAqIGFjdHVhbGx5IHN0b3JpbmcgdGhlIHBvc2l0aW9u cy4KKyAqLworc3RydWN0IHBhcnNlZF9yZXNwIHsKKwlpbnQgbnVtOworCXN0cnVjdCBvcGFsX3Jl c3BfdG9rIHRva3NbTUFYX1RPS1NdOworfTsKKworc3RydWN0IG9wYWxfZGV2OworCit0eXBlZGVm IGludCAoKm9wYWxfc3RlcCkoc3RydWN0IG9wYWxfZGV2ICpkZXYpOworCitzdHJ1Y3Qgb3BhbF9k ZXYgeworCWRldl90IG1ham1pbjsKKwlzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuOworCXZvaWQg KnN1Ym1pdF9kYXRhOworCXN0cnVjdCBvcGFsX2xvY2tfdW5sb2NrIGxrdWw7CisJY29uc3Qgb3Bh bF9zdGVwICpmdW5jczsKKwl2b2lkICoqZnVuY19kYXRhOworCWJvb2wgcmVzdW1lX2Zyb21fc3Vz cGVuZDsKKwlzdHJ1Y3Qgb3BhbF9zdXNwZW5kX3VubGsgKnJlc3VtZV9kYXRhOworCXNpemVfdCBu dW1fZnVuY19kYXRhOworCWF0b21pY190IGluX3VzZTsKKwlzZWN0b3JfdCBzdGFydDsKKwlzZWN0 b3JfdCBsZW5ndGg7CisJdTggbHI7CisJdTgga2V5X3R5cGU7CisJdTgga2V5X25hbWVbT1BBTF9L RVlfTUFYXTsKKwlzaXplX3Qga2V5X25hbWVfbGVuOworCXU4IGtleVtPUEFMX0tFWV9NQVhdOwor CXNpemVfdCBrZXlfbGVuOworCXUxNiBjb21JRDsKKwl1MzIgSFNOOworCXUzMiBUU047CisJdTY0 IGFsaWduOworCXU2NCBsb3dlc3RfbGJhOworCXN0cnVjdCBsaXN0X2hlYWQgbm9kZTsKKwljaGFy IGRpc2tfbmFtZVtESVNLX05BTUVfTEVOXTsKKwlpbnQgc3RhdGU7CisKKwlzdHJ1Y3Qgb3BhbF9j bWQgY21kOworCXN0cnVjdCBwYXJzZWRfcmVzcCBwYXJzZWQ7CisKKwlzaXplX3QgcHJldl9kX2xl bjsKKwl2b2lkICpwcmV2X2RhdGE7CisKKwlvcGFsX3N0ZXAgZXJyb3JfY2I7CisJdm9pZCAqZXJy b3JfY2JfZGF0YTsKK307CisKK0xJU1RfSEVBRChvcGFsX2xpc3QpOworREVGSU5FX1NQSU5MT0NL KGxpc3Rfc3BpbmxvY2spOworCitzdGF0aWMgdm9pZCBwcmludF9idWZmZXIoY29uc3QgdTggKnB0 ciwgdTMyIGxlbmd0aCkKK3sKKyNpZmRlZiBERUJVRworCXByaW50X2hleF9kdW1wX2J5dGVzKCJP UEFMOiAiLCBEVU1QX1BSRUZJWF9PRkZTRVQsIHB0ciwgbGVuZ3RoKTsKKwlwcl9kZWJ1ZygiXG4i KTsKKyNlbmRpZgorfQorCisjZGVmaW5lIFRQRVJfU1lOQ19TVVBQT1JURUQgQklUKDApCisKK3N0 YXRpYyBib29sIGNoZWNrX3RwZXIoY29uc3Qgdm9pZCAqZGF0YSkKK3sKKwljb25zdCBzdHJ1Y3Qg ZDBfdHBlcl9mZWF0dXJlcyAqdHBlciA9IGRhdGE7CisJdTggZmxhZ3MgPSB0cGVyLT5zdXBwb3J0 ZWRfZmVhdHVyZXM7CisKKwlpZiAoIShmbGFncyAmIFRQRVJfU1lOQ19TVVBQT1JURUQpKSB7CisJ CXByX2VycigiVFBlciBzeW5jIG5vdCBzdXBwb3J0ZWQuIGZsYWdzID0gJWRcbiIsCisJCSAgICAg ICB0cGVyLT5zdXBwb3J0ZWRfZmVhdHVyZXMpOworCQlyZXR1cm4gZmFsc2U7CisJfQorCisJcmV0 dXJuIHRydWU7Cit9CisKK3N0YXRpYyBib29sIGNoZWNrX1NVTShjb25zdCB2b2lkICpkYXRhKQor eworCWNvbnN0IHN0cnVjdCBkMF9zaW5nbGVfdXNlcl9tb2RlICpzdW0gPSBkYXRhOworCXUzMiBu bG8gPSBiZTMyX3RvX2NwdShzdW0tPm51bV9sb2NraW5nX29iamVjdHMpOworCisJaWYgKG5sbyA9 PSAwKSB7CisJCXByX2VycigiTmVlZCBhdCBsZWFzdCBvbmUgbG9ja2luZyBvYmplY3QuXG4iKTsK KwkJcmV0dXJuIGZhbHNlOworCX0KKworCXByX2RlYnVnKCJOdW1iZXIgb2YgbG9ja2luZyBvYmpl Y3RzOiAlZFxuIiwgbmxvKTsKKworCXJldHVybiB0cnVlOworfQorCitzdGF0aWMgdTE2IGdldF9j b21JRF92MTAwKGNvbnN0IHZvaWQgKmRhdGEpCit7CisJY29uc3Qgc3RydWN0IGQwX29wYWxfdjEw MCAqdjEwMCA9IGRhdGE7CisKKwlyZXR1cm4gYmUxNl90b19jcHUodjEwMC0+YmFzZUNvbUlEKTsK K30KKworc3RhdGljIHUxNiBnZXRfY29tSURfdjIwMChjb25zdCB2b2lkICpkYXRhKQoreworCWNv bnN0IHN0cnVjdCBkMF9vcGFsX3YyMDAgKnYyMDAgPSBkYXRhOworCisJcmV0dXJuIGJlMTZfdG9f Y3B1KHYyMDAtPmJhc2VDb21JRCk7Cit9CisKK3N0YXRpYyBpbnQgb3BhbF9zZW5kX2NtZChzdHJ1 Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlyZXR1cm4gZGV2LT5zdWJtaXRfZm4oZGV2LT5zdWJtaXRf ZGF0YSwgZGV2LT5jb21JRCwgVENHX1NFQ1BfMDEsCisJCQkgICAgICBkZXYtPmNtZC5jbWQsIElP X0JVRkZFUl9MRU5HVEgsIHRydWUpOworfQorCitzdGF0aWMgaW50IG9wYWxfcmVjdl9jbWQoc3Ry dWN0IG9wYWxfZGV2ICpkZXYpCit7CisJcmV0dXJuIGRldi0+c3VibWl0X2ZuKGRldi0+c3VibWl0 X2RhdGEsIGRldi0+Y29tSUQsIFRDR19TRUNQXzAxLAorCQkJICAgICAgZGV2LT5jbWQucmVzcCwg SU9fQlVGRkVSX0xFTkdUSCwgZmFsc2UpOworfQorCitzdGF0aWMgaW50IG9wYWxfcmVjdl9jaGVj ayhzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzaXplX3QgYnVmbGVuID0gSU9fQlVGRkVSX0xF TkdUSDsKKwl2b2lkICpidWZmZXIgPSBkZXYtPmNtZC5yZXNwOworCXN0cnVjdCBvcGFsX2hlYWRl ciAqaGRyID0gYnVmZmVyOworCWludCByZXQ7CisKKwlkbyB7CisJCXByX2RlYnVnKCIlczogU2Vu dCBPUEFMIGNvbW1hbmQ6IG91dHN0YW5kaW5nPSVkLCBtaW5UcmFuc2Zlcj0lZFxuIiwKKwkJCSBk ZXYtPmRpc2tfbmFtZSwgaGRyLT5jcC5vdXRzdGFuZGluZ0RhdGEsCisJCQkgaGRyLT5jcC5taW5U cmFuc2Zlcik7CisKKwkJaWYgKGhkci0+Y3Aub3V0c3RhbmRpbmdEYXRhID09IDAgfHwKKwkJICAg IGhkci0+Y3AubWluVHJhbnNmZXIgIT0gMCkKKwkJCXJldHVybiAwOworCisJCW1lbXNldChidWZm ZXIsIDAsIGJ1Zmxlbik7CisJCXJldCA9IG9wYWxfcmVjdl9jbWQoZGV2KTsKKwl9IHdoaWxlICgh cmV0KTsKKworCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpbnQgb3BhbF9zZW5kX3JlY3Yoc3Ry dWN0IG9wYWxfZGV2ICpkZXYsIGNvbnRfZm4gKmNvbnQpCit7CisJaW50IHJldDsKKworCXJldCA9 IG9wYWxfc2VuZF9jbWQoZGV2KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCXJldCA9IG9w YWxfcmVjdl9jbWQoZGV2KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCXJldCA9IG9wYWxf cmVjdl9jaGVjayhkZXYpOworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisKKwlyZXR1cm4gY29u dChkZXYpOworfQorCitzdGF0aWMgdm9pZCBjaGVja19nZW9tZXRyeShzdHJ1Y3Qgb3BhbF9kZXYg KmRldiwgY29uc3Qgdm9pZCAqZGF0YSkKK3sKKwljb25zdCBzdHJ1Y3QgZDBfZ2VvbWV0cnlfZmVh dHVyZXMgKmdlbyA9IGRhdGE7CisKKwlkZXYtPmFsaWduID0gZ2VvLT5hbGlnbm1lbnRfZ3JhbnVs YXJpdHk7CisJZGV2LT5sb3dlc3RfbGJhID0gZ2VvLT5sb3dlc3RfYWxpZ25lZF9sYmE7Cit9CisK K3N0YXRpYyBpbnQgbmV4dChzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlvcGFsX3N0ZXAgZnVu YzsKKwlpbnQgZXJyb3IgPSAwOworCisJZG8geworCisJCWZ1bmMgPSBkZXYtPmZ1bmNzW2Rldi0+ c3RhdGVdOworCQlpZiAoIWZ1bmMpCisJCQlicmVhazsKKworCQlkZXYtPnN0YXRlKys7CisJCWVy cm9yID0gZnVuYyhkZXYpOworCisJCWlmIChlcnJvcikgeworCQkJcHJfZXJyKCIlczogRXJyb3Ig b24gc3RlcCBmdW5jdGlvbjogJWQgd2l0aCBlcnJvciAlZDogJXNcbiIsCisJCQkgICAgICAgZGV2 LT5kaXNrX25hbWUsIGRldi0+c3RhdGUsIGVycm9yLAorCQkJICAgICAgIG9wYWxfZXJyb3JfdG9f aHVtYW4oZXJyb3IpKTsKKworCQkJLyoKKwkJCSAqIFdlIGNoZWNrIGZvciBzdGF0ZSA+IDIgYmVj YXVzZSBlcnJvcl9jYiBpcworCQkJICogYW4gZW5kIHNlc3Npb24gY2FsbC4gV2UgbmV2ZXIgc3Rh cnQgYSBzZXNzaW9uIHVudGlsCisJCQkgKiBhZnRlciBzdGF0ZSAyLiBTbyBJZiB3ZSBmYWlsZWQg b24gc3RhdGUgMiBvciBsb3dlcgorCQkJICogdGhhdCBtZWFucyB3ZSBmYWlsZWQgdG8gc3RhcnQg YSBzZXNzaW9uCisJCQkgKiBkdWUgdG8gYSBiYWQgcHcgb3Igc29tZXRoaW5nLiBUaGVyZWZvcmUg aXMgbm8gcmVhc29uCisJCQkgKiB0byBlbmQgYSBub24gZXhpc3RhbnQgc2Vzc2lvbi4KKwkJCSAq LworCQkJaWYgKGRldi0+ZXJyb3JfY2IgJiYgZGV2LT5zdGF0ZSA+IDIpCisJCQkJZGV2LT5lcnJv cl9jYihkZXYtPmVycm9yX2NiX2RhdGEpOworCQl9CisJfSB3aGlsZSAoIWVycm9yKTsKKworCXJl dHVybiBlcnJvcjsKK30KKworc3RhdGljIGludCBvcGFsX2Rpc2NvdmVyeTBfZW5kKHN0cnVjdCBv cGFsX2RldiAqZGV2KQoreworCWJvb2wgZm91bmRDb21JRCA9IGZhbHNlLCBzdXBwb3J0ZWQgPSB0 cnVlLCBzaW5nbGVfdXNlciA9IGZhbHNlOworCWNvbnN0IHN0cnVjdCBkMF9oZWFkZXIgKmhkcjsK Kwljb25zdCB1OCAqZXBvcywgKmNwb3M7CisJdTE2IGNvbUlEID0gMDsKKwlpbnQgZXJyb3IgPSAw OworCisJZXBvcyA9IGRldi0+Y21kLnJlc3A7CisJY3BvcyA9IGRldi0+Y21kLnJlc3A7CisJaGRy ID0gKHN0cnVjdCBkMF9oZWFkZXIgKilkZXYtPmNtZC5yZXNwOworCisJcHJpbnRfYnVmZmVyKGRl di0+Y21kLnJlc3AsIGJlMzJfdG9fY3B1KGhkci0+bGVuZ3RoKSk7CisKKwllcG9zICs9IGJlMzJf dG9fY3B1KGhkci0+bGVuZ3RoKTsgLyogZW5kIG9mIGJ1ZmZlciAqLworCWNwb3MgKz0gc2l6ZW9m KCpoZHIpOyAvKiBjdXJyZW50IHBvc2l0aW9uIG9uIGJ1ZmZlciAqLworCisJd2hpbGUgKGNwb3Mg PCBlcG9zICYmIHN1cHBvcnRlZCkgeworCQljb25zdCBzdHJ1Y3QgZDBfZmVhdHVyZXMgKmJvZHkg PQorCQkJKGNvbnN0IHN0cnVjdCBkMF9mZWF0dXJlcyAqKWNwb3M7CisKKwkJc3dpdGNoIChiZTE2 X3RvX2NwdShib2R5LT5jb2RlKSkgeworCQljYXNlIEZDX1RQRVI6CisJCQlzdXBwb3J0ZWQgPSBj aGVja190cGVyKGJvZHktPmZlYXR1cmVzKTsKKwkJCWJyZWFrOworCQljYXNlIEZDX1NJTkdMRVVT RVI6CisJCQlzaW5nbGVfdXNlciA9IGNoZWNrX1NVTShib2R5LT5mZWF0dXJlcyk7CisJCQlicmVh azsKKwkJY2FzZSBGQ19HRU9NRVRSWToKKwkJCWNoZWNrX2dlb21ldHJ5KGRldiwgYm9keSk7CisJ CQlicmVhazsKKwkJY2FzZSBGQ19MT0NLSU5HOgorCQljYXNlIEZDX0VOVEVSUFJJU0U6CisJCWNh c2UgRkNfREFUQVNUT1JFOgorCQkJLyogc29tZSBpZ25vcmVkIHByb3BlcnRpZXMgKi8KKwkJCXBy X2RlYnVnKCIlczogRm91bmQgT1BBTCBmZWF0dXJlIGRlc2NyaXB0aW9uOiAlZFxuIiwKKwkJCQkg ZGV2LT5kaXNrX25hbWUsIGJlMTZfdG9fY3B1KGJvZHktPmNvZGUpKTsKKwkJCWJyZWFrOworCQlj YXNlIEZDX09QQUxWMTAwOgorCQkJY29tSUQgPSBnZXRfY29tSURfdjEwMChib2R5LT5mZWF0dXJl cyk7CisJCQlmb3VuZENvbUlEID0gdHJ1ZTsKKwkJCWJyZWFrOworCQljYXNlIEZDX09QQUxWMjAw OgorCQkJY29tSUQgPSBnZXRfY29tSURfdjIwMChib2R5LT5mZWF0dXJlcyk7CisJCQlmb3VuZENv bUlEID0gdHJ1ZTsKKwkJCWJyZWFrOworCQljYXNlIDB4YmZmZiAuLi4gMHhmZmZmOgorCQkJLyog dmVuZG9yIHNwZWNpZmljLCBqdXN0IGlnbm9yZSAqLworCQkJYnJlYWs7CisJCWRlZmF1bHQ6CisJ CQlwcl93YXJuKCIlczogT1BBTCBVbmtub3duIGZlYXR1cmU6ICVkXG4iLAorCQkJCWRldi0+ZGlz a19uYW1lLCBiZTE2X3RvX2NwdShib2R5LT5jb2RlKSk7CisKKwkJfQorCQljcG9zICs9IGJvZHkt Pmxlbmd0aCArIDQ7CisJfQorCisJaWYgKCFzdXBwb3J0ZWQpIHsKKwkJcHJfZXJyKCIlczogRGV2 aWNlIG5vdCBzdXBwb3J0ZWRcbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJZXJyb3IgPSAxOworCQln b3RvIGVycl9jYWxsYmFjazsKKwl9CisKKwlpZiAoIXNpbmdsZV91c2VyKQorCQlwcl93YXJuKCIl czogRGV2aWNlIGRvZXNuJ3Qgc3VwcG9ydCBzaW5nbGUgdXNlciBtb2RlXG4iLAorCQkJZGV2LT5k aXNrX25hbWUpOworCisJaWYgKCFmb3VuZENvbUlEKSB7CisJCXByX3dhcm4oIiVzOiBDb3VsZCBu b3QgZmluZCBPUEFMIGNvbUlEIGZvciBkZXZpY2UuIE9QQUwga2VybmVsIHVubG9ja2luZyB3aWxs IGJlIGRpc2FibGVkXG4iLAorCQkJZGV2LT5kaXNrX25hbWUpOworCQllcnJvciA9IDE7CisJCWdv dG8gZXJyX2NhbGxiYWNrOworCX0KKworCWRldi0+Y29tSUQgPSBjb21JRDsKKworZXJyX2NhbGxi YWNrOgorCXJldHVybiBlcnJvcjsKK30KKworc3RhdGljIGludCBvcGFsX2Rpc2NvdmVyeTAoc3Ry dWN0IG9wYWxfZGV2ICpkZXYpCit7CisJaW50IHJldDsKKworCW1lbXNldChkZXYtPmNtZC5yZXNw LCAwLCBJT19CVUZGRVJfTEVOR1RIKTsKKwlkZXYtPmNvbUlEID0gMHgwMDAxOworCXJldCA9IG9w YWxfcmVjdl9jbWQoZGV2KTsKKwlpZiAocmV0KQorCQlyZXR1cm4gcmV0OworCXJldHVybiBvcGFs X2Rpc2NvdmVyeTBfZW5kKGRldik7Cit9CisKK3N0YXRpYyB2b2lkIGFkZF90b2tlbl91OChzdHJ1 Y3Qgb3BhbF9jbWQgKmNtZCwgdTggdG9rKQoreworCWNtZC0+Y21kW2NtZC0+cG9zKytdID0gdG9r OworfQorCitzdGF0aWMgc3NpemVfdCB0ZXN0X2FuZF9hZGRfdG9rZW5fdTgoc3RydWN0IG9wYWxf Y21kICpjbWQsIHU4IHRvaykKK3sKKwlCVUlMRF9CVUdfT04oSU9fQlVGRkVSX0xFTkdUSCA+PSBT SVpFX01BWCk7CisKKwlpZiAoY21kLT5wb3MgPj0gSU9fQlVGRkVSX0xFTkdUSCAtIDEpIHsKKwkJ cHJfZXJyKCJFcnJvciBhZGRpbmcgdTg6IGVuZCBvZiBidWZmZXIuXG4iKTsKKwkJcmV0dXJuIC1F UkFOR0U7CisJfQorCisJYWRkX3Rva2VuX3U4KGNtZCwgdG9rKTsKKworCXJldHVybiAxOworfQor CisjZGVmaW5lIFRJTllfQVRPTV9EQVRBX01BU0sgR0VOTUFTSyg1LCAwKQorI2RlZmluZSBUSU5Z X0FUT01fU0lHTkVEIEJJVCg2KQorCisjZGVmaW5lIFNIT1JUX0FUT01fSUQgQklUKDcpCisjZGVm aW5lIFNIT1JUX0FUT01fQllURVNUUklORyBCSVQoNSkKKyNkZWZpbmUgU0hPUlRfQVRPTV9TSUdO RUQgQklUKDQpCisjZGVmaW5lIFNIT1JUX0FUT01fTEVOX01BU0sgR0VOTUFTSygzLCAwKQorCitz dGF0aWMgdm9pZCBhZGRfc2hvcnRfYXRvbV9oZWFkZXIoc3RydWN0IG9wYWxfY21kICpjbWQsIGJv b2wgYnl0ZXN0cmluZywKKwkJCQkgIGJvb2wgaGFzX3NpZ24sIGludCBsZW4pCit7CisJdTggYXRv bTsKKworCWF0b20gPSBTSE9SVF9BVE9NX0lEOworCWF0b20gfD0gYnl0ZXN0cmluZyA/IFNIT1JU X0FUT01fQllURVNUUklORyA6IDA7CisJYXRvbSB8PSBoYXNfc2lnbiA/IFNIT1JUX0FUT01fU0lH TkVEIDogMDsKKwlhdG9tIHw9IGxlbiAmIFNIT1JUX0FUT01fTEVOX01BU0s7CisKKwlhZGRfdG9r ZW5fdTgoY21kLCBhdG9tKTsKK30KKworI2RlZmluZSBNRURJVU1fQVRPTV9JRCAoQklUKDcpIHwg QklUKDYpKQorI2RlZmluZSBNRURJVU1fQVRPTV9CWVRFU1RSSU5HIEJJVCg0KQorI2RlZmluZSBN RURJVU1fQVRPTV9TSUdORUQgQklUKDMpCisjZGVmaW5lIE1FRElVTV9BVE9NX0xFTl9NQVNLIEdF Tk1BU0soMiwgMCkKKworc3RhdGljIHZvaWQgYWRkX21lZGl1bV9hdG9tX2hlYWRlcihzdHJ1Y3Qg b3BhbF9jbWQgKmNtZCwgYm9vbCBieXRlc3RyaW5nLAorCQkJCSAgIGJvb2wgaGFzX3NpZ24sIGlu dCBsZW4pCit7CisJdTggaGVhZGVyMDsKKworCWhlYWRlcjAgPSBNRURJVU1fQVRPTV9JRDsKKwlo ZWFkZXIwIHw9IGJ5dGVzdHJpbmcgPyBNRURJVU1fQVRPTV9CWVRFU1RSSU5HIDogMDsKKwloZWFk ZXIwIHw9IGhhc19zaWduID8gTUVESVVNX0FUT01fU0lHTkVEIDogMDsKKwloZWFkZXIwIHw9IChs ZW4gPj4gOCkgJiBNRURJVU1fQVRPTV9MRU5fTUFTSzsKKwljbWQtPmNtZFtjbWQtPnBvcysrXSA9 IGhlYWRlcjA7CisJY21kLT5jbWRbY21kLT5wb3MrK10gPSBsZW47Cit9CisKK3N0YXRpYyB2b2lk IGFkZF90b2tlbl91NjQoc3RydWN0IG9wYWxfY21kICpjbWQsIHU2NCBudW1iZXIsIHNpemVfdCBs ZW4pCit7CisJYWRkX3Nob3J0X2F0b21faGVhZGVyKGNtZCwgZmFsc2UsIGZhbHNlLCBsZW4pOwor CisJd2hpbGUgKGxlbi0tKSB7CisJCXU4IG4gPSBudW1iZXIgPj4gKGxlbiAqIDgpOworCisJCWFk ZF90b2tlbl91OChjbWQsIG4pOworCX0KK30KKworc3RhdGljIHNzaXplX3QgdGVzdF9hbmRfYWRk X3Rva2VuX3U2NChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTY0IG51bWJlcikKK3sKKwlpbnQgbGVu OworCWludCBtc2I7CisKKwlpZiAoIShudW1iZXIgJiB+VElOWV9BVE9NX0RBVEFfTUFTSykpCisJ CXJldHVybiB0ZXN0X2FuZF9hZGRfdG9rZW5fdTgoY21kLCBudW1iZXIpOworCisJbXNiID0gZmxz KG51bWJlcik7CisJbGVuID0gRElWX1JPVU5EX1VQKG1zYiwgNCk7CisKKwlpZiAoY21kLT5wb3Mg Pj0gSU9fQlVGRkVSX0xFTkdUSCAtIGxlbiAtIDEpIHsKKwkJcHJfZXJyKCJFcnJvciBhZGRpbmcg dTY0OiBlbmQgb2YgYnVmZmVyLlxuIik7CisJCXJldHVybiAtRVJBTkdFOworCX0KKworCWFkZF90 b2tlbl91NjQoY21kLCBudW1iZXIsIGxlbik7CisKKwkvKiByZXR1cm4gbGVuZ3RoIG9mIHRva2Vu IHBsdXMgYXRvbSAqLworCXJldHVybiBsZW4gKyAxOworfQorCitzdGF0aWMgdm9pZCBhZGRfdG9r ZW5fYnl0ZXN0cmluZyhzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwKKwkJCQkgY29uc3QgdTggKmJ5dGVz dHJpbmcsIHNpemVfdCBsZW4pCit7CisJbWVtY3B5KCZjbWQtPmNtZFtjbWQtPnBvc10sIGJ5dGVz dHJpbmcsIGxlbik7CisJY21kLT5wb3MgKz0gbGVuOworfQorCitzdGF0aWMgc3NpemVfdCB0ZXN0 X2FuZF9hZGRfdG9rZW5fYnl0ZXN0cmluZyhzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwKKwkJCQkJICAg ICBjb25zdCB1OCAqYnl0ZXN0cmluZywgc2l6ZV90IGxlbikKK3sKKwlzaXplX3QgaGVhZGVyX2xl biA9IDE7CisJYm9vbCBpc19zaG9ydF9hdG9tID0gdHJ1ZTsKKworCWlmIChsZW4gJiB+U0hPUlRf QVRPTV9MRU5fTUFTSykgeworCQloZWFkZXJfbGVuID0gMjsKKwkJaXNfc2hvcnRfYXRvbSA9IGZh bHNlOworCX0KKworCWlmIChjbWQtPnBvcyA+PSBJT19CVUZGRVJfTEVOR1RIIC0gbGVuIC0gaGVh ZGVyX2xlbikgeworCQlwcl9lcnIoIkVycm9yIGFkZGluZyBieXRlc3RyaW5nOiBlbmQgb2YgYnVm ZmVyLlxuIik7CisJCXJldHVybiAtRVJBTkdFOworCX0KKworCWlmIChpc19zaG9ydF9hdG9tKQor CQlhZGRfc2hvcnRfYXRvbV9oZWFkZXIoY21kLCB0cnVlLCBmYWxzZSwgbGVuKTsKKwllbHNlCisJ CWFkZF9tZWRpdW1fYXRvbV9oZWFkZXIoY21kLCB0cnVlLCBmYWxzZSwgbGVuKTsKKworCWFkZF90 b2tlbl9ieXRlc3RyaW5nKGNtZCwgYnl0ZXN0cmluZywgbGVuKTsKKworCXJldHVybiBoZWFkZXJf bGVuICsgbGVuOworfQorCisjZGVmaW5lIExPQ0tJTkdfUkFOR0VfTk9OX0dMT0JBTCAweDAzCisK K3N0YXRpYyBpbnQgYnVpbGRfbG9ja2luZ19yYW5nZSh1OCAqYnVmZmVyLCBzaXplX3QgbGVuZ3Ro LCB1OCBscikKK3sKKwlpZiAobGVuZ3RoIDwgT1BBTF9VSURfTEVOR1RIKQorCQlyZXR1cm4gLUVS QU5HRTsKKworCW1lbWNweShidWZmZXIsIE9QQUxVSURbT1BBTF9MT0NLSU5HUkFOR0VfR0xPQkFM XSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWlmIChsciA9PSAwKQorCQlyZXR1cm4gMDsKKwlidWZm ZXJbNV0gPSBMT0NLSU5HX1JBTkdFX05PTl9HTE9CQUw7CisJYnVmZmVyWzddID0gbHI7CisKKwly ZXR1cm4gMDsKK30KKworc3RhdGljIGludCBidWlsZF9sb2NraW5nX3VzZXIodTggKmJ1ZmZlciwg c2l6ZV90IGxlbmd0aCwgdTggbHIpCit7CisJaWYgKGxlbmd0aCA8IE9QQUxfVUlEX0xFTkdUSCkK KwkJcmV0dXJuIC1FUkFOR0U7CisKKwltZW1jcHkoYnVmZmVyLCBPUEFMVUlEW09QQUxfVVNFUjFf VUlEXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWJ1ZmZlcls3XSA9IGxyICsgMTsKKworCXJldHVy biAwOworfQorCisvKgorICogTiA9IG51bWJlciBvZiBmb3JtYXQgc3BlY2lmaWVycyAoMS05OTkp IHRvIGJlIHJlcGxpY2F0ZWQKKyAqIGMgPSB1OAorICogdSA9IHU2NAorICogcyA9IGJ5dGVzdHJp bmcsIGxlbmd0aAorICoKKyAqIHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjIiwK KyAqCQkJICAgICAgIHU4X3ZhbDEpOworICoKKyAqIHJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92 YShjbWQsICIyYzJ1IiwKKyAqCQkJICAgICAgIHU4X3ZhbDEsIHU4X3ZhbDIsIHU2NF92YWwxLCB1 NjRfdmFsMik7CisgKgorICogcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjNzIiwK KyAqCQkJICAgICAgIGJ5dGVzdHJpbmcxLCBsZW5ndGgxLAorICoJCQkgICAgICAgYnl0ZXN0cmlu ZzIsIGxlbmd0aDIsCisgKgkJCSAgICAgICBieXRlc3RyaW5nMywgbGVuZ3RoMyk7CisgKi8KK3N0 YXRpYyBpbnQgdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKHN0cnVjdCBvcGFsX2NtZCAqY21kLAorCQkJ CSBjb25zdCBjaGFyICpmbXQsIC4uLikKK3sKKwljb25zdCB1OCAqaXQgPSBmbXQsICp0bXA7CisJ aW50IHJldCwgbnVtID0gMSwgc3VtID0gMDsKKwl2YV9saXN0IGFwOworCisJdmFfc3RhcnQoYXAs IGZtdCk7CisKKwl3aGlsZSAoKml0ICE9ICdcMCcpIHsKKwkJdTY0IHRvazY0ID0gMDsKKwkJdTgg dG9rLCAqYnN0cjsKKwkJc2l6ZV90IGxlbjsKKworCQlyZXQgPSAwOworCisJCXN3aXRjaCAoKml0 KSB7CisJCWNhc2UgJzEnIC4uLiAnOSc6CisJCQl0bXAgPSBpdDsKKwkJCW51bSA9IDA7CisJCQl3 aGlsZSAoKnRtcCA+PSAnMCcgJiYgKnRtcCA8PSAnOScpCisJCQkJbnVtID0gbnVtICogMTAgKyAo KnRtcCsrIC0gJzAnKTsKKwkJCWl0ID0gdG1wOworCQkJY29udGludWU7CisJCWNhc2UgJ2MnOgor CQkJd2hpbGUgKG51bS0tKSB7CisJCQkJdG9rID0gdmFfYXJnKGFwLCB1bnNpZ25lZCBpbnQpOwor CQkJCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl91OChjbWQsIHRvayk7CisJCQkJaWYgKHJldCA8 IDApCisJCQkJCWdvdG8gZXJyOworCQkJfQorCQkJbnVtID0gMTsKKwkJCWJyZWFrOworCQljYXNl ICd1JzoKKwkJCXdoaWxlIChudW0tLSkgeworCQkJCXRvazY0ID0gdmFfYXJnKGFwLCB1NjQpOwor CQkJCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl91NjQoY21kLCB0b2s2NCk7CisJCQkJaWYgKHJl dCA8IDApCisJCQkJCWdvdG8gZXJyOworCQkJfQorCQkJbnVtID0gMTsKKwkJCWJyZWFrOworCQlj YXNlICdzJzoKKwkJCXdoaWxlIChudW0tLSkgeworCQkJCWJzdHIgPSB2YV9hcmcoYXAsIHU4ICop OworCQkJCWxlbiA9IHZhX2FyZyhhcCwgc2l6ZV90KTsKKwkJCQlyZXQgPSB0ZXN0X2FuZF9hZGRf dG9rZW5fYnl0ZXN0cmluZyhjbWQsIGJzdHIsCisJCQkJCQkJCSAgICBsZW4pOworCQkJCWlmIChy ZXQgPCAwKQorCQkJCQlnb3RvIGVycjsKKwkJCX0KKwkJCW51bSA9IDE7CisJCQlicmVhazsKKwkJ Y2FzZSAnICc6CisJCWNhc2UgJ1x0JzoKKwkJCS8qIGlnbm9yZWQgKi8KKwkJCWJyZWFrOworCQlk ZWZhdWx0OgorCQkJcHJfd2FybigiVW5yZWNvZ25pemVkIHR5cGUuXG4iKTsKKwkJfQorCisJCWl0 Kys7CisJCXN1bSArPSByZXQ7CisJfQorCisJdmFfZW5kKGFwKTsKKworCXJldHVybiBzdW07CisK KyBlcnI6CisJcHJfZXJyKCJUb2tlbiBmYWlsZWQgdG8gYmUgYWRkZWQuXG4iKTsKKwlyZXR1cm4g cmV0OworfQorCitzdGF0aWMgdm9pZCBzZXRfY29tSUQoc3RydWN0IG9wYWxfY21kICpjbWQsIHUx NiBjb21JRCkKK3sKKwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkciA9IChzdHJ1Y3Qgb3BhbF9oZWFk ZXIgKiljbWQtPmNtZDsKKworCWhkci0+Y3AuZXh0ZW5kZWRDb21JRFswXSA9IGNvbUlEID4+IDg7 CisJaGRyLT5jcC5leHRlbmRlZENvbUlEWzFdID0gY29tSUQ7CisJaGRyLT5jcC5leHRlbmRlZENv bUlEWzJdID0gMDsKKwloZHItPmNwLmV4dGVuZGVkQ29tSURbM10gPSAwOworfQorCitzdGF0aWMg aW50IGNtZF9maW5hbGl6ZShzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCwgdTMyIGhzbiwgdTMyIHRzbikK K3sKKwlzdHJ1Y3Qgb3BhbF9oZWFkZXIgKmhkcjsKKwlpbnQgcmV0OworCisJcmV0ID0gdGVzdF9h bmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjZjIiwKKwkJCQkgICAgT1BBTF9FTkRPRkRBVEEsIE9QQUxf U1RBUlRMSVNULAorCQkJCSAgICAwLCAwLCAwLCBPUEFMX0VORExJU1QpOworCisJaWYgKHJldCA8 IDApIHsKKwkJcHJfZXJyKCJFcnJvciBmaW5hbGl6aW5nIGNvbW1hbmQuXG4iKTsKKwkJcmV0dXJu IC1FRkFVTFQ7CisJfQorCisJaGRyID0gKHN0cnVjdCBvcGFsX2hlYWRlciAqKSBjbWQtPmNtZDsK KworCWhkci0+cGt0LlRTTiA9IGNwdV90b19iZTMyKHRzbik7CisJaGRyLT5wa3QuSFNOID0gY3B1 X3RvX2JlMzIoaHNuKTsKKworCWhkci0+c3VicGt0Lmxlbmd0aCA9IGNwdV90b19iZTMyKGNtZC0+ cG9zIC0gc2l6ZW9mKCpoZHIpKTsKKwl3aGlsZSAoY21kLT5wb3MgJSA0KSB7CisJCWlmIChjbWQt PnBvcyA+PSBJT19CVUZGRVJfTEVOR1RIKSB7CisJCQlwcl9lcnIoIkVycm9yOiBCdWZmZXIgb3Zl cnJ1blxuIik7CisJCQlyZXR1cm4gLUVSQU5HRTsKKwkJfQorCQljbWQtPmNtZFtjbWQtPnBvcysr XSA9IDA7CisJfQorCWhkci0+cGt0Lmxlbmd0aCA9IGNwdV90b19iZTMyKGNtZC0+cG9zIC0gc2l6 ZW9mKGhkci0+Y3ApIC0KKwkJCQkgICAgICBzaXplb2YoaGRyLT5wa3QpKTsKKwloZHItPmNwLmxl bmd0aCA9IGNwdV90b19iZTMyKGNtZC0+cG9zIC0gc2l6ZW9mKGhkci0+Y3ApKTsKKworCXJldHVy biAwOworfQorCitzdGF0aWMgZW51bSBPUEFMX1JFU1BPTlNFX1RPS0VOIHRva2VuX3R5cGUoY29u c3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAorCQkJCQkgICBpbnQgbikKK3sKKwljb25zdCBz dHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rOworCisJaWYgKG4gPj0gcmVzcC0+bnVtKSB7CisJCXBy X2VycigiVG9rZW4gbnVtYmVyIGRvZXNuJ3QgZXhpc3Q6ICVkLCByZXNwOiAlZFxuIiwKKwkJICAg ICAgIG4sIHJlc3AtPm51bSk7CisJCXJldHVybiBPUEFMX0RUQV9UT0tFTklEX0lOVkFMSUQ7CisJ fQorCisJdG9rID0gJnJlc3AtPnRva3Nbbl07CisJaWYgKHRvay0+bGVuID09IDApIHsKKwkJcHJf ZXJyKCJUb2tlbiBsZW5ndGggbXVzdCBiZSBub24temVyb1xuIik7CisJCXJldHVybiBPUEFMX0RU QV9UT0tFTklEX0lOVkFMSUQ7CisJfQorCisJcmV0dXJuIHRvay0+dHlwZTsKK30KKworLyoKKyAq IFRoaXMgZnVuY3Rpb24gcmV0dXJucyAwIGluIGNhc2Ugb2YgaW52YWxpZCB0b2tlbi4gT25lIHNo b3VsZCBjYWxsCisgKiB0b2tlbl90eXBlKCkgZmlyc3QgdG8gZmluZCBvdXQgaWYgdGhlIHRva2Vu IGlzIHZhbGlkIG9yIG5vdC4KKyAqLworc3RhdGljIGVudW0gT1BBTF9UT0tFTiByZXNwb25zZV9n ZXRfdG9rZW4oY29uc3Qgc3RydWN0IHBhcnNlZF9yZXNwICpyZXNwLAorCQkJCQkgIGludCBuKQor eworCWNvbnN0IHN0cnVjdCBvcGFsX3Jlc3BfdG9rICp0b2s7CisKKwlpZiAobiA+PSByZXNwLT5u dW0pIHsKKwkJcHJfZXJyKCJUb2tlbiBudW1iZXIgZG9lc24ndCBleGlzdDogJWQsIHJlc3A6ICVk XG4iLAorCQkgICAgICAgbiwgcmVzcC0+bnVtKTsKKwkJcmV0dXJuIDA7CisJfQorCisJdG9rID0g JnJlc3AtPnRva3Nbbl07CisJaWYgKHRvay0+bGVuID09IDApIHsKKwkJcHJfZXJyKCJUb2tlbiBs ZW5ndGggbXVzdCBiZSBub24temVyb1xuIik7CisJCXJldHVybiAwOworCX0KKworCXJldHVybiB0 b2stPnBvc1swXTsKK30KKworc3RhdGljIHNpemVfdCByZXNwb25zZV9wYXJzZV90aW55KHN0cnVj dCBvcGFsX3Jlc3BfdG9rICp0b2ssCisJCQkJICBjb25zdCB1OCAqcG9zKQoreworCXRvay0+cG9z ID0gcG9zOworCXRvay0+bGVuID0gMTsKKwl0b2stPndpZHRoID0gT1BBTF9XSURUSF9USU5ZOwor CisJaWYgKHBvc1swXSAmIFRJTllfQVRPTV9TSUdORUQpIHsKKwkJdG9rLT50eXBlID0gT1BBTF9E VEFfVE9LRU5JRF9TSU5UOworCX0gZWxzZSB7CisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VO SURfVUlOVDsKKwkJdG9rLT5zdG9yZWQudSA9IHBvc1swXSAmIDB4M2Y7CisJfQorCisJcmV0dXJu IHRvay0+bGVuOworfQorCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3BhcnNlX3Nob3J0KHN0cnVj dCBvcGFsX3Jlc3BfdG9rICp0b2ssCisJCQkJICAgY29uc3QgdTggKnBvcykKK3sKKwl0b2stPnBv cyA9IHBvczsKKwl0b2stPmxlbiA9IChwb3NbMF0gJiBTSE9SVF9BVE9NX0xFTl9NQVNLKSArIDE7 CisJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhfU0hPUlQ7CisKKwlpZiAocG9zWzBdICYgU0hPUlRf QVRPTV9CWVRFU1RSSU5HKSB7CisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNU UklORzsKKwl9IGVsc2UgaWYgKHBvc1swXSAmIFNIT1JUX0FUT01fU0lHTkVEKSB7CisJCXRvay0+ dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfU0lOVDsKKwl9IGVsc2UgeworCQl1NjQgdV9pbnRlZ2Vy ID0gMDsKKwkJaW50IGksIGIgPSAwOworCisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURf VUlOVDsKKwkJaWYgKHRvay0+bGVuID4gOSkgeworCQkJcHJfd2FybigidWludDY0IHdpdGggbW9y ZSB0aGFuIDggYnl0ZXNcbiIpOworCQkJcmV0dXJuIC1FSU5WQUw7CisJCX0KKwkJZm9yIChpID0g dG9rLT5sZW4gLSAxOyBpID4gMDsgaS0tKSB7CisJCQl1X2ludGVnZXIgfD0gKCh1NjQpcG9zW2ld IDw8ICg4ICogYikpOworCQkJYisrOworCQl9CisJCXRvay0+c3RvcmVkLnUgPSB1X2ludGVnZXI7 CisJfQorCisJcmV0dXJuIHRvay0+bGVuOworfQorCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3Bh cnNlX21lZGl1bShzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9rLAorCQkJCSAgICBjb25zdCB1OCAq cG9zKQoreworCXRvay0+cG9zID0gcG9zOworCXRvay0+bGVuID0gKCgocG9zWzBdICYgTUVESVVN X0FUT01fTEVOX01BU0spIDw8IDgpIHwgcG9zWzFdKSArIDI7CisJdG9rLT53aWR0aCA9IE9QQUxf V0lEVEhfTUVESVVNOworCisJaWYgKHBvc1swXSAmIE1FRElVTV9BVE9NX0JZVEVTVFJJTkcpCisJ CXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfQllURVNUUklORzsKKwllbHNlIGlmIChwb3Nb MF0gJiBNRURJVU1fQVRPTV9TSUdORUQpCisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURf U0lOVDsKKwllbHNlCisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKKworCXJl dHVybiB0b2stPmxlbjsKK30KKworI2RlZmluZSBMT05HX0FUT01fSUQgKEJJVCg3KSB8IEJJVCg2 KSB8IEJJVCg1KSkKKyNkZWZpbmUgTE9OR19BVE9NX0JZVEVTVFJJTkcgQklUKDEpCisjZGVmaW5l IExPTkdfQVRPTV9TSUdORUQgQklUKDApCitzdGF0aWMgc2l6ZV90IHJlc3BvbnNlX3BhcnNlX2xv bmcoc3RydWN0IG9wYWxfcmVzcF90b2sgKnRvaywKKwkJCQkgIGNvbnN0IHU4ICpwb3MpCit7CisJ dG9rLT5wb3MgPSBwb3M7CisJdG9rLT5sZW4gPSAoKHBvc1sxXSA8PCAxNikgfCAocG9zWzJdIDw8 IDgpIHwgcG9zWzNdKSArIDQ7CisJdG9rLT53aWR0aCA9IE9QQUxfV0lEVEhfTE9ORzsKKworCWlm IChwb3NbMF0gJiBMT05HX0FUT01fQllURVNUUklORykKKwkJdG9rLT50eXBlID0gT1BBTF9EVEFf VE9LRU5JRF9CWVRFU1RSSU5HOworCWVsc2UgaWYgKHBvc1swXSAmIExPTkdfQVRPTV9TSUdORUQp CisJCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfU0lOVDsKKwllbHNlCisJCXRvay0+dHlw ZSA9IE9QQUxfRFRBX1RPS0VOSURfVUlOVDsKKworCXJldHVybiB0b2stPmxlbjsKK30KKworc3Rh dGljIHNpemVfdCByZXNwb25zZV9wYXJzZV90b2tlbihzdHJ1Y3Qgb3BhbF9yZXNwX3RvayAqdG9r LAorCQkJCSAgIGNvbnN0IHU4ICpwb3MpCit7CisJdG9rLT5wb3MgPSBwb3M7CisJdG9rLT5sZW4g PSAxOworCXRvay0+dHlwZSA9IE9QQUxfRFRBX1RPS0VOSURfVE9LRU47CisJdG9rLT53aWR0aCA9 IE9QQUxfV0lEVEhfVE9LRU47CisKKwlyZXR1cm4gdG9rLT5sZW47Cit9CisKK3N0YXRpYyBpbnQg cmVzcG9uc2VfcGFyc2UoY29uc3QgdTggKmJ1Ziwgc2l6ZV90IGxlbmd0aCwKKwkJCSAgc3RydWN0 IHBhcnNlZF9yZXNwICpyZXNwKQoreworCWNvbnN0IHN0cnVjdCBvcGFsX2hlYWRlciAqaGRyOwor CXN0cnVjdCBvcGFsX3Jlc3BfdG9rICppdGVyOworCWludCByZXQsIG51bV9lbnRyaWVzID0gMDsK Kwl1MzIgY3BvcyA9IDAsIHRvdGFsOworCXNpemVfdCB0b2tlbl9sZW5ndGg7CisJY29uc3QgdTgg KnBvczsKKworCWlmICghYnVmKQorCQlyZXR1cm4gLUVGQVVMVDsKKworCWlmICghcmVzcCkKKwkJ cmV0dXJuIC1FRkFVTFQ7CisKKwloZHIgPSAoc3RydWN0IG9wYWxfaGVhZGVyICopYnVmOworCXBv cyA9IGJ1ZjsKKwlwb3MgKz0gc2l6ZW9mKCpoZHIpOworCisJcHJfZGVidWcoIlJlc3BvbnNlIHNp emU6IGNwOiAlZCwgcGt0OiAlZCwgc3VicGt0OiAlZFxuIiwKKwkJIGJlMzJfdG9fY3B1KGhkci0+ Y3AubGVuZ3RoKSwKKwkJIGJlMzJfdG9fY3B1KGhkci0+cGt0Lmxlbmd0aCksCisJCSBiZTMyX3Rv X2NwdShoZHItPnN1YnBrdC5sZW5ndGgpKTsKKworCWlmICgoaGRyLT5jcC5sZW5ndGggPT0gMCkK KwkgICAgfHwgKGhkci0+cGt0Lmxlbmd0aCA9PSAwKQorCSAgICB8fCAoaGRyLT5zdWJwa3QubGVu Z3RoID09IDApKSB7CisJCXByX2VycigiQmFkIGhlYWRlciBsZW5ndGguIGNwOiAlZCwgcGt0OiAl ZCwgc3VicGt0OiAlZFxuIiwKKwkJICAgICAgIGJlMzJfdG9fY3B1KGhkci0+Y3AubGVuZ3RoKSwK KwkJICAgICAgIGJlMzJfdG9fY3B1KGhkci0+cGt0Lmxlbmd0aCksCisJCSAgICAgICBiZTMyX3Rv X2NwdShoZHItPnN1YnBrdC5sZW5ndGgpKTsKKwkJcHJpbnRfYnVmZmVyKHBvcywgc2l6ZW9mKCpo ZHIpKTsKKwkJcmV0ID0gLUVJTlZBTDsKKwkJZ290byBlcnI7CisJfQorCisJaWYgKHBvcyA+IGJ1 ZiArIGxlbmd0aCkgeworCQlyZXQgPSAtRUZBVUxUOworCQlnb3RvIGVycjsKKwl9CisKKwlpdGVy ID0gcmVzcC0+dG9rczsKKwl0b3RhbCA9IGJlMzJfdG9fY3B1KGhkci0+c3VicGt0Lmxlbmd0aCk7 CisJcHJpbnRfYnVmZmVyKHBvcywgdG90YWwpOworCXdoaWxlIChjcG9zIDwgdG90YWwpIHsKKwkJ aWYgKCEocG9zWzBdICYgMHg4MCkpIC8qIHRpbnkgYXRvbSAqLworCQkJdG9rZW5fbGVuZ3RoID0g cmVzcG9uc2VfcGFyc2VfdGlueShpdGVyLCBwb3MpOworCQllbHNlIGlmICghKHBvc1swXSAmIDB4 NDApKSAvKiBzaG9ydCBhdG9tICovCisJCQl0b2tlbl9sZW5ndGggPSByZXNwb25zZV9wYXJzZV9z aG9ydChpdGVyLCBwb3MpOworCQllbHNlIGlmICghKHBvc1swXSAmIDB4MjApKSAvKiBtZWRpdW0g YXRvbSAqLworCQkJdG9rZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfbWVkaXVtKGl0ZXIsIHBv cyk7CisJCWVsc2UgaWYgKCEocG9zWzBdICYgMHgxMCkpIC8qIGxvbmcgYXRvbSAqLworCQkJdG9r ZW5fbGVuZ3RoID0gcmVzcG9uc2VfcGFyc2VfbG9uZyhpdGVyLCBwb3MpOworCQllbHNlIC8qIFRP S0VOICovCisJCQl0b2tlbl9sZW5ndGggPSByZXNwb25zZV9wYXJzZV90b2tlbihpdGVyLCBwb3Mp OworCisJCWlmICh0b2tlbl9sZW5ndGggPT0gLUVJTlZBTCkgeworCQkJcmV0ID0gLUVJTlZBTDsK KwkJCWdvdG8gZXJyOworCQl9CisKKwkJcG9zICs9IHRva2VuX2xlbmd0aDsKKwkJY3BvcyArPSB0 b2tlbl9sZW5ndGg7CisJCWl0ZXIrKzsKKwkJbnVtX2VudHJpZXMrKzsKKwl9CisKKwlpZiAobnVt X2VudHJpZXMgPT0gMCkgeworCQlwcl9lcnIoIkNvdWxkbid0IHBhcnNlIHJlc3BvbnNlLlxuIik7 CisJCXJldCA9IC1FSU5WQUw7CisJCWdvdG8gZXJyOworCX0KKwlyZXNwLT5udW0gPSBudW1fZW50 cmllczsKKworCXJldHVybiAwOworZXJyOgorCXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBzaXpl X3QgcmVzcG9uc2VfZ2V0X3N0cmluZyhjb25zdCBzdHJ1Y3QgcGFyc2VkX3Jlc3AgKnJlc3AsIGlu dCBuLAorCQkJCSAgY29uc3QgY2hhciAqKnN0b3JlKQoreworCSpzdG9yZSA9IE5VTEw7CisJaWYg KCFyZXNwKSB7CisJCXByX2VycigiUmVzcG9uc2UgaXMgTlVMTFxuIik7CisJCXJldHVybiAwOwor CX0KKworCWlmIChuID4gcmVzcC0+bnVtKSB7CisJCXByX2VycigiUmVzcG9uc2UgaGFzICVkIHRv a2Vucy4gQ2FuJ3QgYWNjZXNzICVkXG4iLAorCQkgICAgICAgcmVzcC0+bnVtLCBuKTsKKwkJcmV0 dXJuIDA7CisJfQorCisJaWYgKHJlc3AtPnRva3Nbbl0udHlwZSAhPSBPUEFMX0RUQV9UT0tFTklE X0JZVEVTVFJJTkcpIHsKKwkJcHJfZXJyKCJUb2tlbiBpcyBub3QgYSBieXRlIHN0cmluZyFcbiIp OworCQlyZXR1cm4gMDsKKwl9CisKKwkqc3RvcmUgPSByZXNwLT50b2tzW25dLnBvcyArIDE7CisJ cmV0dXJuIHJlc3AtPnRva3Nbbl0ubGVuIC0gMTsKK30KKworc3RhdGljIHU2NCByZXNwb25zZV9n ZXRfdTY0KGNvbnN0IHN0cnVjdCBwYXJzZWRfcmVzcCAqcmVzcCwgaW50IG4pCit7CisJaWYgKCFy ZXNwKSB7CisJCXByX2VycigiUmVzcG9uc2UgaXMgTlVMTFxuIik7CisJCXJldHVybiAwOworCX0K KworCWlmIChuID4gcmVzcC0+bnVtKSB7CisJCXByX2VycigiUmVzcG9uc2UgaGFzICVkIHRva2Vu cy4gQ2FuJ3QgYWNjZXNzICVkXG4iLAorCQkgICAgICAgcmVzcC0+bnVtLCBuKTsKKwkJcmV0dXJu IDA7CisJfQorCisJaWYgKHJlc3AtPnRva3Nbbl0udHlwZSAhPSBPUEFMX0RUQV9UT0tFTklEX1VJ TlQpIHsKKwkJcHJfZXJyKCJUb2tlbiBpcyBub3QgdW5zaWduZWQgaXQ6ICVkXG4iLAorCQkgICAg ICAgcmVzcC0+dG9rc1tuXS50eXBlKTsKKwkJcmV0dXJuIDA7CisJfQorCisJaWYgKCEoKHJlc3At PnRva3Nbbl0ud2lkdGggPT0gT1BBTF9XSURUSF9USU5ZKSB8fAorCSAgICAgIChyZXNwLT50b2tz W25dLndpZHRoID09IE9QQUxfV0lEVEhfU0hPUlQpKSkgeworCQlwcl9lcnIoIkF0b20gaXMgbm90 IHNob3J0IG9yIHRpbnk6ICVkXG4iLAorCQkgICAgICAgcmVzcC0+dG9rc1tuXS53aWR0aCk7CisJ CXJldHVybiAwOworCX0KKworCXJldHVybiByZXNwLT50b2tzW25dLnN0b3JlZC51OworfQorCitz dGF0aWMgdTggcmVzcG9uc2Vfc3RhdHVzKGNvbnN0IHN0cnVjdCBwYXJzZWRfcmVzcCAqcmVzcCkK K3sKKwlpZiAoKHRva2VuX3R5cGUocmVzcCwgMCkgPT0gT1BBTF9EVEFfVE9LRU5JRF9UT0tFTikK KwkgICAgJiYgKHJlc3BvbnNlX2dldF90b2tlbihyZXNwLCAwKSA9PSBPUEFMX0VORE9GU0VTU0lP TikpIHsKKwkJcmV0dXJuIDA7CisJfQorCisJaWYgKHJlc3AtPm51bSA8IDUpCisJCXJldHVybiBE VEFFUlJPUl9OT19NRVRIT0RfU1RBVFVTOworCisJaWYgKCh0b2tlbl90eXBlKHJlc3AsIHJlc3At Pm51bSAtIDEpICE9IE9QQUxfRFRBX1RPS0VOSURfVE9LRU4pIHx8CisJICAgICh0b2tlbl90eXBl KHJlc3AsIHJlc3AtPm51bSAtIDUpICE9IE9QQUxfRFRBX1RPS0VOSURfVE9LRU4pIHx8CisJICAg IChyZXNwb25zZV9nZXRfdG9rZW4ocmVzcCwgcmVzcC0+bnVtIC0gMSkgIT0gT1BBTF9FTkRMSVNU KSB8fAorCSAgICAocmVzcG9uc2VfZ2V0X3Rva2VuKHJlc3AsIHJlc3AtPm51bSAtIDUpICE9IE9Q QUxfU1RBUlRMSVNUKSkKKwkJcmV0dXJuIERUQUVSUk9SX05PX01FVEhPRF9TVEFUVVM7CisKKwly ZXR1cm4gcmVzcG9uc2VfZ2V0X3U2NChyZXNwLCByZXNwLT5udW0gLSA0KTsKK30KKworLyogUGFy c2VzIGFuZCBjaGVja3MgZm9yIGVycm9ycyAqLworc3RhdGljIGludCBwYXJzZV9hbmRfY2hlY2tf c3RhdHVzKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXN0cnVjdCBvcGFsX2NtZCAqY21kOwor CWludCBlcnJvcjsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwlwcmludF9idWZmZXIoY21kLT5jbWQs IGNtZC0+cG9zKTsKKworCWVycm9yID0gcmVzcG9uc2VfcGFyc2UoY21kLT5yZXNwLCBJT19CVUZG RVJfTEVOR1RILCAmZGV2LT5wYXJzZWQpOworCWlmIChlcnJvcikgeworCQlwcl9lcnIoIiVzOiBD b3VsZG4ndCBwYXJzZSByZXNwb25zZS5cbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJZ290byBlcnJf cmV0dXJuOworCX0KKworCWVycm9yID0gcmVzcG9uc2Vfc3RhdHVzKCZkZXYtPnBhcnNlZCk7CisJ aWYgKGVycm9yKQorCQlwcl9lcnIoIiVzOiBSZXNwb25zZSBTdGF0dXM6ICVkXG4iLCBkZXYtPmRp c2tfbmFtZSwKKwkJICAgICAgIGVycm9yKTsKKworIGVycl9yZXR1cm46CisJcmV0dXJuIGVycm9y OworfQorCitzdGF0aWMgdm9pZCBjbGVhcl9vcGFsX2NtZChzdHJ1Y3Qgb3BhbF9jbWQgKmNtZCkK K3sKKwljbWQtPnBvcyA9IHNpemVvZihzdHJ1Y3Qgb3BhbF9oZWFkZXIpOworCW1lbXNldChjbWQt PmNtZCwgMCwgSU9fQlVGRkVSX0xFTkdUSCk7CisJY21kLT5jYiA9IE5VTEw7CisJY21kLT5jYl9k YXRhID0gTlVMTDsKK30KKworc3RhdGljIGludCBzdGFydF9vcGFsX3Nlc3Npb25fY29udCh2b2lk ICpkYXRhKQoreworCXN0cnVjdCBvcGFsX2RldiAqZGV2ID0gZGF0YTsKKwl1MzIgSFNOLCBUU047 CisJaW50IGVycm9yID0gMDsKKworCWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYp OworCWlmIChlcnJvcikKKwkJZ290byBlcnJfcmV0dXJuOworCisJSFNOID0gcmVzcG9uc2VfZ2V0 X3U2NCgmZGV2LT5wYXJzZWQsIDQpOworCVRTTiA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFy c2VkLCA1KTsKKworCWlmIChIU04gPT0gMCAmJiBUU04gPT0gMCkgeworCQlwcl9lcnIoIiVzOiBD b3VsZG4ndCBhdXRoZW50aWNhdGUgc2Vzc2lvblxuIiwgZGV2LT5kaXNrX25hbWUpOworCQllcnJv ciA9IC1FUEVSTTsKKwkJZ290byBlcnJfcmV0dXJuOworCX0KKworCWRldi0+SFNOID0gSFNOOwor CWRldi0+VFNOID0gVFNOOworCitlcnJfcmV0dXJuOgorCXJldHVybiBlcnJvcjsKK30KKworc3Ry dWN0IGtleSAqcmVxdWVzdF91c2VyX2tleShjb25zdCBjaGFyICptYXN0ZXJfZGVzYywgY29uc3Qg dTggKiptYXN0ZXJfa2V5LAorCQkJICAgICBzaXplX3QgKm1hc3Rlcl9rZXlsZW4pCit7CisJY29u c3Qgc3RydWN0IHVzZXJfa2V5X3BheWxvYWQgKnVwYXlsb2FkOworCXN0cnVjdCBrZXkgKnVrZXk7 CisKKwl1a2V5ID0gcmVxdWVzdF9rZXkoJmtleV90eXBlX3VzZXIsIG1hc3Rlcl9kZXNjLCBOVUxM KTsKKwlpZiAoSVNfRVJSKHVrZXkpKQorCQlnb3RvIGVycm9yOworCisJZG93bl9yZWFkKCZ1a2V5 LT5zZW0pOworCXVwYXlsb2FkID0gdXNlcl9rZXlfcGF5bG9hZCh1a2V5KTsKKwkqbWFzdGVyX2tl eSA9IHVwYXlsb2FkLT5kYXRhOworCSptYXN0ZXJfa2V5bGVuID0gdXBheWxvYWQtPmRhdGFsZW47 CitlcnJvcjoKKwlyZXR1cm4gdWtleTsKK30KKworc3RhdGljIGludCBnZXRfb3BhbF9rZXkoc3Ry dWN0IG9wYWxfZGV2ICpkZXYpCit7CisJc3RydWN0IGtleSAqdWtleSA9IE5VTEw7CisJY29uc3Qg dTggKnRtcGtleSA9IE5VTEw7CisJc2l6ZV90IHRtcGxlbjsKKwlpbnQgcmV0ID0gMDsKKworCWlm IChkZXYtPmtleV90eXBlID09IE9QQUxfS0VZX1BMQUlOKSB7CisJCXRtcGtleSA9IGRldi0+a2V5 X25hbWU7CisJCXRtcGxlbiA9IGRldi0+a2V5X25hbWVfbGVuOworCX0gZWxzZSBpZiAoZGV2LT5r ZXlfdHlwZSA9PSBPUEFMX0tFWV9LRVlSSU5HKSB7CisJCXVrZXkgPSByZXF1ZXN0X3VzZXJfa2V5 KGRldi0+a2V5X25hbWUsICZ0bXBrZXksICZ0bXBsZW4pOworCQlpZiAoSVNfRVJSKHVrZXkpKSB7 CisJCQlwcl9lcnIoIiVzOiBDYW4ndCByZXRyaWV2ZSBrZXk6ICVsZFxuIiwgZGV2LT5kaXNrX25h bWUsCisJCQkgICAgICAgUFRSX0VSUih1a2V5KSk7CisJCQlyZXR1cm4gUFRSX0VSUih1a2V5KTsK KwkJfQorCX0gZWxzZSB7CisJCXByX2VycigiUmVxdWVzdGVkIGludmFsaWQga2V5IHR5cGU6ICVk XG4iLCBkZXYtPmtleV90eXBlKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCisJaWYgKHRtcGxl biA+IE9QQUxfS0VZX01BWCkgeworCQlwcl9lcnIoIlJlcXVlc3RlZCBrZXkgd2l0aCBpbnZhbGlk IHNpemU6ICV6ZFxuIiwgdG1wbGVuKTsKKwkJcmV0ID0gLUVJTlZBTDsKKwkJZ290byBlcnJfZXhp dDsKKwl9CisKKwlkZXYtPmtleV9sZW4gPSB0bXBsZW47CisJaWYgKCFtZW1jcHkoZGV2LT5rZXks IHRtcGtleSwgdG1wbGVuKSkgeworCQlwcl9lcnIoIkVycm9yIHdoZW4gY29weWluZyBrZXkiKTsK KwkJcmV0ID0gLUVGQVVMVDsKKwkJZ290byBlcnJfZXhpdDsKKwl9CisKK2Vycl9leGl0OgorCWtl eV9wdXQodWtleSk7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQgY2xlYW5fb3BhbF9r ZXkoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJbWVtc2V0KGRldi0+a2V5LCAwLCBPUEFMX0tF WV9NQVgpOworCWRldi0+a2V5X2xlbiA9IDA7Cit9CisKK3N0YXRpYyBpbmxpbmUgdm9pZCBjbGVh bl9mdW5jdGlvbl9kYXRhKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCWRldi0+ZnVuY19kYXRh ID0gTlVMTDsKKwlkZXYtPm51bV9mdW5jX2RhdGEgPSAwOworfQorCisvKiBUaGlzIGlzIGEgZ2Vu ZXJpYyBjb250aW51YXRpb24uCisgKiBXZSB1c2UgdGhpcyB3aGVuIHdlIGRvbid0IGNhcmUgYWJv dXQgdGhlIHJlc3BvbnNlIGRhdGEKKyAqIGFuZCBzaW1wbHkgd2FudCB0byBjaGVjayB0aGUgc3Rh dHVzIGFuZCBjb250aW51ZS4KKyAqLworc3RhdGljIGludCBnZW5lcmljX2NvbnQodm9pZCAqZGF0 YSkKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisKKwlyZXR1cm4gcGFyc2VfYW5k X2NoZWNrX3N0YXR1cyhkZXYpOworfQorCitzdGF0aWMgaW50IGVuZF9zZXNzaW9uX2NvbnQodm9p ZCAqZGF0YSkKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisKKwlkZXYtPkhTTiA9 IDA7CisJZGV2LT5UU04gPSAwOworCXJldHVybiBnZW5lcmljX2NvbnQoZGF0YSk7Cit9CisKK3N0 YXRpYyBpbnQgZmluYWxpemVfYW5kX3NlbmQoc3RydWN0IG9wYWxfZGV2ICpkZXYsIHN0cnVjdCBv cGFsX2NtZCAqY21kLAorCQkJICAgICBjb250X2ZuIGNvbnQpCit7CisJaW50IHJldDsKKworCXJl dCA9IGNtZF9maW5hbGl6ZShjbWQsIGRldi0+SFNOLCBkZXYtPlRTTik7CisJaWYgKHJldCkgewor CQlwcl9lcnIoIiVzOiBFcnJvciBmaW5hbGl6aW5nIGNvbW1hbmQgYnVmZmVyOiAlZFxuIiwKKwkJ ICAgICAgIGRldi0+ZGlza19uYW1lLCByZXQpOworCQlyZXR1cm4gcmV0OworCX0KKworCXByaW50 X2J1ZmZlcihjbWQtPmNtZCwgY21kLT5wb3MpOworCisJcmV0dXJuIG9wYWxfc2VuZF9yZWN2KGRl diwgY29udCk7Cit9CisKK3N0YXRpYyBpbnQgZ2VuX2tleShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikK K3sKKwljb25zdCB1OCAqbWV0aG9kOworCXU4IHVpZFtPUEFMX1VJRF9MRU5HVEhdOworCXN0cnVj dCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJf b3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCW1lbWNweSh1 aWQsIGRldi0+cHJldl9kYXRhLCBtaW4oc2l6ZW9mKHVpZCksIGRldi0+cHJldl9kX2xlbikpOwor CW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRU5LRVldOworCWtmcmVlKGRldi0+cHJldl9kYXRh KTsKKwlkZXYtPnByZXZfZGF0YSA9IE5VTEw7CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5f dmEoY21kLCAiYzJzIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICB1aWQsIE9QQUxf VUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkg ICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisJaWYgKHJldCA8IDAp IHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgZ2VuIGtleSBjb21tYW5kXG4iLAorCQkg ICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5h bGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBn ZXRfYWN0aXZlX2tleV9jb250KHZvaWQgKmRhdGEpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYg PSBkYXRhOworCWNvbnN0IGNoYXIgKmFjdGl2ZWtleTsKKwlzaXplX3Qga2V5bGVuOworCWludCBl cnJvciA9IDA7CisKKwllcnJvciA9IHBhcnNlX2FuZF9jaGVja19zdGF0dXMoZGV2KTsKKwlpZiAo ZXJyb3IpCisJCWdvdG8gZXJyX3JldHVybjsKKwlrZXlsZW4gPSByZXNwb25zZV9nZXRfc3RyaW5n KCZkZXYtPnBhcnNlZCwgNCwgJmFjdGl2ZWtleSk7CisJaWYgKCFhY3RpdmVrZXkpIHsKKwkJcHJf ZXJyKCIlczogQ291bGRuJ3QgZXh0cmFjdCB0aGUgQWN0aXZla2V5IGZyb20gdGhlIHJlc3BvbnNl XG4iLAorCQkgICAgICAgX19mdW5jX18pOworCQllcnJvciA9IDB4MEE7CisJCWdvdG8gZXJyX3Jl dHVybjsKKwl9CisJZGV2LT5wcmV2X2RhdGEgPSBrbWVtZHVwKGFjdGl2ZWtleSwga2V5bGVuLCBH RlBfS0VSTkVMKTsKKworCWlmICghZGV2LT5wcmV2X2RhdGEpIHsKKwkJZXJyb3IgPSAtRU5PTUVN OworCQlnb3RvIGVycl9yZXR1cm47CisJfQorCisJZGV2LT5wcmV2X2RfbGVuID0ga2V5bGVuOwor CisgZXJyX3JldHVybjoKKwlyZXR1cm4gZXJyb3I7Cit9CisKK3N0YXRpYyBpbnQgZ2V0X2FjdGl2 ZV9rZXkoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3QgdTggKm1ldGhvZDsKKwl1OCB1 aWRbT1BBTF9VSURfTEVOR1RIXTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0Owor CisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNt ZCwgZGV2LT5jb21JRCk7CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfR0VUXTsKKworCXJl dCA9IGJ1aWxkX2xvY2tpbmdfcmFuZ2UodWlkLCBzaXplb2YodWlkKSwgZGV2LT5scik7CisJaWYg KHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwg ZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlyZXQgPSB0ZXN0X2Fu ZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDZjIDRjIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAor CQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhP RF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlRM SVNULAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMs IC8qIHN0YXJ0Q2xvdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzEwLCAvKiBBY3RpdmVL ZXkgKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAor CQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNCwgLyogZW5kQ29sdW1uICovCisJCQkJICAgIE9QQUxf VElOWV9VSU5UXzEwLCAvKiBBY3RpdmVLZXkgKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJ CQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwlpZiAocmV0IDwg MCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBnZXQgYWN0aXZlIGtleSBjb21tYW5k XG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXJl dHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2V0X2FjdGl2ZV9rZXlfY29udCk7Cit9 CisKK3N0YXRpYyBpbmxpbmUgaW50IGVuYWJsZV9nbG9iYWxfbHIoc3RydWN0IG9wYWxfY21kICpj bWQsIHU4ICp1aWQsCisJCQkJICAgc3RydWN0IG9wYWxfdXNlcl9scl9zZXR1cCAqc2V0dXApCit7 CisJY29uc3QgdTggKm1ldGhvZDsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOwor CXJldHVybiB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDRjIDJjdWMgMmN1YyA0YyA0 YyAzYyIsCisJCQkJICAgICBPUEFMX0NBTEwsCisJCQkJICAgICB1aWQsIE9QQUxfVUlEX0xFTkdU SCwKKwkJCQkgICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgICBPUEFM X1NUQVJUTElTVCwKKwkJCQkgICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICAgT1BBTF9WQUxV RVMsCisJCQkJICAgICBPUEFMX1NUQVJUTElTVCwKKworCQkJCSAgICAgT1BBTF9TVEFSVE5BTUUs CisJCQkJICAgICBPUEFMX1RJTllfVUlOVF8wNSwgLyogUmVhZExvY2tFbmFibGVkICovCisJCQkJ ICAgICAhIXNldHVwLT5STEUsCisJCQkJICAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgIE9Q QUxfU1RBUlROQU1FLAorCQkJCSAgICAgT1BBTF9USU5ZX1VJTlRfMDYsIC8qIFdyaXRlTG9ja0Vu YWJsZWQgKi8KKwkJCQkgICAgICEhc2V0dXAtPldMRSwKKwkJCQkgICAgIE9QQUxfRU5ETkFNRSwK KworCQkJCSAgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgICBPUEFMX1JFQURMT0NLRUQsCisJ CQkJICAgICBPUEFMX0ZBTFNFLAorCQkJCSAgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgICBP UEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgIE9QQUxfV1JJVEVMT0NLRUQsCisJCQkJICAgICBPUEFM X0ZBTFNFLAorCQkJCSAgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgICBPUEFMX0VORExJU1Qs CisJCQkJICAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgICBPUEFMX0VORExJU1QpOworfQorCitz dGF0aWMgaW50IHNldHVwX2xvY2tpbmdfcmFuZ2Uoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJ Y29uc3QgdTggKm1ldGhvZDsKKwl1OCB1aWRbT1BBTF9VSURfTEVOR1RIXTsKKwlzdHJ1Y3Qgb3Bh bF9jbWQgKmNtZDsKKwlzdHJ1Y3Qgb3BhbF91c2VyX2xyX3NldHVwICpzZXR1cDsKKwlpbnQgcmV0 OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlE KGNtZCwgZGV2LT5jb21JRCk7CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKKwly ZXQgPSBidWlsZF9sb2NraW5nX3JhbmdlKHVpZCwgc2l6ZW9mKHVpZCksIGRldi0+bHIpOworCWlm IChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIs IGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIC1FSU5WQUw7CisJfQorCXNldHVwID0gZGV2LT5m dW5jX2RhdGFbZGV2LT5zdGF0ZSAtIDFdOworCWlmIChkZXYtPmxyID09IDApCisJCXJldCA9IGVu YWJsZV9nbG9iYWxfbHIoY21kLCB1aWQsIHNldHVwKTsKKwllbHNlCisJCXJldCA9IHRlc3RfYW5k X2FkZF90b2tlbl92YShjbWQsICJjMnMgIDRjIDJjdWMgMmN1YyAyY3VjIDJjdSA0YyIsCisJCQkJ ICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1l dGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJ CSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisJCQkJICAgIE9QQUxf U1RBUlRMSVNULAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllf VUlOVF8wMywgLyogUmFuZ2UgU3RhcnQgKi8KKwkJCQkgICAgc2V0dXAtPnJhbmdlX3N0YXJ0LAor CQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAg IE9QQUxfVElOWV9VSU5UXzA0LCAvKiBSYW5nZSBMZW5ndGggKi8KKwkJCQkgICAgc2V0dXAtPnJh bmdlX2xlbmd0aCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxfU1RBUlRO QU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNSwgLyogUmVhZExvY2tFbmFibGVkICovCisJ CQkJICAgICEhc2V0dXAtPlJMRSwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9Q QUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNiwgLyogV3JpdGVMb2NrRW5h YmxlZCAqLworCQkJCSAgICAhIXNldHVwLT5XTEUsCisKKwkJCQkgICAgT1BBTF9FTkROQU1FLAor CQkJCSAgICBPUEFMX0VORExJU1QsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BB TF9FTkRMSVNUKTsKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGlu ZyBTZXR1cCBMb2NraW5nIHJhbmdlIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25h bWUpOworCQlyZXR1cm4gcmV0OworCisJfQorCisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRl diwgY21kLCBnZW5lcmljX2NvbnQpOworfQorCitzdGF0aWMgaW50IHN0YXJ0X2FkbWluc3Bfb3Bh bF9zZXNzaW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2LAorCQkJCSAgICAgIGVudW0gT1BBTF9VSUQg YXV0aCwKKwkJCQkgICAgICBjb25zdCBjaGFyICprZXksCisJCQkJICAgICAgdTgga2V5X2xlbikK K3sKKwljb25zdCB1OCAqbWV0aG9kLCAqc211aWQsICphZG1pbl9zcCwgKmhzYTsKKwlzdHJ1Y3Qg b3BhbF9jbWQgKmNtZDsKKwl1MzIgSFNOOworCWludCByZXQ7CisKKwlpZiAoa2V5ID09IE5VTEwg JiYgYXV0aCAhPSBPUEFMX0FOWUJPRFlfVUlEKSB7CisJCXByX2VycigiJXM6IEF0dGVtcHRlZCB0 byBvcGVuIEFETUlOX1NQIFNlc3Npb24gd2l0aG91dCBhIEhvc3QiIFwKKwkJICAgICAgICJDaGFs bGVuZ2UsIGFuZCBub3QgYXMgdGhlIEFueWJvZHkgVUlEXG4iLCBfX2Z1bmNfXyk7CisJCXJldHVy biAxOworCX0KKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCisJ c2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisJSFNOID0gR0VORVJJQ19IT1NUX1NFU1NJT05f TlVNOworCisJc211aWQgPSBPUEFMVUlEW09QQUxfU01VSURfVUlEXTsKKwltZXRob2QgPSBPUEFM TUVUSE9EW09QQUxfU1RBUlRTRVNTSU9OXTsKKwlhZG1pbl9zcCA9IE9QQUxVSURbT1BBTF9BRE1J TlNQX1VJRF07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIGN1c2Mi LAorCQkJCSAgICBPUEFMX0NBTEwsCisJCQkJICAgIHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJ CQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCQkJCSAgICBPUEFMX1NUQVJUTElT VCwKKwkJCQkgICAgSFNOLAorCQkJCSAgICBhZG1pbl9zcCwgT1BBTF9VSURfTEVOR1RILAorCQkJ CSAgICBPUEFMX1RJTllfVUlOVF8wMSk7CisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczog RXJyb3IgYnVpbGRpbmcgc3RhcnQgYWRtaW5zcCBzZXNzaW9uIGNvbW1hbmQuXG4iLAorCQkgICAg ICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gcmV0OworCX0KKworCXN3aXRjaCAoYXV0aCkg eworCWNhc2UgT1BBTF9BTllCT0RZX1VJRDoKKwkJLyogbm90aGluZyBsZWZ0IHRvIGRvIGZvciBh bnlib2R5LCBqdXN0IGVuZCBhbmQgZmluYWxpemUgKi8KKwkJcmV0ID0gdGVzdF9hbmRfYWRkX3Rv a2VuX3ZhKGNtZCwgImMiLAorCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwkJYnJlYWs7CisJY2Fz ZSBPUEFMX1NJRF9VSUQ6CisJCWhzYSA9IE9QQUxVSURbT1BBTF9TSURfVUlEXTsKKwkJcmV0ID0g dGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjJjIHMgM2MgcyAyYyIsCisJCQkJCSAgICBPUEFM X1NUQVJUTkFNRSwKKwkJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAwLCAvKiBIb3N0Q2hhbGxlbmdl ICovCisJCQkJCSAgICBrZXksIGtleV9sZW4sCisJCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJ CSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAvKiBIb3N0 U2lnbkF1dGggKi8KKwkJCQkJICAgIGhzYSwgT1BBTF9VSURfTEVOR1RILAorCQkJCQkgICAgT1BB TF9FTkROQU1FLAorCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwkJYnJlYWs7CisJZGVmYXVsdDoK KwkJcHJfZXJyKCJDYW5ub3Qgc3RhcnQgQWRtaW4gU1Agc2Vzc2lvbiB3aXRoIGF1dGggJWRcbiIs IGF1dGgpOworCQlyZXR1cm4gMTsKKwl9CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVz OiBFcnJvciBidWlsZGluZyBzdGFydCBhZG1pbnNwIHNlc3Npb24gY29tbWFuZC5cbiIsCisJCSAg ICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZpbmFs aXplX2FuZF9zZW5kKGRldiwgY21kLCBzdGFydF9vcGFsX3Nlc3Npb25fY29udCk7Cit9CisKK3N0 YXRpYyBpbnQgc3RhcnRfYW55Ym9keUFTUF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpk ZXYpCit7CisJcmV0dXJuIHN0YXJ0X2FkbWluc3Bfb3BhbF9zZXNzaW9uKGRldiwgT1BBTF9BTllC T0RZX1VJRCwgTlVMTCwgMCk7Cit9CisKK3N0YXRpYyBpbnQgc3RhcnRfU0lEQVNQX29wYWxfc2Vz c2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlpbnQgcmV0OworCWNvbnN0IHU4ICprZXkg PSBkZXYtPnByZXZfZGF0YTsKKworCWlmICgha2V5KQorCQlyZXQgPSBzdGFydF9hZG1pbnNwX29w YWxfc2Vzc2lvbihkZXYsIE9QQUxfU0lEX1VJRCwgZGV2LT5rZXksCisJCQkJCQkgZGV2LT5rZXlf bGVuKTsKKwllbHNlIHsKKwkJcmV0ID0gc3RhcnRfYWRtaW5zcF9vcGFsX3Nlc3Npb24oZGV2LCBP UEFMX1NJRF9VSUQsIGtleSwKKwkJCQkJCSBkZXYtPnByZXZfZF9sZW4pOworCQlrZnJlZShrZXkp OworCQlkZXYtPnByZXZfZGF0YSA9IE5VTEw7CisJfQorCXJldHVybiByZXQ7Cit9CisKK3N0YXRp YyBpbnQgc3RhcnRfbG9ja2luZ3NwX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwK KwkJCQkJZW51bSBPUEFMX1VJRCBhdXRoLCBjb25zdCB1OCAqa2V5LAorCQkJCQl1OCBrZXlfbGVu KQoreworCisJY29uc3QgdTggKm1ldGhvZCwgKnNtdWlkLCAqbG9ja2luZ19zcCwgKmhzYTsKKwlz dHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlzaXplX3Qga2xlbiA9IGtleV9sZW47CisJdTMyIEhTTjsK KwlpbnQgcmV0OworCisJaWYgKGtleSA9PSBOVUxMKSB7CisJCXByX2VycigiQ2Fubm90IHN0YXJ0 IExvY2tpbmcgU1Agc2Vzc2lvbiB3aXRob3V0IGEga2V5XG4iKTsKKwkJcmV0dXJuIC1FSU5WQUw7 CisJfQorCisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisKKwlzZXRf Y29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKwlIU04gPSBHRU5FUklDX0hPU1RfU0VTU0lPTl9OVU07 CisKKwlzbXVpZCA9IE9QQUxVSURbT1BBTF9TTVVJRF9VSURdOworCW1ldGhvZCA9IE9QQUxNRVRI T0RbT1BBTF9TVEFSVFNFU1NJT05dOworCWxvY2tpbmdfc3AgPSBPUEFMVUlEW09QQUxfTE9DS0lO R1NQX1VJRF07CisJaHNhID0gT1BBTFVJRFthdXRoXTsKKworCXJldCA9IHRlc3RfYW5kX2FkZF90 b2tlbl92YShjbWQsICJjMnMgY3VzYyAyY3NjIDJjc2MgYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwK KwkJCQkgICAgc211aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01F VEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIEhTTiwKKwkJ CQkgICAgbG9ja2luZ19zcCwgT1BBTF9VSURfTEVOR1RILAorCQkJCSAgICBPUEFMX1RJTllfVUlO VF8wMSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRf MDAsIC8qIEhvc3RDaGFsbGVuZ2UgKi8KKwkJCQkgICAga2V5LCBrbGVuLAorCQkJCSAgICBPUEFM X0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9V SU5UXzAzLCAvKiBIb3N0IFNpZ24gQXV0aG9yaXR5ICovCisJCQkJICAgIGhzYSwgT1BBTF9VSURf TEVOR1RILAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsK KworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIHN0YXJ0IGFk bWluc3Agc2Vzc2lvbiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJ cmV0dXJuIHJldDsKKwl9CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBzdGFy dF9vcGFsX3Nlc3Npb25fY29udCk7Cit9CisKK3N0YXRpYyBpbmxpbmUgaW50IHN0YXJ0X2FkbWlu MUxTUF9vcGFsX3Nlc3Npb24oc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJcmV0dXJuIHN0YXJ0 X2xvY2tpbmdzcF9vcGFsX3Nlc3Npb24oZGV2LCBPUEFMX0FETUlOMV9VSUQsCisJCQkJCSAgICBk ZXYtPmtleSwgZGV2LT5rZXlfbGVuKTsKK30KKworc3RhdGljIGludCBzdGFydF9hdXRoX29wYWxf c2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kLCAqc211 aWQsICpsb2NraW5nX3NwOworCXU4IGxrX3VsX3VzZXJbT1BBTF9VSURfTEVOR1RIXTsKKwlzdHJ1 Y3Qgb3BhbF9jbWQgKmNtZDsKKwl1MzIgSFNOOworCWludCByZXQ7CisJc3RydWN0IG9wYWxfdXNl cl9pbmZvICp1aW5mbzsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQp OworCisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlIU04gPSBHRU5FUklDX0hPU1Rf U0VTU0lPTl9OVU07CisKKwl1aW5mbyA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsK KworCXNtdWlkID0gT1BBTFVJRFtPUEFMX1NNVUlEX1VJRF07CisJbWV0aG9kID0gT1BBTE1FVEhP RFtPUEFMX1NUQVJUU0VTU0lPTl07CisJbG9ja2luZ19zcCA9IE9QQUxVSURbT1BBTF9MT0NLSU5H U1BfVUlEXTsKKworCWlmICh1aW5mby0+U1VNKSB7CisJCXJldCA9IGJ1aWxkX2xvY2tpbmdfdXNl cihsa191bF91c2VyLCBzaXplb2YobGtfdWxfdXNlciksCisJCQkJCSBkZXYtPmxyKTsKKwkJaWYg KHJldCA8IDApIHsKKwkJCXByX2VycigiJXM6IENhbid0IGJ1aWxkIGxvY2tpbmcgdXNlclxuIiwK KwkJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCQlyZXR1cm4gcmV0OworCQl9CisJfSBlbHNl IGlmICh1aW5mby0+d2hvICE9IE9QQUxfQURNSU4xICYmICF1aW5mby0+U1VNKSB7CisJCXJldCA9 IGJ1aWxkX2xvY2tpbmdfdXNlcihsa191bF91c2VyLCBzaXplb2YobGtfdWxfdXNlciksCisJCQkJ CSB1aW5mby0+d2hvIC0gMSk7CisJCWlmIChyZXQgPCAwKSB7CisJCQlwcl9lcnIoIiVzOiBDYW4n dCBidWlsZCBsb2NraW5nIHVzZXJcbiIsCisJCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQkJ cmV0dXJuIHJldDsKKwkJfQorCX0gZWxzZQorCQltZW1jcHkobGtfdWxfdXNlciwgT1BBTFVJRFtP UEFMX0FETUlOMV9VSURdLCBPUEFMX1VJRF9MRU5HVEgpOworCisKKwlyZXQgPSB0ZXN0X2FuZF9h ZGRfdG9rZW5fdmEoY21kLCAiYzJzIGN1czNjczNjIHMgMmMiLAorCQkJCSAgICBPUEFMX0NBTEws CisJCQkJICAgIHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9N RVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBIU04sCisJ CQkJICAgIGxvY2tpbmdfc3AsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgT1BBTF9USU5ZX1VJ TlRfMDEsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8w MCwKKwkJCQkgICAgZGV2LT5rZXksIGRldi0+a2V5X2xlbiwKKwkJCQkgICAgT1BBTF9FTkROQU1F LAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDMsCisK KwkJCQkgICAgbGtfdWxfdXNlciwgT1BBTF9VSURfTEVOR1RILAorCisJCQkJICAgIE9QQUxfRU5E TkFNRSwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlmIChyZXQgPCAwKSB7CisJCXByX2Vy cigiJXM6IEVycm9yIGJ1aWxkaW5nIFNUQVJUU0VTU0lPTiBjb21tYW5kLlxuIiwKKwkJICAgICAg IGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVf YW5kX3NlbmQoZGV2LCBjbWQsIHN0YXJ0X29wYWxfc2Vzc2lvbl9jb250KTsKK30KKworc3RhdGlj IGludCByZXZlcnRfdHBlcihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0 aG9kLCAqc211aWQ7CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJaW50IHJldDsKKworCWNtZCA9 ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCisJc2V0X2NvbUlEKGNtZCwgZGV2 LT5jb21JRCk7CisKKwlzbXVpZCA9IE9QQUxVSURbT1BBTF9BRE1JTlNQX1VJRF07CisJbWV0aG9k ID0gT1BBTE1FVEhPRFtPUEFMX1JFVkVSVF07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5f dmEoY21kLCAiYzJzIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBzbXVpZCwgT1BB TF9VSURfTEVOR1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKwkJCQkg ICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisJaWYgKHJldCA8IDAp IHsKKwkJcHJfZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgUkVWRVJUIFRQRVIgY29tbWFuZC5cbiIs CisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJu IGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQorCitzdGF0aWMg aW50IGludGVybmFsX2FjdGl2YXRlX3VzZXIoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29u c3QgdTggKm1ldGhvZDsKKwl1OCB1aWRbT1BBTF9VSURfTEVOR1RIXTsKKwlzdHJ1Y3Qgb3BhbF9j bWQgKmNtZDsKKwlpbnQgcmV0OworCXN0cnVjdCBvcGFsX2tleV9hbmRfdXNlciAqYWN0OworCisJ Y21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwg ZGV2LT5jb21JRCk7CisKKwlhY3QgPSBkZXYtPmZ1bmNfZGF0YVtkZXYtPnN0YXRlIC0gMV07CisK KwltZW1jcHkodWlkLCBPUEFMVUlEW09QQUxfVVNFUjFfVUlEXSwgT1BBTF9VSURfTEVOR1RIKTsK Kwl1aWRbN10gPSBhY3QtPndoby53aG87CisKKwltZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VU XTsKKworCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnMgM2MgYyA0YyAzYyIs CisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJ ICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNU LAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9USU5ZX1VJTlRfMDEsIC8q IFZhbHVlcyAqLworCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCisJCQkJICAgIE9QQUxfU1RB UlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNSwgLyogRW5hYmxlZCAqLworCQkJCSAg ICBPUEFMX1RJTllfVUlOVF8wMSwgLyogVHJ1ZSAqLworCQkJCSAgICBPUEFMX0VORE5BTUUsCisK KwkJCQkgICAgT1BBTF9FTkRMSVNULAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9Q QUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWls ZGluZyBBY3RpdmF0ZSBVc2VyTiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1l KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBj bWQsIGdlbmVyaWNfY29udCk7Cit9CisKK3N0YXRpYyBpbnQgZXJhc2VfbG9ja2luZ19yYW5nZShz dHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwljb25zdCB1OCAqbWV0aG9kOworCXU4IHVpZFtPUEFM X1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisKKwljbWQg PSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKwlzZXRfY29tSUQoY21kLCBkZXYt PmNvbUlEKTsKKworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9FUkFTRV07CisKKwlpZiAoYnVp bGRfbG9ja2luZ19yYW5nZSh1aWQsIHNpemVvZih1aWQpLCBkZXYtPmxyKSA8IDApIHsKKwkJcHJf ZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOwor CQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21k LCAiYzJzIDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xF TkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BB TF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgewor CQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBFcmFzZSBMb2NraW5nIFJhbmdlIENtbWFuZC5c biIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCXJldHVy biBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19jb250KTsKK30KKworc3RhdGlj IGludCBzZXRfbWJyX2RvbmUoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3QgdTggKm1l dGhvZCwgKnVpZDsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0OworCXU4IG1icl9k b25lX3RmID0gKih1OCAqKWRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKworCWNtZCA9 ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+ Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07CisJdWlkID0gT1BBTFVJ RFtPUEFMX01CUkNPTlRST0xdOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwg ImMycyAzYyA2YyAyYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJ RF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAg IE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9W QUxVRVMsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1F LAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMiwgLyogRG9uZSAqLworCQkJCSAgICBtYnJfZG9u ZV90ZiwgICAgICAgLyogRG9uZSBUIG9yIEYgKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCQkJ CSAgICBPUEFMX0VORExJU1QsCisKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFM X0VORExJU1QpOworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIEJ1aWxkaW5n IHNldCBNQlIgRG9uZSBjb21tYW5kXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQly ZXR1cm4gcmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2Vu ZXJpY19jb250KTsKK30KKworc3RhdGljIGludCBzZXRfbWJyX2VuYWJsZV9kaXNhYmxlKHN0cnVj dCBvcGFsX2RldiAqZGV2KQoreworCWNvbnN0IHU4ICptZXRob2QsICp1aWQ7CisJc3RydWN0IG9w YWxfY21kICpjbWQ7CisJaW50IHJldDsKKwl1OCBtYnJfZW5fZGlzID0gKih1OCAqKWRldi0+ZnVu Y19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFs X2NtZChjbWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BB TE1FVEhPRFtPUEFMX1NFVF07CisJdWlkID0gT1BBTFVJRFtPUEFMX01CUkNPTlRST0xdOworCisJ cmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAzYyA2YyAyYyIsCisJCQkJICAg IE9QQUxfQ0FMTCwKKwkJCQkgICAgdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhv ZCwgT1BBTF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAg ICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9WQUxVRVMsCisKKwkJCQkgICAgT1BBTF9T VEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlO VF8wMSwgLyogRW5hYmxlICovCisJCQkJICAgIG1icl9lbl9kaXMsICAgICAgICAvKiBFbmFibGUg b3IgRGlzYWJsZSAqLworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElT VCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisJaWYg KHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3IgQnVpbGRpbmcgc2V0IE1CUiBkb25lIGNv bW1hbmRcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQor CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQor CitzdGF0aWMgaW50IHNldF9uZXdfcHcoc3RydWN0IG9wYWxfZGV2ICpkZXYpCit7CisJY29uc3Qg dTggKm1ldGhvZDsKKwl1OCBjcGluX3VpZFtPUEFMX1VJRF9MRU5HVEhdOworCXN0cnVjdCBvcGFs X2NtZCAqY21kOworCWludCByZXQ7CisJc3RydWN0IG9wYWxfbmV3X3B3ICpwdzsKKwlzaXplX3Qg a2V5X2xlbjsKKwl1OCAqa2V5OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21k KGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlwdyA9IGRldi0+ZnVuY19k YXRhW2Rldi0+c3RhdGUgLSAxXTsKKwlrZXkgPSBwdy0+bmV3X3Bpbi5rZXk7CisJa2V5X2xlbiA9 IHB3LT5uZXdfcGluLmtleV9sZW47CisJbWVtY3B5KGNwaW5fdWlkLCBPUEFMVUlEW09QQUxfQ19Q SU5fQURNSU4xXSwgT1BBTF9VSURfTEVOR1RIKTsKKworCWlmIChwdy0+dXNlcl9mb3JfcHcgIT0g T1BBTF9BRE1JTjEpIHsKKwkJY3Bpbl91aWRbNV0gPSAweDAzOworCQlpZiAocHctPndoby5TVU0p CisJCQljcGluX3VpZFs3XSA9IHB3LT5uZXdfcGluLmxyICsgMTsKKwkJZWxzZQorCQkJY3Bpbl91 aWRbN10gPSBwdy0+dXNlcl9mb3JfcHc7CisJfQorCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFM X1NFVF07CisKKwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDNjIDNjczJj IDJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBjcGluX3VpZCwgT1BBTF9VSURfTEVO R1RILAorCQkJCSAgICBtZXRob2QsIE9QQUxfTUVUSE9EX0xFTkdUSCwKKworCQkJCSAgICBPUEFM X1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9V SU5UXzAxLCAvKiBWYWx1ZXMgKi8KKworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAg T1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAzLCAvKiBQSU4gKi8KKwkJ CQkgICAga2V5LCBrZXlfbGVuLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxf RU5ETElTVCwKKworCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7 CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBTRVQgQU1J TjEgUElOIGNvbW1hbmQuXG4iLAorCQkgICAgICAgZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4g cmV0OworCX0KKworCXJldHVybiBmaW5hbGl6ZV9hbmRfc2VuZChkZXYsIGNtZCwgZ2VuZXJpY19j b250KTsKK30KKworc3RhdGljIGludCBzZXRfc2lkX2NwaW5fcGluKHN0cnVjdCBvcGFsX2RldiAq ZGV2KQoreworCWNvbnN0IHU4ICptZXRob2QsICpjcGluX3VpZDsKKwlzdHJ1Y3Qgb3BhbF9jbWQg KmNtZDsKKwlpbnQgcmV0OworCisJY21kID0gJmRldi0+Y21kOworCWNsZWFyX29wYWxfY21kKGNt ZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwljcGluX3VpZCA9IE9QQUxVSURb T1BBTF9DX1BJTl9TSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9TRVRdOworCisJcmV0 ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMycyAyYyA0Y3MyYyAyYyIsCisJCQkJICAg IE9QQUxfQ0FMTCwKKwkJCQkgICAgY3Bpbl91aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAg bWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJ CQkJICAgIE9QQUxfU1RBUlROQU1FLAorCisJCQkJICAgIE9QQUxfVElOWV9VSU5UXzAxLCAvKiBW YWx1ZXMgKi8KKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1F LAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElOICovCisJCQkJICAgIGRldi0+a2V5 LCBkZXYtPmtleV9sZW4sCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRM SVNULAorCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwor CWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIFNFVCBDUElOIFBJ TiBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsK Kwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29udCk7 Cit9CisKK3N0YXRpYyBpbnQgcXVlcnlfbG9ja2luZ19yYW5nZV9jb250KHZvaWQgKmRhdGEpCit7 CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBkYXRhOworCWludCBlcnJvcjsKKworCWVycm9yID0g cGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYpOworCWlmIChlcnJvcikKKwkJZ290byBlcnJfcmV0 dXJuOworCisJZGV2LT5zdGFydCA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA0KTsK KwlkZXYtPmxlbmd0aCA9IHJlc3BvbnNlX2dldF91NjQoJmRldi0+cGFyc2VkLCA4KTsKKworZXJy X3JldHVybjoKKwlyZXR1cm4gZXJyb3I7Cit9CisKK3N0YXRpYyBpbnQgcXVlcnlfbG9ja2luZ19y YW5nZShzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwl1OCBscl9idWZmZXJbT1BBTF9VSURfTEVO R1RIXTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwljb25zdCB1OCAqbWV0aG9kOworCWludCBy ZXQ7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsKKworCW1ldGhv ZCA9IE9QQUxNRVRIT0RbT1BBTF9HRVRdOworCisJaWYgKGJ1aWxkX2xvY2tpbmdfcmFuZ2UobHJf YnVmZmVyLCBzaXplb2YobHJfYnVmZmVyKSwgZGV2LT5scikgPCAwKSB7CisJCXByX2VycigiJXM6 IENhbid0IGJ1aWxkIGxvY2tpbmcgcmFuZ2VcbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJu IC1FSU5WQUw7CisJfQorCisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlyZXQgPSB0 ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDEyYyIsCisJCQkJICAgIE9QQUxfQ0FMTCwK KwkJCQkgICAgbHJfYnVmZmVyLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BB TF9NRVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFM X1NUQVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfU1RBUlRD T0xVTU4sCisJCQkJICAgIE9QQUxfUkFOR0VTVEFSVCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAor CQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9FTkRDT0xVTU4sCisJCQkJICAg IE9QQUxfUkFOR0VMRU5HVEgsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9F TkRMSVNULAorCQkJCSAgICBPUEFMX0VORExJU1QpOworCisJaWYgKHJldCA8IDApIHsKKwkJcHJf ZXJyKCIlczogRXJyb3IgYnVpbGRpbmcgR0VUIExvY2tpbmcgUmFuZ2UgY29tbWFuZC5cbiIsCisJ CSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQorCisJcmV0dXJuIGZp bmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBxdWVyeV9sb2NraW5nX3JhbmdlX2NvbnQpOworfQor CitzdGF0aWMgaW50IGFkZF91c2VyX3RvX2xyKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXU4 IGxyX2J1ZmZlcltPUEFMX1VJRF9MRU5HVEhdOworCXU4IHVzZXJfdWlkW09QQUxfVUlEX0xFTkdU SF07CisJc3RydWN0IG9wYWxfY21kICpjbWQ7CisJY29uc3QgdTggKm1ldGhvZDsKKwlzdHJ1Y3Qg b3BhbF9sb2NrX3VubG9jayAqbGt1bDsKKwlpbnQgcmV0OworCisJY21kID0gJmRldi0+Y21kOwor CWNsZWFyX29wYWxfY21kKGNtZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwlt ZXRob2QgPSBPUEFMTUVUSE9EW09QQUxfU0VUXTsKKworCWxrdWwgPSBkZXYtPmZ1bmNfZGF0YVtk ZXYtPnN0YXRlIC0gMV07CisKKwltZW1jcHkobHJfYnVmZmVyLCBPUEFMVUlEW09QQUxfTE9DS0lO R1JBTkdFX0FDRV9SRExPQ0tFRF0sCisJICAgICAgIE9QQUxfVUlEX0xFTkdUSCk7CisKKwlpZiAo bGt1bC0+bF9zdGF0ZSA9PSBPUEFMX1JXKQorCQltZW1jcHkobHJfYnVmZmVyLCBPUEFMVUlEW09Q QUxfTE9DS0lOR1JBTkdFX0FDRV9XUkxPQ0tFRF0sCisJCSAgICAgICBPUEFMX1VJRF9MRU5HVEgp OworCisJbHJfYnVmZmVyWzddID0gZGV2LT5scjsKKworCW1lbWNweSh1c2VyX3VpZCwgT1BBTFVJ RFtPUEFMX1VTRVIxX1VJRF0sIE9QQUxfVUlEX0xFTkdUSCk7CisJdXNlcl91aWRbN10gPSBsa3Vs LT5hdXRob3JpdHkud2hvOworCisJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMy cyAzYyAzYyAyYyAyc2MgYzJzYyBjczJjIDVjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAg ICBscl9idWZmZXIsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhP RF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlRO QU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMSwgLyogVmFsdWVzICovCisKKwkJCQkgICAg T1BBTF9TVEFSVExJU1QsCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJ TllfVUlOVF8wMywgLyogQm9vbGVhbkV4cHIgKi8KKworCQkJCSAgICBPUEFMX1NUQVJUTElTVCwK KwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisKKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hBTEZfVUlE X0FVVEhPUklUWV9PQkpfUkVGXSwKKwkJCQkgICAgT1BBTF9VSURfTEVOR1RIX0hBTEYsCisJCQkJ ICAgIHVzZXJfdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwor CQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hBTEZfVUlEX0FV VEhPUklUWV9PQkpfUkVGXSwKKwkJCQkgICAgT1BBTF9VSURfTEVOR1RIX0hBTEYsCisJCQkJICAg IHVzZXJfdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJ CSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTFVJRFtPUEFMX0hBTEZfVUlEX0JPT0xF QU5fQUNFXSwKKwkJCQkgICAgT1BBTF9VSURfTEVOR1RIX0hBTEYsCisJCQkJICAgIE9QQUxfVElO WV9VSU5UXzAxLAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9FTkRMSVNU LAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAgIE9QQUxfRU5ETElTVCwKKwkJCQkgICAg T1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFMX0VORExJU1QpOworCWlmIChyZXQgPCAwKSB7CisJ CXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIGFkZCB1c2VyIHRvIGxvY2tpbmcgcmFuZ2UgY29t bWFuZC5cbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCXJldHVybiByZXQ7CisJfQor CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOworfQor CitzdGF0aWMgaW50IGxvY2tfdW5sb2NrX2xvY2tpbmdfcmFuZ2Uoc3RydWN0IG9wYWxfZGV2ICpk ZXYpCit7CisJdTggbHJfYnVmZmVyW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0IG9wYWxfY21k ICpjbWQ7CisJY29uc3QgdTggKm1ldGhvZDsKKwlzdHJ1Y3Qgb3BhbF9sb2NrX3VubG9jayAqbGt1 bDsKKwlpbnQgcmV0OworCXU4IHJlYWRfbG9ja2VkID0gMSwgd3JpdGVfbG9ja2VkID0gMTsKKwor CWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9jb21JRChjbWQs IGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07CisJbGt1bCA9 IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKwlpZiAoYnVpbGRfbG9ja2luZ19yYW5n ZShscl9idWZmZXIsIHNpemVvZihscl9idWZmZXIpLCBkZXYtPmxyKSA8IDApIHsKKwkJcHJfZXJy KCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25hbWUpOworCQly ZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlzd2l0Y2ggKGxrdWwtPmxfc3RhdGUpIHsKKwljYXNlIE9Q QUxfUk86CisJCXJlYWRfbG9ja2VkID0gMDsKKwkJd3JpdGVfbG9ja2VkID0gMTsKKwkJYnJlYWs7 CisJY2FzZSBPUEFMX1JXOgorCQlyZWFkX2xvY2tlZCA9IDA7CisJCXdyaXRlX2xvY2tlZCA9IDA7 CisJCWJyZWFrOworCWNhc2UgT1BBTF9MSzoKKwkJLyogdmFycyBhcmUgaW5pdGFsaXplZCB0byBs b2NrZWQgKi8KKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJcHJfZXJyKCJUcmllZCB0byBzZXQgYW4g aW52YWxpZCBsb2NraW5nIHN0YXRlLi4uIHJldHVybmluZyB0byB1bGFuZFxuIik7CisJCXJldHVy biAxOworCX0KKworCXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnNjIDNjIDRj IDRjIDNjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBscl9idWZmZXIsIE9QQUxfVUlE X0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisJCQkJICAgIE9Q QUxfU1RBUlRMSVNULAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1ZB TFVFUywKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUs CisJCQkJICAgIE9QQUxfUkVBRExPQ0tFRCwKKwkJCQkgICAgcmVhZF9sb2NrZWQsCisJCQkJICAg IE9QQUxfRU5ETkFNRSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9X UklURUxPQ0tFRCwKKwkJCQkgICAgd3JpdGVfbG9ja2VkLAorCQkJCSAgICBPUEFMX0VORE5BTUUs CisKKwkJCQkgICAgT1BBTF9FTkRMSVNULAorCQkJCSAgICBPUEFMX0VORE5BTUUsCisJCQkJICAg IE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlwcl9lcnIoIiVzOiBFcnJvciBi dWlsZGluZyBTRVQgY29tbWFuZC5cbiIsIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsK Kwl9CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRldiwgY21kLCBnZW5lcmljX2NvbnQpOwor fQorCisKK3N0YXRpYyBpbnQgbG9ja191bmxvY2tfbG9ja2luZ19yYW5nZV9TVU0oc3RydWN0IG9w YWxfZGV2ICpkZXYpCit7CisJdTggbHJfYnVmZmVyW09QQUxfVUlEX0xFTkdUSF07CisJc3RydWN0 IG9wYWxfY21kICpjbWQ7CisJY29uc3QgdTggKm1ldGhvZDsKKwlzdHJ1Y3Qgb3BhbF9sb2NrX3Vu bG9jayAqbGt1bDsKKwlpbnQgcmV0OworCXU4IHJlYWRfbG9ja2VkID0gMSwgd3JpdGVfbG9ja2Vk ID0gMTsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCXNldF9j b21JRChjbWQsIGRldi0+Y29tSUQpOworCisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX1NFVF07 CisJbGt1bCA9IGRldi0+ZnVuY19kYXRhW2Rldi0+c3RhdGUgLSAxXTsKKwlpZiAoYnVpbGRfbG9j a2luZ19yYW5nZShscl9idWZmZXIsIHNpemVvZihscl9idWZmZXIpLCBkZXYtPmxyKSA8IDApIHsK KwkJcHJfZXJyKCIlczogQ2FuJ3QgYnVpbGQgbG9ja2luZyByYW5nZVxuIiwgZGV2LT5kaXNrX25h bWUpOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisKKwlzd2l0Y2ggKGxrdWwtPmxfc3RhdGUpIHsK KwljYXNlIE9QQUxfUk86CisJCXJlYWRfbG9ja2VkID0gMDsKKwkJd3JpdGVfbG9ja2VkID0gMTsK KwkJYnJlYWs7CisJY2FzZSBPUEFMX1JXOgorCQlyZWFkX2xvY2tlZCA9IDA7CisJCXdyaXRlX2xv Y2tlZCA9IDA7CisJCWJyZWFrOworCWNhc2UgT1BBTF9MSzoKKwkJLyogdmFycyBhcmUgaW5pdGFs aXplZCB0byBsb2NrZWQgKi8KKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJcHJfZXJyKCJUcmllZCB0 byBzZXQgYW4gaW52YWxpZCBsb2NraW5nIHN0YXRlLlxuIik7CisJCXJldHVybiAxOworCX0KKwor CXJldCA9IHRlc3RfYW5kX2FkZF90b2tlbl92YShjbWQsICJjMnNjIDNjIDRjIDRjIDRjIDRjIDNj IiwKKwkJCQkgICAgT1BBTF9DQUxMLAorCQkJCSAgICBscl9idWZmZXIsIE9QQUxfVUlEX0xFTkdU SCwKKwkJCQkgICAgbWV0aG9kLCBPUEFMX01FVEhPRF9MRU5HVEgsCisJCQkJICAgIE9QQUxfU1RB UlRMSVNULAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1ZBTFVFUywK KwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJ ICAgIE9QQUxfUkVBRExPQ0tFTkFCTEVELAorCQkJCSAgICBPUEFMX1RSVUUsCisJCQkJICAgIE9Q QUxfRU5ETkFNRSwKKworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9XUklU RUxPQ0tFTkFCTEVELAorCQkJCSAgICBPUEFMX1RSVUUsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwK KworCQkJCSAgICBPUEFMX1NUQVJUTkFNRSwKKwkJCQkgICAgT1BBTF9SRUFETE9DS0VELAorCQkJ CSAgICByZWFkX2xvY2tlZCwKKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJICAgIE9QQUxf U1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1dSSVRFTE9DS0VELAorCQkJCSAgICB3cml0ZV9sb2Nr ZWQsCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKworCQkJCSAgICBPUEFMX0VORExJU1QsCisJCQkJ ICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKwlpZiAocmV0IDwgMCkg eworCQlwcl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBTRVQgY29tbWFuZC5cbiIsIGRldi0+ZGlz a19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisJcmV0dXJuIGZpbmFsaXplX2FuZF9zZW5kKGRl diwgY21kLCBnZW5lcmljX2NvbnQpOworfQorCitpbnQgYWN0aXZhdGVfbHNwKHN0cnVjdCBvcGFs X2RldiAqZGV2KQoreworCXU4IHVzZXJfbHJbT1BBTF9VSURfTEVOR1RIXTsKKwljb25zdCB1OCAq bWV0aG9kLCAqdWlkOworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWludCByZXQ7CisJc2l6ZV90 IHVpbnRfMyA9IDB4ODM7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisKKwljbGVhcl9vcGFsX2NtZChj bWQpOworCXNldF9jb21JRChjbWQsIGRldi0+Y29tSUQpOworCisJdWlkID0gT1BBTFVJRFtPUEFM X0xPQ0tJTkdTUF9VSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9BQ1RJVkFURV07CisK KwlyZXQgPSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIiwKKwkJCQkgICAgT1BBTF9D QUxMLAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9kLCBPUEFM X01FVEhPRF9MRU5HVEgpOworCWlmIChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1 aWxkaW5nIEFjdGl2YXRlIExvY2tpbmdTUCBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlz a19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisJLyogQWN0aXZhdGluZyBhcyBTVU0gKi8KKwlp ZiAoZGV2LT5sciA+IDApIHsKKwkJcmV0ID0gYnVpbGRfbG9ja2luZ19yYW5nZSh1c2VyX2xyLCBz aXplb2YodXNlcl9sciksIGRldi0+bHIpOworCQlpZiAocmV0IDwgMCkgeworCQkJcHJfZXJyKCIl czogQ2FuJ3QgYnVpbGQgbG9ja2luZyB1c2VyXG4iLAorCQkJICAgICAgIGRldi0+ZGlza19uYW1l KTsKKwkJCXJldHVybiByZXQ7CisJCX0KKwkJdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjJj IDRjIGNzYyAyYyIsCisJCQkJICAgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAgICAgT1BBTF9T VEFSVE5BTUUsCisKKwkJCQkgICAgICB1aW50XzMsCisJCQkJICAgICAgT1BBTF9USU5ZX1VJTlRf MDYsCisJCQkJICAgICAgT1BBTF9USU5ZX1VJTlRfMDAsCisJCQkJICAgICAgT1BBTF9USU5ZX1VJ TlRfMDAsCisKKwkJCQkgICAgICBPUEFMX1NUQVJUTElTVCwKKwkJCQkgICAgICB1c2VyX2xyLCBP UEFMX1VJRF9MRU5HVEgsCisJCQkJICAgICAgT1BBTF9FTkRMSVNULAorCisJCQkJICAgICAgT1BB TF9FTkROQU1FLAorCQkJCSAgICAgIE9QQUxfRU5ETElTVCk7CisJfSBlbHNlIC8qIEFjdGlhdmUg Tm9ybWFsIE1vZGUgKi8KKwkJcmV0ID0gdGVzdF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgIjJjIiwK KwkJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCQkgICAgT1BBTF9FTkRMSVNUKTsKKworCWlm IChyZXQgPCAwKSB7CisJCXByX2VycigiJXM6IEVycm9yIGJ1aWxkaW5nIEFjdGl2YXRlIExvY2tp bmdTUCBjb21tYW5kLlxuIiwKKwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJl dDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdlbmVyaWNfY29u dCk7Cit9CisKK3N0YXRpYyBpbnQgZ2V0X2xzcF9saWZlY3ljbGVfY29udCh2b2lkICpkYXRhKQor eworCXN0cnVjdCBvcGFsX2RldiAqZGV2ID0gZGF0YTsKKwl1OCBsY19zdGF0dXM7CisJaW50IGVy cm9yID0gMDsKKworCWVycm9yID0gcGFyc2VfYW5kX2NoZWNrX3N0YXR1cyhkZXYpOworCWlmIChl cnJvcikKKwkJZ290byBlcnJfcmV0dXJuOworCisJbGNfc3RhdHVzID0gcmVzcG9uc2VfZ2V0X3U2 NCgmZGV2LT5wYXJzZWQsIDQpOworCS8qIDB4MDggaXMgTWFudWZhY3VyZWQgSW5hY3RpdmUgKi8K KwkvKiAweDA5IGlzIE1hbnVmYWN0dXJlZCAqLworCWlmIChsY19zdGF0dXMgIT0gMHgwOCkgewor CQlwcl9lcnIoIiVzOiBDb3VsZG4ndCBkZXRlcm1pbmUgdGhlIHN0YXR1cyBvZiB0aGUgTGlmY3lj bGUgc3RhdGVcbiIsCisJCSAgICAgICBkZXYtPmRpc2tfbmFtZSk7CisJCWVycm9yID0gLUVOT0RF VjsKKwkJZ290byBlcnJfcmV0dXJuOworCX0KKworZXJyX3JldHVybjoKKwlyZXR1cm4gZXJyb3I7 Cit9CisKKy8qIERldGVybWluZSBpZiB3ZSdyZSBpbiB0aGUgTWFudWZhY3R1cmVkIEluYWN0aXZl IG9yIEFjdGl2ZSBzdGF0ZSAqLworaW50IGdldF9sc3BfbGlmZWN5Y2xlKHN0cnVjdCBvcGFsX2Rl diAqZGV2KQoreworCXN0cnVjdCBvcGFsX2NtZCAqY21kOworCWNvbnN0IHU4ICptZXRob2QsICp1 aWQ7CisJaW50IHJldDsKKworCWNtZCA9ICZkZXYtPmNtZDsKKworCWNsZWFyX29wYWxfY21kKGNt ZCk7CisJc2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisKKwl1aWQgPSBPUEFMVUlEW09QQUxf TE9DS0lOR1NQX1VJRF07CisJbWV0aG9kID0gT1BBTE1FVEhPRFtPUEFMX0dFVF07CisKKwlyZXQg PSB0ZXN0X2FuZF9hZGRfdG9rZW5fdmEoY21kLCAiYzJzIDJjIDRjIDRjIDJjIiwKKwkJCQkgICAg T1BBTF9DQUxMLAorCQkJCSAgICB1aWQsIE9QQUxfVUlEX0xFTkdUSCwKKwkJCQkgICAgbWV0aG9k LCBPUEFMX01FVEhPRF9MRU5HVEgsCisKKwkJCQkgICAgT1BBTF9TVEFSVExJU1QsCisJCQkJICAg IE9QQUxfU1RBUlRMSVNULAorCisJCQkJICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFM X1RJTllfVUlOVF8wMywgLyogU3RhcnQgQ29sdW1uICovCisJCQkJICAgIE9QQUxfVElOWV9VSU5U XzA2LCAvKiBMaWZjeWNsZSBDb2x1bW4gKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCisJCQkJ ICAgIE9QQUxfU1RBUlROQU1FLAorCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNCwgLyogRW5kIENv bHVtbiAqLworCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wNiwgLyogTGlmZWN5Y2xlIENvbHVtbiAq LworCQkJCSAgICBPUEFMX0VORE5BTUUsCisKKwkJCQkgICAgT1BBTF9FTkRMSVNULAorCQkJCSAg ICBPUEFMX0VORExJU1QpOworCisJaWYgKHJldCA8IDApIHsKKwkJcHJfZXJyKCIlczogRXJyb3Ig QnVpbGRpbmcgR0VUIExpZmVjeWNsZSBTdGF0dXMgY29tbWFuZFxuIiwKKwkJICAgICAgIGRldi0+ ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4gZmluYWxpemVfYW5kX3Nl bmQoZGV2LCBjbWQsIGdldF9sc3BfbGlmZWN5Y2xlX2NvbnQpOworfQorCitzdGF0aWMgaW50IGdl dF9tc2lkX2NwaW5fcGluX2NvbnQodm9pZCAqZGF0YSkKK3sKKwljb25zdCBjaGFyICptc2lkX3Bp bjsKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldiA9IGRhdGE7CisJc2l6ZV90IHN0cmxlbjsKKwlpbnQg ZXJyb3IgPSAwOworCisJZXJyb3IgPSBwYXJzZV9hbmRfY2hlY2tfc3RhdHVzKGRldik7CisJaWYg KGVycm9yKQorCQlnb3RvIGVycl9yZXR1cm47CisKKwlzdHJsZW4gPSByZXNwb25zZV9nZXRfc3Ry aW5nKCZkZXYtPnBhcnNlZCwgNCwgJm1zaWRfcGluKTsKKwlpZiAoIW1zaWRfcGluKSB7CisJCXBy X2VycigiJXM6IENvdWxkbid0IGV4dHJhY3QgUElOIGZyb20gcmVzcG9uc2VcbiIsIF9fZnVuY19f KTsKKwkJZXJyb3IgPSAxOworCQlnb3RvIGVycl9yZXR1cm47CisJfQorCisJZGV2LT5wcmV2X2Rh dGEgPSBrbWVtZHVwKG1zaWRfcGluLCBzdHJsZW4sIEdGUF9LRVJORUwpOworCWlmICghZGV2LT5w cmV2X2RhdGEpIHsKKwkJZXJyb3IgPSAtRU5PTUVNOworCQlnb3RvIGVycl9yZXR1cm47CisJfQor CisJZGV2LT5wcmV2X2RfbGVuID0gc3RybGVuOworCisgZXJyX3JldHVybjoKKwlyZXR1cm4gZXJy b3I7Cit9CisKK3N0YXRpYyBpbnQgZ2V0X21zaWRfY3Bpbl9waW4oc3RydWN0IG9wYWxfZGV2ICpk ZXYpCit7CisJY29uc3QgdTggKm1ldGhvZCwgKnNtdWlkOworCWludCByZXQ7CisJc3RydWN0IG9w YWxfY21kICpjbWQ7CisKKwljbWQgPSAmZGV2LT5jbWQ7CisJY2xlYXJfb3BhbF9jbWQoY21kKTsK KwlzZXRfY29tSUQoY21kLCBkZXYtPmNvbUlEKTsKKworCXNtdWlkID0gT1BBTFVJRFtPUEFMX0Nf UElOX01TSURdOworCW1ldGhvZCA9IE9QQUxNRVRIT0RbT1BBTF9HRVRdOworCisJcmV0ID0gdGVz dF9hbmRfYWRkX3Rva2VuX3ZhKGNtZCwgImMgMnMgMTJjIiwKKwkJCQkgICAgT1BBTF9DQUxMLAor CisJCQkJICAgIHNtdWlkLCBPUEFMX1VJRF9MRU5HVEgsCisJCQkJICAgIG1ldGhvZCwgT1BBTF9N RVRIT0RfTEVOR1RILAorCisJCQkJICAgIE9QQUxfU1RBUlRMSVNULAorCQkJCSAgICBPUEFMX1NU QVJUTElTVCwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJICAgIE9QQUxfVElOWV9VSU5U XzAzLCAvKiBTYXJ0IENvbHVtbiAqLworCQkJCSAgICBPUEFMX1RJTllfVUlOVF8wMywgLyogUElO ICovCisJCQkJICAgIE9QQUxfRU5ETkFNRSwKKwkJCQkgICAgT1BBTF9TVEFSVE5BTUUsCisJCQkJ ICAgIE9QQUxfVElOWV9VSU5UXzA0LCAvKiBFbmQgQ29sdW1uICovCisJCQkJICAgIE9QQUxfVElO WV9VSU5UXzAzLCAvKiBQSU4gKi8KKwkJCQkgICAgT1BBTF9FTkROQU1FLAorCQkJCSAgICBPUEFM X0VORExJU1QsCisJCQkJICAgIE9QQUxfRU5ETElTVCk7CisKKwlpZiAocmV0IDwgMCkgeworCQlw cl9lcnIoIiVzOiBFcnJvciBidWlsZGluZyBHZXQgTVNJRCBDUElOIFBJTiBjb21tYW5kLlxuIiwK KwkJICAgICAgIGRldi0+ZGlza19uYW1lKTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwlyZXR1cm4g ZmluYWxpemVfYW5kX3NlbmQoZGV2LCBjbWQsIGdldF9tc2lkX2NwaW5fcGluX2NvbnQpOworfQor CitzdGF0aWMgdm9pZCB1bmxvY2tfc3VzcGVuZF9maW5hbChzdHJ1Y3Qgb3BhbF9kZXYgKmRldikK K3sKKwlkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQgPSBmYWxzZTsKKwlkZXYtPnJlc3VtZV9kYXRh ID0gTlVMTDsKKwlkZXYtPmZ1bmNfZGF0YSA9IE5VTEw7Cit9CisKK3N0YXRpYyBpbnQgYnVpbGRf ZW5kX29wYWxfc2Vzc2lvbihzdHJ1Y3Qgb3BhbF9kZXYgKmRldikKK3sKKwlzdHJ1Y3Qgb3BhbF9j bWQgKmNtZDsKKworCWNtZCA9ICZkZXYtPmNtZDsKKwljbGVhcl9vcGFsX2NtZChjbWQpOworCisJ c2V0X2NvbUlEKGNtZCwgZGV2LT5jb21JRCk7CisJcmV0dXJuIHRlc3RfYW5kX2FkZF90b2tlbl91 OChjbWQsIE9QQUxfRU5ET0ZTRVNTSU9OKTsKK30KKworc3RhdGljIGludCBlbmRfb3BhbF9zZXNz aW9uKHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCWludCByZXQgPSBidWlsZF9lbmRfb3BhbF9z ZXNzaW9uKGRldik7CisKKwlpZiAocmV0IDwgMCkKKwkJcmV0dXJuIHJldDsKKwlyZXR1cm4gZmlu YWxpemVfYW5kX3NlbmQoZGV2LCAmZGV2LT5jbWQsIGVuZF9zZXNzaW9uX2NvbnQpOworfQorCitz dGF0aWMgc3RydWN0IG9wYWxfZGV2ICpmaW5kX29wYWxfZGV2KGRldl90IG1ham1pbiwgdTggbHIp Cit7CisJc3RydWN0IG9wYWxfZGV2ICppdGVyLCAqb3BhbF9kZXYgPSBOVUxMOworCisJbGlzdF9m b3JfZWFjaF9lbnRyeShpdGVyLCAmb3BhbF9saXN0LCBub2RlKSB7CisJCWlmIChNQUpPUihpdGVy LT5tYWptaW4pICE9IE1BSk9SKG1ham1pbikgfHwKKwkJICAgIE1JTk9SKGl0ZXItPm1ham1pbikg IT0gTUlOT1IobWFqbWluKSkKKwkJCWNvbnRpbnVlOworCisJCWlmIChpdGVyLT5sciA9PSBscikg eworCQkJb3BhbF9kZXYgPSBpdGVyOworCQkJYnJlYWs7CisJCX0KKwl9CisJcmV0dXJuIG9wYWxf ZGV2OworfQorCitzdGF0aWMgaW50IHVwZGF0ZV9vcGFsX2RldihzdHJ1Y3Qgb3BhbF9kZXYgKm9s ZF9kZXYsIHN0cnVjdCBvcGFsX2RldiAqbmV3X2RldikKK3sKKwlpZiAoIWF0b21pY19hZGRfdW5s ZXNzKCZvbGRfZGV2LT5pbl91c2UsIDEsIDEpKSB7CisJCXByX2VycigiJXM6IGRldiB3YXMgaW4g dXNlXG4iLCBfX2Z1bmNfXyk7CisJCXJldHVybiAtRUJVU1k7CisJfQorCisJb2xkX2Rldi0+a2V5 X25hbWVfbGVuID0gbmV3X2Rldi0+a2V5X25hbWVfbGVuOworCWlmICghbWVtY3B5KG9sZF9kZXYt PmtleV9uYW1lLCBuZXdfZGV2LT5rZXlfbmFtZSwgb2xkX2Rldi0+a2V5X25hbWVfbGVuKSkgewor CQlwcl9lcnIoIiVzOiBFcnJvciB1cGRhdGluZyBkZXZpY2U6XG4iLCBvbGRfZGV2LT5kaXNrX25h bWUpOworCQlyZXR1cm4gLUVGQVVMVDsKKwl9CisKKwlpZiAoIXN0cm5jcHkob2xkX2Rldi0+ZGlz a19uYW1lLCBuZXdfZGV2LT5kaXNrX25hbWUsIERJU0tfTkFNRV9MRU4pKSB7CisJCXByX2Vycigi JXM6IEVycm9yIHJlZ2lzdGVyaW5nIGRldmljZTogY29weWluZyBkaXNrIG5hbWVcbiIsCisJCSAg ICAgICBvbGRfZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVGQVVMVDsKKwl9CisKKwlvbGRf ZGV2LT5jb21JRCA9IG5ld19kZXYtPmNvbUlEOworCW9sZF9kZXYtPnN0YXJ0ID0gbmV3X2Rldi0+ c3RhcnQ7CisJb2xkX2Rldi0+bGVuZ3RoID0gbmV3X2Rldi0+bGVuZ3RoOworCW9sZF9kZXYtPmFs aWduID0gbmV3X2Rldi0+YWxpZ247CisJb2xkX2Rldi0+bG93ZXN0X2xiYSA9IG5ld19kZXYtPmxv d2VzdF9sYmE7CisJb2xkX2Rldi0+c3RhdGUgPSBuZXdfZGV2LT5zdGF0ZTsKKwlvbGRfZGV2LT5m dW5jcyA9IG5ld19kZXYtPmZ1bmNzOworCW9sZF9kZXYtPm1ham1pbiA9IG5ld19kZXYtPm1ham1p bjsKKwlvbGRfZGV2LT5zdWJtaXRfZm4gPSBuZXdfZGV2LT5zdWJtaXRfZm47CisJb2xkX2Rldi0+ c3VibWl0X2RhdGEgPSBuZXdfZGV2LT5zdWJtaXRfZGF0YTsKKworCWNsZWFuX2Z1bmN0aW9uX2Rh dGEob2xkX2Rldik7CisKKwkvKgorCSAqIFdvbid0IGJlIGFibGUgdG8gYXV0byB1bmxvY2sgdGhp cyBsb2NraW5nIHJhbmdlIGJhc2VkIG9uIGJsb2NrCisJICogcmVxdWVzdGVzLgorCSAqLworCWlm IChvbGRfZGV2LT5sZW5ndGggPT0gMCkKKwkJcHJfd2FybigiJXM6IE1pc3NpbmcgYmxvY2sgaW5m b3JtYXRpb24gZm9yIGxvY2tpbmcgcmFuZ2UgJWRcbiIsCisJCQlvbGRfZGV2LT5kaXNrX25hbWUs IG9sZF9kZXYtPmxyKTsKKworCXJldHVybiAwOworfQorCitpbnQgb3BhbF9yZWdpc3Rlcl9jb250 KHN0cnVjdCBvcGFsX2RldiAqbmV3X2RldikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9sZF9kZXY7 CisJdW5zaWduZWQgbG9uZyBmbGFnczsKKwlpbnQgZXJyb3IgPSAwOworCisJc3Bpbl9sb2NrX2ly cXNhdmUoJmxpc3Rfc3BpbmxvY2ssIGZsYWdzKTsKKworCW9sZF9kZXYgPSBmaW5kX29wYWxfZGV2 KG5ld19kZXYtPm1ham1pbiwgbmV3X2Rldi0+bHIpOworCWlmICghb2xkX2RldikgeworCQlsaXN0 X2FkZF90YWlsKCZuZXdfZGV2LT5ub2RlLCAmb3BhbF9saXN0KTsKKwkJb2xkX2RldiA9IG5ld19k ZXY7CisJfSBlbHNlIHsKKwkJaWYgKG9sZF9kZXYgPT0gbmV3X2RldikKKwkJCWVycm9yID0gMDsK KwkJZWxzZSB7CisJCQllcnJvciA9IHVwZGF0ZV9vcGFsX2RldihvbGRfZGV2LCBuZXdfZGV2KTsK KwkJCWNsZWFuX29wYWxfa2V5KG5ld19kZXYpOworCQkJa2ZyZWUobmV3X2Rldik7CisJCX0KKwl9 CisKKwlpZiAoZXJyb3IpCisJCWxpc3RfZGVsKCZvbGRfZGV2LT5ub2RlKTsKKworCXNwaW5fdW5s b2NrX2lycXJlc3RvcmUoJmxpc3Rfc3BpbmxvY2ssIGZsYWdzKTsKKworCWlmICghZXJyb3IpCisJ CXByX2luZm8oIiVzOiBSZWdpc3RlcmVkIGtleSBmb3IgbG9ja2luZyByYW5nZTogJWRcbiIsCisJ CQlvbGRfZGV2LT5kaXNrX25hbWUsIG9sZF9kZXYtPmxyKTsKKworCXJldHVybiBlcnJvcjsKK30K KworY29uc3Qgb3BhbF9zdGVwIGVycm9yX2VuZF9zZXNzaW9uW10gPSB7CisJZW5kX29wYWxfc2Vz c2lvbiwKKwlOVUxMLAorfTsKK3N0YXRpYyBpbnQgZW5kX29wYWxfc2Vzc2lvbl9lcnJvcihzdHJ1 Y3Qgb3BhbF9kZXYgKmRldikKK3sKKworCWRldi0+ZnVuY3MgPSBlcnJvcl9lbmRfc2Vzc2lvbjsK KwlkZXYtPnN0YXRlID0gMDsKKwlkZXYtPmVycm9yX2NiID0gTlVMTDsKKwlyZXR1cm4gbmV4dChk ZXYpOworfQorCitzdGF0aWMgc3RydWN0IG9wYWxfZGV2ICphbGxvY19vcGFsX2RldihzdHJ1Y3Qg YmxvY2tfZGV2aWNlICpiZGV2LCB1OCBscikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYgKm9wYWxfZGV2 OworCXN0cnVjdCByZXF1ZXN0X3F1ZXVlICpxOworCXVuc2lnbmVkIGxvbmcgZG1hX2FsaWduOwor CWNvbnN0IGNoYXIgKmRpc2tfbmFtZTsKKwlzdHJ1Y3Qgb3BhbF9jbWQgKmNtZDsKKwlpbnQgcmV0 OworCisJb3BhbF9kZXYgPSBremFsbG9jKHNpemVvZigqb3BhbF9kZXYpLCBHRlBfS0VSTkVMKTsK KwlpZiAoIW9wYWxfZGV2KQorCQlyZXR1cm4gRVJSX1BUUigtRU5PTUVNKTsKKworCW9wYWxfZGV2 LT5tYWptaW4gPSBiZGV2LT5iZF9kZXY7CisJb3BhbF9kZXYtPmxyID0gbHI7CisJY21kID0gJm9w YWxfZGV2LT5jbWQ7CisJY21kLT5jbWQgPSBjbWQtPmNtZF9idWY7CisJY21kLT5yZXNwID0gY21k LT5yZXNwX2J1ZjsKKworCWRpc2tfbmFtZSA9IGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZTsKKwlp ZiAoIXN0cm5jcHkob3BhbF9kZXYtPmRpc2tfbmFtZSwgZGlza19uYW1lLCBESVNLX05BTUVfTEVO KSkgeworCQlwcl9lcnIoIiVzOiBFcnJvciByZWdpc3RlcmluZyBkZXZpY2U6IGNvcHlpbmcgZGlz ayBuYW1lXG4iLAorCQkgICAgICAgZGlza19uYW1lKTsKKwkJcmV0ID0gLUVGQVVMVDsKKwkJZ290 byBlcnJfZnJlZV9kZXY7CisJfQorCisJcSA9IGJkZXYtPmJkX3F1ZXVlOworCWRtYV9hbGlnbiA9 IChxdWV1ZV9kbWFfYWxpZ25tZW50KHEpIHwgcS0+ZG1hX3BhZF9tYXNrKSArIDE7CisJY21kLT5j bWQgPSAodTggKilyb3VuZF91cCgodWludHB0cl90KWNtZC0+Y21kLCBkbWFfYWxpZ24pOworCWNt ZC0+cmVzcCA9ICh1OCAqKXJvdW5kX3VwKCh1aW50cHRyX3QpY21kLT5yZXNwLCBkbWFfYWxpZ24p OworCisJSU5JVF9MSVNUX0hFQUQoJm9wYWxfZGV2LT5ub2RlKTsKKwlhdG9taWNfc2V0KCZvcGFs X2Rldi0+aW5fdXNlLCAxKTsKKworCW9wYWxfZGV2LT5zdGF0ZSA9IDA7CisKKwlyZXR1cm4gb3Bh bF9kZXY7CisKK2Vycl9mcmVlX2RldjoKKwlrZnJlZShvcGFsX2Rldik7CisJcmV0dXJuIEVSUl9Q VFIocmV0KTsKK30KKworaW50IG9wYWxfcmVnaXN0ZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRl diwgc3RydWN0IG9wYWxfa2V5ICprZXlfY21kLAorCQkgIGNvbnN0IG9wYWxfc3RlcCAqZnVuY3Ms IHZvaWQgKnNibXRfZGF0YSwKKwkJICBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKQoreworCXN0 cnVjdCBvcGFsX2RldiAqbmV3X2RldiA9IE5VTEw7CisJdTgga2V5X2xlbiA9IGtleV9jbWQtPmtl eV9sZW47CisJdTggbHIgPSBrZXlfY21kLT5scjsKKwlpbnQgcmV0OworCisJbmV3X2RldiA9IGFs bG9jX29wYWxfZGV2KGJkZXYsIGxyKTsKKwlpZiAoSVNfRVJSKG5ld19kZXYpKSB7CisJCXByX2Vy cigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGRldmljZTogYWxsb2NhdGlvblxuIiwKKwkJICAgICAg IGJkZXYtPmJkX2Rpc2stPmRpc2tfbmFtZSk7CisJCXJldHVybiBQVFJfRVJSKG5ld19kZXYpOwor CX0KKworCWlmICghbWVtY3B5KG5ld19kZXYtPmtleV9uYW1lLCBrZXlfY21kLT5rZXksIGtleV9s ZW4pKSB7CisJCXByX2VycigiJXM6IEVycm9yIHJlZ2lzdGVyaW5nIGtleTogY291bGRuJ3QgY29w eSBrZXlcbiIsCisJCSAgICAgICBuZXdfZGV2LT5kaXNrX25hbWUpOworCQlyZXR1cm4gLUVGQVVM VDsKKwl9CisKKwluZXdfZGV2LT5rZXlfbmFtZV9sZW4gPSBrZXlfbGVuOworCW5ld19kZXYtPmtl eV90eXBlID0ga2V5X2NtZC0+a2V5X3R5cGU7CisJcmV0ID0gZ2V0X29wYWxfa2V5KG5ld19kZXYp OworCWlmIChyZXQpIHsKKwkJcHJfZXJyKCIlczogQ291bGRuJ3QgZ2V0IGtleTogJWRcbiIsIG5l d19kZXYtPmRpc2tfbmFtZSwgcmV0KTsKKwkJcmV0dXJuIHJldDsKKwl9CisKKwluZXdfZGV2LT5m dW5jcyA9IGZ1bmNzOworCW5ld19kZXYtPnN1Ym1pdF9kYXRhID0gc2JtdF9kYXRhOworCW5ld19k ZXYtPnN1Ym1pdF9mbiA9IHN1Ym1pdF9mbjsKKworCW5ld19kZXYtPnN0YXRlID0gMDsKKwlyZXR1 cm4gbmV4dChuZXdfZGV2KTsKK30KKworc3RhdGljIHN0cnVjdCBvcGFsX2RldiAqZ2V0X3JlZ2lz dGVyZWRfb3BhbF9kZXYoZGV2X3QgbWFqbWluLCB1OCBscikKK3sKKwlzdHJ1Y3Qgb3BhbF9kZXYg Kml0ZXIsICpkZXYgPSBOVUxMOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisJYm9vbCBpbl91c2Ug PSBmYWxzZTsKKworCXNwaW5fbG9ja19pcnFzYXZlKCZsaXN0X3NwaW5sb2NrLCBmbGFncyk7CisJ bGlzdF9mb3JfZWFjaF9lbnRyeShpdGVyLCAmb3BhbF9saXN0LCBub2RlKSB7CisJCWlmIChNQUpP UihpdGVyLT5tYWptaW4pICE9IE1BSk9SKG1ham1pbikgfHwKKwkJICAgIE1JTk9SKGl0ZXItPm1h am1pbikgIT0gTUlOT1IobWFqbWluKSkKKwkJCWNvbnRpbnVlOworCQlpZiAoaXRlci0+bHIgPT0g bHIpIHsKKwkJCWRldiA9IGl0ZXI7CisJCQlpZiAoIWF0b21pY19hZGRfdW5sZXNzKCZpdGVyLT5p bl91c2UsIDEsIDEpKSB7CisJCQkJZGV2ID0gTlVMTDsKKwkJCQlpbl91c2UgPSB0cnVlOworCQkJ fQorCQkJYnJlYWs7CisJCX0KKwl9CisKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZsaXN0X3Nw aW5sb2NrLCBmbGFncyk7CisKKwlpZiAoIWRldikKKwkJcmV0dXJuIE5VTEw7CisKKwlyZXR1cm4g ZGV2OworfQorCisvKiBGcmVlIHVwIHRoZSBPcGFsIGRldiBhbmQgaXRzIGtleXMgZHVyaW5nIHR3 byBzY2VuYXJpb3M6CisgKgorICogMSkgV2hlbiBhIGNvbW1hbmQgaXMgY29tcGxldGUgdGhhdCBu byBsb25nZXIgcmVxdWlyZXMKKyAqICAgIHRoZSBvcGFsIGRldiB0byBiZSBhcm91bmQuCisgKiAy KSBXaGVuIGEgY29tbWFuZCwgaW5jbHVkaW5nIE9wYWwgU2F2ZSBmYWlscyB3ZSBjbGVhbgorICog ICAgYW5kIGZyZWUgdGhlIG9wYWwgZGV2LgorICoKKyAqICAgIElmIHdlIGZpbmQgdGhlIG9wYWwg ZGV2IHN0cnVjdHVyZSBpbiB0aGUgbGlzdCBvZgorICogICAgc2F2ZWQgcGFzc3dvcmRzIHdlIHdp bGwgKm5vdCogcmVtb3ZlIGl0LgorICovCitzdGF0aWMgdm9pZCByZW1vdmVfYW5kX2NsZWFuX29w YWxfZGV2KHN0cnVjdCBvcGFsX2RldiAqZGV2KQoreworCXN0cnVjdCBvcGFsX2RldiAqaXRlcjsK Kwlib29sIGZvdW5kID0gZmFsc2U7CisKKwlhdG9taWNfZGVjKCZkZXYtPmluX3VzZSk7CisJc3Bp bl9sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KGl0ZXIsICZvcGFs X2xpc3QsIG5vZGUpIHsKKwkJaWYgKGl0ZXIgPT0gZGV2KSB7CisJCQlmb3VuZCA9IHRydWU7CisJ CQlicmVhazsKKwkJfQorCX0KKworCXNwaW5fdW5sb2NrKCZsaXN0X3NwaW5sb2NrKTsKKwlpZiAo IWZvdW5kKSB7CisJCWNsZWFuX29wYWxfa2V5KGRldik7CisJCWNsZWFuX2Z1bmN0aW9uX2RhdGEo ZGV2KTsKKwkJa2ZyZWUoZGV2KTsKKwl9Cit9CisKK3N0YXRpYyBzdHJ1Y3Qgb3BhbF9kZXYgKmdl dF9vcl9jcmVhdGVfb3BhbF9kZXYoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwKKwkJCQkJICAg ICAgIHU4IGxyLCBib29sIHVzZV9uZXcpCit7CisJc3RydWN0IG9wYWxfZGV2ICpkZXYgPSBOVUxM OworCisJaWYgKCF1c2VfbmV3KQorCQlkZXYgPSBnZXRfcmVnaXN0ZXJlZF9vcGFsX2RldihiZGV2 LT5iZF9kZXYsIGxyKTsKKworCWlmICghZGV2KQorCQlkZXYgPSBhbGxvY19vcGFsX2RldihiZGV2 LCBscik7CisKKwlyZXR1cm4gZGV2OworfQorCitzdGF0aWMgaW50IHNldHVwX29wYWxfZGV2KHN0 cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsICBzdHJ1Y3Qgb3BhbF9kZXYgKmRldiwKKwkJCSAgY29u c3Qgb3BhbF9zdGVwICpmdW5jcywgIHN0cnVjdCBvcGFsX2tleSAqa2V5LAorCQkJICB2b2lkICpz Ym10X2RhdGEsICBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKQoreworCWludCByZXQ7CisKKwlk ZXYtPnN0YXRlID0gMDsKKwlkZXYtPmZ1bmNzID0gZnVuY3M7CisJZGV2LT5UU04gPSAwOworCWRl di0+SFNOID0gMDsKKwlkZXYtPmxyID0ga2V5LT5scjsKKwlkZXYtPmVycm9yX2NiID0gZW5kX29w YWxfc2Vzc2lvbl9lcnJvcjsKKwlkZXYtPmVycm9yX2NiX2RhdGEgPSBkZXY7CisJZGV2LT5zdWJt aXRfZm4gPSBzdWJtaXRfZm47CisJZGV2LT5zdWJtaXRfZGF0YSA9IHNibXRfZGF0YTsKKworCWlm IChrZXkpIHsKKwkJbWVtY3B5KGRldi0+a2V5X25hbWUsIGtleS0+a2V5LCBrZXktPmtleV9sZW4p OworCQlkZXYtPmtleV9uYW1lX2xlbiA9IGtleS0+a2V5X2xlbjsKKwkJZGV2LT5rZXlfdHlwZSA9 IGtleS0+a2V5X3R5cGU7CisKKwkJcmV0ID0gZ2V0X29wYWxfa2V5KGRldik7CisJCWlmIChyZXQp IHsKKwkJCXByX2VycigiJXM6IENvdWxkbid0IGdldCBrZXk6ICVkXG4iLAorCQkJICAgICAgIGRl di0+ZGlza19uYW1lLCByZXQpOworCQkJcmV0dXJuIHJldDsKKwkJfQorCX0KKwlkZXYtPmZ1bmNf ZGF0YSA9IE5VTEw7CisJcmV0dXJuIDA7Cit9CisKK2ludCBvcGFsX3NlY3VyZV9lcmFzZV9sb2Nr aW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXks CisJCQkJICAgIHZvaWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sK KwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKKwl2b2lkICpkYXRhWzNdID0geyBOVUxMIH07CisJY29u c3Qgb3BhbF9zdGVwIGVyYXNlX2Z1bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3Rh cnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJCWdldF9hY3RpdmVfa2V5LAorCQlnZW5fa2V5LAorCQll bmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMLAorCX07CisJaW50IHJldDsKKworCWRldiA9IGdldF9v cl9jcmVhdGVfb3BhbF9kZXYoYmRldiwga2V5LT5vcGFsX2FjdC5rZXkubHIsIHRydWUpOworCWlm ICghZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXJldCA9IHNldHVwX29wYWxfZGV2KGJkZXYs IGRldiwgZXJhc2VfZnVuY3MsICZrZXktPm9wYWxfYWN0LmtleSwKKwkJCSAgICAgc2JtdF9kYXRh LCBzdWJtaXRfZm4pOworCWRldi0+ZnVuY19kYXRhID0gZGF0YTsKKwlkZXYtPmZ1bmNfZGF0YVsx XSA9ICZrZXktPm9wYWxfYWN0LndobzsKKwlpZiAocmV0KQorCQlnb3RvIGVycm9yX3JldHVybjsK KworCXJldCA9IG5leHQoZGV2KTsKKworIGVycm9yX3JldHVybjoKKwlyZW1vdmVfYW5kX2NsZWFu X29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJldDsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF9zZWN1 cmVfZXJhc2VfbG9ja2luZ19yYW5nZSk7CisKK2ludCBvcGFsX2VyYXNlX2xvY2tpbmdfcmFuZ2Uo c3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSwKKwkJCSAgICAg dm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKQoreworCXN0cnVjdCBv cGFsX2RldiAqZGV2OworCWNvbnN0IG9wYWxfc3RlcCBlcmFzZV9mdW5jc1tdID0geworCQlvcGFs X2Rpc2NvdmVyeTAsCisJCXN0YXJ0X2F1dGhfb3BhbF9zZXNzaW9uLAorCQllcmFzZV9sb2NraW5n X3JhbmdlLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMLAorCX07CisJaW50IHJldDsKKwor CWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwga2V5LT5vcGFsX2xycy5rZXkubHIs IHRydWUpOworCWlmICghZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXJldCA9IHNldHVwX29w YWxfZGV2KGJkZXYsIGRldiwgZXJhc2VfZnVuY3MsICZrZXktPm9wYWxfbHJzLmtleSwKKwkJCSAg ICAgc2JtdF9kYXRhLCBzdWJtaXRfZm4pOworCWlmIChyZXQpCisJCWdvdG8gZXJyb3JfcmV0dXJu OworCisJcmV0ID0gbmV4dChkZXYpOworCisgZXJyb3JfcmV0dXJuOgorCXJlbW92ZV9hbmRfY2xl YW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworfQorRVhQT1JUX1NZTUJPTChvcGFsX2Vy YXNlX2xvY2tpbmdfcmFuZ2UpOworCitpbnQgb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFkb3dfbWJy KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsCisJCQkJICAgc3RydWN0IHNlZF9rZXkgKmtleSwg dm9pZCAqc2JtdF9kYXRhLAorCQkJCSAgIHNlZF9zZWNfc3VibWl0ICpzdWJtaXRfZm4pCit7CisJ dm9pZCAqZnVuY19kYXRhWzZdID0geyBOVUxMIH07CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisJ Y29uc3Qgb3BhbF9zdGVwIG1icl9mdW5jc1tdID0geworCQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0 YXJ0X2FkbWluMUxTUF9vcGFsX3Nlc3Npb24sCisJCXNldF9tYnJfZG9uZSwKKwkJZW5kX29wYWxf c2Vzc2lvbiwKKwkJc3RhcnRfYWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKKwkJc2V0X21icl9lbmFi bGVfZGlzYWJsZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJTlVMTCwKKwl9OworCWludCByZXQ7 CisKKwlpZiAoa2V5LT5vcGFsX21ici5lbmFibGVfZGlzYWJsZSAhPSBPUEFMX01CUl9FTkFCTEUg JiYKKwkgICAga2V5LT5vcGFsX21ici5lbmFibGVfZGlzYWJsZSAhPSBPUEFMX01CUl9ESVNBQkxF KQorCQlyZXR1cm4gLUVJTlZBTDsKKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRl diwga2V5LT5vcGFsX21ici5rZXkubHIsIHRydWUpOworCWlmICghZGV2KQorCQlyZXR1cm4gLUVO T01FTTsKKworCXJldCA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgbWJyX2Z1bmNzLCAma2V5 LT5vcGFsX21ici5rZXksCisJCQkgICAgIHNibXRfZGF0YSwgc3VibWl0X2ZuKTsKKwlpZiAocmV0 KQorCQlnb3RvIGVycm9yX3JldHVybjsKKworCWRldi0+bnVtX2Z1bmNfZGF0YSA9IDY7CisJZGV2 LT5mdW5jX2RhdGEgPSBmdW5jX2RhdGE7CisJZGV2LT5mdW5jX2RhdGFbMl0gPSAma2V5LT5vcGFs X21ici5lbmFibGVfZGlzYWJsZTsKKwlkZXYtPmZ1bmNfZGF0YVs1XSA9ICZrZXktPm9wYWxfbWJy LmVuYWJsZV9kaXNhYmxlOworCisJcmV0ID0gbmV4dChkZXYpOworCisgZXJyb3JfcmV0dXJuOgor CXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworCit9CitFWFBP UlRfU1lNQk9MKG9wYWxfZW5hYmxlX2Rpc2FibGVfc2hhZG93X21icik7CisKK2ludCBvcGFsX3Nh dmUoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSwKKwkgICAg ICB2b2lkICpzYm10X2RhdGEsIHNlZF9zZWNfc3VibWl0ICpzdWJtaXRfZm4pCit7CisJdm9pZCAq ZnVuY19kYXRhWzNdID0geyBOVUxMIH07CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisJCWNvbnN0 IG9wYWxfc3RlcCBfYXV0aF9mdW5jc1tdID0geworCQlvcGFsX2Rpc2NvdmVyeTAsCisJCXN0YXJ0 X2F1dGhfb3BhbF9zZXNzaW9uLAorCQlxdWVyeV9sb2NraW5nX3JhbmdlLAorCQllbmRfb3BhbF9z ZXNzaW9uLAorCQlvcGFsX3JlZ2lzdGVyX2NvbnQsCisJCU5VTEwKKwl9OworCWludCByZXQ7CisK KwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIGtleS0+b3BhbF9sa191bmxrLmtl eS5sciwgZmFsc2UpOworCWlmICghZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKwlyZXQgPSBzZXR1 cF9vcGFsX2RldihiZGV2LCBkZXYsIF9hdXRoX2Z1bmNzLCAma2V5LT5vcGFsX2xrX3VubGsua2V5 LAorCQkJICAgICBzYm10X2RhdGEsIHN1Ym1pdF9mbik7CisJaWYgKHJldCkKKwkJZ290byBlcnJv cl9yZXR1cm47CisKKwlkZXYtPm51bV9mdW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRhID0g ZnVuY19kYXRhOworCWRldi0+ZnVuY19kYXRhWzFdID0gJmtleS0+b3BhbF9sa191bmxrLmF1dGhv cml0eTsKKwlkZXYtPmxrdWwgPSBrZXktPm9wYWxfbGtfdW5sazsKKworCXJldCA9IG5leHQoZGV2 KTsKKworIGVycm9yX3JldHVybjoKKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJ cmV0dXJuIHJldDsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF9zYXZlKTsKKworaW50IG9wYWxfYWRk X3VzZXJfdG9fbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtl eSwKKwkJCXZvaWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sKKwl2 b2lkICpmdW5jX2RhdGFbM10gPSB7IE5VTEwgfTsKKwlzdHJ1Y3Qgb3BhbF9kZXYgKmRldjsKKwkJ Y29uc3Qgb3BhbF9zdGVwIGZ1bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRf YWRtaW4xTFNQX29wYWxfc2Vzc2lvbiwKKwkJYWRkX3VzZXJfdG9fbHIsCisJCWVuZF9vcGFsX3Nl c3Npb24sCisJCU5VTEwKKwl9OworCWludCByZXQ7CisKKwlpZiAoIWJkZXYgfHwgIWJkZXYtPmJk X2Rpc2spIHsKKwkJcHJfZXJyKCJDYW4ndCBhc3NpZ24gdXNlciB0byBMUiB3aXRob3V0IGJhY2tp bmcgZGlza1xuIik7CisJCXJldHVybiAtRUZBVUxUOworCX0KKwlpZiAoa2V5LT5vcGFsX2xrX3Vu bGsubF9zdGF0ZSAhPSBPUEFMX1JPICYmCisJICAgIGtleS0+b3BhbF9sa191bmxrLmxfc3RhdGUg IT0gT1BBTF9SVykgeworCQlwcl9lcnIoIkxvY2tpbmcgc3RhdGUgd2FzIG5vdCBSTyBvciBSV1xu Iik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKwlpZiAoa2V5LT5vcGFsX2xrX3VubGsuYXV0aG9y aXR5LndobyA8IE9QQUxfVVNFUjEgJiYKKwkgICAga2V5LT5vcGFsX2xrX3VubGsuYXV0aG9yaXR5 LndobyA+IE9QQUxfVVNFUjkpIHsKKwkJcHJfZXJyKCJBdXRob3JpdHkgd2FzIG5vdCB3aXRoaW4g dGhlIHJhbmdlIG9mIHVzZXJzOiAlZFxuIiwKKwkJICAgICAgIGtleS0+b3BhbF9sa191bmxrLmF1 dGhvcml0eS53aG8pOworCQlyZXR1cm4gLUVJTlZBTDsKKwl9CisJaWYgKGtleS0+b3BhbF9sa191 bmxrLmF1dGhvcml0eS5TVU0pIHsKKwkJcHJfZXJyKCIlcyBub3Qgc3VwcG9ydGVkIGluIFNVTS4g VXNlIHNldHVwIGxvY2tpbmcgcmFuZ2VcbiIsCisJCSAgICAgICBfX2Z1bmNfXyk7CisJCXJldHVy biAtRUlOVkFMOworCX0KKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwga2V5 LT5vcGFsX2xrX3VubGsua2V5LmxyLCB0cnVlKTsKKwlpZiAoIWRldikKKwkJcmV0dXJuIC1FTk9N RU07CisJcmV0ID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBmdW5jcywgJmtleS0+b3BhbF9s a191bmxrLmtleSwKKwkJCQkgICAgc2JtdF9kYXRhLCBzdWJtaXRfZm4pOworCWlmIChyZXQpCisJ CWdvdG8gZXJyb3JfcmV0dXJuOworCisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYtPmZ1 bmNfZGF0YSA9IGZ1bmNfZGF0YTsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9ICZrZXktPm9wYWxfbGtf dW5sazsKKworCXJldCA9IG5leHQoZGV2KTsKKworIGVycm9yX3JldHVybjoKKwlyZW1vdmVfYW5k X2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJldDsKKworfQorRVhQT1JUX1NZTUJPTChv cGFsX2FkZF91c2VyX3RvX2xyKTsKKworaW50IG9wYWxfcmV2ZXJ0dHBlcihzdHJ1Y3QgYmxvY2tf ZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5LAorCQkgICAgdm9pZCAqc2JtdF9kYXRh LCBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKQoreworCWNvbnN0IG9wYWxfc3RlcCByZXZlcnRf ZnVuY3NbXSA9IHsKKwkJb3BhbF9kaXNjb3ZlcnkwLAorCQlzdGFydF9TSURBU1Bfb3BhbF9zZXNz aW9uLAorCQlyZXZlcnRfdHBlciwgLyogY29udHJvbGxlciB3aWxsIHRlcm1pbmF0ZSBzZXNzaW9u ICovCisJCU5VTEwsCisJfTsKKworCXJldHVybiBvcGFsX3JlZ2lzdGVyKGJkZXYsICZrZXktPm9w YWwsIHJldmVydF9mdW5jcywKKwkJCSAgICAgc2JtdF9kYXRhLCBzdWJtaXRfZm4pOworfQorRVhQ T1JUX1NZTUJPTChvcGFsX3JldmVydHRwZXIpOworCisvKiBUaGVzZSBhcmUgZ2xvYmFsJ2QgYmVj YXVzZSBib3RoIGxvY2tfdW5sb2NrX2ludGVybmFsCisgKiBhbmQgb3BhbF91bmxvY2tfZnJvbV9z dXNwZW5kIG5lZWQgdGhlbS4KKyAqLworY29uc3Qgb3BhbF9zdGVwIHVsa19mdW5jc19TVU1bXSA9 IHsKKwlvcGFsX2Rpc2NvdmVyeTAsCisJc3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJbG9ja191 bmxvY2tfbG9ja2luZ19yYW5nZV9TVU0sCisJZW5kX29wYWxfc2Vzc2lvbiwKKwlOVUxMCit9Owor Y29uc3Qgb3BhbF9zdGVwIF91bmxvY2tfZnVuY3NbXSA9IHsKKwlvcGFsX2Rpc2NvdmVyeTAsCisJ c3RhcnRfYXV0aF9vcGFsX3Nlc3Npb24sCisJbG9ja191bmxvY2tfbG9ja2luZ19yYW5nZSwKKwll bmRfb3BhbF9zZXNzaW9uLAorCU5VTEwKK307CitpbnQgb3BhbF9sb2NrX3VubG9jayhzdHJ1Y3Qg YmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5LAorICAgICAgICAgICAgICAg ICAgICAgdm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKQoreworCXZv aWQgKmZ1bmNfZGF0YVszXSA9IHsgTlVMTCB9OworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCWlu dCByZXQ7CisKKwlpZiAoa2V5LT5vcGFsX2xrX3VubGsuYXV0aG9yaXR5LndobyA8IE9QQUxfQURN SU4xIHx8CisJICAgIGtleS0+b3BhbF9sa191bmxrLmF1dGhvcml0eS53aG8gPiBPUEFMX1VTRVI5 KQorCQlyZXR1cm4gLUVJTlZBTDsKKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRl diwga2V5LT5vcGFsX2xrX3VubGsua2V5LmxyLCB0cnVlKTsKKwlpZiAoIWRldikKKwkJcmV0dXJu IC1FTk9NRU07CisKKwlpZiAoa2V5LT5vcGFsX2xrX3VubGsuYXV0aG9yaXR5LlNVTSkKKwkJcmV0 ID0gc2V0dXBfb3BhbF9kZXYoYmRldiwgZGV2LCB1bGtfZnVuY3NfU1VNLAorCQkJCSAgICAgJmtl eS0+b3BhbF9sa191bmxrLmtleSwKKwkJCQkgICAgIHNibXRfZGF0YSwgc3VibWl0X2ZuKTsKKwll bHNlCisJCXJldCA9IHNldHVwX29wYWxfZGV2KGJkZXYsIGRldiwgX3VubG9ja19mdW5jcywKKwkJ CQkgICAgICZrZXktPm9wYWxfbGtfdW5say5rZXksCisJCQkJICAgICBzYm10X2RhdGEsIHN1Ym1p dF9mbik7CisJaWYgKHJldCkKKwkJZ290byBlcnJvcl9yZXR1cm47CisKKwlkZXYtPm51bV9mdW5j X2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOworCWRldi0+ZnVuY19kYXRh WzFdID0gJmtleS0+b3BhbF9sa191bmxrLmF1dGhvcml0eTsKKwlkZXYtPmZ1bmNfZGF0YVsyXSA9 ICZrZXktPm9wYWxfbGtfdW5sazsKKworCXJldCA9IG5leHQoZGV2KTsKKworIGVycm9yX3JldHVy bjoKKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJldDsKK30KK0VY UE9SVF9TWU1CT0wob3BhbF9sb2NrX3VubG9jayk7CisKK2ludCBvcGFsX3Rha2Vfb3duZXJzaGlw KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXksCisJCQl2b2lk ICpzYm10X2RhdGEsIHNlZF9zZWNfc3VibWl0ICpzdWJtaXRfZm4pCit7CisJY29uc3Qgb3BhbF9z dGVwIG93bmVyX2Z1bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYW55Ym9k eUFTUF9vcGFsX3Nlc3Npb24sCisJCWdldF9tc2lkX2NwaW5fcGluLAorCQllbmRfb3BhbF9zZXNz aW9uLAorCQlzdGFydF9TSURBU1Bfb3BhbF9zZXNzaW9uLAorCQlzZXRfc2lkX2NwaW5fcGluLAor CQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMCisJfTsKKworCXJldHVybiBvcGFsX3JlZ2lzdGVy KGJkZXYsICZrZXktPm9wYWwsIG93bmVyX2Z1bmNzLCBzYm10X2RhdGEsCisJCQkgICAgIHN1Ym1p dF9mbik7Cit9CitFWFBPUlRfU1lNQk9MKG9wYWxfdGFrZV9vd25lcnNoaXApOworCitpbnQgb3Bh bF9hY3RpdmF0ZV9sc3Aoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkg KmtleSwKKwkJICAgICAgdm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2Zu KQoreworCWNvbnN0IG9wYWxfc3RlcCBhY3RpdmVfZnVuY3NbXSA9IHsKKwkJb3BhbF9kaXNjb3Zl cnkwLAorCQlzdGFydF9TSURBU1Bfb3BhbF9zZXNzaW9uLCAvKiBPcGVuIHNlc3Npb24gYXMgU0lE IGF1dGggKi8KKwkJZ2V0X2xzcF9saWZlY3ljbGUsCisJCWFjdGl2YXRlX2xzcCwKKwkJZW5kX29w YWxfc2Vzc2lvbiwKKwkJTlVMTAorCX07CisJc3RydWN0IG9wYWxfZGV2ICpkZXY7CisJaW50IHJl dDsKKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwga2V5LT5vcGFsLmxyLCB0 cnVlKTsKKwlpZiAoIWRldikKKwkJcmV0dXJuIC1FTk9NRU07CisJcmV0ID0gc2V0dXBfb3BhbF9k ZXYoYmRldiwgZGV2LCBhY3RpdmVfZnVuY3MsICZrZXktPm9wYWwsCisJCQkgICAgIHNibXRfZGF0 YSwgc3VibWl0X2ZuKTsKKwlpZiAocmV0KQorCQlnb3RvIGVycm9yX3JldHVybjsKKworCXJldCA9 IG5leHQoZGV2KTsKKworIGVycm9yX3JldHVybjoKKwlyZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2 KGRldik7CisJcmV0dXJuIHJldDsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF9hY3RpdmF0ZV9sc3Ap OworCitpbnQgb3BhbF9zZXR1cF9sb2NraW5nX3JhbmdlKHN0cnVjdCBibG9ja19kZXZpY2UgKmJk ZXYsIHN0cnVjdCBzZWRfa2V5ICpwdywKKwkJCSAgICAgdm9pZCAqc2JtdF9kYXRhLCBzZWRfc2Vj X3N1Ym1pdCAqc3VibWl0X2ZuKQoreworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXZvaWQgKmRh dGFbM10gPSB7IE5VTEwgfTsKKwljb25zdCBvcGFsX3N0ZXAgbHJfZnVuY3NbXSA9IHsKKwkJb3Bh bF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hdXRoX29wYWxfc2Vzc2lvbiwKKwkJc2V0dXBfbG9ja2lu Z19yYW5nZSwKKwkJZW5kX29wYWxfc2Vzc2lvbiwKKwkJTlVMTCwKKwl9OworCWludCByZXQ7CisK KwlkZXYgPSBnZXRfb3JfY3JlYXRlX29wYWxfZGV2KGJkZXYsIHB3LT5vcGFsX2xycy5rZXkubHIs IHRydWUpOworCWlmICghZGV2KQorCQlyZXR1cm4gLUVOT01FTTsKKworCXJldCA9IHNldHVwX29w YWxfZGV2KGJkZXYsIGRldiwgbHJfZnVuY3MsICZwdy0+b3BhbF9scnMua2V5LAorCQkJICAgICBz Ym10X2RhdGEsIHN1Ym1pdF9mbik7CisJaWYgKHJldCkKKwkJZ290byBlcnJvcl9yZXR1cm47CisK KwlkZXYtPmZ1bmNfZGF0YSA9IGRhdGE7CisJZGV2LT5udW1fZnVuY19kYXRhID0gMzsKKwlkZXYt PmZ1bmNfZGF0YVsxXSA9ICZwdy0+b3BhbF9scnMud2hvOworCWRldi0+ZnVuY19kYXRhWzJdID0g JnB3LT5vcGFsX2xyczsKKworCXJldCA9IG5leHQoZGV2KTsKKworIGVycm9yX3JldHVybjoKKwly ZW1vdmVfYW5kX2NsZWFuX29wYWxfZGV2KGRldik7CisJcmV0dXJuIHJldDsKK30KK0VYUE9SVF9T WU1CT0wob3BhbF9zZXR1cF9sb2NraW5nX3JhbmdlKTsKKworaW50IG9wYWxfc2V0X25ld19wdyhz dHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqcHcsCisJCSAgICB2b2lk ICpzYm10X2RhdGEsIHNlZF9zZWNfc3VibWl0ICpzdWJtaXRfZm4pCit7CisJY29uc3Qgb3BhbF9z dGVwIHB3X2Z1bmNzW10gPSB7CisJCW9wYWxfZGlzY292ZXJ5MCwKKwkJc3RhcnRfYXV0aF9vcGFs X3Nlc3Npb24sCisJCXNldF9uZXdfcHcsCisJCWVuZF9vcGFsX3Nlc3Npb24sCisJCU5VTEwKKwl9 OworCXN0cnVjdCBvcGFsX2RldiAqZGV2OworCXZvaWQgKmRhdGFbM10gPSB7IE5VTEwgfTsKKwlp bnQgcmV0OworCisJaWYgKHB3LT5zZWRfdHlwZSAhPSBPUEFMX1BXKQorCQlyZXR1cm4gLUVJTlZB TDsKKworCWlmIChwdy0+b3BhbF9wdy53aG8ud2hvIDwgT1BBTF9BRE1JTjEgfHwKKwkgICAgcHct Pm9wYWxfcHcud2hvLndobyA+IE9QQUxfVVNFUjkpCisJCXJldHVybiAtRUlOVkFMOworCisJZGV2 ID0gZ2V0X29yX2NyZWF0ZV9vcGFsX2RldihiZGV2LCBwdy0+b3BhbF9wdy5jdXJyZW50X3Bpbi5s ciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJldHVybiAtRU5PTUVNOworCisJcmV0ID0gc2V0dXBf b3BhbF9kZXYoYmRldiwgZGV2LCBwd19mdW5jcywKKwkJCSAgICAgJnB3LT5vcGFsX3B3LmN1cnJl bnRfcGluLAorCQkJICAgICBzYm10X2RhdGEsIHN1Ym1pdF9mbik7CisJaWYgKHJldCkKKwkJZ290 byBlcnJvcl9yZXR1cm47CisKKwlkZXYtPm51bV9mdW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19k YXRhID0gZGF0YTsKKwlkZXYtPmZ1bmNfZGF0YVsxXSA9ICh2b2lkICopICZwdy0+b3BhbF9wdy53 aG87CisJZGV2LT5mdW5jX2RhdGFbMl0gPSAodm9pZCAqKSAmcHctPm9wYWxfcHc7CisKKwlyZXQg PSBuZXh0KGRldik7CisKKyBlcnJvcl9yZXR1cm46CisJcmVtb3ZlX2FuZF9jbGVhbl9vcGFsX2Rl dihkZXYpOworCXJldHVybiByZXQ7Cit9CitFWFBPUlRfU1lNQk9MKG9wYWxfc2V0X25ld19wdyk7 CisKK2ludCBvcGFsX2FjdGl2YXRlX3VzZXIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3Ry dWN0IHNlZF9rZXkgKnB3LAorCQkgICAgICAgdm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1p dCAqc3VibWl0X2ZuKQoreworCWNvbnN0IG9wYWxfc3RlcCBhY3RfZnVuY3NbXSA9IHsKKwkJb3Bh bF9kaXNjb3ZlcnkwLAorCQlzdGFydF9hZG1pbjFMU1Bfb3BhbF9zZXNzaW9uLAorCQlpbnRlcm5h bF9hY3RpdmF0ZV91c2VyLAorCQllbmRfb3BhbF9zZXNzaW9uLAorCQlOVUxMCisJfTsKKwlzdHJ1 Y3Qgb3BhbF9kZXYgKmRldjsKKwl2b2lkICpkYXRhWzNdID0geyBOVUxMIH07CisJaW50IHJldDsK KworCWlmIChwdy0+c2VkX3R5cGUgIT0gT1BBTF9BQ1RfVVNSKSB7CisJCXByX2VycigiU2VkIHR5 cGUgd2FzIG5vdCBhY3QgdXNlclxuIik7CisJCXJldHVybiAtRUlOVkFMOworCX0KKworCS8qIFdl IGNhbid0IGFjdGl2YXRlIEFkbWluMSBpdCdzIGFjdGl2ZSBhcyBtYW51ZmFjdHVyZWQgKi8KKwlp ZiAocHctPm9wYWxfYWN0Lndoby53aG8gPCBPUEFMX1VTRVIxICYmCisJICAgIHB3LT5vcGFsX2Fj dC53aG8ud2hvID4gT1BBTF9VU0VSOSkgeworCQlwcl9lcnIoIldobyB3YXMgbm90IGEgdmFsaWQg dXNlcjogJWQgXG4iLCBwdy0+b3BhbF9hY3Qud2hvLndobyk7CisJCXJldHVybiAtRUlOVkFMOwor CX0KKworCWRldiA9IGdldF9vcl9jcmVhdGVfb3BhbF9kZXYoYmRldiwgcHctPm9wYWxfYWN0Lmtl eS5sciwgdHJ1ZSk7CisJaWYgKCFkZXYpCisJCXJldHVybiAtRU5PTUVNOworCisJcmV0ID0gc2V0 dXBfb3BhbF9kZXYoYmRldiwgZGV2LCBhY3RfZnVuY3MsICZwdy0+b3BhbF9hY3Qua2V5LAorCQkJ ICAgICBzYm10X2RhdGEsIHN1Ym1pdF9mbik7CisJaWYgKHJldCkKKwkJZ290byBlcnJvcl9yZXR1 cm47CisKKwlkZXYtPm51bV9mdW5jX2RhdGEgPSAzOworCWRldi0+ZnVuY19kYXRhID0gZGF0YTsK KwlkZXYtPmZ1bmNfZGF0YVsxXSA9ICZwdy0+b3BhbF9hY3Q7CisJZGV2LT5mdW5jX2RhdGFbMl0g PSAmcHctPm9wYWxfYWN0OworCisJcmV0ID0gbmV4dChkZXYpOworCisgZXJyb3JfcmV0dXJuOgor CXJlbW92ZV9hbmRfY2xlYW5fb3BhbF9kZXYoZGV2KTsKKwlyZXR1cm4gcmV0OworCit9CitFWFBP UlRfU1lNQk9MKG9wYWxfYWN0aXZhdGVfdXNlcik7CisKK2ludCBvcGFsX3VubG9ja19mcm9tX3N1 c3BlbmQoc3RydWN0IG9wYWxfc3VzcGVuZF91bmxrICpkYXRhKQoreworCWludCBtYWptaW4gPSBk YXRhLT5kZXY7CisJc3RydWN0IG9wYWxfZGV2ICppdGVyLCAqZGV2ID0gTlVMTDsKKwl2b2lkICpm dW5jX2RhdGFbM10gPSB7IE5VTEwgfTsKKwl1OCBjb3VudCA9IDA7CisJc3RydWN0IG9wYWxfZGV2 ICp0b2RvWzY0XSA9IHsgTlVMTCB9OworCWludCByZXQgPSAwOworCWJvb2wgd2FzX2ZhaWx1cmUg PSBmYWxzZTsKKworCXNwaW5fbG9jaygmbGlzdF9zcGlubG9jayk7CisJbGlzdF9mb3JfZWFjaF9l bnRyeShpdGVyLCAmb3BhbF9saXN0LCBub2RlKSB7CisJCWlmIChNQUpPUihpdGVyLT5tYWptaW4p ICE9IE1BSk9SKG1ham1pbikgfHwKKwkJICAgIE1JTk9SKGl0ZXItPm1ham1pbikgIT0gTUlOT1Io bWFqbWluKSkKKwkJCWNvbnRpbnVlOworCisJCWlmIChhdG9taWNfYWRkX3VubGVzcygmaXRlci0+ aW5fdXNlLCAxLCAxKSkgeworCQkJaWYgKGNvdW50IDwgNjQpCisJCQkJdG9kb1tjb3VudCsrXSA9 IGl0ZXI7CisJCQllbHNlCisJCQkJYnJlYWs7CisJCX0KKwl9CisJc3Bpbl91bmxvY2soJmxpc3Rf c3BpbmxvY2spOworCisJd2hpbGUgKGNvdW50KSB7CisJCWRldiA9IHRvZG9bLS1jb3VudF07CisJ CWRldi0+ZnVuY19kYXRhID0gZnVuY19kYXRhOworCQlkZXYtPnJlc3VtZV9mcm9tX3N1c3BlbmQg PSB0cnVlOworCQlkZXYtPnJlc3VtZV9kYXRhID0gZGF0YTsKKwkJZGV2LT5lcnJvcl9jYiA9IGVu ZF9vcGFsX3Nlc3Npb25fZXJyb3I7CisJCWRldi0+ZXJyb3JfY2JfZGF0YSA9IGRldjsKKwkJZGV2 LT5zdGF0ZSA9IDA7CisJCWlmIChkZXYtPmxrdWwuYXV0aG9yaXR5LlNVTSkKKwkJCWRldi0+ZnVu Y3MgPSB1bGtfZnVuY3NfU1VNOworCQllbHNlCisJCQlkZXYtPmZ1bmNzID0gX3VubG9ja19mdW5j czsKKwkJZGV2LT5UU04gPSAwOworCQlkZXYtPkhTTiA9IDA7CisJCWRldi0+ZnVuY19kYXRhWzJd ID0gJmRldi0+bGt1bDsKKwkJZGV2LT5mdW5jX2RhdGFbMV0gPSAmZGV2LT5sa3VsLmF1dGhvcml0 eTsKKwkJcmV0ID0gbmV4dChkZXYpOworCQlpZiAocmV0KQorCQkJd2FzX2ZhaWx1cmUgPSB0cnVl OworCQl1bmxvY2tfc3VzcGVuZF9maW5hbChkZXYpOworCX0KKwlyZXR1cm4gd2FzX2ZhaWx1cmUg PyAxIDogMDsKK30KK0VYUE9SVF9TWU1CT0wob3BhbF91bmxvY2tfZnJvbV9zdXNwZW5kKTsKZGlm ZiAtLWdpdCBhL2Jsb2NrL3NlZC1vcGFsX2ludGVybmFsLmggYi9ibG9jay9zZWQtb3BhbF9pbnRl cm5hbC5oCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjEyMzY5ZWIKLS0tIC9k ZXYvbnVsbAorKysgYi9ibG9jay9zZWQtb3BhbF9pbnRlcm5hbC5oCkBAIC0wLDAgKzEsNjAxIEBA CisvKgorICogQ29weXJpZ2h0IMKpIDIwMTYgSW50ZWwgQ29ycG9yYXRpb24KKyAqCisgKiBBdXRo b3JzOgorICogICAgUmFmYWVsIEFudG9nbm9sbGkgPHJhZmFlbC5hbnRvZ25vbGxpQGludGVsLmNv bT4KKyAqICAgIFNjb3R0ICBCYXVlciAgICAgIDxzY290dC5iYXVlckBpbnRlbC5jb20+CisgKgor ICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0 IGFuZC9vciBtb2RpZnkgaXQKKyAqIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB0 aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UsCisgKiB2ZXJzaW9uIDIsIGFzIHB1Ymxpc2hl ZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBp cyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVQK KyAqIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1F UkNIQU5UQUJJTElUWSBvcgorICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBT ZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvcgorICogbW9yZSBkZXRhaWxzLgor ICovCisKKyNpZm5kZWYgX05WTUVfT1BBTF9JTlRFUk5BTF9ICisjZGVmaW5lIF9OVk1FX09QQUxf SU5URVJOQUxfSAorCisjaW5jbHVkZSA8bGludXgva2V5LXR5cGUuaD4KKyNpbmNsdWRlIDxrZXlz L3VzZXItdHlwZS5oPgorCisjZGVmaW5lIERUQUVSUk9SX05PX01FVEhPRF9TVEFUVVMgMHg4OQor I2RlZmluZSBHRU5FUklDX0hPU1RfU0VTU0lPTl9OVU0gMHg0MQorCisKKworLyoKKyAqIERlcml2 ZWQgZnJvbToKKyAqIFRDR19TdG9yYWdlX0FyY2hpdGVjdHVyZV9Db3JlX1NwZWNfdjIuMDFfcjEu MDAKKyAqIFNlY3Rpb246IDUuMS41IE1ldGhvZCBTdGF0dXMgQ29kZXMKKyAqLworc3RhdGljIGNv bnN0IGNoYXIgKm9wYWxfZXJyb3JzW10gPSB7CisJIlN1Y2Nlc3MiLAorCSJOb3QgQXV0aG9yaXpl ZCIsCisJIlVua25vd24gRXJyb3IiLAorCSJTUCBCdXN5IiwKKwkiU1AgRmFpbGVkIiwKKwkiU1Ag RGlzYWJsZWQiLAorCSJTUCBGcm96ZW4iLAorCSJObyBTZXNzaW9ucyBBdmFpbGFibGUiLAorCSJV bmlxdWVuZXNzIENvbmZsaWN0IiwKKwkiSW5zdWZmaWNpZW50IFNwYWNlIiwKKwkiSW5zdWZmaWNp ZW50IFJvd3MiLAorCSJJbnZhbGlkIEZ1bmN0aW9uIiwKKwkiSW52YWxpZCBQYXJhbWV0ZXIiLAor CSJJbnZhbGlkIFJlZmVyZW5jZSIsCisJIlVua25vd24gRXJyb3IiLAorCSJUUEVSIE1hbGZ1bmN0 aW9uIiwKKwkiVHJhbnNhY3Rpb24gRmFpbHVyZSIsCisJIlJlc3BvbnNlIE92ZXJmbG93IiwKKwki QXV0aG9yaXR5IExvY2tlZCBPdXQiLAorfTsKKworc3RhdGljIGNvbnN0IGNoYXIgKm9wYWxfZXJy b3JfdG9faHVtYW4oaW50IGVycm9yKQoreworCWlmIChlcnJvciA9PSAweDNmKQorCQlyZXR1cm4g IkZhaWxlZCI7CisKKwlpZiAoZXJyb3IgPj0gQVJSQVlfU0laRShvcGFsX2Vycm9ycykgfHwgZXJy b3IgPCAwKQorCQlyZXR1cm4gIlVua25vd24gRXJyb3IiOworCisJcmV0dXJuIG9wYWxfZXJyb3Jz W2Vycm9yXTsKK30KKworLyoKKyAqIFVzZXIgSURzIHVzZWQgaW4gdGhlIFRDRyBzdG9yYWdlIFNT Q3MKKyAqIERlcml2ZWQgZnJvbTogVENHX1N0b3JhZ2VfQXJjaGl0ZWN0dXJlX0NvcmVfU3BlY192 Mi4wMV9yMS4wMAorICogU2VjdGlvbjogNi4zIEFzc2lnbmVkIFVJRHMKKyAqLworc3RhdGljIGNv bnN0IHU4IE9QQUxVSURbXVs4XSA9IHsKKwkvKiB1c2VycyAqLworCisJLyogc2Vzc2lvbiBtYW5h Z2VtZW50ICAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwg MHhmZn0sCisJLyogc3BlY2lhbCAidGhpc1NQIiBzeW50YXggKi8KKwl7IDB4MDAsIDB4MDAsIDB4 MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEgfSwKKwkvKiBBZG1pbmlzdHJhdGl2ZSBT UCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMiwgMHgwNSwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMSB9 LAorCS8qIExvY2tpbmcgU1AgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDIsIDB4MDUsIDB4MDAsIDB4 MDAsIDB4MDAsIDB4MDIgfSwKKwkvKiBFTlRFUlBSSVNFIExvY2tpbmcgU1AgICovCisJeyAweDAw LCAweDAwLCAweDAyLCAweDA1LCAweDAwLCAweDAxLCAweDAwLCAweDAxIH0sCisJLyogYW55Ym9k eSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMSB9 LAorCS8qIFNJRCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgwMCwgMHgwMCwgMHgw MCwgMHgwNiB9LAorCS8qIEFETUlOMSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwOSwgMHgw MCwgMHgwMSwgMHgwMCwgMHgwMSB9LAorCS8qIFVTRVIxICovCisJeyAweDAwLCAweDAwLCAweDAw LCAweDA5LCAweDAwLCAweDAzLCAweDAwLCAweDAxIH0sCisJLyogVVNFUjIgKi8KKwl7IDB4MDAs IDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDMsIDB4MDAsIDB4MDIgfSwKKwkvKiBQU0lEIHVz ZXIgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAsIDB4MDEsIDB4ZmYsIDB4MDEg fSwKKwkvKiBCYW5kTWFzdGVyIDAgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDksIDB4MDAs IDB4MDAsIDB4ODAsIDB4MDEgfSwKKwkgLyogRXJhc2VNYXN0ZXIgKi8KKwl7IDB4MDAsIDB4MDAs IDB4MDAsIDB4MDksIDB4MDAsIDB4MDAsIDB4ODQsIDB4MDEgfSwKKworCS8qIHRhYmxlcyAqLwor CisJLyogTG9ja2luZ19HbG9iYWxSYW5nZSAqLworCXsgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMiwg MHgwMCwgMHgwMCwgMHgwMCwgMHgwMSB9LAorCS8qIEFDRV9Mb2NraW5nX1JhbmdlX1NldF9SZExv Y2tlZCBVSUQgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDgsIDB4MDAsIDB4MDMsIDB4RTAs IDB4MDEgfSwKKwkvKiBBQ0VfTG9ja2luZ19SYW5nZV9TZXRfV3JMb2NrZWQgVUlEICovCisJeyAw eDAwLCAweDAwLCAweDAwLCAweDA4LCAweDAwLCAweDAzLCAweEU4LCAweDAxIH0sCisJLyogTUJS IENvbnRyb2wgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDgsIDB4MDMsIDB4MDAsIDB4MDAsIDB4MDAs IDB4MDEgfSwKKwkvKiBTaGFkb3cgTUJSICovCisJeyAweDAwLCAweDAwLCAweDA4LCAweDA0LCAw eDAwLCAweDAwLCAweDAwLCAweDAwIH0sCisJLyogQVVUSE9SSVRZX1RBQkxFICovCisJeyAweDAw LCAweDAwLCAweDAwLCAweDA5LCAweDAwLCAweDAwLCAweDAwLCAweDAwfSwKKwkvKiBDX1BJTl9U QUJMRSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwQiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgw MH0sCisJLyogT1BBTCBMb2NraW5nIEluZm8gKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDgsIDB4MDEs IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDEgfSwKKwkvKiBFbnRlcnByaXNlIExvY2tpbmcgSW5mbyAq LworCXsgMHgwMCwgMHgwMCwgMHgwOCwgMHgwMSwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCB9LAor CisJLyogQ19QSU5fVEFCTEUgb2JqZWN0IElEJ3MgKi8KKworCS8qIENfUElOX01TSUQgKi8KKwl7 IDB4MDAsIDB4MDAsIDB4MDAsIDB4MEIsIDB4MDAsIDB4MDAsIDB4ODQsIDB4MDJ9LAorCS8qIENf UElOX1NJRCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwQiwgMHgwMCwgMHgwMCwgMHgwMCwg MHgwMX0sCisJIC8qIENfUElOX0FETUlOMSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwQiwg MHgwMCwgMHgwMSwgMHgwMCwgMHgwMX0sCisKKwkvKiBoYWxmIFVJRCdzIChvbmx5IGZpcnN0IDQg Ynl0ZXMgdXNlZCkgKi8KKworCS8qIEhhbGYtVUlEIOKAkyBBdXRob3JpdHlfb2JqZWN0X3JlZiAq LworCXsgMHgwMCwgMHgwMCwgMHgwQywgMHgwNSwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiB9LAor CS8qIEhhbGYtVUlEIOKAkyBCb29sZWFuIEFDRSAqLworCXsgMHgwMCwgMHgwMCwgMHgwNCwgMHgw RSwgMHhmZiwgMHhmZiwgMHhmZiwgMHhmZiB9LAorCisJLyogc3BlY2lhbCB2YWx1ZSBmb3Igb21p dHRlZCBvcHRpb25hbCBwYXJhbWV0ZXIgKi8KKworCS8qIEhFWEZGIGZvciBvbWl0dGVkICovCisJ eyAweGZmLCAweGZmLCAweGZmLCAweGZmLCAweGZmLCAweGZmLCAweGZmLCAweGZmfSwKK307Citz dGF0aWMgY29uc3Qgc2l6ZV90IE9QQUxfVUlEX0xFTkdUSCA9IDg7CitzdGF0aWMgY29uc3Qgc2l6 ZV90IE9QQUxfTVNJRF9LRVlMRU4gPSAxNTsKK3N0YXRpYyBjb25zdCBzaXplX3QgT1BBTF9VSURf TEVOR1RIX0hBTEYgPSA0OworCisKKy8qIEVudW0gdG8gaW5kZXggT1BBTFVJRCBhcnJheSAqLwor ZW51bSBPUEFMX1VJRCB7CisJLyogdXNlcnMgKi8KKwlPUEFMX1NNVUlEX1VJRCwKKwlPUEFMX1RI SVNTUF9VSUQsCisJT1BBTF9BRE1JTlNQX1VJRCwKKwlPUEFMX0xPQ0tJTkdTUF9VSUQsCisJT1BB TF9FTlRFUlBSSVNFX0xPQ0tJTkdTUF9VSUQsCisJT1BBTF9BTllCT0RZX1VJRCwKKwlPUEFMX1NJ RF9VSUQsCisJT1BBTF9BRE1JTjFfVUlELAorCU9QQUxfVVNFUjFfVUlELAorCU9QQUxfVVNFUjJf VUlELAorCU9QQUxfUFNJRF9VSUQsCisJT1BBTF9FTlRFUlBSSVNFX0JBTkRNQVNURVIwX1VJRCwK KwlPUEFMX0VOVEVSUFJJU0VfRVJBU0VNQVNURVJfVUlELAorCS8qIHRhYmxlcyAqLworCU9QQUxf TE9DS0lOR1JBTkdFX0dMT0JBTCwKKwlPUEFMX0xPQ0tJTkdSQU5HRV9BQ0VfUkRMT0NLRUQsCisJ T1BBTF9MT0NLSU5HUkFOR0VfQUNFX1dSTE9DS0VELAorCU9QQUxfTUJSQ09OVFJPTCwKKwlPUEFM X01CUiwKKwlPUEFMX0FVVEhPUklUWV9UQUJMRSwKKwlPUEFMX0NfUElOX1RBQkxFLAorCU9QQUxf TE9DS0lOR19JTkZPX1RBQkxFLAorCU9QQUxfRU5URVJQUklTRV9MT0NLSU5HX0lORk9fVEFCTEUs CisJLyogQ19QSU5fVEFCTEUgb2JqZWN0IElEJ3MgKi8KKwlPUEFMX0NfUElOX01TSUQsCisJT1BB TF9DX1BJTl9TSUQsCisJT1BBTF9DX1BJTl9BRE1JTjEsCisJLyogaGFsZiBVSUQncyAob25seSBm aXJzdCA0IGJ5dGVzIHVzZWQpICovCisJT1BBTF9IQUxGX1VJRF9BVVRIT1JJVFlfT0JKX1JFRiwK KwlPUEFMX0hBTEZfVUlEX0JPT0xFQU5fQUNFLAorCS8qIG9taXR0ZWQgb3B0aW9uYWwgcGFyYW1l dGVyICovCisJT1BBTF9VSURfSEVYRkYsCit9OworCisvKgorICogVENHIFN0b3JhZ2UgU1NDIE1l dGhvZHMuCisgKiBEZXJpdmVkIGZyb206IFRDR19TdG9yYWdlX0FyY2hpdGVjdHVyZV9Db3JlX1Nw ZWNfdjIuMDFfcjEuMDAKKyAqIFNlY3Rpb246IDYuMyBBc3NpZ25lZCBVSURzCisgKi8KK3N0YXRp YyBjb25zdCB1OCBPUEFMTUVUSE9EW11bOF0gPSB7CisJLyogUHJvcGVydGllcyAqLworCXsgMHgw MCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHhmZiwgMHgwMSB9LAorCS8qIFNUQVJU U0VTU0lPTiAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwMCwgMHhmZiwg MHgwMiB9LAorCS8qIFJldmVydCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwg MHgwMCwgMHgwMiwgMHgwMiB9LAorCS8qIEFjdGl2YXRlICovCisJeyAweDAwLCAweDAwLCAweDAw LCAweDA2LCAweDAwLCAweDAwLCAweDAyLCAweDAzIH0sCisJLyogRW50ZXJwcmlzZSBHZXQgKi8K Kwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYgfSwKKwkv KiBFbnRlcnByaXNlIFNldCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgw MCwgMHgwMCwgMHgwNyB9LAorCS8qIE5FWFQgKi8KKwl7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDYs IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDggfSwKKwkvKiBFbnRlcnByaXNlIEF1dGhlbnRpY2F0ZSAq LworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgwMCwgMHgwYyB9LAor CS8qIEdldEFDTCAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgwMCwgMHgwMCwgMHgw MCwgMHgwZCB9LAorCS8qIEdlbktleSAqLworCXsgMHgwMCwgMHgwMCwgMHgwMCwgMHgwNiwgMHgw MCwgMHgwMCwgMHgwMCwgMHgxMCB9LAorCS8qIHJldmVydFNQICovCisJeyAweDAwLCAweDAwLCAw eDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDExIH0sCisJLyogR2V0ICovCisJeyAweDAw LCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDE2IH0sCisJLyogU2V0ICov CisJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAwLCAweDAwLCAweDE3IH0sCisJ LyogQXV0aGVudGljYXRlICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA2LCAweDAwLCAweDAw LCAweDAwLCAweDFjIH0sCisJLyogUmFuZG9tICovCisJeyAweDAwLCAweDAwLCAweDAwLCAweDA2 LCAweDAwLCAweDAwLCAweDA2LCAweDAxIH0sCisJLyogRXJhc2UgKi8KKwl7IDB4MDAsIDB4MDAs IDB4MDAsIDB4MDYsIDB4MDAsIDB4MDAsIDB4MDgsIDB4MDMgfSwKK307CitzdGF0aWMgY29uc3Qg c2l6ZV90IE9QQUxfTUVUSE9EX0xFTkdUSCA9IDg7CisKKy8qIEVudW0gZm9yIGluZGV4aW5nIHRo ZSBPUEFMTUVUSE9EIGFycmF5ICovCitlbnVtIE9QQUxfTUVUSE9EIHsKKwlPUEFMX1BST1BFUlRJ RVMsCisJT1BBTF9TVEFSVFNFU1NJT04sCisJT1BBTF9SRVZFUlQsCisJT1BBTF9BQ1RJVkFURSwK KwlPUEFMX0VHRVQsCisJT1BBTF9FU0VULAorCU9QQUxfTkVYVCwKKwlPUEFMX0VBVVRIRU5USUNB VEUsCisJT1BBTF9HRVRBQ0wsCisJT1BBTF9HRU5LRVksCisJT1BBTF9SRVZFUlRTUCwKKwlPUEFM X0dFVCwKKwlPUEFMX1NFVCwKKwlPUEFMX0FVVEhFTlRJQ0FURSwKKwlPUEFMX1JBTkRPTSwKKwlP UEFMX0VSQVNFLAorfTsKKworLyoKKyAqIFRva2VuIGRlZnMgZGVyaXZlZCBmcm9tOgorICogVENH X1N0b3JhZ2VfQXJjaGl0ZWN0dXJlX0NvcmVfU3BlY192Mi4wMV9yMS4wMAorICogMy4yLjIgRGF0 YSBTdHJlYW0gRW5jb2RpbmcKKyAqLworZW51bSBPUEFMX1JFU1BPTlNFX1RPS0VOIHsKKwlPUEFM X0RUQV9UT0tFTklEX0JZVEVTVFJJTkcgPSAweGUwLAorCU9QQUxfRFRBX1RPS0VOSURfU0lOVCA9 IDB4ZTEsCisJT1BBTF9EVEFfVE9LRU5JRF9VSU5UID0gMHhlMiwKKwlPUEFMX0RUQV9UT0tFTklE X1RPS0VOID0gMHhlMywgLyogYWN0dWFsIHRva2VuIGlzIHJldHVybmVkICovCisJT1BBTF9EVEFf VE9LRU5JRF9JTlZBTElEID0gMFgwCit9OworCitlbnVtIE9QQUxfVE9LRU4geworCS8qIEJvb2xl YW4gKi8KKwlPUEFMX1RSVUUgPSAweDAxLAorCU9QQUxfRkFMU0UgPSAweDAwLAorCU9QQUxfQk9P TEVBTl9FWFBSID0gMHgwMywKKwkvKiBjZWxsYmxvY2tzICovCisJT1BBTF9UQUJMRSA9IDB4MDAs CisJT1BBTF9TVEFSVFJPVyA9IDB4MDEsCisJT1BBTF9FTkRST1cgPSAweDAyLAorCU9QQUxfU1RB UlRDT0xVTU4gPSAweDAzLAorCU9QQUxfRU5EQ09MVU1OID0gMHgwNCwKKwlPUEFMX1ZBTFVFUyA9 IDB4MDEsCisJLyogYXV0aG9yaXR5IHRhYmxlICovCisJT1BBTF9QSU4gPSAweDAzLAorCS8qIGxv Y2tpbmcgdG9rZW5zICovCisJT1BBTF9SQU5HRVNUQVJUID0gMHgwMywKKwlPUEFMX1JBTkdFTEVO R1RIID0gMHgwNCwKKwlPUEFMX1JFQURMT0NLRU5BQkxFRCA9IDB4MDUsCisJT1BBTF9XUklURUxP Q0tFTkFCTEVEID0gMHgwNiwKKwlPUEFMX1JFQURMT0NLRUQgPSAweDA3LAorCU9QQUxfV1JJVEVM T0NLRUQgPSAweDA4LAorCU9QQUxfQUNUSVZFS0VZID0gMHgwQSwKKwkvKiBsb2NraW5nIGluZm8g dGFibGUgKi8KKwlPUEFMX01BWFJBTkdFUyA9IDB4MDQsCisJIC8qIG1iciBjb250cm9sICovCisJ T1BBTF9NQlJFTkFCTEUgPSAweDAxLAorCU9QQUxfTUJSRE9ORSA9IDB4MDIsCisJLyogcHJvcGVy dGllcyAqLworCU9QQUxfSE9TVFBST1BFUlRJRVMgPSAweDAwLAorCS8qIGF0b21zICovCisJT1BB TF9TVEFSVExJU1QgPSAweGYwLAorCU9QQUxfRU5ETElTVCA9IDB4ZjEsCisJT1BBTF9TVEFSVE5B TUUgPSAweGYyLAorCU9QQUxfRU5ETkFNRSA9IDB4ZjMsCisJT1BBTF9DQUxMID0gMHhmOCwKKwlP UEFMX0VORE9GREFUQSA9IDB4ZjksCisJT1BBTF9FTkRPRlNFU1NJT04gPSAweGZhLAorCU9QQUxf U1RBUlRUUkFOU0FDVE9OID0gMHhmYiwKKwlPUEFMX0VORFRSQU5TQUNUT04gPSAweGZDLAorCU9Q QUxfRU1QVFlBVE9NID0gMHhmZiwKKwlPUEFMX1dIRVJFID0gMHgwMCwKK307CisKKy8qIFVzZWZ1 bCB0aW55IGF0b21zLgorICogVXNlZnVsIGZvciB0YWJsZSBjb2x1bW5zIGV0YworICovCitlbnVt IE9QQUxfVElOWV9BVE9NIHsKKwlPUEFMX1RJTllfVUlOVF8wMCA9IDB4MDAsCisJT1BBTF9USU5Z X1VJTlRfMDEgPSAweDAxLAorCU9QQUxfVElOWV9VSU5UXzAyID0gMHgwMiwKKwlPUEFMX1RJTllf VUlOVF8wMyA9IDB4MDMsCisJT1BBTF9USU5ZX1VJTlRfMDQgPSAweDA0LAorCU9QQUxfVElOWV9V SU5UXzA1ID0gMHgwNSwKKwlPUEFMX1RJTllfVUlOVF8wNiA9IDB4MDYsCisJT1BBTF9USU5ZX1VJ TlRfMDcgPSAweDA3LAorCU9QQUxfVElOWV9VSU5UXzA4ID0gMHgwOCwKKwlPUEFMX1RJTllfVUlO VF8wOSA9IDB4MDksCisJT1BBTF9USU5ZX1VJTlRfMTAgPSAweDBhLAorCU9QQUxfVElOWV9VSU5U XzExID0gMHgwYiwKKwlPUEFMX1RJTllfVUlOVF8xMiA9IDB4MGMsCisJT1BBTF9USU5ZX1VJTlRf MTMgPSAweDBkLAorCU9QQUxfVElOWV9VSU5UXzE0ID0gMHgwZSwKKwlPUEFMX1RJTllfVUlOVF8x NSA9IDB4MGYsCit9OworCitlbnVtIE9QQUxfQVRPTV9XSURUSCB7CisJT1BBTF9XSURUSF9USU5Z LAorCU9QQUxfV0lEVEhfU0hPUlQsCisJT1BBTF9XSURUSF9NRURJVU0sCisJT1BBTF9XSURUSF9M T05HLAorCU9QQUxfV0lEVEhfVE9LRU4KK307CisKKy8qIExvY2tpbmcgc3RhdGUgZm9yIGEgbG9j a2luZyByYW5nZSAqLworZW51bSBPUEFMX0xPQ0tJTkdTVEFURSB7CisJT1BBTF9MT0NLSU5HX1JF QURXUklURSA9IDB4MDEsCisJT1BBTF9MT0NLSU5HX1JFQURPTkxZID0gMHgwMiwKKwlPUEFMX0xP Q0tJTkdfTE9DS0VEID0gMHgwMywKK307CisKKy8qCisgKiBTdHJ1Y3R1cmVzIHRvIGJ1aWxkIGFu ZCBkZWNvZGUgdGhlIE9wYWwgU1NDIG1lc3NhZ2VzCisgKiBmaWVsZHMgdGhhdCBhcmUgTk9UIHJl YWxseSBudW1lcmljIGFyZSBkZWZpbmVkIGFzIHU4W10gdG8KKyAqIGhlbHAgcmVkdWNlIHRoZSBl bmRpYW5uZXNzIGlzc3VlcworICovCisKKy8qIFBhY2tldHMgZGVyaXZlZCBmcm9tOgorICogVENH X1N0b3JhZ2VfQXJjaGl0ZWN0dXJlX0NvcmVfU3BlY192Mi4wMV9yMS4wMAorICogU2VjaW9uOiAz LjIuMyBDb21QYWNrZXRzLCBQYWNrZXRzICYgU3VicGFja2V0cworICovCisKKy8qIENvbW0gUGFj a2V0IChoZWFkZXIpIGZvciB0cmFuc21pc3Npb25zLiAqLworc3RydWN0IG9wYWxfY29tcGFja2V0 IHsKKwl1MzIgcmVzZXJ2ZWQwOworCXU4IGV4dGVuZGVkQ29tSURbNF07CisJdTMyIG91dHN0YW5k aW5nRGF0YTsKKwl1MzIgbWluVHJhbnNmZXI7CisJdTMyIGxlbmd0aDsKK307CisKKy8qIFBhY2tl dCBzdHJ1Y3R1cmUuICovCitzdHJ1Y3Qgb3BhbF9wYWNrZXQgeworCXUzMiBUU047CisJdTMyIEhT TjsKKwl1MzIgc2VxX251bWJlcjsKKwl1MTYgcmVzZXJ2ZWQwOworCXUxNiBhY2tfdHlwZTsKKwl1 MzIgYWNrbm93bGVkZ21lbnQ7CisJdTMyIGxlbmd0aDsKK307CisKKy8qIERhdGEgc3ViIHBhY2tl dCBoZWFkZXIgKi8KK3N0cnVjdCBvcGFsX2RhdGFfc3VicGFja2V0IHsKKwl1OCByZXNlcnZlZDBb Nl07CisJdTE2IGtpbmQ7CisJdTMyIGxlbmd0aDsKK307CisKKy8qIGhlYWRlciBvZiBhIHJlc3Bv bnNlICovCitzdHJ1Y3Qgb3BhbF9oZWFkZXIgeworCXN0cnVjdCBvcGFsX2NvbXBhY2tldCBjcDsK KwlzdHJ1Y3Qgb3BhbF9wYWNrZXQgcGt0OworCXN0cnVjdCBvcGFsX2RhdGFfc3VicGFja2V0IHN1 YnBrdDsKK307CisKKyNkZWZpbmUgRkNfVFBFUiAgICAgICAweDAwMDEKKyNkZWZpbmUgRkNfTE9D S0lORyAgICAweDAwMDIKKyNkZWZpbmUgRkNfR0VPTUVUUlkgICAweDAwMDMKKyNkZWZpbmUgRkNf RU5URVJQUklTRSAweDAxMDAKKyNkZWZpbmUgRkNfREFUQVNUT1JFICAweDAyMDIKKyNkZWZpbmUg RkNfU0lOR0xFVVNFUiAweDAyMDEKKyNkZWZpbmUgRkNfT1BBTFYxMDAgICAweDAyMDAKKyNkZWZp bmUgRkNfT1BBTFYyMDAgICAweDAyMDMKKworLyoKKyAqIFRoZSBEaXNjb3ZlcnkgMCBIZWFkZXIu IEFzIGRlZmluZWQgaW4KKyAqIE9wYWwgU1NDIERvY3VtZW50YXRpb24KKyAqIFNlY3Rpb246IDMu My41IENhcGFiaWxpdHkgRGlzY292ZXJ5CisgKi8KK3N0cnVjdCBkMF9oZWFkZXIgeworCXUzMiBs ZW5ndGg7IC8qIHRoZSBsZW5ndGggb2YgdGhlIGhlYWRlciA0OCBpbiAyLjAwLjEwMCAqLworCXUz MiByZXZpc2lvbjsgLyoqPCByZXZpc2lvbiBvZiB0aGUgaGVhZGVyIDEgaW4gMi4wMC4xMDAgKi8K Kwl1MzIgcmVzZXJ2ZWQwMTsKKwl1MzIgcmVzZXJ2ZWQwMjsKKwkvKgorCSAqIHRoZSByZW1haW5k ZXIgb2YgdGhlIHN0cnVjdHVyZSBpcyB2ZW5kb3Igc3BlY2lmaWMgYW5kIHdpbGwgbm90IGJlCisJ ICogYWRkcmVzc2VkIG5vdworCSAqLworCXU4IGlnbm9yZWRbMzJdOworfTsKKworLyoKKyAqIFRQ ZXIgRmVhdHVyZSBEZXNjcmlwdG9yLiBDb250YWlucyBmbGFncyBpbmRpY2F0aW5nIHN1cHBvcnQg Zm9yIHRoZQorICogVFBlciBmZWF0dXJlcyBkZXNjcmliZWQgaW4gdGhlIE9QQUwgc3BlY2lmaWNh dGlvbi4gVGhlIG5hbWVzIG1hdGNoIHRoZQorICogT1BBTCB0ZXJtaW5vbG9neQorICoKKyAqIGNv ZGUgPT0gMHgwMDEgaW4gMi4wMC4xMDAKKyAqLworc3RydWN0IGQwX3RwZXJfZmVhdHVyZXMgewor CS8qCisJICogc3VwcG9ydGVkX2ZlYXR1cmVzIGJpdHM6CisJICogYml0IDc6IHJlc2VydmVkCisJ ICogYml0IDY6IGNvbSBJRCBtYW5hZ2VtZW50CisJICogYml0IDU6IHJlc2VydmVkCisJICogYml0 IDQ6IHN0cmVhbWluZyBzdXBwb3J0CisJICogYml0IDM6IGJ1ZmZlciBtYW5hZ2VtZW50CisJICog Yml0IDI6IEFDSy9OQUNLCisJICogYml0IDE6IGFzeW5jCisJICogYml0IDA6IHN5bmMKKwkgKi8K Kwl1OCBzdXBwb3J0ZWRfZmVhdHVyZXM7CisJLyoKKwkgKiBieXRlcyA1IHRocm91Z2ggMTUgYXJl IHJlc2VydmVkLCBidXQgd2UgcmVwcmVzZW50IHRoZSBmaXJzdCAzIGFzCisJICogdTggdG8ga2Vl cCB0aGUgb3RoZXIgdHdvIDMyYml0cyBpbnRlZ2VycyBhbGlnbmVkLgorCSAqLworCXU4IHJlc2Vy dmVkMDFbM107CisJdTMyIHJlc2VydmVkMDI7CisJdTMyIHJlc2VydmVkMDM7Cit9OworCisvKgor ICogTG9ja2luZyBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRhaW5zIGZsYWdzIGluZGljYXRpbmcg c3VwcG9ydCBmb3IgdGhlCisgKiBsb2NraW5nIGZlYXR1cmVzIGRlc2NyaWJlZCBpbiB0aGUgT1BB TCBzcGVjaWZpY2F0aW9uLiBUaGUgbmFtZXMgbWF0Y2ggdGhlCisgKiBPUEFMIHRlcm1pbm9sb2d5 CisgKgorICogY29kZSA9PSAweDAwMDIgaW4gMi4wMC4xMDAKKyAqLworc3RydWN0IGQwX2xvY2tp bmdfZmVhdHVyZXMgeworCS8qCisJICogc3VwcG9ydGVkX2ZlYXR1cmVzIGJpdHM6CisJICogYml0 cyA2LTc6IHJlc2VydmVkCisJICogYml0IDU6IE1CUiBkb25lCisJICogYml0IDQ6IE1CUiBlbmFi bGVkCisJICogYml0IDM6IG1lZGlhIGVuY3J5cHRpb24KKwkgKiBiaXQgMjogbG9ja2VkCisJICog Yml0IDE6IGxvY2tpbmcgZW5hYmxlZAorCSAqIGJpdCAwOiBsb2NraW5nIHN1cHBvcnRlZAorCSAq LworCXU4IHN1cHBvcnRlZF9mZWF0dXJlczsKKwkvKgorCSAqIGJ5dGVzIDUgdGhyb3VnaCAxNSBh cmUgcmVzZXJ2ZWQsIGJ1dCB3ZSByZXByZXNlbnQgdGhlIGZpcnN0IDMgYXMKKwkgKiB1OCB0byBr ZWVwIHRoZSBvdGhlciB0d28gMzJiaXRzIGludGVnZXJzIGFsaWduZWQuCisJICovCisJdTggcmVz ZXJ2ZWQwMVszXTsKKwl1MzIgcmVzZXJ2ZWQwMjsKKwl1MzIgcmVzZXJ2ZWQwMzsKK307CisKKy8q CisgKiBHZW9tZXRyeSBGZWF0dXJlIERlc2NyaXB0b3IuIENvbnRhaW5zIGZsYWdzIGluZGljYXRp bmcgc3VwcG9ydCBmb3IgdGhlCisgKiBnZW9tZXRyeSBmZWF0dXJlcyBkZXNjcmliZWQgaW4gdGhl IE9QQUwgc3BlY2lmaWNhdGlvbi4gVGhlIG5hbWVzIG1hdGNoIHRoZQorICogT1BBTCB0ZXJtaW5v bG9neQorICoKKyAqIGNvZGUgPT0gMHgwMDAzIGluIDIuMDAuMTAwCisgKi8KK3N0cnVjdCBkMF9n ZW9tZXRyeV9mZWF0dXJlcyB7CisJLyoKKwkgKiBza2lwIDMyIGJpdHMgZnJvbSBoZWFkZXIsIG5l ZWRlZCB0byBhbGlnbiB0aGUgc3RydWN0IHRvIDY0IGJpdHMuCisJICovCisJdTggaGVhZGVyWzRd OworCS8qCisJICogcmVzZXJ2ZWQwMToKKwkgKiBiaXRzIDEtNjogcmVzZXJ2ZWQKKwkgKiBiaXQg MDogYWxpZ24KKwkgKi8KKwl1OCByZXNlcnZlZDAxOworCXU4IHJlc2VydmVkMDJbN107CisJdTMy IGxvZ2ljYWxfYmxvY2tfc2l6ZTsKKwl1NjQgYWxpZ25tZW50X2dyYW51bGFyaXR5OworCXU2NCBs b3dlc3RfYWxpZ25lZF9sYmE7Cit9OworCisvKgorICogRW50ZXJwcmlzZSBTU0MgRmVhdHVyZQor ICoKKyAqIGNvZGUgPT0gMHgwMTAwCisgKi8KK3N0cnVjdCBkMF9lbnRlcnByaXNlX3NzYyB7CisJ dTE2IGJhc2VDb21JRDsKKwl1MTYgbnVtQ29tSURzOworCS8qIHJhbmdlX2Nyb3NzaW5nOgorCSAq IGJpdHMgMS02OiByZXNlcnZlZAorCSAqIGJpdCAwOiByYW5nZSBjcm9zc2luZworCSAqLworCXU4 IHJhbmdlX2Nyb3NzaW5nOworCXU4IHJlc2VydmVkMDE7CisJdTE2IHJlc2VydmVkMDI7CisJdTMy IHJlc2VydmVkMDM7CisJdTMyIHJlc2VydmVkMDQ7Cit9OworCisvKgorICogT3BhbCBWMSBmZWF0 dXJlCisgKgorICogY29kZSA9PSAweDAyMDAKKyAqLworc3RydWN0IGQwX29wYWxfdjEwMCB7CisJ dTE2IGJhc2VDb21JRDsKKwl1MTYgbnVtQ29tSURzOworfTsKKworLyoKKyAqIFNpbmdsZSBVc2Vy IE1vZGUgZmVhdHVyZQorICoKKyAqIGNvZGUgPT0gMHgwMjAxCisgKi8KK3N0cnVjdCBkMF9zaW5n bGVfdXNlcl9tb2RlIHsKKwl1MzIgbnVtX2xvY2tpbmdfb2JqZWN0czsKKwkvKiByZXNlcnZlZDAx OgorCSAqIGJpdCAwOiBhbnkKKwkgKiBiaXQgMTogYWxsCisJICogYml0IDI6IHBvbGljeQorCSAq IGJpdHMgMy03OiByZXNlcnZlZAorCSAqLworCXU4IHJlc2VydmVkMDE7CisJdTggcmVzZXJ2ZWQw MjsKKwl1MTYgcmVzZXJ2ZWQwMzsKKwl1MzIgcmVzZXJ2ZWQwNDsKK307CisKKy8qCisgKiBBZGRp dG9uYWwgRGF0YXN0b3JlcyBmZWF0dXJlCisgKgorICogY29kZSA9PSAweDAyMDIKKyAqLworc3Ry dWN0IGQwX2RhdGFzdG9yZV90YWJsZSB7CisJdTE2IHJlc2VydmVkMDE7CisJdTE2IG1heF90YWJs ZXM7CisJdTMyIG1heF9zaXplX3RhYmxlczsKKwl1MzIgdGFibGVfc2l6ZV9hbGlnbm1lbnQ7Cit9 OworCisvKgorICogT1BBTCAyLjAgZmVhdHVyZQorICoKKyAqIGNvZGUgPT0gMHgwMjAzCisgKi8K K3N0cnVjdCBkMF9vcGFsX3YyMDAgeworCXUxNiBiYXNlQ29tSUQ7CisJdTE2IG51bUNvbUlEczsK KwkvKiByYW5nZV9jcm9zc2luZzoKKwkgKiBiaXRzIDEtNjogcmVzZXJ2ZWQKKwkgKiBiaXQgMDog cmFuZ2UgY3Jvc3NpbmcKKwkgKi8KKwl1OCByYW5nZV9jcm9zc2luZzsKKwkvKiBudW1fbG9ja2lu Z19hZG1pbl9hdXRoOgorCSAqIG5vdCBhbGlnbmVkIHRvIDE2IGJpdHMsIHNvIHVzZSB0d28gdTgu CisJICogc3RvcmVkIGluIGJpZyBlbmRpYW46CisJICogMDogTVNCCisJICogMTogTFNCCisJICov CisJdTggbnVtX2xvY2tpbmdfYWRtaW5fYXV0aFsyXTsKKwkvKiBudW1fbG9ja2luZ191c2VyX2F1 dGg6CisJICogbm90IGFsaWduZWQgdG8gMTYgYml0cywgc28gdXNlIHR3byB1OC4KKwkgKiBzdG9y ZWQgaW4gYmlnIGVuZGlhbjoKKwkgKiAwOiBNU0IKKwkgKiAxOiBMU0IKKwkgKi8KKwl1OCBudW1f bG9ja2luZ191c2VyX2F1dGhbMl07CisJdTggaW5pdGlhbFBJTjsKKwl1OCByZXZlcnRlZFBJTjsK Kwl1OCByZXNlcnZlZDAxOworCXUzMiByZXNlcnZlZDAyOworfTsKKworLyogVW5pb24gb2YgZmVh dHVyZXMgdXNlZCB0byBwYXJzZSB0aGUgZGlzY292ZXJ5IDAgcmVzcG9uc2UgKi8KK3N0cnVjdCBk MF9mZWF0dXJlcyB7CisJdTE2IGNvZGU7CisJLyoKKwkgKiByX3ZlcnNpb24gYml0czoKKwkgKiBi aXRzIDQtNzogdmVyc2lvbgorCSAqIGJpdHMgMC0zOiByZXNlcnZlZAorCSAqLworCXU4IHJfdmVy c2lvbjsKKwl1OCBsZW5ndGg7CisJdTggZmVhdHVyZXNbXTsKK307CisKK3N0cnVjdCBrZXkgKnJl cXVlc3RfdXNlcl9rZXkoY29uc3QgY2hhciAqbWFzdGVyX2Rlc2MsIGNvbnN0IHU4ICoqbWFzdGVy X2tleSwKKwkJCSAgICAgc2l6ZV90ICptYXN0ZXJfa2V5bGVuKTsKKworI2VuZGlmIC8qIF9OVk1F X09QQUxfSU5URVJOQUxfSCAqLwpkaWZmIC0tZ2l0IGEvYmxvY2svc2VkLmMgYi9ibG9jay9zZWQu YwpuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi4yNDFiMWRjCi0tLSAvZGV2L251 bGwKKysrIGIvYmxvY2svc2VkLmMKQEAgLTAsMCArMSwyMDcgQEAKKy8qCisgKiBDb3B5cmlnaHQg wqkgMjAxNiBJbnRlbCBDb3Jwb3JhdGlvbgorICoKKyAqIEF1dGhvcnM6CisgKiAgICBSYWZhZWwg QW50b2dub2xsaSA8cmFmYWVsLmFudG9nbm9sbGlAaW50ZWwuY29tPgorICogICAgU2NvdHQgIEJh dWVyICAgICAgPHNjb3R0LmJhdWVyQGludGVsLmNvbT4KKyAqCisgKiBUaGlzIHByb2dyYW0gaXMg ZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeSBpdAor ICogdW5kZXIgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJs aWMgTGljZW5zZSwKKyAqIHZlcnNpb24gMiwgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3 YXJlIEZvdW5kYXRpb24uCisgKgorICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRo ZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVAorICogQU5ZIFdBUlJBTlRZOyB3 aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZIG9yCisg KiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VIEdlbmVyYWwg UHVibGljIExpY2Vuc2UgZm9yCisgKiBtb3JlIGRldGFpbHMuCisgKi8KKworI2luY2x1ZGUgPGxp bnV4L2Jsa2Rldi5oPgorI2luY2x1ZGUgPGxpbnV4L3NlZC5oPgorI2luY2x1ZGUgPGxpbnV4L3Nl ZC1vcGFsLmg+CisjaW5jbHVkZSA8YXNtL3VhY2Nlc3MuaD4KKworCitpbnQgc2VkX3NhdmUoc3Ry dWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSwKKwkgICAgIHZvaWQg KnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sKKwlzd2l0Y2ggKGtleS0+ c2VkX3R5cGUpIHsKKwljYXNlIE9QQUxfTE9DS19VTkxPQ0s6CisJCXJldHVybiBvcGFsX3NhdmUo YmRldiwga2V5LCBzYm10X2RhdGEsIHN1Ym1pdF9mbik7CisJfQorCisJcmV0dXJuIC1FT1BOT1RT VVBQOworfQorCitpbnQgc2VkX2xvY2tfdW5sb2NrKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYs IHN0cnVjdCBzZWRfa2V5ICprZXksCisJCSAgICB2b2lkICpzYm10X2RhdGEsIHNlZF9zZWNfc3Vi bWl0ICpzdWJtaXRfZm4pCit7CisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFM X0xPQ0tfVU5MT0NLOgorCQlyZXR1cm4gb3BhbF9sb2NrX3VubG9jayhiZGV2LCBrZXksIHNibXRf ZGF0YSwgc3VibWl0X2ZuKTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK2ludCBz ZWRfdGFrZV9vd25lcnNoaXAoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9r ZXkgKmtleSwKKwkJICAgICAgIHZvaWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1p dF9mbikKK3sKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTDoKKwkJcmV0 dXJuIG9wYWxfdGFrZV9vd25lcnNoaXAoYmRldiwga2V5LCBzYm10X2RhdGEsIHN1Ym1pdF9mbik7 CisJfQorCisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQorCitpbnQgc2VkX2FjdGl2YXRlX2xzcChz dHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qgc2VkX2tleSAqa2V5LAorCQkgICAgIHZv aWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sKKworCXN3aXRjaCAo a2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTDoKKwkJcmV0dXJuIG9wYWxfYWN0aXZhdGVfbHNw KGJkZXYsIGtleSwgc2JtdF9kYXRhLCBzdWJtaXRfZm4pOworCX0KKworCXJldHVybiAtRU9QTk9U U1VQUDsKK30KKworaW50IHNlZF9zZXRfcHcoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3Ry dWN0IHNlZF9rZXkgKmtleSwKKwkgICAgICAgdm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1p dCAqc3VibWl0X2ZuKQoreworCisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFM X1BXOgorCQlyZXR1cm4gb3BhbF9zZXRfbmV3X3B3KGJkZXYsIGtleSwgc2JtdF9kYXRhLCBzdWJt aXRfZm4pOworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNlZF9hY3RpdmF0 ZV91c2VyKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXksCisJ CSAgICAgIHZvaWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sKKwor CXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTF9BQ1RfVVNSOgorCQlyZXR1cm4g b3BhbF9hY3RpdmF0ZV91c2VyKGJkZXYsIGtleSwgc2JtdF9kYXRhLCBzdWJtaXRfZm4pOworCX0K KworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNlZF9yZXZlcnR0cGVyKHN0cnVjdCBi bG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXksCisJCSAgIHZvaWQgKnNibXRf ZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sKKworCXN3aXRjaCAoa2V5LT5zZWRf dHlwZSkgeworCWNhc2UgT1BBTDoKKwkJcmV0dXJuIG9wYWxfcmV2ZXJ0dHBlcihiZGV2LCBrZXks IHNibXRfZGF0YSwgc3VibWl0X2ZuKTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisK K2ludCBzZWRfc2V0dXBfbG9ja2luZ19yYW5nZShzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBz dHJ1Y3Qgc2VkX2tleSAqa2V5LAorCQkJICAgIHZvaWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJt aXQgKnN1Ym1pdF9mbikKK3sKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BB TF9MUl9TRVRVUDoKKwkJcmV0dXJuIG9wYWxfc2V0dXBfbG9ja2luZ19yYW5nZShiZGV2LCBrZXks IHNibXRfZGF0YSwgc3VibWl0X2ZuKTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisK K2ludCBzZWRfYWRkdXNlcl90b19scihzdHJ1Y3QgYmxvY2tfZGV2aWNlICpiZGV2LCBzdHJ1Y3Qg c2VkX2tleSAqa2V5LAorCQkgICAgICB2b2lkICpzYm10X2RhdGEsIHNlZF9zZWNfc3VibWl0ICpz dWJtaXRfZm4pCit7CisKKwlzd2l0Y2ggKGtleS0+c2VkX3R5cGUpIHsKKwljYXNlIE9QQUxfTE9D S19VTkxPQ0s6CisJCXJldHVybiBvcGFsX2FkZF91c2VyX3RvX2xyKGJkZXYsIGtleSwgc2JtdF9k YXRhLCBzdWJtaXRfZm4pOworCX0KKworCXJldHVybiAtRU9QTk9UU1VQUDsKK30KKworaW50IHNl ZF9kb19tYnIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9rZXkgKmtleSwK KwkgICAgICAgdm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKQorewor CisJc3dpdGNoIChrZXktPnNlZF90eXBlKSB7CisJY2FzZSBPUEFMX01CUl9EQVRBOgorCQlyZXR1 cm4gb3BhbF9lbmFibGVfZGlzYWJsZV9zaGFkb3dfbWJyKGJkZXYsIGtleSwgc2JtdF9kYXRhLAor CQkJCQkJICAgICAgc3VibWl0X2ZuKTsKKwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisK K2ludCBzZWRfZXJhc2VfbHIoc3RydWN0IGJsb2NrX2RldmljZSAqYmRldiwgc3RydWN0IHNlZF9r ZXkgKmtleSwKKwkJIHZvaWQgKnNibXRfZGF0YSwgc2VkX3NlY19zdWJtaXQgKnN1Ym1pdF9mbikK K3sKKworCXN3aXRjaCAoa2V5LT5zZWRfdHlwZSkgeworCWNhc2UgT1BBTDoKKwkJcmV0dXJuIG9w YWxfZXJhc2VfbG9ja2luZ19yYW5nZShiZGV2LCBrZXksIHNibXRfZGF0YSwgc3VibWl0X2ZuKTsK Kwl9CisKKwlyZXR1cm4gLUVPUE5PVFNVUFA7Cit9CisKK2ludCBzZWRfc2VjdXJlX2VyYXNlX2xy KHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXksCisJCQl2b2lk ICpzYm10X2RhdGEsIHNlZF9zZWNfc3VibWl0ICpzdWJtaXRfZm4pCit7CisJc3dpdGNoIChrZXkt PnNlZF90eXBlKSB7CisJY2FzZSBPUEFMX0FDVF9VU1I6CisJCXJldHVybiBvcGFsX3NlY3VyZV9l cmFzZV9sb2NraW5nX3JhbmdlKGJkZXYsIGtleSwKKwkJCQkJCSAgICAgICBzYm10X2RhdGEsIHN1 Ym1pdF9mbik7CisKKwl9CisJcmV0dXJuIC1FT1BOT1RTVVBQOworfQorCisKKyNkZWZpbmUgQ01E X1RPX0ZOX0lORFgoY21kKSBcCisJKGNtZCkgLSBJT0NfU0VEX1NBVkUKKworaW50ICgqc2VkX2Zu W10pKHN0cnVjdCBibG9ja19kZXZpY2UgKmJkZXYsIHN0cnVjdCBzZWRfa2V5ICprZXksCisJCSAg dm9pZCAqc2JtdF9kYXRhLCBzZWRfc2VjX3N1Ym1pdCAqc3VibWl0X2ZuKSA9Cit7CisJc2VkX3Nh dmUsCisJc2VkX2xvY2tfdW5sb2NrLAorCXNlZF90YWtlX293bmVyc2hpcCwKKwlzZWRfYWN0aXZh dGVfbHNwLAorCXNlZF9zZXRfcHcsCisJc2VkX2FjdGl2YXRlX3VzZXIsCisJc2VkX3JldmVydHRw ZXIsCisJc2VkX3NldHVwX2xvY2tpbmdfcmFuZ2UsCisJc2VkX2FkZHVzZXJfdG9fbHIsCisJc2Vk X2RvX21iciwKKwlzZWRfZXJhc2VfbHIsCisJc2VkX3NlY3VyZV9lcmFzZV9scgorfTsKKworLyog VGhlIHNibXRfY3RybF9kYXRhIGlzIGEgb3BhcXVlIHBvaW50ZXIgdG8gc29tZSBzdHJ1Y3R1cmUg d2hpY2ggd2lsbCBiZSB1c2VkCisgKiBieSB0aGUgc3VibWl0X2ZuIHRvIHByb3Blcmx5IHN1Ym1p dCB0aGUgb3BhbCBjb21tYW5kIHRvIHRoZSBjb250cm9sbGVyLgorICogVGhlIHN1Ym1pdF9mbiBt dXN0IGJlIGEgYmxvY2tpbmcgY2FsbC4KKyAqLworaW50IGJsa2Rldl9zZWRfaW9jdGwoc3RydWN0 IGJsb2NrX2RldmljZSAqYmRldiwgZm1vZGVfdCBmbW9kZSwgdW5zaWduZWQgaW50IGNtZCwKKwkJ ICAgICB1bnNpZ25lZCBsb25nIGFyZywgdm9pZCAqc2JtdF9jdHJsX2RhdGEsCisJCSAgICAgc2Vk X3NlY19zdWJtaXQgKnN1Ym1pdF9mbikKK3sKKwlzdHJ1Y3Qgc2VkX2tleSBrZXk7CisKKwkgLyog Q2FsbGVyIHNob3VsZCBkbyB0aGlzIGJ1dCBzaW5jZSB3ZSdyZSBnb2luZyB0byB1c2UgY21kIGFz IGFuIGluZGV4CisJICogbGV0cyAndHJ1c3QgYnV0IHZlcmlmeScuCisJICovCisJaWYgKCFpc19z ZWRfaW9jdGwoY21kKSkKKwkJcmV0dXJuIC1FSU5WQUw7CisJaWYgKGNvcHlfZnJvbV91c2VyKCZr ZXksICh2b2lkIF9fdXNlciAqKWFyZywgc2l6ZW9mKGtleSkpKQorCQlyZXR1cm4gLUVGQVVMVDsK KwlyZXR1cm4gc2VkX2ZuW0NNRF9UT19GTl9JTkRYKGNtZCldKGJkZXYsICZrZXksIHNibXRfY3Ry bF9kYXRhLCBzdWJtaXRfZm4pOworfQorRVhQT1JUX1NZTUJPTF9HUEwoYmxrZGV2X3NlZF9pb2N0 bCk7Ci0tIAoyLjcuNAoKCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fCkxpbnV4LW52bWUgbWFpbGluZyBsaXN0CkxpbnV4LW52bWVAbGlzdHMuaW5mcmFkZWFk Lm9yZwpodHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xpbnV4LW52 bWUK From mboxrd@z Thu Jan 1 00:00:00 1970 From: scott.bauer@intel.com (Scott Bauer) Date: Tue, 29 Nov 2016 14:52:00 -0700 Subject: [PATCH v2 2/4] block: Add Sed-opal library In-Reply-To: <1480456322-27339-1-git-send-email-scott.bauer@intel.com> References: <1480456322-27339-1-git-send-email-scott.bauer@intel.com> Message-ID: <1480456322-27339-3-git-send-email-scott.bauer@intel.com> This patch implements the necessary logic to bring an Opal enabled drive out of a factory-enabled into a working Opal state. This patch set also enables logic to save a password to be replayed during a resume from suspend. The key can be saved in the driver or in the Kernel's Key managment. Signed-off-by: Scott Bauer Signed-off-by: Rafael Antognolli --- block/Makefile | 2 +- block/sed-opal.c | 3157 +++++++++++++++++++++++++++++++++++++++++++++ block/sed-opal_internal.h | 601 +++++++++ block/sed.c | 207 +++ 4 files changed, 3966 insertions(+), 1 deletion(-) create mode 100644 block/sed-opal.c create mode 100644 block/sed-opal_internal.h create mode 100644 block/sed.c diff --git a/block/Makefile b/block/Makefile index 36acdd7..6632d42 100644 --- a/block/Makefile +++ b/block/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \ blk-lib.o blk-mq.o blk-mq-tag.o \ blk-mq-sysfs.o blk-mq-cpumap.o ioctl.o \ genhd.o scsi_ioctl.o partition-generic.o ioprio.o \ - badblocks.o partitions/ + badblocks.o sed.o sed-opal.o partitions/ obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_BLK_DEV_BSG) += bsg.o diff --git a/block/sed-opal.c b/block/sed-opal.c new file mode 100644 index 0000000..53602aa --- /dev/null +++ b/block/sed-opal.c @@ -0,0 +1,3157 @@ +/* + * Copyright ? 2016 Intel Corporation + * + * Authors: + * Rafael Antognolli + * Scott Bauer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":OPAL: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sed-opal_internal.h" + +#define IO_BUFFER_LENGTH 2048 + +#define MAX_TOKS 64 + +typedef int (cont_fn)(void *data); + +struct opal_cmd { + struct block_device *bdev; + cont_fn *cb; + void *cb_data; + + size_t pos; + u8 cmd_buf[IO_BUFFER_LENGTH * 2]; + u8 resp_buf[IO_BUFFER_LENGTH * 2]; + u8 *cmd; + u8 *resp; +}; + +/* + * On the parsed response, we don't store again the toks that are already + * stored in the response buffer. Instead, for each token, we just store a + * pointer to the position in the buffer where the token starts, and the size + * of the token in bytes. + */ +struct opal_resp_tok { + const u8 *pos; + size_t len; + enum OPAL_RESPONSE_TOKEN type; + enum OPAL_ATOM_WIDTH width; + union { + u64 u; + s64 s; + } stored; +}; + +/* + * From the response header it's not possible to know how many tokens there are + * on the payload. So we hardcode that the maximum will be MAX_TOKS, and later + * if we start dealing with messages that have more than that, we can increase + * this number. This is done to avoid having to make two passes through the + * response, the first one counting how many tokens we have and the second one + * actually storing the positions. + */ +struct parsed_resp { + int num; + struct opal_resp_tok toks[MAX_TOKS]; +}; + +struct opal_dev; + +typedef int (*opal_step)(struct opal_dev *dev); + +struct opal_dev { + dev_t majmin; + sed_sec_submit *submit_fn; + void *submit_data; + struct opal_lock_unlock lkul; + const opal_step *funcs; + void **func_data; + bool resume_from_suspend; + struct opal_suspend_unlk *resume_data; + size_t num_func_data; + atomic_t in_use; + sector_t start; + sector_t length; + u8 lr; + u8 key_type; + u8 key_name[OPAL_KEY_MAX]; + size_t key_name_len; + u8 key[OPAL_KEY_MAX]; + size_t key_len; + u16 comID; + u32 HSN; + u32 TSN; + u64 align; + u64 lowest_lba; + struct list_head node; + char disk_name[DISK_NAME_LEN]; + int state; + + struct opal_cmd cmd; + struct parsed_resp parsed; + + size_t prev_d_len; + void *prev_data; + + opal_step error_cb; + void *error_cb_data; +}; + +LIST_HEAD(opal_list); +DEFINE_SPINLOCK(list_spinlock); + +static void print_buffer(const u8 *ptr, u32 length) +{ +#ifdef DEBUG + print_hex_dump_bytes("OPAL: ", DUMP_PREFIX_OFFSET, ptr, length); + pr_debug("\n"); +#endif +} + +#define TPER_SYNC_SUPPORTED BIT(0) + +static bool check_tper(const void *data) +{ + const struct d0_tper_features *tper = data; + u8 flags = tper->supported_features; + + if (!(flags & TPER_SYNC_SUPPORTED)) { + pr_err("TPer sync not supported. flags = %d\n", + tper->supported_features); + return false; + } + + return true; +} + +static bool check_SUM(const void *data) +{ + const struct d0_single_user_mode *sum = data; + u32 nlo = be32_to_cpu(sum->num_locking_objects); + + if (nlo == 0) { + pr_err("Need at least one locking object.\n"); + return false; + } + + pr_debug("Number of locking objects: %d\n", nlo); + + return true; +} + +static u16 get_comID_v100(const void *data) +{ + const struct d0_opal_v100 *v100 = data; + + return be16_to_cpu(v100->baseComID); +} + +static u16 get_comID_v200(const void *data) +{ + const struct d0_opal_v200 *v200 = data; + + return be16_to_cpu(v200->baseComID); +} + +static int opal_send_cmd(struct opal_dev *dev) +{ + return dev->submit_fn(dev->submit_data, dev->comID, TCG_SECP_01, + dev->cmd.cmd, IO_BUFFER_LENGTH, true); +} + +static int opal_recv_cmd(struct opal_dev *dev) +{ + return dev->submit_fn(dev->submit_data, dev->comID, TCG_SECP_01, + dev->cmd.resp, IO_BUFFER_LENGTH, false); +} + +static int opal_recv_check(struct opal_dev *dev) +{ + size_t buflen = IO_BUFFER_LENGTH; + void *buffer = dev->cmd.resp; + struct opal_header *hdr = buffer; + int ret; + + do { + pr_debug("%s: Sent OPAL command: outstanding=%d, minTransfer=%d\n", + dev->disk_name, hdr->cp.outstandingData, + hdr->cp.minTransfer); + + if (hdr->cp.outstandingData == 0 || + hdr->cp.minTransfer != 0) + return 0; + + memset(buffer, 0, buflen); + ret = opal_recv_cmd(dev); + } while (!ret); + + return ret; +} + +static int opal_send_recv(struct opal_dev *dev, cont_fn *cont) +{ + int ret; + + ret = opal_send_cmd(dev); + if (ret) + return ret; + ret = opal_recv_cmd(dev); + if (ret) + return ret; + ret = opal_recv_check(dev); + if (ret) + return ret; + + return cont(dev); +} + +static void check_geometry(struct opal_dev *dev, const void *data) +{ + const struct d0_geometry_features *geo = data; + + dev->align = geo->alignment_granularity; + dev->lowest_lba = geo->lowest_aligned_lba; +} + +static int next(struct opal_dev *dev) +{ + opal_step func; + int error = 0; + + do { + + func = dev->funcs[dev->state]; + if (!func) + break; + + dev->state++; + error = func(dev); + + if (error) { + pr_err("%s: Error on step function: %d with error %d: %s\n", + dev->disk_name, dev->state, error, + opal_error_to_human(error)); + + /* + * We check for state > 2 because error_cb is + * an end session call. We never start a session until + * after state 2. So If we failed on state 2 or lower + * that means we failed to start a session + * due to a bad pw or something. Therefore is no reason + * to end a non existant session. + */ + if (dev->error_cb && dev->state > 2) + dev->error_cb(dev->error_cb_data); + } + } while (!error); + + return error; +} + +static int opal_discovery0_end(struct opal_dev *dev) +{ + bool foundComID = false, supported = true, single_user = false; + const struct d0_header *hdr; + const u8 *epos, *cpos; + u16 comID = 0; + int error = 0; + + epos = dev->cmd.resp; + cpos = dev->cmd.resp; + hdr = (struct d0_header *)dev->cmd.resp; + + print_buffer(dev->cmd.resp, be32_to_cpu(hdr->length)); + + epos += be32_to_cpu(hdr->length); /* end of buffer */ + cpos += sizeof(*hdr); /* current position on buffer */ + + while (cpos < epos && supported) { + const struct d0_features *body = + (const struct d0_features *)cpos; + + switch (be16_to_cpu(body->code)) { + case FC_TPER: + supported = check_tper(body->features); + break; + case FC_SINGLEUSER: + single_user = check_SUM(body->features); + break; + case FC_GEOMETRY: + check_geometry(dev, body); + break; + case FC_LOCKING: + case FC_ENTERPRISE: + case FC_DATASTORE: + /* some ignored properties */ + pr_debug("%s: Found OPAL feature description: %d\n", + dev->disk_name, be16_to_cpu(body->code)); + break; + case FC_OPALV100: + comID = get_comID_v100(body->features); + foundComID = true; + break; + case FC_OPALV200: + comID = get_comID_v200(body->features); + foundComID = true; + break; + case 0xbfff ... 0xffff: + /* vendor specific, just ignore */ + break; + default: + pr_warn("%s: OPAL Unknown feature: %d\n", + dev->disk_name, be16_to_cpu(body->code)); + + } + cpos += body->length + 4; + } + + if (!supported) { + pr_err("%s: Device not supported\n", dev->disk_name); + error = 1; + goto err_callback; + } + + if (!single_user) + pr_warn("%s: Device doesn't support single user mode\n", + dev->disk_name); + + if (!foundComID) { + pr_warn("%s: Could not find OPAL comID for device. OPAL kernel unlocking will be disabled\n", + dev->disk_name); + error = 1; + goto err_callback; + } + + dev->comID = comID; + +err_callback: + return error; +} + +static int opal_discovery0(struct opal_dev *dev) +{ + int ret; + + memset(dev->cmd.resp, 0, IO_BUFFER_LENGTH); + dev->comID = 0x0001; + ret = opal_recv_cmd(dev); + if (ret) + return ret; + return opal_discovery0_end(dev); +} + +static void add_token_u8(struct opal_cmd *cmd, u8 tok) +{ + cmd->cmd[cmd->pos++] = tok; +} + +static ssize_t test_and_add_token_u8(struct opal_cmd *cmd, u8 tok) +{ + BUILD_BUG_ON(IO_BUFFER_LENGTH >= SIZE_MAX); + + if (cmd->pos >= IO_BUFFER_LENGTH - 1) { + pr_err("Error adding u8: end of buffer.\n"); + return -ERANGE; + } + + add_token_u8(cmd, tok); + + return 1; +} + +#define TINY_ATOM_DATA_MASK GENMASK(5, 0) +#define TINY_ATOM_SIGNED BIT(6) + +#define SHORT_ATOM_ID BIT(7) +#define SHORT_ATOM_BYTESTRING BIT(5) +#define SHORT_ATOM_SIGNED BIT(4) +#define SHORT_ATOM_LEN_MASK GENMASK(3, 0) + +static void add_short_atom_header(struct opal_cmd *cmd, bool bytestring, + bool has_sign, int len) +{ + u8 atom; + + atom = SHORT_ATOM_ID; + atom |= bytestring ? SHORT_ATOM_BYTESTRING : 0; + atom |= has_sign ? SHORT_ATOM_SIGNED : 0; + atom |= len & SHORT_ATOM_LEN_MASK; + + add_token_u8(cmd, atom); +} + +#define MEDIUM_ATOM_ID (BIT(7) | BIT(6)) +#define MEDIUM_ATOM_BYTESTRING BIT(4) +#define MEDIUM_ATOM_SIGNED BIT(3) +#define MEDIUM_ATOM_LEN_MASK GENMASK(2, 0) + +static void add_medium_atom_header(struct opal_cmd *cmd, bool bytestring, + bool has_sign, int len) +{ + u8 header0; + + header0 = MEDIUM_ATOM_ID; + header0 |= bytestring ? MEDIUM_ATOM_BYTESTRING : 0; + header0 |= has_sign ? MEDIUM_ATOM_SIGNED : 0; + header0 |= (len >> 8) & MEDIUM_ATOM_LEN_MASK; + cmd->cmd[cmd->pos++] = header0; + cmd->cmd[cmd->pos++] = len; +} + +static void add_token_u64(struct opal_cmd *cmd, u64 number, size_t len) +{ + add_short_atom_header(cmd, false, false, len); + + while (len--) { + u8 n = number >> (len * 8); + + add_token_u8(cmd, n); + } +} + +static ssize_t test_and_add_token_u64(struct opal_cmd *cmd, u64 number) +{ + int len; + int msb; + + if (!(number & ~TINY_ATOM_DATA_MASK)) + return test_and_add_token_u8(cmd, number); + + msb = fls(number); + len = DIV_ROUND_UP(msb, 4); + + if (cmd->pos >= IO_BUFFER_LENGTH - len - 1) { + pr_err("Error adding u64: end of buffer.\n"); + return -ERANGE; + } + + add_token_u64(cmd, number, len); + + /* return length of token plus atom */ + return len + 1; +} + +static void add_token_bytestring(struct opal_cmd *cmd, + const u8 *bytestring, size_t len) +{ + memcpy(&cmd->cmd[cmd->pos], bytestring, len); + cmd->pos += len; +} + +static ssize_t test_and_add_token_bytestring(struct opal_cmd *cmd, + const u8 *bytestring, size_t len) +{ + size_t header_len = 1; + bool is_short_atom = true; + + if (len & ~SHORT_ATOM_LEN_MASK) { + header_len = 2; + is_short_atom = false; + } + + if (cmd->pos >= IO_BUFFER_LENGTH - len - header_len) { + pr_err("Error adding bytestring: end of buffer.\n"); + return -ERANGE; + } + + if (is_short_atom) + add_short_atom_header(cmd, true, false, len); + else + add_medium_atom_header(cmd, true, false, len); + + add_token_bytestring(cmd, bytestring, len); + + return header_len + len; +} + +#define LOCKING_RANGE_NON_GLOBAL 0x03 + +static int build_locking_range(u8 *buffer, size_t length, u8 lr) +{ + if (length < OPAL_UID_LENGTH) + return -ERANGE; + + memcpy(buffer, OPALUID[OPAL_LOCKINGRANGE_GLOBAL], OPAL_UID_LENGTH); + + if (lr == 0) + return 0; + buffer[5] = LOCKING_RANGE_NON_GLOBAL; + buffer[7] = lr; + + return 0; +} + +static int build_locking_user(u8 *buffer, size_t length, u8 lr) +{ + if (length < OPAL_UID_LENGTH) + return -ERANGE; + + memcpy(buffer, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH); + + buffer[7] = lr + 1; + + return 0; +} + +/* + * N = number of format specifiers (1-999) to be replicated + * c = u8 + * u = u64 + * s = bytestring, length + * + * ret = test_and_add_token_va(cmd, "c", + * u8_val1); + * + * ret = test_and_add_token_va(cmd, "2c2u", + * u8_val1, u8_val2, u64_val1, u64_val2); + * + * ret = test_and_add_token_va(cmd, "3s", + * bytestring1, length1, + * bytestring2, length2, + * bytestring3, length3); + */ +static int test_and_add_token_va(struct opal_cmd *cmd, + const char *fmt, ...) +{ + const u8 *it = fmt, *tmp; + int ret, num = 1, sum = 0; + va_list ap; + + va_start(ap, fmt); + + while (*it != '\0') { + u64 tok64 = 0; + u8 tok, *bstr; + size_t len; + + ret = 0; + + switch (*it) { + case '1' ... '9': + tmp = it; + num = 0; + while (*tmp >= '0' && *tmp <= '9') + num = num * 10 + (*tmp++ - '0'); + it = tmp; + continue; + case 'c': + while (num--) { + tok = va_arg(ap, unsigned int); + ret = test_and_add_token_u8(cmd, tok); + if (ret < 0) + goto err; + } + num = 1; + break; + case 'u': + while (num--) { + tok64 = va_arg(ap, u64); + ret = test_and_add_token_u64(cmd, tok64); + if (ret < 0) + goto err; + } + num = 1; + break; + case 's': + while (num--) { + bstr = va_arg(ap, u8 *); + len = va_arg(ap, size_t); + ret = test_and_add_token_bytestring(cmd, bstr, + len); + if (ret < 0) + goto err; + } + num = 1; + break; + case ' ': + case '\t': + /* ignored */ + break; + default: + pr_warn("Unrecognized type.\n"); + } + + it++; + sum += ret; + } + + va_end(ap); + + return sum; + + err: + pr_err("Token failed to be added.\n"); + return ret; +} + +static void set_comID(struct opal_cmd *cmd, u16 comID) +{ + struct opal_header *hdr = (struct opal_header *)cmd->cmd; + + hdr->cp.extendedComID[0] = comID >> 8; + hdr->cp.extendedComID[1] = comID; + hdr->cp.extendedComID[2] = 0; + hdr->cp.extendedComID[3] = 0; +} + +static int cmd_finalize(struct opal_cmd *cmd, u32 hsn, u32 tsn) +{ + struct opal_header *hdr; + int ret; + + ret = test_and_add_token_va(cmd, "6c", + OPAL_ENDOFDATA, OPAL_STARTLIST, + 0, 0, 0, OPAL_ENDLIST); + + if (ret < 0) { + pr_err("Error finalizing command.\n"); + return -EFAULT; + } + + hdr = (struct opal_header *) cmd->cmd; + + hdr->pkt.TSN = cpu_to_be32(tsn); + hdr->pkt.HSN = cpu_to_be32(hsn); + + hdr->subpkt.length = cpu_to_be32(cmd->pos - sizeof(*hdr)); + while (cmd->pos % 4) { + if (cmd->pos >= IO_BUFFER_LENGTH) { + pr_err("Error: Buffer overrun\n"); + return -ERANGE; + } + cmd->cmd[cmd->pos++] = 0; + } + hdr->pkt.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp) - + sizeof(hdr->pkt)); + hdr->cp.length = cpu_to_be32(cmd->pos - sizeof(hdr->cp)); + + return 0; +} + +static enum OPAL_RESPONSE_TOKEN token_type(const struct parsed_resp *resp, + int n) +{ + const struct opal_resp_tok *tok; + + if (n >= resp->num) { + pr_err("Token number doesn't exist: %d, resp: %d\n", + n, resp->num); + return OPAL_DTA_TOKENID_INVALID; + } + + tok = &resp->toks[n]; + if (tok->len == 0) { + pr_err("Token length must be non-zero\n"); + return OPAL_DTA_TOKENID_INVALID; + } + + return tok->type; +} + +/* + * This function returns 0 in case of invalid token. One should call + * token_type() first to find out if the token is valid or not. + */ +static enum OPAL_TOKEN response_get_token(const struct parsed_resp *resp, + int n) +{ + const struct opal_resp_tok *tok; + + if (n >= resp->num) { + pr_err("Token number doesn't exist: %d, resp: %d\n", + n, resp->num); + return 0; + } + + tok = &resp->toks[n]; + if (tok->len == 0) { + pr_err("Token length must be non-zero\n"); + return 0; + } + + return tok->pos[0]; +} + +static size_t response_parse_tiny(struct opal_resp_tok *tok, + const u8 *pos) +{ + tok->pos = pos; + tok->len = 1; + tok->width = OPAL_WIDTH_TINY; + + if (pos[0] & TINY_ATOM_SIGNED) { + tok->type = OPAL_DTA_TOKENID_SINT; + } else { + tok->type = OPAL_DTA_TOKENID_UINT; + tok->stored.u = pos[0] & 0x3f; + } + + return tok->len; +} + +static size_t response_parse_short(struct opal_resp_tok *tok, + const u8 *pos) +{ + tok->pos = pos; + tok->len = (pos[0] & SHORT_ATOM_LEN_MASK) + 1; + tok->width = OPAL_WIDTH_SHORT; + + if (pos[0] & SHORT_ATOM_BYTESTRING) { + tok->type = OPAL_DTA_TOKENID_BYTESTRING; + } else if (pos[0] & SHORT_ATOM_SIGNED) { + tok->type = OPAL_DTA_TOKENID_SINT; + } else { + u64 u_integer = 0; + int i, b = 0; + + tok->type = OPAL_DTA_TOKENID_UINT; + if (tok->len > 9) { + pr_warn("uint64 with more than 8 bytes\n"); + return -EINVAL; + } + for (i = tok->len - 1; i > 0; i--) { + u_integer |= ((u64)pos[i] << (8 * b)); + b++; + } + tok->stored.u = u_integer; + } + + return tok->len; +} + +static size_t response_parse_medium(struct opal_resp_tok *tok, + const u8 *pos) +{ + tok->pos = pos; + tok->len = (((pos[0] & MEDIUM_ATOM_LEN_MASK) << 8) | pos[1]) + 2; + tok->width = OPAL_WIDTH_MEDIUM; + + if (pos[0] & MEDIUM_ATOM_BYTESTRING) + tok->type = OPAL_DTA_TOKENID_BYTESTRING; + else if (pos[0] & MEDIUM_ATOM_SIGNED) + tok->type = OPAL_DTA_TOKENID_SINT; + else + tok->type = OPAL_DTA_TOKENID_UINT; + + return tok->len; +} + +#define LONG_ATOM_ID (BIT(7) | BIT(6) | BIT(5)) +#define LONG_ATOM_BYTESTRING BIT(1) +#define LONG_ATOM_SIGNED BIT(0) +static size_t response_parse_long(struct opal_resp_tok *tok, + const u8 *pos) +{ + tok->pos = pos; + tok->len = ((pos[1] << 16) | (pos[2] << 8) | pos[3]) + 4; + tok->width = OPAL_WIDTH_LONG; + + if (pos[0] & LONG_ATOM_BYTESTRING) + tok->type = OPAL_DTA_TOKENID_BYTESTRING; + else if (pos[0] & LONG_ATOM_SIGNED) + tok->type = OPAL_DTA_TOKENID_SINT; + else + tok->type = OPAL_DTA_TOKENID_UINT; + + return tok->len; +} + +static size_t response_parse_token(struct opal_resp_tok *tok, + const u8 *pos) +{ + tok->pos = pos; + tok->len = 1; + tok->type = OPAL_DTA_TOKENID_TOKEN; + tok->width = OPAL_WIDTH_TOKEN; + + return tok->len; +} + +static int response_parse(const u8 *buf, size_t length, + struct parsed_resp *resp) +{ + const struct opal_header *hdr; + struct opal_resp_tok *iter; + int ret, num_entries = 0; + u32 cpos = 0, total; + size_t token_length; + const u8 *pos; + + if (!buf) + return -EFAULT; + + if (!resp) + return -EFAULT; + + hdr = (struct opal_header *)buf; + pos = buf; + pos += sizeof(*hdr); + + pr_debug("Response size: cp: %d, pkt: %d, subpkt: %d\n", + be32_to_cpu(hdr->cp.length), + be32_to_cpu(hdr->pkt.length), + be32_to_cpu(hdr->subpkt.length)); + + if ((hdr->cp.length == 0) + || (hdr->pkt.length == 0) + || (hdr->subpkt.length == 0)) { + pr_err("Bad header length. cp: %d, pkt: %d, subpkt: %d\n", + be32_to_cpu(hdr->cp.length), + be32_to_cpu(hdr->pkt.length), + be32_to_cpu(hdr->subpkt.length)); + print_buffer(pos, sizeof(*hdr)); + ret = -EINVAL; + goto err; + } + + if (pos > buf + length) { + ret = -EFAULT; + goto err; + } + + iter = resp->toks; + total = be32_to_cpu(hdr->subpkt.length); + print_buffer(pos, total); + while (cpos < total) { + if (!(pos[0] & 0x80)) /* tiny atom */ + token_length = response_parse_tiny(iter, pos); + else if (!(pos[0] & 0x40)) /* short atom */ + token_length = response_parse_short(iter, pos); + else if (!(pos[0] & 0x20)) /* medium atom */ + token_length = response_parse_medium(iter, pos); + else if (!(pos[0] & 0x10)) /* long atom */ + token_length = response_parse_long(iter, pos); + else /* TOKEN */ + token_length = response_parse_token(iter, pos); + + if (token_length == -EINVAL) { + ret = -EINVAL; + goto err; + } + + pos += token_length; + cpos += token_length; + iter++; + num_entries++; + } + + if (num_entries == 0) { + pr_err("Couldn't parse response.\n"); + ret = -EINVAL; + goto err; + } + resp->num = num_entries; + + return 0; +err: + return ret; +} + +static size_t response_get_string(const struct parsed_resp *resp, int n, + const char **store) +{ + *store = NULL; + if (!resp) { + pr_err("Response is NULL\n"); + return 0; + } + + if (n > resp->num) { + pr_err("Response has %d tokens. Can't access %d\n", + resp->num, n); + return 0; + } + + if (resp->toks[n].type != OPAL_DTA_TOKENID_BYTESTRING) { + pr_err("Token is not a byte string!\n"); + return 0; + } + + *store = resp->toks[n].pos + 1; + return resp->toks[n].len - 1; +} + +static u64 response_get_u64(const struct parsed_resp *resp, int n) +{ + if (!resp) { + pr_err("Response is NULL\n"); + return 0; + } + + if (n > resp->num) { + pr_err("Response has %d tokens. Can't access %d\n", + resp->num, n); + return 0; + } + + if (resp->toks[n].type != OPAL_DTA_TOKENID_UINT) { + pr_err("Token is not unsigned it: %d\n", + resp->toks[n].type); + return 0; + } + + if (!((resp->toks[n].width == OPAL_WIDTH_TINY) || + (resp->toks[n].width == OPAL_WIDTH_SHORT))) { + pr_err("Atom is not short or tiny: %d\n", + resp->toks[n].width); + return 0; + } + + return resp->toks[n].stored.u; +} + +static u8 response_status(const struct parsed_resp *resp) +{ + if ((token_type(resp, 0) == OPAL_DTA_TOKENID_TOKEN) + && (response_get_token(resp, 0) == OPAL_ENDOFSESSION)) { + return 0; + } + + if (resp->num < 5) + return DTAERROR_NO_METHOD_STATUS; + + if ((token_type(resp, resp->num - 1) != OPAL_DTA_TOKENID_TOKEN) || + (token_type(resp, resp->num - 5) != OPAL_DTA_TOKENID_TOKEN) || + (response_get_token(resp, resp->num - 1) != OPAL_ENDLIST) || + (response_get_token(resp, resp->num - 5) != OPAL_STARTLIST)) + return DTAERROR_NO_METHOD_STATUS; + + return response_get_u64(resp, resp->num - 4); +} + +/* Parses and checks for errors */ +static int parse_and_check_status(struct opal_dev *dev) +{ + struct opal_cmd *cmd; + int error; + + cmd = &dev->cmd; + print_buffer(cmd->cmd, cmd->pos); + + error = response_parse(cmd->resp, IO_BUFFER_LENGTH, &dev->parsed); + if (error) { + pr_err("%s: Couldn't parse response.\n", dev->disk_name); + goto err_return; + } + + error = response_status(&dev->parsed); + if (error) + pr_err("%s: Response Status: %d\n", dev->disk_name, + error); + + err_return: + return error; +} + +static void clear_opal_cmd(struct opal_cmd *cmd) +{ + cmd->pos = sizeof(struct opal_header); + memset(cmd->cmd, 0, IO_BUFFER_LENGTH); + cmd->cb = NULL; + cmd->cb_data = NULL; +} + +static int start_opal_session_cont(void *data) +{ + struct opal_dev *dev = data; + u32 HSN, TSN; + int error = 0; + + error = parse_and_check_status(dev); + if (error) + goto err_return; + + HSN = response_get_u64(&dev->parsed, 4); + TSN = response_get_u64(&dev->parsed, 5); + + if (HSN == 0 && TSN == 0) { + pr_err("%s: Couldn't authenticate session\n", dev->disk_name); + error = -EPERM; + goto err_return; + } + + dev->HSN = HSN; + dev->TSN = TSN; + +err_return: + return error; +} + +struct key *request_user_key(const char *master_desc, const u8 **master_key, + size_t *master_keylen) +{ + const struct user_key_payload *upayload; + struct key *ukey; + + ukey = request_key(&key_type_user, master_desc, NULL); + if (IS_ERR(ukey)) + goto error; + + down_read(&ukey->sem); + upayload = user_key_payload(ukey); + *master_key = upayload->data; + *master_keylen = upayload->datalen; +error: + return ukey; +} + +static int get_opal_key(struct opal_dev *dev) +{ + struct key *ukey = NULL; + const u8 *tmpkey = NULL; + size_t tmplen; + int ret = 0; + + if (dev->key_type == OPAL_KEY_PLAIN) { + tmpkey = dev->key_name; + tmplen = dev->key_name_len; + } else if (dev->key_type == OPAL_KEY_KEYRING) { + ukey = request_user_key(dev->key_name, &tmpkey, &tmplen); + if (IS_ERR(ukey)) { + pr_err("%s: Can't retrieve key: %ld\n", dev->disk_name, + PTR_ERR(ukey)); + return PTR_ERR(ukey); + } + } else { + pr_err("Requested invalid key type: %d\n", dev->key_type); + return -EINVAL; + } + + if (tmplen > OPAL_KEY_MAX) { + pr_err("Requested key with invalid size: %zd\n", tmplen); + ret = -EINVAL; + goto err_exit; + } + + dev->key_len = tmplen; + if (!memcpy(dev->key, tmpkey, tmplen)) { + pr_err("Error when copying key"); + ret = -EFAULT; + goto err_exit; + } + +err_exit: + key_put(ukey); + + return 0; +} + +static void clean_opal_key(struct opal_dev *dev) +{ + memset(dev->key, 0, OPAL_KEY_MAX); + dev->key_len = 0; +} + +static inline void clean_function_data(struct opal_dev *dev) +{ + dev->func_data = NULL; + dev->num_func_data = 0; +} + +/* This is a generic continuation. + * We use this when we don't care about the response data + * and simply want to check the status and continue. + */ +static int generic_cont(void *data) +{ + struct opal_dev *dev = data; + + return parse_and_check_status(dev); +} + +static int end_session_cont(void *data) +{ + struct opal_dev *dev = data; + + dev->HSN = 0; + dev->TSN = 0; + return generic_cont(data); +} + +static int finalize_and_send(struct opal_dev *dev, struct opal_cmd *cmd, + cont_fn cont) +{ + int ret; + + ret = cmd_finalize(cmd, dev->HSN, dev->TSN); + if (ret) { + pr_err("%s: Error finalizing command buffer: %d\n", + dev->disk_name, ret); + return ret; + } + + print_buffer(cmd->cmd, cmd->pos); + + return opal_send_recv(dev, cont); +} + +static int gen_key(struct opal_dev *dev) +{ + const u8 *method; + u8 uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + memcpy(uid, dev->prev_data, min(sizeof(uid), dev->prev_d_len)); + method = OPALMETHOD[OPAL_GENKEY]; + kfree(dev->prev_data); + dev->prev_data = NULL; + + ret = test_and_add_token_va(cmd, "c2s 2c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error building gen key command\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int get_active_key_cont(void *data) +{ + struct opal_dev *dev = data; + const char *activekey; + size_t keylen; + int error = 0; + + error = parse_and_check_status(dev); + if (error) + goto err_return; + keylen = response_get_string(&dev->parsed, 4, &activekey); + if (!activekey) { + pr_err("%s: Couldn't extract the Activekey from the response\n", + __func__); + error = 0x0A; + goto err_return; + } + dev->prev_data = kmemdup(activekey, keylen, GFP_KERNEL); + + if (!dev->prev_data) { + error = -ENOMEM; + goto err_return; + } + + dev->prev_d_len = keylen; + + err_return: + return error; +} + +static int get_active_key(struct opal_dev *dev) +{ + const u8 *method; + u8 uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_GET]; + + ret = build_locking_range(uid, sizeof(uid), dev->lr); + if (ret < 0) { + pr_err("%s: Can't build locking range\n", dev->disk_name); + return -EINVAL; + } + + ret = test_and_add_token_va(cmd, "c2s 6c 4c 2c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* startCloumn */ + OPAL_TINY_UINT_10, /* ActiveKey */ + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_04, /* endColumn */ + OPAL_TINY_UINT_10, /* ActiveKey */ + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error building get active key command\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, get_active_key_cont); +} + +static inline int enable_global_lr(struct opal_cmd *cmd, u8 *uid, + struct opal_user_lr_setup *setup) +{ + const u8 *method; + + method = OPALMETHOD[OPAL_SET]; + return test_and_add_token_va(cmd, "c2s 4c 2cuc 2cuc 4c 4c 3c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_VALUES, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_TINY_UINT_05, /* ReadLockEnabled */ + !!setup->RLE, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_06, /* WriteLockEnabled */ + !!setup->WLE, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_READLOCKED, + OPAL_FALSE, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_WRITELOCKED, + OPAL_FALSE, + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST); +} + +static int setup_locking_range(struct opal_dev *dev) +{ + const u8 *method; + u8 uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + struct opal_user_lr_setup *setup; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_SET]; + ret = build_locking_range(uid, sizeof(uid), dev->lr); + if (ret < 0) { + pr_err("%s: Can't build locking range\n", dev->disk_name); + return -EINVAL; + } + setup = dev->func_data[dev->state - 1]; + if (dev->lr == 0) + ret = enable_global_lr(cmd, uid, setup); + else + ret = test_and_add_token_va(cmd, "c2s 4c 2cuc 2cuc 2cuc 2cu 4c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_VALUES, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* Range Start */ + setup->range_start, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_04, /* Range Length */ + setup->range_length, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_05, /* ReadLockEnabled */ + !!setup->RLE, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_06, /* WriteLockEnabled */ + !!setup->WLE, + + OPAL_ENDNAME, + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error building Setup Locking range command.\n", + dev->disk_name); + return ret; + + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int start_adminsp_opal_session(struct opal_dev *dev, + enum OPAL_UID auth, + const char *key, + u8 key_len) +{ + const u8 *method, *smuid, *admin_sp, *hsa; + struct opal_cmd *cmd; + u32 HSN; + int ret; + + if (key == NULL && auth != OPAL_ANYBODY_UID) { + pr_err("%s: Attempted to open ADMIN_SP Session without a Host" \ + "Challenge, and not as the Anybody UID\n", __func__); + return 1; + } + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + + set_comID(cmd, dev->comID); + HSN = GENERIC_HOST_SESSION_NUM; + + smuid = OPALUID[OPAL_SMUID_UID]; + method = OPALMETHOD[OPAL_STARTSESSION]; + admin_sp = OPALUID[OPAL_ADMINSP_UID]; + + ret = test_and_add_token_va(cmd, "c2s cusc", + OPAL_CALL, + smuid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + OPAL_STARTLIST, + HSN, + admin_sp, OPAL_UID_LENGTH, + OPAL_TINY_UINT_01); + if (ret < 0) { + pr_err("%s: Error building start adminsp session command.\n", + dev->disk_name); + return ret; + } + + switch (auth) { + case OPAL_ANYBODY_UID: + /* nothing left to do for anybody, just end and finalize */ + ret = test_and_add_token_va(cmd, "c", + OPAL_ENDLIST); + break; + case OPAL_SID_UID: + hsa = OPALUID[OPAL_SID_UID]; + ret = test_and_add_token_va(cmd, "2c s 3c s 2c", + OPAL_STARTNAME, + OPAL_TINY_UINT_00, /* HostChallenge */ + key, key_len, + OPAL_ENDNAME, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* HostSignAuth */ + hsa, OPAL_UID_LENGTH, + OPAL_ENDNAME, + OPAL_ENDLIST); + break; + default: + pr_err("Cannot start Admin SP session with auth %d\n", auth); + return 1; + } + + if (ret < 0) { + pr_err("%s: Error building start adminsp session command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, start_opal_session_cont); +} + +static int start_anybodyASP_opal_session(struct opal_dev *dev) +{ + return start_adminsp_opal_session(dev, OPAL_ANYBODY_UID, NULL, 0); +} + +static int start_SIDASP_opal_session(struct opal_dev *dev) +{ + int ret; + const u8 *key = dev->prev_data; + + if (!key) + ret = start_adminsp_opal_session(dev, OPAL_SID_UID, dev->key, + dev->key_len); + else { + ret = start_adminsp_opal_session(dev, OPAL_SID_UID, key, + dev->prev_d_len); + kfree(key); + dev->prev_data = NULL; + } + return ret; +} + +static int start_lockingsp_opal_session(struct opal_dev *dev, + enum OPAL_UID auth, const u8 *key, + u8 key_len) +{ + + const u8 *method, *smuid, *locking_sp, *hsa; + struct opal_cmd *cmd; + size_t klen = key_len; + u32 HSN; + int ret; + + if (key == NULL) { + pr_err("Cannot start Locking SP session without a key\n"); + return -EINVAL; + } + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + + set_comID(cmd, dev->comID); + HSN = GENERIC_HOST_SESSION_NUM; + + smuid = OPALUID[OPAL_SMUID_UID]; + method = OPALMETHOD[OPAL_STARTSESSION]; + locking_sp = OPALUID[OPAL_LOCKINGSP_UID]; + hsa = OPALUID[auth]; + + ret = test_and_add_token_va(cmd, "c2s cusc 2csc 2csc c", + OPAL_CALL, + smuid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + HSN, + locking_sp, OPAL_UID_LENGTH, + OPAL_TINY_UINT_01, + + OPAL_STARTNAME, + OPAL_TINY_UINT_00, /* HostChallenge */ + key, klen, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* Host Sign Authority */ + hsa, OPAL_UID_LENGTH, + OPAL_ENDNAME, + + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building start adminsp session command.\n", + dev->disk_name); + return ret; + } + return finalize_and_send(dev, cmd, start_opal_session_cont); +} + +static inline int start_admin1LSP_opal_session(struct opal_dev *dev) +{ + return start_lockingsp_opal_session(dev, OPAL_ADMIN1_UID, + dev->key, dev->key_len); +} + +static int start_auth_opal_session(struct opal_dev *dev) +{ + const u8 *method, *smuid, *locking_sp; + u8 lk_ul_user[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + u32 HSN; + int ret; + struct opal_user_info *uinfo; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + + set_comID(cmd, dev->comID); + + HSN = GENERIC_HOST_SESSION_NUM; + + uinfo = dev->func_data[dev->state - 1]; + + smuid = OPALUID[OPAL_SMUID_UID]; + method = OPALMETHOD[OPAL_STARTSESSION]; + locking_sp = OPALUID[OPAL_LOCKINGSP_UID]; + + if (uinfo->SUM) { + ret = build_locking_user(lk_ul_user, sizeof(lk_ul_user), + dev->lr); + if (ret < 0) { + pr_err("%s: Can't build locking user\n", + dev->disk_name); + return ret; + } + } else if (uinfo->who != OPAL_ADMIN1 && !uinfo->SUM) { + ret = build_locking_user(lk_ul_user, sizeof(lk_ul_user), + uinfo->who - 1); + if (ret < 0) { + pr_err("%s: Can't build locking user\n", + dev->disk_name); + return ret; + } + } else + memcpy(lk_ul_user, OPALUID[OPAL_ADMIN1_UID], OPAL_UID_LENGTH); + + + ret = test_and_add_token_va(cmd, "c2s cus3cs3c s 2c", + OPAL_CALL, + smuid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + HSN, + locking_sp, OPAL_UID_LENGTH, + OPAL_TINY_UINT_01, + OPAL_STARTNAME, + OPAL_TINY_UINT_00, + dev->key, dev->key_len, + OPAL_ENDNAME, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, + + lk_ul_user, OPAL_UID_LENGTH, + + OPAL_ENDNAME, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building STARTSESSION command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, start_opal_session_cont); +} + +static int revert_tper(struct opal_dev *dev) +{ + const u8 *method, *smuid; + struct opal_cmd *cmd; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + + set_comID(cmd, dev->comID); + + smuid = OPALUID[OPAL_ADMINSP_UID]; + method = OPALMETHOD[OPAL_REVERT]; + + ret = test_and_add_token_va(cmd, "c2s 2c", + OPAL_CALL, + smuid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + OPAL_STARTLIST, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error building REVERT TPER command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int internal_activate_user(struct opal_dev *dev) +{ + const u8 *method; + u8 uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + int ret; + struct opal_key_and_user *act; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + act = dev->func_data[dev->state - 1]; + + memcpy(uid, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH); + uid[7] = act->who.who; + + method = OPALMETHOD[OPAL_SET]; + + ret = test_and_add_token_va(cmd, "c2s 3c c 4c 3c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_01, /* Values */ + + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_TINY_UINT_05, /* Enabled */ + OPAL_TINY_UINT_01, /* True */ + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building Activate UserN command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int erase_locking_range(struct opal_dev *dev) +{ + const u8 *method; + u8 uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_ERASE]; + + if (build_locking_range(uid, sizeof(uid), dev->lr) < 0) { + pr_err("%s: Can't build locking range\n", dev->disk_name); + return -EINVAL; + } + + ret = test_and_add_token_va(cmd, "c2s 2c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building Erase Locking Range Cmmand.\n", + dev->disk_name); + return ret; + } + return finalize_and_send(dev, cmd, generic_cont); +} + +static int set_mbr_done(struct opal_dev *dev) +{ + const u8 *method, *uid; + struct opal_cmd *cmd; + int ret; + u8 mbr_done_tf = *(u8 *)dev->func_data[dev->state - 1]; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_SET]; + uid = OPALUID[OPAL_MBRCONTROL]; + + ret = test_and_add_token_va(cmd, "c2s 3c 6c 2c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_VALUES, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_02, /* Done */ + mbr_done_tf, /* Done T or F */ + OPAL_ENDNAME, + OPAL_ENDLIST, + + OPAL_ENDNAME, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error Building set MBR Done command\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int set_mbr_enable_disable(struct opal_dev *dev) +{ + const u8 *method, *uid; + struct opal_cmd *cmd; + int ret; + u8 mbr_en_dis = *(u8 *)dev->func_data[dev->state - 1]; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_SET]; + uid = OPALUID[OPAL_MBRCONTROL]; + + ret = test_and_add_token_va(cmd, "c2s 3c 6c 2c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_VALUES, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_01, /* Enable */ + mbr_en_dis, /* Enable or Disable */ + OPAL_ENDNAME, + OPAL_ENDLIST, + + OPAL_ENDNAME, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error Building set MBR done command\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int set_new_pw(struct opal_dev *dev) +{ + const u8 *method; + u8 cpin_uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + int ret; + struct opal_new_pw *pw; + size_t key_len; + u8 *key; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + pw = dev->func_data[dev->state - 1]; + key = pw->new_pin.key; + key_len = pw->new_pin.key_len; + memcpy(cpin_uid, OPALUID[OPAL_C_PIN_ADMIN1], OPAL_UID_LENGTH); + + if (pw->user_for_pw != OPAL_ADMIN1) { + cpin_uid[5] = 0x03; + if (pw->who.SUM) + cpin_uid[7] = pw->new_pin.lr + 1; + else + cpin_uid[7] = pw->user_for_pw; + } + + method = OPALMETHOD[OPAL_SET]; + + ret = test_and_add_token_va(cmd, "c2s 3c 3cs2c 2c", + OPAL_CALL, + cpin_uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_01, /* Values */ + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* PIN */ + key, key_len, + OPAL_ENDNAME, + OPAL_ENDLIST, + + OPAL_ENDNAME, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building SET AMIN1 PIN command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int set_sid_cpin_pin(struct opal_dev *dev) +{ + const u8 *method, *cpin_uid; + struct opal_cmd *cmd; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + cpin_uid = OPALUID[OPAL_C_PIN_SID]; + method = OPALMETHOD[OPAL_SET]; + + ret = test_and_add_token_va(cmd, "c2s 2c 4cs2c 2c", + OPAL_CALL, + cpin_uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + + OPAL_TINY_UINT_01, /* Values */ + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* PIN */ + dev->key, dev->key_len, + OPAL_ENDNAME, + OPAL_ENDLIST, + + OPAL_ENDNAME, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building SET CPIN PIN command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int query_locking_range_cont(void *data) +{ + struct opal_dev *dev = data; + int error; + + error = parse_and_check_status(dev); + if (error) + goto err_return; + + dev->start = response_get_u64(&dev->parsed, 4); + dev->length = response_get_u64(&dev->parsed, 8); + +err_return: + return error; +} + +static int query_locking_range(struct opal_dev *dev) +{ + u8 lr_buffer[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + const u8 *method; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + + method = OPALMETHOD[OPAL_GET]; + + if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) { + pr_err("%s: Can't build locking range\n", dev->disk_name); + return -EINVAL; + } + + set_comID(cmd, dev->comID); + + ret = test_and_add_token_va(cmd, "c2s 12c", + OPAL_CALL, + lr_buffer, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_STARTCOLUMN, + OPAL_RANGESTART, + OPAL_ENDNAME, + OPAL_STARTNAME, + OPAL_ENDCOLUMN, + OPAL_RANGELENGTH, + OPAL_ENDNAME, + OPAL_ENDLIST, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building GET Locking Range command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, query_locking_range_cont); +} + +static int add_user_to_lr(struct opal_dev *dev) +{ + u8 lr_buffer[OPAL_UID_LENGTH]; + u8 user_uid[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + const u8 *method; + struct opal_lock_unlock *lkul; + int ret; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_SET]; + + lkul = dev->func_data[dev->state - 1]; + + memcpy(lr_buffer, OPALUID[OPAL_LOCKINGRANGE_ACE_RDLOCKED], + OPAL_UID_LENGTH); + + if (lkul->l_state == OPAL_RW) + memcpy(lr_buffer, OPALUID[OPAL_LOCKINGRANGE_ACE_WRLOCKED], + OPAL_UID_LENGTH); + + lr_buffer[7] = dev->lr; + + memcpy(user_uid, OPALUID[OPAL_USER1_UID], OPAL_UID_LENGTH); + user_uid[7] = lkul->authority.who; + + ret = test_and_add_token_va(cmd, "c2s 3c 3c 2c 2sc c2sc cs2c 5c", + OPAL_CALL, + lr_buffer, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_01, /* Values */ + + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* BooleanExpr */ + + OPAL_STARTLIST, + OPAL_STARTNAME, + + OPALUID[OPAL_HALF_UID_AUTHORITY_OBJ_REF], + OPAL_UID_LENGTH_HALF, + user_uid, OPAL_UID_LENGTH, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPALUID[OPAL_HALF_UID_AUTHORITY_OBJ_REF], + OPAL_UID_LENGTH_HALF, + user_uid, OPAL_UID_LENGTH, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPALUID[OPAL_HALF_UID_BOOLEAN_ACE], + OPAL_UID_LENGTH_HALF, + OPAL_TINY_UINT_01, + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error building add user to locking range command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int lock_unlock_locking_range(struct opal_dev *dev) +{ + u8 lr_buffer[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + const u8 *method; + struct opal_lock_unlock *lkul; + int ret; + u8 read_locked = 1, write_locked = 1; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_SET]; + lkul = dev->func_data[dev->state - 1]; + if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) { + pr_err("%s: Can't build locking range\n", dev->disk_name); + return -EINVAL; + } + + switch (lkul->l_state) { + case OPAL_RO: + read_locked = 0; + write_locked = 1; + break; + case OPAL_RW: + read_locked = 0; + write_locked = 0; + break; + case OPAL_LK: + /* vars are initalized to locked */ + break; + default: + pr_err("Tried to set an invalid locking state... returning to uland\n"); + return 1; + } + + ret = test_and_add_token_va(cmd, "c2sc 3c 4c 4c 3c", + OPAL_CALL, + lr_buffer, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_VALUES, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_READLOCKED, + read_locked, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_WRITELOCKED, + write_locked, + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building SET command.\n", dev->disk_name); + return ret; + } + return finalize_and_send(dev, cmd, generic_cont); +} + + +static int lock_unlock_locking_range_SUM(struct opal_dev *dev) +{ + u8 lr_buffer[OPAL_UID_LENGTH]; + struct opal_cmd *cmd; + const u8 *method; + struct opal_lock_unlock *lkul; + int ret; + u8 read_locked = 1, write_locked = 1; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + method = OPALMETHOD[OPAL_SET]; + lkul = dev->func_data[dev->state - 1]; + if (build_locking_range(lr_buffer, sizeof(lr_buffer), dev->lr) < 0) { + pr_err("%s: Can't build locking range\n", dev->disk_name); + return -EINVAL; + } + + switch (lkul->l_state) { + case OPAL_RO: + read_locked = 0; + write_locked = 1; + break; + case OPAL_RW: + read_locked = 0; + write_locked = 0; + break; + case OPAL_LK: + /* vars are initalized to locked */ + break; + default: + pr_err("Tried to set an invalid locking state.\n"); + return 1; + } + + ret = test_and_add_token_va(cmd, "c2sc 3c 4c 4c 4c 4c 3c", + OPAL_CALL, + lr_buffer, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_VALUES, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_READLOCKENABLED, + OPAL_TRUE, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_WRITELOCKENABLED, + OPAL_TRUE, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_READLOCKED, + read_locked, + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_WRITELOCKED, + write_locked, + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDNAME, + OPAL_ENDLIST); + if (ret < 0) { + pr_err("%s: Error building SET command.\n", dev->disk_name); + return ret; + } + return finalize_and_send(dev, cmd, generic_cont); +} + +int activate_lsp(struct opal_dev *dev) +{ + u8 user_lr[OPAL_UID_LENGTH]; + const u8 *method, *uid; + struct opal_cmd *cmd; + int ret; + size_t uint_3 = 0x83; + + cmd = &dev->cmd; + + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + uid = OPALUID[OPAL_LOCKINGSP_UID]; + method = OPALMETHOD[OPAL_ACTIVATE]; + + ret = test_and_add_token_va(cmd, "c2s", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH); + if (ret < 0) { + pr_err("%s: Error building Activate LockingSP command.\n", + dev->disk_name); + return ret; + } + /* Activating as SUM */ + if (dev->lr > 0) { + ret = build_locking_range(user_lr, sizeof(user_lr), dev->lr); + if (ret < 0) { + pr_err("%s: Can't build locking user\n", + dev->disk_name); + return ret; + } + test_and_add_token_va(cmd, "2c 4c csc 2c", + OPAL_STARTLIST, + OPAL_STARTNAME, + + uint_3, + OPAL_TINY_UINT_06, + OPAL_TINY_UINT_00, + OPAL_TINY_UINT_00, + + OPAL_STARTLIST, + user_lr, OPAL_UID_LENGTH, + OPAL_ENDLIST, + + OPAL_ENDNAME, + OPAL_ENDLIST); + } else /* Actiave Normal Mode */ + ret = test_and_add_token_va(cmd, "2c", + OPAL_STARTLIST, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building Activate LockingSP command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, generic_cont); +} + +static int get_lsp_lifecycle_cont(void *data) +{ + struct opal_dev *dev = data; + u8 lc_status; + int error = 0; + + error = parse_and_check_status(dev); + if (error) + goto err_return; + + lc_status = response_get_u64(&dev->parsed, 4); + /* 0x08 is Manufacured Inactive */ + /* 0x09 is Manufactured */ + if (lc_status != 0x08) { + pr_err("%s: Couldn't determine the status of the Lifcycle state\n", + dev->disk_name); + error = -ENODEV; + goto err_return; + } + +err_return: + return error; +} + +/* Determine if we're in the Manufactured Inactive or Active state */ +int get_lsp_lifecycle(struct opal_dev *dev) +{ + struct opal_cmd *cmd; + const u8 *method, *uid; + int ret; + + cmd = &dev->cmd; + + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + uid = OPALUID[OPAL_LOCKINGSP_UID]; + method = OPALMETHOD[OPAL_GET]; + + ret = test_and_add_token_va(cmd, "c2s 2c 4c 4c 2c", + OPAL_CALL, + uid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTLIST, + + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* Start Column */ + OPAL_TINY_UINT_06, /* Lifcycle Column */ + OPAL_ENDNAME, + + OPAL_STARTNAME, + OPAL_TINY_UINT_04, /* End Column */ + OPAL_TINY_UINT_06, /* Lifecycle Column */ + OPAL_ENDNAME, + + OPAL_ENDLIST, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error Building GET Lifecycle Status command\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, get_lsp_lifecycle_cont); +} + +static int get_msid_cpin_pin_cont(void *data) +{ + const char *msid_pin; + struct opal_dev *dev = data; + size_t strlen; + int error = 0; + + error = parse_and_check_status(dev); + if (error) + goto err_return; + + strlen = response_get_string(&dev->parsed, 4, &msid_pin); + if (!msid_pin) { + pr_err("%s: Couldn't extract PIN from response\n", __func__); + error = 1; + goto err_return; + } + + dev->prev_data = kmemdup(msid_pin, strlen, GFP_KERNEL); + if (!dev->prev_data) { + error = -ENOMEM; + goto err_return; + } + + dev->prev_d_len = strlen; + + err_return: + return error; +} + +static int get_msid_cpin_pin(struct opal_dev *dev) +{ + const u8 *method, *smuid; + int ret; + struct opal_cmd *cmd; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + set_comID(cmd, dev->comID); + + smuid = OPALUID[OPAL_C_PIN_MSID]; + method = OPALMETHOD[OPAL_GET]; + + ret = test_and_add_token_va(cmd, "c 2s 12c", + OPAL_CALL, + + smuid, OPAL_UID_LENGTH, + method, OPAL_METHOD_LENGTH, + + OPAL_STARTLIST, + OPAL_STARTLIST, + OPAL_STARTNAME, + OPAL_TINY_UINT_03, /* Sart Column */ + OPAL_TINY_UINT_03, /* PIN */ + OPAL_ENDNAME, + OPAL_STARTNAME, + OPAL_TINY_UINT_04, /* End Column */ + OPAL_TINY_UINT_03, /* PIN */ + OPAL_ENDNAME, + OPAL_ENDLIST, + OPAL_ENDLIST); + + if (ret < 0) { + pr_err("%s: Error building Get MSID CPIN PIN command.\n", + dev->disk_name); + return ret; + } + + return finalize_and_send(dev, cmd, get_msid_cpin_pin_cont); +} + +static void unlock_suspend_final(struct opal_dev *dev) +{ + dev->resume_from_suspend = false; + dev->resume_data = NULL; + dev->func_data = NULL; +} + +static int build_end_opal_session(struct opal_dev *dev) +{ + struct opal_cmd *cmd; + + cmd = &dev->cmd; + clear_opal_cmd(cmd); + + set_comID(cmd, dev->comID); + return test_and_add_token_u8(cmd, OPAL_ENDOFSESSION); +} + +static int end_opal_session(struct opal_dev *dev) +{ + int ret = build_end_opal_session(dev); + + if (ret < 0) + return ret; + return finalize_and_send(dev, &dev->cmd, end_session_cont); +} + +static struct opal_dev *find_opal_dev(dev_t majmin, u8 lr) +{ + struct opal_dev *iter, *opal_dev = NULL; + + list_for_each_entry(iter, &opal_list, node) { + if (MAJOR(iter->majmin) != MAJOR(majmin) || + MINOR(iter->majmin) != MINOR(majmin)) + continue; + + if (iter->lr == lr) { + opal_dev = iter; + break; + } + } + return opal_dev; +} + +static int update_opal_dev(struct opal_dev *old_dev, struct opal_dev *new_dev) +{ + if (!atomic_add_unless(&old_dev->in_use, 1, 1)) { + pr_err("%s: dev was in use\n", __func__); + return -EBUSY; + } + + old_dev->key_name_len = new_dev->key_name_len; + if (!memcpy(old_dev->key_name, new_dev->key_name, old_dev->key_name_len)) { + pr_err("%s: Error updating device:\n", old_dev->disk_name); + return -EFAULT; + } + + if (!strncpy(old_dev->disk_name, new_dev->disk_name, DISK_NAME_LEN)) { + pr_err("%s: Error registering device: copying disk name\n", + old_dev->disk_name); + return -EFAULT; + } + + old_dev->comID = new_dev->comID; + old_dev->start = new_dev->start; + old_dev->length = new_dev->length; + old_dev->align = new_dev->align; + old_dev->lowest_lba = new_dev->lowest_lba; + old_dev->state = new_dev->state; + old_dev->funcs = new_dev->funcs; + old_dev->majmin = new_dev->majmin; + old_dev->submit_fn = new_dev->submit_fn; + old_dev->submit_data = new_dev->submit_data; + + clean_function_data(old_dev); + + /* + * Won't be able to auto unlock this locking range based on block + * requestes. + */ + if (old_dev->length == 0) + pr_warn("%s: Missing block information for locking range %d\n", + old_dev->disk_name, old_dev->lr); + + return 0; +} + +int opal_register_cont(struct opal_dev *new_dev) +{ + struct opal_dev *old_dev; + unsigned long flags; + int error = 0; + + spin_lock_irqsave(&list_spinlock, flags); + + old_dev = find_opal_dev(new_dev->majmin, new_dev->lr); + if (!old_dev) { + list_add_tail(&new_dev->node, &opal_list); + old_dev = new_dev; + } else { + if (old_dev == new_dev) + error = 0; + else { + error = update_opal_dev(old_dev, new_dev); + clean_opal_key(new_dev); + kfree(new_dev); + } + } + + if (error) + list_del(&old_dev->node); + + spin_unlock_irqrestore(&list_spinlock, flags); + + if (!error) + pr_info("%s: Registered key for locking range: %d\n", + old_dev->disk_name, old_dev->lr); + + return error; +} + +const opal_step error_end_session[] = { + end_opal_session, + NULL, +}; +static int end_opal_session_error(struct opal_dev *dev) +{ + + dev->funcs = error_end_session; + dev->state = 0; + dev->error_cb = NULL; + return next(dev); +} + +static struct opal_dev *alloc_opal_dev(struct block_device *bdev, u8 lr) +{ + struct opal_dev *opal_dev; + struct request_queue *q; + unsigned long dma_align; + const char *disk_name; + struct opal_cmd *cmd; + int ret; + + opal_dev = kzalloc(sizeof(*opal_dev), GFP_KERNEL); + if (!opal_dev) + return ERR_PTR(-ENOMEM); + + opal_dev->majmin = bdev->bd_dev; + opal_dev->lr = lr; + cmd = &opal_dev->cmd; + cmd->cmd = cmd->cmd_buf; + cmd->resp = cmd->resp_buf; + + disk_name = bdev->bd_disk->disk_name; + if (!strncpy(opal_dev->disk_name, disk_name, DISK_NAME_LEN)) { + pr_err("%s: Error registering device: copying disk name\n", + disk_name); + ret = -EFAULT; + goto err_free_dev; + } + + q = bdev->bd_queue; + dma_align = (queue_dma_alignment(q) | q->dma_pad_mask) + 1; + cmd->cmd = (u8 *)round_up((uintptr_t)cmd->cmd, dma_align); + cmd->resp = (u8 *)round_up((uintptr_t)cmd->resp, dma_align); + + INIT_LIST_HEAD(&opal_dev->node); + atomic_set(&opal_dev->in_use, 1); + + opal_dev->state = 0; + + return opal_dev; + +err_free_dev: + kfree(opal_dev); + return ERR_PTR(ret); +} + +int opal_register(struct block_device *bdev, struct opal_key *key_cmd, + const opal_step *funcs, void *sbmt_data, + sed_sec_submit *submit_fn) +{ + struct opal_dev *new_dev = NULL; + u8 key_len = key_cmd->key_len; + u8 lr = key_cmd->lr; + int ret; + + new_dev = alloc_opal_dev(bdev, lr); + if (IS_ERR(new_dev)) { + pr_err("%s: Error registering device: allocation\n", + bdev->bd_disk->disk_name); + return PTR_ERR(new_dev); + } + + if (!memcpy(new_dev->key_name, key_cmd->key, key_len)) { + pr_err("%s: Error registering key: couldn't copy key\n", + new_dev->disk_name); + return -EFAULT; + } + + new_dev->key_name_len = key_len; + new_dev->key_type = key_cmd->key_type; + ret = get_opal_key(new_dev); + if (ret) { + pr_err("%s: Couldn't get key: %d\n", new_dev->disk_name, ret); + return ret; + } + + new_dev->funcs = funcs; + new_dev->submit_data = sbmt_data; + new_dev->submit_fn = submit_fn; + + new_dev->state = 0; + return next(new_dev); +} + +static struct opal_dev *get_registered_opal_dev(dev_t majmin, u8 lr) +{ + struct opal_dev *iter, *dev = NULL; + unsigned long flags; + bool in_use = false; + + spin_lock_irqsave(&list_spinlock, flags); + list_for_each_entry(iter, &opal_list, node) { + if (MAJOR(iter->majmin) != MAJOR(majmin) || + MINOR(iter->majmin) != MINOR(majmin)) + continue; + if (iter->lr == lr) { + dev = iter; + if (!atomic_add_unless(&iter->in_use, 1, 1)) { + dev = NULL; + in_use = true; + } + break; + } + } + + spin_unlock_irqrestore(&list_spinlock, flags); + + if (!dev) + return NULL; + + return dev; +} + +/* Free up the Opal dev and its keys during two scenarios: + * + * 1) When a command is complete that no longer requires + * the opal dev to be around. + * 2) When a command, including Opal Save fails we clean + * and free the opal dev. + * + * If we find the opal dev structure in the list of + * saved passwords we will *not* remove it. + */ +static void remove_and_clean_opal_dev(struct opal_dev *dev) +{ + struct opal_dev *iter; + bool found = false; + + atomic_dec(&dev->in_use); + spin_lock(&list_spinlock); + list_for_each_entry(iter, &opal_list, node) { + if (iter == dev) { + found = true; + break; + } + } + + spin_unlock(&list_spinlock); + if (!found) { + clean_opal_key(dev); + clean_function_data(dev); + kfree(dev); + } +} + +static struct opal_dev *get_or_create_opal_dev(struct block_device *bdev, + u8 lr, bool use_new) +{ + struct opal_dev *dev = NULL; + + if (!use_new) + dev = get_registered_opal_dev(bdev->bd_dev, lr); + + if (!dev) + dev = alloc_opal_dev(bdev, lr); + + return dev; +} + +static int setup_opal_dev(struct block_device *bdev, struct opal_dev *dev, + const opal_step *funcs, struct opal_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + int ret; + + dev->state = 0; + dev->funcs = funcs; + dev->TSN = 0; + dev->HSN = 0; + dev->lr = key->lr; + dev->error_cb = end_opal_session_error; + dev->error_cb_data = dev; + dev->submit_fn = submit_fn; + dev->submit_data = sbmt_data; + + if (key) { + memcpy(dev->key_name, key->key, key->key_len); + dev->key_name_len = key->key_len; + dev->key_type = key->key_type; + + ret = get_opal_key(dev); + if (ret) { + pr_err("%s: Couldn't get key: %d\n", + dev->disk_name, ret); + return ret; + } + } + dev->func_data = NULL; + return 0; +} + +int opal_secure_erase_locking_range(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + struct opal_dev *dev; + void *data[3] = { NULL }; + const opal_step erase_funcs[] = { + opal_discovery0, + start_auth_opal_session, + get_active_key, + gen_key, + end_opal_session, + NULL, + }; + int ret; + + dev = get_or_create_opal_dev(bdev, key->opal_act.key.lr, true); + if (!dev) + return -ENOMEM; + + ret = setup_opal_dev(bdev, dev, erase_funcs, &key->opal_act.key, + sbmt_data, submit_fn); + dev->func_data = data; + dev->func_data[1] = &key->opal_act.who; + if (ret) + goto error_return; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_secure_erase_locking_range); + +int opal_erase_locking_range(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + struct opal_dev *dev; + const opal_step erase_funcs[] = { + opal_discovery0, + start_auth_opal_session, + erase_locking_range, + end_opal_session, + NULL, + }; + int ret; + + dev = get_or_create_opal_dev(bdev, key->opal_lrs.key.lr, true); + if (!dev) + return -ENOMEM; + + ret = setup_opal_dev(bdev, dev, erase_funcs, &key->opal_lrs.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_erase_locking_range); + +int opal_enable_disable_shadow_mbr(struct block_device *bdev, + struct sed_key *key, void *sbmt_data, + sed_sec_submit *submit_fn) +{ + void *func_data[6] = { NULL }; + struct opal_dev *dev; + const opal_step mbr_funcs[] = { + opal_discovery0, + start_admin1LSP_opal_session, + set_mbr_done, + end_opal_session, + start_admin1LSP_opal_session, + set_mbr_enable_disable, + end_opal_session, + NULL, + }; + int ret; + + if (key->opal_mbr.enable_disable != OPAL_MBR_ENABLE && + key->opal_mbr.enable_disable != OPAL_MBR_DISABLE) + return -EINVAL; + + dev = get_or_create_opal_dev(bdev, key->opal_mbr.key.lr, true); + if (!dev) + return -ENOMEM; + + ret = setup_opal_dev(bdev, dev, mbr_funcs, &key->opal_mbr.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->num_func_data = 6; + dev->func_data = func_data; + dev->func_data[2] = &key->opal_mbr.enable_disable; + dev->func_data[5] = &key->opal_mbr.enable_disable; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; + +} +EXPORT_SYMBOL(opal_enable_disable_shadow_mbr); + +int opal_save(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + void *func_data[3] = { NULL }; + struct opal_dev *dev; + const opal_step _auth_funcs[] = { + opal_discovery0, + start_auth_opal_session, + query_locking_range, + end_opal_session, + opal_register_cont, + NULL + }; + int ret; + + dev = get_or_create_opal_dev(bdev, key->opal_lk_unlk.key.lr, false); + if (!dev) + return -ENOMEM; + ret = setup_opal_dev(bdev, dev, _auth_funcs, &key->opal_lk_unlk.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->num_func_data = 3; + dev->func_data = func_data; + dev->func_data[1] = &key->opal_lk_unlk.authority; + dev->lkul = key->opal_lk_unlk; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_save); + +int opal_add_user_to_lr(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + void *func_data[3] = { NULL }; + struct opal_dev *dev; + const opal_step funcs[] = { + opal_discovery0, + start_admin1LSP_opal_session, + add_user_to_lr, + end_opal_session, + NULL + }; + int ret; + + if (!bdev || !bdev->bd_disk) { + pr_err("Can't assign user to LR without backing disk\n"); + return -EFAULT; + } + if (key->opal_lk_unlk.l_state != OPAL_RO && + key->opal_lk_unlk.l_state != OPAL_RW) { + pr_err("Locking state was not RO or RW\n"); + return -EINVAL; + } + if (key->opal_lk_unlk.authority.who < OPAL_USER1 && + key->opal_lk_unlk.authority.who > OPAL_USER9) { + pr_err("Authority was not within the range of users: %d\n", + key->opal_lk_unlk.authority.who); + return -EINVAL; + } + if (key->opal_lk_unlk.authority.SUM) { + pr_err("%s not supported in SUM. Use setup locking range\n", + __func__); + return -EINVAL; + } + + dev = get_or_create_opal_dev(bdev, key->opal_lk_unlk.key.lr, true); + if (!dev) + return -ENOMEM; + ret = setup_opal_dev(bdev, dev, funcs, &key->opal_lk_unlk.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->num_func_data = 3; + dev->func_data = func_data; + dev->func_data[2] = &key->opal_lk_unlk; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; + +} +EXPORT_SYMBOL(opal_add_user_to_lr); + +int opal_reverttper(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + const opal_step revert_funcs[] = { + opal_discovery0, + start_SIDASP_opal_session, + revert_tper, /* controller will terminate session */ + NULL, + }; + + return opal_register(bdev, &key->opal, revert_funcs, + sbmt_data, submit_fn); +} +EXPORT_SYMBOL(opal_reverttper); + +/* These are global'd because both lock_unlock_internal + * and opal_unlock_from_suspend need them. + */ +const opal_step ulk_funcs_SUM[] = { + opal_discovery0, + start_auth_opal_session, + lock_unlock_locking_range_SUM, + end_opal_session, + NULL +}; +const opal_step _unlock_funcs[] = { + opal_discovery0, + start_auth_opal_session, + lock_unlock_locking_range, + end_opal_session, + NULL +}; +int opal_lock_unlock(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + void *func_data[3] = { NULL }; + struct opal_dev *dev; + int ret; + + if (key->opal_lk_unlk.authority.who < OPAL_ADMIN1 || + key->opal_lk_unlk.authority.who > OPAL_USER9) + return -EINVAL; + + dev = get_or_create_opal_dev(bdev, key->opal_lk_unlk.key.lr, true); + if (!dev) + return -ENOMEM; + + if (key->opal_lk_unlk.authority.SUM) + ret = setup_opal_dev(bdev, dev, ulk_funcs_SUM, + &key->opal_lk_unlk.key, + sbmt_data, submit_fn); + else + ret = setup_opal_dev(bdev, dev, _unlock_funcs, + &key->opal_lk_unlk.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->num_func_data = 3; + dev->func_data = func_data; + dev->func_data[1] = &key->opal_lk_unlk.authority; + dev->func_data[2] = &key->opal_lk_unlk; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_lock_unlock); + +int opal_take_ownership(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + const opal_step owner_funcs[] = { + opal_discovery0, + start_anybodyASP_opal_session, + get_msid_cpin_pin, + end_opal_session, + start_SIDASP_opal_session, + set_sid_cpin_pin, + end_opal_session, + NULL + }; + + return opal_register(bdev, &key->opal, owner_funcs, sbmt_data, + submit_fn); +} +EXPORT_SYMBOL(opal_take_ownership); + +int opal_activate_lsp(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + const opal_step active_funcs[] = { + opal_discovery0, + start_SIDASP_opal_session, /* Open session as SID auth */ + get_lsp_lifecycle, + activate_lsp, + end_opal_session, + NULL + }; + struct opal_dev *dev; + int ret; + + dev = get_or_create_opal_dev(bdev, key->opal.lr, true); + if (!dev) + return -ENOMEM; + ret = setup_opal_dev(bdev, dev, active_funcs, &key->opal, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_activate_lsp); + +int opal_setup_locking_range(struct block_device *bdev, struct sed_key *pw, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + struct opal_dev *dev; + void *data[3] = { NULL }; + const opal_step lr_funcs[] = { + opal_discovery0, + start_auth_opal_session, + setup_locking_range, + end_opal_session, + NULL, + }; + int ret; + + dev = get_or_create_opal_dev(bdev, pw->opal_lrs.key.lr, true); + if (!dev) + return -ENOMEM; + + ret = setup_opal_dev(bdev, dev, lr_funcs, &pw->opal_lrs.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->func_data = data; + dev->num_func_data = 3; + dev->func_data[1] = &pw->opal_lrs.who; + dev->func_data[2] = &pw->opal_lrs; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_setup_locking_range); + +int opal_set_new_pw(struct block_device *bdev, struct sed_key *pw, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + const opal_step pw_funcs[] = { + opal_discovery0, + start_auth_opal_session, + set_new_pw, + end_opal_session, + NULL + }; + struct opal_dev *dev; + void *data[3] = { NULL }; + int ret; + + if (pw->sed_type != OPAL_PW) + return -EINVAL; + + if (pw->opal_pw.who.who < OPAL_ADMIN1 || + pw->opal_pw.who.who > OPAL_USER9) + return -EINVAL; + + dev = get_or_create_opal_dev(bdev, pw->opal_pw.current_pin.lr, true); + if (!dev) + return -ENOMEM; + + ret = setup_opal_dev(bdev, dev, pw_funcs, + &pw->opal_pw.current_pin, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->num_func_data = 3; + dev->func_data = data; + dev->func_data[1] = (void *) &pw->opal_pw.who; + dev->func_data[2] = (void *) &pw->opal_pw; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; +} +EXPORT_SYMBOL(opal_set_new_pw); + +int opal_activate_user(struct block_device *bdev, struct sed_key *pw, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + const opal_step act_funcs[] = { + opal_discovery0, + start_admin1LSP_opal_session, + internal_activate_user, + end_opal_session, + NULL + }; + struct opal_dev *dev; + void *data[3] = { NULL }; + int ret; + + if (pw->sed_type != OPAL_ACT_USR) { + pr_err("Sed type was not act user\n"); + return -EINVAL; + } + + /* We can't activate Admin1 it's active as manufactured */ + if (pw->opal_act.who.who < OPAL_USER1 && + pw->opal_act.who.who > OPAL_USER9) { + pr_err("Who was not a valid user: %d \n", pw->opal_act.who.who); + return -EINVAL; + } + + dev = get_or_create_opal_dev(bdev, pw->opal_act.key.lr, true); + if (!dev) + return -ENOMEM; + + ret = setup_opal_dev(bdev, dev, act_funcs, &pw->opal_act.key, + sbmt_data, submit_fn); + if (ret) + goto error_return; + + dev->num_func_data = 3; + dev->func_data = data; + dev->func_data[1] = &pw->opal_act; + dev->func_data[2] = &pw->opal_act; + + ret = next(dev); + + error_return: + remove_and_clean_opal_dev(dev); + return ret; + +} +EXPORT_SYMBOL(opal_activate_user); + +int opal_unlock_from_suspend(struct opal_suspend_unlk *data) +{ + int majmin = data->dev; + struct opal_dev *iter, *dev = NULL; + void *func_data[3] = { NULL }; + u8 count = 0; + struct opal_dev *todo[64] = { NULL }; + int ret = 0; + bool was_failure = false; + + spin_lock(&list_spinlock); + list_for_each_entry(iter, &opal_list, node) { + if (MAJOR(iter->majmin) != MAJOR(majmin) || + MINOR(iter->majmin) != MINOR(majmin)) + continue; + + if (atomic_add_unless(&iter->in_use, 1, 1)) { + if (count < 64) + todo[count++] = iter; + else + break; + } + } + spin_unlock(&list_spinlock); + + while (count) { + dev = todo[--count]; + dev->func_data = func_data; + dev->resume_from_suspend = true; + dev->resume_data = data; + dev->error_cb = end_opal_session_error; + dev->error_cb_data = dev; + dev->state = 0; + if (dev->lkul.authority.SUM) + dev->funcs = ulk_funcs_SUM; + else + dev->funcs = _unlock_funcs; + dev->TSN = 0; + dev->HSN = 0; + dev->func_data[2] = &dev->lkul; + dev->func_data[1] = &dev->lkul.authority; + ret = next(dev); + if (ret) + was_failure = true; + unlock_suspend_final(dev); + } + return was_failure ? 1 : 0; +} +EXPORT_SYMBOL(opal_unlock_from_suspend); diff --git a/block/sed-opal_internal.h b/block/sed-opal_internal.h new file mode 100644 index 0000000..12369eb --- /dev/null +++ b/block/sed-opal_internal.h @@ -0,0 +1,601 @@ +/* + * Copyright ? 2016 Intel Corporation + * + * Authors: + * Rafael Antognolli + * Scott Bauer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef _NVME_OPAL_INTERNAL_H +#define _NVME_OPAL_INTERNAL_H + +#include +#include + +#define DTAERROR_NO_METHOD_STATUS 0x89 +#define GENERIC_HOST_SESSION_NUM 0x41 + + + +/* + * Derived from: + * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 + * Section: 5.1.5 Method Status Codes + */ +static const char *opal_errors[] = { + "Success", + "Not Authorized", + "Unknown Error", + "SP Busy", + "SP Failed", + "SP Disabled", + "SP Frozen", + "No Sessions Available", + "Uniqueness Conflict", + "Insufficient Space", + "Insufficient Rows", + "Invalid Function", + "Invalid Parameter", + "Invalid Reference", + "Unknown Error", + "TPER Malfunction", + "Transaction Failure", + "Response Overflow", + "Authority Locked Out", +}; + +static const char *opal_error_to_human(int error) +{ + if (error == 0x3f) + return "Failed"; + + if (error >= ARRAY_SIZE(opal_errors) || error < 0) + return "Unknown Error"; + + return opal_errors[error]; +} + +/* + * User IDs used in the TCG storage SSCs + * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 + * Section: 6.3 Assigned UIDs + */ +static const u8 OPALUID[][8] = { + /* users */ + + /* session management */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, + /* special "thisSP" syntax */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + /* Administrative SP */ + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, + /* Locking SP */ + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, + /* ENTERPRISE Locking SP */ + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, + /* anybody */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, + /* SID */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06 }, + /* ADMIN1 */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }, + /* USER1 */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, + /* USER2 */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x02 }, + /* PSID user */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x01, 0xff, 0x01 }, + /* BandMaster 0 */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x01 }, + /* EraseMaster */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x84, 0x01 }, + + /* tables */ + + /* Locking_GlobalRange */ + { 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x01 }, + /* ACE_Locking_Range_Set_RdLocked UID */ + { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE0, 0x01 }, + /* ACE_Locking_Range_Set_WrLocked UID */ + { 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0xE8, 0x01 }, + /* MBR Control */ + { 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x01 }, + /* Shadow MBR */ + { 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00 }, + /* AUTHORITY_TABLE */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00}, + /* C_PIN_TABLE */ + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00}, + /* OPAL Locking Info */ + { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x01 }, + /* Enterprise Locking Info */ + { 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00 }, + + /* C_PIN_TABLE object ID's */ + + /* C_PIN_MSID */ + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x84, 0x02}, + /* C_PIN_SID */ + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01}, + /* C_PIN_ADMIN1 */ + { 0x00, 0x00, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01}, + + /* half UID's (only first 4 bytes used) */ + + /* Half-UID ? Authority_object_ref */ + { 0x00, 0x00, 0x0C, 0x05, 0xff, 0xff, 0xff, 0xff }, + /* Half-UID ? Boolean ACE */ + { 0x00, 0x00, 0x04, 0x0E, 0xff, 0xff, 0xff, 0xff }, + + /* special value for omitted optional parameter */ + + /* HEXFF for omitted */ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; +static const size_t OPAL_UID_LENGTH = 8; +static const size_t OPAL_MSID_KEYLEN = 15; +static const size_t OPAL_UID_LENGTH_HALF = 4; + + +/* Enum to index OPALUID array */ +enum OPAL_UID { + /* users */ + OPAL_SMUID_UID, + OPAL_THISSP_UID, + OPAL_ADMINSP_UID, + OPAL_LOCKINGSP_UID, + OPAL_ENTERPRISE_LOCKINGSP_UID, + OPAL_ANYBODY_UID, + OPAL_SID_UID, + OPAL_ADMIN1_UID, + OPAL_USER1_UID, + OPAL_USER2_UID, + OPAL_PSID_UID, + OPAL_ENTERPRISE_BANDMASTER0_UID, + OPAL_ENTERPRISE_ERASEMASTER_UID, + /* tables */ + OPAL_LOCKINGRANGE_GLOBAL, + OPAL_LOCKINGRANGE_ACE_RDLOCKED, + OPAL_LOCKINGRANGE_ACE_WRLOCKED, + OPAL_MBRCONTROL, + OPAL_MBR, + OPAL_AUTHORITY_TABLE, + OPAL_C_PIN_TABLE, + OPAL_LOCKING_INFO_TABLE, + OPAL_ENTERPRISE_LOCKING_INFO_TABLE, + /* C_PIN_TABLE object ID's */ + OPAL_C_PIN_MSID, + OPAL_C_PIN_SID, + OPAL_C_PIN_ADMIN1, + /* half UID's (only first 4 bytes used) */ + OPAL_HALF_UID_AUTHORITY_OBJ_REF, + OPAL_HALF_UID_BOOLEAN_ACE, + /* omitted optional parameter */ + OPAL_UID_HEXFF, +}; + +/* + * TCG Storage SSC Methods. + * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 + * Section: 6.3 Assigned UIDs + */ +static const u8 OPALMETHOD[][8] = { + /* Properties */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01 }, + /* STARTSESSION */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02 }, + /* Revert */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x02 }, + /* Activate */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x03 }, + /* Enterprise Get */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06 }, + /* Enterprise Set */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07 }, + /* NEXT */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08 }, + /* Enterprise Authenticate */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c }, + /* GetACL */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d }, + /* GenKey */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10 }, + /* revertSP */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11 }, + /* Get */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x16 }, + /* Set */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x17 }, + /* Authenticate */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c }, + /* Random */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x01 }, + /* Erase */ + { 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x03 }, +}; +static const size_t OPAL_METHOD_LENGTH = 8; + +/* Enum for indexing the OPALMETHOD array */ +enum OPAL_METHOD { + OPAL_PROPERTIES, + OPAL_STARTSESSION, + OPAL_REVERT, + OPAL_ACTIVATE, + OPAL_EGET, + OPAL_ESET, + OPAL_NEXT, + OPAL_EAUTHENTICATE, + OPAL_GETACL, + OPAL_GENKEY, + OPAL_REVERTSP, + OPAL_GET, + OPAL_SET, + OPAL_AUTHENTICATE, + OPAL_RANDOM, + OPAL_ERASE, +}; + +/* + * Token defs derived from: + * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 + * 3.2.2 Data Stream Encoding + */ +enum OPAL_RESPONSE_TOKEN { + OPAL_DTA_TOKENID_BYTESTRING = 0xe0, + OPAL_DTA_TOKENID_SINT = 0xe1, + OPAL_DTA_TOKENID_UINT = 0xe2, + OPAL_DTA_TOKENID_TOKEN = 0xe3, /* actual token is returned */ + OPAL_DTA_TOKENID_INVALID = 0X0 +}; + +enum OPAL_TOKEN { + /* Boolean */ + OPAL_TRUE = 0x01, + OPAL_FALSE = 0x00, + OPAL_BOOLEAN_EXPR = 0x03, + /* cellblocks */ + OPAL_TABLE = 0x00, + OPAL_STARTROW = 0x01, + OPAL_ENDROW = 0x02, + OPAL_STARTCOLUMN = 0x03, + OPAL_ENDCOLUMN = 0x04, + OPAL_VALUES = 0x01, + /* authority table */ + OPAL_PIN = 0x03, + /* locking tokens */ + OPAL_RANGESTART = 0x03, + OPAL_RANGELENGTH = 0x04, + OPAL_READLOCKENABLED = 0x05, + OPAL_WRITELOCKENABLED = 0x06, + OPAL_READLOCKED = 0x07, + OPAL_WRITELOCKED = 0x08, + OPAL_ACTIVEKEY = 0x0A, + /* locking info table */ + OPAL_MAXRANGES = 0x04, + /* mbr control */ + OPAL_MBRENABLE = 0x01, + OPAL_MBRDONE = 0x02, + /* properties */ + OPAL_HOSTPROPERTIES = 0x00, + /* atoms */ + OPAL_STARTLIST = 0xf0, + OPAL_ENDLIST = 0xf1, + OPAL_STARTNAME = 0xf2, + OPAL_ENDNAME = 0xf3, + OPAL_CALL = 0xf8, + OPAL_ENDOFDATA = 0xf9, + OPAL_ENDOFSESSION = 0xfa, + OPAL_STARTTRANSACTON = 0xfb, + OPAL_ENDTRANSACTON = 0xfC, + OPAL_EMPTYATOM = 0xff, + OPAL_WHERE = 0x00, +}; + +/* Useful tiny atoms. + * Useful for table columns etc + */ +enum OPAL_TINY_ATOM { + OPAL_TINY_UINT_00 = 0x00, + OPAL_TINY_UINT_01 = 0x01, + OPAL_TINY_UINT_02 = 0x02, + OPAL_TINY_UINT_03 = 0x03, + OPAL_TINY_UINT_04 = 0x04, + OPAL_TINY_UINT_05 = 0x05, + OPAL_TINY_UINT_06 = 0x06, + OPAL_TINY_UINT_07 = 0x07, + OPAL_TINY_UINT_08 = 0x08, + OPAL_TINY_UINT_09 = 0x09, + OPAL_TINY_UINT_10 = 0x0a, + OPAL_TINY_UINT_11 = 0x0b, + OPAL_TINY_UINT_12 = 0x0c, + OPAL_TINY_UINT_13 = 0x0d, + OPAL_TINY_UINT_14 = 0x0e, + OPAL_TINY_UINT_15 = 0x0f, +}; + +enum OPAL_ATOM_WIDTH { + OPAL_WIDTH_TINY, + OPAL_WIDTH_SHORT, + OPAL_WIDTH_MEDIUM, + OPAL_WIDTH_LONG, + OPAL_WIDTH_TOKEN +}; + +/* Locking state for a locking range */ +enum OPAL_LOCKINGSTATE { + OPAL_LOCKING_READWRITE = 0x01, + OPAL_LOCKING_READONLY = 0x02, + OPAL_LOCKING_LOCKED = 0x03, +}; + +/* + * Structures to build and decode the Opal SSC messages + * fields that are NOT really numeric are defined as u8[] to + * help reduce the endianness issues + */ + +/* Packets derived from: + * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 + * Secion: 3.2.3 ComPackets, Packets & Subpackets + */ + +/* Comm Packet (header) for transmissions. */ +struct opal_compacket { + u32 reserved0; + u8 extendedComID[4]; + u32 outstandingData; + u32 minTransfer; + u32 length; +}; + +/* Packet structure. */ +struct opal_packet { + u32 TSN; + u32 HSN; + u32 seq_number; + u16 reserved0; + u16 ack_type; + u32 acknowledgment; + u32 length; +}; + +/* Data sub packet header */ +struct opal_data_subpacket { + u8 reserved0[6]; + u16 kind; + u32 length; +}; + +/* header of a response */ +struct opal_header { + struct opal_compacket cp; + struct opal_packet pkt; + struct opal_data_subpacket subpkt; +}; + +#define FC_TPER 0x0001 +#define FC_LOCKING 0x0002 +#define FC_GEOMETRY 0x0003 +#define FC_ENTERPRISE 0x0100 +#define FC_DATASTORE 0x0202 +#define FC_SINGLEUSER 0x0201 +#define FC_OPALV100 0x0200 +#define FC_OPALV200 0x0203 + +/* + * The Discovery 0 Header. As defined in + * Opal SSC Documentation + * Section: 3.3.5 Capability Discovery + */ +struct d0_header { + u32 length; /* the length of the header 48 in 2.00.100 */ + u32 revision; /**< revision of the header 1 in 2.00.100 */ + u32 reserved01; + u32 reserved02; + /* + * the remainder of the structure is vendor specific and will not be + * addressed now + */ + u8 ignored[32]; +}; + +/* + * TPer Feature Descriptor. Contains flags indicating support for the + * TPer features described in the OPAL specification. The names match the + * OPAL terminology + * + * code == 0x001 in 2.00.100 + */ +struct d0_tper_features { + /* + * supported_features bits: + * bit 7: reserved + * bit 6: com ID management + * bit 5: reserved + * bit 4: streaming support + * bit 3: buffer management + * bit 2: ACK/NACK + * bit 1: async + * bit 0: sync + */ + u8 supported_features; + /* + * bytes 5 through 15 are reserved, but we represent the first 3 as + * u8 to keep the other two 32bits integers aligned. + */ + u8 reserved01[3]; + u32 reserved02; + u32 reserved03; +}; + +/* + * Locking Feature Descriptor. Contains flags indicating support for the + * locking features described in the OPAL specification. The names match the + * OPAL terminology + * + * code == 0x0002 in 2.00.100 + */ +struct d0_locking_features { + /* + * supported_features bits: + * bits 6-7: reserved + * bit 5: MBR done + * bit 4: MBR enabled + * bit 3: media encryption + * bit 2: locked + * bit 1: locking enabled + * bit 0: locking supported + */ + u8 supported_features; + /* + * bytes 5 through 15 are reserved, but we represent the first 3 as + * u8 to keep the other two 32bits integers aligned. + */ + u8 reserved01[3]; + u32 reserved02; + u32 reserved03; +}; + +/* + * Geometry Feature Descriptor. Contains flags indicating support for the + * geometry features described in the OPAL specification. The names match the + * OPAL terminology + * + * code == 0x0003 in 2.00.100 + */ +struct d0_geometry_features { + /* + * skip 32 bits from header, needed to align the struct to 64 bits. + */ + u8 header[4]; + /* + * reserved01: + * bits 1-6: reserved + * bit 0: align + */ + u8 reserved01; + u8 reserved02[7]; + u32 logical_block_size; + u64 alignment_granularity; + u64 lowest_aligned_lba; +}; + +/* + * Enterprise SSC Feature + * + * code == 0x0100 + */ +struct d0_enterprise_ssc { + u16 baseComID; + u16 numComIDs; + /* range_crossing: + * bits 1-6: reserved + * bit 0: range crossing + */ + u8 range_crossing; + u8 reserved01; + u16 reserved02; + u32 reserved03; + u32 reserved04; +}; + +/* + * Opal V1 feature + * + * code == 0x0200 + */ +struct d0_opal_v100 { + u16 baseComID; + u16 numComIDs; +}; + +/* + * Single User Mode feature + * + * code == 0x0201 + */ +struct d0_single_user_mode { + u32 num_locking_objects; + /* reserved01: + * bit 0: any + * bit 1: all + * bit 2: policy + * bits 3-7: reserved + */ + u8 reserved01; + u8 reserved02; + u16 reserved03; + u32 reserved04; +}; + +/* + * Additonal Datastores feature + * + * code == 0x0202 + */ +struct d0_datastore_table { + u16 reserved01; + u16 max_tables; + u32 max_size_tables; + u32 table_size_alignment; +}; + +/* + * OPAL 2.0 feature + * + * code == 0x0203 + */ +struct d0_opal_v200 { + u16 baseComID; + u16 numComIDs; + /* range_crossing: + * bits 1-6: reserved + * bit 0: range crossing + */ + u8 range_crossing; + /* num_locking_admin_auth: + * not aligned to 16 bits, so use two u8. + * stored in big endian: + * 0: MSB + * 1: LSB + */ + u8 num_locking_admin_auth[2]; + /* num_locking_user_auth: + * not aligned to 16 bits, so use two u8. + * stored in big endian: + * 0: MSB + * 1: LSB + */ + u8 num_locking_user_auth[2]; + u8 initialPIN; + u8 revertedPIN; + u8 reserved01; + u32 reserved02; +}; + +/* Union of features used to parse the discovery 0 response */ +struct d0_features { + u16 code; + /* + * r_version bits: + * bits 4-7: version + * bits 0-3: reserved + */ + u8 r_version; + u8 length; + u8 features[]; +}; + +struct key *request_user_key(const char *master_desc, const u8 **master_key, + size_t *master_keylen); + +#endif /* _NVME_OPAL_INTERNAL_H */ diff --git a/block/sed.c b/block/sed.c new file mode 100644 index 0000000..241b1dc --- /dev/null +++ b/block/sed.c @@ -0,0 +1,207 @@ +/* + * Copyright ? 2016 Intel Corporation + * + * Authors: + * Rafael Antognolli + * Scott Bauer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include + + +int sed_save(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + switch (key->sed_type) { + case OPAL_LOCK_UNLOCK: + return opal_save(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_lock_unlock(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + switch (key->sed_type) { + case OPAL_LOCK_UNLOCK: + return opal_lock_unlock(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_take_ownership(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL: + return opal_take_ownership(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_activate_lsp(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL: + return opal_activate_lsp(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_set_pw(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL_PW: + return opal_set_new_pw(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_activate_user(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL_ACT_USR: + return opal_activate_user(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_reverttper(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL: + return opal_reverttper(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_setup_locking_range(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL_LR_SETUP: + return opal_setup_locking_range(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_adduser_to_lr(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL_LOCK_UNLOCK: + return opal_add_user_to_lr(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_do_mbr(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL_MBR_DATA: + return opal_enable_disable_shadow_mbr(bdev, key, sbmt_data, + submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_erase_lr(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + + switch (key->sed_type) { + case OPAL: + return opal_erase_locking_range(bdev, key, sbmt_data, submit_fn); + } + + return -EOPNOTSUPP; +} + +int sed_secure_erase_lr(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) +{ + switch (key->sed_type) { + case OPAL_ACT_USR: + return opal_secure_erase_locking_range(bdev, key, + sbmt_data, submit_fn); + + } + return -EOPNOTSUPP; +} + + +#define CMD_TO_FN_INDX(cmd) \ + (cmd) - IOC_SED_SAVE + +int (*sed_fn[])(struct block_device *bdev, struct sed_key *key, + void *sbmt_data, sed_sec_submit *submit_fn) = +{ + sed_save, + sed_lock_unlock, + sed_take_ownership, + sed_activate_lsp, + sed_set_pw, + sed_activate_user, + sed_reverttper, + sed_setup_locking_range, + sed_adduser_to_lr, + sed_do_mbr, + sed_erase_lr, + sed_secure_erase_lr +}; + +/* The sbmt_ctrl_data is a opaque pointer to some structure which will be used + * by the submit_fn to properly submit the opal command to the controller. + * The submit_fn must be a blocking call. + */ +int blkdev_sed_ioctl(struct block_device *bdev, fmode_t fmode, unsigned int cmd, + unsigned long arg, void *sbmt_ctrl_data, + sed_sec_submit *submit_fn) +{ + struct sed_key key; + + /* Caller should do this but since we're going to use cmd as an index + * lets 'trust but verify'. + */ + if (!is_sed_ioctl(cmd)) + return -EINVAL; + if (copy_from_user(&key, (void __user *)arg, sizeof(key))) + return -EFAULT; + return sed_fn[CMD_TO_FN_INDX(cmd)](bdev, &key, sbmt_ctrl_data, submit_fn); +} +EXPORT_SYMBOL_GPL(blkdev_sed_ioctl); -- 2.7.4