This allows co-existense of meshd and bluetoothd. meshd will
automatically take control of the first available LE-capable
controller that is powered down.
---
Makefile.mesh | 4 +-
mesh/btmesh.c | 5 +-
mesh/main.c | 22 ++---
mesh/mesh.c | 253 +++++++++++++++++++++++++++++++++++++++++++++-----
mesh/mesh.h | 4 +-
mesh/net.c | 49 +++++-----
6 files changed, 269 insertions(+), 68 deletions(-)
diff --git a/Makefile.mesh b/Makefile.mesh
index 643b1a59a..e93e68e38 100644
--- a/Makefile.mesh
+++ b/Makefile.mesh
@@ -23,7 +23,7 @@ libexec_PROGRAMS += mesh/meshd
mesh_meshd_SOURCES = $(mesh_sources) mesh/main.c
mesh_meshd_LDADD = src/shared/ecc.lo src/shared/queue.lo src/shared/io-ell.lo \
- src/shared/util.lo src/shared/hci.lo \
+ src/shared/util.lo src/shared/hci.lo src/shared/mgmt.lo \
@DBUS_LIBS@ @ELL_LIBS@ -ljson-c
noinst_PROGRAMS += mesh/btmesh
@@ -34,7 +34,7 @@ mesh_btmesh_SOURCES = $(mesh_sources) \
mesh/btmesh.c
mesh_btmesh_LDADD = src/shared/ecc.lo src/shared/queue.lo src/shared/io-ell.lo \
- src/shared/util.lo src/shared/hci.lo \
+ src/shared/util.lo src/shared/hci.lo src/shared/mgmt.lo \
src/libshared-mainloop.la \
-lreadline @ELL_LIBS@ -ljson-c
diff --git a/mesh/btmesh.c b/mesh/btmesh.c
index c312d85db..108ec39f3 100644
--- a/mesh/btmesh.c
+++ b/mesh/btmesh.c
@@ -153,8 +153,8 @@ int main(int argc, char *argv[])
l_info("Starting mesh on hci%d\n", index);
- mesh = mesh_create(index);
- if (!mesh || !mesh_load_config(mesh, config_option)) {
+ mesh = mesh_new(index, config_option);
+ if (!mesh) {
l_info("Failed to create mesh\n");
bt_shell_cleanup();
return EXIT_FAILURE;
@@ -170,6 +170,7 @@ int main(int argc, char *argv[])
bt_shell_run();
mesh_unref(mesh);
+ mesh_cleanup();
l_main_exit();
return status;
diff --git a/mesh/main.c b/mesh/main.c
index 8c03f51eb..289b0582b 100644
--- a/mesh/main.c
+++ b/mesh/main.c
@@ -30,6 +30,9 @@
#include <sys/stat.h>
#include <ell/ell.h>
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
#include "mesh/mesh.h"
#include "mesh/net.h"
#include "mesh/storage.h"
@@ -81,6 +84,7 @@ int main(int argc, char *argv[])
sigset_t mask;
struct bt_mesh *mesh = NULL;
const char *config_file = NULL;
+ int index = MGMT_INDEX_NONE;
if (!l_main_init())
return -1;
@@ -107,12 +111,7 @@ int main(int argc, char *argv[])
goto done;
}
- mesh = mesh_create(atoi(str));
- if (!mesh) {
- l_error("Failed to initialize mesh");
- status = EXIT_FAILURE;
- goto done;
- }
+ index = atoi(str);
break;
case 'n':
@@ -135,14 +134,8 @@ int main(int argc, char *argv[])
}
}
- if (!mesh) {
- usage();
- status = EXIT_FAILURE;
- goto done;
- }
-
- if (!mesh_load_config(mesh, config_file)) {
- l_error("Failed to load mesh configuration: %s", config_file);
+ if (!mesh_new(index, config_file)) {
+ l_error("Failed to initialize mesh");
status = EXIT_FAILURE;
goto done;
}
@@ -168,6 +161,7 @@ int main(int argc, char *argv[])
done:
mesh_unref(mesh);
+ mesh_cleanup();
l_main_exit();
return status;
diff --git a/mesh/mesh.c b/mesh/mesh.c
index a6f733f5c..3fba0140c 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -26,9 +26,11 @@
#include <ell/ell.h>
#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
-#include "mesh/mesh-defs.h"
+#include "src/shared/mgmt.h"
+#include "mesh/mesh-defs.h"
#include "mesh/mesh-io.h"
#include "mesh/node.h"
#include "mesh/net.h"
@@ -44,11 +46,25 @@ struct scan_filter {
struct bt_mesh {
struct mesh_net *net;
- int ref_count;
+ struct mesh_io *io;
struct l_queue *filters;
+ int ref_count;
+ uint16_t index;
+ uint16_t req_index;
uint8_t max_filters;
};
+static struct l_queue *controllers;
+static struct l_queue *mesh_list;
+static struct mgmt *mgmt_mesh;
+static bool initialized;
+static struct bt_mesh *current;
+
+static bool simple_match(const void *a, const void *b)
+{
+ return a == b;
+}
+
static void save_exit_config(struct bt_mesh *mesh)
{
const char *cfg_filename;
@@ -64,36 +80,233 @@ static void save_exit_config(struct bt_mesh *mesh)
l_info("Saved final configuration to %s", cfg_filename);
}
-struct bt_mesh *mesh_create(uint16_t index)
+static void start_io(struct bt_mesh *mesh, uint16_t index)
{
- struct bt_mesh *mesh;
struct mesh_io *io;
struct mesh_io_caps caps;
+ l_debug("Starting mesh on hci %u", index);
+
+ io = mesh_io_new(index, MESH_IO_TYPE_GENERIC);
+ if (!io) {
+ l_error("Failed to start mesh io (hci %u)", index);
+ current = NULL;
+ return;
+ }
+
+ mesh_io_get_caps(io, &caps);
+ mesh->max_filters = caps.max_num_filters;
+
+ mesh_net_attach(mesh->net, io);
+ mesh_net_set_window_accuracy(mesh->net, caps.window_accuracy);
+ mesh->io = io;
+ mesh->index = index;
+
+ current = NULL;
+
+ l_debug("Started mesh (io %p) on hci %u", mesh->io, index);
+}
+
+static void read_info_cb(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ uint16_t index = L_PTR_TO_UINT(user_data);
+ const struct mgmt_rp_read_info *rp = param;
+ uint32_t current_settings, supported_settings;
+
+ if (!current)
+ /* Already initialized */
+ return;
+
+ l_debug("hci %u status 0x%02x", index, status);
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ l_error("Failed to read info for hci index %u: %s (0x%02x)",
+ index, mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(*rp)) {
+ l_error("Read info response too short");
+ return;
+ }
+
+ current_settings = btohl(rp->current_settings);
+ supported_settings = btohl(rp->supported_settings);
+
+ l_debug("settings: supp %8.8x curr %8.8x",
+ supported_settings, current_settings);
+
+ if (current_settings & MGMT_SETTING_POWERED) {
+ l_info("Controller hci %u is in use", index);
+ return;
+ }
+
+ if (!(supported_settings & MGMT_SETTING_LE)) {
+ l_info("Controller hci %u does not support LE", index);
+ return;
+ }
+
+ start_io(current, index);
+}
+
+static void index_added(uint16_t index, uint16_t length, const void *param,
+ void *user_data)
+{
+ l_debug("hci device %u", index);
+
+ if (!current)
+ return;
+
+ if (current->req_index != MGMT_INDEX_NONE &&
+ index != current->req_index) {
+ l_debug("Ignore index %d", index);
+ return;
+ }
+
+ if (l_queue_find(controllers, simple_match, L_UINT_TO_PTR(index)))
+ return;
+
+ l_queue_push_tail(controllers, L_UINT_TO_PTR(index));
+
+ if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INFO, index, 0, NULL,
+ read_info_cb, L_UINT_TO_PTR(index), NULL) > 0)
+ return;
+
+ l_queue_remove(controllers, L_UINT_TO_PTR(index));
+}
+
+static void index_removed(uint16_t index, uint16_t length, const void *param,
+ void *user_data)
+{
+ l_warn("Hci dev %4.4x removed", index);
+ l_queue_remove(controllers, L_UINT_TO_PTR(index));
+}
+
+static void read_index_list_cb(uint8_t status, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_rp_read_index_list *rp = param;
+ uint16_t num;
+ int i;
+
+ if (status != MGMT_STATUS_SUCCESS) {
+ l_error("Failed to read index list: %s (0x%02x)",
+ mgmt_errstr(status), status);
+ return;
+ }
+
+ if (length < sizeof(*rp)) {
+ l_error("Read index list response sixe too short");
+ return;
+ }
+
+ num = btohs(rp->num_controllers);
+
+ l_debug("Number of controllers: %u", num);
+
+ if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+ l_error("Incorrect packet size for index list response");
+ return;
+ }
+
+ for (i = 0; i < num; i++) {
+ uint16_t index;
+
+ index = btohs(rp->index[i]);
+ index_added(index, 0, NULL, user_data);
+ }
+}
+
+static bool load_config(struct bt_mesh *mesh, const char *in_config_name)
+{
+ if (!mesh->net)
+ return false;
+
+ if (!storage_parse_config(mesh->net, in_config_name))
+ return false;
+
+ /* Register foundational models */
+ mesh_config_srv_init(mesh->net, PRIMARY_ELE_IDX);
+
+ return true;
+}
+
+static bool init_mesh(void)
+{
+ if (initialized)
+ return true;
+
+ controllers = l_queue_new();
+ if (!controllers)
+ return false;
+
+ mesh_list = l_queue_new();
+ if (!mesh_list)
+ return false;
+
+ mgmt_mesh = mgmt_new_default();
+ if (!mgmt_mesh)
+ goto fail;
+
+ mgmt_register(mgmt_mesh, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+ index_added, NULL, NULL);
+ mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+ index_removed, NULL, NULL);
+
+ initialized = true;
+ return true;
+
+fail:
+ l_error("Failed to initialize mesh management");
+
+ l_queue_destroy(controllers, NULL);
+
+ return false;
+}
+
+struct bt_mesh *mesh_new(uint16_t index, const char *config_file)
+{
+ struct bt_mesh *mesh;
+
+ if (!init_mesh())
+ return NULL;
+
mesh = l_new(struct bt_mesh, 1);
if (!mesh)
return NULL;
+ mesh->req_index = index;
+ mesh->index = MGMT_INDEX_NONE;
+
mesh->net = mesh_net_new(index);
if (!mesh->net) {
l_free(mesh);
return NULL;
}
- io = mesh_io_new(index, MESH_IO_TYPE_GENERIC);
- if (!io) {
- mesh_net_unref(mesh->net);
+ if (!load_config(mesh, config_file)) {
+ l_error("Failed to load mesh configuration: %s", config_file);
l_free(mesh);
return NULL;
}
- mesh_io_get_caps(io, &caps);
- mesh->max_filters = caps.max_num_filters;
+ /*
+ * TODO: Check if another mesh is searching for io.
+ * If so, add to pending list and return.
+ */
+ l_debug("send read index_list");
+ if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INDEX_LIST,
+ MGMT_INDEX_NONE, 0, NULL,
+ read_index_list_cb, mesh, NULL) > 0) {
+ current = mesh;
+ l_queue_push_tail(mesh_list, mesh);
+ return mesh_ref(mesh);
+ }
- mesh_net_attach(mesh->net, io);
- mesh_net_set_window_accuracy(mesh->net, caps.window_accuracy);
+ l_free(mesh);
- return mesh_ref(mesh);
+ return NULL;
}
struct bt_mesh *mesh_ref(struct bt_mesh *mesh)
@@ -127,18 +340,15 @@ void mesh_unref(struct bt_mesh *mesh)
mesh_io_destroy(io);
mesh_net_unref(mesh->net);
+ l_queue_remove(mesh_list, mesh);
l_free(mesh);
}
-bool mesh_load_config(struct bt_mesh *mesh, const char *in_config_name)
+void mesh_cleanup(void)
{
- if (!storage_parse_config(mesh->net, in_config_name))
- return false;
-
- /* Register foundational models */
- mesh_config_srv_init(mesh->net, PRIMARY_ELE_IDX);
-
- return true;
+ l_queue_destroy(controllers, NULL);
+ l_queue_destroy(mesh_list, NULL);
+ mgmt_unref(mgmt_mesh);
}
bool mesh_set_output(struct bt_mesh *mesh, const char *config_name)
@@ -177,8 +387,5 @@ const char *mesh_status_str(uint8_t err)
struct mesh_net *mesh_get_net(struct bt_mesh *mesh)
{
- if (!mesh)
- return NULL;
-
return mesh->net;
}
diff --git a/mesh/mesh.h b/mesh/mesh.h
index 7cd1e6158..8d389883b 100644
--- a/mesh/mesh.h
+++ b/mesh/mesh.h
@@ -21,11 +21,11 @@
struct bt_mesh;
struct mesh_net;
-struct bt_mesh *mesh_create(uint16_t index);
+struct bt_mesh *mesh_new(uint16_t index, const char *in_config_name);
struct bt_mesh *mesh_ref(struct bt_mesh *mesh);
void mesh_unref(struct bt_mesh *mesh);
-bool mesh_load_config(struct bt_mesh *mesh, const char *in_config_name);
bool mesh_set_output(struct bt_mesh *mesh, const char *out_config_name);
+void mesh_cleanup(void);
const char *mesh_status_str(uint8_t err);
/* Command line testing */
diff --git a/mesh/net.c b/mesh/net.c
index 544f9efa5..fb17e639d 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -1133,7 +1133,8 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,
return MESH_STATUS_STORAGE_FAIL;
}
- start_network_beacon(subnet, net);
+ if (net->io)
+ start_network_beacon(subnet, net);
return MESH_STATUS_SUCCESS;
}
@@ -3099,13 +3100,34 @@ bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)
return true;
}
-
bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
{
if (!net)
return false;
net->io = io;
+ if (net->provisioned) {
+
+ mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
+ beacon_recv, net);
+ mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
+ net_msg_recv, net);
+ l_queue_foreach(net->subnets, start_network_beacon, net);
+
+ } else {
+ uint8_t *uuid = node_uuid_get(net->local_node);
+
+ if (!uuid)
+ return false;
+
+ mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
+ mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_NET);
+
+ mesh_prov_listen(net, uuid, (uint8_t *) &net->prov_caps,
+ acceptor_prov_open,
+ acceptor_prov_close,
+ acceptor_prov_receive, net);
+ }
return true;
}
@@ -4150,33 +4172,10 @@ bool mesh_net_provisioned_new(struct mesh_net *net, uint8_t device_key[16],
void mesh_net_provisioned_set(struct mesh_net *net, bool provisioned)
{
- struct mesh_io *io;
-
if (!net)
return;
net->provisioned = provisioned;
- io = net->io;
-
- if (provisioned) {
- mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
- beacon_recv, net);
- mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
- net_msg_recv, net);
- } else {
- uint8_t *uuid = node_uuid_get(net->local_node);
-
- if (!uuid)
- return;
-
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_NET);
-
- mesh_prov_listen(net, uuid, (uint8_t *) &net->prov_caps,
- acceptor_prov_open,
- acceptor_prov_close,
- acceptor_prov_receive, net);
- }
}
bool mesh_net_provisioned_get(struct mesh_net *net)
--
2.17.1
SGkgSW5nYSwNCg0KVGhpcyBwYXRjaCB3YXMgYXBwbGllZC4NCg0KT24gVHVlLCAyMDE4LTA5LTA0
IGF0IDE3OjIwIC0wNzAwLCBJbmdhIFN0b3RsYW5kIHdyb3RlOg0KPiBUaGlzIGFsbG93cyBjby1l
eGlzdGVuc2Ugb2YgbWVzaGQgYW5kIGJsdWV0b290aGQuIG1lc2hkIHdpbGwNCj4gYXV0b21hdGlj
YWxseSB0YWtlIGNvbnRyb2wgb2YgdGhlIGZpcnN0IGF2YWlsYWJsZSBMRS1jYXBhYmxlDQo+IGNv
bnRyb2xsZXIgdGhhdCBpcyBwb3dlcmVkIGRvd24uDQo+IC0tLQ0KPiAgTWFrZWZpbGUubWVzaCB8
ICAgNCArLQ0KPiAgbWVzaC9idG1lc2guYyB8ICAgNSArLQ0KPiAgbWVzaC9tYWluLmMgICB8ICAy
MiArKy0tLQ0KPiAgbWVzaC9tZXNoLmMgICB8IDI1MyArKysrKysrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKystLS0tLQ0KPiAgbWVzaC9tZXNoLmggICB8ICAgNCArLQ0KPiAg
bWVzaC9uZXQuYyAgICB8ICA0OSArKysrKy0tLS0tDQo+ICA2IGZpbGVzIGNoYW5nZWQsIDI2OSBp
bnNlcnRpb25zKCspLCA2OCBkZWxldGlvbnMoLSkNCj4gDQo+IGRpZmYgLS1naXQgYS9NYWtlZmls
ZS5tZXNoIGIvTWFrZWZpbGUubWVzaA0KPiBpbmRleCA2NDNiMWE1OWEuLmU5M2U2OGUzOCAxMDA2
NDQNCj4gLS0tIGEvTWFrZWZpbGUubWVzaA0KPiArKysgYi9NYWtlZmlsZS5tZXNoDQo+IEBAIC0y
Myw3ICsyMyw3IEBAIGxpYmV4ZWNfUFJPR1JBTVMgKz0gbWVzaC9tZXNoZA0KPiAgbWVzaF9tZXNo
ZF9TT1VSQ0VTID0gJChtZXNoX3NvdXJjZXMpIG1lc2gvbWFpbi5jDQo+ICANCj4gIG1lc2hfbWVz
aGRfTERBREQgPSBzcmMvc2hhcmVkL2VjYy5sbyBzcmMvc2hhcmVkL3F1ZXVlLmxvIHNyYy9zaGFy
ZWQvaW8tZWxsLmxvIFwNCj4gLQkJCQlzcmMvc2hhcmVkL3V0aWwubG8gc3JjL3NoYXJlZC9oY2ku
bG8gXA0KPiArCQkJCXNyYy9zaGFyZWQvdXRpbC5sbyBzcmMvc2hhcmVkL2hjaS5sbyBzcmMvc2hh
cmVkL21nbXQubG8gXA0KPiAgCQkJCUBEQlVTX0xJQlNAIEBFTExfTElCU0AgLWxqc29uLWMNCj4g
IA0KPiAgbm9pbnN0X1BST0dSQU1TICs9IG1lc2gvYnRtZXNoDQo+IEBAIC0zNCw3ICszNCw3IEBA
IG1lc2hfYnRtZXNoX1NPVVJDRVMgPSAkKG1lc2hfc291cmNlcykgXA0KPiAgCQkJCQkJbWVzaC9i
dG1lc2guYw0KPiAgDQo+ICBtZXNoX2J0bWVzaF9MREFERCA9IHNyYy9zaGFyZWQvZWNjLmxvIHNy
Yy9zaGFyZWQvcXVldWUubG8gc3JjL3NoYXJlZC9pby1lbGwubG8gXA0KPiAtCQkJCXNyYy9zaGFy
ZWQvdXRpbC5sbyBzcmMvc2hhcmVkL2hjaS5sbyBcDQo+ICsJCQkJc3JjL3NoYXJlZC91dGlsLmxv
IHNyYy9zaGFyZWQvaGNpLmxvIHNyYy9zaGFyZWQvbWdtdC5sbyBcDQo+ICAJCQkJc3JjL2xpYnNo
YXJlZC1tYWlubG9vcC5sYSBcDQo+ICAJCQkJLWxyZWFkbGluZSBARUxMX0xJQlNAIC1sanNvbi1j
DQo+ICANCj4gZGlmZiAtLWdpdCBhL21lc2gvYnRtZXNoLmMgYi9tZXNoL2J0bWVzaC5jDQo+IGlu
ZGV4IGMzMTJkODVkYi4uMTA4ZWMzOWYzIDEwMDY0NA0KPiAtLS0gYS9tZXNoL2J0bWVzaC5jDQo+
ICsrKyBiL21lc2gvYnRtZXNoLmMNCj4gQEAgLTE1Myw4ICsxNTMsOCBAQCBpbnQgbWFpbihpbnQg
YXJnYywgY2hhciAqYXJndltdKQ0KPiAgDQo+ICAJbF9pbmZvKCJTdGFydGluZyBtZXNoIG9uIGhj
aSVkXG4iLCBpbmRleCk7DQo+ICANCj4gLQltZXNoID0gbWVzaF9jcmVhdGUoaW5kZXgpOw0KPiAt
CWlmICghbWVzaCB8fCAhbWVzaF9sb2FkX2NvbmZpZyhtZXNoLCBjb25maWdfb3B0aW9uKSkgew0K
PiArCW1lc2ggPSBtZXNoX25ldyhpbmRleCwgY29uZmlnX29wdGlvbik7DQo+ICsJaWYgKCFtZXNo
KSB7DQo+ICAJCWxfaW5mbygiRmFpbGVkIHRvIGNyZWF0ZSBtZXNoXG4iKTsNCj4gIAkJYnRfc2hl
bGxfY2xlYW51cCgpOw0KPiAgCQlyZXR1cm4gRVhJVF9GQUlMVVJFOw0KPiBAQCAtMTcwLDYgKzE3
MCw3IEBAIGludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pDQo+ICAJYnRfc2hlbGxfcnVu
KCk7DQo+ICANCj4gIAltZXNoX3VucmVmKG1lc2gpOw0KPiArCW1lc2hfY2xlYW51cCgpOw0KPiAg
CWxfbWFpbl9leGl0KCk7DQo+ICANCj4gIAlyZXR1cm4gc3RhdHVzOw0KPiBkaWZmIC0tZ2l0IGEv
bWVzaC9tYWluLmMgYi9tZXNoL21haW4uYw0KPiBpbmRleCA4YzAzZjUxZWIuLjI4OWIwNTgyYiAx
MDA2NDQNCj4gLS0tIGEvbWVzaC9tYWluLmMNCj4gKysrIGIvbWVzaC9tYWluLmMNCj4gQEAgLTMw
LDYgKzMwLDkgQEANCj4gICNpbmNsdWRlIDxzeXMvc3RhdC5oPg0KPiAgI2luY2x1ZGUgPGVsbC9l
bGwuaD4NCj4gIA0KPiArI2luY2x1ZGUgImxpYi9ibHVldG9vdGguaCINCj4gKyNpbmNsdWRlICJs
aWIvbWdtdC5oIg0KPiArDQo+ICAjaW5jbHVkZSAibWVzaC9tZXNoLmgiDQo+ICAjaW5jbHVkZSAi
bWVzaC9uZXQuaCINCj4gICNpbmNsdWRlICJtZXNoL3N0b3JhZ2UuaCINCj4gQEAgLTgxLDYgKzg0
LDcgQEAgaW50IG1haW4oaW50IGFyZ2MsIGNoYXIgKmFyZ3ZbXSkNCj4gIAlzaWdzZXRfdCBtYXNr
Ow0KPiAgCXN0cnVjdCBidF9tZXNoICptZXNoID0gTlVMTDsNCj4gIAljb25zdCBjaGFyICpjb25m
aWdfZmlsZSA9IE5VTEw7DQo+ICsJaW50IGluZGV4ID0gTUdNVF9JTkRFWF9OT05FOw0KPiAgDQo+
ICAJaWYgKCFsX21haW5faW5pdCgpKQ0KPiAgCQlyZXR1cm4gLTE7DQo+IEBAIC0xMDcsMTIgKzEx
MSw3IEBAIGludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pDQo+ICAJCQkJZ290byBkb25l
Ow0KPiAgCQkJfQ0KPiAgDQo+IC0JCQltZXNoID0gbWVzaF9jcmVhdGUoYXRvaShzdHIpKTsNCj4g
LQkJCWlmICghbWVzaCkgew0KPiAtCQkJCWxfZXJyb3IoIkZhaWxlZCB0byBpbml0aWFsaXplIG1l
c2giKTsNCj4gLQkJCQlzdGF0dXMgPSBFWElUX0ZBSUxVUkU7DQo+IC0JCQkJZ290byBkb25lOw0K
PiAtCQkJfQ0KPiArCQkJaW5kZXggPSBhdG9pKHN0cik7DQo+ICANCj4gIAkJCWJyZWFrOw0KPiAg
CQljYXNlICduJzoNCj4gQEAgLTEzNSwxNCArMTM0LDggQEAgaW50IG1haW4oaW50IGFyZ2MsIGNo
YXIgKmFyZ3ZbXSkNCj4gIAkJfQ0KPiAgCX0NCj4gIA0KPiAtCWlmICghbWVzaCkgew0KPiAtCQl1
c2FnZSgpOw0KPiAtCQlzdGF0dXMgPSBFWElUX0ZBSUxVUkU7DQo+IC0JCWdvdG8gZG9uZTsNCj4g
LQl9DQo+IC0NCj4gLQlpZiAoIW1lc2hfbG9hZF9jb25maWcobWVzaCwgY29uZmlnX2ZpbGUpKSB7
DQo+IC0JCWxfZXJyb3IoIkZhaWxlZCB0byBsb2FkIG1lc2ggY29uZmlndXJhdGlvbjogJXMiLCBj
b25maWdfZmlsZSk7DQo+ICsJaWYgKCFtZXNoX25ldyhpbmRleCwgY29uZmlnX2ZpbGUpKSB7DQo+
ICsJCWxfZXJyb3IoIkZhaWxlZCB0byBpbml0aWFsaXplIG1lc2giKTsNCj4gIAkJc3RhdHVzID0g
RVhJVF9GQUlMVVJFOw0KPiAgCQlnb3RvIGRvbmU7DQo+ICAJfQ0KPiBAQCAtMTY4LDYgKzE2MSw3
IEBAIGludCBtYWluKGludCBhcmdjLCBjaGFyICphcmd2W10pDQo+ICANCj4gIGRvbmU6DQo+ICAJ
bWVzaF91bnJlZihtZXNoKTsNCj4gKwltZXNoX2NsZWFudXAoKTsNCj4gIAlsX21haW5fZXhpdCgp
Ow0KPiAgDQo+ICAJcmV0dXJuIHN0YXR1czsNCj4gZGlmZiAtLWdpdCBhL21lc2gvbWVzaC5jIGIv
bWVzaC9tZXNoLmMNCj4gaW5kZXggYTZmNzMzZjVjLi4zZmJhMDE0MGMgMTAwNjQ0DQo+IC0tLSBh
L21lc2gvbWVzaC5jDQo+ICsrKyBiL21lc2gvbWVzaC5jDQo+IEBAIC0yNiw5ICsyNiwxMSBAQA0K
PiAgI2luY2x1ZGUgPGVsbC9lbGwuaD4NCj4gIA0KPiAgI2luY2x1ZGUgImxpYi9ibHVldG9vdGgu
aCINCj4gKyNpbmNsdWRlICJsaWIvbWdtdC5oIg0KPiAgDQo+IC0jaW5jbHVkZSAibWVzaC9tZXNo
LWRlZnMuaCINCj4gKyNpbmNsdWRlICJzcmMvc2hhcmVkL21nbXQuaCINCj4gIA0KPiArI2luY2x1
ZGUgIm1lc2gvbWVzaC1kZWZzLmgiDQo+ICAjaW5jbHVkZSAibWVzaC9tZXNoLWlvLmgiDQo+ICAj
aW5jbHVkZSAibWVzaC9ub2RlLmgiDQo+ICAjaW5jbHVkZSAibWVzaC9uZXQuaCINCj4gQEAgLTQ0
LDExICs0NiwyNSBAQCBzdHJ1Y3Qgc2Nhbl9maWx0ZXIgew0KPiAgDQo+ICBzdHJ1Y3QgYnRfbWVz
aCB7DQo+ICAJc3RydWN0IG1lc2hfbmV0ICpuZXQ7DQo+IC0JaW50IHJlZl9jb3VudDsNCj4gKwlz
dHJ1Y3QgbWVzaF9pbyAqaW87DQo+ICAJc3RydWN0IGxfcXVldWUgKmZpbHRlcnM7DQo+ICsJaW50
IHJlZl9jb3VudDsNCj4gKwl1aW50MTZfdCBpbmRleDsNCj4gKwl1aW50MTZfdCByZXFfaW5kZXg7
DQo+ICAJdWludDhfdCBtYXhfZmlsdGVyczsNCj4gIH07DQo+ICANCj4gK3N0YXRpYyBzdHJ1Y3Qg
bF9xdWV1ZSAqY29udHJvbGxlcnM7DQo+ICtzdGF0aWMgc3RydWN0IGxfcXVldWUgKm1lc2hfbGlz
dDsNCj4gK3N0YXRpYyBzdHJ1Y3QgbWdtdCAqbWdtdF9tZXNoOw0KPiArc3RhdGljIGJvb2wgaW5p
dGlhbGl6ZWQ7DQo+ICtzdGF0aWMgc3RydWN0IGJ0X21lc2ggKmN1cnJlbnQ7DQo+ICsNCj4gK3N0
YXRpYyBib29sIHNpbXBsZV9tYXRjaChjb25zdCB2b2lkICphLCBjb25zdCB2b2lkICpiKQ0KPiAr
ew0KPiArCXJldHVybiBhID09IGI7DQo+ICt9DQo+ICsNCj4gIHN0YXRpYyB2b2lkIHNhdmVfZXhp
dF9jb25maWcoc3RydWN0IGJ0X21lc2ggKm1lc2gpDQo+ICB7DQo+ICAJY29uc3QgY2hhciAqY2Zn
X2ZpbGVuYW1lOw0KPiBAQCAtNjQsMzYgKzgwLDIzMyBAQCBzdGF0aWMgdm9pZCBzYXZlX2V4aXRf
Y29uZmlnKHN0cnVjdCBidF9tZXNoICptZXNoKQ0KPiAgCQlsX2luZm8oIlNhdmVkIGZpbmFsIGNv
bmZpZ3VyYXRpb24gdG8gJXMiLCBjZmdfZmlsZW5hbWUpOw0KPiAgfQ0KPiAgDQo+IC1zdHJ1Y3Qg
YnRfbWVzaCAqbWVzaF9jcmVhdGUodWludDE2X3QgaW5kZXgpDQo+ICtzdGF0aWMgdm9pZCBzdGFy
dF9pbyhzdHJ1Y3QgYnRfbWVzaCAqbWVzaCwgdWludDE2X3QgaW5kZXgpDQo+ICB7DQo+IC0Jc3Ry
dWN0IGJ0X21lc2ggKm1lc2g7DQo+ICAJc3RydWN0IG1lc2hfaW8gKmlvOw0KPiAgCXN0cnVjdCBt
ZXNoX2lvX2NhcHMgY2FwczsNCj4gIA0KPiArCWxfZGVidWcoIlN0YXJ0aW5nIG1lc2ggb24gaGNp
ICV1IiwgaW5kZXgpOw0KPiArDQo+ICsJaW8gPSBtZXNoX2lvX25ldyhpbmRleCwgTUVTSF9JT19U
WVBFX0dFTkVSSUMpOw0KPiArCWlmICghaW8pIHsNCj4gKwkJbF9lcnJvcigiRmFpbGVkIHRvIHN0
YXJ0IG1lc2ggaW8gKGhjaSAldSkiLCBpbmRleCk7DQo+ICsJCWN1cnJlbnQgPSBOVUxMOw0KPiAr
CQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJbWVzaF9pb19nZXRfY2FwcyhpbywgJmNhcHMpOw0K
PiArCW1lc2gtPm1heF9maWx0ZXJzID0gY2Fwcy5tYXhfbnVtX2ZpbHRlcnM7DQo+ICsNCj4gKwlt
ZXNoX25ldF9hdHRhY2gobWVzaC0+bmV0LCBpbyk7DQo+ICsJbWVzaF9uZXRfc2V0X3dpbmRvd19h
Y2N1cmFjeShtZXNoLT5uZXQsIGNhcHMud2luZG93X2FjY3VyYWN5KTsNCj4gKwltZXNoLT5pbyA9
IGlvOw0KPiArCW1lc2gtPmluZGV4ID0gaW5kZXg7DQo+ICsNCj4gKwljdXJyZW50ID0gTlVMTDsN
Cj4gKw0KPiArCWxfZGVidWcoIlN0YXJ0ZWQgbWVzaCAoaW8gJXApIG9uIGhjaSAldSIsIG1lc2gt
PmlvLCBpbmRleCk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyB2b2lkIHJlYWRfaW5mb19jYih1aW50
OF90IHN0YXR1cywgdWludDE2X3QgbGVuZ3RoLA0KPiArCQkJCQljb25zdCB2b2lkICpwYXJhbSwg
dm9pZCAqdXNlcl9kYXRhKQ0KPiArew0KPiArCXVpbnQxNl90IGluZGV4ID0gTF9QVFJfVE9fVUlO
VCh1c2VyX2RhdGEpOw0KPiArCWNvbnN0IHN0cnVjdCBtZ210X3JwX3JlYWRfaW5mbyAqcnAgPSBw
YXJhbTsNCj4gKwl1aW50MzJfdCBjdXJyZW50X3NldHRpbmdzLCBzdXBwb3J0ZWRfc2V0dGluZ3M7
DQo+ICsNCj4gKwlpZiAoIWN1cnJlbnQpDQo+ICsJCS8qIEFscmVhZHkgaW5pdGlhbGl6ZWQgKi8N
Cj4gKwkJcmV0dXJuOw0KPiArDQo+ICsJbF9kZWJ1ZygiaGNpICV1IHN0YXR1cyAweCUwMngiLCBp
bmRleCwgc3RhdHVzKTsNCj4gKw0KPiArCWlmIChzdGF0dXMgIT0gTUdNVF9TVEFUVVNfU1VDQ0VT
Uykgew0KPiArCQlsX2Vycm9yKCJGYWlsZWQgdG8gcmVhZCBpbmZvIGZvciBoY2kgaW5kZXggJXU6
ICVzICgweCUwMngpIiwNCj4gKwkJCQkJaW5kZXgsIG1nbXRfZXJyc3RyKHN0YXR1cyksIHN0YXR1
cyk7DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwlpZiAobGVuZ3RoIDwgc2l6ZW9mKCpy
cCkpIHsNCj4gKwkJbF9lcnJvcigiUmVhZCBpbmZvIHJlc3BvbnNlIHRvbyBzaG9ydCIpOw0KPiAr
CQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJY3VycmVudF9zZXR0aW5ncyA9IGJ0b2hsKHJwLT5j
dXJyZW50X3NldHRpbmdzKTsNCj4gKwlzdXBwb3J0ZWRfc2V0dGluZ3MgPSBidG9obChycC0+c3Vw
cG9ydGVkX3NldHRpbmdzKTsNCj4gKw0KPiArCWxfZGVidWcoInNldHRpbmdzOiBzdXBwICU4Ljh4
IGN1cnIgJTguOHgiLA0KPiArCQkJCQlzdXBwb3J0ZWRfc2V0dGluZ3MsIGN1cnJlbnRfc2V0dGlu
Z3MpOw0KPiArDQo+ICsJaWYgKGN1cnJlbnRfc2V0dGluZ3MgJiBNR01UX1NFVFRJTkdfUE9XRVJF
RCkgew0KPiArCQlsX2luZm8oIkNvbnRyb2xsZXIgaGNpICV1IGlzIGluIHVzZSIsIGluZGV4KTsN
Cj4gKwkJcmV0dXJuOw0KPiArCX0NCj4gKw0KPiArCWlmICghKHN1cHBvcnRlZF9zZXR0aW5ncyAm
IE1HTVRfU0VUVElOR19MRSkpIHsNCj4gKwkJbF9pbmZvKCJDb250cm9sbGVyIGhjaSAldSBkb2Vz
IG5vdCBzdXBwb3J0IExFIiwgaW5kZXgpOw0KPiArCQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJ
c3RhcnRfaW8oY3VycmVudCwgaW5kZXgpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgdm9pZCBpbmRl
eF9hZGRlZCh1aW50MTZfdCBpbmRleCwgdWludDE2X3QgbGVuZ3RoLCBjb25zdCB2b2lkICpwYXJh
bSwNCj4gKwkJCQkJCQl2b2lkICp1c2VyX2RhdGEpDQo+ICt7DQo+ICsJbF9kZWJ1ZygiaGNpIGRl
dmljZSAldSIsIGluZGV4KTsNCj4gKw0KPiArCWlmICghY3VycmVudCkNCj4gKwkJcmV0dXJuOw0K
PiArDQo+ICsJaWYgKGN1cnJlbnQtPnJlcV9pbmRleCAhPSBNR01UX0lOREVYX05PTkUgJiYNCj4g
KwkJCQkJaW5kZXggIT0gY3VycmVudC0+cmVxX2luZGV4KSB7DQo+ICsJCWxfZGVidWcoIklnbm9y
ZSBpbmRleCAlZCIsIGluZGV4KTsNCj4gKwkJcmV0dXJuOw0KPiArCX0NCj4gKw0KPiArCWlmIChs
X3F1ZXVlX2ZpbmQoY29udHJvbGxlcnMsIHNpbXBsZV9tYXRjaCwgTF9VSU5UX1RPX1BUUihpbmRl
eCkpKQ0KPiArCQlyZXR1cm47DQo+ICsNCj4gKwlsX3F1ZXVlX3B1c2hfdGFpbChjb250cm9sbGVy
cywgTF9VSU5UX1RPX1BUUihpbmRleCkpOw0KPiArDQo+ICsJaWYgKG1nbXRfc2VuZChtZ210X21l
c2gsIE1HTVRfT1BfUkVBRF9JTkZPLCBpbmRleCwgMCwgTlVMTCwNCj4gKwkJCXJlYWRfaW5mb19j
YiwgTF9VSU5UX1RPX1BUUihpbmRleCksIE5VTEwpID4gMCkNCj4gKwkJcmV0dXJuOw0KPiArDQo+
ICsJbF9xdWV1ZV9yZW1vdmUoY29udHJvbGxlcnMsIExfVUlOVF9UT19QVFIoaW5kZXgpKTsNCj4g
K30NCj4gKw0KPiArc3RhdGljIHZvaWQgaW5kZXhfcmVtb3ZlZCh1aW50MTZfdCBpbmRleCwgdWlu
dDE2X3QgbGVuZ3RoLCBjb25zdCB2b2lkICpwYXJhbSwNCj4gKwkJCQkJCQl2b2lkICp1c2VyX2Rh
dGEpDQo+ICt7DQo+ICsJbF93YXJuKCJIY2kgZGV2ICU0LjR4IHJlbW92ZWQiLCBpbmRleCk7DQo+
ICsJbF9xdWV1ZV9yZW1vdmUoY29udHJvbGxlcnMsIExfVUlOVF9UT19QVFIoaW5kZXgpKTsNCj4g
K30NCj4gKw0KPiArc3RhdGljIHZvaWQgcmVhZF9pbmRleF9saXN0X2NiKHVpbnQ4X3Qgc3RhdHVz
LCB1aW50MTZfdCBsZW5ndGgsDQo+ICsJCQkJCWNvbnN0IHZvaWQgKnBhcmFtLCB2b2lkICp1c2Vy
X2RhdGEpDQo+ICt7DQo+ICsJY29uc3Qgc3RydWN0IG1nbXRfcnBfcmVhZF9pbmRleF9saXN0ICpy
cCA9IHBhcmFtOw0KPiArCXVpbnQxNl90IG51bTsNCj4gKwlpbnQgaTsNCj4gKw0KPiArCWlmIChz
dGF0dXMgIT0gTUdNVF9TVEFUVVNfU1VDQ0VTUykgew0KPiArCQlsX2Vycm9yKCJGYWlsZWQgdG8g
cmVhZCBpbmRleCBsaXN0OiAlcyAoMHglMDJ4KSIsDQo+ICsJCQkJCQltZ210X2VycnN0cihzdGF0
dXMpLCBzdGF0dXMpOw0KPiArCQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJaWYgKGxlbmd0aCA8
IHNpemVvZigqcnApKSB7DQo+ICsJCWxfZXJyb3IoIlJlYWQgaW5kZXggbGlzdCByZXNwb25zZSBz
aXhlIHRvbyBzaG9ydCIpOw0KPiArCQlyZXR1cm47DQo+ICsJfQ0KPiArDQo+ICsJbnVtID0gYnRv
aHMocnAtPm51bV9jb250cm9sbGVycyk7DQo+ICsNCj4gKwlsX2RlYnVnKCJOdW1iZXIgb2YgY29u
dHJvbGxlcnM6ICV1IiwgbnVtKTsNCj4gKw0KPiArCWlmIChudW0gKiBzaXplb2YodWludDE2X3Qp
ICsgc2l6ZW9mKCpycCkgIT0gbGVuZ3RoKSB7DQo+ICsJCWxfZXJyb3IoIkluY29ycmVjdCBwYWNr
ZXQgc2l6ZSBmb3IgaW5kZXggbGlzdCByZXNwb25zZSIpOw0KPiArCQlyZXR1cm47DQo+ICsJfQ0K
PiArDQo+ICsJZm9yIChpID0gMDsgaSA8IG51bTsgaSsrKSB7DQo+ICsJCXVpbnQxNl90IGluZGV4
Ow0KPiArDQo+ICsJCWluZGV4ID0gYnRvaHMocnAtPmluZGV4W2ldKTsNCj4gKwkJaW5kZXhfYWRk
ZWQoaW5kZXgsIDAsIE5VTEwsIHVzZXJfZGF0YSk7DQo+ICsJfQ0KPiArfQ0KPiArDQo+ICtzdGF0
aWMgYm9vbCBsb2FkX2NvbmZpZyhzdHJ1Y3QgYnRfbWVzaCAqbWVzaCwgY29uc3QgY2hhciAqaW5f
Y29uZmlnX25hbWUpDQo+ICt7DQo+ICsJaWYgKCFtZXNoLT5uZXQpDQo+ICsJCXJldHVybiBmYWxz
ZTsNCj4gKw0KPiArCWlmICghc3RvcmFnZV9wYXJzZV9jb25maWcobWVzaC0+bmV0LCBpbl9jb25m
aWdfbmFtZSkpDQo+ICsJCXJldHVybiBmYWxzZTsNCj4gKw0KPiArCS8qIFJlZ2lzdGVyIGZvdW5k
YXRpb25hbCBtb2RlbHMgKi8NCj4gKwltZXNoX2NvbmZpZ19zcnZfaW5pdChtZXNoLT5uZXQsIFBS
SU1BUllfRUxFX0lEWCk7DQo+ICsNCj4gKwlyZXR1cm4gdHJ1ZTsNCj4gK30NCj4gKw0KPiArc3Rh
dGljIGJvb2wgaW5pdF9tZXNoKHZvaWQpDQo+ICt7DQo+ICsJaWYgKGluaXRpYWxpemVkKQ0KPiAr
CQlyZXR1cm4gdHJ1ZTsNCj4gKw0KPiArCWNvbnRyb2xsZXJzID0gbF9xdWV1ZV9uZXcoKTsNCj4g
KwlpZiAoIWNvbnRyb2xsZXJzKQ0KPiArCQlyZXR1cm4gZmFsc2U7DQo+ICsNCj4gKwltZXNoX2xp
c3QgPSBsX3F1ZXVlX25ldygpOw0KPiArCWlmICghbWVzaF9saXN0KQ0KPiArCQlyZXR1cm4gZmFs
c2U7DQo+ICsNCj4gKwltZ210X21lc2ggPSBtZ210X25ld19kZWZhdWx0KCk7DQo+ICsJaWYgKCFt
Z210X21lc2gpDQo+ICsJCWdvdG8gZmFpbDsNCj4gKw0KPiArCW1nbXRfcmVnaXN0ZXIobWdtdF9t
ZXNoLCBNR01UX0VWX0lOREVYX0FEREVELCBNR01UX0lOREVYX05PTkUsDQo+ICsJCQkJCQlpbmRl
eF9hZGRlZCwgTlVMTCwgTlVMTCk7DQo+ICsJbWdtdF9yZWdpc3RlcihtZ210X21lc2gsIE1HTVRf
RVZfSU5ERVhfUkVNT1ZFRCwgTUdNVF9JTkRFWF9OT05FLA0KPiArCQkJCQkJaW5kZXhfcmVtb3Zl
ZCwgTlVMTCwgTlVMTCk7DQo+ICsNCj4gKwlpbml0aWFsaXplZCA9IHRydWU7DQo+ICsJcmV0dXJu
IHRydWU7DQo+ICsNCj4gK2ZhaWw6DQo+ICsJbF9lcnJvcigiRmFpbGVkIHRvIGluaXRpYWxpemUg
bWVzaCBtYW5hZ2VtZW50Iik7DQo+ICsNCj4gKwlsX3F1ZXVlX2Rlc3Ryb3koY29udHJvbGxlcnMs
IE5VTEwpOw0KPiArDQo+ICsJcmV0dXJuIGZhbHNlOw0KPiArfQ0KPiArDQo+ICtzdHJ1Y3QgYnRf
bWVzaCAqbWVzaF9uZXcodWludDE2X3QgaW5kZXgsIGNvbnN0IGNoYXIgKmNvbmZpZ19maWxlKQ0K
PiArew0KPiArCXN0cnVjdCBidF9tZXNoICptZXNoOw0KPiArDQo+ICsJaWYgKCFpbml0X21lc2go
KSkNCj4gKwkJcmV0dXJuIE5VTEw7DQo+ICsNCj4gIAltZXNoID0gbF9uZXcoc3RydWN0IGJ0X21l
c2gsIDEpOw0KPiAgCWlmICghbWVzaCkNCj4gIAkJcmV0dXJuIE5VTEw7DQo+ICANCj4gKwltZXNo
LT5yZXFfaW5kZXggPSBpbmRleDsNCj4gKwltZXNoLT5pbmRleCA9IE1HTVRfSU5ERVhfTk9ORTsN
Cj4gKw0KPiAgCW1lc2gtPm5ldCA9IG1lc2hfbmV0X25ldyhpbmRleCk7DQo+ICAJaWYgKCFtZXNo
LT5uZXQpIHsNCj4gIAkJbF9mcmVlKG1lc2gpOw0KPiAgCQlyZXR1cm4gTlVMTDsNCj4gIAl9DQo+
ICANCj4gLQlpbyA9IG1lc2hfaW9fbmV3KGluZGV4LCBNRVNIX0lPX1RZUEVfR0VORVJJQyk7DQo+
IC0JaWYgKCFpbykgew0KPiAtCQltZXNoX25ldF91bnJlZihtZXNoLT5uZXQpOw0KPiArCWlmICgh
bG9hZF9jb25maWcobWVzaCwgY29uZmlnX2ZpbGUpKSB7DQo+ICsJCWxfZXJyb3IoIkZhaWxlZCB0
byBsb2FkIG1lc2ggY29uZmlndXJhdGlvbjogJXMiLCBjb25maWdfZmlsZSk7DQo+ICAJCWxfZnJl
ZShtZXNoKTsNCj4gIAkJcmV0dXJuIE5VTEw7DQo+ICAJfQ0KPiAgDQo+IC0JbWVzaF9pb19nZXRf
Y2FwcyhpbywgJmNhcHMpOw0KPiAtCW1lc2gtPm1heF9maWx0ZXJzID0gY2Fwcy5tYXhfbnVtX2Zp
bHRlcnM7DQo+ICsJLyoNCj4gKwkgKiBUT0RPOiBDaGVjayBpZiBhbm90aGVyIG1lc2ggaXMgc2Vh
cmNoaW5nIGZvciBpby4NCj4gKwkgKiBJZiBzbywgYWRkIHRvIHBlbmRpbmcgbGlzdCBhbmQgcmV0
dXJuLg0KPiArCSAqLw0KPiArCWxfZGVidWcoInNlbmQgcmVhZCBpbmRleF9saXN0Iik7DQo+ICsJ
aWYgKG1nbXRfc2VuZChtZ210X21lc2gsIE1HTVRfT1BfUkVBRF9JTkRFWF9MSVNULA0KPiArCQkJ
CU1HTVRfSU5ERVhfTk9ORSwgMCwgTlVMTCwNCj4gKwkJCQlyZWFkX2luZGV4X2xpc3RfY2IsIG1l
c2gsIE5VTEwpID4gMCkgew0KPiArCQljdXJyZW50ID0gbWVzaDsNCj4gKwkJbF9xdWV1ZV9wdXNo
X3RhaWwobWVzaF9saXN0LCBtZXNoKTsNCj4gKwkJcmV0dXJuIG1lc2hfcmVmKG1lc2gpOw0KPiAr
CX0NCj4gIA0KPiAtCW1lc2hfbmV0X2F0dGFjaChtZXNoLT5uZXQsIGlvKTsNCj4gLQltZXNoX25l
dF9zZXRfd2luZG93X2FjY3VyYWN5KG1lc2gtPm5ldCwgY2Fwcy53aW5kb3dfYWNjdXJhY3kpOw0K
PiArCWxfZnJlZShtZXNoKTsNCj4gIA0KPiAtCXJldHVybiBtZXNoX3JlZihtZXNoKTsNCj4gKwly
ZXR1cm4gTlVMTDsNCj4gIH0NCj4gIA0KPiAgc3RydWN0IGJ0X21lc2ggKm1lc2hfcmVmKHN0cnVj
dCBidF9tZXNoICptZXNoKQ0KPiBAQCAtMTI3LDE4ICszNDAsMTUgQEAgdm9pZCBtZXNoX3VucmVm
KHN0cnVjdCBidF9tZXNoICptZXNoKQ0KPiAgCQltZXNoX2lvX2Rlc3Ryb3koaW8pOw0KPiAgDQo+
ICAJbWVzaF9uZXRfdW5yZWYobWVzaC0+bmV0KTsNCj4gKwlsX3F1ZXVlX3JlbW92ZShtZXNoX2xp
c3QsIG1lc2gpOw0KPiAgCWxfZnJlZShtZXNoKTsNCj4gIH0NCj4gIA0KPiAtYm9vbCBtZXNoX2xv
YWRfY29uZmlnKHN0cnVjdCBidF9tZXNoICptZXNoLCBjb25zdCBjaGFyICppbl9jb25maWdfbmFt
ZSkNCj4gK3ZvaWQgbWVzaF9jbGVhbnVwKHZvaWQpDQo+ICB7DQo+IC0JaWYgKCFzdG9yYWdlX3Bh
cnNlX2NvbmZpZyhtZXNoLT5uZXQsIGluX2NvbmZpZ19uYW1lKSkNCj4gLQkJcmV0dXJuIGZhbHNl
Ow0KPiAtDQo+IC0JLyogUmVnaXN0ZXIgZm91bmRhdGlvbmFsIG1vZGVscyAqLw0KPiAtCW1lc2hf
Y29uZmlnX3Nydl9pbml0KG1lc2gtPm5ldCwgUFJJTUFSWV9FTEVfSURYKTsNCj4gLQ0KPiAtCXJl
dHVybiB0cnVlOw0KPiArCWxfcXVldWVfZGVzdHJveShjb250cm9sbGVycywgTlVMTCk7DQo+ICsJ
bF9xdWV1ZV9kZXN0cm95KG1lc2hfbGlzdCwgTlVMTCk7DQo+ICsJbWdtdF91bnJlZihtZ210X21l
c2gpOw0KPiAgfQ0KPiAgDQo+ICBib29sIG1lc2hfc2V0X291dHB1dChzdHJ1Y3QgYnRfbWVzaCAq
bWVzaCwgY29uc3QgY2hhciAqY29uZmlnX25hbWUpDQo+IEBAIC0xNzcsOCArMzg3LDUgQEAgY29u
c3QgY2hhciAqbWVzaF9zdGF0dXNfc3RyKHVpbnQ4X3QgZXJyKQ0KPiAgDQo+ICBzdHJ1Y3QgbWVz
aF9uZXQgKm1lc2hfZ2V0X25ldChzdHJ1Y3QgYnRfbWVzaCAqbWVzaCkNCj4gIHsNCj4gLQlpZiAo
IW1lc2gpDQo+IC0JCXJldHVybiBOVUxMOw0KPiAtDQo+ICAJcmV0dXJuIG1lc2gtPm5ldDsNCj4g
IH0NCj4gZGlmZiAtLWdpdCBhL21lc2gvbWVzaC5oIGIvbWVzaC9tZXNoLmgNCj4gaW5kZXggN2Nk
MWU2MTU4Li44ZDM4OTg4M2IgMTAwNjQ0DQo+IC0tLSBhL21lc2gvbWVzaC5oDQo+ICsrKyBiL21l
c2gvbWVzaC5oDQo+IEBAIC0yMSwxMSArMjEsMTEgQEANCj4gIHN0cnVjdCBidF9tZXNoOw0KPiAg
c3RydWN0IG1lc2hfbmV0Ow0KPiAgDQo+IC1zdHJ1Y3QgYnRfbWVzaCAqbWVzaF9jcmVhdGUodWlu
dDE2X3QgaW5kZXgpOw0KPiArc3RydWN0IGJ0X21lc2ggKm1lc2hfbmV3KHVpbnQxNl90IGluZGV4
LCBjb25zdCBjaGFyICppbl9jb25maWdfbmFtZSk7DQo+ICBzdHJ1Y3QgYnRfbWVzaCAqbWVzaF9y
ZWYoc3RydWN0IGJ0X21lc2ggKm1lc2gpOw0KPiAgdm9pZCBtZXNoX3VucmVmKHN0cnVjdCBidF9t
ZXNoICptZXNoKTsNCj4gLWJvb2wgbWVzaF9sb2FkX2NvbmZpZyhzdHJ1Y3QgYnRfbWVzaCAqbWVz
aCwgY29uc3QgY2hhciAqaW5fY29uZmlnX25hbWUpOw0KPiAgYm9vbCBtZXNoX3NldF9vdXRwdXQo
c3RydWN0IGJ0X21lc2ggKm1lc2gsIGNvbnN0IGNoYXIgKm91dF9jb25maWdfbmFtZSk7DQo+ICt2
b2lkIG1lc2hfY2xlYW51cCh2b2lkKTsNCj4gIGNvbnN0IGNoYXIgKm1lc2hfc3RhdHVzX3N0cih1
aW50OF90IGVycik7DQo+ICANCj4gIC8qIENvbW1hbmQgbGluZSB0ZXN0aW5nICovDQo+IGRpZmYg
LS1naXQgYS9tZXNoL25ldC5jIGIvbWVzaC9uZXQuYw0KPiBpbmRleCA1NDRmOWVmYTUuLmZiMTdl
NjM5ZCAxMDA2NDQNCj4gLS0tIGEvbWVzaC9uZXQuYw0KPiArKysgYi9tZXNoL25ldC5jDQo+IEBA
IC0xMTMzLDcgKzExMzMsOCBAQCBpbnQgbWVzaF9uZXRfYWRkX2tleShzdHJ1Y3QgbWVzaF9uZXQg
Km5ldCwgYm9vbCB1cGRhdGUsIHVpbnQxNl90IGlkeCwNCj4gIAkJcmV0dXJuIE1FU0hfU1RBVFVT
X1NUT1JBR0VfRkFJTDsNCj4gIAl9DQo+ICANCj4gLQlzdGFydF9uZXR3b3JrX2JlYWNvbihzdWJu
ZXQsIG5ldCk7DQo+ICsJaWYgKG5ldC0+aW8pDQo+ICsJCXN0YXJ0X25ldHdvcmtfYmVhY29uKHN1
Ym5ldCwgbmV0KTsNCj4gIA0KPiAgCXJldHVybiBNRVNIX1NUQVRVU19TVUNDRVNTOw0KPiAgfQ0K
PiBAQCAtMzA5OSwxMyArMzEwMCwzNCBAQCBib29sIG1lc2hfbmV0X3NldF9iZWFjb25fbW9kZShz
dHJ1Y3QgbWVzaF9uZXQgKm5ldCwgYm9vbCBlbmFibGUpDQo+ICAJcmV0dXJuIHRydWU7DQo+ICB9
DQo+ICANCj4gLQ0KPiAgYm9vbCBtZXNoX25ldF9hdHRhY2goc3RydWN0IG1lc2hfbmV0ICpuZXQs
IHN0cnVjdCBtZXNoX2lvICppbykNCj4gIHsNCj4gIAlpZiAoIW5ldCkNCj4gIAkJcmV0dXJuIGZh
bHNlOw0KPiAgDQo+ICAJbmV0LT5pbyA9IGlvOw0KPiArCWlmIChuZXQtPnByb3Zpc2lvbmVkKSB7
DQo+ICsNCj4gKwkJbWVzaF9pb19yZWdpc3Rlcl9yZWN2X2NiKGlvLCBNRVNIX0lPX0ZJTFRFUl9C
RUFDT04sDQo+ICsJCQkJCQkJYmVhY29uX3JlY3YsIG5ldCk7DQo+ICsJCW1lc2hfaW9fcmVnaXN0
ZXJfcmVjdl9jYihpbywgTUVTSF9JT19GSUxURVJfTkVULA0KPiArCQkJCQkJCW5ldF9tc2dfcmVj
diwgbmV0KTsNCj4gKwkJbF9xdWV1ZV9mb3JlYWNoKG5ldC0+c3VibmV0cywgc3RhcnRfbmV0d29y
a19iZWFjb24sIG5ldCk7DQo+ICsNCj4gKwl9IGVsc2Ugew0KPiArCQl1aW50OF90ICp1dWlkID0g
bm9kZV91dWlkX2dldChuZXQtPmxvY2FsX25vZGUpOw0KPiArDQo+ICsJCWlmICghdXVpZCkNCj4g
KwkJCXJldHVybiBmYWxzZTsNCj4gKw0KPiArCQltZXNoX2lvX2RlcmVnaXN0ZXJfcmVjdl9jYihp
bywgTUVTSF9JT19GSUxURVJfQkVBQ09OKTsNCj4gKwkJbWVzaF9pb19kZXJlZ2lzdGVyX3JlY3Zf
Y2IoaW8sIE1FU0hfSU9fRklMVEVSX05FVCk7DQo+ICsNCj4gKwkJbWVzaF9wcm92X2xpc3Rlbihu
ZXQsIHV1aWQsICh1aW50OF90ICopICZuZXQtPnByb3ZfY2FwcywNCj4gKwkJCQkJYWNjZXB0b3Jf
cHJvdl9vcGVuLA0KPiArCQkJCQlhY2NlcHRvcl9wcm92X2Nsb3NlLA0KPiArCQkJCQlhY2NlcHRv
cl9wcm92X3JlY2VpdmUsIG5ldCk7DQo+ICsJfQ0KPiAgDQo+ICAJcmV0dXJuIHRydWU7DQo+ICB9
DQo+IEBAIC00MTUwLDMzICs0MTcyLDEwIEBAIGJvb2wgbWVzaF9uZXRfcHJvdmlzaW9uZWRfbmV3
KHN0cnVjdCBtZXNoX25ldCAqbmV0LCB1aW50OF90IGRldmljZV9rZXlbMTZdLA0KPiAgDQo+ICB2
b2lkIG1lc2hfbmV0X3Byb3Zpc2lvbmVkX3NldChzdHJ1Y3QgbWVzaF9uZXQgKm5ldCwgYm9vbCBw
cm92aXNpb25lZCkNCj4gIHsNCj4gLQlzdHJ1Y3QgbWVzaF9pbyAqaW87DQo+IC0NCj4gIAlpZiAo
IW5ldCkNCj4gIAkJcmV0dXJuOw0KPiAgDQo+ICAJbmV0LT5wcm92aXNpb25lZCA9IHByb3Zpc2lv
bmVkOw0KPiAtCWlvID0gbmV0LT5pbzsNCj4gLQ0KPiAtCWlmIChwcm92aXNpb25lZCkgew0KPiAt
CQltZXNoX2lvX3JlZ2lzdGVyX3JlY3ZfY2IoaW8sIE1FU0hfSU9fRklMVEVSX0JFQUNPTiwNCj4g
LQkJCQkJCQliZWFjb25fcmVjdiwgbmV0KTsNCj4gLQkJbWVzaF9pb19yZWdpc3Rlcl9yZWN2X2Ni
KGlvLCBNRVNIX0lPX0ZJTFRFUl9ORVQsDQo+IC0JCQkJCQkJbmV0X21zZ19yZWN2LCBuZXQpOw0K
PiAtCX0gZWxzZSB7DQo+IC0JCXVpbnQ4X3QgKnV1aWQgPSBub2RlX3V1aWRfZ2V0KG5ldC0+bG9j
YWxfbm9kZSk7DQo+IC0NCj4gLQkJaWYgKCF1dWlkKQ0KPiAtCQkJcmV0dXJuOw0KPiAtDQo+IC0J
CW1lc2hfaW9fZGVyZWdpc3Rlcl9yZWN2X2NiKGlvLCBNRVNIX0lPX0ZJTFRFUl9CRUFDT04pOw0K
PiAtCQltZXNoX2lvX2RlcmVnaXN0ZXJfcmVjdl9jYihpbywgTUVTSF9JT19GSUxURVJfTkVUKTsN
Cj4gLQ0KPiAtCQltZXNoX3Byb3ZfbGlzdGVuKG5ldCwgdXVpZCwgKHVpbnQ4X3QgKikgJm5ldC0+
cHJvdl9jYXBzLA0KPiAtCQkJCQlhY2NlcHRvcl9wcm92X29wZW4sDQo+IC0JCQkJCWFjY2VwdG9y
X3Byb3ZfY2xvc2UsDQo+IC0JCQkJCWFjY2VwdG9yX3Byb3ZfcmVjZWl2ZSwgbmV0KTsNCj4gLQl9
DQo+ICB9DQo+ICANCj4gIGJvb2wgbWVzaF9uZXRfcHJvdmlzaW9uZWRfZ2V0KHN0cnVjdCBtZXNo
X25ldCAqbmV0KQ==