2017-08-14 19:01:14

by Gix, Brian

[permalink] [raw]
Subject: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner

With the recent adoption of the Bluetooth Mesh Profile, we offer this
GATT Client provisioner tool (meshctl).

Brian Gix / Inga Stotland` (5):
mesh: Add BT SIG reserved numbers for Mesh
mesh: define APIs for Bluetooth Mesh
mesh: Baseline Mesh runtime configuration files
mesh: Baseline Mesh implementation
mesh: Add mesh to main bluez build

Makefile.tools | 24 +
bootstrap-configure | 1 +
configure.ac | 18 +
lib/uuid.h | 10 +
mesh/README | 26 +
mesh/agent.c | 276 ++++++
mesh/agent.h | 58 ++
mesh/config-client.c | 667 +++++++++++++++
mesh/config-model.h | 119 +++
mesh/config-server.c | 165 ++++
mesh/crypto.c | 1168 ++++++++++++++++++++++++++
mesh/crypto.h | 133 +++
mesh/gatt.c | 609 ++++++++++++++
mesh/gatt.h | 47 ++
mesh/keys.h | 43 +
mesh/local_node.json | 61 ++
mesh/main.c | 2269 ++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/mesh-net.h | 174 ++++
mesh/net.c | 2184 ++++++++++++++++++++++++++++++++++++++++++++++++
mesh/net.h | 72 ++
mesh/node.c | 879 +++++++++++++++++++
mesh/node.h | 146 ++++
mesh/onoff-model.c | 306 +++++++
mesh/onoff-model.h | 50 ++
mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
mesh/prov-db.h | 52 ++
mesh/prov.c | 664 +++++++++++++++
mesh/prov.h | 43 +
mesh/prov_db.json | 37 +
mesh/util.c | 369 ++++++++
mesh/util.h | 71 ++
31 files changed, 12340 insertions(+)
create mode 100644 mesh/README
create mode 100644 mesh/agent.c
create mode 100644 mesh/agent.h
create mode 100644 mesh/config-client.c
create mode 100644 mesh/config-model.h
create mode 100644 mesh/config-server.c
create mode 100644 mesh/crypto.c
create mode 100644 mesh/crypto.h
create mode 100644 mesh/gatt.c
create mode 100644 mesh/gatt.h
create mode 100644 mesh/keys.h
create mode 100644 mesh/local_node.json
create mode 100644 mesh/main.c
create mode 100644 mesh/mesh-net.h
create mode 100644 mesh/net.c
create mode 100644 mesh/net.h
create mode 100644 mesh/node.c
create mode 100644 mesh/node.h
create mode 100644 mesh/onoff-model.c
create mode 100644 mesh/onoff-model.h
create mode 100644 mesh/prov-db.c
create mode 100644 mesh/prov-db.h
create mode 100644 mesh/prov.c
create mode 100644 mesh/prov.h
create mode 100644 mesh/prov_db.json
create mode 100644 mesh/util.c
create mode 100644 mesh/util.h

--
2.9.5


2017-08-21 10:42:34

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner

Hi Brian,

> With the recent adoption of the Bluetooth Mesh Profile, we offer this
> GATT Client provisioner tool (meshctl).
>
> Brian Gix / Inga Stotland` (5):
> mesh: Add BT SIG reserved numbers for Mesh
> mesh: define APIs for Bluetooth Mesh
> mesh: Baseline Mesh runtime configuration files
> mesh: Baseline Mesh implementation
> mesh: Add mesh to main bluez build
>
> Makefile.tools | 24 +
> bootstrap-configure | 1 +
> configure.ac | 18 +
> lib/uuid.h | 10 +
> mesh/README | 26 +
> mesh/agent.c | 276 ++++++
> mesh/agent.h | 58 ++
> mesh/config-client.c | 667 +++++++++++++++
> mesh/config-model.h | 119 +++
> mesh/config-server.c | 165 ++++
> mesh/crypto.c | 1168 ++++++++++++++++++++++++++
> mesh/crypto.h | 133 +++
> mesh/gatt.c | 609 ++++++++++++++
> mesh/gatt.h | 47 ++
> mesh/keys.h | 43 +
> mesh/local_node.json | 61 ++
> mesh/main.c | 2269 ++++++++++++++++++++++++++++++++++++++++++++++++++
> mesh/mesh-net.h | 174 ++++
> mesh/net.c | 2184 ++++++++++++++++++++++++++++++++++++++++++++++++
> mesh/net.h | 72 ++
> mesh/node.c | 879 +++++++++++++++++++
> mesh/node.h | 146 ++++
> mesh/onoff-model.c | 306 +++++++
> mesh/onoff-model.h | 50 ++
> mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
> mesh/prov-db.h | 52 ++
> mesh/prov.c | 664 +++++++++++++++
> mesh/prov.h | 43 +
> mesh/prov_db.json | 37 +
> mesh/util.c | 369 ++++++++
> mesh/util.h | 71 ++
> 31 files changed, 12340 insertions(+)
> create mode 100644 mesh/README
> create mode 100644 mesh/agent.c
> create mode 100644 mesh/agent.h
> create mode 100644 mesh/config-client.c
> create mode 100644 mesh/config-model.h
> create mode 100644 mesh/config-server.c
> create mode 100644 mesh/crypto.c
> create mode 100644 mesh/crypto.h
> create mode 100644 mesh/gatt.c
> create mode 100644 mesh/gatt.h
> create mode 100644 mesh/keys.h
> create mode 100644 mesh/local_node.json
> create mode 100644 mesh/main.c
> create mode 100644 mesh/mesh-net.h
> create mode 100644 mesh/net.c
> create mode 100644 mesh/net.h
> create mode 100644 mesh/node.c
> create mode 100644 mesh/node.h
> create mode 100644 mesh/onoff-model.c
> create mode 100644 mesh/onoff-model.h
> create mode 100644 mesh/prov-db.c
> create mode 100644 mesh/prov-db.h
> create mode 100644 mesh/prov.c
> create mode 100644 mesh/prov.h
> create mode 100644 mesh/prov_db.json
> create mode 100644 mesh/util.c
> create mode 100644 mesh/util.h

all 5 patches have been applied.

Regards

Marcel


2017-08-16 12:30:34

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner

Hi Szymon,

On Wed, Aug 16, 2017 at 3:28 PM, Szymon Janc <[email protected]> wrote:
> Hi Brian,
>
> On Monday, 14 August 2017 21:01:14 CEST Brian Gix wrote:
>> With the recent adoption of the Bluetooth Mesh Profile, we offer this
>> GATT Client provisioner tool (meshctl).
>>
>> Brian Gix / Inga Stotland` (5):
>> mesh: Add BT SIG reserved numbers for Mesh
>> mesh: define APIs for Bluetooth Mesh
>> mesh: Baseline Mesh runtime configuration files
>> mesh: Baseline Mesh implementation
>> mesh: Add mesh to main bluez build
>>
>> Makefile.tools | 24 +
>> bootstrap-configure | 1 +
>> configure.ac | 18 +
>> lib/uuid.h | 10 +
>> mesh/README | 26 +
>> mesh/agent.c | 276 ++++++
>> mesh/agent.h | 58 ++
>> mesh/config-client.c | 667 +++++++++++++++
>> mesh/config-model.h | 119 +++
>> mesh/config-server.c | 165 ++++
>> mesh/crypto.c | 1168 ++++++++++++++++++++++++++
>> mesh/crypto.h | 133 +++
>> mesh/gatt.c | 609 ++++++++++++++
>> mesh/gatt.h | 47 ++
>> mesh/keys.h | 43 +
>> mesh/local_node.json | 61 ++
>> mesh/main.c | 2269
>> ++++++++++++++++++++++++++++++++++++++++++++++++++ mesh/mesh-net.h |
>> 174 ++++
>> mesh/net.c | 2184
>> ++++++++++++++++++++++++++++++++++++++++++++++++ mesh/net.h |
>> 72 ++
>> mesh/node.c | 879 +++++++++++++++++++
>> mesh/node.h | 146 ++++
>> mesh/onoff-model.c | 306 +++++++
>> mesh/onoff-model.h | 50 ++
>> mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
>> mesh/prov-db.h | 52 ++
>> mesh/prov.c | 664 +++++++++++++++
>> mesh/prov.h | 43 +
>> mesh/prov_db.json | 37 +
>> mesh/util.c | 369 ++++++++
>> mesh/util.h | 71 ++
>> 31 files changed, 12340 insertions(+)
>> create mode 100644 mesh/README
>> create mode 100644 mesh/agent.c
>> create mode 100644 mesh/agent.h
>> create mode 100644 mesh/config-client.c
>> create mode 100644 mesh/config-model.h
>> create mode 100644 mesh/config-server.c
>> create mode 100644 mesh/crypto.c
>> create mode 100644 mesh/crypto.h
>> create mode 100644 mesh/gatt.c
>> create mode 100644 mesh/gatt.h
>> create mode 100644 mesh/keys.h
>> create mode 100644 mesh/local_node.json
>> create mode 100644 mesh/main.c
>> create mode 100644 mesh/mesh-net.h
>> create mode 100644 mesh/net.c
>> create mode 100644 mesh/net.h
>> create mode 100644 mesh/node.c
>> create mode 100644 mesh/node.h
>> create mode 100644 mesh/onoff-model.c
>> create mode 100644 mesh/onoff-model.h
>> create mode 100644 mesh/prov-db.c
>> create mode 100644 mesh/prov-db.h
>> create mode 100644 mesh/prov.c
>> create mode 100644 mesh/prov.h
>> create mode 100644 mesh/prov_db.json
>> create mode 100644 mesh/util.c
>> create mode 100644 mesh/util.h
>
> Seems like 4th patch didn't make it to the list. Looking at code size it seems
> like it is too big and was rejected by vger. Would it be possible to upload
> this code eg to gihub?

Or CC you as well.

--
Luiz Augusto von Dentz

2017-08-16 12:29:26

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 4/5] mesh: Baseline Mesh implementation

Hi Brian,

On Tue, Aug 15, 2017 at 6:36 PM, Gix, Brian <[email protected]> wrote:
> Hi Luiz,
>
> We actually use the agent.c code for Out-Of-Band data input during Provisioning.

Which seems that was based on client/agent.c though there exists
rl_prompt_input and rl_release_prompt which basically does the same
thing now, but with introduction of input_request the handling becomes
quite a bit different.

I tried doing the conversion myself but it makes very no sense to me
to name this agent, in fact much of what it does with types,
HEXADECIMAL, etc could be done using different callbacks instead of a
global variable.

>> -----Original Message-----
>> From: Luiz Augusto von Dentz [mailto:[email protected]]
>> Sent: Tuesday, August 15, 2017 2:07 AM
>> To: Gix, Brian <[email protected]>
>> Cc: [email protected]; Marcel Holtmann
>> <[email protected]>
>> Subject: Re: [PATCH 4/5] mesh: Baseline Mesh implementation
>>
>> Hi Brian,
>>
>> On Mon, Aug 14, 2017 at 10:01 PM, Brian Gix <[email protected]> wrote:
>> > ---
>> > mesh/agent.c | 276 ++++++
>> > mesh/config-client.c | 667 +++++++++++++++
>> > mesh/config-server.c | 165 ++++
>> > mesh/crypto.c | 1168 ++++++++++++++++++++++++++
>> > mesh/gatt.c | 609 ++++++++++++++
>> > mesh/main.c | 2269
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>> > mesh/net.c | 2184
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>> > mesh/node.c | 879 +++++++++++++++++++
>> > mesh/onoff-model.c | 306 +++++++
>> > mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
>> > mesh/prov.c | 664 +++++++++++++++
>> > mesh/util.c | 369 ++++++++
>> > 12 files changed, 11155 insertions(+)
>> > create mode 100644 mesh/agent.c
>> > create mode 100644 mesh/config-client.c
>> > create mode 100644 mesh/config-server.c
>> > create mode 100644 mesh/crypto.c
>> > create mode 100644 mesh/gatt.c
>> > create mode 100644 mesh/main.c
>> > create mode 100644 mesh/net.c
>> > create mode 100644 mesh/node.c
>> > create mode 100644 mesh/onoff-model.c
>> > create mode 100644 mesh/prov-db.c
>> > create mode 100644 mesh/prov.c
>> > create mode 100644 mesh/util.c
>> >
>> > diff --git a/mesh/agent.c b/mesh/agent.c
>> > new file mode 100644
>> > index 0000000..0944862
>> > --- /dev/null
>> > +++ b/mesh/agent.c
>> > @@ -0,0 +1,276 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <inttypes.h>
>> > +#include <readline/readline.h>
>> > +
>> > +#include <glib.h>
>> > +
>> > +#include <lib/bluetooth.h>
>> > +#include "client/display.h"
>> > +#include "util.h"
>> > +#include "agent.h"
>> > +
>> > +#define AGENT_PROMPT COLOR_RED "[agent]" COLOR_OFF " "
>> > +
>> > +static char *agent_saved_prompt = NULL;
>> > +static int agent_saved_point = 0;
>> > +
>> > +struct input_request {
>> > + oob_type_t type;
>> > + uint16_t len;
>> > + agent_input_cb cb;
>> > + void *user_data;
>> > +};
>> > +
>> > +static struct input_request pending_request = {NONE, 0, NULL, NULL};
>> > +
>> > +static void agent_prompt(const char *msg)
>> > +{
>> > + char *prompt;
>> > +
>> > + /* Normal use should not prompt for user input to the agent a second
>> > + * time before it releases the prompt, but we take a safe action. */
>> > + if (agent_saved_prompt)
>> > + return;
>> > +
>> > + agent_saved_point = rl_point;
>> > + agent_saved_prompt = g_strdup(rl_prompt);
>> > +
>> > + rl_set_prompt("");
>> > + rl_redisplay();
>> > +
>> > + prompt = g_strdup_printf(AGENT_PROMPT "%s", msg);
>> > + rl_set_prompt(prompt);
>> > + g_free(prompt);
>> > +
>> > + rl_replace_line("", 0);
>> > + rl_redisplay();
>> > +}
>> > +
>> > +static void agent_release_prompt(void)
>> > +{
>> > + if (!agent_saved_prompt)
>> > + return;
>> > +
>> > + /* This will cause rl_expand_prompt to re-run over the last prompt,
>> but
>> > + * our prompt doesn't expand anyway. */
>> > + rl_set_prompt(agent_saved_prompt);
>> > + rl_replace_line("", 0);
>> > + rl_point = agent_saved_point;
>> > + rl_redisplay();
>> > +
>> > + g_free(agent_saved_prompt);
>> > + agent_saved_prompt = NULL;
>> > +}
>> > +
>> > +bool agent_completion(void)
>> > +{
>> > + if (pending_request.type == NONE)
>> > + return false;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool response_hexadecimal(const char *input)
>> > +{
>> > + uint8_t buf[MAX_HEXADECIMAL_OOB_LEN];
>> > +
>> > + if (!str2hex(input, strlen(input), buf, pending_request.len) ) {
>> > + rl_printf("Incorrect input: expecting %d hex octets\n",
>> > + pending_request.len);
>> > + return false;
>> > + }
>> > +
>> > + if (pending_request.cb)
>> > + pending_request.cb(HEXADECIMAL, buf, pending_request.len,
>> > + pending_request.user_data);
>> > + return true;
>> > +}
>> > +
>> > +static bool response_decimal(const char *input)
>> > +{
>> > + uint8_t buf[DECIMAL_OOB_LEN];
>> > +
>> > + if (strlen(input) > pending_request.len)
>> > + return false;
>> > +
>> > + bt_put_be32(atoi(input), buf);
>> > +
>> > + if (pending_request.cb)
>> > + pending_request.cb(DECIMAL, buf, DECIMAL_OOB_LEN,
>> > + pending_request.user_data);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static void response_ascii(const char *input)
>> > +{
>> > + if (pending_request.cb)
>> > + pending_request.cb(ASCII, (uint8_t *) input, strlen(input),
>> > + pending_request.user_data);
>> > +}
>> > +
>> > +bool agent_input(const char *input)
>> > +{
>> > + bool repeat = false;
>> > +
>> > + if (pending_request.type == NONE)
>> > + return false;
>> > +
>> > + switch (pending_request.type) {
>> > + case HEXADECIMAL:
>> > + if (!response_hexadecimal(input))
>> > + repeat = true;
>> > + break;
>> > + case DECIMAL:
>> > + if (!response_decimal(input))
>> > + repeat = true;
>> > + break;
>> > + case ASCII:
>> > + response_ascii(input);
>> > + break;
>> > + case OUTPUT:
>> > + repeat = true;
>> > + case NONE:
>> > + default:
>> > + break;
>> > + };
>> > +
>> > + if (!repeat) {
>> > + pending_request.type = NONE;
>> > + pending_request.len = 0;
>> > + pending_request.cb = NULL;
>> > + pending_request.user_data = NULL;
>> > +
>> > + agent_release_prompt();
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +void agent_release(void)
>> > +{
>> > + agent_release_prompt();
>> > +}
>> > +
>> > +static bool request_hexadecimal(uint16_t len)
>> > +{
>> > + if (len > MAX_HEXADECIMAL_OOB_LEN)
>> > + return false;
>> > +
>> > + rl_printf("Request hexadecimal key (hex %d octets)\n", len);
>> > + agent_prompt("Enter key (hex number): ");
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static uint32_t power_ten(uint8_t power)
>> > +{
>> > + uint32_t ret = 1;
>> > +
>> > + while (power--)
>> > + ret *= 10;
>> > +
>> > + return ret;
>> > +}
>> > +
>> > +static bool request_decimal(uint16_t len)
>> > +{
>> > + rl_printf("Request decimal key (0 - %d)\n", power_ten(len) - 1);
>> > + agent_prompt("Enter Numeric key: ");
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool request_ascii(uint16_t len)
>> > +{
>> > + if (len != MAX_ASCII_OOB_LEN)
>> > + return false;
>> > +
>> > + rl_printf("Request ASCII key (max characters %d)\n", len);
>> > + agent_prompt("Enter key (ascii string): ");
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool agent_input_request(oob_type_t type, uint16_t max_len,
>> agent_input_cb cb,
>> > + void *user_data)
>> > +{
>> > + bool result;
>> > +
>> > + if (pending_request.type != NONE)
>> > + return FALSE;
>> > +
>> > + switch (type) {
>> > + case HEXADECIMAL:
>> > + result = request_hexadecimal(max_len);
>> > + break;
>> > + case DECIMAL:
>> > + result = request_decimal(max_len);
>> > + break;
>> > + case ASCII:
>> > + result = request_ascii(max_len);
>> > + break;
>> > + case NONE:
>> > + case OUTPUT:
>> > + default:
>> > + return false;
>> > + };
>> > +
>> > + if (result) {
>> > + pending_request.type = type;
>> > + pending_request.len = max_len;
>> > + pending_request.cb = cb;
>> > + pending_request.user_data = user_data;
>> > +
>> > + return true;
>> > + }
>> > +
>> > + return false;
>> > +}
>> > +
>> > +bool agent_output_request(const char* str)
>> > +{
>> > + if (pending_request.type != NONE)
>> > + return false;
>> > +
>> > + pending_request.type = OUTPUT;
>> > + agent_prompt(str);
>> > + return true;
>> > +}
>> > +
>> > +void agent_output_request_cancel(void)
>> > +{
>> > + if (pending_request.type != OUTPUT)
>> > + return;
>> > + pending_request.type = NONE;
>> > + agent_release_prompt();
>> > +}
>>
>> The whole agent.c can be removed as well.
>>
>> > diff --git a/mesh/config-client.c b/mesh/config-client.c
>> > new file mode 100644
>> > index 0000000..a0f6eee
>> > --- /dev/null
>> > +++ b/mesh/config-client.c
>> > @@ -0,0 +1,667 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <inttypes.h>
>> > +#include <stdbool.h>
>> > +#include <sys/uio.h>
>> > +#include <wordexp.h>
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "src/shared/util.h"
>> > +#include "client/display.h"
>> > +#include "mesh-net.h"
>> > +#include "keys.h"
>> > +#include "net.h"
>> > +#include "node.h"
>> > +#include "prov-db.h"
>> > +#include "util.h"
>> > +#include "config-model.h"
>> > +
>> > +#define MIN_COMPOSITION_LEN 16
>> > +
>> > +static bool client_msg_recvd(uint16_t src, uint8_t *data,
>> > + uint16_t len, void *user_data)
>> > +{
>> > + uint32_t opcode;
>> > + struct mesh_node *node;
>> > + uint16_t app_idx, net_idx, addr;
>> > + uint32_t mod_id;
>> > + uint16_t primary;
>> > + uint16_t ele_addr;
>> > + uint8_t ele_idx;
>> > + struct mesh_publication pub;
>> > + int n;
>> > +
>> > + if (mesh_opcode_get(data, len, &opcode, &n)) {
>> > + len -= n;
>> > + data += n;
>> > + } else
>> > + return false;
>> > +
>> > + if (IS_UNICAST(src)) {
>> > + node = node_find_by_addr(src);
>> > + } else
>> > + node = NULL;
>> > +
>> > + if (!node)
>> > + return false;
>> > +
>> > + primary = node_get_primary(node);
>> > + if (primary != src)
>> > + return false;
>> > +
>> > + switch (opcode & ~OP_UNRELIABLE) {
>> > + default:
>> > + return false;
>> > +
>> > + case OP_DEV_COMP_STATUS:
>> > + if (len < MIN_COMPOSITION_LEN || !node)
>> > + break;
>> > + if (node_parse_composition(node, data, len)) {
>> > + if (!prov_db_add_node_composition(node, data, len))
>> > + break;
>> > + }
>> > +
>> > + if (node_get_composition(node))
>> > + prov_db_print_node_composition(node);
>> > + break;
>> > +
>> > + case OP_APPKEY_STATUS:
>> > + if (len != 4)
>> > + break;
>> > +
>> > + rl_printf("Node %4.4x AppKey Status %s\n", src,
>> > + mesh_status_str(data[0]));
>> > + net_idx = get_le16(data + 1) & 0xfff;
>> > + app_idx = get_le16(data + 2) >> 4;
>> > +
>> > + rl_printf("\tNetKey %3.3x, AppKey %3.3x\n", net_idx, app_idx);
>> > +
>> > + if (data[0] != MESH_STATUS_SUCCESS &&
>> > + data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
>> > + node_app_key_delete(node, net_idx, app_idx))
>> > + prov_db_node_keys(node, node_get_app_keys(node),
>> > + "appKeys");
>> > + break;
>> > +
>> > + case OP_NETKEY_STATUS:
>> > + if (len != 3)
>> > + break;
>> > +
>> > + rl_printf("Node %4.4x NetKey Status %s\n", src,
>> > + mesh_status_str(data[0]));
>> > + net_idx = get_le16(data + 1) & 0xfff;
>> > +
>> > + rl_printf("\tNetKey %3.3x\n", net_idx);
>> > +
>> > + if (data[0] != MESH_STATUS_SUCCESS &&
>> > + data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
>> > + node_net_key_delete(node, net_idx))
>> > + prov_db_node_keys(node, node_get_net_keys(node),
>> > + "netKeys");
>> > + break;
>> > +
>> > + case OP_MODEL_APP_STATUS:
>> > + if (len != 7 && len != 9)
>> > + break;
>> > +
>> > + rl_printf("Node %4.4x Model App Status %s\n", src,
>> > + mesh_status_str(data[0]));
>> > + addr = get_le16(data + 1);
>> > + app_idx = get_le16(data + 3);
>> > +
>> > + rl_printf("\tElement %4.4x AppIdx %3.3x\n ", addr, app_idx);
>> > +
>> > + if (len == 7) {
>> > + mod_id = get_le16(data + 5);
>> > + rl_printf("ModelId %4.4x\n", mod_id);
>> > + mod_id = 0xffff0000 | mod_id;
>> > + } else {
>> > + mod_id = get_le16(data + 7);
>> > + rl_printf("ModelId %4.4x %4.4x\n", get_le16(data + 5),
>> > + mod_id);
>> > + mod_id = get_le16(data + 5) << 16 | mod_id;
>> > + }
>> > +
>> > + if (data[0] == MESH_STATUS_SUCCESS &&
>> > + node_add_binding(node, addr - src, mod_id, app_idx))
>> > + prov_db_add_binding(node, addr - src, mod_id, app_idx);
>> > + break;
>> > +
>> > + case OP_CONFIG_DEFAULT_TTL_STATUS:
>> > + if (len != 1)
>> > + return true;
>> > + rl_printf("Node %4.4x Default TTL %d\n", src, data[0]);
>> > + if (node_set_default_ttl (node, data[0]))
>> > + prov_db_node_set_ttl(node, data[0]);
>> > + break;
>> > +
>> > + case OP_CONFIG_MODEL_PUB_STATUS:
>> > + if (len != 12 && len != 14)
>> > + return true;
>> > +
>> > + rl_printf("\nSet publication for node %4.4x status: %s\n", src,
>> > + data[0] == MESH_STATUS_SUCCESS ? "Success" :
>> > + mesh_status_str(data[0]));
>> > +
>> > + if (data[0] != MESH_STATUS_SUCCESS)
>> > + return true;
>> > +
>> > + ele_addr = get_le16(data + 1);
>> > + mod_id = get_le16(data + 10);
>> > + if (len == 14)
>> > + mod_id = (mod_id << 16) | get_le16(data + 12);
>> > + else
>> > + mod_id |= 0xffff0000;
>> > +
>> > + pub.u.addr16 = get_le16(data + 3);
>> > + pub.app_idx = get_le16(data + 5);
>> > + pub.ttl = data[7];
>> > + pub.period = data[8];
>> > + n = (data[8] & 0x3f);
>> > + switch (data[8] >> 6) {
>> > + case 0:
>> > + rl_printf("Period: %d ms\n", n * 100);
>> > + break;
>> > + case 2:
>> > + n *= 10;
>> > + /* fall through */
>> > + case 1:
>> > + rl_printf("Period: %d sec\n", n);
>> > + break;
>> > + case 3:
>> > + rl_printf("Period: %d min\n", n * 10);
>> > + break;
>> > + }
>> > +
>> > + pub.retransmit = data[9];
>> > + rl_printf("Retransmit count: %d\n", data[9] >> 5);
>> > + rl_printf("Retransmit Interval Steps: %d\n", data[9] & 0x1f);
>> > +
>> > + ele_idx = ele_addr - node_get_primary(node);
>> > +
>> > + /* Local configuration is saved by server */
>> > + if (node == node_get_local_node())
>> > + break;
>> > +
>> > + if (node_model_pub_set(node, ele_idx, mod_id, &pub))
>> > + prov_db_node_set_model_pub(node, ele_idx, mod_id,
>> > + node_model_pub_get(node, ele_idx, mod_id));
>> > + break;
>> > + }
>> > + return true;
>> > +}
>> > +
>> > +static uint32_t target;
>> > +static uint32_t parms[8];
>> > +
>> > +static uint32_t read_input_parameters(const char *args)
>> > +{
>> > + uint32_t i;
>> > +
>> > + if (!args)
>> > + return 0;
>> > +
>> > + memset(parms, 0xff, sizeof(parms));
>> > +
>> > + for (i = 0; i < sizeof(parms)/sizeof(parms[0]); i++) {
>> > + int n;
>> > +
>> > + sscanf(args, "%x", &parms[i]);
>> > + if (parms[i] == 0xffffffff)
>> > + break;
>> > +
>> > + n = strcspn(args, " \t");
>> > + args = args + n + strspn(args + n, " \t");
>> > + }
>> > +
>> > + return i;
>> > +}
>> > +
>> > +static void cmd_set_node(const char *args)
>> > +{
>> > + uint32_t dst;
>> > + char *end;
>> > +
>> > + dst = strtol(args, &end, 16);
>> > + if (end != (args + 4)) {
>> > + rl_printf("Bad unicast address %s: "
>> > + "expected format 4 digit hex\n", args);
>> > + target = UNASSIGNED_ADDRESS;
>> > + } else {
>> > + rl_printf("Configuring node %4.4x\n", dst);
>> > + target = dst;
>> > + set_menu_prompt("config", args);
>> > + }
>> > +
>> > +}
>> > +
>> > +static bool config_send(uint8_t *buf, uint16_t len)
>> > +{
>> > + struct mesh_node *node = node_get_local_node();
>> > + uint16_t primary;
>> > +
>> > + if(!node)
>> > + return false;
>> > +
>> > + primary = node_get_primary(node);
>> > + if (target != primary)
>> > + return net_access_layer_send(DEFAULT_TTL, primary,
>> > + target, APP_IDX_DEV, buf, len);
>> > +
>> > + node_local_data_handler(primary, target, node_get_iv_index(node),
>> > + node_get_sequence_number(node), APP_IDX_DEV,
>> > + buf, len);
>> > + return true;
>> > +
>> > +}
>> > +
>> > +static void cmd_get_composition(const char *args)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + struct mesh_node *node;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + node = node_find_by_addr(target);
>> > +
>> > + if (!node)
>> > + return;
>> > +
>> > + n = mesh_opcode_set(OP_DEV_COMP_GET, msg);
>> > +
>> > + /* By default, use page 0 */
>> > + msg[n++] = (read_input_parameters(args) == 1) ? parms[0] : 0;
>> > +
>> > + if (!config_send(msg, n))
>> > + rl_printf("Failed to send \"GET NODE COMPOSITION\"\n");
>> > +}
>> > +
>> > +static void cmd_net_key(const char *args, uint32_t opcode)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + uint16_t net_idx;
>> > + uint8_t *key;
>> > + struct mesh_node *node;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(opcode, msg);
>> > +
>> > + if (read_input_parameters(args) != 1) {
>> > + rl_printf("Bad arguments %s\n", args);
>> > + return;
>> > + }
>> > +
>> > + node = node_find_by_addr(target);
>> > + if (!node) {
>> > + rl_printf("Node %4.4x\n not found", target);
>> > + return;
>> > + }
>> > +
>> > + net_idx = parms[0];
>> > +
>> > + if (opcode != OP_NETKEY_DELETE) {
>> > +
>> > + key = keys_net_key_get(net_idx, true);
>> > + if (!key) {
>> > + rl_printf("Network key with index %4.4x not found\n",
>> > + net_idx);
>> > + return;
>> > + }
>> > +
>> > + put_le16(net_idx, &msg[n]);
>> > + n += 2;
>> > +
>> > + memcpy(msg + n, key, 16);
>> > + n += 16;
>> > + }
>> > +
>> > + if (!config_send(msg, n)) {
>> > + rl_printf("Failed to send \"%s NET KEY\"\n",
>> > + opcode == OP_NETKEY_ADD ? "ADD" : "DEL");
>> > + return;
>> > + }
>> > +
>> > + if (opcode != OP_NETKEY_DELETE) {
>> > + if (node_net_key_add(node, net_idx))
>> > + prov_db_node_keys(node, node_get_net_keys(node),
>> > + "netKeys");
>> > + } else {
>> > + if (node_net_key_delete(node, net_idx))
>> > + prov_db_node_keys(node, node_get_net_keys(node),
>> > + "netKeys");
>> > + }
>> > +
>> > +}
>> > +
>> > +static void cmd_add_net_key(const char *args)
>> > +{
>> > + cmd_net_key(args, OP_NETKEY_ADD);
>> > +}
>> > +
>> > +static void cmd_del_net_key(const char *args)
>> > +{
>> > + cmd_net_key(args, OP_NETKEY_DELETE);
>> > +}
>> > +
>> > +static void cmd_app_key(const char *args, uint32_t opcode)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + uint16_t net_idx;
>> > + uint16_t app_idx;
>> > + uint8_t *key;
>> > + struct mesh_node *node;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + if (read_input_parameters(args) != 1) {
>> > + rl_printf("Bad arguments %s\n", args);
>> > + return;
>> > + }
>> > +
>> > + node = node_find_by_addr(target);
>> > + if (!node) {
>> > + rl_printf("Node %4.4x\n not found", target);
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(opcode, msg);
>> > +
>> > + app_idx = parms[0];
>> > + net_idx = keys_app_key_get_bound(app_idx);
>> > + if (net_idx == NET_IDX_INVALID) {
>> > + rl_printf("App key with index %4.4x not found\n", app_idx);
>> > + return;
>> > + }
>> > +
>> > + msg[n++] = net_idx & 0xf;
>> > + msg[n++] = ((net_idx >> 8) & 0xf) |
>> > + ((app_idx << 4) & 0xf0);
>> > + msg[n++] = app_idx >> 4;
>> > +
>> > + if (opcode != OP_APPKEY_DELETE) {
>> > + key = keys_app_key_get(app_idx, true);
>> > + if (!key) {
>> > + rl_printf("App key %4.4x not found\n", net_idx);
>> > + return;
>> > + }
>> > +
>> > + memcpy(msg + n, key, 16);
>> > + n += 16;
>> > + }
>> > +
>> > + if (!config_send(msg, n)) {
>> > + rl_printf("Failed to send \"ADD %s KEY\"\n",
>> > + opcode == OP_APPKEY_ADD ? "ADD" : "DEL");
>> > + return;
>> > + }
>> > +
>> > + if (opcode != OP_APPKEY_DELETE) {
>> > + if (node_app_key_add(node, app_idx))
>> > + prov_db_node_keys(node, node_get_app_keys(node),
>> > + "appKeys");
>> > + } else {
>> > + if (node_app_key_delete(node, net_idx, app_idx))
>> > + prov_db_node_keys(node, node_get_app_keys(node),
>> > + "appKeys");
>> > + }
>> > +}
>> > +
>> > +static void cmd_add_app_key(const char *args)
>> > +{
>> > + cmd_app_key(args, OP_APPKEY_ADD);
>> > +}
>> > +
>> > +static void cmd_del_app_key(const char *args)
>> > +{
>> > + cmd_app_key(args, OP_APPKEY_DELETE);
>> > +}
>> > +
>> > +static void cmd_bind(const char *args)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + int parm_cnt;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + parm_cnt = read_input_parameters(args);
>> > + if (parm_cnt != 3 && parm_cnt != 4) {
>> > + rl_printf("Bad arguments %s\n", args);
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(OP_MODEL_APP_BIND, msg);
>> > +
>> > + put_le16(target + parms[0], msg + n);
>> > + n += 2;
>> > + put_le16(parms[1], msg + n);
>> > + n += 2;
>> > + if (parm_cnt == 4) {
>> > + put_le16(parms[3], msg + n);
>> > + put_le16(parms[2], msg + n + 2);
>> > + n += 4;
>> > + } else {
>> > + put_le16(parms[2], msg + n);
>> > + n += 2;
>> > + }
>> > +
>> > + if (!config_send(msg, n))
>> > + rl_printf("Failed to send \"MODEL APP BIND\"\n");
>> > +}
>> > +
>> > +static void cmd_set_ttl(const char *args)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + int parm_cnt;
>> > + uint8_t ttl;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_SET, msg);
>> > +
>> > + parm_cnt = read_input_parameters(args);
>> > + if (parm_cnt) {
>> > + ttl = parms[0] & TTL_MASK;
>> > + } else
>> > + ttl = node_get_default_ttl(node_get_local_node());
>> > +
>> > + msg[n++] = ttl;
>> > +
>> > + if (!config_send(msg, n))
>> > + rl_printf("Failed to send \"SET_DEFAULT TTL\"\n");
>> > +}
>> > +
>> > +static void cmd_set_pub(const char *args)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + int parm_cnt;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg);
>> > +
>> > + parm_cnt = read_input_parameters(args);
>> > + if (parm_cnt != 5) {
>> > + rl_printf("Bad arguments: %s\n", args);
>> > + return;
>> > + }
>> > +
>> > + put_le16(parms[0], msg + n);
>> > + n += 2;
>> > + /* Publish address */
>> > + put_le16(parms[1], msg + n);
>> > + n += 2;
>> > + /* App key index + credential (set to 0) */
>> > + put_le16(parms[2], msg + n);
>> > + n += 2;
>> > + /* TTL */
>> > + msg[n++] = DEFAULT_TTL;
>> > + /* Publish period step count and step resolution */
>> > + msg[n++] = parms[3];
>> > + /* Publish retransmit count & interval steps */
>> > + msg[n++] = (1 << 5) + 2;
>> > + /* Model Id */
>> > + if (parms[4] > 0xffff) {
>> > + put_le16(parms[4] >> 16, msg + n);
>> > + put_le16(parms[4], msg + n + 2);
>> > + n += 4;
>> > + } else {
>> > + put_le16(parms[4], msg + n);
>> > + n += 2;
>> > + }
>> > +
>> > + if (!config_send(msg, n))
>> > + rl_printf("Failed to send \"SET MODEL PUBLICATION\"\n");
>> > +}
>> > +
>> > +static void cmd_default(uint32_t opcode)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(opcode, msg);
>> > +
>> > + if (!config_send(msg, n))
>> > + rl_printf("Failed to send command (opcode 0x%x)\n", opcode);
>> > +}
>> > +
>> > +static void cmd_get_ttl(const char *args)
>> > +{
>> > + cmd_default(OP_CONFIG_DEFAULT_TTL_GET);
>> > +}
>> > +
>> > +static void cmd_back(const char *args)
>> > +{
>> > + cmd_menu_main(false);
>> > +}
>> > +
>> > +static void cmd_help(const char *args);
>> > +
>> > +static const struct menu_entry cfg_menu[] = {
>> > + {"target", "<unicast>", cmd_set_node,
>> > + "Set target node to configure"},
>> > + {"get-composition", "[<page_num>]", cmd_get_composition,
>> > + "Get Composition Data"},
>> > + {"add-netkey", "<net_idx>", cmd_add_net_key,
>> > + "Add network key"},
>> > + {"del-netkey", "<net_idx>", cmd_del_net_key,
>> > + "Delete network key"},
>> > + {"add-appkey", "<app_idx>", cmd_add_app_key,
>> > + "Add application key"},
>> > + {"del-appkey", "<app_idx>", cmd_del_app_key,
>> > + "Delete application key"},
>> > + {"bind", "<ele_idx> <app_idx> <mod_id> [cid]",
>> > + cmd_bind, "Bind app key to a model"},
>> > + {"set-ttl", "<ttl>", cmd_set_ttl,
>> > + "Set default TTL"},
>> > + {"get-ttl", NULL, cmd_get_ttl,
>> > + "Get default TTL"},
>> > + {"set-pub", "<ele_addr> <pub_addr> <app_idx> "
>> > + "<period (step|res)> <model>",
>> > + cmd_set_pub, "Set publication"},
>> > + {"back", NULL, cmd_back,
>> > + "Back to main menu"},
>> > + {"help", NULL, cmd_help,
>> > + "Config Commands"},
>> > + {}
>> > +};
>> > +
>> > +static void cmd_help(const char *args)
>> > +{
>> > + rl_printf("Client Configuration Menu\n");
>> > + print_cmd_menu(cfg_menu);
>> > +}
>> > +
>> > +void config_set_node(const char *args)
>> > +{
>> > + cmd_set_node(args);
>> > +}
>> > +
>> > +void config_client_get_composition(uint32_t dst)
>> > +{
>> > + uint32_t tmp = target;
>> > +
>> > + target = dst;
>> > + cmd_get_composition("");
>> > + target = tmp;
>> > +}
>> > +
>> > +static struct mesh_model_ops client_cbs = {
>> > + client_msg_recvd,
>> > + NULL,
>> > + NULL,
>> > + NULL
>> > +};
>> > +
>> > +bool config_client_init(void)
>> > +{
>> > + if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
>> > + CONFIG_CLIENT_MODEL_ID,
>> > + &client_cbs, NULL))
>> > + return false;
>> > +
>> > + add_cmd_menu("configure", cfg_menu);
>> > +
>> > + return true;
>> > +}
>> > diff --git a/mesh/config-server.c b/mesh/config-server.c
>> > new file mode 100644
>> > index 0000000..14e5d7b
>> > --- /dev/null
>> > +++ b/mesh/config-server.c
>> > @@ -0,0 +1,165 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <inttypes.h>
>> > +#include <stdbool.h>
>> > +#include <sys/uio.h>
>> > +#include <wordexp.h>
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "src/shared/util.h"
>> > +#include "client/display.h"
>> > +#include "mesh-net.h"
>> > +#include "keys.h"
>> > +#include "net.h"
>> > +#include "node.h"
>> > +#include "prov-db.h"
>> > +#include "util.h"
>> > +#include "config-model.h"
>> > +
>> > +static bool server_msg_recvd(uint16_t src, uint8_t *data,
>> > + uint16_t len, void *user_data)
>> > +{
>> > + uint32_t opcode;
>> > + uint8_t msg[32];
>> > + struct mesh_node *node;
>> > + uint16_t primary;
>> > + uint32_t mod_id;
>> > + uint16_t ele_addr;
>> > + uint8_t ele_idx;
>> > + struct mesh_publication pub;
>> > +
>> > + int n;
>> > +
>> > + if (mesh_opcode_get(data, len, &opcode, &n)) {
>> > + len -= n;
>> > + data += n;
>> > + } else
>> > + return false;
>> > +
>> > + node = node_get_local_node();
>> > +
>> > + if (!node)
>> > + return true;
>> > +
>> > + switch (opcode & ~OP_UNRELIABLE) {
>> > + default:
>> > + return false;
>> > +
>> > + case OP_CONFIG_DEFAULT_TTL_SET:
>> > + if (len != 1 || data[0] > TTL_MASK || data[0] == 1)
>> > + return true;
>> > +
>> > + if (data[0] <= TTL_MASK) {
>> > + node_set_default_ttl(node, data[0]);
>> > + prov_db_node_set_ttl(node, data[0]);
>> > + }
>> > +
>> > + /* Fall Through */
>> > +
>> > + case OP_CONFIG_DEFAULT_TTL_GET:
>> > + n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_STATUS, msg);
>> > + msg[n++] = node_get_default_ttl(node);
>> > + break;
>> > +
>> > + case OP_CONFIG_MODEL_PUB_SET:
>> > + if (len != 11 && len != 13)
>> > + return true;
>> > +
>> > + rl_printf("Set publication\n");
>> > +
>> > + ele_addr = get_le16(data);
>> > + mod_id = get_le16(data + 9);
>> > + if (len == 14)
>> > + mod_id = (mod_id << 16) | get_le16(data + 11);
>> > + else
>> > + mod_id |= 0xffff0000;
>> > +
>> > + pub.u.addr16 = get_le16(data + 2);
>> > + pub.app_idx = get_le16(data + 4);
>> > + pub.ttl = data[6];
>> > + pub.period = data[7];
>> > + n = (data[7] & 0x3f);
>> > + switch (data[7] >> 6) {
>> > + case 0:
>> > + rl_printf("Period: %d ms\n", n * 100);
>> > + break;
>> > + case 2:
>> > + n *= 10;
>> > + /* fall through */
>> > + case 1:
>> > + rl_printf("Period: %d sec\n", n);
>> > + break;
>> > + case 3:
>> > + rl_printf("Period: %d min\n", n * 10);
>> > + break;
>> > + }
>> > +
>> > + pub.retransmit = data[8];
>> > + rl_printf("Retransmit count: %d\n", data[8] >> 5);
>> > + rl_printf("Retransmit Interval Steps: %d\n", data[8] & 0x1f);
>> > +
>> > + ele_idx = ele_addr - node_get_primary(node);
>> > +
>> > + if (node_model_pub_set(node, ele_idx, mod_id, &pub)) {
>> > + prov_db_node_set_model_pub(node, ele_idx, mod_id,
>> > + node_model_pub_get(node, ele_idx, mod_id));
>> > + }
>> > + break;
>> > + }
>> > +
>> > + primary = node_get_primary(node);
>> > + if (src != primary)
>> > + net_access_layer_send(node_get_default_ttl(node), primary,
>> > + src, APP_IDX_DEV, msg, len);
>> > + return true;
>> > +}
>> > +
>> > +
>> > +static struct mesh_model_ops server_cbs = {
>> > + server_msg_recvd,
>> > + NULL,
>> > + NULL,
>> > + NULL
>> > +};
>> > +
>> > +bool config_server_init(void)
>> > +{
>> > + if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
>> > + CONFIG_SERVER_MODEL_ID,
>> > + &server_cbs, NULL))
>> > + return false;
>> > +
>> > + return true;
>> > +}
>> > diff --git a/mesh/crypto.c b/mesh/crypto.c
>> > new file mode 100644
>> > index 0000000..189624e
>> > --- /dev/null
>> > +++ b/mesh/crypto.c
>> > @@ -0,0 +1,1168 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <fcntl.h>
>> > +#include <unistd.h>
>> > +#include <string.h>
>> > +#include <sys/socket.h>
>> > +
>> > +#include <linux/if_alg.h>
>> > +
>> > +#include <glib.h>
>> > +
>> > +#ifndef SOL_ALG
>> > +#define SOL_ALG 279
>> > +#endif
>> > +
>> > +#ifndef ALG_SET_AEAD_AUTHSIZE
>> > +#define ALG_SET_AEAD_AUTHSIZE 5
>> > +#endif
>> > +
>> > +#include "src/shared/util.h"
>> > +#include "mesh-net.h"
>> > +#include "crypto.h"
>> > +
>> > +static int alg_new(int fd, const void *keyval, socklen_t keylen,
>> > + size_t mic_size)
>> > +{
>> > + if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, keyval, keylen) < 0) {
>> > + g_printerr("key");
>> > + return -1;
>> > + }
>> > +
>> > + if (mic_size &&
>> > + setsockopt(fd, SOL_ALG,
>> > + ALG_SET_AEAD_AUTHSIZE, NULL, mic_size) < 0) {
>> > + g_printerr("taglen");
>> > + return -1;
>> > + }
>> > +
>> > + /* FIXME: This should use accept4() with SOCK_CLOEXEC */
>> > + return accept(fd, NULL, 0);
>> > +}
>> > +
>> > +static bool alg_encrypt(int fd, const void *inbuf, size_t inlen,
>> > + void *outbuf, size_t outlen)
>> > +{
>> > + __u32 alg_op = ALG_OP_ENCRYPT;
>> > + char cbuf[CMSG_SPACE(sizeof(alg_op))];
>> > + struct cmsghdr *cmsg;
>> > + struct msghdr msg;
>> > + struct iovec iov;
>> > + ssize_t len;
>> > +
>> > + memset(cbuf, 0, sizeof(cbuf));
>> > + memset(&msg, 0, sizeof(msg));
>> > +
>> > + msg.msg_control = cbuf;
>> > + msg.msg_controllen = sizeof(cbuf);
>> > +
>> > + cmsg = CMSG_FIRSTHDR(&msg);
>> > + cmsg->cmsg_level = SOL_ALG;
>> > + cmsg->cmsg_type = ALG_SET_OP;
>> > + cmsg->cmsg_len = CMSG_LEN(sizeof(alg_op));
>> > + memcpy(CMSG_DATA(cmsg), &alg_op, sizeof(alg_op));
>> > +
>> > + iov.iov_base = (void *) inbuf;
>> > + iov.iov_len = inlen;
>> > +
>> > + msg.msg_iov = &iov;
>> > + msg.msg_iovlen = 1;
>> > +
>> > + len = sendmsg(fd, &msg, 0);
>> > + if (len < 0)
>> > + return false;
>> > +
>> > + len = read(fd, outbuf, outlen);
>> > + if (len < 0)
>> > + return false;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static int aes_ecb_setup(const uint8_t key[16])
>> > +{
>> > + struct sockaddr_alg salg;
>> > + int fd, nfd;
>> > +
>> > + fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
>> > + if (fd < 0)
>> > + return -1;
>> > +
>> > + memset(&salg, 0, sizeof(salg));
>> > + salg.salg_family = AF_ALG;
>> > + strcpy((char *) salg.salg_type, "skcipher");
>> > + strcpy((char *) salg.salg_name, "ecb(aes)");
>> > +
>> > + if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
>> > + close(fd);
>> > + return -1;
>> > + }
>> > +
>> > + nfd = alg_new(fd, key, 16, 0);
>> > +
>> > + close(fd);
>> > +
>> > + return nfd;
>> > +}
>> > +
>> > +static bool aes_ecb(int fd, const uint8_t plaintext[16], uint8_t
>> encrypted[16])
>> > +{
>> > + return alg_encrypt(fd, plaintext, 16, encrypted, 16);
>> > +}
>> > +
>> > +static void aes_ecb_destroy(int fd)
>> > +{
>> > + close(fd);
>> > +}
>> > +
>> > +static bool aes_ecb_one(const uint8_t key[16],
>> > + const uint8_t plaintext[16], uint8_t encrypted[16])
>> > +{
>> > + bool result;
>> > + int fd;
>> > +
>> > + fd = aes_ecb_setup(key);
>> > + if (fd < 0)
>> > + return false;
>> > +
>> > + result = aes_ecb(fd, plaintext, encrypted);
>> > +
>> > + aes_ecb_destroy(fd);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +/* Maximum message length that can be passed to aes_cmac */
>> > +#define CMAC_MSG_MAX (64 + 64 + 17)
>> > +
>> > +static int aes_cmac_setup(const uint8_t key[16])
>> > +{
>> > + struct sockaddr_alg salg;
>> > + int fd, nfd;
>> > +
>> > + fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
>> > + if (fd < 0)
>> > + return -1;
>> > +
>> > + memset(&salg, 0, sizeof(salg));
>> > + salg.salg_family = AF_ALG;
>> > + strcpy((char *) salg.salg_type, "hash");
>> > + strcpy((char *) salg.salg_name, "cmac(aes)");
>> > +
>> > + if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
>> > + close(fd);
>> > + return -1;
>> > + }
>> > +
>> > + nfd = alg_new(fd, key, 16, 0);
>> > +
>> > + close(fd);
>> > +
>> > + return nfd;
>> > +}
>> > +
>> > +static bool aes_cmac(int fd, const uint8_t *msg,
>> > + size_t msg_len, uint8_t res[16])
>> > +{
>> > + ssize_t len;
>> > +
>> > + if (msg_len > CMAC_MSG_MAX)
>> > + return false;
>> > +
>> > + len = send(fd, msg, msg_len, 0);
>> > + if (len < 0)
>> > + return false;
>> > +
>> > + len = read(fd, res, 16);
>> > + if (len < 0)
>> > + return false;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static void aes_cmac_destroy(int fd)
>> > +{
>> > + close(fd);
>> > +}
>> > +
>> > +static int aes_cmac_N_start(const uint8_t N[16])
>> > +{
>> > + int fd;
>> > +
>> > + fd = aes_cmac_setup(N);
>> > + return fd;
>> > +}
>> > +
>> > +static bool aes_cmac_one(const uint8_t key[16], const void *msg,
>> > + size_t msg_len, uint8_t res[16])
>> > +{
>> > + bool result;
>> > + int fd;
>> > +
>> > + fd = aes_cmac_setup(key);
>> > + if (fd < 0)
>> > + return false;
>> > +
>> > + result = aes_cmac(fd, msg, msg_len, res);
>> > +
>> > + aes_cmac_destroy(fd);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +bool mesh_crypto_aes_cmac(const uint8_t key[16], const uint8_t *msg,
>> > + size_t msg_len, uint8_t res[16])
>> > +{
>> > + return aes_cmac_one(key, msg, msg_len, res);
>> > +}
>> > +
>> > +bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const
>> uint8_t key[16],
>> > + const uint8_t *aad, uint16_t aad_len,
>> > + const uint8_t *msg, uint16_t msg_len,
>> > + uint8_t *out_msg, void *out_mic,
>> > + size_t mic_size)
>> > +{
>> > + uint8_t pmsg[16], cmic[16], cmsg[16];
>> > + uint8_t mic[16], Xn[16];
>> > + uint16_t blk_cnt, last_blk;
>> > + bool result;
>> > + size_t i, j;
>> > + int fd;
>> > +
>> > + if (aad_len >= 0xff00) {
>> > + g_printerr("Unsupported AAD size");
>> > + return false;
>> > + }
>> > +
>> > + fd = aes_ecb_setup(key);
>> > + if (fd < 0)
>> > + return false;
>> > +
>> > + /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
>> > + pmsg[0] = 0x01;
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(0x0000, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, cmic);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* X_0 = e(AppKey, 0x09 || nonce || length) */
>> > + if (mic_size == sizeof(uint64_t))
>> > + pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
>> > + else
>> > + pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
>> > +
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(msg_len, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* If AAD is being used to authenticate, include it here */
>> > + if (aad_len) {
>> > + put_be16(aad_len, pmsg);
>> > +
>> > + for (i = 0; i < sizeof(uint16_t); i++)
>> > + pmsg[i] = Xn[i] ^ pmsg[i];
>> > +
>> > + j = 0;
>> > + aad_len += sizeof(uint16_t);
>> > + while (aad_len > 16) {
>> > + do {
>> > + pmsg[i] = Xn[i] ^ aad[j];
>> > + i++, j++;
>> > + } while (i < 16);
>> > +
>> > + aad_len -= 16;
>> > + i = 0;
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > + }
>> > +
>> > + for (i = 0; i < aad_len; i++, j++)
>> > + pmsg[i] = Xn[i] ^ aad[j];
>> > +
>> > + for (i = aad_len; i < 16; i++)
>> > + pmsg[i] = Xn[i];
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > + }
>> > +
>> > + last_blk = msg_len % 16;
>> > + blk_cnt = (msg_len + 15) / 16;
>> > + if (!last_blk)
>> > + last_blk = 16;
>> > +
>> > + for (j = 0; j < blk_cnt; j++) {
>> > + if (j + 1 == blk_cnt) {
>> > + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
>> > + for (i = 0; i < last_blk; i++)
>> > + pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
>> > + for (i = last_blk; i < 16; i++)
>> > + pmsg[i] = Xn[i] ^ 0x00;
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* MIC = C_mic ^ X_1 */
>> > + for (i = 0; i < sizeof(mic); i++)
>> > + mic[i] = cmic[i] ^ Xn[i];
>> > +
>> > + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
>> > + pmsg[0] = 0x01;
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(j + 1, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, cmsg);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + if (out_msg) {
>> > + /* Encrypted = Payload[0-15] ^ C_1 */
>> > + for (i = 0; i < last_blk; i++)
>> > + out_msg[(j * 16) + i] =
>> > + msg[(j * 16) + i] ^ cmsg[i];
>> > +
>> > + }
>> > + } else {
>> > + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
>> > + for (i = 0; i < 16; i++)
>> > + pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
>> > + pmsg[0] = 0x01;
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(j + 1, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, cmsg);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + if (out_msg) {
>> > + /* Encrypted = Payload[0-15] ^ C_N */
>> > + for (i = 0; i < 16; i++)
>> > + out_msg[(j * 16) + i] =
>> > + msg[(j * 16) + i] ^ cmsg[i];
>> > + }
>> > +
>> > + }
>> > + }
>> > +
>> > + if (out_msg)
>> > + memcpy(out_msg + msg_len, mic, mic_size);
>> > +
>> > + if (out_mic) {
>> > + switch (mic_size) {
>> > + case sizeof(uint32_t):
>> > + *(uint32_t *)out_mic = get_be32(mic);
>> > + break;
>> > + case sizeof(uint64_t):
>> > + *(uint64_t *)out_mic = get_be64(mic);
>> > + break;
>> > + default:
>> > + g_printerr("Unsupported MIC size");
>> > + }
>> > + }
>> > +
>> > +done:
>> > + aes_ecb_destroy(fd);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const
>> uint8_t key[16],
>> > + const uint8_t *aad, uint16_t aad_len,
>> > + const uint8_t *enc_msg, uint16_t enc_msg_len,
>> > + uint8_t *out_msg, void *out_mic,
>> > + size_t mic_size)
>> > +{
>> > + uint8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16];
>> > + uint8_t mic[16];
>> > + uint16_t msg_len = enc_msg_len - mic_size;
>> > + uint16_t last_blk, blk_cnt;
>> > + bool result;
>> > + size_t i, j;
>> > + int fd;
>> > +
>> > + if (enc_msg_len < 5 || aad_len >= 0xff00)
>> > + return false;
>> > +
>> > + fd = aes_ecb_setup(key);
>> > + if (fd < 0)
>> > + return false;
>> > +
>> > + /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
>> > + pmsg[0] = 0x01;
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(0x0000, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, cmic);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* X_0 = e(AppKey, 0x09 || nonce || length) */
>> > + if (mic_size == sizeof(uint64_t))
>> > + pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
>> > + else
>> > + pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
>> > +
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(msg_len, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* If AAD is being used to authenticate, include it here */
>> > + if (aad_len) {
>> > + put_be16(aad_len, pmsg);
>> > +
>> > + for (i = 0; i < sizeof(uint16_t); i++)
>> > + pmsg[i] = Xn[i] ^ pmsg[i];
>> > +
>> > + j = 0;
>> > + aad_len += sizeof(uint16_t);
>> > + while (aad_len > 16) {
>> > + do {
>> > + pmsg[i] = Xn[i] ^ aad[j];
>> > + i++, j++;
>> > + } while (i < 16);
>> > +
>> > + aad_len -= 16;
>> > + i = 0;
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > + }
>> > +
>> > + for (i = 0; i < aad_len; i++, j++)
>> > + pmsg[i] = Xn[i] ^ aad[j];
>> > +
>> > + for (i = aad_len; i < 16; i++)
>> > + pmsg[i] = Xn[i];
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > + }
>> > +
>> > + last_blk = msg_len % 16;
>> > + blk_cnt = (msg_len + 15) / 16;
>> > + if (!last_blk)
>> > + last_blk = 16;
>> > +
>> > + for (j = 0; j < blk_cnt; j++) {
>> > + if (j + 1 == blk_cnt) {
>> > + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
>> > + pmsg[0] = 0x01;
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(j + 1, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, cmsg);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* Encrypted = Payload[0-15] ^ C_1 */
>> > + for (i = 0; i < last_blk; i++)
>> > + msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
>> > +
>> > + if (out_msg)
>> > + memcpy(out_msg + (j * 16), msg, last_blk);
>> > +
>> > + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
>> > + for (i = 0; i < last_blk; i++)
>> > + pmsg[i] = Xn[i] ^ msg[i];
>> > + for (i = last_blk; i < 16; i++)
>> > + pmsg[i] = Xn[i] ^ 0x00;
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* MIC = C_mic ^ X_1 */
>> > + for (i = 0; i < sizeof(mic); i++)
>> > + mic[i] = cmic[i] ^ Xn[i];
>> > + } else {
>> > + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
>> > + pmsg[0] = 0x01;
>> > + memcpy(pmsg + 1, nonce, 13);
>> > + put_be16(j + 1, pmsg + 14);
>> > +
>> > + result = aes_ecb(fd, pmsg, cmsg);
>> > + if (!result)
>> > + goto done;
>> > +
>> > + /* Encrypted = Payload[0-15] ^ C_1 */
>> > + for (i = 0; i < 16; i++)
>> > + msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
>> > +
>> > + if (out_msg)
>> > + memcpy(out_msg + (j * 16), msg, 16);
>> > +
>> > + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
>> > + for (i = 0; i < 16; i++)
>> > + pmsg[i] = Xn[i] ^ msg[i];
>> > +
>> > + result = aes_ecb(fd, pmsg, Xn);
>> > + if (!result)
>> > + goto done;
>> > + }
>> > + }
>> > +
>> > + switch (mic_size) {
>> > + case sizeof(uint32_t):
>> > + if (out_mic)
>> > + *(uint32_t *)out_mic = get_be32(mic);
>> > + else if (get_be32(enc_msg + enc_msg_len - mic_size) !=
>> > + get_be32(mic))
>> > + result = false;
>> > + break;
>> > +
>> > + case sizeof(uint64_t):
>> > + if (out_mic)
>> > + *(uint64_t *)out_mic = get_be64(mic);
>> > + else if (get_be64(enc_msg + enc_msg_len - mic_size) !=
>> > + get_be64(mic))
>> > + result = false;
>> > + break;
>> > +
>> > + default:
>> > + g_printerr("Unsupported MIC size");
>> > + result = false;
>> > + }
>> > +
>> > +done:
>> > + aes_ecb_destroy(fd);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +bool mesh_crypto_k1(const uint8_t ikm[16], const uint8_t salt[16],
>> > + const void *info, size_t info_len, uint8_t okm[16])
>> > +{
>> > + uint8_t res[16];
>> > +
>> > + if (!aes_cmac_one(salt, ikm, 16, res))
>> > + return false;
>> > +
>> > + return aes_cmac_one(res, info, info_len, okm);
>> > +}
>> > +
>> > +bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
>> > + uint8_t net_id[1],
>> > + uint8_t enc_key[16],
>> > + uint8_t priv_key[16])
>> > +{
>> > + int fd;
>> > + uint8_t output[16];
>> > + uint8_t t[16];
>> > + uint8_t *stage;
>> > + bool success = false;
>> > +
>> > + stage = g_malloc(sizeof(output) + p_len + 1);
>> > + if (stage == NULL)
>> > + return false;
>> > +
>> > + if (!mesh_crypto_s1("smk2", 4, stage))
>> > + goto fail;
>> > +
>> > + if (!aes_cmac_one(stage, n, 16, t))
>> > + goto fail;
>> > +
>> > + fd = aes_cmac_N_start(t);
>> > + if (fd < 0)
>> > + goto fail;
>> > +
>> > + memcpy(stage, p, p_len);
>> > + stage[p_len] = 1;
>> > +
>> > + if(!aes_cmac(fd, stage, p_len + 1, output))
>> > + goto done;
>> > +
>> > + net_id[0] = output[15] & 0x7f;
>> > +
>> > + memcpy(stage, output, 16);
>> > + memcpy(stage + 16, p, p_len);
>> > + stage[p_len + 16] = 2;
>> > +
>> > + if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
>> > + goto done;
>> > +
>> > + memcpy(enc_key, output, 16);
>> > +
>> > + memcpy(stage, output, 16);
>> > + memcpy(stage + 16, p, p_len);
>> > + stage[p_len + 16] = 3;
>> > +
>> > + if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
>> > + goto done;
>> > +
>> > + memcpy(priv_key, output, 16);
>> > + success = true;
>> > +
>> > +done:
>> > + aes_cmac_destroy(fd);
>> > +fail:
>> > + g_free(stage);
>> > +
>> > + return success;
>> > +}
>> > +
>> > +static bool crypto_128(const uint8_t n[16], const char *s, uint8_t
>> out128[16])
>> > +{
>> > + uint8_t id128[] = { 'i', 'd', '1', '2', '8', 0x01 };
>> > + uint8_t salt[16];
>> > +
>> > + if (!mesh_crypto_s1(s, 4, salt))
>> > + return false;
>> > +
>> > + return mesh_crypto_k1(n, salt, id128, sizeof(id128), out128);
>> > +}
>> > +
>> > +bool mesh_crypto_nkik(const uint8_t n[16], uint8_t identity_key[16])
>> > +{
>> > + return crypto_128(n, "nkik", identity_key);
>> > +}
>> > +
>> > +static bool identity_calc(const uint8_t net_key[16], uint16_t addr,
>> > + bool check, uint8_t id[16])
>> > +{
>> > + uint8_t id_key[16];
>> > + uint8_t tmp[16];
>> > +
>> > + if (!mesh_crypto_nkik(net_key, id_key))
>> > + return false;
>> > +
>> > + memset(tmp, 0, sizeof(tmp));
>> > + put_be16(addr, tmp + 14);
>> > +
>> > + if (check) {
>> > + memcpy(tmp + 6, id + 8, 8);
>> > + } else {
>> > + mesh_get_random_bytes(tmp + 6, 8);
>> > + memcpy(id + 8, tmp + 6, 8);
>> > + }
>> > +
>> > + if (!aes_ecb_one(id_key, tmp, tmp))
>> > + return false;
>> > +
>> > + if (check)
>> > + return (memcmp(id, tmp + 8, 8) == 0);
>> > +
>> > + memcpy(id, tmp + 8, 8);
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_identity(const uint8_t net_key[16], uint16_t addr,
>> > + uint8_t id[16])
>> > +{
>> > + return identity_calc(net_key, addr, false, id);
>> > +}
>> > +
>> > +bool mesh_crypto_identity_check(const uint8_t net_key[16], uint16_t
>> addr,
>> > + uint8_t id[16])
>> > +{
>> > + return identity_calc(net_key, addr, true, id);
>> > +}
>> > +
>> > +bool mesh_crypto_nkbk(const uint8_t n[16], uint8_t beacon_key[16])
>> > +{
>> > + return crypto_128(n, "nkbk", beacon_key);
>> > +}
>> > +
>> > +bool mesh_crypto_k3(const uint8_t n[16], uint8_t out64[8])
>> > +{
>> > + uint8_t tmp[16];
>> > + uint8_t t[16];
>> > + uint8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
>> > +
>> > + if (!mesh_crypto_s1("smk3", 4, tmp))
>> > + return false;
>> > +
>> > + if (!aes_cmac_one(tmp, n, 16, t))
>> > + return false;
>> > +
>> > + if (!aes_cmac_one(t, id64, sizeof(id64), tmp))
>> > + return false;
>> > +
>> > + memcpy(out64, tmp + 8, 8);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_k4(const uint8_t a[16], uint8_t out6[1])
>> > +{
>> > + uint8_t tmp[16];
>> > + uint8_t t[16];
>> > + uint8_t id6[] = { 'i', 'd', '6', 0x01 };
>> > +
>> > + if (!mesh_crypto_s1("smk4", 4, tmp))
>> > + return false;
>> > +
>> > + if (!aes_cmac_one(tmp, a, 16, t))
>> > + return false;
>> > +
>> > + if (!aes_cmac_one(t, id6, sizeof(id6), tmp))
>> > + return false;
>> > +
>> > + out6[0] = tmp[15] & 0x3f;
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_beacon_cmac(const uint8_t encryption_key[16],
>> > + const uint8_t network_id[8],
>> > + uint32_t iv_index, bool kr, bool iu,
>> > + uint64_t *cmac)
>> > +{
>> > + uint8_t msg[13], tmp[16];
>> > +
>> > + if (!cmac)
>> > + return false;
>> > +
>> > + msg[0] = kr ? 0x01 : 0x00;
>> > + msg[0] |= iu ? 0x02 : 0x00;
>> > + memcpy(msg + 1, network_id, 8);
>> > + put_be32(iv_index, msg + 9);
>> > +
>> > + if (!aes_cmac_one(encryption_key, msg, 13, tmp))
>> > + return false;
>> > +
>> > + *cmac = get_be64(tmp);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_network_nonce(bool ctl, uint8_t ttl, uint32_t seq,
>> > + uint16_t src, uint32_t iv_index,
>> > + uint8_t nonce[13])
>> > +{
>> > + nonce[0] = 0;
>> > + nonce[1] = (ttl & TTL_MASK) | (ctl ? CTL : 0x00);
>> > + nonce[2] = (seq >> 16) & 0xff;
>> > + nonce[3] = (seq >> 8) & 0xff;
>> > + nonce[4] = seq & 0xff;
>> > +
>> > + /* SRC */
>> > + put_be16(src, nonce + 5);
>> > +
>> > + put_be16(0, nonce + 7);
>> > +
>> > + /* IV Index */
>> > + put_be32(iv_index, nonce + 9);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_network_encrypt(bool ctl, uint8_t ttl,
>> > + uint32_t seq, uint16_t src,
>> > + uint32_t iv_index,
>> > + const uint8_t net_key[16],
>> > + const uint8_t *enc_msg, uint8_t enc_msg_len,
>> > + uint8_t *out, void *net_mic)
>> > +{
>> > + uint8_t nonce[13];
>> > +
>> > + if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
>> > + return false;
>> > +
>> > + return mesh_crypto_aes_ccm_encrypt(nonce, net_key,
>> > + NULL, 0, enc_msg,
>> > + enc_msg_len, out,
>> > + net_mic,
>> > + ctl ? sizeof(uint64_t) : sizeof(uint32_t));
>> > +}
>> > +
>> > +bool mesh_crypto_network_decrypt(bool ctl, uint8_t ttl,
>> > + uint32_t seq, uint16_t src,
>> > + uint32_t iv_index,
>> > + const uint8_t net_key[16],
>> > + const uint8_t *enc_msg, uint8_t enc_msg_len,
>> > + uint8_t *out, void *net_mic, size_t mic_size)
>> > +{
>> > + uint8_t nonce[13];
>> > +
>> > + if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
>> > + return false;
>> > +
>> > + return mesh_crypto_aes_ccm_decrypt(nonce, net_key, NULL, 0,
>> > + enc_msg, enc_msg_len, out,
>> > + net_mic, mic_size);
>> > +}
>> > +
>> > +bool mesh_crypto_application_nonce(uint32_t seq, uint16_t src,
>> > + uint16_t dst, uint32_t iv_index,
>> > + bool aszmic, uint8_t nonce[13])
>> > +{
>> > + nonce[0] = 0x01;
>> > + nonce[1] = aszmic ? 0x80 : 0x00;
>> > + nonce[2] = (seq & 0x00ff0000) >> 16;
>> > + nonce[3] = (seq & 0x0000ff00) >> 8;
>> > + nonce[4] = (seq & 0x000000ff);
>> > + nonce[5] = (src & 0xff00) >> 8;
>> > + nonce[6] = (src & 0x00ff);
>> > + nonce[7] = (dst & 0xff00) >> 8;
>> > + nonce[8] = (dst & 0x00ff);
>> > + put_be32(iv_index, nonce + 9);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_device_nonce(uint32_t seq, uint16_t src,
>> > + uint16_t dst, uint32_t iv_index,
>> > + bool aszmic, uint8_t nonce[13])
>> > +{
>> > + nonce[0] = 0x02;
>> > + nonce[1] = aszmic ? 0x80 : 0x00;
>> > + nonce[2] = (seq & 0x00ff0000) >> 16;
>> > + nonce[3] = (seq & 0x0000ff00) >> 8;
>> > + nonce[4] = (seq & 0x000000ff);
>> > + nonce[5] = (src & 0xff00) >> 8;
>> > + nonce[6] = (src & 0x00ff);
>> > + nonce[7] = (dst & 0xff00) >> 8;
>> > + nonce[8] = (dst & 0x00ff);
>> > + put_be32(iv_index, nonce + 9);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq,
>> uint16_t src,
>> > + uint16_t dst, uint32_t iv_index,
>> > + const uint8_t app_key[16],
>> > + const uint8_t *aad, uint8_t aad_len,
>> > + const uint8_t *msg, uint8_t msg_len,
>> > + uint8_t *out, void *app_mic,
>> > + size_t mic_size)
>> > +{
>> > + uint8_t nonce[13];
>> > + bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
>> > +
>> > + if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
>> > + iv_index, aszmic, nonce))
>> > + return false;
>> > +
>> > + if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
>> > + iv_index, aszmic, nonce))
>> > + return false;
>> > +
>> > + return mesh_crypto_aes_ccm_encrypt(nonce, app_key, aad,
>> aad_len,
>> > + msg, msg_len,
>> > + out, app_mic, mic_size);
>> > +}
>> > +
>> > +bool mesh_crypto_application_decrypt(uint8_t key_id, uint32_t seq,
>> uint16_t src,
>> > + uint16_t dst, uint32_t iv_index,
>> > + const uint8_t app_key[16],
>> > + const uint8_t *aad, uint8_t aad_len,
>> > + const uint8_t *enc_msg, uint8_t enc_msg_len,
>> > + uint8_t *out, void *app_mic, size_t mic_size)
>> > +{
>> > + uint8_t nonce[13];
>> > + bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
>> > +
>> > + if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
>> > + iv_index, aszmic, nonce))
>> > + return false;
>> > +
>> > + if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
>> > + iv_index, aszmic, nonce))
>> > + return false;
>> > +
>> > + return mesh_crypto_aes_ccm_decrypt(nonce, app_key,
>> > + aad, aad_len, enc_msg,
>> > + enc_msg_len, out,
>> > + app_mic, mic_size);
>> > +}
>> > +
>> > +bool mesh_crypto_session_key(const uint8_t secret[32],
>> > + const uint8_t salt[16],
>> > + uint8_t session_key[16])
>> > +{
>> > + const uint8_t prsk[4] = "prsk";
>> > +
>> > + if (!aes_cmac_one(salt, secret, 32, session_key))
>> > + return false;
>> > +
>> > + return aes_cmac_one(session_key, prsk, 4, session_key);
>> > +}
>> > +
>> > +bool mesh_crypto_nonce(const uint8_t secret[32],
>> > + const uint8_t salt[16],
>> > + uint8_t nonce[13])
>> > +{
>> > + const uint8_t prsn[4] = "prsn";
>> > + uint8_t tmp[16];
>> > + bool result;
>> > +
>> > + if (!aes_cmac_one(salt, secret, 32, tmp))
>> > + return false;
>> > +
>> > + result = aes_cmac_one(tmp, prsn, 4, tmp);
>> > +
>> > + if (result)
>> > + memcpy(nonce, tmp + 3, 13);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +bool mesh_crypto_s1(const void *info, size_t len, uint8_t salt[16])
>> > +{
>> > + const uint8_t zero[16] = {0};
>> > +
>> > + return aes_cmac_one(zero, info, len, salt);
>> > +}
>> > +
>> > +bool mesh_crypto_prov_prov_salt(const uint8_t conf_salt[16],
>> > + const uint8_t prov_rand[16],
>> > + const uint8_t dev_rand[16],
>> > + uint8_t prov_salt[16])
>> > +{
>> > + const uint8_t zero[16] = {0};
>> > + uint8_t tmp[16 * 3];
>> > +
>> > + memcpy(tmp, conf_salt, 16);
>> > + memcpy(tmp + 16, prov_rand, 16);
>> > + memcpy(tmp + 32, dev_rand, 16);
>> > +
>> > + return aes_cmac_one(zero, tmp, sizeof(tmp), prov_salt);
>> > +}
>> > +
>> > +bool mesh_crypto_prov_conf_key(const uint8_t secret[32],
>> > + const uint8_t salt[16],
>> > + uint8_t conf_key[16])
>> > +{
>> > + const uint8_t prck[4] = "prck";
>> > +
>> > + if (!aes_cmac_one(salt, secret, 32, conf_key))
>> > + return false;
>> > +
>> > + return aes_cmac_one(conf_key, prck, 4, conf_key);
>> > +}
>> > +
>> > +bool mesh_crypto_device_key(const uint8_t secret[32],
>> > + const uint8_t salt[16],
>> > + uint8_t device_key[16])
>> > +{
>> > + const uint8_t prdk[4] = "prdk";
>> > +
>> > + if (!aes_cmac_one(salt, secret, 32, device_key))
>> > + return false;
>> > +
>> > + return aes_cmac_one(device_key, prdk, 4, device_key);
>> > +}
>> > +
>> > +bool mesh_crypto_virtual_addr(const uint8_t virtual_label[16],
>> > + uint16_t *addr)
>> > +{
>> > + uint8_t tmp[16];
>> > +
>> > + if (!mesh_crypto_s1("vtad", 4, tmp))
>> > + return false;
>> > +
>> > + if (!addr || !aes_cmac_one(tmp, virtual_label, 16, tmp))
>> > + return false;
>> > +
>> > + *addr = (get_be16(tmp + 14) & 0x3fff) | 0x8000;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_packet_encode(uint8_t *packet, uint8_t packet_len,
>> > + const uint8_t network_key[16],
>> > + uint32_t iv_index,
>> > + const uint8_t privacy_key[16])
>> > +{
>> > + uint8_t network_nonce[13] = { 0x00, 0x00 };
>> > + uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
>> > + uint8_t tmp[16];
>> > + int i;
>> > +
>> > + /* Detect Proxy packet by CTL == true && DST == 0x0000 */
>> > + if ((packet[1] & CTL) && get_be16(packet + 7) == 0)
>> > + network_nonce[0] = 0x03;
>> > + else
>> > + /* CTL + TTL */
>> > + network_nonce[1] = packet[1];
>> > +
>> > + /* Seq Num */
>> > + network_nonce[2] = packet[2];
>> > + network_nonce[3] = packet[3];
>> > + network_nonce[4] = packet[4];
>> > +
>> > + /* SRC */
>> > + network_nonce[5] = packet[5];
>> > + network_nonce[6] = packet[6];
>> > +
>> > + /* DST not available */
>> > + network_nonce[7] = 0;
>> > + network_nonce[8] = 0;
>> > +
>> > + /* IV Index */
>> > + put_be32(iv_index, network_nonce + 9);
>> > +
>> > + /* Check for Long net-MIC */
>> > + if (packet[1] & CTL) {
>> > + if (!mesh_crypto_aes_ccm_encrypt(network_nonce,
>> network_key,
>> > + NULL, 0,
>> > + packet + 7, packet_len - 7 - 8,
>> > + packet + 7, NULL, sizeof(uint64_t)))
>> > + return false;
>> > + } else {
>> > + if (!mesh_crypto_aes_ccm_encrypt(network_nonce,
>> network_key,
>> > + NULL, 0,
>> > + packet + 7, packet_len - 7 - 4,
>> > + packet + 7, NULL, sizeof(uint32_t)))
>> > + return false;
>> > + }
>> > +
>> > + put_be32(iv_index, privacy_counter + 5);
>> > + memcpy(privacy_counter + 9, packet + 7, 7);
>> > +
>> > + if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
>> > + return false;
>> > +
>> > + for (i = 0; i < 6; i++)
>> > + packet[1 + i] ^= tmp[i];
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_crypto_packet_decode(const uint8_t *packet, uint8_t
>> packet_len,
>> > + bool proxy, uint8_t *out, uint32_t iv_index,
>> > + const uint8_t network_key[16],
>> > + const uint8_t privacy_key[16])
>> > +{
>> > + uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
>> > + uint8_t network_nonce[13] = { 0x00, 0x00, };
>> > + uint8_t tmp[16];
>> > + uint16_t src;
>> > + int i;
>> > +
>> > + if (packet_len < 14)
>> > + return false;
>> > +
>> > + put_be32(iv_index, privacy_counter + 5);
>> > + memcpy(privacy_counter + 9, packet + 7, 7);
>> > +
>> > + if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
>> > + return false;
>> > +
>> > + memcpy(out, packet, packet_len);
>> > + for (i = 0; i < 6; i++)
>> > + out[1 + i] ^= tmp[i];
>> > +
>> > + src = get_be16(out + 5);
>> > +
>> > + /* Pre-check SRC address for illegal values */
>> > + if (!src || src >= 0x8000)
>> > + return false;
>> > +
>> > + /* Detect Proxy packet by CTL == true && proxy == true */
>> > + if ((out[1] & CTL) && proxy)
>> > + network_nonce[0] = 0x03;
>> > + else
>> > + /* CTL + TTL */
>> > + network_nonce[1] = out[1];
>> > +
>> > + /* Seq Num */
>> > + network_nonce[2] = out[2];
>> > + network_nonce[3] = out[3];
>> > + network_nonce[4] = out[4];
>> > +
>> > + /* SRC */
>> > + network_nonce[5] = out[5];
>> > + network_nonce[6] = out[6];
>> > +
>> > + /* DST not available */
>> > + network_nonce[7] = 0;
>> > + network_nonce[8] = 0;
>> > +
>> > + /* IV Index */
>> > + put_be32(iv_index, network_nonce + 9);
>> > +
>> > + /* Check for Long MIC */
>> > + if (out[1] & CTL) {
>> > + uint64_t mic;
>> > +
>> > + if (!mesh_crypto_aes_ccm_decrypt(network_nonce,
>> network_key,
>> > + NULL, 0, packet + 7, packet_len - 7,
>> > + out + 7, &mic, sizeof(mic)))
>> > + return false;
>> > +
>> > + mic ^= get_be64(out + packet_len - 8);
>> > + put_be64(mic, out + packet_len - 8);
>> > +
>> > + if (mic)
>> > + return false;
>> > + } else {
>> > + uint32_t mic;
>> > +
>> > + if (!mesh_crypto_aes_ccm_decrypt(network_nonce,
>> network_key,
>> > + NULL, 0, packet + 7, packet_len - 7,
>> > + out + 7, &mic, sizeof(mic)))
>> > + return false;
>> > +
>> > + mic ^= get_be32(out + packet_len - 4);
>> > + put_be32(mic, out + packet_len - 4);
>> > +
>> > + if (mic)
>> > + return false;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool mesh_get_random_bytes(void *buf, size_t num_bytes)
>> > +{
>> > + ssize_t len;
>> > + int fd;
>> > +
>> > + fd = open("/dev/urandom", O_RDONLY);
>> > + if (fd < 0)
>> > + return false;
>> > +
>> > + len = read(fd, buf, num_bytes);
>> > +
>> > + close(fd);
>> > +
>> > + if (len < 0)
>> > + return false;
>> > +
>> > + return true;
>> > +}
>> > diff --git a/mesh/gatt.c b/mesh/gatt.c
>> > new file mode 100644
>> > index 0000000..b981054
>> > --- /dev/null
>> > +++ b/mesh/gatt.c
>> > @@ -0,0 +1,609 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <sys/uio.h>
>> > +#include <wordexp.h>
>> > +
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "src/shared/io.h"
>> > +#include "gdbus/gdbus.h"
>> > +#include "lib/bluetooth.h"
>> > +#include "lib/uuid.h"
>> > +#include "client/display.h"
>> > +#include "node.h"
>> > +#include "util.h"
>> > +#include "gatt.h"
>> > +#include "prov.h"
>> > +#include "net.h"
>> > +
>> > +#define MESH_PROV_DATA_OUT_UUID_STR "00002adc-0000-1000-
>> 8000-00805f9b34fb"
>> > +#define MESH_PROXY_DATA_OUT_UUID_STR "00002ade-0000-1000-
>> 8000-00805f9b34fb"
>> > +
>> > +static struct io *write_io;
>> > +static uint16_t write_mtu;
>> > +
>> > +static struct io *notify_io;
>> > +static uint16_t notify_mtu;
>> > +
>> > +struct write_data {
>> > + GDBusProxy *proxy;
>> > + void *user_data;
>> > + struct iovec iov;
>> > + GDBusReturnFunction cb;
>> > + uint8_t *gatt_data;
>> > + uint8_t gatt_len;
>> > +};
>> > +
>> > +struct notify_data {
>> > + GDBusProxy *proxy;
>> > + bool enable;
>> > + GDBusReturnFunction cb;
>> > + void *user_data;
>> > +};
>> > +
>> > +bool mesh_gatt_is_child(GDBusProxy *proxy, GDBusProxy *parent,
>> > + const char *name)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *parent_path;
>> > +
>> > + if (!parent)
>> > + return FALSE;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
>> > + return FALSE;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &parent_path);
>> > +
>> > + if (!strcmp(parent_path, g_dbus_proxy_get_path(parent)))
>> > + return TRUE;
>> > + else
>> > + return FALSE;
>> > +}
>> > +
>> > +/* Refactor this once actual MTU is available */
>> > +#define GATT_MTU 23
>> > +
>> > +static void write_data_free(void *user_data)
>> > +{
>> > + struct write_data *data = user_data;
>> > +
>> > + g_free(data->gatt_data);
>> > + free(data);
>> > +}
>> > +
>> > +static void write_setup(DBusMessageIter *iter, void *user_data)
>> > +{
>> > + struct write_data *data = user_data;
>> > + struct iovec *iov = &data->iov;
>> > + DBusMessageIter array, dict;
>> > +
>> > + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y",
>> &array);
>> > + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
>> > + &iov->iov_base, iov->iov_len);
>> > + dbus_message_iter_close_container(iter, &array);
>> > +
>> > + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
>> > + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
>> > + DBUS_TYPE_STRING_AS_STRING
>> > + DBUS_TYPE_VARIANT_AS_STRING
>> > + DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
>> > + &dict);
>> > +
>> > + dbus_message_iter_close_container(iter, &dict);
>> > +}
>> > +
>> > +uint16_t mesh_gatt_sar(uint8_t **pkt, uint16_t size)
>> > +{
>> > + const uint8_t *data = *pkt;
>> > + uint8_t gatt_hdr = *data++;
>> > + uint8_t type = gatt_hdr & GATT_TYPE_MASK;
>> > + static uint8_t gatt_size;
>> > + static uint8_t gatt_pkt[67];
>> > +
>> > + print_byte_array("GATT-RX:\t", *pkt, size);
>> > + if (size < 1) {
>> > + gatt_pkt[0] = GATT_TYPE_INVALID;
>> > + /* TODO: Disconnect GATT per last paragraph sec 6.6 */
>> > + return 0;
>> > + }
>> > +
>> > + size--;
>> > +
>> > + switch (gatt_hdr & GATT_SAR_MASK) {
>> > + case GATT_SAR_FIRST:
>> > + gatt_size = 1;
>> > + gatt_pkt[0] = type;
>> > + /* TODO: Start Proxy Timeout */
>> > + /* fall through */
>> > +
>> > + case GATT_SAR_CONTINUE:
>> > + if (gatt_pkt[0] != type ||
>> > + gatt_size + size > MAX_GATT_SIZE) {
>> > +
>> > + /* Invalidate packet and return failure */
>> > + gatt_pkt[0] = GATT_TYPE_INVALID;
>> > + /* TODO: Disconnect GATT per last paragraph sec 6.6 */
>> > + return 0;
>> > + }
>> > +
>> > + memcpy(gatt_pkt + gatt_size, data, size);
>> > + gatt_size += size;
>> > +
>> > + /* We are good to this point, but incomplete */
>> > + return 0;
>> > +
>> > + default:
>> > + case GATT_SAR_COMPLETE:
>> > + gatt_size = 1;
>> > + gatt_pkt[0] = type;
>> > +
>> > + /* fall through */
>> > +
>> > + case GATT_SAR_LAST:
>> > + if (gatt_pkt[0] != type ||
>> > + gatt_size + size > MAX_GATT_SIZE) {
>> > +
>> > + /* Invalidate packet and return failure */
>> > + gatt_pkt[0] = GATT_TYPE_INVALID;
>> > + /* Disconnect GATT per last paragraph sec 6.6 */
>> > + return 0;
>> > + }
>> > +
>> > + memcpy(gatt_pkt + gatt_size, data, size);
>> > + gatt_size += size;
>> > + *pkt = gatt_pkt;
>> > + return gatt_size;
>> > + }
>> > +}
>> > +
>> > +static bool pipe_write(struct io *io, void *user_data)
>> > +{
>> > + struct write_data *data = user_data;
>> > + struct iovec iov[2];
>> > + uint8_t sar;
>> > + uint8_t max_len = write_mtu - 4;
>> > +
>> > + if (data == NULL)
>> > + return true;
>> > +
>> > + print_byte_array("GATT-TX:\t", data->gatt_data, data->gatt_len);
>> > +
>> > + sar = data->gatt_data[0];
>> > +
>> > + data->iov.iov_base = data->gatt_data + 1;
>> > + data->iov.iov_len--;
>> > +
>> > + iov[0].iov_base = &sar;
>> > + iov[0].iov_len = sizeof(sar);
>> > +
>> > + while (1) {
>> > + int err;
>> > +
>> > + iov[1] = data->iov;
>> > +
>> > + err = io_send(io, iov, 2);
>> > + if (err < 0) {
>> > + rl_printf("Failed to write: %s\n", strerror(-err));
>> > + write_data_free(data);
>> > + return false;
>> > + }
>> > +
>> > + switch (sar & GATT_SAR_MASK) {
>> > + case GATT_SAR_FIRST:
>> > + case GATT_SAR_CONTINUE:
>> > + data->gatt_len -= max_len;
>> > + data->iov.iov_base = data->iov.iov_base + max_len;
>> > +
>> > + sar &= GATT_TYPE_MASK;
>> > + if (max_len < data->gatt_len) {
>> > + data->iov.iov_len = max_len;
>> > + sar |= GATT_SAR_CONTINUE;
>> > + } else {
>> > + data->iov.iov_len = data->gatt_len;
>> > + sar |= GATT_SAR_LAST;
>> > + }
>> > +
>> > + break;
>> > +
>> > + default:
>> > + if(data->cb)
>> > + data->cb(NULL, data->user_data);
>> > + write_data_free(data);
>> > + return true;
>> > + }
>> > + }
>> > +}
>> > +
>> > +static void write_reply(DBusMessage *message, void *user_data)
>> > +{
>> > + struct write_data *data = user_data;
>> > + struct write_data *tmp;
>> > + uint8_t *dptr = data->gatt_data;
>> > + uint8_t max_len = GATT_MTU - 3;
>> > + uint8_t max_seg = GATT_MTU - 4;
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to write: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + if (data == NULL)
>> > + return;
>> > +
>> > + switch (data->gatt_data[0] & GATT_SAR_MASK) {
>> > + case GATT_SAR_FIRST:
>> > + case GATT_SAR_CONTINUE:
>> > + tmp = g_new0(struct write_data, 1);
>> > + if (!data)
>> > + return;
>> > +
>> > + *tmp = *data;
>> > + tmp->gatt_data = g_malloc(data->gatt_len);
>> > +
>> > + if (!tmp->gatt_data) {
>> > + g_free(tmp);
>> > + return;
>> > + }
>> > +
>> > + tmp->gatt_data[0] = dptr[0];
>> > + data = tmp;
>> > + memcpy(data->gatt_data + 1, dptr + max_len,
>> > + data->gatt_len - max_seg);
>> > + data->gatt_len -= max_seg;
>> > + data->gatt_data[0] &= GATT_TYPE_MASK;
>> > + data->iov.iov_base = data->gatt_data;
>> > + if (max_len < data->gatt_len) {
>> > + data->iov.iov_len = max_len;
>> > + data->gatt_data[0] |= GATT_SAR_CONTINUE;
>> > + } else {
>> > + data->iov.iov_len = data->gatt_len;
>> > + data->gatt_data[0] |= GATT_SAR_LAST;
>> > + }
>> > +
>> > + break;
>> > +
>> > + default:
>> > + if(data->cb)
>> > + data->cb(message, data->user_data);
>> > + return;
>> > + }
>> > +
>> > + if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
>> write_setup,
>> > + write_reply, data, write_data_free) == FALSE) {
>> > + rl_printf("Failed to write\n");
>> > + write_data_free(data);
>> > + return;
>> > + }
>> > +
>> > +}
>> > +
>> > +static void write_io_destroy(void)
>> > +{
>> > + io_destroy(write_io);
>> > + write_io = NULL;
>> > + write_mtu = 0;
>> > +}
>> > +
>> > +static void notify_io_destroy(void)
>> > +{
>> > + io_destroy(notify_io);
>> > + notify_io = NULL;
>> > + notify_mtu = 0;
>> > +}
>> > +
>> > +static bool pipe_hup(struct io *io, void *user_data)
>> > +{
>> > + rl_printf("%s closed\n", io == notify_io ? "Notify" : "Write");
>> > +
>> > + if (io == notify_io)
>> > + notify_io_destroy();
>> > + else
>> > + write_io_destroy();
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static struct io *pipe_io_new(int fd)
>> > +{
>> > + struct io *io;
>> > +
>> > + io = io_new(fd);
>> > +
>> > + io_set_close_on_destroy(io, true);
>> > +
>> > + io_set_disconnect_handler(io, pipe_hup, NULL, NULL);
>> > +
>> > + return io;
>> > +}
>> > +
>> > +static void acquire_write_reply(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + struct write_data *data = user_data;
>> > + DBusError error;
>> > + int fd;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + dbus_error_free(&error);
>> > + if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
>> > + write_setup, write_reply, data,
>> > + write_data_free) == FALSE) {
>> > + rl_printf("Failed to write\n");
>> > + write_data_free(data);
>> > + }
>> > + return;
>> > + }
>> > +
>> > + if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD,
>> &fd,
>> > + DBUS_TYPE_UINT16, &write_mtu,
>> > + DBUS_TYPE_INVALID) == false)) {
>> > + rl_printf("Invalid AcquireWrite response\n");
>> > + return;
>> > + }
>> > +
>> > + rl_printf("AcquireWrite success: fd %d MTU %u\n", fd, write_mtu);
>> > +
>> > + write_io = pipe_io_new(fd);
>> > +
>> > + pipe_write(write_io, data);
>> > +}
>> > +
>> > +bool mesh_gatt_write(GDBusProxy *proxy, uint8_t *buf, uint16_t len,
>> > + GDBusReturnFunction cb, void *user_data)
>> > +{
>> > + struct write_data *data;
>> > + DBusMessageIter iter;
>> > + uint8_t max_len;
>> > +
>> > + if (!buf || !len)
>> > + return false;
>> > +
>> > + if (len > 69)
>> > + return false;
>> > +
>> > + data = g_new0(struct write_data, 1);
>> > + if (!data)
>> > + return false;
>> > +
>> > + max_len = write_mtu ? write_mtu - 3 : GATT_MTU - 3;
>> > +
>> > + /* TODO: should keep in queue in case we need to cancel write? */
>> > +
>> > + data->gatt_len = len;
>> > + data->gatt_data = g_memdup(buf, len);
>> > + data->gatt_data[0] &= GATT_TYPE_MASK;
>> > + if (max_len < len) {
>> > + len = max_len;
>> > + data->gatt_data[0] |= GATT_SAR_FIRST;
>> > + }
>> > + data->iov.iov_base = data->gatt_data;
>> > + data->iov.iov_len = len;
>> > + data->proxy = proxy;
>> > + data->user_data = user_data;
>> > + data->cb = cb;
>> > +
>> > + if (write_io)
>> > + return pipe_write(write_io, data);
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "WriteAcquired", &iter)) {
>> > + if (g_dbus_proxy_method_call(proxy, "AcquireWrite", NULL,
>> > + acquire_write_reply, data, NULL) == FALSE) {
>> > + rl_printf("Failed to AcquireWrite\n");
>> > + write_data_free(data);
>> > + return false;
>> > + }
>> > + } else {
>> > + if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
>> > + write_setup, write_reply, data,
>> > + write_data_free) == FALSE) {
>> > + rl_printf("Failed to write\n");
>> > + write_data_free(data);
>> > + return false;
>> > + }
>> > + print_byte_array("GATT-TX: ", buf, len);
>> > + rl_printf("Attempting to write %s\n",
>> > + g_dbus_proxy_get_path(proxy));
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static void notify_reply(DBusMessage *message, void *user_data)
>> > +{
>> > + struct notify_data *data = user_data;
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to %s notify: %s\n",
>> > + data->enable ? "start" : "stop", error.name);
>> > + dbus_error_free(&error);
>> > + goto done;
>> > + }
>> > +
>> > + rl_printf("Notify %s\n", data->enable ? "started" : "stopped");
>> > +
>> > +done:
>> > + if (data->cb)
>> > + data->cb(message, data->user_data);
>> > +
>> > + g_free(data);
>> > +}
>> > +
>> > +static bool pipe_read(struct io *io, bool prov, void *user_data)
>> > +{
>> > + struct mesh_node *node = user_data;
>> > + uint8_t buf[512];
>> > + uint8_t *res;
>> > + int fd = io_get_fd(io);
>> > + ssize_t len;
>> > +
>> > + if (io != notify_io)
>> > + return true;
>> > +
>> > + while ((len = read(fd, buf, sizeof(buf)))) {
>> > + if (len <= 0)
>> > + break;
>> > +
>> > + res = buf;
>> > + mesh_gatt_sar(&res, len);
>> > +
>> > + if (prov)
>> > + prov_data_ready(node, res, len);
>> > + else
>> > + net_data_ready(res, len);
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool pipe_read_prov(struct io *io, void *user_data)
>> > +{
>> > + return pipe_read(io, true, user_data);
>> > +}
>> > +
>> > +static bool pipe_read_proxy(struct io *io, void *user_data)
>> > +{
>> > + return pipe_read(io, false, user_data);
>> > +}
>> > +
>> > +static void acquire_notify_reply(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + struct notify_data *data = user_data;
>> > + DBusMessageIter iter;
>> > + DBusError error;
>> > + int fd;
>> > + const char *uuid;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + dbus_error_free(&error);
>> > + if (g_dbus_proxy_method_call(data->proxy, "StartNotify", NULL,
>> > + notify_reply, data, NULL) == FALSE) {
>> > + rl_printf("Failed to StartNotify\n");
>> > + g_free(data);
>> > + }
>> > + return;
>> > + }
>> > +
>> > + if (notify_io) {
>> > + io_destroy(notify_io);
>> > + notify_io = NULL;
>> > + }
>> > +
>> > + notify_mtu = 0;
>> > +
>> > + if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD,
>> &fd,
>> > + DBUS_TYPE_UINT16, &notify_mtu,
>> > + DBUS_TYPE_INVALID) == false)) {
>> > + if (g_dbus_proxy_method_call(data->proxy, "StartNotify", NULL,
>> > + notify_reply, data, NULL) == FALSE) {
>> > + rl_printf("Failed to StartNotify\n");
>> > + g_free(data);
>> > + }
>> > + return;
>> > + }
>> > +
>> > + rl_printf("AcquireNotify success: fd %d MTU %u\n", fd, notify_mtu);
>> > +
>> > + if (g_dbus_proxy_get_property(data->proxy, "UUID", &iter) ==
>> FALSE)
>> > + goto done;
>> > +
>> > + notify_io = pipe_io_new(fd);
>> > +
>> > + dbus_message_iter_get_basic(&iter, &uuid);
>> > +
>> > + if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
>> > + io_set_read_handler(notify_io, pipe_read_prov, data-
>> >user_data,
>> > + NULL);
>> > + else if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
>> > + io_set_read_handler(notify_io, pipe_read_proxy, data-
>> >user_data,
>> > + NULL);
>> > +
>> > +done:
>> > + if (data->cb)
>> > + data->cb(message, data->user_data);
>> > +
>> > + g_free(data);
>> > +}
>> > +
>> > +bool mesh_gatt_notify(GDBusProxy *proxy, bool enable,
>> GDBusReturnFunction cb,
>> > + void *user_data)
>> > +{
>> > + struct notify_data *data;
>> > + DBusMessageIter iter;
>> > + const char *method;
>> > +
>> > + data = g_new0(struct notify_data, 1);
>> > + data->proxy = proxy;
>> > + data->enable = enable;
>> > + data->cb = cb;
>> > + data->user_data = user_data;
>> > +
>> > + if (enable == TRUE) {
>> > + if (g_dbus_proxy_get_property(proxy, "NotifyAcquired", &iter)) {
>> > + method = "AcquireNotify";
>> > + cb = acquire_notify_reply;
>> > + } else {
>> > + method = "StartNotify";
>> > + cb = notify_reply;
>> > + }
>> > + } else {
>> > + if (notify_io) {
>> > + notify_io_destroy();
>> > + if (cb)
>> > + cb(NULL, user_data);
>> > + return true;
>> > + } else {
>> > + method = "StopNotify";
>> > + cb = notify_reply;
>> > + }
>> > + }
>> > +
>> > + if (g_dbus_proxy_method_call(proxy, method, NULL, cb,
>> > + data, NULL) == FALSE) {
>> > + rl_printf("Failed to %s\n", method);
>> > + return false;
>> > + }
>> > + return true;
>> > +}
>> > diff --git a/mesh/main.c b/mesh/main.c
>> > new file mode 100644
>> > index 0000000..a347484
>> > --- /dev/null
>> > +++ b/mesh/main.c
>> > @@ -0,0 +1,2269 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <signal.h>
>> > +#include <sys/signalfd.h>
>> > +#include <wordexp.h>
>> > +
>> > +#include <inttypes.h>
>> > +#include <ctype.h>
>> > +#include <sys/file.h>
>> > +#include <sys/ioctl.h>
>> > +#include <sys/stat.h>
>> > +#include "bluetooth/bluetooth.h"
>> > +
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "lib/bluetooth.h"
>> > +#include "lib/uuid.h"
>> > +#include "src/shared/util.h"
>> > +#include "gdbus/gdbus.h"
>> > +#include "monitor/uuid.h"
>> > +#include "client/display.h"
>> > +#include "mesh-net.h"
>> > +#include "gatt.h"
>> > +#include "crypto.h"
>> > +#include "node.h"
>> > +#include "net.h"
>> > +#include "keys.h"
>> > +#include "prov.h"
>> > +#include "util.h"
>> > +#include "agent.h"
>> > +#include "prov-db.h"
>> > +#include "config-model.h"
>> > +#include "onoff-model.h"
>> > +
>> > +/* String display constants */
>> > +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
>> > +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
>> > +#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
>> > +
>> > +#define PROMPT_ON COLOR_BLUE "[meshctl]" COLOR_OFF "# "
>> > +#define PROMPT_OFF "Waiting to connect to bluetoothd..."
>> > +
>> > +#define MESH_PROV_DATA_IN_UUID_STR "00002adb-0000-1000-8000-
>> 00805f9b34fb"
>> > +#define MESH_PROV_DATA_OUT_UUID_STR "00002adc-0000-1000-
>> 8000-00805f9b34fb"
>> > +#define MESH_PROXY_DATA_IN_UUID_STR "00002add-0000-1000-8000-
>> 00805f9b34fb"
>> > +#define MESH_PROXY_DATA_OUT_UUID_STR "00002ade-0000-1000-
>> 8000-00805f9b34fb"
>> > +
>> > +static GMainLoop *main_loop;
>> > +static DBusConnection *dbus_conn;
>> > +
>> > +struct adapter {
>> > +GDBusProxy *proxy;
>> > + GList *mesh_devices;
>> > +};
>> > +
>> > +struct mesh_device {
>> > + GDBusProxy *proxy;
>> > + uint8_t dev_uuid[16];
>> > + gboolean hide;
>> > +};
>> > +
>> > +GList *service_list;
>> > +GList *char_list;
>> > +
>> > +static GList *ctrl_list;
>> > +static struct adapter *default_ctrl;
>> > +
>> > +static char *mesh_prov_db_filename;
>> > +static char *mesh_local_config_filename;
>> > +
>> > +static bool discovering = false;
>> > +static bool discover_mesh;
>> > +static uint16_t prov_net_key_index = NET_IDX_PRIMARY;
>> > +
>> > +static guint input = 0;
>> > +
>> > +#define CONN_TYPE_NETWORK 0x00
>> > +#define CONN_TYPE_IDENTITY 0x01
>> > +#define CONN_TYPE_PROVISION 0x02
>> > +#define CONN_TYPE_INVALID 0xff
>> > +
>> > +#define NET_IDX_INVALID 0xffff
>> > +
>> > +struct {
>> > + GDBusProxy *device;
>> > + GDBusProxy *service;
>> > + GDBusProxy *data_in;
>> > + GDBusProxy *data_out;
>> > + bool session_open;
>> > + uint16_t unicast;
>> > + uint16_t net_idx;
>> > + uint8_t dev_uuid[16];
>> > + uint8_t type;
>> > +} connection;
>> > +
>> > +static bool service_is_mesh(GDBusProxy *proxy, const char *target_uuid)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *uuid;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
>> > + return false;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &uuid);
>> > +
>> > + if (target_uuid)
>> > + return (!bt_uuid_strcmp(uuid, target_uuid));
>> > + else if (bt_uuid_strcmp(uuid, MESH_PROV_SVC_UUID) ||
>> > + bt_uuid_strcmp(uuid, MESH_PROXY_SVC_UUID))
>> > + return true;
>> > + else
>> > + return false;
>> > +}
>> > +
>> > +static bool char_is_mesh(GDBusProxy *proxy, const char *target_uuid)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *uuid;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
>> > + return false;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &uuid);
>> > +
>> > + if (target_uuid)
>> > + return (!bt_uuid_strcmp(uuid, target_uuid));
>> > +
>> > + if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_IN_UUID_STR))
>> > + return true;
>> > +
>> > + if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
>> > + return true;
>> > +
>> > + if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_IN_UUID_STR))
>> > + return true;
>> > +
>> > + if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
>> > + return true;
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static gboolean check_default_ctrl(void)
>> > +{
>> > + if (!default_ctrl) {
>> > + rl_printf("No default controller available\n");
>> > + return FALSE;
>> > + }
>> > +
>> > + return TRUE;
>> > +}
>> > +
>> > +static void proxy_leak(gpointer data)
>> > +{
>> > + rl_printf("Leaking proxy %p\n", data);
>> > +}
>> > +
>> > +static gboolean input_handler(GIOChannel *channel, GIOCondition
>> condition,
>> > + gpointer user_data)
>> > +{
>> > + if (condition & G_IO_IN) {
>> > + rl_callback_read_char();
>> > + return TRUE;
>> > + }
>> > +
>> > + if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
>> > + g_main_loop_quit(main_loop);
>> > + return FALSE;
>> > + }
>> > +
>> > + return TRUE;
>> > +}
>> > +
>> > +static guint setup_standard_input(void)
>> > +{
>> > + GIOChannel *channel;
>> > + guint source;
>> > +
>> > + channel = g_io_channel_unix_new(fileno(stdin));
>> > +
>> > + source = g_io_add_watch(channel,
>> > + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
>> > + input_handler, NULL);
>> > +
>> > + g_io_channel_unref(channel);
>> > +
>> > + return source;
>> > +}
>> > +
>> > +static void connect_handler(DBusConnection *connection, void
>> *user_data)
>> > +{
>> > + rl_set_prompt(PROMPT_ON);
>> > + rl_printf("\r");
>> > + rl_on_new_line();
>> > + rl_redisplay();
>> > +}
>> > +
>> > +static void disconnect_handler(DBusConnection *connection, void
>> *user_data)
>> > +{
>> > + if (input > 0) {
>> > + g_source_remove(input);
>> > + input = 0;
>> > + }
>> > +
>> > + rl_set_prompt(PROMPT_OFF);
>> > + rl_printf("\r");
>> > + rl_on_new_line();
>> > + rl_redisplay();
>> > +
>> > + g_list_free_full(ctrl_list, proxy_leak);
>> > + ctrl_list = NULL;
>> > +
>> > + default_ctrl = NULL;
>> > +}
>> > +
>> > +static void print_adapter(GDBusProxy *proxy, const char *description)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *address, *name;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
>> > + return;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &address);
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
>> > + dbus_message_iter_get_basic(&iter, &name);
>> > + else
>> > + name = "<unknown>";
>> > +
>> > + rl_printf("%s%s%sController %s %s %s\n",
>> > + description ? "[" : "",
>> > + description ? : "",
>> > + description ? "] " : "",
>> > + address, name,
>> > + default_ctrl &&
>> > + default_ctrl->proxy == proxy ?
>> > + "[default]" : "");
>> > +
>> > +}
>> > +
>> > +static void print_device(GDBusProxy *proxy, const char *description)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *address, *name;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
>> > + return;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &address);
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
>> > + dbus_message_iter_get_basic(&iter, &name);
>> > + else
>> > + name = "<unknown>";
>> > +
>> > + rl_printf("%s%s%sDevice %s %s\n",
>> > + description ? "[" : "",
>> > + description ? : "",
>> > + description ? "] " : "",
>> > + address, name);
>> > +}
>> > +
>> > +static void print_iter(const char *label, const char *name,
>> > + DBusMessageIter *iter)
>> > +{
>> > + dbus_bool_t valbool;
>> > + dbus_uint32_t valu32;
>> > + dbus_uint16_t valu16;
>> > + dbus_int16_t vals16;
>> > + unsigned char byte;
>> > + const char *valstr;
>> > + DBusMessageIter subiter;
>> > + char *entry;
>> > +
>> > + if (iter == NULL) {
>> > + rl_printf("%s%s is nil\n", label, name);
>> > + return;
>> > + }
>> > +
>> > + switch (dbus_message_iter_get_arg_type(iter)) {
>> > + case DBUS_TYPE_INVALID:
>> > + rl_printf("%s%s is invalid\n", label, name);
>> > + break;
>> > + case DBUS_TYPE_STRING:
>> > + case DBUS_TYPE_OBJECT_PATH:
>> > + dbus_message_iter_get_basic(iter, &valstr);
>> > + rl_printf("%s%s: %s\n", label, name, valstr);
>> > + break;
>> > + case DBUS_TYPE_BOOLEAN:
>> > + dbus_message_iter_get_basic(iter, &valbool);
>> > + rl_printf("%s%s: %s\n", label, name,
>> > + valbool == TRUE ? "yes" : "no");
>> > + break;
>> > + case DBUS_TYPE_UINT32:
>> > + dbus_message_iter_get_basic(iter, &valu32);
>> > + rl_printf("%s%s: 0x%06x\n", label, name, valu32);
>> > + break;
>> > + case DBUS_TYPE_UINT16:
>> > + dbus_message_iter_get_basic(iter, &valu16);
>> > + rl_printf("%s%s: 0x%04x\n", label, name, valu16);
>> > + break;
>> > + case DBUS_TYPE_INT16:
>> > + dbus_message_iter_get_basic(iter, &vals16);
>> > + rl_printf("%s%s: %d\n", label, name, vals16);
>> > + break;
>> > + case DBUS_TYPE_BYTE:
>> > + dbus_message_iter_get_basic(iter, &byte);
>> > + rl_printf("%s%s: 0x%02x\n", label, name, byte);
>> > + break;
>> > + case DBUS_TYPE_VARIANT:
>> > + dbus_message_iter_recurse(iter, &subiter);
>> > + print_iter(label, name, &subiter);
>> > + break;
>> > + case DBUS_TYPE_ARRAY:
>> > + dbus_message_iter_recurse(iter, &subiter);
>> > + while (dbus_message_iter_get_arg_type(&subiter) !=
>> > + DBUS_TYPE_INVALID) {
>> > + print_iter(label, name, &subiter);
>> > + dbus_message_iter_next(&subiter);
>> > + }
>> > + break;
>> > + case DBUS_TYPE_DICT_ENTRY:
>> > + dbus_message_iter_recurse(iter, &subiter);
>> > + entry = g_strconcat(name, "Key", NULL);
>> > + print_iter(label, entry, &subiter);
>> > + g_free(entry);
>> > +
>> > + entry = g_strconcat(name, " Value", NULL);
>> > + dbus_message_iter_next(&subiter);
>> > + print_iter(label, entry, &subiter);
>> > + g_free(entry);
>> > + break;
>> > + default:
>> > + rl_printf("%s%s has unsupported type\n", label, name);
>> > + break;
>> > + }
>> > +}
>> > +
>> > +static void print_property(GDBusProxy *proxy, const char *name)
>> > +{
>> > + DBusMessageIter iter;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
>> > + return;
>> > +
>> > + print_iter("\t", name, &iter);
>> > +}
>> > +
>> > +static void forget_mesh_devices()
>> > +{
>> > + g_list_free_full(default_ctrl->mesh_devices, g_free);
>> > + default_ctrl->mesh_devices = NULL;
>> > +}
>> > +
>> > +static struct mesh_device *find_device_by_uuid(GList *source, uint8_t
>> uuid[16])
>> > +{
>> > + GList *list;
>> > +
>> > + for (list = g_list_first(source); list; list = g_list_next(list)) {
>> > + struct mesh_device *dev = list->data;
>> > +
>> > + if (!memcmp(dev->dev_uuid, uuid, 16))
>> > + return dev;
>> > + }
>> > +
>> > + return NULL;
>> > +}
>> > +
>> > +static void print_prov_service(struct prov_svc_data *prov_data)
>> > +{
>> > + const char *prefix = "\t\t";
>> > + char txt_uuid[16 * 2 + 1];
>> > + int i;
>> > +
>> > + rl_printf("%sMesh Provisioning Service (%s)\n", prefix,
>> > + MESH_PROV_SVC_UUID);
>> > + for (i = 0; i < 16; ++i) {
>> > + sprintf(txt_uuid + (i * 2), "%2.2x", prov_data->dev_uuid[i]);
>> > + }
>> > +
>> > + rl_printf("%s\tDevice UUID: %s\n", prefix, txt_uuid);
>> > + rl_printf("%s\tOOB: %4.4x\n", prefix, prov_data->oob);
>> > +
>> > +}
>> > +
>> > +static bool parse_prov_service_data(const char *uuid, uint8_t *data, int
>> len,
>> > + void *data_out)
>> > +{
>> > + struct prov_svc_data *prov_data = data_out;
>> > + int i;
>> > +
>> > + if (len < 18)
>> > + return false;
>> > +
>> > + for (i = 0; i < 16; ++i) {
>> > + prov_data->dev_uuid[i] = data[i];
>> > + }
>> > +
>> > + prov_data->oob = get_be16(&data[16]);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_mesh_service_data(const char *uuid, uint8_t *data, int
>> len,
>> > + void *data_out)
>> > +{
>> > + const char *prefix = "\t\t";
>> > +
>> > + if (!(len == 9 && data[0] == 0x00) && !(len == 17 && data[0] == 0x01)) {
>> > + rl_printf("Unexpected mesh proxy service data length %d\n",
>> > + len);
>> > + return false;
>> > + }
>> > +
>> > + if (data[0] != connection.type)
>> > + return false;
>> > +
>> > + if (data[0] == CONN_TYPE_IDENTITY) {
>> > + uint8_t *key;
>> > +
>> > + if (IS_UNASSIGNED(connection.unicast)) {
>> > + /* This would be a bug */
>> > + rl_printf("Error: Searching identity with "
>> > + "unicast 0000\n");
>> > + return false;
>> > + }
>> > +
>> > + key = keys_net_key_get(prov_net_key_index, true);
>> > + if (!key)
>> > + return false;
>> > +
>> > + if (!mesh_crypto_identity_check(key, connection.unicast,
>> > + &data[1]))
>> > + return false;
>> > +
>> > + if (discovering) {
>> > + rl_printf("\n%sMesh Proxy Service (%s)\n", prefix,
>> > + uuid);
>> > + rl_printf("%sIdentity for node %4.4x\n", prefix,
>> > + connection.unicast);
>> > + }
>> > +
>> > + } else if (data[0] == CONN_TYPE_NETWORK) {
>> > + uint16_t net_idx = net_validate_proxy_beacon(data + 1);
>> > +
>> > + if (net_idx == NET_IDX_INVALID || net_idx !=
>> connection.net_idx)
>> > + return false;
>> > +
>> > + if (discovering) {
>> > + rl_printf("\n%sMesh Proxy Service (%s)\n", prefix,
>> > + uuid);
>> > + rl_printf("%sNetwork Beacon for net index %4.4x\n",
>> > + prefix, net_idx);
>> > + }
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_service_data(GDBusProxy *proxy, const char
>> *target_uuid,
>> > + void *data_out)
>> > +{
>> > + DBusMessageIter iter, entries;
>> > + bool mesh_prov = false;
>> > + bool mesh_proxy = false;
>> > +
>> > + if (target_uuid) {
>> > + mesh_prov = !strcmp(target_uuid, MESH_PROV_SVC_UUID);
>> > + mesh_proxy = !strcmp(target_uuid, MESH_PROXY_SVC_UUID);
>> > + }
>> > +
>> > + if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
>> > + return true;
>> > +
>> > + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
>> > + return false;
>> > +
>> > + dbus_message_iter_recurse(&iter, &entries);
>> > +
>> > + while (dbus_message_iter_get_arg_type(&entries)
>> > + == DBUS_TYPE_DICT_ENTRY) {
>> > + DBusMessageIter value, entry, array;
>> > + const char *uuid_str;
>> > + bt_uuid_t uuid;
>> > + uint8_t *service_data;
>> > + int len;
>> > +
>> > + dbus_message_iter_recurse(&entries, &entry);
>> > + dbus_message_iter_get_basic(&entry, &uuid_str);
>> > +
>> > + if (bt_string_to_uuid(&uuid, uuid_str) < 0)
>> > + goto fail;
>> > +
>> > + dbus_message_iter_next(&entry);
>> > +
>> > + if (dbus_message_iter_get_arg_type(&entry) !=
>> DBUS_TYPE_VARIANT)
>> > + goto fail;
>> > +
>> > + dbus_message_iter_recurse(&entry, &value);
>> > +
>> > + if (dbus_message_iter_get_arg_type(&value) !=
>> DBUS_TYPE_ARRAY)
>> > + goto fail;
>> > +
>> > + dbus_message_iter_recurse(&value, &array);
>> > +
>> > + if (dbus_message_iter_get_arg_type(&array) !=
>> DBUS_TYPE_BYTE)
>> > + goto fail;
>> > +
>> > + dbus_message_iter_get_fixed_array(&array, &service_data,
>> &len);
>> > +
>> > + if (mesh_prov && !strcmp(uuid_str, MESH_PROV_SVC_UUID)) {
>> > + return parse_prov_service_data(uuid_str, service_data,
>> > + len, data_out);
>> > + } else if (mesh_proxy &&
>> > + !strcmp(uuid_str, MESH_PROXY_SVC_UUID)) {
>> > + return parse_mesh_service_data(uuid_str, service_data,
>> > + len, data_out);
>> > + }
>> > +
>> > + dbus_message_iter_next(&entries);
>> > + }
>> > +
>> > + if (!target_uuid)
>> > + return true;
>> > +fail:
>> > + return false;
>> > +}
>> > +
>> > +static void print_uuids(GDBusProxy *proxy)
>> > +{
>> > + DBusMessageIter iter, value;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
>> > + return;
>> > +
>> > + dbus_message_iter_recurse(&iter, &value);
>> > +
>> > + while (dbus_message_iter_get_arg_type(&value) ==
>> DBUS_TYPE_STRING) {
>> > + const char *uuid, *text;
>> > +
>> > + dbus_message_iter_get_basic(&value, &uuid);
>> > +
>> > + text = uuidstr_to_str(uuid);
>> > + if (text) {
>> > + char str[26];
>> > + unsigned int n;
>> > +
>> > + str[sizeof(str) - 1] = '\0';
>> > +
>> > + n = snprintf(str, sizeof(str), "%s", text);
>> > + if (n > sizeof(str) - 1) {
>> > + str[sizeof(str) - 2] = '.';
>> > + str[sizeof(str) - 3] = '.';
>> > + if (str[sizeof(str) - 4] == ' ')
>> > + str[sizeof(str) - 4] = '.';
>> > +
>> > + n = sizeof(str) - 1;
>> > + }
>> > +
>> > + rl_printf("\tUUID: %s%*c(%s)\n",
>> > + str, 26 - n, ' ', uuid);
>> > + } else
>> > + rl_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
>> > +
>> > + dbus_message_iter_next(&value);
>> > + }
>> > +}
>> > +
>> > +static gboolean device_is_child(GDBusProxy *device, GDBusProxy
>> *master)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *adapter, *path;
>> > +
>> > + if (!master)
>> > + return FALSE;
>> > +
>> > + if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
>> > + return FALSE;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &adapter);
>> > + path = g_dbus_proxy_get_path(master);
>> > +
>> > + if (!strcmp(path, adapter))
>> > + return TRUE;
>> > +
>> > + return FALSE;
>> > +}
>> > +
>> > +static struct adapter *find_parent(GDBusProxy *device)
>> > +{
>> > + GList *list;
>> > +
>> > + for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
>> > + struct adapter *adapter = list->data;
>> > +
>> > + if (device_is_child(device, adapter->proxy) == TRUE)
>> > + return adapter;
>> > + }
>> > + return NULL;
>> > +}
>> > +
>> > +static void set_connected_device(GDBusProxy *proxy)
>> > +{
>> > + char *desc = NULL;
>> > + DBusMessageIter iter;
>> > + char buf[10];
>> > + bool mesh;
>> > +
>> > + connection.device = proxy;
>> > +
>> > + if (proxy == NULL) {
>> > + memset(&connection, 0, sizeof(connection));
>> > + connection.type = CONN_TYPE_INVALID;
>> > + goto done;
>> > + }
>> > +
>> > + if (connection.type == CONN_TYPE_IDENTITY) {
>> > + mesh = true;
>> > + snprintf(buf, 10, "Node-%4.4x", connection.unicast);
>> > + } else if (connection.type == CONN_TYPE_NETWORK) {
>> > + mesh = true;
>> > + snprintf(buf, 9, "Net-%4.4x", connection.net_idx);
>> > + } else {
>> > + mesh = false;
>> > + }
>> > +
>> > + if (!g_dbus_proxy_get_property(proxy, "Alias", &iter) && !mesh)
>> > + goto done;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &desc);
>> > + desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ",
>> desc,
>> > + (desc && mesh) ? "-" : "",
>> > + mesh ? buf : "");
>> > +
>> > +done:
>> > + rl_set_prompt(desc ? desc : PROMPT_ON);
>> > + rl_printf("\r");
>> > + rl_on_new_line();
>> > + g_free(desc);
>> > +
>> > + /* If disconnected, return to main menu */
>> > + if (proxy == NULL)
>> > + cmd_menu_main(true);
>> > +}
>> > +
>> > +static void connect_reply(DBusMessage *message, void *user_data)
>> > +{
>> > + GDBusProxy *proxy = user_data;
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to connect: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + set_connected_device(NULL);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Connection successful\n");
>> > +
>> > + set_connected_device(proxy);
>> > +}
>> > +
>> > +static void update_device_info(GDBusProxy *proxy)
>> > +{
>> > + struct adapter *adapter = find_parent(proxy);
>> > + DBusMessageIter iter;
>> > + struct prov_svc_data prov_data;
>> > +
>> > + if (!adapter) {
>> > + /* TODO: Error */
>> > + return;
>> > + }
>> > +
>> > + if (adapter != default_ctrl)
>> > + return;
>> > +
>> > + if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
>> > + return;
>> > +
>> > + if (parse_service_data(proxy, MESH_PROV_SVC_UUID, &prov_data))
>> {
>> > + struct mesh_device *dev;
>> > +
>> > + dev = find_device_by_uuid(adapter->mesh_devices,
>> > + prov_data.dev_uuid);
>> > +
>> > + /* Display provisioning service once per sicovery session */
>> > + if (discovering && (!dev || !dev->hide))
>> > + print_prov_service(&prov_data);
>> > +
>> > + if (dev) {
>> > + dev->proxy = proxy;
>> > + dev->hide = discovering;
>> > + return;
>> > + }
>> > +
>> > + dev = g_malloc0(sizeof(struct mesh_device));
>> > + if (!dev)
>> > + return;
>> > +
>> > + dev->proxy = proxy;
>> > + dev->hide = discovering;
>> > +
>> > + memcpy(dev->dev_uuid, prov_data.dev_uuid, 16);
>> > +
>> > + adapter->mesh_devices = g_list_append(adapter-
>> >mesh_devices,
>> > + dev);
>> > + print_device(proxy, COLORED_NEW);
>> > +
>> > + node_create_new(&prov_data);
>> > +
>> > + } else if (parse_service_data(proxy, MESH_PROXY_SVC_UUID, NULL)
>> &&
>> > + discover_mesh) {
>> > + bool res;
>> > +
>> > + g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
>> > + NULL, NULL, NULL, NULL);
>> > + discover_mesh = false;
>> > +
>> > + forget_mesh_devices();
>> > +
>> > + res = g_dbus_proxy_method_call(proxy, "Connect", NULL,
>> > + connect_reply, proxy, NULL);
>> > +
>> > + if (!res)
>> > + rl_printf("Failed to connect to mesh\n");
>> > +
>> > + else
>> > + rl_printf("Trying to connect to mesh\n");
>> > +
>> > + }
>> > +}
>> > +
>> > +static void adapter_added(GDBusProxy *proxy)
>> > +{
>> > + struct adapter *adapter = g_malloc0(sizeof(struct adapter));
>> > +
>> > + adapter->proxy = proxy;
>> > + ctrl_list = g_list_append(ctrl_list, adapter);
>> > +
>> > + if (!default_ctrl)
>> > + default_ctrl = adapter;
>> > +
>> > + print_adapter(proxy, COLORED_NEW);
>> > +}
>> > +
>> > +static void data_out_notify(GDBusProxy *proxy, bool enable,
>> > + GDBusReturnFunction cb)
>> > +{
>> > + struct mesh_node *node;
>> > +
>> > + node = node_find_by_uuid(connection.dev_uuid);
>> > +
>> > + if (!mesh_gatt_notify(proxy, enable, cb, node))
>> > + rl_printf("Failed to %s notification on %s\n", enable ?
>> > + "start" : "stop", g_dbus_proxy_get_path(proxy));
>> > + else
>> > + rl_printf("%s notification on %s\n", enable ?
>> > + "Start" : "Stop", g_dbus_proxy_get_path(proxy));
>> > +}
>> > +
>> > +struct disconnect_data {
>> > + GDBusReturnFunction cb;
>> > + void *data;
>> > +};
>> > +
>> > +static void disconnect(GDBusReturnFunction cb, void *user_data)
>> > +{
>> > + GDBusProxy *proxy;
>> > + DBusMessageIter iter;
>> > + const char *addr;
>> > +
>> > + proxy = connection.device;
>> > + if (!proxy)
>> > + return;
>> > +
>> > + if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, cb,
>> user_data,
>> > + NULL) == FALSE) {
>> > + rl_printf("Failed to disconnect\n");
>> > + return;
>> > + }
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
>> > + dbus_message_iter_get_basic(&iter, &addr);
>> > +
>> > + rl_printf("Attempting to disconnect from %s\n", addr);
>> > +}
>> > +
>> > +static void disc_notify_cb(DBusMessage *message, void *user_data)
>> > +{
>> > + struct disconnect_data *disc_data = user_data;
>> > +
>> > + disconnect(disc_data->cb, disc_data->data);
>> > +
>> > + g_free(user_data);
>> > +}
>> > +
>> > +static void disconnect_device(GDBusReturnFunction cb, void *user_data)
>> > +{
>> > + DBusMessageIter iter;
>> > +
>> > + net_session_close(connection.data_in);
>> > +
>> > + /* Stop notificiation on prov_out or proxy out characteristics */
>> > + if (connection.data_out) {
>> > + if (g_dbus_proxy_get_property(connection.data_out, "Notifying",
>> > + &iter) == TRUE) {
>> > + struct disconnect_data *disc_data;
>> > + disc_data = g_malloc(sizeof(struct disconnect_data));
>> > + disc_data->cb = cb;
>> > + disc_data->data = user_data;
>> > +
>> > + if (mesh_gatt_notify(connection.data_out, false,
>> > + disc_notify_cb, disc_data))
>> > + return;
>> > + }
>> > + }
>> > +
>> > + disconnect(cb, user_data);
>> > +}
>> > +
>> > +static void mesh_prov_done(void *user_data, int status);
>> > +
>> > +static void notify_prov_out_cb(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + struct mesh_node *node = user_data;
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to start notify: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Notify for Mesh Provisioning Out Data started\n");
>> > +
>> > + if (connection.type != CONN_TYPE_PROVISION) {
>> > + rl_printf("Error: wrong connection type %d (expected %d)\n",
>> > + connection.type, CONN_TYPE_PROVISION);
>> > + return;
>> > + }
>> > +
>> > + if (!connection.data_in) {
>> > + rl_printf("Error: don't have mesh provisioning data in\n");
>> > + return;
>> > + }
>> > +
>> > + if (!node) {
>> > + rl_printf("Error: provisioning node not present\n");
>> > + return;
>> > + }
>> > +
>> > + if(!prov_open(node, connection.data_in, prov_net_key_index,
>> > + mesh_prov_done, node))
>> > + {
>> > + rl_printf("Failed to start provisioning\n");
>> > + node_free(node);
>> > + disconnect_device(NULL, NULL);
>> > + } else
>> > + rl_printf("Initiated provisioning\n");
>> > +
>> > +}
>> > +
>> > +static void session_open_cb (int status)
>> > +{
>> > + if (status) {
>> > + rl_printf("Failed to open Mesh session\n");
>> > + disconnect_device(NULL, NULL);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Mesh session is open\n");
>> > +
>> > + /* Get composition data for a newly provisioned node */
>> > + if (connection.type == CONN_TYPE_IDENTITY)
>> > + config_client_get_composition(connection.unicast);
>> > +}
>> > +
>> > +static void notify_proxy_out_cb(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to start notify: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Notify for Mesh Proxy Out Data started\n");
>> > +
>> > + if (connection.type != CONN_TYPE_IDENTITY &&
>> > + connection.type != CONN_TYPE_NETWORK) {
>> > + rl_printf("Error: wrong connection type %d "
>> > + "(expected %d or %d)\n", connection.type,
>> > + CONN_TYPE_IDENTITY, CONN_TYPE_NETWORK);
>> > + return;
>> > + }
>> > +
>> > + if (!connection.data_in) {
>> > + rl_printf("Error: don't have mesh proxy data in\n");
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Trying to open mesh session\n");
>> > + net_session_open(connection.data_in, true, session_open_cb);
>> > + connection.session_open = true;
>> > +}
>> > +
>> > +static GDBusProxy *get_characteristic(GDBusProxy *device, const char
>> *char_uuid)
>> > +{
>> > + GList *l;
>> > + GDBusProxy *service;
>> > + const char *svc_uuid;
>> > +
>> > + if (connection.type == CONN_TYPE_PROVISION) {
>> > + svc_uuid = MESH_PROV_SVC_UUID;
>> > + } else {
>> > + svc_uuid = MESH_PROXY_SVC_UUID;
>> > + }
>> > + for (l = service_list; l; l = l->next) {
>> > + if (mesh_gatt_is_child(l->data, device, "Device") &&
>> > + service_is_mesh(l->data, svc_uuid))
>> > + break;
>> > + }
>> > +
>> > + if (l)
>> > + service = l->data;
>> > + else {
>> > + rl_printf("Mesh service not found\n");
>> > + return NULL;
>> > + }
>> > +
>> > + for (l = char_list; l; l = l->next) {
>> > + if (mesh_gatt_is_child(l->data, service, "Service") &&
>> > + char_is_mesh(l->data, char_uuid)) {
>> > + rl_printf("Found matching char: path %s, uuid %s\n",
>> > + g_dbus_proxy_get_path(l->data), char_uuid);
>> > + return l->data;
>> > + }
>> > + }
>> > + return NULL;
>> > +}
>> > +
>> > +static void mesh_session_setup(GDBusProxy *proxy)
>> > +{
>> > + if (connection.type == CONN_TYPE_PROVISION) {
>> > + connection.data_in = get_characteristic(proxy,
>> > + MESH_PROV_DATA_IN_UUID_STR);
>> > + if (!connection.data_in)
>> > + goto fail;
>> > +
>> > + connection.data_out = get_characteristic(proxy,
>> > + MESH_PROV_DATA_OUT_UUID_STR);
>> > + if (!connection.data_out)
>> > + goto fail;
>> > +
>> > + data_out_notify(connection.data_out, true, notify_prov_out_cb);
>> > +
>> > + } else if (connection.type != CONN_TYPE_INVALID){
>> > +
>> > + connection.data_in = get_characteristic(proxy,
>> > + MESH_PROXY_DATA_IN_UUID_STR);
>> > + if (!connection.data_in)
>> > + goto fail;
>> > +
>> > + connection.data_out = get_characteristic(proxy,
>> > + MESH_PROXY_DATA_OUT_UUID_STR);
>> > + if (!connection.data_out)
>> > + goto fail;
>> > +
>> > + data_out_notify(connection.data_out, true,
>> notify_proxy_out_cb);
>> > + }
>> > +
>> > + return;
>> > +
>> > +fail:
>> > +
>> > + rl_printf("Services resolved, mesh characteristics not found\n");
>> > +}
>> > +
>> > +static void proxy_added(GDBusProxy *proxy, void *user_data)
>> > +{
>> > + const char *interface;
>> > +
>> > + interface = g_dbus_proxy_get_interface(proxy);
>> > +
>> > + if (!strcmp(interface, "org.bluez.Device1")) {
>> > + update_device_info(proxy);
>> > +
>> > + } else if (!strcmp(interface, "org.bluez.Adapter1")) {
>> > +
>> > + adapter_added(proxy);
>> > +
>> > + } else if (!strcmp(interface, "org.bluez.GattService1") &&
>> > + service_is_mesh(proxy, NULL)) {
>> > +
>> > + rl_printf("Service added %s\n", g_dbus_proxy_get_path(proxy));
>> > + service_list = g_list_append(service_list, proxy);
>> > +
>> > + } else if (!strcmp(interface, "org.bluez.GattCharacteristic1") &&
>> > + char_is_mesh(proxy, NULL)) {
>> > +
>> > + rl_printf("Char added %s:\n", g_dbus_proxy_get_path(proxy));
>> > +
>> > + char_list = g_list_append(char_list, proxy);
>> > + }
>> > +}
>> > +
>> > +static void start_discovery_reply(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to %s discovery: %s\n",
>> > + enable == TRUE ? "start" : "stop", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
>> > +}
>> > +
>> > +static struct mesh_device *find_device_by_proxy(GList *source,
>> > + GDBusProxy *proxy)
>> > +{
>> > + GList *list;
>> > +
>> > + for (list = g_list_first(source); list; list = g_list_next(list)) {
>> > + struct mesh_device *dev = list->data;
>> > + GDBusProxy *proxy = dev->proxy;
>> > +
>> > + if (dev->proxy == proxy)
>> > + return dev;
>> > + }
>> > +
>> > + return NULL;
>> > +}
>> > +
>> > +static void device_removed(GDBusProxy *proxy)
>> > +{
>> > + struct adapter *adapter = find_parent(proxy);
>> > + struct mesh_device *dev;
>> > +
>> > + if (!adapter) {
>> > + /* TODO: Error */
>> > + return;
>> > + }
>> > +
>> > + dev = find_device_by_proxy(adapter->mesh_devices, proxy);
>> > + if (dev)
>> > + adapter->mesh_devices = g_list_remove(adapter-
>> >mesh_devices,
>> > + dev);
>> > +
>> > + print_device(proxy, COLORED_DEL);
>> > +
>> > + if (connection.device == proxy)
>> > + set_connected_device(NULL);
>> > +
>> > +}
>> > +
>> > +static void adapter_removed(GDBusProxy *proxy)
>> > +{
>> > + GList *ll;
>> > + for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll)) {
>> > + struct adapter *adapter = ll->data;
>> > +
>> > + if (adapter->proxy == proxy) {
>> > + print_adapter(proxy, COLORED_DEL);
>> > +
>> > + if (default_ctrl && default_ctrl->proxy == proxy) {
>> > + default_ctrl = NULL;
>> > + set_connected_device(NULL);
>> > + }
>> > +
>> > + ctrl_list = g_list_remove_link(ctrl_list, ll);
>> > +
>> > + g_list_free_full(adapter->mesh_devices, g_free);
>> > + g_free(adapter);
>> > + g_list_free(ll);
>> > + return;
>> > + }
>> > + }
>> > +}
>> > +
>> > +static void proxy_removed(GDBusProxy *proxy, void *user_data)
>> > +{
>> > + const char *interface;
>> > +
>> > + interface = g_dbus_proxy_get_interface(proxy);
>> > +
>> > + if (!strcmp(interface, "org.bluez.Device1")) {
>> > + device_removed(proxy);
>> > + } else if (!strcmp(interface, "org.bluez.Adapter1")) {
>> > + adapter_removed(proxy);
>> > + } else if (!strcmp(interface, "org.bluez.GattService1")) {
>> > + if (proxy == connection.service) {
>> > + if (service_is_mesh(proxy, MESH_PROXY_SVC_UUID)) {
>> > + data_out_notify(connection.data_out,
>> > + false, NULL);
>> > + net_session_close(connection.data_in);
>> > + }
>> > + connection.service = NULL;
>> > + connection.data_in = NULL;
>> > + connection.data_out = NULL;
>> > + }
>> > +
>> > + service_list = g_list_remove(service_list, proxy);
>> > +
>> > + } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
>> > + char_list = g_list_remove(char_list, proxy);
>> > + }
>> > +}
>> > +
>> > +static int get_characteristic_value(DBusMessageIter *value, uint8_t *buf)
>> > +{
>> > + DBusMessageIter array;
>> > + uint8_t *data;
>> > + int len;
>> > +
>> > + if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
>> > + return 0;
>> > +
>> > + dbus_message_iter_recurse(value, &array);
>> > +
>> > + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
>> > + return 0;
>> > +
>> > + dbus_message_iter_get_fixed_array(&array, &data, &len);
>> > + memcpy(buf, data, len);
>> > +
>> > + return len;
>> > +}
>> > +
>> > +static bool process_mesh_characteristic(GDBusProxy *proxy)
>> > +{
>> > + DBusMessageIter iter;
>> > + const char *uuid;
>> > + uint8_t *res;
>> > + uint8_t buf[256];
>> > + bool is_prov;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
>> > + return false;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &uuid);
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Value", &iter) == FALSE)
>> > + return false;
>> > +
>> > + is_prov = !bt_uuid_strcmp(uuid,
>> MESH_PROV_DATA_OUT_UUID_STR);
>> > +
>> > + if (is_prov || !bt_uuid_strcmp(uuid,
>> MESH_PROXY_DATA_OUT_UUID_STR))
>> > + {
>> > + struct mesh_node *node;
>> > + uint16_t len;
>> > +
>> > + len = get_characteristic_value(&iter, buf);
>> > +
>> > + if (!len || len > 69)
>> > + return false;
>> > +
>> > + res = buf;
>> > + len = mesh_gatt_sar(&res, len);
>> > +
>> > + if (!len)
>> > + return false;
>> > +
>> > + if (is_prov) {
>> > + node = node_find_by_uuid(connection.dev_uuid);
>> > +
>> > + if (!node) {
>> > + rl_printf("Node not found?\n");
>> > + return false;
>> > + }
>> > +
>> > + return prov_data_ready(node, res, len);
>> > + }
>> > +
>> > + return net_data_ready(res, len);
>> > + }
>> > +
>> > + return false;
>> > +}
>> > +
>> > +
>> > +static void property_changed(GDBusProxy *proxy, const char *name,
>> > + DBusMessageIter *iter, void *user_data)
>> > +{
>> > + const char *interface;
>> > +
>> > + interface = g_dbus_proxy_get_interface(proxy);
>> > +
>> > + if (!strcmp(interface, "org.bluez.Device1")) {
>> > +
>> > + if (default_ctrl && device_is_child(proxy,
>> > + default_ctrl->proxy) == TRUE) {
>> > +
>> > + if (strcmp(name, "Connected") == 0) {
>> > + dbus_bool_t connected;
>> > + dbus_message_iter_get_basic(iter, &connected);
>> > +
>> > + if (connected && connection.device == NULL)
>> > + set_connected_device(proxy);
>> > + else if (!connected &&
>> > + connection.device == proxy)
>> > + set_connected_device(NULL);
>> > + } else if ((strcmp(name, "Alias") == 0) &&
>> > + connection.device == proxy) {
>> > + /* Re-generate prompt */
>> > + set_connected_device(proxy);
>> > + } else if (!strcmp(name, "ServiceData")) {
>> > + update_device_info(proxy);
>> > + } else if (!strcmp(name, "ServicesResolved")) {
>> > + gboolean resolved;
>> > +
>> > + dbus_message_iter_get_basic(iter, &resolved);
>> > +
>> > + rl_printf("Services resolved %s\n", resolved ?
>> > + "yes" : "no");
>> > +
>> > + if (resolved)
>> > + mesh_session_setup(connection.device);
>> > + }
>> > +
>> > + }
>> > + } else if (!strcmp(interface, "org.bluez.Adapter1")) {
>> > + DBusMessageIter addr_iter;
>> > + char *str;
>> > +
>> > + rl_printf("Adapter property changed \n");
>> > + if (g_dbus_proxy_get_property(proxy, "Address",
>> > + &addr_iter) == TRUE) {
>> > + const char *address;
>> > +
>> > + dbus_message_iter_get_basic(&addr_iter, &address);
>> > + str = g_strdup_printf("[" COLORED_CHG
>> > + "] Controller %s ", address);
>> > + } else
>> > + str = g_strdup("");
>> > +
>> > + if (strcmp(name, "Discovering") == 0) {
>> > + int temp;
>> > +
>> > + dbus_message_iter_get_basic(iter, &temp);
>> > + discovering = !!temp;
>> > + }
>> > +
>> > + print_iter(str, name, iter);
>> > + g_free(str);
>> > + } else if (!strcmp(interface, "org.bluez.GattService1")) {
>> > + rl_printf("Service property changed %s\n",
>> > + g_dbus_proxy_get_path(proxy));
>> > + } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
>> > + rl_printf("Characteristic property changed %s\n",
>> > + g_dbus_proxy_get_path(proxy));
>> > +
>> > + if ((connection.type == CONN_TYPE_PROVISION) ||
>> > + connection.session_open)
>> > + process_mesh_characteristic(proxy);
>> > + }
>> > +}
>> > +
>> > +static void message_handler(DBusConnection *connection,
>> > + DBusMessage *message, void *user_data)
>> > +{
>> > + rl_printf("[SIGNAL] %s.%s\n",
>> dbus_message_get_interface(message),
>> > + dbus_message_get_member(message));
>> > +}
>> > +
>> > +static struct adapter *find_ctrl_by_address(GList *source, const char
>> *address)
>> > +{
>> > + GList *list;
>> > +
>> > + for (list = g_list_first(source); list; list = g_list_next(list)) {
>> > + struct adapter *adapter = list->data;
>> > + DBusMessageIter iter;
>> > + const char *str;
>> > +
>> > + if (g_dbus_proxy_get_property(adapter->proxy,
>> > + "Address", &iter) == FALSE)
>> > + continue;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &str);
>> > +
>> > + if (!strcmp(str, address))
>> > + return adapter;
>> > + }
>> > +
>> > + return NULL;
>> > +}
>> > +
>> > +static gboolean parse_argument_on_off(const char *arg, dbus_bool_t
>> *value)
>> > +{
>> > + if (!arg || !strlen(arg)) {
>> > + rl_printf("Missing on/off argument\n");
>> > + return FALSE;
>> > + }
>> > +
>> > + if (!strcmp(arg, "on") || !strcmp(arg, "yes")) {
>> > + *value = TRUE;
>> > + return TRUE;
>> > + }
>> > +
>> > + if (!strcmp(arg, "off") || !strcmp(arg, "no")) {
>> > + *value = FALSE;
>> > + return TRUE;
>> > + }
>> > +
>> > + rl_printf("Invalid argument %s\n", arg);
>> > + return FALSE;
>> > +}
>> > +
>> > +static void cmd_list(const char *arg)
>> > +{
>> > + GList *list;
>> > +
>> > + for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
>> > + struct adapter *adapter = list->data;
>> > + print_adapter(adapter->proxy, NULL);
>> > + }
>> > +}
>> > +
>> > +static void cmd_show(const char *arg)
>> > +{
>> > + struct adapter *adapter;
>> > + GDBusProxy *proxy;
>> > + DBusMessageIter iter;
>> > + const char *address;
>> > +
>> > +
>> > + if (!arg || !strlen(arg)) {
>> > + if (check_default_ctrl() == FALSE)
>> > + return;
>> > +
>> > + proxy = default_ctrl->proxy;
>> > + } else {
>> > + adapter = find_ctrl_by_address(ctrl_list, arg);
>> > + if (!adapter) {
>> > + rl_printf("Controller %s not available\n", arg);
>> > + return;
>> > + }
>> > + proxy = adapter->proxy;
>> > + }
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
>> > + return;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &address);
>> > + rl_printf("Controller %s\n", address);
>> > +
>> > + print_property(proxy, "Name");
>> > + print_property(proxy, "Alias");
>> > + print_property(proxy, "Class");
>> > + print_property(proxy, "Powered");
>> > + print_property(proxy, "Discoverable");
>> > + print_uuids(proxy);
>> > + print_property(proxy, "Modalias");
>> > + print_property(proxy, "Discovering");
>> > +}
>> > +
>> > +static void cmd_select(const char *arg)
>> > +{
>> > + struct adapter *adapter;
>> > +
>> > + if (!arg || !strlen(arg)) {
>> > + rl_printf("Missing controller address argument\n");
>> > + return;
>> > + }
>> > +
>> > + adapter = find_ctrl_by_address(ctrl_list, arg);
>> > + if (!adapter) {
>> > + rl_printf("Controller %s not available\n", arg);
>> > + return;
>> > + }
>> > +
>> > + if (default_ctrl && default_ctrl->proxy == adapter->proxy)
>> > + return;
>> > +
>> > + forget_mesh_devices();
>> > +
>> > + default_ctrl = adapter;
>> > + print_adapter(adapter->proxy, NULL);
>> > +}
>> > +
>> > +static void generic_callback(const DBusError *error, void *user_data)
>> > +{
>> > + char *str = user_data;
>> > +
>> > + if (dbus_error_is_set(error))
>> > + rl_printf("Failed to set %s: %s\n", str, error->name);
>> > + else
>> > + rl_printf("Changing %s succeeded\n", str);
>> > +}
>> > +
>> > +static void cmd_power(const char *arg)
>> > +{
>> > + dbus_bool_t powered;
>> > + char *str;
>> > +
>> > + if (parse_argument_on_off(arg, &powered) == FALSE)
>> > + return;
>> > +
>> > + if (check_default_ctrl() == FALSE)
>> > + return;
>> > +
>> > + str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
>> > +
>> > + if (g_dbus_proxy_set_property_basic(default_ctrl->proxy,
>> "Powered",
>> > + DBUS_TYPE_BOOLEAN, &powered,
>> > + generic_callback, str, g_free) == TRUE)
>> > + return;
>> > +
>> > + g_free(str);
>> > +}
>> > +
>> > +static void cmd_scan(const char *arg)
>> > +{
>> > + dbus_bool_t enable;
>> > + const char *method;
>> > +
>> > + if (parse_argument_on_off(arg, &enable) == FALSE)
>> > + return;
>> > +
>> > + if (check_default_ctrl() == FALSE)
>> > + return;
>> > +
>> > + if (enable == TRUE) {
>> > + method = "StartDiscovery";
>> > + } else {
>> > + method = "StopDiscovery";
>> > + }
>> > +
>> > + if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
>> > + NULL, start_discovery_reply,
>> > + GUINT_TO_POINTER(enable), NULL) == FALSE) {
>> > + rl_printf("Failed to %s discovery\n",
>> > + enable == TRUE ? "start" : "stop");
>> > + return;
>> > + }
>> > +}
>> > +
>> > +static void append_variant(DBusMessageIter *iter, int type, void *val)
>> > +{
>> > + DBusMessageIter value;
>> > + char sig[2] = { type, '\0' };
>> > +
>> > + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig,
>> &value);
>> > +
>> > + dbus_message_iter_append_basic(&value, type, val);
>> > +
>> > + dbus_message_iter_close_container(iter, &value);
>> > +}
>> > +
>> > +static void append_array_variant(DBusMessageIter *iter, int type, void
>> *val,
>> > + int n_elements)
>> > +{
>> > + DBusMessageIter variant, array;
>> > + char type_sig[2] = { type, '\0' };
>> > + char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
>> > +
>> > + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
>> > + array_sig, &variant);
>> > +
>> > + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
>> > + type_sig, &array);
>> > +
>> > + if (dbus_type_is_fixed(type) == TRUE) {
>> > + dbus_message_iter_append_fixed_array(&array, type, val,
>> > + n_elements);
>> > + } else if (type == DBUS_TYPE_STRING || type ==
>> DBUS_TYPE_OBJECT_PATH) {
>> > + const char ***str_array = val;
>> > + int i;
>> > +
>> > + for (i = 0; i < n_elements; i++)
>> > + dbus_message_iter_append_basic(&array, type,
>> > + &((*str_array)[i]));
>> > + }
>> > +
>> > + dbus_message_iter_close_container(&variant, &array);
>> > +
>> > + dbus_message_iter_close_container(iter, &variant);
>> > +}
>> > +
>> > +static void dict_append_entry(DBusMessageIter *dict, const char *key,
>> > + int type, void *val)
>> > +{
>> > + DBusMessageIter entry;
>> > +
>> > + if (type == DBUS_TYPE_STRING) {
>> > + const char *str = *((const char **) val);
>> > +
>> > + if (str == NULL)
>> > + return;
>> > + }
>> > +
>> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
>> > + NULL, &entry);
>> > +
>> > + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
>> &key);
>> > +
>> > + append_variant(&entry, type, val);
>> > +
>> > + dbus_message_iter_close_container(dict, &entry);
>> > +}
>> > +
>> > +static void dict_append_basic_array(DBusMessageIter *dict, int
>> key_type,
>> > + const void *key, int type, void *val,
>> > + int n_elements)
>> > +{
>> > + DBusMessageIter entry;
>> > +
>> > + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
>> > + NULL, &entry);
>> > +
>> > + dbus_message_iter_append_basic(&entry, key_type, key);
>> > +
>> > + append_array_variant(&entry, type, val, n_elements);
>> > +
>> > + dbus_message_iter_close_container(dict, &entry);
>> > +}
>> > +
>> > +static void dict_append_array(DBusMessageIter *dict, const char *key, int
>> type,
>> > + void *val, int n_elements)
>> > +{
>> > + dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
>> > + n_elements);
>> > +}
>> > +
>> > +#define DISTANCE_VAL_INVALID 0x7FFF
>> > +
>> > +struct set_discovery_filter_args {
>> > + char *transport;
>> > + dbus_uint16_t rssi;
>> > + dbus_int16_t pathloss;
>> > + char **uuids;
>> > + size_t uuids_len;
>> > + dbus_bool_t reset;
>> > +};
>> > +
>> > +static void set_discovery_filter_setup(DBusMessageIter *iter, void
>> *user_data)
>> > +{
>> > + struct set_discovery_filter_args *args = user_data;
>> > + DBusMessageIter dict;
>> > +
>> > + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
>> > + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
>> > + DBUS_TYPE_STRING_AS_STRING
>> > + DBUS_TYPE_VARIANT_AS_STRING
>> > + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
>> > +
>> > + dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &args-
>> >uuids,
>> > + args->uuids_len);
>> > +
>> > + if (args->pathloss != DISTANCE_VAL_INVALID)
>> > + dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
>> > + &args->pathloss);
>> > +
>> > + if (args->rssi != DISTANCE_VAL_INVALID)
>> > + dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi);
>> > +
>> > + if (args->transport != NULL)
>> > + dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
>> > + &args->transport);
>> > + if (args->reset)
>> > + dict_append_entry(&dict, "ResetData", DBUS_TYPE_BOOLEAN,
>> > + &args->reset);
>> > +
>> > + dbus_message_iter_close_container(iter, &dict);
>> > +}
>> > +
>> > +
>> > +static void set_discovery_filter_reply(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("SetDiscoveryFilter failed: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("SetDiscoveryFilter success\n");
>> > +}
>> > +
>> > +static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
>> > +static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
>> > +static char **filtered_scan_uuids;
>> > +static size_t filtered_scan_uuids_len;
>> > +static char *filtered_scan_transport = "le";
>> > +
>> > +static void set_scan_filter_commit(void)
>> > +{
>> > + struct set_discovery_filter_args args;
>> > +
>> > + args.pathloss = filtered_scan_pathloss;
>> > + args.rssi = filtered_scan_rssi;
>> > + args.transport = filtered_scan_transport;
>> > + args.uuids = filtered_scan_uuids;
>> > + args.uuids_len = filtered_scan_uuids_len;
>> > + args.reset = TRUE;
>> > +
>> > + if (check_default_ctrl() == FALSE)
>> > + return;
>> > +
>> > + if (g_dbus_proxy_method_call(default_ctrl->proxy,
>> "SetDiscoveryFilter",
>> > + set_discovery_filter_setup, set_discovery_filter_reply,
>> > + &args, NULL) == FALSE) {
>> > + rl_printf("Failed to set discovery filter\n");
>> > + return;
>> > + }
>> > +}
>> > +
>> > +static void set_scan_filter_uuids(const char *arg)
>> > +{
>> > + g_strfreev(filtered_scan_uuids);
>> > + filtered_scan_uuids = NULL;
>> > + filtered_scan_uuids_len = 0;
>> > +
>> > + if (!arg || !strlen(arg))
>> > + goto commit;
>> > +
>> > + rl_printf("set_scan_filter_uuids %s\n", arg);
>> > + filtered_scan_uuids = g_strsplit(arg, " ", -1);
>> > + if (!filtered_scan_uuids) {
>> > + rl_printf("Failed to parse input\n");
>> > + return;
>> > + }
>> > +
>> > + filtered_scan_uuids_len = g_strv_length(filtered_scan_uuids);
>> > +
>> > +commit:
>> > + set_scan_filter_commit();
>> > +}
>> > +
>> > +static void cmd_scan_unprovisioned_devices(const char *arg)
>> > +{
>> > + dbus_bool_t enable;
>> > +
>> > + if (parse_argument_on_off(arg, &enable) == FALSE)
>> > + return;
>> > +
>> > + if (enable == TRUE) {
>> > + discover_mesh = false;
>> > + set_scan_filter_uuids(MESH_PROV_SVC_UUID);
>> > + }
>> > + cmd_scan(arg);
>> > +}
>> > +
>> > +static void cmd_info(const char *arg)
>> > +{
>> > + GDBusProxy *proxy;
>> > + DBusMessageIter iter;
>> > + const char *address;
>> > +
>> > + proxy = connection.device;
>> > + if (!proxy)
>> > + return;
>> > +
>> > + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
>> > + return;
>> > +
>> > + dbus_message_iter_get_basic(&iter, &address);
>> > + rl_printf("Device %s\n", address);
>> > +
>> > + print_property(proxy, "Name");
>> > + print_property(proxy, "Alias");
>> > + print_property(proxy, "Class");
>> > + print_property(proxy, "Appearance");
>> > + print_property(proxy, "Icon");
>> > + print_property(proxy, "Trusted");
>> > + print_property(proxy, "Blocked");
>> > + print_property(proxy, "Connected");
>> > + print_uuids(proxy);
>> > + print_property(proxy, "Modalias");
>> > + print_property(proxy, "ManufacturerData");
>> > + print_property(proxy, "ServiceData");
>> > + print_property(proxy, "RSSI");
>> > + print_property(proxy, "TxPower");
>> > +}
>> > +
>> > +static void cmd_connect(const char *arg)
>> > +{
>> > + if (check_default_ctrl() == FALSE)
>> > + return;
>> > +
>> > + memset(&connection, 0, sizeof(connection));
>> > +
>> > + if (!arg || !strlen(arg)) {
>> > + connection.net_idx = NET_IDX_PRIMARY;
>> > + } else {
>> > + char *end;
>> > + connection.net_idx = strtol(arg, &end, 16);
>> > + if (end == arg) {
>> > + connection.net_idx = NET_IDX_INVALID;
>> > + rl_printf("Invalid network index %s\n", arg);
>> > + return;
>> > + }
>> > + }
>> > +
>> > + if (discovering)
>> > + g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
>> > + NULL, NULL, NULL, NULL);
>> > +
>> > + set_scan_filter_uuids(MESH_PROXY_SVC_UUID);
>> > + discover_mesh = true;
>> > +
>> > + connection.type = CONN_TYPE_NETWORK;
>> > +
>> > +
>> > + rl_printf("Looking for mesh network with net index %4.4x\n",
>> > + connection.net_idx);
>> > +
>> > + if (g_dbus_proxy_method_call(default_ctrl->proxy,
>> > + "StartDiscovery", NULL, start_discovery_reply,
>> > + GUINT_TO_POINTER(TRUE), NULL) == FALSE)
>> > + rl_printf("Failed to start mesh proxy discovery\n");
>> > +
>> > + g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery",
>> > + NULL, NULL, NULL, NULL);
>> > +
>> > +}
>> > +
>> > +static void prov_disconn_reply(DBusMessage *message, void
>> *user_data)
>> > +{
>> > + struct mesh_node *node = user_data;
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to disconnect: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + set_connected_device(NULL);
>> > +
>> > + set_scan_filter_uuids(MESH_PROXY_SVC_UUID);
>> > + discover_mesh = true;
>> > +
>> > + connection.type = CONN_TYPE_IDENTITY;
>> > + connection.data_in = NULL;
>> > + connection.data_out = NULL;
>> > + connection.unicast = node_get_primary(node);
>> > +
>> > + if (g_dbus_proxy_method_call(default_ctrl->proxy,
>> > + "StartDiscovery", NULL, start_discovery_reply,
>> > + GUINT_TO_POINTER(TRUE), NULL) == FALSE)
>> > + rl_printf("Failed to start mesh proxy discovery\n");
>> > +
>> > +}
>> > +
>> > +static void disconn_reply(DBusMessage *message, void *user_data)
>> > +{
>> > + GDBusProxy *proxy = user_data;
>> > + DBusError error;
>> > +
>> > + dbus_error_init(&error);
>> > +
>> > + if (dbus_set_error_from_message(&error, message) == TRUE) {
>> > + rl_printf("Failed to disconnect: %s\n", error.name);
>> > + dbus_error_free(&error);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Successfully disconnected\n");
>> > +
>> > + if (proxy != connection.device)
>> > + return;
>> > +
>> > + set_connected_device(NULL);
>> > +}
>> > +
>> > +static void cmd_disconn(const char *arg)
>> > +{
>> > + if (connection.type == CONN_TYPE_PROVISION) {
>> > + struct mesh_node *node =
>> node_find_by_uuid(connection.dev_uuid);
>> > + if (node)
>> > + node_free(node);
>> > + }
>> > +
>> > + disconnect_device(disconn_reply, connection.device);
>> > +}
>> > +
>> > +static void mesh_prov_done(void *user_data, int status)
>> > +{
>> > + struct mesh_node *node = user_data;
>> > +
>> > + if (status){
>> > + rl_printf("Provisioning failed\n");
>> > + node_free(node);
>> > + disconnect_device(NULL, NULL);
>> > + return;
>> > + }
>> > +
>> > + rl_printf("Provision success. Assigned Primary Unicast %4.4x\n",
>> > + node_get_primary(node));
>> > +
>> > + if (!prov_db_add_new_node(node))
>> > + rl_printf("Failed to add node to provisioning DB\n");
>> > +
>> > + disconnect_device(prov_disconn_reply, node);
>> > +}
>> > +
>> > +static void cmd_start_prov(const char *arg)
>> > +{
>> > + GDBusProxy *proxy;
>> > + struct mesh_device *dev;
>> > + struct mesh_node *node;
>> > + int len;
>> > +
>> > + if (!arg) {
>> > + rl_printf("Mesh Device UUID is required\n");
>> > + return;
>> > + }
>> > +
>> > + len = strlen(arg);
>> > + if ( len > 32 || len % 2) {
>> > + rl_printf("Incorrect UUID size %d\n", len);
>> > + }
>> > +
>> > + disconnect_device(NULL, NULL);
>> > +
>> > + memset(connection.dev_uuid, 0, 16);
>> > + str2hex(arg, len, connection.dev_uuid, len/2);
>> > +
>> > + node = node_find_by_uuid(connection.dev_uuid);
>> > + if (!node) {
>> > + rl_printf("Device with UUID %s not found.\n", arg);
>> > + rl_printf("Stale services? Remove device and re-discover\n");
>> > + return;
>> > + }
>> > +
>> > + /* TODO: add command to remove a node from mesh, i.e.,
>> "unprovision" */
>> > + if (node_is_provisioned(node)) {
>> > + rl_printf("Already provisioned with unicast %4.4x\n",
>> > + node_get_primary(node));
>> > + return;
>> > + }
>> > +
>> > + dev = find_device_by_uuid(default_ctrl->mesh_devices,
>> > + connection.dev_uuid);
>> > + if (!dev || !dev->proxy) {
>> > + rl_printf("Could not find device proxy\n");
>> > + memset(connection.dev_uuid, 0, 16);
>> > + return;
>> > + }
>> > +
>> > + proxy = dev->proxy;
>> > + if (discovering)
>> > + g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
>> > + NULL, NULL, NULL, NULL);
>> > + forget_mesh_devices();
>> > +
>> > + connection.type = CONN_TYPE_PROVISION;
>> > +
>> > + if (g_dbus_proxy_method_call(proxy, "Connect", NULL,
>> connect_reply,
>> > + proxy, NULL) == FALSE) {
>> > + rl_printf("Failed to connect ");
>> > + print_device(proxy, NULL);
>> > + return;
>> > + } else {
>> > + rl_printf("Trying to connect ");
>> > + print_device(proxy, NULL);
>> > + }
>> > +
>> > +}
>> > +
>> > +static void cmd_config(const char *arg)
>> > +{
>> > + rl_printf("Switching to Mesh Client configuration menu\n");
>> > +
>> > + if (!switch_cmd_menu("configure"))
>> > + return;
>> > +
>> > + set_menu_prompt("config", NULL);
>> > +
>> > + if (arg && strlen(arg))
>> > + config_set_node(arg);
>> > +}
>> > +
>> > +static void cmd_onoff_cli(const char *arg)
>> > +{
>> > + rl_printf("Switching to Mesh Generic ON OFF Client menu\n");
>> > +
>> > + if (!switch_cmd_menu("onoff"))
>> > + return;
>> > +
>> > + set_menu_prompt("on/off", NULL);
>> > +
>> > + if (arg && strlen(arg))
>> > + onoff_set_node(arg);
>> > +}
>> > +
>> > +static void cmd_print_mesh(const char *arg)
>> > +{
>> > + if (!prov_db_show(mesh_prov_db_filename))
>> > + rl_printf("Unavailable\n");
>> > +
>> > +}
>> > +
>> > + static void cmd_print_local(const char *arg)
>> > +{
>> > + if (!prov_db_show(mesh_local_config_filename))
>> > + rl_printf("Unavailable\n");
>> > +}
>> > +
>> > +static void disc_quit_cb(DBusMessage *message, void *user_data)
>> > +{
>> > + g_main_loop_quit(main_loop);
>> > +}
>> > +
>> > +static void cmd_quit(const char *arg)
>> > +{
>> > + if (connection.device) {
>> > + disconnect_device(disc_quit_cb, NULL);
>> > + return;
>> > + }
>> > +
>> > + g_main_loop_quit(main_loop);
>> > +}
>> > +
>> > +static const struct menu_entry meshctl_cmd_table[] = {
>> > + { "list", NULL, cmd_list, "List available controllers"},
>> > + { "show", "[ctrl]", cmd_show, "Controller information"},
>> > + { "select", "<ctrl>", cmd_select, "Select default controller"},
>> > + { "info", "[dev]", cmd_info, "Device information"},
>> > + { "connect", "[net_idx]",cmd_connect, "Connect to mesh
>> network"},
>> > + { "discover-unprovisioned", "<on/off>",
>> cmd_scan_unprovisioned_devices,
>> > + "Look for devices to provision" },
>> > + { "provision", "<uuid>", cmd_start_prov, "Initiate provisioning"},
>> > + { "power", "<on/off>", cmd_power, "Set controller power" },
>> > + { "disconnect", "[dev]", cmd_disconn, "Disconnect device"},
>> > + { "mesh-info", NULL, cmd_print_mesh,
>> > + "Mesh networkinfo (provisioner)" },
>> > + { "local-info", NULL, cmd_print_local, "Local mesh node info" },
>> > + { "configure", "[dst]", cmd_config, "Config client model menu"},
>> > + { "onoff", "[dst]", cmd_onoff_cli,
>> > + "Generic On/Off model menu"},
>> > + { "quit", NULL, cmd_quit, "Quit program" },
>> > + { "exit", NULL, cmd_quit },
>> > + { "help" },
>> > + { }
>> > +};
>> > +
>> > +static void rl_handler(char *input)
>> > +{
>> > + char *cmd, *arg;
>> > +
>> > + if (!input) {
>> > + rl_insert_text("quit");
>> > + rl_redisplay();
>> > + rl_crlf();
>> > + g_main_loop_quit(main_loop);
>> > + return;
>> > + }
>> > +
>> > + if (!strlen(input))
>> > + goto done;
>> > + else if (!strcmp(input, "q") || !strcmp(input, "quit")
>> > + || !strcmp(input, "exit")) {
>> > + cmd_quit(NULL);
>> > + goto done;
>> > + }
>> > +
>> > + if (agent_input(input) == TRUE)
>> > + goto done;
>> > +
>> > + add_history(input);
>> > +
>> > + cmd = strtok_r(input, " \t\r\n", &arg);
>> > + if (!cmd)
>> > + goto done;
>> > +
>> > + process_menu_cmd(cmd, arg);
>> > +
>> > +done:
>> > + free(input);
>> > +}
>> > +
>> > +static gboolean signal_handler(GIOChannel *channel, GIOCondition
>> condition,
>> > + gpointer user_data)
>> > +{
>> > + static bool terminated = false;
>> > + struct signalfd_siginfo si;
>> > + ssize_t result;
>> > + int fd;
>> > +
>> > + if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
>> > + g_main_loop_quit(main_loop);
>> > + return FALSE;
>> > + }
>> > +
>> > + fd = g_io_channel_unix_get_fd(channel);
>> > +
>> > + result = read(fd, &si, sizeof(si));
>> > + if (result != sizeof(si))
>> > + return FALSE;
>> > +
>> > + switch (si.ssi_signo) {
>> > + case SIGINT:
>> > + if (input) {
>> > + rl_replace_line("", 0);
>> > + rl_crlf();
>> > + rl_on_new_line();
>> > + rl_redisplay();
>> > + break;
>> > + }
>> > +
>> > + /*
>> > + * If input was not yet setup up that means signal was received
>> > + * while daemon was not yet running. Since user is not able
>> > + * to terminate client by CTRL-D or typing exit treat this as
>> > + * exit and fall through.
>> > + */
>> > +
>> > + /* fall through */
>> > + case SIGTERM:
>> > + if (!terminated) {
>> > + rl_replace_line("", 0);
>> > + rl_crlf();
>> > + g_main_loop_quit(main_loop);
>> > + }
>> > +
>> > + terminated = true;
>> > + break;
>> > + }
>> > +
>> > + return TRUE;
>> > +}
>> > +
>> > +static guint setup_signalfd(void)
>> > +{
>> > + GIOChannel *channel;
>> > + guint source;
>> > + sigset_t mask;
>> > + int fd;
>> > +
>> > + sigemptyset(&mask);
>> > + sigaddset(&mask, SIGINT);
>> > + sigaddset(&mask, SIGTERM);
>> > +
>> > + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
>> > + perror("Failed to set signal mask");
>> > + return 0;
>> > + }
>> > +
>> > + fd = signalfd(-1, &mask, 0);
>> > + if (fd < 0) {
>> > + perror("Failed to create signal descriptor");
>> > + return 0;
>> > + }
>> > +
>> > + channel = g_io_channel_unix_new(fd);
>> > +
>> > + g_io_channel_set_close_on_unref(channel, TRUE);
>> > + g_io_channel_set_encoding(channel, NULL, NULL);
>> > + g_io_channel_set_buffered(channel, FALSE);
>> > +
>> > + source = g_io_add_watch(channel,
>> > + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
>> > + signal_handler, NULL);
>> > +
>> > + g_io_channel_unref(channel);
>> > +
>> > + return source;
>> > +}
>> > +
>> > +static gboolean option_version = FALSE;
>> > +static const char *mesh_config_dir;
>> > +
>> > +static GOptionEntry options[] = {
>> > + { "config", 'c', 0, G_OPTION_ARG_STRING, &mesh_config_dir,
>> > + "Read local mesh config JSON files from <directory>" },
>> > + { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
>> > + "Show version information and exit" },
>> > + { NULL },
>> > +};
>> > +
>> > +static void client_ready(GDBusClient *client, void *user_data)
>> > +{
>> > + if (!input)
>> > + input = setup_standard_input();
>> > +}
>> > +
>> > +int main(int argc, char *argv[])
>> > +{
>> > + GOptionContext *context;
>> > + GError *error = NULL;
>> > + GDBusClient *client;
>> > + guint signal;
>> > + int len;
>> > + int extra;
>> > +
>> > + context = g_option_context_new(NULL);
>> > + g_option_context_add_main_entries(context, options, NULL);
>> > +
>> > + if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
>> > + if (error != NULL) {
>> > + g_printerr("%s\n", error->message);
>> > + g_error_free(error);
>> > + } else
>> > + g_printerr("An unknown error occurred\n");
>> > + exit(1);
>> > + }
>> > +
>> > + g_option_context_free(context);
>> > +
>> > + if (option_version == TRUE) {
>> > + rl_printf("%s\n", VERSION);
>> > + exit(0);
>> > + }
>> > +
>> > + if (!mesh_config_dir) {
>> > + rl_printf("Local config directory not provided.\n");
>> > + mesh_config_dir = "";
>> > + } else {
>> > + rl_printf("Reading prov_db.json and local_node.json from %s\n",
>> > + mesh_config_dir);
>> > + }
>> > +
>> > + len = strlen(mesh_config_dir);
>> > + if (len && mesh_config_dir[len - 1] != '/') {
>> > + extra = 1;
>> > + rl_printf("mesh_config_dir[%d] %s\n", len,
>> > + &mesh_config_dir[len - 1]);
>> > + } else {
>> > + extra = 0;
>> > + }
>> > + mesh_local_config_filename = g_malloc(len +
>> strlen("local_node.json")
>> > + + 2);
>> > + if (!mesh_local_config_filename)
>> > + exit(1);
>> > +
>> > + mesh_prov_db_filename = g_malloc(len + strlen("prov_db.json") +
>> 2);
>> > + if (!mesh_prov_db_filename) {
>> > + exit(1);
>> > + }
>> > +
>> > + sprintf(mesh_local_config_filename, "%s", mesh_config_dir);
>> > +
>> > + if (extra)
>> > + sprintf(mesh_local_config_filename + len , "%c", '/');
>> > +
>> > + sprintf(mesh_local_config_filename + len + extra, "%s",
>> > + "local_node.json");
>> > + len = len + extra + strlen("local_node.json");
>> > + sprintf(mesh_local_config_filename + len, "%c", '\0');
>> > +
>> > + if (!prov_db_read_local_node(mesh_local_config_filename, true)) {
>> > + g_printerr("Failed to parse local node configuration file %s\n",
>> > + mesh_local_config_filename);
>> > + exit(1);
>> > + }
>> > +
>> > + sprintf(mesh_prov_db_filename, "%s", mesh_config_dir);
>> > + len = strlen(mesh_config_dir);
>> > + if (extra)
>> > + sprintf(mesh_prov_db_filename + len , "%c", '/');
>> > +
>> > + sprintf(mesh_prov_db_filename + len + extra, "%s", "prov_db.json");
>> > + sprintf(mesh_prov_db_filename + len + extra +
>> strlen("prov_db.json"),
>> > + "%c", '\0');
>> > +
>> > + if (!prov_db_read(mesh_prov_db_filename)) {
>> > + g_printerr("Failed to parse provisioning database file %s\n",
>> > + mesh_prov_db_filename);
>> > + exit(1);
>> > + }
>> > +
>> > + main_loop = g_main_loop_new(NULL, FALSE);
>> > + dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
>> > +
>> > + setlinebuf(stdout);
>> > +
>> > + rl_erase_empty_line = 1;
>> > + rl_callback_handler_install(NULL, rl_handler);
>> > +
>> > + rl_set_prompt(PROMPT_OFF);
>> > + rl_redisplay();
>> > +
>> > + signal = setup_signalfd();
>> > + client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
>> > +
>> > + g_dbus_client_set_connect_watch(client, connect_handler, NULL);
>> > + g_dbus_client_set_disconnect_watch(client, disconnect_handler,
>> NULL);
>> > + g_dbus_client_set_signal_watch(client, message_handler, NULL);
>> > +
>> > + g_dbus_client_set_proxy_handlers(client, proxy_added,
>> proxy_removed,
>> > + property_changed, NULL);
>> > +
>> > + g_dbus_client_set_ready_watch(client, client_ready, NULL);
>> > +
>> > + cmd_menu_init(meshctl_cmd_table);
>> > +
>> > + if (!config_client_init())
>> > + g_printerr("Failed to initialize mesh configuration client\n");
>> > +
>> > + if (!config_server_init())
>> > + g_printerr("Failed to initialize mesh configuration server\n");
>> > +
>> > + if (!onoff_client_init(PRIMARY_ELEMENT_IDX))
>> > + g_printerr("Failed to initialize mesh generic On/Off client\n");
>> > +
>> > + g_main_loop_run(main_loop);
>> > +
>> > + g_dbus_client_unref(client);
>> > + g_source_remove(signal);
>> > + if (input > 0)
>> > + g_source_remove(input);
>> > +
>> > + rl_message("");
>> > + rl_callback_handler_remove();
>> > +
>> > + dbus_connection_unref(dbus_conn);
>> > + g_main_loop_unref(main_loop);
>> > +
>> > + node_cleanup();
>> > +
>> > + g_list_free(char_list);
>> > + g_list_free(service_list);
>> > + g_list_free_full(ctrl_list, proxy_leak);
>> > +
>> > + agent_release();
>> > +
>> > + return 0;
>> > +}
>> > diff --git a/mesh/net.c b/mesh/net.c
>> > new file mode 100644
>> > index 0000000..fb2d200
>> > --- /dev/null
>> > +++ b/mesh/net.c
>> > @@ -0,0 +1,2184 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <inttypes.h>
>> > +#include <ctype.h>
>> > +#include <stdbool.h>
>> > +#include <stdio.h>
>> > +#include <string.h>
>> > +#include <glib.h>
>> > +
>> > +#include "src/shared/util.h"
>> > +#include "client/display.h"
>> > +
>> > +#include "crypto.h"
>> > +#include "gatt.h"
>> > +#include "mesh-net.h"
>> > +#include "util.h"
>> > +#include "keys.h"
>> > +#include "node.h"
>> > +#include "prov-db.h"
>> > +#include "net.h"
>> > +
>> > +struct address_range
>> > +{
>> > + uint16_t min;
>> > + uint16_t max;
>> > +};
>> > +
>> > +struct mesh_net {
>> > + uint32_t iv_index;
>> > + uint32_t seq_num;
>> > + uint32_t seq_num_reserved;
>> > + uint16_t primary_addr;
>> > + uint8_t iv_upd_state;
>> > + uint8_t num_elements;
>> > + uint8_t default_ttl;
>> > + bool iv_update;
>> > + bool provisioner;
>> > + bool blacklist;
>> > + guint iv_update_timeout;
>> > + GDBusProxy *proxy_in;
>> > + GList *address_pool;
>> > + GList *dest; /* List of valid local destinations for Whitelist */
>> > + GList *sar_in; /* Incoming segmented messages in progress */
>> > + GList *msg_out; /* Pre-Network encoded, might be multi-segment */
>> > + GList *pkt_out; /* Fully encoded packets awaiting Tx in order */
>> > + net_mesh_session_open_callback open_cb;
>> > +};
>> > +
>> > +struct generic_key {
>> > + uint16_t idx;
>> > +};
>> > +
>> > +struct net_key_parts {
>> > + uint8_t nid;
>> > + uint8_t enc_key[16];
>> > + uint8_t privacy_key[16];
>> > + uint8_t net_key[16];
>> > + uint8_t beacon_key[16];
>> > + uint8_t net_id[8];
>> > +};
>> > +
>> > +struct mesh_net_key {
>> > + struct generic_key generic;
>> > + uint8_t phase;
>> > + struct net_key_parts current;
>> > + struct net_key_parts new;
>> > +};
>> > +
>> > +struct app_key_parts {
>> > + uint8_t key[16];
>> > + uint8_t akf_aid;
>> > +};
>> > +
>> > +struct mesh_app_key {
>> > + struct generic_key generic;
>> > + uint16_t net_idx;
>> > + struct app_key_parts current;
>> > + struct app_key_parts new;
>> > +};
>> > +
>> > +struct mesh_virt_addr {
>> > + uint16_t va16;
>> > + uint32_t va32;
>> > + uint8_t va128[16];
>> > +};
>> > +
>> > +struct mesh_pkt {
>> > + uint8_t data[30];
>> > + uint8_t len;
>> > +};
>> > +
>> > +struct mesh_sar_msg {
>> > + guint ack_to;
>> > + guint msg_to;
>> > + uint32_t iv_index;
>> > + uint32_t seqAuth;
>> > + uint32_t ack;
>> > + uint32_t dst;
>> > + uint16_t src;
>> > + uint16_t net_idx;
>> > + uint16_t len;
>> > + uint8_t akf_aid;
>> > + uint8_t ttl;
>> > + uint8_t segN;
>> > + uint8_t activity_cnt;
>> > + bool ctl;
>> > + bool segmented;
>> > + bool szmic;
>> > + bool proxy;
>> > + uint8_t data[20]; /* Open ended, min 20 */
>> > +};
>> > +
>> > +struct mesh_destination {
>> > + uint16_t cnt;
>> > + uint16_t dst;
>> > +};
>> > +
>> > +/* Network Packet Layer based Offsets */
>> > +#define AKF_BIT 0x40
>> > +
>> > +#define PKT_IVI(p) !!((p)[0] & 0x80)
>> > +#define SET_PKT_IVI(p,v) do {(p)[0] &= 0x7f; \
>> > + (p)[0] |= ((v) ? 0x80 : 0);} while(0)
>> > +#define PKT_NID(p) ((p)[0] & 0x7f)
>> > +#define SET_PKT_NID(p,v) do {(p)[0] &= 0x80; (p)[0] |= (v);} while(0)
>> > +#define PKT_CTL(p) (!!((p)[1] & 0x80))
>> > +#define SET_PKT_CTL(p,v) do {(p)[1] &= 0x7f; \
>> > + (p)[1] |= ((v) ? 0x80 : 0);} while(0)
>> > +#define PKT_TTL(p) ((p)[1] & 0x7f)
>> > +#define SET_PKT_TTL(p,v) do {(p)[1] &= 0x80; (p)[1] |= (v);} while(0)
>> > +#define PKT_SEQ(p) (get_be32((p) + 1) & 0xffffff)
>> > +#define SET_PKT_SEQ(p,v) put_be32(((p)[1] << 24) + ((v) & 0xffffff), \
>> > + (p) + 1)
>> > +#define PKT_SRC(p) get_be16((p) + 5)
>> > +#define SET_PKT_SRC(p,v) put_be16(v, (p) + 5)
>> > +#define PKT_DST(p) get_be16((p) + 7)
>> > +#define SET_PKT_DST(p,v) put_be16(v, (p) + 7)
>> > +#define PKT_TRANS(p) ((p) + 9)
>> > +#define PKT_TRANS_LEN(l) ((l) - 9)
>> > +
>> > +#define PKT_SEGMENTED(p) (!!((p)[9] & 0x80))
>> > +#define SET_PKT_SEGMENTED(p,v) do {(p)[9] &= 0x7f; \
>> > + (p)[9] |= ((v) ? 0x80 : 0);} while(0)
>> > +#define PKT_AKF_AID(p) ((p)[9] & 0x7f)
>> > +#define SET_PKT_AKF_AID(p,v) do {(p)[9] &= 0x80; (p)[9] |= (v);}
>> while(0)
>> > +#define PKT_OPCODE(p) ((p)[9] & 0x7f)
>> > +#define SET_PKT_OPCODE(p,v) do {(p)[9] &= 0x80; (p)[9] |= (v);}
>> while(0)
>> > +#define PKT_OBO(p) (!!((p)[10] & 0x80))
>> > +#define PKT_SZMIC(p) (!!(PKT_SEGMENTED(p) ? ((p)[10] & 0x40) :
>> 0))
>> > +#define SET_PKT_SZMIC(p,v) do {(p)[10] &= 0x7f; \
>> > + (p)[10] |= ((v) ? 0x80 : 0);} while(0)
>> > +#define PKT_SEQ0(p) ((get_be16((p) + 10) >> 2) & 0x1fff)
>> > +#define SET_PKT_SEQ0(p,v) do {put_be16((get_be16((p) + 10) &
>> 0x8003) \
>> > + | (((v) & 0x1fff) << 2), \
>> > + (p) + 10);} while(0)
>> > +#define SET_PKT_SEGO(p,v) do {put_be16((get_be16( \
>> > + (p) + 11) & 0xfc1f) | ((v) << 5), \
>> > + (p) + 11);} while(0)
>> > +#define SET_PKT_SEGN(p,v) do {(p)[12] = ((p)[12] & 0xe0) | (v);}
>> while(0)
>> > +#define PKT_ACK(p) (get_be32((p) + 12))
>> > +#define SET_PKT_ACK(p,v) (put_be32((v)(p) + 12))
>> > +
>> > +/* Transport Layer based offsets */
>> > +#define TRANS_SEGMENTED(t) (!!((t)[0] & 0x80))
>> > +#define SET_TRANS_SEGMENTD(t,v) do {(t)[0] &= 0x7f; \
>> > + (t)[0] |= ((v) ? 0x80 : 0);} while(0)
>> > +#define TRANS_OPCODE(t) ((t)[0] & 0x7f)
>> > +#define SET_TRANS_OPCODE(t,v) do {(t)[0] &= 0x80; (t)[0] |= (v);}
>> while(0)
>> > +#define TRANS_AKF_AID(t) ((t)[0] & 0x7f)
>> > +#define SET_TRANS_AKF_AID(t,v) do {(t)[0] &= 0xc0; (t)[0] |= (v);}
>> while(0)
>> > +#define TRANS_AKF(t) (!!((t)[0] & AKF_BIT))
>> > +#define TRANS_SZMIC(t) (!!(TRANS_SEGMENTED(t) ? ((t)[1] & 0x80) :
>> 0))
>> > +#define TRANS_SEQ0(t) ((get_be16((t) + 1) >> 2) & 0x1fff)
>> > +#define SET_TRANS_SEQ0(t,v) do {put_be16((get_be16((t) + 1) &
>> 0x8003) \
>> > + | (((v) & 0x1fff) << 2), \
>> > + (t) + 1);} while(0)
>> > +#define SET_TRANS_ACK(t,v) put_be32((v), (t) + 3)
>> > +#define TRANS_SEGO(t) ((get_be16((t) + 2) >> 5) & 0x1f)
>> > +#define TRANS_SEGN(t) ((t)[3] & 0x1f)
>> > +
>> > +#define TRANS_PAYLOAD(t) ((t) + (TRANS_SEGMENTED(t) ? 4 : 1))
>> > +#define TRANS_LEN(t,l) ((l) -(TRANS_SEGMENTED(t) ? 4 : 1))
>> > +
>> > +/* Proxy Config Opcodes */
>> > +#define FILTER_SETUP 0x00
>> > +#define FILTER_ADD 0x01
>> > +#define FILTER_DEL 0x02
>> > +#define FILTER_STATUS 0x03
>> > +
>> > +/* Proxy Filter Types */
>> > +#define WHITELIST_FILTER 0x00
>> > +#define BLACKLIST_FILTER 0x01
>> > +
>> > +/* IV Updating states for timing enforcement */
>> > +#define IV_UPD_INIT 0
>> > +#define IV_UPD_NORMAL 1
>> > +#define IV_UPD_UPDATING 2
>> > +#define IV_UPD_NORMAL_HOLD 3
>> > +
>> > +#define IV_IDX_DIFF_RANGE 42
>> > +
>> > +static struct mesh_net net;
>> > +static GList *virt_addrs = NULL;
>> > +static GList *net_keys = NULL;
>> > +static GList *app_keys = NULL;
>> > +
>> > +/* Forward static declarations */
>> > +static void resend_segs(struct mesh_sar_msg *sar);
>> > +
>> > +static int match_net_id(const void *a, const void *net_id)
>> > +{
>> > + const struct mesh_net_key *net_key = a;
>> > +
>> > + if (net_key->current.nid != 0xff &&
>> > + !memcmp(net_key->current.net_id, net_id, 8))
>> > + return 0;
>> > +
>> > + if (net_key->new.nid != 0xff &&
>> > + !memcmp(net_key->new.net_id, net_id, 8))
>> > + return 0;
>> > +
>> > + return -1;
>> > +}
>> > +
>> > +static struct mesh_net_key *find_net_key_by_id(const uint8_t *net_id)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(net_keys, net_id, match_net_id);
>> > +
>> > + if (!l)
>> > + return NULL;
>> > +
>> > + return l->data;
>> > +}
>> > +
>> > +uint16_t net_validate_proxy_beacon(const uint8_t *proxy_beacon)
>> > +{
>> > + struct mesh_net_key *net_key =
>> find_net_key_by_id(proxy_beacon);
>> > +
>> > + if (net_key == NULL)
>> > + return NET_IDX_INVALID;
>> > +
>> > + return net_key->generic.idx;
>> > +}
>> > +
>> > +static int match_sar_dst(const void *a, const void *b)
>> > +{
>> > + const struct mesh_sar_msg *sar = a;
>> > + uint16_t dst = GPOINTER_TO_UINT(b);
>> > +
>> > + return (sar->dst == dst) ? 0 : -1;
>> > +}
>> > +
>> > +static struct mesh_sar_msg *find_sar_out_by_dst(uint16_t dst)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(net.msg_out, GUINT_TO_POINTER(dst),
>> > + match_sar_dst);
>> > +
>> > + if (!l)
>> > + return NULL;
>> > +
>> > + return l->data;
>> > +}
>> > +
>> > +static int match_sar_src(const void *a, const void *b)
>> > +{
>> > + const struct mesh_sar_msg *sar = a;
>> > + uint16_t src = GPOINTER_TO_UINT(b);
>> > +
>> > + return (sar->src == src) ? 0 : -1;
>> > +}
>> > +
>> > +static struct mesh_sar_msg *find_sar_in_by_src(uint16_t src)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(net.sar_in, GUINT_TO_POINTER(src),
>> > + match_sar_src);
>> > +
>> > + if (!l)
>> > + return NULL;
>> > +
>> > + return l->data;
>> > +}
>> > +
>> > +static int match_key_index(const void *a, const void *b)
>> > +{
>> > + const struct generic_key *generic = a;
>> > + uint16_t index = GPOINTER_TO_UINT(b);
>> > +
>> > + return (generic->idx == index) ? 0 : -1;
>> > +}
>> > +
>> > +static bool delete_key(GList **list, uint16_t index)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(*list, GUINT_TO_POINTER(index),
>> > + match_key_index);
>> > +
>> > + if (!l)
>> > + return false;
>> > +
>> > + *list = g_list_delete_link(*list, l);
>> > +
>> > + return true;
>> > +
>> > +}
>> > +
>> > +static uint8_t *get_key(GList *list, uint16_t index)
>> > +{
>> > + GList *l;
>> > + struct mesh_app_key *app_key;
>> > + struct mesh_net_key *net_key;
>> > +
>> > + l = g_list_find_custom(list, GUINT_TO_POINTER(index),
>> > + match_key_index);
>> > +
>> > + if (!l) return NULL;
>> > +
>> > + if (list == app_keys) {
>> > + app_key = l->data;
>> > +
>> > + /* All App Keys must belong to a valid Net Key */
>> > + l = g_list_find_custom(net_keys,
>> > + GUINT_TO_POINTER(app_key->net_idx),
>> > + match_key_index);
>> > +
>> > + if (!l) return NULL;
>> > +
>> > + net_key = l->data;
>> > +
>> > + if (net_key->phase == 2 && app_key->new.akf_aid != 0xff)
>> > + return app_key->new.key;
>> > +
>> > + if (app_key->current.akf_aid != 0xff)
>> > + return app_key->current.key;
>> > +
>> > + return NULL;
>> > + }
>> > +
>> > + net_key = l->data;
>> > +
>> > + if (net_key->phase == 2 && net_key->new.nid != 0xff)
>> > + return net_key->new.net_key;
>> > +
>> > + if (net_key->current.nid != 0xff)
>> > + return net_key->current.net_key;
>> > +
>> > + return NULL;
>> > +}
>> > +
>> > +bool keys_app_key_add(uint16_t net_idx, uint16_t app_idx, uint8_t
>> *key,
>> > + bool update)
>> > +{
>> > + struct mesh_app_key *app_key = NULL;
>> > + uint8_t akf_aid;
>> > + GList *l = g_list_find_custom(app_keys,
>> GUINT_TO_POINTER(app_idx),
>> > + match_key_index);
>> > +
>> > + if (!mesh_crypto_k4(key, &akf_aid))
>> > + return false;
>> > +
>> > + akf_aid |= AKF_BIT;
>> > +
>> > + if (l && update) {
>> > +
>> > + app_key = l->data;
>> > +
>> > + if (app_key->net_idx != net_idx)
>> > + return false;
>> > +
>> > + memcpy(app_key->new.key, key, 16);
>> > + app_key->new.akf_aid = akf_aid;
>> > +
>> > + } else if (l) {
>> > +
>> > + app_key = l->data;
>> > +
>> > + if (memcmp(app_key->current.key, key, 16) ||
>> > + app_key->net_idx != net_idx)
>> > + return false;
>> > +
>> > + } else {
>> > +
>> > + app_key = g_new(struct mesh_app_key, 1);
>> > + memcpy(app_key->current.key, key, 16);
>> > + app_key->net_idx = net_idx;
>> > + app_key->generic.idx = app_idx;
>> > + app_key->current.akf_aid = akf_aid;
>> > +
>> > + /* Invalidate "New" version */
>> > + app_key->new.akf_aid = 0xff;
>> > +
>> > + app_keys = g_list_append(app_keys, app_key);
>> > +
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool keys_net_key_add(uint16_t net_idx, uint8_t *key, bool update)
>> > +{
>> > + struct mesh_net_key *net_key = NULL;
>> > + uint8_t p = 0;
>> > + GList *l = g_list_find_custom(net_keys,
>> GUINT_TO_POINTER(net_idx),
>> > + match_key_index);
>> > +
>> > + if (l && update) {
>> > + bool result;
>> > +
>> > + net_key = l->data;
>> > +
>> > + memcpy(net_key->new.net_key, key, 16);
>> > +
>> > + /* Calculate the many component parts */
>> > + result = mesh_crypto_nkbk(key, net_key->new.beacon_key);
>> > + if (!result)
>> > + return false;
>> > +
>> > + result = mesh_crypto_k3(key, net_key->new.net_id);
>> > + if (!result)
>> > + return false;
>> > +
>> > + result = mesh_crypto_k2(key, &p, 1,
>> > + &net_key->new.nid,
>> > + net_key->new.enc_key,
>> > + net_key->new.privacy_key);
>> > + if (!result)
>> > + net_key->new.nid = 0xff;
>> > +
>> > + return result;
>> > +
>> > + } else if (l) {
>> > + net_key = l->data;
>> > +
>> > + if (memcmp(net_key->current.net_key, key, 16))
>> > + return false;
>> > + } else {
>> > + bool result;
>> > +
>> > + net_key = g_new(struct mesh_net_key, 1);
>> > + memcpy(net_key->current.net_key, key, 16);
>> > + net_key->generic.idx = net_idx;
>> > +
>> > + /* Invalidate "New" version */
>> > + net_key->new.nid = 0xff;
>> > +
>> > + /* Calculate the many component parts */
>> > + result = mesh_crypto_nkbk(key, net_key->current.beacon_key);
>> > + if (!result) {
>> > + g_free(net_key);
>> > + return false;
>> > + }
>> > +
>> > + result = mesh_crypto_k3(key, net_key->current.net_id);
>> > + if (!result) {
>> > + g_free(net_key);
>> > + return false;
>> > + }
>> > +
>> > + result = mesh_crypto_k2(key, &p, 1,
>> > + &net_key->current.nid,
>> > + net_key->current.enc_key,
>> > + net_key->current.privacy_key);
>> > +
>> > + if (!result) {
>> > + g_free(net_key);
>> > + return false;
>> > + }
>> > +
>> > + net_keys = g_list_append(net_keys, net_key);
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static struct mesh_app_key *find_app_key_by_idx(uint16_t app_idx)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
>> > + match_key_index);
>> > +
>> > + if (!l) return NULL;
>> > +
>> > + return l->data;
>> > +}
>> > +
>> > +static struct mesh_net_key *find_net_key_by_idx(uint16_t net_idx)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
>> > + match_key_index);
>> > +
>> > + if (!l) return NULL;
>> > +
>> > + return l->data;
>> > +}
>> > +
>> > +static int match_virt_dst(const void *a, const void *b)
>> > +{
>> > + const struct mesh_virt_addr *virt = a;
>> > + uint32_t dst = GPOINTER_TO_UINT(b);
>> > +
>> > + if (dst < 0x10000 && dst == virt->va16)
>> > + return 0;
>> > +
>> > + if (dst == virt->va32)
>> > + return 0;
>> > +
>> > + return -1;
>> > +}
>> > +
>> > +static struct mesh_virt_addr *find_virt_by_dst(uint32_t dst)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(virt_addrs, GUINT_TO_POINTER(dst),
>> > + match_virt_dst);
>> > +
>> > + if (!l) return NULL;
>> > +
>> > + return l->data;
>> > +}
>> > +
>> > +uint8_t *keys_net_key_get(uint16_t net_idx, bool current)
>> > +{
>> > + GList *l;
>> > +
>> > +
>> > + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
>> > + match_key_index);
>> > + if (!l) {
>> > + return NULL;
>> > + } else {
>> > + struct mesh_net_key *key = l->data;
>> > + if (current)
>> > + return key->current.net_key;
>> > + else
>> > + return key->new.net_key;
>> > + }
>> > +}
>> > +
>> > +bool keys_app_key_delete(uint16_t app_idx)
>> > +{
>> > + /* TODO: remove all associated bindings */
>> > + return delete_key(&app_keys, app_idx);
>> > +}
>> > +
>> > +bool keys_net_key_delete(uint16_t net_idx)
>> > +{
>> > + /* TODO: remove all associated app keys and bindings */
>> > + return delete_key(&net_keys, net_idx);
>> > +}
>> > +
>> > +uint8_t keys_get_kr_phase(uint16_t net_idx)
>> > +{
>> > + GList *l;
>> > + struct mesh_net_key *key;
>> > +
>> > + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
>> > + match_key_index);
>> > +
>> > + if (!l)
>> > + return KR_PHASE_INVALID;
>> > +
>> > + key = l->data;
>> > +
>> > + return key->phase;
>> > +}
>> > +
>> > +bool keys_set_kr_phase(uint16_t index, uint8_t phase)
>> > +{
>> > + GList *l;
>> > + struct mesh_net_key *net_key;
>> > +
>> > + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(index),
>> > + match_key_index);
>> > +
>> > + if (!l)
>> > + return false;
>> > +
>> > + net_key = l->data;
>> > + net_key->phase = phase;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +uint16_t keys_app_key_get_bound(uint16_t app_idx)
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
>> > + match_key_index);
>> > + if (!l)
>> > + return NET_IDX_INVALID;
>> > + else {
>> > + struct mesh_app_key *key = l->data;
>> > + return key->net_idx;
>> > + }
>> > +}
>> > +
>> > +uint8_t *keys_app_key_get(uint16_t app_idx, bool current)
>> > +{
>> > + GList *l;
>> > +
>> > +
>> > + l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
>> > + match_key_index);
>> > + if (!l) {
>> > + return NULL;
>> > + } else {
>> > + struct mesh_app_key *key = l->data;
>> > + if (current)
>> > + return key->current.key;
>> > + else
>> > + return key->new.key;
>> > + }
>> > +}
>> > +
>> > +void keys_cleanup_all(void)
>> > +{
>> > + g_list_free_full(app_keys, g_free);
>> > + g_list_free_full(net_keys, g_free);
>> > + app_keys = net_keys = NULL;
>> > +}
>> > +
>> > +bool net_get_key(uint16_t net_idx, uint8_t *key)
>> > +{
>> > + uint8_t *buf;
>> > +
>> > + buf = get_key(net_keys, net_idx);
>> > +
>> > + if (!buf)
>> > + return false;
>> > +
>> > + memcpy(key, buf, 16);
>> > + return true;
>> > +}
>> > +
>> > +bool net_get_flags(uint16_t net_idx, uint8_t *out_flags)
>> > +{
>> > + uint8_t phase;
>> > +
>> > + phase = keys_get_kr_phase(net_idx);
>> > +
>> > + if (phase == KR_PHASE_INVALID || !out_flags)
>> > + return false;
>> > +
>> > + if (phase != KR_PHASE_NONE)
>> > + *out_flags = 0x01;
>> > + else
>> > + *out_flags = 0x00;
>> > +
>> > + if (net.iv_update)
>> > + *out_flags |= 0x02;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +uint32_t net_get_iv_index(bool *update)
>> > +{
>> > + if (update)
>> > + *update = net.iv_update;
>> > +
>> > + return net.iv_index;
>> > +}
>> > +
>> > +void net_set_iv_index(uint32_t iv_index, bool update)
>> > +{
>> > + net.iv_index = iv_index;
>> > + net.iv_update = update;
>> > +}
>> > +
>> > +void set_sequence_number(uint32_t seq_num)
>> > +{
>> > + net.seq_num = seq_num;
>> > +}
>> > +
>> > +uint32_t get_sequence_number(void)
>> > +{
>> > + return net.seq_num;
>> > +}
>> > +
>> > +bool net_add_address_pool(uint16_t min, uint16_t max)
>> > +{
>> > + uint32_t range;
>> > + if (max < min)
>> > + return false;
>> > + range = min + (max << 16);
>> > + net.address_pool = g_list_append(net.address_pool,
>> > + GUINT_TO_POINTER(range));
>> > + return true;
>> > +}
>> > +
>> > +static int match_address_range(const void *a, const void *b)
>> > +{
>> > + uint32_t range = GPOINTER_TO_UINT(a);
>> > + uint8_t num_elements = (uint8_t) (GPOINTER_TO_UINT(b));
>> > + uint16_t max = range >> 16;
>> > + uint16_t min = range & 0xffff;
>> > +
>> > + return ((max - min) >= (num_elements - 1)) ? 0 : -1;
>> > +
>> > +}
>> > +
>> > +uint16_t net_obtain_address(uint8_t num_eles)
>> > +{
>> > + uint16_t addr;
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(net.address_pool,
>> GUINT_TO_POINTER(num_eles),
>> > + match_address_range);
>> > + if (l) {
>> > + uint32_t range = GPOINTER_TO_UINT(l->data);
>> > + uint16_t max = range >> 16;
>> > + uint16_t min = range & 0xffff;
>> > +
>> > + addr = min;
>> > + min += num_eles;
>> > +
>> > + if (min > max)
>> > + net.address_pool = g_list_delete_link(net.address_pool,
>> > + l);
>> > + else {
>> > + range = min + (max << 16);
>> > + l->data = GUINT_TO_POINTER(range);
>> > + }
>> > + return addr;
>> > + }
>> > +
>> > + return UNASSIGNED_ADDRESS;
>> > +}
>> > +
>> > +static int range_cmp(const void *a, const void *b)
>> > +{
>> > + uint32_t range1 = GPOINTER_TO_UINT(a);
>> > + uint32_t range2 = GPOINTER_TO_UINT(b);
>> > +
>> > + return range2 - range1;
>> > +}
>> > +
>> > +void net_release_address(uint16_t addr, uint8_t num_elements)
>> > +{
>> > + GList *l;
>> > + uint32_t range;
>> > +
>> > + for (l = net.address_pool; l != NULL; l = l->next)
>> > + {
>> > + uint16_t max;
>> > + uint16_t min;
>> > +
>> > + range = GPOINTER_TO_UINT(l->data);
>> > +
>> > + max = range >> 16;
>> > + min = range & 0xffff;
>> > +
>> > + if (min == (addr + num_elements + 1))
>> > + min = addr;
>> > + else if (addr && max == (addr - 1))
>> > + max = addr + num_elements + 1;
>> > + else
>> > + continue;
>> > +
>> > + range = min + (max << 16);
>> > + l->data = GUINT_TO_POINTER(range);
>> > + return;
>> > + }
>> > +
>> > + range = addr + ((addr + num_elements - 1) << 16);
>> > + net.address_pool = g_list_insert_sorted(net.address_pool,
>> > + GUINT_TO_POINTER(range),
>> > + range_cmp);
>> > +}
>> > +
>> > +bool net_reserve_address_range(uint16_t base, uint8_t num_elements)
>> > +{
>> > + GList *l;
>> > + uint32_t range;
>> > + uint16_t max;
>> > + uint16_t min;
>> > + bool shrink;
>> > +
>> > + for (l = net.address_pool; l != NULL; l = l->next) {
>> > +
>> > + range = GPOINTER_TO_UINT(l->data);
>> > +
>> > + max = range >> 16;
>> > + min = range & 0xffff;
>> > +
>> > + if (base >= min && (base + num_elements - 1) <= max)
>> > + break;
>> > + }
>> > +
>> > + if (!l)
>> > + return false;
>> > +
>> > + net.address_pool = g_list_delete_link(net.address_pool, l);
>> > +
>> > + shrink = false;
>> > +
>> > + if (base == min) {
>> > + shrink = true;
>> > + min = base + num_elements;
>> > + }
>> > +
>> > + if (max == base + num_elements - 1) {
>> > + shrink = true;
>> > + max -= num_elements;
>> > + }
>> > +
>> > + if (min > max)
>> > + return true;
>> > +
>> > + if (shrink)
>> > + range = min + (max << 16);
>> > + else
>> > + range = min + ((base - 1) << 16);
>> > +
>> > + net.address_pool = g_list_insert_sorted(net.address_pool,
>> > + GUINT_TO_POINTER(range),
>> > + range_cmp);
>> > +
>> > + if (shrink)
>> > + return true;
>> > +
>> > + range = (base + num_elements) + (max << 16);
>> > + net.address_pool = g_list_insert_sorted(net.address_pool,
>> > + GUINT_TO_POINTER(range),
>> > + range_cmp);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static int match_destination(const void *a, const void *b)
>> > +{
>> > + const struct mesh_destination *dest = a;
>> > + uint16_t dst = GPOINTER_TO_UINT(b);
>> > +
>> > + return (dest->dst == dst) ? 0 : -1;
>> > +}
>> > +
>> > +void net_dest_ref(uint16_t dst)
>> > +{
>> > + struct mesh_destination *dest;
>> > + GList *l;
>> > +
>> > + if (!dst) return;
>> > +
>> > + l = g_list_find_custom(net.dest, GUINT_TO_POINTER(dst),
>> > + match_destination);
>> > +
>> > + if (l) {
>> > + dest = l->data;
>> > + dest->cnt++;
>> > + return;
>> > + }
>> > +
>> > + dest = g_new0(struct mesh_destination, 1);
>> > + dest->dst = dst;
>> > + dest->cnt++;
>> > + net.dest = g_list_append(net.dest, dest);
>> > +}
>> > +
>> > +void net_dest_unref(uint16_t dst)
>> > +{
>> > + struct mesh_destination *dest;
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(net.dest, GUINT_TO_POINTER(dst),
>> > + match_destination);
>> > +
>> > + if (!l)
>> > + return;
>> > +
>> > + dest = l->data;
>> > + dest->cnt--;
>> > +
>> > + if (dest->cnt == 0) {
>> > + net.dest = g_list_remove(net.dest, dest);
>> > + g_free(dest);
>> > + }
>> > +}
>> > +
>> > +struct build_whitelist {
>> > + uint8_t len;
>> > + uint8_t data[12];
>> > +};
>> > +
>> > +static void whitefilter_add(gpointer data, gpointer user_data)
>> > +{
>> > + struct mesh_destination *dest = data;
>> > + struct build_whitelist *white = user_data;
>> > +
>> > + if (white->len == 0)
>> > + white->data[white->len++] = FILTER_ADD;
>> > +
>> > + put_be16(dest->dst, white->data + white->len);
>> > + white->len += 2;
>> > +
>> > + if (white->len > (sizeof(white->data) - sizeof(uint16_t))) {
>> > + net_ctl_msg_send(0, 0, 0, white->data, white->len);
>> > + white->len = 0;
>> > + }
>> > +}
>> > +
>> > +static void setup_whitelist()
>> > +{
>> > + struct build_whitelist white;
>> > +
>> > + white.len = 0;
>> > +
>> > + /* Enable (and Clear) Proxy Whitelist */
>> > + white.data[white.len++] = FILTER_SETUP;
>> > + white.data[white.len++] = WHITELIST_FILTER;
>> > +
>> > + net_ctl_msg_send(0, 0, 0, white.data, white.len);
>> > +
>> > + white.len = 0;
>> > + g_list_foreach(net.dest, whitefilter_add, &white);
>> > +
>> > + if (white.len)
>> > + net_ctl_msg_send(0, 0, 0, white.data, white.len);
>> > +}
>> > +
>> > +static void beacon_update(bool first, bool iv_update, uint32_t iv_index)
>> > +{
>> > +
>> > + /* Enforcement of 96 hour and 192 hour IVU time windows */
>> > + if (iv_update && !net.iv_update) {
>> > + rl_printf("iv_upd_state = IV_UPD_UPDATING\n");
>> > + net.iv_upd_state = IV_UPD_UPDATING;
>> > + /* TODO: Start timer to enforce IV Update parameters */
>> > + } else if (first) {
>> > + if (iv_update)
>> > + net.iv_upd_state = IV_UPD_UPDATING;
>> > + else
>> > + net.iv_upd_state = IV_UPD_NORMAL;
>> > +
>> > + rl_printf("iv_upd_state = IV_UPD_%s\n",
>> > + iv_update ? "UPDATING" : "NORMAL");
>> > +
>> > + } else if (iv_update && iv_index != net.iv_index) {
>> > + rl_printf("IV Update too soon -- Rejecting\n");
>> > + return;
>> > + }
>> > +
>> > + if (iv_index > net.iv_index ||
>> > + iv_update != net.iv_update) {
>> > +
>> > + /* Don't reset our seq_num unless
>> > + * we start using new iv_index */
>> > + if (!(iv_update && (net.iv_index + 1 == iv_index))) {
>> > + net.seq_num = 0;
>> > + net.seq_num_reserved = 100;
>> > + }
>> > + }
>> > +
>> > + if (!net.seq_num || net.iv_index != iv_index ||
>> > + net.iv_update != iv_update) {
>> > +
>> > + if (net.seq_num_reserved <= net.seq_num)
>> > + net.seq_num_reserved = net.seq_num + 100;
>> > +
>> > + prov_db_local_set_iv_index(iv_index, iv_update,
>> > + net.provisioner);
>> > + prov_db_local_set_seq_num(net.seq_num_reserved);
>> > + }
>> > +
>> > + net.iv_index = iv_index;
>> > + net.iv_update = iv_update;
>> > +
>> > + if (first) {
>> > + /* Must be done once per Proxy Connection after Beacon RXed */
>> > + setup_whitelist();
>> > + if (net.open_cb)
>> > + net.open_cb(0);
>> > + }
>> > +}
>> > +
>> > +static bool process_beacon(uint8_t *data, uint8_t size)
>> > +{
>> > + struct mesh_net_key *net_key;
>> > + struct net_key_parts *key_part;
>> > + bool rxed_iv_update, rxed_key_refresh, iv_update;
>> > + bool my_krf;
>> > + uint32_t rxed_iv_index, iv_index;
>> > + uint64_t cmac;
>> > +
>> > + if (size != 22)
>> > + return false;
>> > +
>> > + rxed_key_refresh = (data[1] & 0x01) == 0x01;
>> > + iv_update = rxed_iv_update = (data[1] & 0x02) == 0x02;
>> > + iv_index = rxed_iv_index = get_be32(data + 10);
>> > +
>> > + /* Inhibit recognizing iv_update true-->false
>> > + * if we have outbound SAR messages in flight */
>> > + if (net.msg_out != NULL) {
>> > + if (net.iv_update && !rxed_iv_update)
>> > + iv_update = true;
>> > + }
>> > +
>> > + /* Don't bother going further if nothing has changed */
>> > + if (iv_index == net.iv_index && iv_update == net.iv_update &&
>> > + net.iv_upd_state != IV_UPD_INIT)
>> > + return true;
>> > +
>> > + /* Find key we are using for SNBs */
>> > + net_key = find_net_key_by_id(data + 2);
>> > +
>> > + if (net_key == NULL)
>> > + return false;
>> > +
>> > + /* We are Provisioner, and control the key_refresh flag */
>> > + if (rxed_key_refresh != !!(net_key->phase == 2))
>> > + return false;
>> > +
>> > + if (net_key->phase != 2) {
>> > + my_krf = false;
>> > + key_part = &net_key->current;
>> > + } else {
>> > + my_krf = true;
>> > + key_part = &net_key->new;
>> > + }
>> > +
>> > + /* Ignore for incorrect KR state */
>> > + if (memcmp(key_part->net_id, data + 2, 8))
>> > + return false;
>> > +
>> > + if ((net.iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
>> > + (iv_index < net.iv_index)) {
>> > + rl_printf("iv index outside range\n");
>> > + return false;
>> > + }
>> > +
>> > + /* Any behavioral changes must pass CMAC test */
>> > + if (!mesh_crypto_beacon_cmac(key_part->beacon_key, key_part-
>> >net_id,
>> > + rxed_iv_index, my_krf,
>> > + rxed_iv_update, &cmac)) {
>> > + return false;
>> > + }
>> > +
>> > + if (cmac != get_be64(data + 14))
>> > + return false;
>> > +
>> > + if (iv_update && (net.iv_upd_state > IV_UPD_UPDATING)) {
>> > + if (iv_index != net.iv_index) {
>> > + rl_printf("Update too soon -- Rejecting\n");
>> > + }
>> > + /* Silently ignore old beacons */
>> > + return true;
>> > + }
>> > +
>> > + beacon_update(net.iv_upd_state == IV_UPD_INIT, iv_update,
>> iv_index);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +struct decode_params {
>> > + struct mesh_net_key *net_key;
>> > + uint8_t *packet;
>> > + uint32_t iv_index;
>> > + uint8_t size;
>> > + bool proxy;
>> > +};
>> > +
>> > +static void try_decode(gpointer data, gpointer user_data)
>> > +{
>> > + struct mesh_net_key *net_key = data;
>> > + struct decode_params *decode = user_data;
>> > + uint8_t nid = decode->packet[0] & 0x7f;
>> > + uint8_t tmp[29];
>> > + bool status = false;
>> > +
>> > + if (decode->net_key)
>> > + return;
>> > +
>> > + if (net_key->current.nid == nid)
>> > + status = mesh_crypto_packet_decode(decode->packet,
>> > + decode->size, decode->proxy, tmp,
>> > + decode->iv_index,
>> > + net_key->current.enc_key,
>> > + net_key->current.privacy_key);
>> > +
>> > + if (!status && net_key->new.nid == nid)
>> > + status = mesh_crypto_packet_decode(decode->packet,
>> > + decode->size, decode->proxy, tmp,
>> > + decode->iv_index,
>> > + net_key->new.enc_key,
>> > + net_key->new.privacy_key);
>> > +
>> > + if (status) {
>> > + decode->net_key = net_key;
>> > + memcpy(decode->packet, tmp, decode->size);
>> > + return;
>> > + }
>> > +}
>> > +
>> > +static struct mesh_net_key *net_packet_decode(bool proxy, uint32_t
>> iv_index,
>> > + uint8_t *packet, uint8_t size)
>> > +{
>> > + struct decode_params decode = {
>> > + .proxy = proxy,
>> > + .iv_index = iv_index,
>> > + .packet = packet,
>> > + .size = size,
>> > + .net_key = NULL,
>> > + };
>> > +
>> > + g_list_foreach(net_keys, try_decode, &decode);
>> > +
>> > + return decode.net_key;
>> > +}
>> > +
>> > +static void flush_sar(GList **list, struct mesh_sar_msg *sar)
>> > +{
>> > + *list = g_list_remove(*list, sar);
>> > +
>> > + if (sar->msg_to)
>> > + g_source_remove(sar->msg_to);
>> > +
>> > + if (sar->ack_to)
>> > + g_source_remove(sar->ack_to);
>> > +
>> > + g_free(sar);
>> > +}
>> > +
>> > +static void flush_sar_list(GList **list)
>> > +{
>> > + struct mesh_sar_msg *sar;
>> > + GList *l = g_list_first(*list);
>> > +
>> > + while (l) {
>> > + sar = l->data;
>> > + flush_sar(list, sar);
>> > + l = g_list_first(*list);
>> > + }
>> > +}
>> > +
>> > +static void flush_pkt_list(GList **list)
>> > +{
>> > + struct mesh_pkt *pkt;
>> > + GList *l = g_list_first(*list);
>> > +
>> > + while (l) {
>> > + pkt = l->data;
>> > + *list = g_list_remove(*list, pkt);
>> > + g_free(pkt);
>> > + }
>> > +}
>> > +
>> > +static void resend_unacked_segs(gpointer data, gpointer user_data)
>> > +{
>> > + struct mesh_sar_msg *sar = data;
>> > +
>> > + if (sar->activity_cnt)
>> > + resend_segs(sar);
>> > +}
>> > +
>> > +static void send_pkt_cmplt(DBusMessage *message, void *user_data)
>> > +{
>> > + struct mesh_pkt *pkt = user_data;
>> > + GList *l = g_list_first(net.pkt_out);
>> > +
>> > + if (l && user_data == l->data) {
>> > + net.pkt_out = g_list_delete_link(net.pkt_out, l);
>> > + g_free(pkt);
>> > + } else {
>> > + /* This is a serious error, and probable memory leak */
>> > + rl_printf("ERR: send_pkt_cmplt %p not head of queue\n", pkt);
>> > + }
>> > +
>> > + l = g_list_first(net.pkt_out);
>> > +
>> > + if (l == NULL) {
>> > + /* If queue is newly empty, resend all SAR outbound packets */
>> > + g_list_foreach(net.msg_out, resend_unacked_segs, NULL);
>> > + return;
>> > + }
>> > +
>> > + pkt = l->data;
>> > +
>> > + mesh_gatt_write(net.proxy_in, pkt->data, pkt->len,
>> > + send_pkt_cmplt, pkt);
>> > +}
>> > +
>> > +static void send_mesh_pkt(struct mesh_pkt *pkt)
>> > +{
>> > + bool queued = !!(net.pkt_out);
>> > +
>> > + net.pkt_out = g_list_append(net.pkt_out, pkt);
>> > +
>> > + if (queued)
>> > + return;
>> > +
>> > + mesh_gatt_write(net.proxy_in, pkt->data, pkt->len,
>> > + send_pkt_cmplt, pkt);
>> > +}
>> > +
>> > +static uint32_t get_next_seq()
>> > +{
>> > + uint32_t this_seq = net.seq_num++;
>> > +
>> > + if (net.seq_num + 32 >= net.seq_num_reserved) {
>> > + net.seq_num_reserved = net.seq_num + 100;
>> > + prov_db_local_set_seq_num(net.seq_num_reserved);
>> > + }
>> > +
>> > + return this_seq;
>> > +}
>> > +
>> > +static void send_seg(struct mesh_sar_msg *sar, uint8_t seg)
>> > +{
>> > + struct mesh_net_key *net_key;
>> > + struct net_key_parts *part;
>> > + struct mesh_pkt *pkt;
>> > + uint8_t *data;
>> > +
>> > + net_key = find_net_key_by_idx(sar->net_idx);
>> > +
>> > + if (net_key == NULL)
>> > + return;
>> > +
>> > + /* Choose which components to use to secure pkt */
>> > + if (net_key->phase == 2 && net_key->new.nid != 0xff)
>> > + part = &net_key->new;
>> > + else
>> > + part = &net_key->current;
>> > +
>> > + pkt = g_new0(struct mesh_pkt, 1);
>> > +
>> > + if (pkt == NULL)
>> > + return;
>> > +
>> > + /* leave extra byte at start for GATT Proxy type */
>> > + data = pkt->data + 1;
>> > +
>> > + SET_PKT_NID(data, part->nid);
>> > + SET_PKT_IVI(data, sar->iv_index & 1);
>> > + SET_PKT_CTL(data, sar->ctl);
>> > + SET_PKT_TTL(data, sar->ttl);
>> > + SET_PKT_SEQ(data, get_next_seq());
>> > + SET_PKT_SRC(data, sar->src);
>> > + SET_PKT_DST(data, sar->dst);
>> > + SET_PKT_SEGMENTED(data, sar->segmented);
>> > +
>> > + if (sar->ctl)
>> > + SET_PKT_OPCODE(data, sar->data[0]);
>> > + else
>> > + SET_PKT_AKF_AID(data, sar->akf_aid);
>> > +
>> > + if (sar->segmented) {
>> > +
>> > + if (!sar->ctl)
>> > + SET_PKT_SZMIC(data, sar->szmic);
>> > +
>> > + SET_PKT_SEQ0(data, sar->seqAuth);
>> > + SET_PKT_SEGO(data, seg);
>> > + SET_PKT_SEGN(data, sar->segN);
>> > +
>> > + memcpy(PKT_TRANS(data) + 4,
>> > + sar->data + sar->ctl + (seg * 12), 12);
>> > +
>> > + pkt->len = 9 + 4;
>> > +
>> > + if (sar->segN == seg)
>> > + pkt->len += (sar->len - sar->ctl) % 12;
>> > +
>> > + if (pkt->len == (9 + 4))
>> > + pkt->len += 12;
>> > +
>> > + } else {
>> > + memcpy(PKT_TRANS(data) + 1,
>> > + sar->data + sar->ctl, 15);
>> > +
>> > + pkt->len = 9 + 1 + sar->len - sar->ctl;
>> > + }
>> > +
>> > + pkt->len += (sar->ctl ? 8 : 4);
>> > + mesh_crypto_packet_encode(data, pkt->len,
>> > + part->enc_key,
>> > + sar->iv_index,
>> > + part->privacy_key);
>> > +
>> > +
>> > + /* Prepend GATT_Proxy packet type */
>> > + if (sar->proxy)
>> > + pkt->data[0] = PROXY_CONFIG_PDU;
>> > + else
>> > + pkt->data[0] = PROXY_NETWORK_PDU;
>> > +
>> > + pkt->len++;
>> > +
>> > + send_mesh_pkt(pkt);
>> > +}
>> > +
>> > +static void resend_segs(struct mesh_sar_msg *sar)
>> > +{
>> > + uint32_t ack = 1;
>> > + uint8_t i;
>> > +
>> > + sar->activity_cnt = 0;
>> > +
>> > + for (i = 0; i <= sar->segN; i++, ack <<= 1) {
>> > + if (!(ack & sar->ack))
>> > + send_seg(sar, i);
>> > + }
>> > +}
>> > +
>> > +static bool ack_rxed(bool to, uint16_t src, uint16_t dst, bool obo,
>> > + uint16_t seq0, uint32_t ack_flags)
>> > +{
>> > + struct mesh_sar_msg *sar = find_sar_out_by_dst(src);
>> > + uint32_t full_ack;
>> > +
>> > + /* Silently ignore unknown (stale?) ACKs */
>> > + if (sar == NULL)
>> > + return true;
>> > +
>> > + full_ack = 0xffffffff >> (31 - sar->segN);
>> > +
>> > + sar->ack |= (ack_flags & full_ack);
>> > +
>> > + if (sar->ack == full_ack) {
>> > + /* Outbound message 100% received by remote node */
>> > + flush_sar(&net.msg_out, sar);
>> > + return true;
>> > + }
>> > +
>> > + /* Because we are GATT, and slow, only resend PKTs if it is
>> > + * time *and* our outbound PKT queue is empty. */
>> > + sar->activity_cnt++;
>> > +
>> > + if (net.pkt_out == NULL)
>> > + resend_segs(sar);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool proxy_ctl_rxed(uint16_t net_idx, uint32_t iv_index,
>> > + uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
>> > + uint8_t *trans, uint16_t len)
>> > +{
>> > + if (len < 1)
>> > + return false;
>> > +
>> > + switch(trans[0]) {
>> > + case FILTER_STATUS:
>> > + if (len != 4)
>> > + return false;
>> > +
>> > + net.blacklist = !!(trans[1] == BLACKLIST_FILTER);
>> > + rl_printf("Proxy %slist filter length: %d\n",
>> > + net.blacklist ? "Black" : "White",
>> > + get_be16(trans + 2));
>> > +
>> > + return true;
>> > +
>> > + default:
>> > + return false;
>> > + }
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static bool ctl_rxed(uint16_t net_idx, uint32_t iv_index,
>> > + uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
>> > + uint8_t *trans, uint16_t len)
>> > +{
>> > + /* TODO: Handle control messages */
>> > + return false;
>> > +}
>> > +
>> > +struct decrypt_params {
>> > + uint8_t *nonce;
>> > + uint8_t *aad;
>> > + uint8_t *out_msg;
>> > + uint8_t *trans;
>> > + uint32_t iv_index;
>> > + uint32_t seq_num;
>> > + uint16_t src;
>> > + uint16_t dst;
>> > + uint16_t len;
>> > + uint16_t net_idx;
>> > + uint16_t app_idx;
>> > + uint8_t akf_aid;
>> > + bool szmic;
>> > +};
>> > +
>> > +
>> > +static void try_decrypt(gpointer data, gpointer user_data)
>> > +{
>> > + struct mesh_app_key *app_key = data;
>> > + struct decrypt_params *decrypt = user_data;
>> > + size_t mic_size = decrypt->szmic ? sizeof(uint64_t) : sizeof(uint32_t);
>> > + bool status = false;
>> > +
>> > + /* Already done... Nothing to do */
>> > + if (decrypt->app_idx != APP_IDX_INVALID)
>> > + return;
>> > +
>> > + /* Don't decrypt on Appkeys not owned by this NetKey */
>> > + if (app_key->net_idx != decrypt->net_idx)
>> > + return;
>> > +
>> > + /* Test and decrypt against current key copy */
>> > + if (app_key->current.akf_aid == decrypt->akf_aid)
>> > + status = mesh_crypto_aes_ccm_decrypt(decrypt->nonce,
>> > + app_key->current.key,
>> > + decrypt->aad, decrypt->aad ? 16 : 0,
>> > + decrypt->trans, decrypt->len,
>> > + decrypt->out_msg, NULL, mic_size);
>> > +
>> > + /* Test and decrypt against new key copy */
>> > + if (!status && app_key->new.akf_aid == decrypt->akf_aid)
>> > + status = mesh_crypto_aes_ccm_decrypt(decrypt->nonce,
>> > + app_key->new.key,
>> > + decrypt->aad, decrypt->aad ? 16 : 0,
>> > + decrypt->trans, decrypt->len,
>> > + decrypt->out_msg, NULL, mic_size);
>> > +
>> > + /* If successful, terminate with successful App IDX */
>> > + if (status)
>> > + decrypt->app_idx = app_key->generic.idx;
>> > +}
>> > +
>> > +static uint16_t access_pkt_decrypt(uint8_t *nonce, uint8_t *aad,
>> > + uint16_t net_idx, uint8_t akf_aid, bool szmic,
>> > + uint8_t *trans, uint16_t len)
>> > +{
>> > + uint8_t *out_msg;
>> > + struct decrypt_params decrypt = {
>> > + .nonce = nonce,
>> > + .aad = aad,
>> > + .net_idx = net_idx,
>> > + .akf_aid = akf_aid,
>> > + .szmic = szmic,
>> > + .trans = trans,
>> > + .len = len,
>> > + .app_idx = APP_IDX_INVALID,
>> > + };
>> > +
>> > + out_msg = g_malloc(len);
>> > +
>> > + if (out_msg == NULL)
>> > + return false;
>> > +
>> > + decrypt.out_msg = out_msg;
>> > +
>> > + g_list_foreach(app_keys, try_decrypt, &decrypt);
>> > +
>> > + if (decrypt.app_idx != APP_IDX_INVALID)
>> > + memcpy(trans, out_msg, len);
>> > +
>> > + g_free(out_msg);
>> > +
>> > + return decrypt.app_idx;
>> > +}
>> > +
>> > +static bool access_rxed(uint8_t *nonce, uint16_t net_idx,
>> > + uint32_t iv_index, uint32_t seq_num,
>> > + uint16_t src, uint16_t dst,
>> > + uint8_t akf_aid, bool szmic, uint8_t *trans, uint16_t len)
>> > +{
>> > + uint16_t app_idx = access_pkt_decrypt(nonce, NULL,
>> > + net_idx, akf_aid, szmic, trans, len);
>> > +
>> > + if (app_idx != APP_IDX_INVALID) {
>> > + len -= szmic ? sizeof(uint64_t) : sizeof(uint32_t);
>> > +
>> > + node_local_data_handler(src, dst, iv_index, seq_num,
>> > + app_idx, trans, len);
>> > + return true;
>> > + }
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static void try_virt_decrypt(gpointer data, gpointer user_data)
>> > +{
>> > + struct mesh_virt_addr *virt = data;
>> > + struct decrypt_params *decrypt = user_data;
>> > +
>> > + if (decrypt->app_idx != APP_IDX_INVALID || decrypt->dst != virt-
>> >va16)
>> > + return;
>> > +
>> > + decrypt->app_idx = access_pkt_decrypt(decrypt->nonce,
>> > + virt->va128,
>> > + decrypt->net_idx, decrypt->akf_aid,
>> > + decrypt->szmic, decrypt->trans, decrypt->len);
>> > +
>> > + if (decrypt->app_idx != APP_IDX_INVALID) {
>> > + uint16_t len = decrypt->len;
>> > +
>> > + len -= decrypt->szmic ? sizeof(uint64_t) : sizeof(uint32_t);
>> > +
>> > + node_local_data_handler(decrypt->src, virt->va32,
>> > + decrypt->iv_index, decrypt->seq_num,
>> > + decrypt->app_idx, decrypt->trans, len);
>> > + }
>> > +}
>> > +
>> > +static bool virtual_rxed(uint8_t *nonce, uint16_t net_idx,
>> > + uint32_t iv_index, uint32_t seq_num,
>> > + uint16_t src, uint16_t dst,
>> > + uint8_t akf_aid, bool szmic, uint8_t *trans, uint16_t len)
>> > +{
>> > + struct decrypt_params decrypt = {
>> > + .nonce = nonce,
>> > + .net_idx = net_idx,
>> > + .iv_index = iv_index,
>> > + .seq_num = seq_num,
>> > + .src = dst,
>> > + .dst = dst,
>> > + .akf_aid = akf_aid,
>> > + .szmic = szmic,
>> > + .trans = trans,
>> > + .len = len,
>> > + .app_idx = APP_IDX_INVALID,
>> > + };
>> > +
>> > + /* Cycle through known virtual addresses */
>> > + g_list_foreach(virt_addrs, try_virt_decrypt, &decrypt);
>> > +
>> > + if (decrypt.app_idx != APP_IDX_INVALID)
>> > + return true;
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static bool msg_rxed(uint16_t net_idx, uint32_t iv_index, bool szmic,
>> > + uint8_t ttl, uint32_t seq_num, uint32_t seq_auth,
>> > + uint16_t src, uint16_t dst,
>> > + uint8_t *trans, uint16_t len)
>> > +{
>> > + uint8_t akf_aid = TRANS_AKF_AID(trans);
>> > + bool result;
>> > + size_t mic_size = szmic ? sizeof(uint64_t) : sizeof(uint32_t);
>> > + uint8_t nonce[13];
>> > + uint8_t *dev_key;
>> > + uint8_t *out = NULL;
>> > +
>> > + if (!TRANS_AKF(trans)) {
>> > + /* Compose Nonce */
>> > + result = mesh_crypto_device_nonce(seq_auth, src, dst,
>> > + iv_index, szmic, nonce);
>> > +
>> > + if (!result) return false;
>> > +
>> > + out = g_malloc0(TRANS_LEN(trans, len));
>> > + if (out == NULL) return false;
>> > +
>> > + /* If we are provisioner, we probably RXed on remote Dev Key */
>> > + if (net.provisioner) {
>> > + dev_key = node_get_device_key(node_find_by_addr(src));
>> > +
>> > + if (dev_key == NULL)
>> > + goto local_dev_key;
>> > + } else
>> > + goto local_dev_key;
>> > +
>> > + result = mesh_crypto_aes_ccm_decrypt(nonce, dev_key,
>> > + NULL, 0,
>> > + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len),
>> > + out, NULL, mic_size);
>> > +
>> > + if (result) {
>> > + node_local_data_handler(src, dst,
>> > + iv_index, seq_num, APP_IDX_DEV,
>> > + out, TRANS_LEN(trans, len) - mic_size);
>> > + goto done;
>> > + }
>> > +
>> > +local_dev_key:
>> > + /* Always fallback to the local Dev Key */
>> > + dev_key = node_get_device_key(node_get_local_node());
>> > +
>> > + if (dev_key == NULL)
>> > + goto done;
>> > +
>> > + result = mesh_crypto_aes_ccm_decrypt(nonce, dev_key,
>> > + NULL, 0,
>> > + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len),
>> > + out, NULL, mic_size);
>> > +
>> > + if (result) {
>> > + node_local_data_handler(src, dst,
>> > + iv_index, seq_num, APP_IDX_DEV,
>> > + out, TRANS_LEN(trans, len) - mic_size);
>> > + goto done;
>> > + }
>> > +
>> > + goto done;
>> > + }
>> > +
>> > + result = mesh_crypto_application_nonce(seq_auth, src, dst,
>> > + iv_index, szmic, nonce);
>> > +
>> > + if (!result) goto done;
>> > +
>> > + /* If Virtual destination wrap the Access decoder with Virtual */
>> > + if (IS_VIRTUAL(dst)) {
>> > + result = virtual_rxed(nonce, net_idx, iv_index, seq_num,
>> > + src, dst, akf_aid, szmic,
>> > + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len));
>> > + goto done;
>> > + }
>> > +
>> > + /* Try all matching App Keys until success or exhaustion */
>> > + result = access_rxed(nonce, net_idx, iv_index, seq_num,
>> > + src, dst, akf_aid, szmic,
>> > + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len));
>> > +
>> > +done:
>> > + if (out != NULL)
>> > + g_free(out);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +static void send_sar_ack(struct mesh_sar_msg *sar)
>> > +{
>> > + uint8_t ack[7];
>> > +
>> > + sar->activity_cnt = 0;
>> > +
>> > + memset(ack, 0, sizeof(ack));
>> > + SET_TRANS_OPCODE(ack, NET_OP_SEG_ACKNOWLEDGE);
>> > + SET_TRANS_SEQ0(ack, sar->seqAuth);
>> > + SET_TRANS_ACK(ack, sar->ack);
>> > +
>> > + net_ctl_msg_send(0xff, sar->dst, sar->src, ack, sizeof(ack));
>> > +}
>> > +
>> > +static gboolean sar_out_ack_timeout(void *user_data)
>> > +{
>> > + struct mesh_sar_msg *sar = user_data;
>> > +
>> > + sar->activity_cnt++;
>> > +
>> > + /* Because we are GATT, and slow, only resend PKTs if it is
>> > + * time *and* our outbound PKT queue is empty. */
>> > + if (net.pkt_out == NULL)
>> > + resend_segs(sar);
>> > +
>> > + /* Only add resent SAR pkts to empty queue */
>> > + return true;
>> > +}
>> > +
>> > +static gboolean sar_out_msg_timeout(void *user_data)
>> > +{
>> > + struct mesh_sar_msg *sar = user_data;
>> > +
>> > + /* msg_to will expire when we return false */
>> > + sar->msg_to = 0;
>> > +
>> > + flush_sar(&net.msg_out, sar);
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static gboolean sar_in_ack_timeout(void *user_data)
>> > +{
>> > + struct mesh_sar_msg *sar = user_data;
>> > + uint32_t full_ack = 0xffffffff >> (31 - sar->segN);
>> > +
>> > + if (sar->activity_cnt || sar->ack != full_ack)
>> > + send_sar_ack(sar);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static gboolean sar_in_msg_timeout(void *user_data)
>> > +{
>> > + struct mesh_sar_msg *sar = user_data;
>> > +
>> > + /* msg_to will expire when we return false */
>> > + sar->msg_to = 0;
>> > +
>> > + flush_sar(&net.sar_in, sar);
>> > +
>> > + return false;
>> > +}
>> > +
>> > +static uint32_t calc_seqAuth(uint32_t seq_num, uint8_t *trans)
>> > +{
>> > + uint32_t seqAuth = seq_num & ~0x1fff;
>> > +
>> > + seqAuth |= TRANS_SEQ0(trans);
>> > +
>> > + return seqAuth;
>> > +}
>> > +
>> > +static bool seg_rxed(uint16_t net_idx, uint32_t iv_index, bool ctl,
>> > + uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
>> > + uint8_t *trans, uint16_t len)
>> > +{
>> > + struct mesh_sar_msg *sar;
>> > + uint32_t seqAuth = calc_seqAuth(seq_num, trans);
>> > + uint8_t segN, segO;
>> > + uint32_t old_ack, full_ack, last_ack_mask;
>> > + bool send_ack, result = false;
>> > +
>> > + segN = TRANS_SEGN(trans);
>> > + segO = TRANS_SEGO(trans);
>> > +
>> > + /* Only support single incoming SAR'd message per SRC */
>> > + sar = find_sar_in_by_src(src);
>> > +
>> > + /* Reuse existing SAR structure if appropriate */
>> > + if (sar) {
>> > + uint64_t iv_seqAuth = (uint64_t)iv_index << 32 | seqAuth;
>> > + uint64_t old_iv_seqAuth = (uint64_t)sar->iv_index << 32 |
>> > + sar->seqAuth;
>> > + if (old_iv_seqAuth < iv_seqAuth) {
>> > +
>> > + flush_sar(&net.sar_in, sar);
>> > + sar = NULL;
>> > +
>> > + } else if (old_iv_seqAuth > iv_seqAuth) {
>> > +
>> > + /* New segment is Stale. Silently ignore */
>> > + return false;
>> > +
>> > + } else if (segN != sar->segN) {
>> > +
>> > + /* Remote side sent conflicting data: abandon */
>> > + flush_sar(&net.sar_in, sar);
>> > + sar = NULL;
>> > +
>> > + }
>> > + }
>> > +
>> > + if (sar == NULL) {
>> > + sar = g_malloc0(sizeof(*sar) + (12 * segN));
>> > +
>> > + if (sar == NULL)
>> > + return false;
>> > +
>> > + sar->net_idx = net_idx;
>> > + sar->iv_index = iv_index;
>> > + sar->ctl = ctl;
>> > + sar->ttl = ttl;
>> > + sar->seqAuth = seqAuth;
>> > + sar->src = src;
>> > + sar->dst = dst;
>> > + sar->segmented = true;
>> > + sar->szmic = TRANS_SZMIC(trans);
>> > + sar->segN = segN;
>> > +
>> > + /* In all cases, the reassembled packet should begin with the
>> > + * same first octet of all segments, minus the SEGMENTED flag */
>> > + sar->data[0] = trans[0] & 0x7f;
>> > +
>> > + net.sar_in = g_list_append(net.sar_in, sar);
>> > +
>> > + /* Setup expiration timers */
>> > + if (IS_UNICAST(dst))
>> > + sar->ack_to = g_timeout_add(5000,
>> > + sar_in_ack_timeout, sar);
>> > +
>> > + sar->msg_to = g_timeout_add(60000, sar_in_msg_timeout, sar);
>> > + }
>> > +
>> > + /* If last segment, calculate full msg size */
>> > + if (segN == segO)
>> > + sar->len = (segN * 12) + len - 3;
>> > +
>> > + /* Copy to correct offset */
>> > + memcpy(sar->data + 1 + (12 * segO), trans + 4, 12);
>> > +
>> > + full_ack = 0xffffffff >> (31 - segN);
>> > + last_ack_mask = 0xffffffff << segO;
>> > + old_ack = sar->ack;
>> > + sar->ack |= 1 << segO;
>> > + send_ack = false;
>> > +
>> > + /* Determine if we should forward message */
>> > + if (sar->ack == full_ack && old_ack != full_ack) {
>> > +
>> > + /* First time we have seen this complete message */
>> > + send_ack = true;
>> > +
>> > + if (ctl)
>> > + result = ctl_rxed(sar->net_idx, sar->iv_index,
>> > + sar->ttl, sar->seqAuth, sar->src,
>> > + sar->dst, sar->data, sar->len);
>> > + else
>> > + result = msg_rxed(sar->net_idx, sar->iv_index,
>> > + sar->szmic, sar->ttl,
>> > + seq_num, sar->seqAuth, sar->src,
>> > + sar->dst, sar->data, sar->len);
>> > + }
>> > +
>> > + /* Never Ack Group addressed SAR messages */
>> > + if (!IS_UNICAST(dst))
>> > + return result;
>> > +
>> > + /* Tickle the ACK system so it knows we are still RXing segments */
>> > + sar->activity_cnt++;
>> > +
>> > + /* Determine if we should ACK */
>> > + if (old_ack == sar->ack)
>> > + /* Let the timer generate repeat ACKs as needed */
>> > + send_ack = false;
>> > + else if ((last_ack_mask & sar->ack) == (last_ack_mask & full_ack))
>> > + /* If this was largest segO outstanding segment, we ACK */
>> > + send_ack = true;
>> > +
>> > + if (send_ack)
>> > + send_sar_ack(sar);
>> > +
>> > + return result;
>> > +}
>> > +
>> > +bool net_data_ready(uint8_t *msg, uint8_t len)
>> > +{
>> > + uint8_t type = *msg++;
>> > + uint32_t iv_index = net.iv_index;
>> > + struct mesh_net_key *net_key;
>> > +
>> > + if (len-- < 10) return false;
>> > +
>> > + if (type == PROXY_MESH_BEACON)
>> > + return process_beacon(msg, len);
>> > + else if (type > PROXY_CONFIG_PDU)
>> > + return false;
>> > +
>> > + /* RXed iv_index must be equal or 1 less than local iv_index */
>> > + /* With the clue being high-order bit of first octet */
>> > + if (!!(iv_index & 0x01) != !!(msg[0] & 0x80)) {
>> > + if (iv_index)
>> > + iv_index--;
>> > + else
>> > + return false;
>> > + }
>> > +
>> > + net_key = net_packet_decode(type == PROXY_CONFIG_PDU,
>> > + iv_index, msg, len);
>> > +
>> > + if (net_key == NULL)
>> > + return false;
>> > +
>> > + /* CTL packets have 64 bit network MIC, otherwise 32 bit MIC */
>> > + len -= PKT_CTL(msg) ? sizeof(uint64_t) : sizeof(uint32_t);
>> > +
>> > + if (type == PROXY_CONFIG_PDU) {
>> > +
>> > + /* Proxy Configuration DST messages must be 0x0000 */
>> > + if (PKT_DST(msg))
>> > + return false;
>> > +
>> > + return proxy_ctl_rxed(net_key->generic.idx,
>> > + iv_index, PKT_TTL(msg), PKT_SEQ(msg),
>> > + PKT_SRC(msg), PKT_DST(msg),
>> > + PKT_TRANS(msg), PKT_TRANS_LEN(len));
>> > +
>> > + } if (PKT_CTL(msg) && PKT_OPCODE(msg) ==
>> NET_OP_SEG_ACKNOWLEDGE) {
>> > +
>> > + return ack_rxed(false, PKT_SRC(msg), PKT_DST(msg),
>> > + PKT_OBO(msg), PKT_SEQ0(msg), PKT_ACK(msg));
>> > +
>> > + } else if (PKT_SEGMENTED(msg)) {
>> > +
>> > + return seg_rxed(net_key->generic.idx, iv_index, PKT_CTL(msg),
>> > + PKT_TTL(msg), PKT_SEQ(msg),
>> > + PKT_SRC(msg), PKT_DST(msg),
>> > + PKT_TRANS(msg), PKT_TRANS_LEN(len));
>> > +
>> > + } else if (!PKT_CTL(msg)){
>> > +
>> > + return msg_rxed(net_key->generic.idx,
>> > + iv_index, false, PKT_TTL(msg), PKT_SEQ(msg),
>> > + PKT_SEQ(msg), PKT_SRC(msg), PKT_DST(msg),
>> > + PKT_TRANS(msg), PKT_TRANS_LEN(len));
>> > + } else {
>> > +
>> > + return ctl_rxed(net_key->generic.idx,
>> > + iv_index, PKT_TTL(msg), PKT_SEQ(msg),
>> > + PKT_SRC(msg), PKT_DST(msg),
>> > + PKT_TRANS(msg), PKT_TRANS_LEN(len));
>> > +
>> > + }
>> > +
>> > + return false;
>> > +}
>> > +
>> > +bool net_session_open(GDBusProxy *data_in, bool provisioner,
>> > + net_mesh_session_open_callback cb)
>> > +{
>> > + if (net.proxy_in)
>> > + return false;
>> > +
>> > + net.proxy_in = data_in;
>> > + net.iv_upd_state = IV_UPD_INIT;
>> > + net.blacklist = false;
>> > + net.provisioner = provisioner;
>> > + net.open_cb = cb;
>> > + flush_pkt_list(&net.pkt_out);
>> > + return true;
>> > +}
>> > +
>> > +void net_session_close(GDBusProxy *data_in)
>> > +{
>> > + if (net.proxy_in == data_in)
>> > + net.proxy_in = NULL;
>> > +
>> > + flush_sar_list(&net.sar_in);
>> > + flush_sar_list(&net.msg_out);
>> > + flush_pkt_list(&net.pkt_out);
>> > +}
>> > +
>> > +bool net_register_unicast(uint16_t unicast, uint8_t count)
>> > +{
>> > + /* TODO */
>> > + return true;
>> > +}
>> > +
>> > +bool net_register_group(uint16_t group_addr)
>> > +{
>> > + /* TODO */
>> > + return true;
>> > +}
>> > +
>> > +uint32_t net_register_virtual(uint8_t buf[16])
>> > +{
>> > + /* TODO */
>> > + return 0;
>> > +}
>> > +
>> > +static bool get_enc_keys(uint16_t app_idx, uint16_t dst,
>> > + uint8_t *akf_aid, uint8_t **app_enc_key,
>> > + uint16_t *net_idx)
>> > +{
>> > + if (app_idx == APP_IDX_DEV) {
>> > + struct mesh_node *node;
>> > + uint8_t *enc_key = NULL;
>> > +
>> > + if (net.provisioner) {
>> > + /* Default to Remote Device Key when Provisioner */
>> > + node = node_find_by_addr(dst);
>> > + enc_key = node_get_device_key(node);
>> > + }
>> > +
>> > + if (enc_key == NULL) {
>> > + /* Use Local node Device Key */
>> > + node = node_get_local_node();
>> > + enc_key = node_get_device_key(node);
>> > + }
>> > +
>> > + if (enc_key == NULL || node == NULL)
>> > + return false;
>> > +
>> > + if (akf_aid) *akf_aid = 0;
>> > + if (app_enc_key) *app_enc_key = enc_key;
>> > + if (net_idx) *net_idx = node_get_primary_net_idx(node);
>> > +
>> > + } else {
>> > + struct mesh_app_key *app_key =
>> find_app_key_by_idx(app_idx);
>> > + struct mesh_net_key *net_key;
>> > + bool phase_two;
>> > +
>> > +
>> > + if (app_key == NULL)
>> > + return false;
>> > +
>> > + net_key = find_net_key_by_idx(app_key->net_idx);
>> > +
>> > + if (net_key == NULL)
>> > + return false;
>> > +
>> > + if (net_idx) *net_idx = app_key->net_idx;
>> > +
>> > + phase_two = !!(net_key->phase == 2);
>> > +
>> > + if (phase_two && app_key->new.akf_aid != 0xff) {
>> > + if (app_enc_key) *app_enc_key = app_key->new.key;
>> > + if (akf_aid) *akf_aid = app_key->new.akf_aid;
>> > + } else {
>> > + if (app_enc_key) *app_enc_key = app_key->current.key;
>> > + if (akf_aid) *akf_aid = app_key->current.akf_aid;
>> > + }
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool net_ctl_msg_send(uint8_t ttl, uint16_t src, uint16_t dst,
>> > + uint8_t *buf, uint16_t len)
>> > +{
>> > + struct mesh_node *node = node_get_local_node();
>> > + struct mesh_sar_msg sar_ctl;
>> > +
>> > + /* For simplicity, we will reject segmented OB CTL messages */
>> > + if (len > 12 || node == NULL || buf == NULL || buf[0] & 0x80)
>> > + return false;
>> > +
>> > + if (!src) {
>> > + src = node_get_primary(node);
>> > +
>> > + if (!src)
>> > + return false;
>> > + }
>> > +
>> > + if (ttl == 0xff)
>> > + ttl = net.default_ttl;
>> > +
>> > + memset(&sar_ctl, 0, sizeof(sar_ctl));
>> > +
>> > + if (!dst)
>> > + sar_ctl.proxy = true;
>> > +
>> > + /* Get the default net_idx for remote device (or local) */
>> > + get_enc_keys(APP_IDX_DEV, dst, NULL, NULL, &sar_ctl.net_idx);
>> > + sar_ctl.ctl = true;
>> > + sar_ctl.iv_index = net.iv_index - net.iv_update;
>> > + sar_ctl.ttl = ttl;
>> > + sar_ctl.src = src;
>> > + sar_ctl.dst = dst;
>> > + sar_ctl.len = len;
>> > + memcpy(sar_ctl.data, buf, len);
>> > + send_seg(&sar_ctl, 0);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool net_access_layer_send(uint8_t ttl, uint16_t src, uint32_t dst,
>> > + uint16_t app_idx, uint8_t *buf, uint16_t len)
>> > +{
>> > + struct mesh_node *node = node_get_local_node();
>> > + struct mesh_sar_msg *sar;
>> > + uint8_t *app_enc_key = NULL;
>> > + uint8_t *aad = NULL;
>> > + uint32_t mic32;
>> > + uint8_t aad_len = 0;
>> > + uint8_t i, j, ackless_retries = 0;
>> > + uint8_t segN, akf_aid;
>> > + uint16_t net_idx;
>> > + bool result;
>> > +
>> > + if (len > 384 || node == NULL)
>> > + return false;
>> > +
>> > + if (!src)
>> > + src = node_get_primary(node);
>> > +
>> > + if (!src || !dst)
>> > + return false;
>> > +
>> > + if (ttl == 0xff)
>> > + ttl = net.default_ttl;
>> > +
>> > + if (IS_VIRTUAL(dst)) {
>> > + struct mesh_virt_addr *virt = find_virt_by_dst(dst);
>> > +
>> > + if (virt == NULL)
>> > + return false;
>> > +
>> > + dst = virt->va16;
>> > + aad = virt->va128;
>> > + aad_len = sizeof(virt->va128);
>> > + }
>> > +
>> > + result = get_enc_keys(app_idx, dst,
>> > + &akf_aid, &app_enc_key, &net_idx);
>> > +
>> > + if (!result)
>> > + return false;
>> > +
>> > + segN = SEG_MAX(len);
>> > +
>> > + /* Only one ACK required SAR message per destination at a time */
>> > + if (segN && IS_UNICAST(dst)) {
>> > + sar = find_sar_out_by_dst(dst);
>> > +
>> > + if (sar)
>> > + flush_sar(&net.msg_out, sar);
>> > + }
>> > +
>> > + sar = g_malloc0(sizeof(struct mesh_sar_msg) + (segN * 12));
>> > +
>> > + if (sar == NULL)
>> > + return false;
>> > +
>> > + if (segN)
>> > + sar->segmented = true;
>> > +
>> > + sar->ttl = ttl;
>> > + sar->segN = segN;
>> > + sar->seqAuth = net.seq_num;
>> > + sar->iv_index = net.iv_index - net.iv_update;
>> > + sar->net_idx = net_idx;
>> > + sar->src = src;
>> > + sar->dst = dst;
>> > + sar->akf_aid = akf_aid;
>> > + sar->len = len + sizeof(uint32_t);
>> > +
>> > + mesh_crypto_application_encrypt(akf_aid,
>> > + sar->seqAuth, src,
>> > + dst, sar->iv_index,
>> > + app_enc_key,
>> > + aad, aad_len,
>> > + buf, len,
>> > + sar->data, &mic32,
>> > + sizeof(uint32_t));
>> > +
>> > + /* If sending as a segmented message to a non-Unicast (thus non-
>> ACKing)
>> > + * destination, send each segments multiple times. */
>> > + if (!IS_UNICAST(dst) && segN)
>> > + ackless_retries = 4;
>> > +
>> > + for (j = 0; j <= ackless_retries; j++) {
>> > + for (i = 0; i <= segN; i++)
>> > + send_seg(sar, i);
>> > + }
>> > +
>> > + if (IS_UNICAST(dst) && segN) {
>> > + net.msg_out = g_list_append(net.msg_out, sar);
>> > + sar->ack_to = g_timeout_add(2000, sar_out_ack_timeout, sar);
>> > + sar->msg_to = g_timeout_add(60000, sar_out_msg_timeout, sar);
>> > + } else
>> > + g_free(sar);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool net_set_default_ttl(uint8_t ttl)
>> > +{
>> > + if (ttl > 0x7f)
>> > + return false;
>> > +
>> > + net.default_ttl = ttl;
>> > + return true;
>> > +}
>> > +
>> > +uint8_t net_get_default_ttl()
>> > +{
>> > + return net.default_ttl;
>> > +}
>> > +
>> > +bool net_set_seq_num(uint32_t seq_num)
>> > +{
>> > + if (seq_num > 0xffffff)
>> > + return false;
>> > +
>> > + net.seq_num = seq_num;
>> > + return true;
>> > +}
>> > +
>> > +uint32_t net_get_seq_num()
>> > +{
>> > + return net.seq_num;
>> > +}
>> > diff --git a/mesh/node.c b/mesh/node.c
>> > new file mode 100644
>> > index 0000000..ba8d4b6
>> > --- /dev/null
>> > +++ b/mesh/node.c
>> > @@ -0,0 +1,879 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <sys/uio.h>
>> > +#include <wordexp.h>
>> > +
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "client/display.h"
>> > +#include "src/shared/util.h"
>> > +#include "gdbus/gdbus.h"
>> > +#include "monitor/uuid.h"
>> > +#include "mesh-net.h"
>> > +#include "config-model.h"
>> > +#include "node.h"
>> > +#include "keys.h"
>> > +#include "gatt.h"
>> > +#include "net.h"
>> > +#include "prov-db.h"
>> > +#include "util.h"
>> > +
>> > +struct mesh_model {
>> > + struct mesh_model_ops cbs;
>> > + void *user_data;
>> > + GList *bindings;
>> > + GList *subscriptions;
>> > + uint32_t id;
>> > + struct mesh_publication *pub;
>> > +};
>> > +
>> > +struct mesh_element {
>> > + GList *models;
>> > + uint16_t loc;
>> > + uint8_t index;
>> > +};
>> > +
>> > +struct mesh_node {
>> > + const char *name;
>> > + GList *net_keys;
>> > + GList *app_keys;
>> > + void *prov;
>> > + GList *elements;
>> > + uint32_t iv_index;
>> > + uint32_t seq_number;
>> > + uint16_t primary_net_idx;
>> > + uint16_t primary;
>> > + uint16_t oob;
>> > + uint16_t features;
>> > + uint8_t gatt_pkt[MAX_GATT_SIZE];
>> > + uint8_t dev_uuid[16];
>> > + uint8_t dev_key[16];
>> > + uint8_t num_ele;
>> > + uint8_t ttl;
>> > + uint8_t gatt_size;
>> > + bool provisioner;
>> > + struct mesh_node_composition *comp;
>> > +};
>> > +
>> > +static GList *nodes;
>> > +
>> > +static struct mesh_node *local_node;
>> > +
>> > +static int match_node_unicast(const void *a, const void *b)
>> > +{
>> > + const struct mesh_node *node = a;
>> > + uint16_t dst = GPOINTER_TO_UINT(b);
>> > +
>> > + if (dst >= node->primary &&
>> > + dst <= (node->primary + node->num_ele - 1))
>> > + return 0;
>> > +
>> > + return -1;
>> > +}
>> > +
>> > +static int match_device_uuid(const void *a, const void *b)
>> > +{
>> > + const struct mesh_node *node = a;
>> > + const uint8_t *uuid = b;
>> > +
>> > + return memcmp(node->dev_uuid, uuid, 16);
>> > +}
>> > +
>> > +static int match_element_idx(const void *a, const void *b)
>> > +{
>> > + const struct mesh_element *element = a;
>> > + uint32_t index = GPOINTER_TO_UINT(b);
>> > +
>> > + return (element->index == index) ? 0 : -1;
>> > +}
>> > +
>> > +static int match_model_id(const void *a, const void *b)
>> > +{
>> > + const struct mesh_model *model = a;
>> > + uint32_t id = GPOINTER_TO_UINT(b);
>> > +
>> > + return (model->id == id) ? 0 : -1;
>> > +}
>> > +
>> > +struct mesh_node *node_find_by_addr(uint16_t addr)
>> > +{
>> > + GList *l;
>> > +
>> > + if (!IS_UNICAST(addr))
>> > + return NULL;
>> > +
>> > + l = g_list_find_custom(nodes, GUINT_TO_POINTER(addr),
>> > + match_node_unicast);
>> > +
>> > + if (l)
>> > + return l->data;
>> > + else
>> > + return NULL;
>> > +}
>> > +
>> > +struct mesh_node *node_find_by_uuid(uint8_t uuid[16])
>> > +{
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(nodes, uuid, match_device_uuid);
>> > +
>> > + if (l)
>> > + return l->data;
>> > + else
>> > + return NULL;
>> > +}
>> > +
>> > +struct mesh_node *node_create_new(struct prov_svc_data *prov)
>> > +{
>> > + struct mesh_node *node;
>> > +
>> > + if (node_find_by_uuid(prov->dev_uuid))
>> > + return NULL;
>> > +
>> > + node = g_malloc0(sizeof(struct mesh_node));
>> > + if (!node)
>> > + return NULL;
>> > +
>> > + memcpy(node->dev_uuid, prov->dev_uuid, 16);
>> > + node->oob = prov->oob;
>> > + nodes = g_list_append(nodes, node);
>> > +
>> > + return node;
>> > +}
>> > +
>> > +struct mesh_node *node_new(void)
>> > +{
>> > + struct mesh_node *node;
>> > +
>> > + node = g_malloc0(sizeof(struct mesh_node));
>> > + if (!node)
>> > + return NULL;
>> > +
>> > + nodes = g_list_append(nodes, node);
>> > +
>> > + return node;
>> > +}
>> > +
>> > +static void model_free(void *data)
>> > +{
>> > + struct mesh_model *model = data;
>> > +
>> > + g_list_free(model->bindings);
>> > + g_list_free(model->subscriptions);
>> > + g_free(model->pub);
>> > + g_free(model);
>> > +}
>> > +
>> > +static void element_free(void *data)
>> > +{
>> > + struct mesh_element *element = data;
>> > +
>> > + g_list_free_full(element->models, model_free);
>> > + g_free(element);
>> > +}
>> > +
>> > +static void free_node_resources(void *data)
>> > +{
>> > + struct mesh_node *node = data;
>> > + g_list_free(node->net_keys);
>> > + g_list_free(node->app_keys);
>> > +
>> > + g_list_free_full(node->elements, element_free);
>> > +
>> > + if(node->comp)
>> > + g_free(node->comp);
>> > +
>> > + g_free(node);
>> > +}
>> > +
>> > +void node_free(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return;
>> > + nodes = g_list_remove(nodes, node);
>> > + free_node_resources(node);
>> > +}
>> > +
>> > +void node_cleanup(void)
>> > +{
>> > + g_list_free_full(nodes, free_node_resources);
>> > + local_node = NULL;
>> > +}
>> > +
>> > +bool node_is_provisioned(struct mesh_node *node)
>> > +{
>> > + return (!IS_UNASSIGNED(node->primary));
>> > +}
>> > +
>> > +void *node_get_prov(struct mesh_node *node)
>> > +{
>> > + return node->prov;
>> > +}
>> > +
>> > +void node_set_prov(struct mesh_node *node, void *prov)
>> > +{
>> > + node->prov = prov;
>> > +}
>> > +
>> > +bool node_app_key_add(struct mesh_node *node, uint16_t idx)
>> > +{
>> > + uint32_t index;
>> > + uint16_t net_idx;
>> > +
>> > + if (!node)
>> > + return false;
>> > +
>> > + net_idx = keys_app_key_get_bound(idx);
>> > + if (net_idx == NET_IDX_INVALID)
>> > + return false;
>> > +
>> > + if (!g_list_find(node->net_keys, GUINT_TO_POINTER(net_idx)))
>> > + return false;
>> > +
>> > + index = (net_idx << 16) + idx;
>> > +
>> > + if (g_list_find(node->app_keys, GUINT_TO_POINTER(index)))
>> > + return false;
>> > +
>> > + node->app_keys = g_list_append(node->app_keys,
>> GUINT_TO_POINTER(index));
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool node_net_key_add(struct mesh_node *node, uint16_t index)
>> > +{
>> > + if(!node)
>> > + return false;
>> > +
>> > + if (g_list_find(node->net_keys, GUINT_TO_POINTER(index)))
>> > + return false;
>> > +
>> > + node->net_keys = g_list_append(node->net_keys,
>> GUINT_TO_POINTER(index));
>> > + return true;
>> > +}
>> > +
>> > +bool node_net_key_delete(struct mesh_node *node, uint16_t index)
>> > +{
>> > + GList *l;
>> > +
>> > + if(!node)
>> > + return false;
>> > +
>> > + l = g_list_find(node->net_keys, GUINT_TO_POINTER(index));
>> > + if (!l)
>> > + return false;
>> > +
>> > + node->net_keys = g_list_remove(node->net_keys,
>> > + GUINT_TO_POINTER(index));
>> > + /* TODO: remove all associated app keys and bindings */
>> > + return true;
>> > +}
>> > +
>> > +bool node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
>> > + uint16_t idx)
>> > +{
>> > + GList *l;
>> > + uint32_t index;
>> > +
>> > + if(!node)
>> > + return false;
>> > +
>> > + index = (net_idx << 16) + idx;
>> > +
>> > + l = g_list_find(node->app_keys, GUINT_TO_POINTER(index));
>> > + if (!l)
>> > + return false;
>> > +
>> > + node->app_keys = g_list_remove(node->app_keys,
>> > + GUINT_TO_POINTER(index));
>> > + /* TODO: remove all associated bindings */
>> > + return true;
>> > +}
>> > +
>> > +void node_set_primary(struct mesh_node *node, uint16_t unicast)
>> > +{
>> > + node->primary = unicast;
>> > +}
>> > +
>> > +uint16_t node_get_primary(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return UNASSIGNED_ADDRESS;
>> > + else
>> > + return node->primary;
>> > +}
>> > +
>> > +void node_set_device_key(struct mesh_node *node, uint8_t *key)
>> > +
>> > +{
>> > + if (!node || !key)
>> > + return;
>> > +
>> > + memcpy(node->dev_key, key, 16);
>> > +}
>> > +
>> > +uint8_t *node_get_device_key(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return NULL;
>> > + else
>> > + return node->dev_key;
>> > +}
>> > +
>> > +void node_set_num_elements(struct mesh_node *node, uint8_t
>> num_ele)
>> > +{
>> > + node->num_ele = num_ele;
>> > +}
>> > +
>> > +uint8_t node_get_num_elements(struct mesh_node *node)
>> > +{
>> > + return node->num_ele;
>> > +}
>> > +
>> > +GList *node_get_net_keys(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return NULL;
>> > + else
>> > + return node->net_keys;
>> > +}
>> > +
>> > +GList *node_get_app_keys(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return NULL;
>> > + else
>> > + return node->app_keys;
>> > +}
>> > +
>> > +bool node_parse_composition(struct mesh_node *node, uint8_t *data,
>> uint16_t len)
>> > +{
>> > + struct mesh_node_composition *comp;
>> > + uint16_t features;
>> > + int i;
>> > +
>> > + comp = g_malloc0(sizeof(struct mesh_node_composition));
>> > + if (!comp)
>> > + return false;
>> > +
>> > + /* skip page -- We only support Page Zero */
>> > + data++;
>> > + len--;
>> > +
>> > + comp->cid = get_le16(&data[0]);
>> > + comp->pid = get_le16(&data[2]);
>> > + comp->vid = get_le16(&data[4]);
>> > + comp->crpl = get_le16(&data[6]);
>> > + features = get_le16(&data[8]);
>> > + data += 10;
>> > + len -= 10;
>> > +
>> > + comp->relay = !!(features & MESH_FEATURE_RELAY);
>> > + comp->proxy = !!(features & MESH_FEATURE_PROXY);
>> > + comp->friend = !!(features & MESH_FEATURE_FRIEND);
>> > + comp->lpn = !!(features & MESH_FEATURE_LPN);
>> > +
>> > + for (i = 0; i< node->num_ele; i++) {
>> > + uint8_t m, v;
>> > + uint32_t mod_id;
>> > + uint16_t vendor_id;
>> > + struct mesh_element *ele;
>> > + ele = g_malloc0(sizeof(struct mesh_element));
>> > + if (!ele)
>> > + return false;
>> > +
>> > + ele->index = i;
>> > + ele->loc = get_le16(data);
>> > + data += 2;
>> > + node->elements = g_list_append(node->elements, ele);
>> > +
>> > + m = *data++;
>> > + v = *data++;
>> > + len -= 4;
>> > +
>> > + while (len >= 2 && m--) {
>> > + mod_id = get_le16(data);
>> > + /* initialize uppper 16 bits to 0xffff for SIG models */
>> > + mod_id |= 0xffff0000;
>> > + if (!node_set_model(node, ele->index, mod_id))
>> > + return false;
>> > + data += 2;
>> > + len -= 2;
>> > + }
>> > + while (len >= 4 && v--) {
>> > + mod_id = get_le16(data);
>> > + vendor_id = get_le16(data);
>> > + mod_id |= (vendor_id << 16);
>> > + if (!node_set_model(node, ele->index, mod_id))
>> > + return false;
>> > + data += 4;
>> > + len -= 4;
>> > + }
>> > +
>> > + }
>> > +
>> > + node->comp = comp;
>> > + return true;
>> > +}
>> > +
>> > +bool node_set_local_node(struct mesh_node *node)
>> > +{
>> > + if (local_node) {
>> > + rl_printf("Local node already registered\n");
>> > + return false;
>> > + }
>> > + net_register_unicast(node->primary, node->num_ele);
>> > +
>> > + local_node = node;
>> > + local_node->provisioner = true;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +struct mesh_node *node_get_local_node()
>> > +{
>> > + return local_node;
>> > +}
>> > +
>> > +uint16_t node_get_primary_net_idx(struct mesh_node *node)
>> > +{
>> > + if (node == NULL)
>> > + return NET_IDX_INVALID;
>> > +
>> > + return node->primary_net_idx;
>> > +}
>> > +
>> > +static bool deliver_model_data(struct mesh_element* element, uint16_t
>> src,
>> > + uint16_t app_idx, uint8_t *data, uint16_t len)
>> > +{
>> > + GList *l;
>> > +
>> > + for(l = element->models; l; l = l->next) {
>> > + struct mesh_model *model = l->data;
>> > +
>> > + if (!g_list_find(model->bindings, GUINT_TO_POINTER(app_idx)))
>> > + continue;
>> > +
>> > + if (model->cbs.recv &&
>> > + model->cbs.recv(src, data, len, model->user_data))
>> > + return true;
>> > + }
>> > +
>> > + return false;
>> > +}
>> > +
>> > +void node_local_data_handler(uint16_t src, uint32_t dst,
>> > + uint32_t iv_index, uint32_t seq_num,
>> > + uint16_t app_idx, uint8_t *data, uint16_t len)
>> > +{
>> > + GList *l;
>> > + bool res;
>> > + uint64_t iv_seq;
>> > + uint64_t iv_seq_remote;
>> > + uint8_t ele_idx;
>> > + struct mesh_element *element;
>> > + struct mesh_node *remote;
>> > + bool loopback;
>> > +
>> > + if (!local_node || seq_num > 0xffffff)
>> > + return;
>> > +
>> > + iv_seq = iv_index << 24;
>> > + iv_seq |= seq_num;
>> > +
>> > + remote = node_find_by_addr(src);
>> > +
>> > + if (!remote) {
>> > + if (local_node->provisioner) {
>> > + rl_printf("Remote node unknown (%4.4x)\n", src);
>> > + return;
>> > + }
>> > +
>> > + remote = g_new0(struct mesh_node, 1);
>> > + if (!remote)
>> > + return;
>> > +
>> > + /* Not Provisioner; Assume all SRC elements stand alone */
>> > + remote->primary = src;
>> > + remote->num_ele = 1;
>> > + nodes = g_list_append(nodes, remote);
>> > + }
>> > +
>> > + loopback = (src < (local_node->primary + local_node->num_ele) &&
>> > + src >= local_node->primary);
>> > +
>> > + if (!loopback) {
>> > + iv_seq_remote = remote->iv_index << 24;
>> > + iv_seq |= remote->seq_number;
>> > +
>> > + if (iv_seq_remote >= iv_seq) {
>> > + rl_printf("Replayed message detected "
>> > + "(%14lx >= %14lx)\n",
>> > + iv_seq_remote, iv_seq);
>> > + return;
>> > + }
>> > + }
>> > +
>> > + if (IS_GROUP(dst) || IS_VIRTUAL(dst)) {
>> > + /* TODO: if subscription address, deliver to subscribers */
>> > + return;
>> > + }
>> > +
>> > + if (IS_ALL_NODES(dst)) {
>> > + ele_idx = 0;
>> > + } else {
>> > + if (dst >= (local_node->primary + local_node->num_ele) ||
>> > + dst < local_node->primary)
>> > + return;
>> > +
>> > + ele_idx = dst - local_node->primary;
>> > + }
>> > +
>> > + l = g_list_find_custom(local_node->elements,
>> > + GUINT_TO_POINTER(ele_idx), match_element_idx);
>> > +
>> > + /* This should not happen */
>> > + if (!l)
>> > + return;
>> > +
>> > + element = l->data;
>> > + res = deliver_model_data(element, src, app_idx, data, len);
>> > +
>> > + if (res && !loopback) {
>> > + /* TODO: Save remote in Replay Protection db */
>> > + remote->iv_index = iv_index;
>> > + remote->seq_number = seq_num;
>> > + prov_db_node_set_iv_seq(remote, iv_index, seq_num);
>> > + }
>> > +}
>> > +
>> > +static gboolean restore_model_state(gpointer data)
>> > +{
>> > + struct mesh_model *model = data;
>> > + GList *l;
>> > + struct mesh_model_ops *ops;
>> > +
>> > + ops = &model->cbs;
>> > +
>> > + if (model->bindings && ops->bind) {
>> > + for (l = model->bindings; l; l = l->next) {
>> > + if (ops->bind(GPOINTER_TO_UINT(l->data), ACTION_ADD) !=
>> > + MESH_STATUS_SUCCESS)
>> > + break;
>> > + }
>> > + }
>> > +
>> > + if (model->pub && ops->pub)
>> > + ops->pub(model->pub);
>> > +
>> > + g_idle_remove_by_data(data);
>> > +
>> > + return true;
>> > +
>> > +}
>> > +
>> > +bool node_local_model_register(uint8_t ele_idx, uint16_t model_id,
>> > + struct mesh_model_ops *ops, void *user_data)
>> > +{
>> > + uint32_t id = 0xffff0000 | model_id;
>> > +
>> > + return node_local_vendor_model_register(ele_idx, id, ops,
>> user_data);
>> > +}
>> > +
>> > +bool node_local_vendor_model_register(uint8_t ele_idx, uint32_t
>> model_id,
>> > + struct mesh_model_ops *ops, void *user_data)
>> > +{
>> > + struct mesh_element *ele;
>> > + struct mesh_model *model;
>> > + GList *l;
>> > +
>> > + if (!local_node)
>> > + return false;
>> > +
>> > + l = g_list_find_custom(local_node->elements,
>> GUINT_TO_POINTER(ele_idx),
>> > + match_element_idx);
>> > + if (!l)
>> > + return false;
>> > +
>> > + ele = l->data;
>> > +
>> > + l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
>> > + match_model_id);
>> > + if (!l)
>> > + return false;
>> > +
>> > + model = l->data;
>> > + model->cbs = *ops;
>> > + model->user_data = user_data;
>> > +
>> > + if (model_id >= 0xffff0000)
>> > + model_id = model_id & 0xffff;
>> > +
>> > + /* Silently assign device key binding to configuration models */
>> > + if (model_id == CONFIG_SERVER_MODEL_ID ||
>> > + model_id == CONFIG_CLIENT_MODEL_ID) {
>> > + model->bindings = g_list_append(model->bindings,
>> > + GUINT_TO_POINTER(APP_IDX_DEV));
>> > + } else {
>> > + g_idle_add(restore_model_state, model);
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool node_set_element(struct mesh_node *node, uint8_t ele_idx)
>> > +{
>> > + struct mesh_element *ele;
>> > + GList *l;
>> > +
>> > + if (!node)
>> > + return false;
>> > +
>> > + l = g_list_find_custom(node->elements,
>> GUINT_TO_POINTER(ele_idx),
>> > + match_element_idx);
>> > + if (l)
>> > + return false;
>> > +
>> > + ele = g_malloc0(sizeof(struct mesh_element));
>> > + if (!ele)
>> > + return false;
>> > +
>> > + ele->index = ele_idx;
>> > + node->elements = g_list_append(node->elements, ele);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool node_set_model(struct mesh_node *node, uint8_t ele_idx,
>> uint32_t id)
>> > +{
>> > + struct mesh_element *ele;
>> > + struct mesh_model *model;
>> > + GList *l;
>> > +
>> > + if (!node)
>> > + return false;
>> > +
>> > + l = g_list_find_custom(node->elements,
>> GUINT_TO_POINTER(ele_idx),
>> > + match_element_idx);
>> > + if (!l)
>> > + return false;
>> > +
>> > + ele = l->data;
>> > +
>> > + l = g_list_find_custom(ele->models, GUINT_TO_POINTER(id),
>> > + match_model_id);
>> > + if (l)
>> > + return false;
>> > +
>> > + model = g_malloc0(sizeof(struct mesh_model));
>> > + if (!model)
>> > + return false;
>> > +
>> > + model->id = id;
>> > + ele->models = g_list_append(ele->models, model);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool node_set_composition(struct mesh_node *node,
>> > + struct mesh_node_composition *comp)
>> > +{
>> > + if (!node || !comp || node->comp)
>> > + return false;
>> > +
>> > + node->comp = g_malloc0(sizeof(struct mesh_node_composition));
>> > + if (!node->comp)
>> > + return false;
>> > +
>> > + *(node->comp) = *comp;
>> > + return true;
>> > +}
>> > +
>> > +struct mesh_node_composition *node_get_composition(struct
>> mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return NULL;
>> > +
>> > + return node->comp;
>> > +}
>> > +
>> > +static struct mesh_model *get_model(struct mesh_node *node, uint8_t
>> ele_idx,
>> > + uint32_t model_id)
>> > +{
>> > + struct mesh_element *ele;
>> > + GList *l;
>> > +
>> > + if (!node)
>> > + return NULL;
>> > +
>> > + l = g_list_find_custom(node->elements,
>> GUINT_TO_POINTER(ele_idx),
>> > + match_element_idx);
>> > + if (!l)
>> > + return NULL;
>> > +
>> > + ele = l->data;
>> > +
>> > + l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
>> > + match_model_id);
>> > + if (!l)
>> > + return NULL;
>> > +
>> > + return l->data;
>> > +
>> > +}
>> > +
>> > +bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
>> > + uint32_t model_id, uint16_t app_idx)
>> > +{
>> > + struct mesh_model *model;
>> > + GList *l;
>> > +
>> > + model = get_model(node, ele_idx, model_id);
>> > + if(!model)
>> > + return false;
>> > +
>> > + l = g_list_find(model->bindings, GUINT_TO_POINTER(app_idx));
>> > + if (l)
>> > + return false;
>> > +
>> > + if ((node == local_node) && model->cbs.bind) {
>> > + if (!model->cbs.bind(app_idx, ACTION_ADD))
>> > + return false;
>> > + }
>> > +
>> > + model->bindings = g_list_append(model->bindings,
>> > + GUINT_TO_POINTER(app_idx));
>> > +
>> > + return true;
>> > +}
>> > +
>> > +uint8_t node_get_default_ttl(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return DEFAULT_TTL;
>> > + else if (node == local_node)
>> > + return net_get_default_ttl();
>> > + else
>> > + return node->ttl;
>> > +}
>> > +
>> > +bool node_set_default_ttl(struct mesh_node *node, uint8_t ttl)
>> > +{
>> > + if (!node)
>> > + return false;
>> > +
>> > + node->ttl = ttl;
>> > +
>> > + if (node == local_node || local_node == NULL)
>> > + return net_set_default_ttl(ttl);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool node_set_sequence_number(struct mesh_node *node, uint32_t
>> seq)
>> > +{
>> > + if (!node)
>> > + return false;
>> > +
>> > + node->seq_number = seq;
>> > +
>> > + if (node == local_node || local_node == NULL)
>> > + return net_set_seq_num(seq);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +uint32_t node_get_sequence_number(struct mesh_node *node)
>> > +{
>> > + if (!node)
>> > + return 0xffffffff;
>> > + else if (node == local_node)
>> > + return net_get_seq_num();
>> > +
>> > + return node->seq_number;
>> > +}
>> > +
>> > +bool node_set_iv_index(struct mesh_node *node, uint32_t iv_index)
>> > +{
>> > + if (!node)
>> > + return false;
>> > +
>> > + node->iv_index = iv_index;
>> > + return true;
>> > +}
>> > +
>> > +uint32_t node_get_iv_index(struct mesh_node *node)
>> > +{
>> > + bool update;
>> > +
>> > + if (!node)
>> > + return 0xffffffff;
>> > + else if (node == local_node)
>> > + return net_get_iv_index(&update);
>> > + return node->iv_index;
>> > +}
>> > +
>> > +bool node_model_pub_set(struct mesh_node *node, uint8_t ele,
>> uint32_t model_id,
>> > + struct mesh_publication *pub)
>> > +{
>> > + struct mesh_model *model;
>> > +
>> > + model = get_model(node, ele, model_id);
>> > + if(!model)
>> > + return false;
>> > +
>> > + if (!model->pub)
>> > + model->pub = g_malloc0(sizeof(struct mesh_publication));
>> > + if (!model)
>> > + return false;
>> > +
>> > + memcpy(model->pub, pub, (sizeof(struct mesh_publication)));
>> > +
>> > + if((node == local_node) && model->cbs.pub)
>> > + model->cbs.pub(pub);
>> > + return true;
>> > +}
>> > +
>> > +struct mesh_publication *node_model_pub_get(struct mesh_node
>> *node, uint8_t ele,
>> > + uint32_t model_id)
>> > +{
>> > + struct mesh_model *model;
>> > +
>> > + model = get_model(node, ele, model_id);
>> > + if(!model)
>> > + return NULL;
>> > + else
>> > + return model->pub;
>> > +}
>> > diff --git a/mesh/onoff-model.c b/mesh/onoff-model.c
>> > new file mode 100644
>> > index 0000000..61c6ed6
>> > --- /dev/null
>> > +++ b/mesh/onoff-model.c
>> > @@ -0,0 +1,306 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <inttypes.h>
>> > +#include <stdbool.h>
>> > +#include <sys/uio.h>
>> > +#include <wordexp.h>
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "client/display.h"
>> > +#include "src/shared/util.h"
>> > +#include "mesh-net.h"
>> > +#include "keys.h"
>> > +#include "net.h"
>> > +#include "node.h"
>> > +#include "prov-db.h"
>> > +#include "util.h"
>> > +#include "onoff-model.h"
>> > +
>> > +static uint8_t trans_id;
>> > +static uint16_t onoff_app_idx = APP_IDX_INVALID;
>> > +
>> > +static int client_bind(uint16_t app_idx, int action)
>> > +{
>> > + if (action == ACTION_ADD) {
>> > + if (onoff_app_idx != APP_IDX_INVALID) {
>> > + return MESH_STATUS_INSUFF_RESOURCES;
>> > + } else {
>> > + onoff_app_idx = app_idx;
>> > + rl_printf("On/Off client model: new binding %4.4x\n",
>> > + app_idx);
>> > + }
>> > + } else {
>> > + if (onoff_app_idx == app_idx)
>> > + onoff_app_idx = APP_IDX_INVALID;
>> > + }
>> > + return MESH_STATUS_SUCCESS;
>> > +}
>> > +
>> > +static void print_remaining_time(uint8_t remaining_time)
>> > +{
>> > + uint8_t step = (remaining_time & 0xc0) >> 6;
>> > + uint8_t count = remaining_time & 0x3f;
>> > + int secs = 0, msecs = 0, minutes = 0, hours = 0;
>> > +
>> > + switch (step) {
>> > + case 0:
>> > + msecs = 100 * count;
>> > + secs = msecs / 60;
>> > + msecs -= (secs * 60);
>> > + break;
>> > + case 1:
>> > + secs = 1 * count;
>> > + minutes = secs / 60;
>> > + secs -= (minutes * 60);
>> > + break;
>> > +
>> > + case 2:
>> > + secs = 10 * count;
>> > + minutes = secs / 60;
>> > + secs -= (minutes * 60);
>> > + break;
>> > + case 3:
>> > + minutes = 10 * count;
>> > + hours = minutes / 60;
>> > + minutes -= (hours * 60);
>> > + break;
>> > +
>> > + default:
>> > + break;
>> > + }
>> > +
>> > + rl_printf("\n\t\tRemaining time: %d hrs %d mins %d secs %d
>> msecs\n",
>> > + hours, minutes, secs, msecs);
>> > +
>> > +}
>> > +
>> > +static bool client_msg_recvd(uint16_t src, uint8_t *data,
>> > + uint16_t len, void *user_data)
>> > +{
>> > + uint32_t opcode;
>> > + int n;
>> > +
>> > + if (mesh_opcode_get(data, len, &opcode, &n)) {
>> > + len -= n;
>> > + data += n;
>> > + } else
>> > + return false;
>> > +
>> > + rl_printf("On Off Model Message received (%d) opcode %x\n",
>> > + len, opcode);
>> > + print_byte_array("\t",data, len);
>> > +
>> > + switch (opcode & ~OP_UNRELIABLE) {
>> > + default:
>> > + return false;
>> > +
>> > + case OP_GENERIC_ONOFF_STATUS:
>> > + if (len != 1 && len != 3)
>> > + break;
>> > +
>> > + rl_printf("Node %4.4x: Off Status present = %s",
>> > + src, data[0] ? "ON" : "OFF");
>> > +
>> > + if (len == 3) {
>> > + rl_printf(", target = %s", data[1] ? "ON" : "OFF");
>> > + print_remaining_time(data[2]);
>> > + } else
>> > + rl_printf("\n");
>> > + break;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +
>> > +static uint32_t target;
>> > +static uint32_t parms[8];
>> > +
>> > +static uint32_t read_input_parameters(const char *args)
>> > +{
>> > + uint32_t i;
>> > +
>> > + if (!args)
>> > + return 0;
>> > +
>> > + memset(parms, 0xff, sizeof(parms));
>> > +
>> > + for (i = 0; i < sizeof(parms)/sizeof(parms[0]); i++) {
>> > + int n;
>> > +
>> > + sscanf(args, "%x", &parms[i]);
>> > + if (parms[i] == 0xffffffff)
>> > + break;
>> > +
>> > + n = strcspn(args, " \t");
>> > + args = args + n + strspn(args + n, " \t");
>> > + }
>> > +
>> > + return i;
>> > +}
>> > +
>> > +static void cmd_set_node(const char *args)
>> > +{
>> > + uint32_t dst;
>> > + char *end;
>> > +
>> > + dst = strtol(args, &end, 16);
>> > + if (end != (args + 4)) {
>> > + rl_printf("Bad unicast address %s: "
>> > + "expected format 4 digit hex\n",
>> > + args);
>> > + target = UNASSIGNED_ADDRESS;
>> > + } else {
>> > + rl_printf("Controlling ON/OFF for node %4.4x\n", dst);
>> > + target = dst;
>> > + set_menu_prompt("on/off", args);
>> > + }
>> > +}
>> > +
>> > +static bool send_cmd(uint8_t *buf, uint16_t len)
>> > +{
>> > + struct mesh_node *node = node_get_local_node();
>> > + uint8_t ttl;
>> > +
>> > + if(!node)
>> > + return false;
>> > +
>> > + ttl = node_get_default_ttl(node);
>> > +
>> > + return net_access_layer_send(ttl, node_get_primary(node),
>> > + target, onoff_app_idx, buf, len);
>> > +}
>> > +
>> > +static void cmd_get_status(const char *args)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + struct mesh_node *node;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + node = node_find_by_addr(target);
>> > +
>> > + if (!node)
>> > + return;
>> > +
>> > + n = mesh_opcode_set(OP_GENERIC_ONOFF_GET, msg);
>> > +
>> > + if (!send_cmd(msg, n))
>> > + rl_printf("Failed to send \"GENERIC ON/OFF GET\"\n");
>> > +}
>> > +
>> > +static void cmd_set(const char *args)
>> > +{
>> > + uint16_t n;
>> > + uint8_t msg[32];
>> > + struct mesh_node *node;
>> > +
>> > + if (IS_UNASSIGNED(target)) {
>> > + rl_printf("Destination not set\n");
>> > + return;
>> > + }
>> > +
>> > + node = node_find_by_addr(target);
>> > +
>> > + if (!node)
>> > + return;
>> > +
>> > + if ((read_input_parameters(args) != 1) &&
>> > + parms[0] != 0 && parms[0] != 1) {
>> > + rl_printf("Bad arguments %s. Expecting \"0\" or \"1\"\n", args);
>> > + return;
>> > + }
>> > +
>> > + n = mesh_opcode_set(OP_GENERIC_ONOFF_SET, msg);
>> > + msg[n++] = parms[0];
>> > + msg[n++] = trans_id++;
>> > +
>> > + if (!send_cmd(msg, n))
>> > + rl_printf("Failed to send \"GENERIC ON/OFF SET\"\n");
>> > +
>> > +}
>> > +
>> > +static void cmd_back(const char *args)
>> > +{
>> > + cmd_menu_main(false);
>> > +}
>> > +
>> > +static void cmd_help(const char *args);
>> > +
>> > +static const struct menu_entry cfg_menu[] = {
>> > + {"target", "<unicast>", cmd_set_node,
>> > + "Set node to configure"},
>> > + {"get", NULL, cmd_get_status,
>> > + "Get ON/OFF status"},
>> > + {"onoff", "<0/1>", cmd_set,
>> > + "Send \"SET ON/OFF\" command"},
>> > + {"back", NULL, cmd_back,
>> > + "Back to main menu"},
>> > + {"help", NULL, cmd_help,
>> > + "Config Commands"},
>> > + {}
>> > +};
>> > +
>> > +static void cmd_help(const char *args)
>> > +{
>> > + rl_printf("Client Configuration Menu\n");
>> > + print_cmd_menu(cfg_menu);
>> > +}
>> > +
>> > +void onoff_set_node(const char *args) {
>> > + cmd_set_node(args);
>> > +}
>> > +
>> > +static struct mesh_model_ops client_cbs = {
>> > + client_msg_recvd,
>> > + client_bind,
>> > + NULL,
>> > + NULL
>> > +};
>> > +
>> > +bool onoff_client_init(uint8_t ele)
>> > +{
>> > + if (!node_local_model_register(ele,
>> GENERIC_ONOFF_CLIENT_MODEL_ID,
>> > + &client_cbs, NULL))
>> > + return false;
>> > +
>> > + add_cmd_menu("onoff", cfg_menu);
>> > +
>> > + return true;
>> > +}
>> > diff --git a/mesh/prov-db.c b/mesh/prov-db.c
>> > new file mode 100644
>> > index 0000000..aad6145
>> > --- /dev/null
>> > +++ b/mesh/prov-db.c
>> > @@ -0,0 +1,1599 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <errno.h>
>> > +#include <fcntl.h>
>> > +#include <glib.h>
>> > +#include <stdbool.h>
>> > +#include <stdio.h>
>> > +#include <stdlib.h>
>> > +#include <string.h>
>> > +#include <unistd.h>
>> > +
>> > +#include <json-c/json.h>
>> > +#include <sys/stat.h>
>> > +
>> > +#include <readline/readline.h>
>> > +#include <glib.h>
>> > +
>> > +#include "src/shared/util.h"
>> > +#include "client/display.h"
>> > +
>> > +#include "mesh-net.h"
>> > +#include "crypto.h"
>> > +#include "keys.h"
>> > +#include "net.h"
>> > +#include "node.h"
>> > +#include "util.h"
>> > +#include "prov-db.h"
>> > +
>> > +#define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
>> > +
>> > +static const char *prov_filename;
>> > +static const char *local_filename;
>> > +
>> > +static char* prov_file_read(const char *filename)
>> > +{
>> > + int fd;
>> > + char *str;
>> > + struct stat st;
>> > + ssize_t sz;
>> > +
>> > + if (!filename)
>> > + return NULL;
>> > +
>> > + fd = open(filename,O_RDONLY);
>> > + if (!fd)
>> > + return NULL;
>> > +
>> > + if (fstat(fd, &st) == -1) {
>> > + close(fd);
>> > + return NULL;
>> > + }
>> > +
>> > + str = (char *) g_malloc0(st.st_size + 1);
>> > + if (!str) {
>> > + close(fd);
>> > + return NULL;
>> > + }
>> > +
>> > + sz = read(fd, str, st.st_size);
>> > + if (sz != st.st_size)
>> > + rl_printf("Incomplete read: %d vs %d\n", (int)sz,
>> > + (int)(st.st_size));
>> > +
>> > + close(fd);
>> > +
>> > + return str;
>> > +}
>> > +
>> > +static void prov_file_write(json_object *jmain, bool local)
>> > +{
>> > + FILE *outfile;
>> > + const char *out_str;
>> > + const char *out_filename;
>> > +
>> > + if (local)
>> > + out_filename = local_filename;
>> > + else
>> > + out_filename = prov_filename;
>> > +
>> > + outfile = fopen(out_filename, "wr");
>> > + if (!outfile) {
>> > + rl_printf("Failed to open file %s for writing\n", out_filename);
>> > + return;
>> > + }
>> > +
>> > + out_str = json_object_to_json_string_ext(jmain,
>> > + JSON_C_TO_STRING_PRETTY);
>> > +
>> > + fwrite(out_str, sizeof(char), strlen(out_str), outfile);
>> > + fclose(outfile);
>> > +}
>> > +
>> > +static void put_uint16(json_object *jobject, const char *desc, uint16_t
>> value)
>> > +{
>> > + json_object *jstring;
>> > + char buf[5];
>> > +
>> > + snprintf(buf, 5, "%4.4x", value);
>> > + jstring = json_object_new_string(buf);
>> > + json_object_object_add(jobject, desc, jstring);
>> > +}
>> > +
>> > +static void put_uint32(json_object *jobject, const char *desc, uint32_t
>> value)
>> > +{
>> > + json_object *jstring;
>> > + char buf[9];
>> > +
>> > + snprintf(buf, 9, "%8.8x", value);
>> > + jstring = json_object_new_string(buf);
>> > + json_object_object_add(jobject, desc, jstring);
>> > +}
>> > +
>> > +static void put_uint16_array_entry(json_object *jarray, uint16_t value)
>> > +{
>> > + json_object *jstring;
>> > + char buf[5];
>> > +
>> > + snprintf(buf, 5, "%4.4x", value);
>> > + jstring = json_object_new_string(buf);
>> > + json_object_array_add(jarray, jstring);
>> > +}
>> > +
>> > +static void put_uint32_array_entry(json_object *jarray, uint32_t value)
>> > +{
>> > + json_object *jstring;
>> > + char buf[9];
>> > +
>> > + snprintf(buf, 9, "%8.8x", value);
>> > + jstring = json_object_new_string(buf);
>> > + json_object_array_add(jarray, jstring);
>> > +}
>> > +
>> > +static void put_uint16_list(json_object *jarray, GList *list)
>> > +{
>> > + GList *l;
>> > +
>> > + if (!list)
>> > + return;
>> > +
>> > + for (l = list; l; l = l->next) {
>> > + uint32_t ivalue = GPOINTER_TO_UINT(l->data);
>> > + put_uint16_array_entry(jarray, ivalue);
>> > + }
>> > +}
>> > +
>> > +static void add_node_idxs(json_object *jnode, const char *desc,
>> > + GList *idxs)
>> > +{
>> > + json_object *jarray;
>> > +
>> > + jarray = json_object_new_array();
>> > +
>> > + put_uint16_list(jarray, idxs);
>> > +
>> > + json_object_object_add(jnode, desc, jarray);
>> > +}
>> > +
>> > +static bool parse_unicast_range(json_object *jobject)
>> > +{
>> > + int cnt;
>> > + int i;
>> > +
>> > + cnt = json_object_array_length(jobject);
>> > +
>> > + for (i = 0; i < cnt; ++i) {
>> > + json_object *jrange;
>> > + json_object *jvalue;
>> > + uint16_t low, high;
>> > + char *str;
>> > +
>> > + jrange = json_object_array_get_idx(jobject, i);
>> > + json_object_object_get_ex(jrange, "lowAddress", &jvalue);
>> > + str = (char *)json_object_get_string(jvalue);
>> > + if (sscanf(str, "%04hx", &low) != 1)
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jrange, "highAddress", &jvalue);
>> > + str = (char *)json_object_get_string(jvalue);
>> > + if (sscanf(str, "%04hx", &high) != 1)
>> > + return false;
>> > +
>> > + if(high < low)
>> > + return false;
>> > +
>> > + net_add_address_pool(low, high);
>> > + }
>> > + return true;
>> > +}
>> > +
>> > +static int parse_node_keys(struct mesh_node *node, json_object *jidxs,
>> > + bool is_app_key)
>> > +{
>> > + int idx_cnt;
>> > + int i;
>> > +
>> > + idx_cnt = json_object_array_length(jidxs);
>> > + for (i = 0; i < idx_cnt; ++i) {
>> > + int idx;
>> > + json_object *jvalue;
>> > +
>> > + jvalue = json_object_array_get_idx(jidxs, i);
>> > + if (!jvalue)
>> > + break;
>> > + idx = json_object_get_int(jvalue);
>> > + if (!CHECK_KEY_IDX_RANGE(idx))
>> > + break;
>> > +
>> > + if (is_app_key)
>> > + node_app_key_add(node, idx);
>> > + else
>> > + node_net_key_add(node, idx);
>> > + }
>> > +
>> > + return i;
>> > +}
>> > +
>> > +static bool parse_composition_models(struct mesh_node *node, int
>> index,
>> > + json_object *jmodels)
>> > +{
>> > + int model_cnt;
>> > + int i;
>> > +
>> > + model_cnt = json_object_array_length(jmodels);
>> > +
>> > + for (i = 0; i < model_cnt; ++i) {
>> > + json_object *jmodel;
>> > + char *str;
>> > + uint32_t model_id;
>> > + int len;
>> > +
>> > + jmodel = json_object_array_get_idx(jmodels, i);
>> > + str = (char *)json_object_get_string(jmodel);
>> > + len = strlen(str);
>> > +
>> > + if (len != 4 && len != 8)
>> > + return false;
>> > +
>> > + if (sscanf(str, "%08x", &model_id) != 1)
>> > + return false;
>> > + if (len == 4)
>> > + model_id += 0xffff0000;
>> > +
>> > + node_set_model(node, index, model_id);
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_composition_elements(struct mesh_node *node,
>> > + json_object *jelements)
>> > +{
>> > + int el_cnt;
>> > + int i;
>> > +
>> > + el_cnt = json_object_array_length(jelements);
>> > + node_set_num_elements(node, el_cnt);
>> > +
>> > + for (i = 0; i < el_cnt; ++i) {
>> > + json_object *jelement;
>> > + json_object *jmodels;
>> > + json_object *jvalue;
>> > + int index;
>> > +
>> > + jelement = json_object_array_get_idx(jelements, i);
>> > + json_object_object_get_ex(jelement, "elementIndex", &jvalue);
>> > + if (jvalue) {
>> > + index = json_object_get_int(jvalue);
>> > + if (index >= el_cnt) {
>> > + return false;
>> > + }
>> > + } else
>> > + return false;
>> > +
>> > + if (!node_set_element(node, index))
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jelement, "models", &jmodels);
>> > + if (!jmodels)
>> > + continue;
>> > +
>> > + if(!parse_composition_models(node, index, jmodels))
>> > + return false;
>> > + }
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_model_pub(struct mesh_node *node, int ele_idx,
>> > + uint32_t model_id, json_object *jpub)
>> > +{
>> > + json_object *jvalue;
>> > + struct mesh_publication pub;
>> > + char *str;
>> > +
>> > + memset(&pub, 0, sizeof(struct mesh_publication));
>> > +
>> > + /* Read only required fields */
>> > + json_object_object_get_ex(jpub, "address", &jvalue);
>> > + if (!jvalue)
>> > + return false;
>> > +
>> > + str = (char *)json_object_get_string(jvalue);
>> > + if (sscanf(str, "%04hx", &pub.u.addr16) != 1)
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jpub, "index", &jvalue);
>> > + if (!jvalue)
>> > + return false;
>> > +
>> > + str = (char *)json_object_get_string(jvalue);
>> > + if (sscanf(str, "%04hx", &pub.app_idx) != 1)
>> > + return false;
>> > +
>> > +
>> > + json_object_object_get_ex(jpub, "ttl", &jvalue);
>> > + pub.ttl = json_object_get_int(jvalue);
>> > +
>> > + if (!node_model_pub_set(node, ele_idx, model_id, &pub))
>> > + return false;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_bindings(struct mesh_node *node, int ele_idx,
>> > + uint32_t model_id, json_object *jbindings)
>> > +{
>> > + int cnt;
>> > + int i;
>> > +
>> > + cnt = json_object_array_length(jbindings);
>> > +
>> > + for (i = 0; i < cnt; ++i) {
>> > + int key_idx;
>> > + json_object *jvalue;
>> > +
>> > + jvalue = json_object_array_get_idx(jbindings, i);
>> > + if (!jvalue)
>> > + return true;
>> > +
>> > + key_idx = json_object_get_int(jvalue);
>> > + if (!CHECK_KEY_IDX_RANGE(key_idx))
>> > + return false;
>> > +
>> > + if (!node_add_binding(node, ele_idx, model_id, key_idx))
>> > + return false;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_configuration_models(struct mesh_node *node, int
>> ele_idx,
>> > + json_object *jmodels, uint32_t target_id, json_object **jtarget)
>> > +{
>> > + int model_cnt;
>> > + int i;
>> > +
>> > + if (jtarget)
>> > + *jtarget = NULL;
>> > +
>> > + model_cnt = json_object_array_length(jmodels);
>> > +
>> > + for (i = 0; i < model_cnt; ++i) {
>> > + json_object *jmodel;
>> > + json_object *jvalue;
>> > + json_object *jarray;
>> > + char *str;
>> > + int len;
>> > + uint32_t model_id;
>> > +
>> > + jmodel = json_object_array_get_idx(jmodels, i);
>> > +
>> > + json_object_object_get_ex(jmodel, "modelId", &jvalue);
>> > + str = (char *)json_object_get_string(jvalue);
>> > +
>> > + len = strlen(str);
>> > +
>> > + if (len != 4 && len != 8)
>> > + return false;
>> > +
>> > + if (sscanf(str, "%08x", &model_id) != 1)
>> > + return false;
>> > + if (len == 4)
>> > + model_id += 0xffff0000;
>> > +
>> > + if (jtarget && model_id == target_id) {
>> > + *jtarget = jmodel;
>> > + return true;
>> > + }
>> > +
>> > + json_object_object_get_ex(jmodel, "bind", &jarray);
>> > + if (jarray && !parse_bindings(node, ele_idx, model_id, jarray))
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jmodel, "publish", &jvalue);
>> > +
>> > + if (jvalue && !parse_model_pub(node, ele_idx, model_id, jvalue))
>> > + return false;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +static bool parse_configuration_elements(struct mesh_node *node,
>> > + json_object *jelements, bool local)
>> > +{
>> > + int el_cnt;
>> > + int i;
>> > +
>> > + el_cnt = json_object_array_length(jelements);
>> > + node_set_num_elements(node, el_cnt);
>> > +
>> > + for (i = 0; i < el_cnt; ++i) {
>> > + json_object *jelement;
>> > + json_object *jmodels;
>> > + json_object *jvalue;
>> > + int index;
>> > + uint16_t addr;
>> > +
>> > + jelement = json_object_array_get_idx(jelements, i);
>> > + json_object_object_get_ex(jelement, "elementIndex", &jvalue);
>> > + if (jvalue) {
>> > + index = json_object_get_int(jvalue);
>> > + if (index >= el_cnt) {
>> > + return false;
>> > + }
>> > + } else
>> > + return false;
>> > +
>> > + if (index == 0) {
>> > + char *str;
>> > +
>> > + json_object_object_get_ex(jelement, "unicastAddress",
>> > + &jvalue);
>> > + str = (char *)json_object_get_string(jvalue);
>> > + if (sscanf(str, "%04hx", &addr) != 1)
>> > + return false;
>> > +
>> > + if (!local && !net_reserve_address_range(addr, el_cnt))
>> > + return false;
>> > +
>> > + node_set_primary(node, addr);
>> > + }
>> > +
>> > + json_object_object_get_ex(jelement, "models", &jmodels);
>> > + if (!jmodels)
>> > + continue;
>> > +
>> > + if(!parse_configuration_models(node, index, jmodels, 0, NULL))
>> > + return false;
>> > + }
>> > + return true;
>> > +}
>> > +
>> > +static void add_key(json_object *jobject, const char *desc, uint8_t* key)
>> > +{
>> > + json_object *jstring;
>> > + char hexstr[33];
>> > +
>> > + hex2str(key, 16, hexstr, 33);
>> > + jstring = json_object_new_string(hexstr);
>> > + json_object_object_add(jobject, desc, jstring);
>> > +}
>> > +
>> > +static json_object *find_node_by_primary(json_object *jmain, uint16_t
>> primary)
>> > +{
>> > + json_object *jarray;
>> > + int i, len;
>> > +
>> > + json_object_object_get_ex(jmain, "nodes", &jarray);
>> > +
>> > + if (!jarray)
>> > + return NULL;
>> > + len = json_object_array_length(jarray);
>> > +
>> > + for (i = 0; i < len; ++i) {
>> > + json_object *jnode;
>> > + json_object *jconfig;
>> > + json_object *jelements;
>> > + json_object *jelement;
>> > + json_object *jvalue;
>> > + char *str;
>> > + uint16_t addr;
>> > +
>> > + jnode = json_object_array_get_idx(jarray, i);
>> > + if (!jnode)
>> > + return NULL;
>> > +
>> > + json_object_object_get_ex(jnode, "configuration", &jconfig);
>> > + if (!jconfig)
>> > + return NULL;
>> > +
>> > + json_object_object_get_ex(jconfig, "elements", &jelements);
>> > + if (!jelements)
>> > + return NULL;
>> > +
>> > + jelement = json_object_array_get_idx(jelements, 0);
>> > + if (!jelement)
>> > + return NULL;
>> > +
>> > + json_object_object_get_ex(jelement, "unicastAddress",
>> > + &jvalue);
>> > + str = (char *)json_object_get_string(jvalue);
>> > + if (sscanf(str, "%04hx", &addr) != 1)
>> > + return NULL;
>> > +
>> > + if (addr == primary)
>> > + return jnode;
>> > + }
>> > +
>> > + return NULL;
>> > +
>> > +}
>> > +
>> > +void prov_db_print_node_composition(struct mesh_node *node)
>> > +{
>> > + char *in_str;
>> > + const char *comp_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + json_object *jcomp;
>> > + uint16_t primary = node_get_primary(node);
>> > + const char *filename;
>> > + bool res = false;
>> > +
>> > + if (!node || !node_get_composition(node))
>> > + return;
>> > +
>> > + if (node == node_get_local_node())
>> > + filename = local_filename;
>> > + else
>> > + filename = prov_filename;
>> > +
>> > + in_str = prov_file_read(filename);
>> > + if (!in_str)
>> > + return;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + jnode = find_node_by_primary(jmain, primary);
>> > + if (!jnode)
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jnode, "composition", &jcomp);
>> > + if (!jcomp)
>> > + goto done;
>> > +
>> > + comp_str = json_object_to_json_string_ext(jcomp,
>> > + JSON_C_TO_STRING_PRETTY);
>> > +
>> > + res = true;
>> > +
>> > +done:
>> > + if (res)
>> > + rl_printf("\tComposition data for node %4.4x %s\n",
>> > + primary, comp_str);
>> > + else
>> > + rl_printf("\tComposition data for node %4.4x not present\n",
>> > + primary);
>> > + g_free(in_str);
>> > +
>> > + if (jmain)
>> > + json_object_put(jmain);
>> > +}
>> > +
>> > +bool prov_db_add_node_composition(struct mesh_node *node, uint8_t
>> *data,
>> > + uint16_t len)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + json_object *jcomp;
>> > + json_object *jbool;
>> > + json_object *jfeatures;
>> > + json_object *jelements;
>> > + struct mesh_node_composition *comp;
>> > + uint8_t num_ele;
>> > + int i;
>> > + uint16_t primary = node_get_primary(node);
>> > + bool res = NULL;
>> > +
>> > + comp = node_get_composition(node);
>> > + if (!comp)
>> > + return false;
>> > +
>> > + in_str = prov_file_read(prov_filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + jnode = find_node_by_primary(jmain, primary);
>> > + if (!jnode)
>> > + goto done;
>> > +
>> > + jcomp = json_object_new_object();
>> > +
>> > + put_uint16(jcomp, "cid", comp->cid);
>> > + put_uint16(jcomp, "pid", comp->pid);
>> > + put_uint16(jcomp, "vid", comp->pid);
>> > + put_uint16(jcomp, "crpl", comp->crpl);
>> > +
>> > + jfeatures = json_object_new_object();
>> > + jbool = json_object_new_boolean(comp->relay);
>> > + json_object_object_add(jfeatures, "relay", jbool);
>> > + jbool = json_object_new_boolean(comp->proxy);
>> > + json_object_object_add(jfeatures, "proxy", jbool);
>> > + jbool = json_object_new_boolean(comp->friend);
>> > + json_object_object_add(jfeatures, "friend", jbool);
>> > + jbool = json_object_new_boolean(comp->lpn);
>> > + json_object_object_add(jfeatures, "lpn", jbool);
>> > + json_object_object_add(jcomp, "features", jfeatures);
>> > +
>> > + data += 11;
>> > + len -= 11;
>> > +
>> > + num_ele = node_get_num_elements(node);
>> > +
>> > + jelements = json_object_new_array();
>> > +
>> > + for (i = 0; i < num_ele; ++i) {
>> > + json_object *jelement;
>> > + json_object *jmodels;
>> > + json_object *jint;
>> > + uint32_t mod_id;
>> > + uint16_t vendor_id;
>> > + uint8_t m, v;
>> > +
>> > + jelement = json_object_new_object();
>> > +
>> > + /* Element Index */
>> > + jint = json_object_new_int(i);
>> > + json_object_object_add(jelement, "elementIndex", jint);
>> > +
>> > + /* Location */
>> > + put_uint16(jelement, "location", get_le16(data));
>> > + data += 2;
>> > + m = *data++;
>> > + v = *data++;
>> > + len -= 4;
>> > +
>> > + /* Models */
>> > + jmodels = json_object_new_array();
>> > + while (len >= 2 && m--) {
>> > + mod_id = get_le16(data);
>> > + data += 2;
>> > + len -= 2;
>> > + put_uint16_array_entry(jmodels, (uint16_t) mod_id);
>> > + }
>> > +
>> > + while (len >= 4 && v--) {
>> > + mod_id = get_le16(data);
>> > + vendor_id = get_le16(data);
>> > + mod_id |= (vendor_id << 16);
>> > + data += 4;
>> > + len -= 4;
>> > + put_uint32_array_entry(jmodels, mod_id);
>> > + }
>> > +
>> > + json_object_object_add(jelement, "models", jmodels);
>> > + json_object_array_add(jelements, jelement);
>> > + }
>> > +
>> > + json_object_object_add(jcomp, "elements", jelements);
>> > +
>> > + json_object_object_add(jnode, "composition", jcomp);
>> > +
>> > + prov_file_write(jmain, false);
>> > +
>> > + res = true;;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +}
>> > +
>> > +bool prov_db_node_set_ttl(struct mesh_node *node, uint8_t ttl)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + json_object *jconfig;
>> > + json_object *jvalue;
>> > + uint16_t primary = node_get_primary(node);
>> > + const char *filename;
>> > + bool local = node == node_get_local_node();
>> > + bool res = false;
>> > +
>> > + if (local)
>> > + filename = local_filename;
>> > + else
>> > + filename = prov_filename;
>> > +
>> > + in_str = prov_file_read(filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + if (local)
>> > + json_object_object_get_ex(jmain, "node", &jnode);
>> > + else
>> > + jnode = find_node_by_primary(jmain, primary);
>> > +
>> > + if (!jnode)
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jnode, "configuration", &jconfig);
>> > + if (!jconfig)
>> > + goto done;
>> > +
>> > + json_object_object_del(jconfig, "defaultTTL");
>> > +
>> > + jvalue = json_object_new_int(ttl);
>> > + json_object_object_add(jconfig, "defaultTTL", jvalue);
>> > +
>> > + prov_file_write(jmain, local);
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +
>> > +}
>> > +
>> > +static void set_local_iv_index(json_object *jobj, uint32_t idx, bool
>> update)
>> > +{
>> > + json_object *jvalue;
>> > +
>> > + json_object_object_del(jobj, "IVindex");
>> > + jvalue = json_object_new_int(idx);
>> > + json_object_object_add(jobj, "IVindex", jvalue);
>> > +
>> > + json_object_object_del(jobj, "IVupdate");
>> > + jvalue = json_object_new_int((update) ? 1 : 0);
>> > + json_object_object_add(jobj, "IVupdate", jvalue);
>> > +
>> > +}
>> > +
>> > +bool prov_db_local_set_iv_index(uint32_t iv_index, bool update, bool
>> prov)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + bool res = false;
>> > +
>> > + in_str = prov_file_read(local_filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jmain, "node", &jnode);
>> > + set_local_iv_index(jnode, iv_index, update);
>> > + prov_file_write(jmain, true);
>> > +
>> > + g_free(in_str);
>> > + json_object_put(jmain);
>> > +
>> > + /* If provisioner, save to global DB as well */
>> > + if (prov) {
>> > + in_str = prov_file_read(prov_filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + set_local_iv_index(jmain, iv_index, update);
>> > + prov_file_write(jmain, false);
>> > + }
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +
>> > +}
>> > +
>> > +bool prov_db_local_set_seq_num(uint32_t seq_num)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + json_object *jvalue;
>> > + bool res = false;
>> > +
>> > + in_str = prov_file_read(local_filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jmain, "node", &jnode);
>> > +
>> > + json_object_object_del(jnode, "sequenceNumber");
>> > + jvalue = json_object_new_int(seq_num);
>> > + json_object_object_add(jnode, "sequenceNumber", jvalue);
>> > +
>> > + prov_file_write(jmain, true);
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +}
>> > +
>> > +bool prov_db_node_set_iv_seq(struct mesh_node *node, uint32_t iv,
>> uint32_t seq)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + json_object *jvalue;
>> > + uint16_t primary = node_get_primary(node);
>> > + bool res = false;
>> > +
>> > + in_str = prov_file_read(prov_filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + jnode = find_node_by_primary(jmain, primary);
>> > + if (!jnode)
>> > + goto done;
>> > +
>> > + json_object_object_del(jnode, "IVindex");
>> > +
>> > + jvalue = json_object_new_int(iv);
>> > + json_object_object_add(jnode, "IVindex", jvalue);
>> > +
>> > + json_object_object_del(jnode, "sequenceNumber");
>> > +
>> > + jvalue = json_object_new_int(seq);
>> > + json_object_object_add(jnode, "sequenceNumber", jvalue);
>> > +
>> > + prov_file_write(jmain, false);
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +
>> > +}
>> > +
>> > +bool prov_db_node_keys(struct mesh_node *node, GList *idxs, const
>> char *desc)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jnode;
>> > + json_object *jconfig;
>> > + json_object *jidxs;
>> > + uint16_t primary = node_get_primary(node);
>> > + const char *filename;
>> > + bool local = (node == node_get_local_node());
>> > + bool res = false;
>> > +
>> > + if (local)
>> > + filename = local_filename;
>> > + else
>> > + filename = prov_filename;
>> > +
>> > + in_str = prov_file_read(filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + jnode = find_node_by_primary(jmain, primary);
>> > + if (!jnode)
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jnode, "configuration", &jconfig);
>> > + if (!jconfig)
>> > + goto done;
>> > +
>> > + json_object_object_del(jconfig, desc);
>> > +
>> > + if (idxs) {
>> > + jidxs = json_object_new_array();
>> > + put_uint16_list(jidxs, idxs);
>> > + json_object_object_add(jconfig, desc, jidxs);
>> > + }
>> > +
>> > + prov_file_write(jmain, local);
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +
>> > +}
>> > +
>> > +static json_object *get_jmodel_obj(struct mesh_node *node, uint8_t
>> ele_idx,
>> > + uint32_t model_id, json_object **jmain)
>> > +{
>> > + char *in_str;
>> > + json_object *jnode;
>> > + json_object *jconfig;
>> > + json_object *jelements, *jelement;
>> > + json_object *jmodels, *jmodel = NULL;
>> > + uint16_t primary = node_get_primary(node);
>> > + const char *filename;
>> > + bool local = (node == node_get_local_node());
>> > +
>> > + if (local)
>> > + filename = local_filename;
>> > + else
>> > + filename = prov_filename;
>> > +
>> > + in_str = prov_file_read(filename);
>> > + if (!in_str)
>> > + return NULL;
>> > +
>> > + *jmain = json_tokener_parse(in_str);
>> > + if (!(*jmain))
>> > + goto done;
>> > +
>> > + if (local)
>> > + json_object_object_get_ex(*jmain, "node", &jnode);
>> > + else
>> > + jnode = find_node_by_primary(*jmain, primary);
>> > +
>> > + if (!jnode)
>> > + goto done;
>> > +
>> > + /* Configuration is mandatory for nodes in provisioning database */
>> > + json_object_object_get_ex(jnode, "configuration", &jconfig);
>> > + if (!jconfig)
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jconfig, "elements", &jelements);
>> > + if (!jelements) {
>> > + goto done;
>> > + }
>> > +
>> > + jelement = json_object_array_get_idx(jelements, ele_idx);
>> > + if (!jelement) {
>> > + goto done;
>> > + }
>> > +
>> > + json_object_object_get_ex(jelement, "models", &jmodels);
>> > +
>> > + if (!jmodels) {
>> > + jmodels = json_object_new_array();
>> > + json_object_object_add(jelement, "models", jmodels);
>> > + } else {
>> > + parse_configuration_models(node, ele_idx, jmodels,
>> > + model_id, &jmodel);
>> > + }
>> > +
>> > + if (!jmodel) {
>> > + jmodel = json_object_new_object();
>> > +
>> > + if ((model_id & 0xffff0000) == 0xffff0000)
>> > + put_uint16(jmodel, "modelId", model_id & 0xffff);
>> > + else
>> > + put_uint32(jmodel, "modelId", model_id);
>> > +
>> > + json_object_array_add(jmodels, jmodel);
>> > + }
>> > +
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if(!jmodel && *jmain)
>> > + json_object_put(*jmain);
>> > +
>> > + return jmodel;
>> > +
>> > +}
>> > +
>> > +bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx,
>> > + uint32_t model_id, uint16_t app_idx)
>> > +{
>> > + json_object *jmain;
>> > + json_object *jmodel;
>> > + json_object *jvalue;
>> > + json_object *jbindings = NULL;
>> > + bool local = (node == node_get_local_node());
>> > +
>> > + jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
>> > +
>> > + if (!jmodel)
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jmodel, "bind", &jbindings);
>> > +
>> > + if (!jbindings) {
>> > + jbindings = json_object_new_array();
>> > + json_object_object_add(jmodel, "bind", jbindings);
>> > + }
>> > +
>> > + jvalue = json_object_new_int(app_idx);
>> > + json_object_array_add(jbindings, jvalue);
>> > +
>> > + prov_file_write(jmain, local);
>> > +
>> > + json_object_put(jmain);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool prov_db_node_set_model_pub(struct mesh_node *node, uint8_t
>> ele_idx,
>> > + uint32_t model_id,
>> > + struct mesh_publication *pub)
>> > +{
>> > + json_object *jmain;
>> > + json_object *jmodel;
>> > + json_object *jpub;
>> > + json_object *jvalue;
>> > + bool local = (node == node_get_local_node());
>> > +
>> > + jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
>> > +
>> > + if (!jmodel)
>> > + return false;
>> > +
>> > + json_object_object_del(jmodel, "publish");
>> > + if (!pub)
>> > + goto done;
>> > +
>> > + jpub = json_object_new_object();
>> > +
>> > + /* Save only required fields */
>> > + put_uint16(jpub, "address", pub->u.addr16);
>> > + put_uint16(jpub, "index", pub->app_idx);
>> > + jvalue = json_object_new_int(pub->ttl);
>> > + json_object_object_add(jpub, "ttl", jvalue);
>> > +
>> > + json_object_object_add(jmodel, "publish", jpub);
>> > +
>> > +done:
>> > + prov_file_write(jmain, local);
>> > +
>> > + json_object_put(jmain);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool prov_db_add_new_node(struct mesh_node *node)
>> > +{
>> > + char *in_str;
>> > + json_object *jmain;
>> > + json_object *jarray;
>> > + json_object *jnode;
>> > + json_object *jconfig;
>> > + json_object *jelements;
>> > + uint8_t num_ele;
>> > + uint16_t primary;
>> > + int i;
>> > + bool first_node;
>> > + bool res = false;
>> > +
>> > + in_str = prov_file_read(prov_filename);
>> > + if (!in_str)
>> > + return false;
>> > +
>> > + jmain = json_tokener_parse(in_str);
>> > + if (!jmain)
>> > + goto done;
>> > + json_object_object_get_ex(jmain, "nodes", &jarray);
>> > +
>> > + if (!jarray) {
>> > + jarray = json_object_new_array();
>> > + first_node = true;
>> > + } else
>> > + first_node = false;
>> > +
>> > + jnode = json_object_new_object();
>> > +
>> > + /* Device key */
>> > + add_key(jnode, "deviceKey", node_get_device_key(node));
>> > +
>> > + /* Net key */
>> > + jconfig = json_object_new_object();
>> > + add_node_idxs(jconfig, "netKeys", node_get_net_keys(node));
>> > +
>> > + num_ele = node_get_num_elements(node);
>> > + if (num_ele == 0)
>> > + goto done;
>> > +
>> > + jelements = json_object_new_array();
>> > +
>> > + primary = node_get_primary(node);
>> > + if (IS_UNASSIGNED(primary))
>> > + goto done;
>> > +
>> > + for (i = 0; i < num_ele; ++i) {
>> > + json_object *jelement;
>> > + json_object *jint;
>> > +
>> > + jelement = json_object_new_object();
>> > +
>> > + /* Element Index */
>> > + jint = json_object_new_int(i);
>> > + json_object_object_add(jelement, "elementIndex", jint);
>> > +
>> > + /* Unicast */
>> > + put_uint16(jelement, "unicastAddress", primary + i);
>> > +
>> > + json_object_array_add(jelements, jelement);
>> > + }
>> > +
>> > + json_object_object_add(jconfig, "elements", jelements);
>> > +
>> > + json_object_object_add(jnode, "configuration", jconfig);
>> > +
>> > + json_object_array_add(jarray, jnode);
>> > +
>> > + if (first_node)
>> > + json_object_object_add(jmain, "nodes", jarray);
>> > +
>> > + prov_file_write(jmain, false);
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(in_str);
>> > +
>> > + if (jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +}
>> > +
>> > +static bool parse_node_composition(struct mesh_node *node,
>> json_object *jcomp)
>> > +{
>> > + json_object *jvalue;
>> > + json_object *jelements;
>> > + json_bool enable;
>> > + char *str;
>> > + struct mesh_node_composition comp;
>> > +
>> > + json_object_object_get_ex(jcomp, "cid", &jvalue);
>> > + if (!jvalue)
>> > + return false;
>> > +
>> > + str = (char *)json_object_get_string(jvalue);
>> > +
>> > + if (sscanf(str, "%04hx", &comp.cid) != 1)
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jcomp, "pid", &jvalue);
>> > + if (!jvalue)
>> > + return false;
>> > +
>> > + str = (char *)json_object_get_string(jvalue);
>> > +
>> > + if (sscanf(str, "%04hx", &comp.vid) != 1)
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jcomp, "vid", &jvalue);
>> > + if (!jvalue)
>> > + return false;
>> > +
>> > + str = (char *)json_object_get_string(jvalue);
>> > +
>> > + if (sscanf(str, "%04hx", &comp.vid) != 1)
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jcomp, "crpl", &jvalue);
>> > + if (!jvalue)
>> > + return false;
>> > +
>> > + str = (char *)json_object_get_string(jvalue);
>> > +
>> > + if (sscanf(str, "%04hx", &comp.crpl) != 1)
>> > + return false;
>> > +
>> > + /* Extract features */
>> > + json_object_object_get_ex(jcomp, "relay", &jvalue);
>> > + enable = json_object_get_boolean(jvalue);
>> > + comp.relay = (enable) ? true : false;
>> > +
>> > + json_object_object_get_ex(jcomp, "proxy", &jvalue);
>> > + enable = json_object_get_boolean(jvalue);
>> > + comp.proxy = (enable) ? true : false;
>> > +
>> > + json_object_object_get_ex(jcomp, "friend", &jvalue);
>> > + enable = json_object_get_boolean(jvalue);
>> > + comp.friend = (enable) ? true : false;
>> > +
>> > + json_object_object_get_ex(jcomp, "lowPower", &jvalue);
>> > + enable = json_object_get_boolean(jvalue);
>> > + comp.lpn = (enable) ? true : false;
>> > +
>> > + if (!node_set_composition(node, &comp))
>> > + return false;
>> > +
>> > + json_object_object_get_ex(jcomp, "elements", &jelements);
>> > + if (!jelements)
>> > + return false;
>> > +
>> > + return parse_composition_elements(node, jelements);
>> > +}
>> > +
>> > +static bool parse_node(json_object *jnode, bool local)
>> > +{
>> > + json_object *jconfig;
>> > + json_object *jelements;
>> > + json_object *jidxs;
>> > + json_object *jvalue;
>> > + json_object *jint;
>> > + uint8_t key[16];
>> > + char *value_str;
>> > + uint32_t idx;
>> > + struct mesh_node *node;
>> > +
>> > + /* Device key */
>> > + if (!json_object_object_get_ex(jnode, "deviceKey", &jvalue) ||
>> > + !jvalue) {
>> > + if (!mesh_get_random_bytes(key, 16))
>> > + return false;
>> > +
>> > + add_key(jnode, "deviceKey", key);
>> > + } else {
>> > + value_str = (char *)json_object_get_string(jvalue);
>> > + if (!str2hex(value_str, strlen(value_str), key, 16))
>> > + return false;;
>> > + }
>> > +
>> > + node = node_new();
>> > +
>> > + if (!node)
>> > + return false;
>> > +
>> > + node_set_device_key(node, key);
>> > +
>> > + json_object_object_get_ex(jnode, "IVindex", &jint);
>> > + if (jint)
>> > + idx = json_object_get_int(jint);
>> > + else
>> > + idx = 0;
>> > +
>> > + node_set_iv_index(node, idx);
>> > + if (local) {
>> > + bool update = false;
>> > + json_object_object_get_ex(jnode, "IVupdate", &jint);
>> > + if (jint)
>> > + update = json_object_get_int(jint) ? true : false;
>> > + net_set_iv_index(idx, update);
>> > + }
>> > +
>> > + if (json_object_object_get_ex(jnode, "sequenceNumber", &jint) &&
>> > + jint) {
>> > + int seq = json_object_get_int(jint);
>> > + node_set_sequence_number(node, seq);
>> > + }
>> > +
>> > + /* Composition is mandatory for local node */
>> > + json_object_object_get_ex(jnode, "composition", &jconfig);
>> > + if ((jconfig && !parse_node_composition(node, jconfig)) ||
>> > + (!jconfig && local)) {
>> > + node_free(node);
>> > + return false;
>> > + }
>> > +
>> > + /* Configuration is mandatory for nodes in provisioning database */
>> > + json_object_object_get_ex(jnode, "configuration", &jconfig);
>> > + if (!jconfig) {
>> > + if (local) {
>> > + /* This is an unprovisioned local device */
>> > + goto done;
>> > + } else {
>> > + node_free(node);
>> > + return false;
>> > + }
>> > + }
>> > +
>> > + json_object_object_get_ex(jconfig, "elements", &jelements);
>> > + if (!jelements) {
>> > + node_free(node);
>> > + return false;
>> > + }
>> > +
>> > + if (!parse_configuration_elements(node, jelements, local)) {
>> > + node_free(node);
>> > + return false;;
>> > + }
>> > +
>> > + json_object_object_get_ex(jconfig, "netKeys", &jidxs);
>> > + if (!jidxs || (parse_node_keys(node, jidxs, false) == 0)) {
>> > + node_free(node);
>> > + return false;
>> > + }
>> > +
>> > + json_object_object_get_ex(jconfig, "appKeys", &jidxs);
>> > + if (jidxs)
>> > + parse_node_keys(node, jidxs, true);
>> > +
>> > + json_object_object_get_ex(jconfig, "defaultTTL", &jvalue);
>> > + if (jvalue) {
>> > + int ttl = json_object_get_int(jvalue);
>> > + node_set_default_ttl(node, ttl &TTL_MASK);
>> > + }
>> > +
>> > +done:
>> > + if (local && !node_set_local_node(node)) {
>> > + node_free(node);
>> > + return false;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool prov_db_show(const char *filename)
>> > +{
>> > + char *str;
>> > +
>> > + str = prov_file_read(filename);
>> > + if (!str)
>> > + return false;
>> > +
>> > + rl_printf("%s\n", str);
>> > + g_free(str);
>> > + return true;
>> > +}
>> > +
>> > +static bool read_json_db(const char *filename, bool provisioner, bool
>> local)
>> > +{
>> > + char *str;
>> > + json_object *jmain;
>> > + json_object *jarray;
>> > + json_object *jprov;
>> > + json_object *jvalue;
>> > + json_object *jtemp;
>> > + uint8_t key[16];
>> > + int value_int;
>> > + char *value_str;
>> > + int len;
>> > + int i;
>> > + uint32_t index;
>> > + bool refresh = false;
>> > + bool res = false;
>> > +
>> > + str = prov_file_read(filename);
>> > + if (!str) return false;
>> > +
>> > + jmain = json_tokener_parse(str);
>> > + if (!jmain)
>> > + goto done;
>> > +
>> > + if (local) {
>> > + json_object *jnode;
>> > + bool result;
>> > +
>> > + json_object_object_get_ex(jmain, "node", &jnode);
>> > + if (!jnode) {
>> > + rl_printf("Cannot find \"node\" object");
>> > + goto done;
>> > + } else
>> > + result = parse_node(jnode, true);
>> > +
>> > + /*
>> > + * If local node is provisioner, the rest of mesh settings
>> > + * are read from provisioning database.
>> > + */
>> > + if (provisioner) {
>> > + res = result;
>> > + goto done;
>> > + }
>> > + }
>> > +
>> > + /* IV index */
>> > + json_object_object_get_ex(jmain, "IVindex", &jvalue);
>> > + if (!jvalue)
>> > + goto done;
>> > +
>> > + index = json_object_get_int(jvalue);
>> > +
>> > + json_object_object_get_ex(jmain, "IVupdate", &jvalue);
>> > + if (!jvalue)
>> > + goto done;
>> > +
>> > + value_int = json_object_get_int(jvalue);
>> > +
>> > + net_set_iv_index(index, value_int);
>> > +
>> > + /* Network key(s) */
>> > + json_object_object_get_ex(jmain, "netKeys", &jarray);
>> > + if (!jarray)
>> > + goto done;
>> > +
>> > + len = json_object_array_length(jarray);
>> > + rl_printf("# netkeys = %d\n", len);
>> > +
>> > + for (i = 0; i < len; ++i) {
>> > + uint32_t idx;
>> > +
>> > + jtemp = json_object_array_get_idx(jarray, i);
>> > + json_object_object_get_ex(jtemp, "index", &jvalue);
>> > + if (!jvalue)
>> > + goto done;
>> > + idx = json_object_get_int(jvalue);
>> > +
>> > + json_object_object_get_ex(jtemp, "key", &jvalue);
>> > + if (!jvalue) {
>> > + if (!mesh_get_random_bytes(key, 16))
>> > + goto done;
>> > + add_key(jtemp, "key", key);
>> > + refresh = true;
>> > + } else {
>> > + value_str = (char *)json_object_get_string(jvalue);
>> > + if (!str2hex(value_str, strlen(value_str), key, 16)) {
>> > + goto done;
>> > + }
>> > + }
>> > +
>> > + if (!keys_net_key_add(idx, key, false))
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jtemp, "keyRefresh", &jvalue);
>> > + if (!jvalue)
>> > + goto done;
>> > +
>> > + keys_set_kr_phase(idx, (uint8_t) json_object_get_int(jvalue));
>> > + }
>> > +
>> > + /* App keys */
>> > + json_object_object_get_ex(jmain, "appKeys", &jarray);
>> > + if (jarray) {
>> > + len = json_object_array_length(jarray);
>> > + rl_printf("# appkeys = %d\n", len);
>> > +
>> > + for (i = 0; i < len; ++i) {
>> > + int app_idx;
>> > + int net_idx;
>> > +
>> > + jtemp = json_object_array_get_idx(jarray, i);
>> > + json_object_object_get_ex(jtemp, "index",
>> > + &jvalue);
>> > + if (!jvalue)
>> > + goto done;
>> > +
>> > + app_idx = json_object_get_int(jvalue);
>> > + if (!CHECK_KEY_IDX_RANGE(app_idx))
>> > + goto done;
>> > +
>> > + json_object_object_get_ex(jtemp, "key", &jvalue);
>> > + if (!jvalue) {
>> > + if (!mesh_get_random_bytes(key, 16))
>> > + goto done;
>> > + add_key(jtemp, "key", key);
>> > + refresh = true;
>> > + } else {
>> > + value_str =
>> > + (char *)json_object_get_string(jvalue);
>> > + str2hex(value_str, strlen(value_str), key, 16);
>> > + }
>> > +
>> > + json_object_object_get_ex(jtemp, "boundNetKey",
>> > + &jvalue);
>> > + if (!jvalue)
>> > + goto done;
>> > +
>> > + net_idx = json_object_get_int(jvalue);
>> > + if (!CHECK_KEY_IDX_RANGE(net_idx))
>> > + goto done;
>> > +
>> > + keys_app_key_add(net_idx, app_idx, key, false);
>> > + }
>> > + }
>> > +
>> > + /* Provisioner info */
>> > + json_object_object_get_ex(jmain, "provisioners", &jarray);
>> > + if (!jarray)
>> > + goto done;
>> > +
>> > + len = json_object_array_length(jarray);
>> > + rl_printf("# provisioners = %d\n", len);
>> > +
>> > + for (i = 0; i < len; ++i) {
>> > +
>> > + jprov = json_object_array_get_idx(jarray, i);
>> > +
>> > + /* Allocated unicast range */
>> > + json_object_object_get_ex(jprov, "allocatedUnicastRange",
>> > + &jtemp);
>> > + if (!jtemp) {
>> > + goto done;
>> > + }
>> > +
>> > + if (!parse_unicast_range(jtemp)) {
>> > + rl_printf("Doneed to parse unicast range\n");
>> > + goto done;
>> > + }
>> > + }
>> > +
>> > + json_object_object_get_ex(jmain, "nodes", &jarray);
>> > + if (!jarray) {
>> > + res = true;
>> > + goto done;
>> > + }
>> > +
>> > + len = json_object_array_length(jarray);
>> > +
>> > + rl_printf("# provisioned nodes = %d\n", len);
>> > + for (i = 0; i < len; ++i) {
>> > + json_object *jnode;
>> > + jnode = json_object_array_get_idx(jarray, i);
>> > +
>> > + if (!jnode || !parse_node(jnode, false))
>> > + goto done;
>> > + }
>> > +
>> > + res = true;
>> > +done:
>> > +
>> > + g_free(str);
>> > +
>> > + if (res && refresh)
>> > + prov_file_write(jmain, false);
>> > +
>> > + if (jmain)
>> > + json_object_put(jmain);
>> > +
>> > + return res;
>> > +}
>> > +
>> > +bool prov_db_read(const char *filename)
>> > +{
>> > + prov_filename = filename;
>> > + return read_json_db(filename, true, false);
>> > +}
>> > +
>> > +bool prov_db_read_local_node(const char *filename, bool provisioner)
>> > +{
>> > + local_filename = filename;
>> > + return read_json_db(filename, provisioner, true);
>> > +}
>> > diff --git a/mesh/prov.c b/mesh/prov.c
>> > new file mode 100644
>> > index 0000000..89fc884
>> > --- /dev/null
>> > +++ b/mesh/prov.c
>> > @@ -0,0 +1,664 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <errno.h>
>> > +#include <unistd.h>
>> > +#include <stdlib.h>
>> > +#include <stdbool.h>
>> > +#include <sys/uio.h>
>> > +#include <wordexp.h>
>> > +
>> > +#include <readline/readline.h>
>> > +#include <readline/history.h>
>> > +#include <glib.h>
>> > +
>> > +#include "src/shared/util.h"
>> > +#include "src/shared/ecc.h"
>> > +
>> > +#include "gdbus/gdbus.h"
>> > +#include "monitor/uuid.h"
>> > +#include "client/display.h"
>> > +#include "node.h"
>> > +#include "gatt.h"
>> > +#include "crypto.h"
>> > +#include "mesh-net.h"
>> > +#include "util.h"
>> > +#include "agent.h"
>> > +#include "prov.h"
>> > +#include "net.h"
>> > +
>> > +/* Provisioning Security Levels */
>> > +#define MESH_PROV_SEC_HIGH 2
>> > +#define MESH_PROV_SEC_MED 1
>> > +#define MESH_PROV_SEC_LOW 0
>> > +
>> > +/* For Deployment, Security levels below HIGH are *not* recomended */
>> > +#define mesh_gatt_prov_security() MESH_PROV_SEC_MED
>> > +
>> > +#define PROV_INVITE 0x00
>> > +#define PROV_CAPS 0x01
>> > +#define PROV_START 0x02
>> > +#define PROV_PUB_KEY 0x03
>> > +#define PROV_INP_CMPLT 0x04
>> > +#define PROV_CONFIRM 0x05
>> > +#define PROV_RANDOM 0x06
>> > +#define PROV_DATA 0x07
>> > +#define PROV_COMPLETE 0x08
>> > +#define PROV_FAILED 0x09
>> > +
>> > +#define PROV_NO_OOB 0
>> > +#define PROV_STATIC_OOB 1
>> > +#define PROV_OUTPUT_OOB 2
>> > +#define PROV_INPUT_OOB 3
>> > +
>> > +#define PROV_ERR_INVALID_PDU 0x01
>> > +#define PROV_ERR_INVALID_FORMAT 0x02
>> > +#define PROV_ERR_UNEXPECTED_PDU 0x03
>> > +#define PROV_ERR_CONFIRM_FAILED 0x04
>> > +#define PROV_ERR_INSUF_RESOURCE 0x05
>> > +#define PROV_ERR_DECRYPT_FAILED 0x06
>> > +#define PROV_ERR_UNEXPECTED_ERR 0x07
>> > +#define PROV_ERR_CANT_ASSIGN_ADDR 0x08
>> > +
>> > +/* Expected Provisioning PDU sizes */
>> > +static const uint16_t expected_pdu_size[] = {
>> > + 1 + 1, /* PROV_INVITE */
>> > + 1 + 1 + 2 + 1 + 1 + 1 + 2 + 1 + 2, /* PROV_CAPS */
>> > + 1 + 1 + 1 + 1 + 1 + 1, /* PROV_START */
>> > + 1 + 64, /* PROV_PUB_KEY */
>> > + 1, /* PROV_INP_CMPLT */
>> > + 1 + 16, /* PROV_CONFIRM */
>> > + 1 + 16, /* PROV_RANDOM */
>> > + 1 + 16 + 2 + 1 + 4 + 2 + 8, /* PROV_DATA */
>> > + 1, /* PROV_COMPLETE */
>> > + 1 + 1, /* PROV_FAILED */
>> > +};
>> > +
>> > +typedef struct __packed {
>> > + uint8_t attention;
>> > +} __attribute__ ((packed)) prov_invite;
>> > +
>> > +typedef struct {
>> > + uint8_t num_ele;
>> > + uint16_t algorithms;
>> > + uint8_t pub_type;
>> > + uint8_t static_type;
>> > + uint8_t output_size;
>> > + uint16_t output_action;
>> > + uint8_t input_size;
>> > + uint16_t input_action;
>> > +} __attribute__ ((packed)) prov_caps;
>> > +
>> > +typedef struct {
>> > + uint8_t algorithm;
>> > + uint8_t pub_key;
>> > + uint8_t auth_method;
>> > + uint8_t auth_action;
>> > + uint8_t auth_size;
>> > +} __attribute__ ((packed)) prov_start;
>> > +
>> > +typedef struct {
>> > + prov_invite invite;
>> > + prov_caps caps;
>> > + prov_start start;
>> > + uint8_t prv_pub_key[64];
>> > + uint8_t dev_pub_key[64];
>> > +} __attribute__ ((packed)) conf_input;
>> > +
>> > +struct prov_data {
>> > + GDBusProxy *prov_in;
>> > + provision_done_cb prov_done;
>> > + void *user_data;
>> > + uint16_t net_idx;
>> > + uint16_t new_addr;
>> > + uint8_t state;
>> > + uint8_t eph_priv_key[32];
>> > + uint8_t ecdh_secret[32];
>> > + conf_input conf_in;
>> > + uint8_t rand_auth[32];
>> > + uint8_t salt[16];
>> > + uint8_t conf_key[16];
>> > + uint8_t mesh_conf[16];
>> > + uint8_t dev_key[16];
>> > +};
>> > +
>> > +static uint8_t u16_highest_bit(uint16_t mask)
>> > +{
>> > + uint8_t cnt = 0;
>> > +
>> > + if (!mask) return 0xff;
>> > +
>> > + while (mask & 0xfffe) {
>> > + cnt++;
>> > + mask >>= 1;
>> > + }
>> > +
>> > + return cnt;
>> > +}
>> > +
>> > +bool prov_open(struct mesh_node *node, GDBusProxy *prov_in,
>> uint16_t net_idx,
>> > + provision_done_cb cb, void *user_data)
>> > +{
>> > + uint8_t invite[] = { PROXY_PROVISIONING_PDU, PROV_INVITE, 0x10 };
>> > + struct prov_data *prov = node_get_prov(node);
>> > +
>> > + if (prov) return false;
>> > +
>> > + prov = g_new0(struct prov_data, 1);
>> > + prov->prov_in = prov_in;
>> > + prov->net_idx = net_idx;
>> > + prov->prov_done = cb;
>> > + prov->user_data = user_data;
>> > + node_set_prov(node, prov);
>> > + prov->conf_in.invite.attention = invite[2];
>> > + prov->state = PROV_INVITE;
>> > +
>> > + rl_printf("Open-Node: %p\n", node);
>> > + rl_printf("Open-Prov: %p\n", prov);
>> > + rl_printf("Open-Prov: proxy %p\n", prov_in);
>> > +
>> > + return mesh_gatt_write(prov_in, invite, sizeof(invite), NULL, node);
>> > +}
>> > +
>> > +static bool prov_send_prov_data(void *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > + uint8_t out[35] = { PROXY_PROVISIONING_PDU, PROV_DATA };
>> > + uint8_t key[16];
>> > + uint8_t nonce[13];
>> > + uint64_t mic;
>> > +
>> > + if (prov == NULL) return false;
>> > +
>> > + mesh_crypto_session_key(prov->ecdh_secret, prov->salt, key);
>> > + mesh_crypto_nonce(prov->ecdh_secret, prov->salt, nonce);
>> > + mesh_crypto_device_key(prov->ecdh_secret, prov->salt, prov-
>> >dev_key);
>> > +
>> > + print_byte_array("S-Key\t", key, sizeof(key));
>> > + print_byte_array("S-Nonce\t", nonce, sizeof(nonce));
>> > + print_byte_array("DevKey\t", prov->dev_key, sizeof(prov-
>> >dev_key));
>> > +
>> > + if (!net_get_key(prov->net_idx, out + 2))
>> > + return false;
>> > +
>> > + put_be16(prov->net_idx, out + 2 + 16);
>> > + net_get_flags(prov->net_idx, out + 2 + 16 + 2);
>> > + put_be32(net_get_iv_index(NULL), out + 2 + 16 + 2 + 1);
>> > + put_be16(prov->new_addr, out + 2 + 16 + 2 + 1 + 4);
>> > +
>> > + print_byte_array("Data\t", out + 2, 16 + 2 + 1 + 4 + 2);
>> > +
>> > + mesh_crypto_aes_ccm_encrypt(nonce, key,
>> > + NULL, 0,
>> > + out + 2,
>> > + sizeof(out) - 2 - sizeof(mic),
>> > + out + 2,
>> > + &mic, sizeof(mic));
>> > +
>> > + print_byte_array("DataEncrypted + mic\t", out + 2, sizeof(out) - 2);
>> > +
>> > + prov->state = PROV_DATA;
>> > + return mesh_gatt_write(prov->prov_in, out, sizeof(out), NULL, node);
>> > +}
>> > +
>> > +static bool prov_send_confirm(void *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > + uint8_t out[18] = { PROXY_PROVISIONING_PDU, PROV_CONFIRM };
>> > +
>> > + if (prov == NULL) return false;
>> > +
>> > + mesh_get_random_bytes(prov->rand_auth, 16);
>> > +
>> > + mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
>> > + sizeof(prov->rand_auth), out + 2);
>> > +
>> > + prov->state = PROV_CONFIRM;
>> > + return mesh_gatt_write(prov->prov_in, out, sizeof(out), NULL, node);
>> > +}
>> > +
>> > +static void prov_out_oob_done(oob_type_t type, void *buf, uint16_t len,
>> > + void *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > +
>> > + if (prov == NULL) return;
>> > +
>> > + switch (type) {
>> > + default:
>> > + case NONE:
>> > + case OUTPUT:
>> > + prov_complete(node, PROV_ERR_INVALID_PDU);
>> > + return;
>> > +
>> > + case ASCII:
>> > + case HEXADECIMAL:
>> > + if (len > 16)
>> > + prov_complete(node, PROV_ERR_INVALID_PDU);
>> > +
>> > + memcpy(prov->rand_auth + 16, buf, len);
>> > + break;
>> > +
>> > + case DECIMAL:
>> > + if (len != 4)
>> > + prov_complete(node, PROV_ERR_INVALID_PDU);
>> > +
>> > + memcpy(prov->rand_auth +
>> > + sizeof(prov->rand_auth) -
>> > + sizeof(uint32_t),
>> > + buf, len);
>> > + break;
>> > + }
>> > +
>> > + prov_send_confirm(node);
>> > +}
>> > +
>> > +static uint32_t power_ten(uint8_t power)
>> > +{
>> > + uint32_t ret = 1;
>> > +
>> > + while (power--)
>> > + ret *= 10;
>> > +
>> > + return ret;
>> > +}
>> > +
>> > +char *in_action[3] = {
>> > + "Push",
>> > + "Twist",
>> > + "Enter"
>> > +};
>> > +
>> > +static void prov_calc_ecdh(DBusMessage *message, void *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > + uint8_t action = prov->conf_in.start.auth_action;
>> > + uint8_t size = prov->conf_in.start.auth_size;
>> > + char in_oob_display[100];
>> > + uint8_t *tmp = (void *) in_oob_display;
>> > + uint32_t in_oob;
>> > +
>> > + if (prov == NULL) return;
>> > +
>> > + /* Convert to Mesh byte order */
>> > + memcpy(tmp, prov->conf_in.dev_pub_key, 64);
>> > + swap_u256_bytes(tmp);
>> > + swap_u256_bytes(tmp + 32);
>> > +
>> > + ecdh_shared_secret(tmp, prov->eph_priv_key, prov->ecdh_secret);
>> > +
>> > + /* Convert to Mesh byte order */
>> > + swap_u256_bytes(prov->ecdh_secret);
>> > +
>> > + mesh_crypto_s1(&prov->conf_in,
>> > + sizeof(prov->conf_in), prov->salt);
>> > +
>> > + mesh_crypto_prov_conf_key(prov->ecdh_secret,
>> > + prov->salt, prov->conf_key);
>> > +
>> > + switch (prov->conf_in.start.auth_method) {
>> > + default:
>> > + prov_complete(node, PROV_ERR_INVALID_PDU);
>> > + break;
>> > +
>> > + case 0: /* No OOB */
>> > + prov_send_confirm(node);
>> > + break;
>> > +
>> > + case 1: /* Static OOB */
>> > + agent_input_request(HEXADECIMAL,
>> > + 16,
>> > + prov_out_oob_done, node);
>> > + break;
>> > +
>> > + case 2: /* Output OOB */
>> > + if (action <= 3)
>> > + agent_input_request(DECIMAL,
>> > + size,
>> > + prov_out_oob_done, node);
>> > + else
>> > + agent_input_request(ASCII,
>> > + size,
>> > + prov_out_oob_done, node);
>> > + break;
>> > +
>> > + case 3: /* Input OOB */
>> > +
>> > + if (action <= 2) {
>> > + mesh_get_random_bytes(&in_oob, sizeof(in_oob));
>> > + in_oob %= power_ten(size);
>> > + sprintf(in_oob_display, "%s %d on device\n",
>> > + in_action[action], in_oob);
>> > + put_be32(in_oob,
>> > + prov->rand_auth +
>> > + sizeof(prov->rand_auth) -
>> > + sizeof(uint32_t));
>> > + } else {
>> > + uint8_t in_ascii[9];
>> > + int i = size;
>> > +
>> > + mesh_get_random_bytes(in_ascii, i);
>> > +
>> > + while (i--) {
>> > + in_ascii[i] =
>> > + in_ascii[i] % ((26 * 2) + 10);
>> > + if (in_ascii[i] >= 10 + 26)
>> > + in_ascii[i] += 'a' - (10 + 26);
>> > + else if (in_ascii[i] >= 10)
>> > + in_ascii[i] += 'A' - 10;
>> > + else
>> > + in_ascii[i] += '0';
>> > + }
>> > + in_ascii[size] = '\0';
>> > + memcpy(prov->rand_auth + 16, in_ascii, size);
>> > + sprintf(in_oob_display,
>> > + "Enter %s on device\n",
>> > + in_ascii);
>> > + }
>> > + rl_printf("Agent String: %s\n", in_oob_display);
>> > + agent_output_request(in_oob_display);
>> > + break;
>> > + }
>> > +}
>> > +
>> > +static void prov_send_pub_key(struct mesh_node *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > + uint8_t out[66] = { PROXY_PROVISIONING_PDU, PROV_PUB_KEY };
>> > + GDBusReturnFunction cb = NULL;
>> > +
>> > + if (prov == NULL) return;
>> > +
>> > + if (prov->conf_in.start.pub_key)
>> > + cb = prov_calc_ecdh;
>> > +
>> > + memcpy(out + 2, prov->conf_in.prv_pub_key, 64);
>> > + prov->state = PROV_PUB_KEY;
>> > + mesh_gatt_write(prov->prov_in, out, 66, cb, node);
>> > +}
>> > +
>> > +static void prov_oob_pub_key(oob_type_t type, void *buf, uint16_t len,
>> > + void *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > +
>> > + if (prov == NULL) return;
>> > +
>> > + memcpy(prov->conf_in.dev_pub_key, buf, 64);
>> > + prov_send_pub_key(node);
>> > +}
>> > +
>> > +static void prov_start_cmplt(DBusMessage *message, void *node)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > +
>> > + if (prov == NULL) return;
>> > +
>> > + if (prov->conf_in.start.pub_key)
>> > + agent_input_request(HEXADECIMAL, 64, prov_oob_pub_key,
>> node);
>> > + else
>> > + prov_send_pub_key(node);
>> > +}
>> > +
>> > +bool prov_data_ready(struct mesh_node *node, uint8_t *buf, uint8_t
>> len)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > + uint8_t sec_level = MESH_PROV_SEC_HIGH;
>> > + uint8_t out[35] = { PROXY_PROVISIONING_PDU };
>> > +
>> > + if (prov == NULL || len < 2) return false;
>> > +
>> > + buf++;
>> > + len--;
>> > +
>> > + rl_printf("Got provisioning data (%d bytes)\n", len);
>> > +
>> > + if (buf[0] > PROV_FAILED || expected_pdu_size[buf[0]] != len)
>> > + return prov_complete(node, PROV_ERR_INVALID_PDU);
>> > +
>> > + print_byte_array("\t", buf, len);
>> > +
>> > + if (buf[0] == PROV_FAILED)
>> > + return prov_complete(node, buf[1]);
>> > +
>> > + /* Check provisioning state */
>> > + switch (prov->state) {
>> > + default:
>> > + return prov_complete(node, PROV_ERR_INVALID_PDU);
>> > +
>> > + case PROV_INVITE:
>> > +
>> > + if (buf[0] != PROV_CAPS)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + /* Normalize to beginning of packed Param struct */
>> > + buf++;
>> > + len--;
>> > +
>> > + /* Save Capability values */
>> > + memcpy(&prov->conf_in.caps, buf, len);
>> > +
>> > + sec_level = mesh_gatt_prov_security();
>> > +
>> > + if (sec_level == MESH_PROV_SEC_HIGH) {
>> > +
>> > + /* Enforce High Security */
>> > + if (prov->conf_in.caps.pub_type != 1 &&
>> > + prov->conf_in.caps.static_type != 1)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + } else if (sec_level == MESH_PROV_SEC_MED) {
>> > +
>> > + /* Enforce Medium Security */
>> > + if (prov->conf_in.caps.pub_type != 1 &&
>> > + prov->conf_in.caps.static_type != 1 &&
>> > + prov->conf_in.caps.input_size == 0 &&
>> > + prov->conf_in.caps.output_size == 0)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + }
>> > +
>> > + /* Num Elements cannot be Zero */
>> > + if (prov->conf_in.caps.num_ele == 0)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + /* All nodes must support Algorithm 0x0001 */
>> > + if (!(get_be16(buf + 1) & 0x0001))
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + /* Pub Key and Static type may not be > 1 */
>> > + if (prov->conf_in.caps.pub_type > 0x01 ||
>> > + prov->conf_in.caps.static_type > 0x01)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + prov->new_addr =
>> > + net_obtain_address(prov->conf_in.caps.num_ele);
>> > +
>> > + if (!prov->new_addr)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + out[1] = PROV_START;
>> > + prov->conf_in.start.algorithm = 0;
>> > + prov->conf_in.start.pub_key =
>> > + prov->conf_in.caps.pub_type;
>> > +
>> > + /* Compose START based on most secure values */
>> > + if (prov->conf_in.caps.static_type) {
>> > +
>> > + prov->conf_in.start.auth_method =
>> > + PROV_STATIC_OOB;
>> > +
>> > + } else if (prov->conf_in.caps.output_size >
>> > + prov->conf_in.caps.input_size) {
>> > +
>> > + prov->conf_in.start.auth_method =
>> > + PROV_OUTPUT_OOB;
>> > + prov->conf_in.start.auth_action =
>> > + u16_highest_bit(get_be16(buf + 6));
>> > + prov->conf_in.start.auth_size =
>> > + prov->conf_in.caps.output_size;
>> > +
>> > + } else if (prov->conf_in.caps.input_size > 0) {
>> > +
>> > + prov->conf_in.start.auth_method =
>> > + PROV_INPUT_OOB;
>> > + prov->conf_in.start.auth_action =
>> > + u16_highest_bit(get_be16(buf + 9));
>> > + prov->conf_in.start.auth_size =
>> > + prov->conf_in.caps.input_size;
>> > + }
>> > +
>> > + /* Range Check START values */
>> > + if (prov->conf_in.start.auth_size > 8)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + prov->state = PROV_START;
>> > +
>> > + memcpy(out + 2, &prov->conf_in.start, 5);
>> > +
>> > + ecc_make_key(prov->conf_in.prv_pub_key,
>> > + prov->eph_priv_key);
>> > +
>> > + /* Swap public key to share into Mesh byte ordering */
>> > + swap_u256_bytes(prov->conf_in.prv_pub_key);
>> > + swap_u256_bytes(prov->conf_in.prv_pub_key + 32);
>> > +
>> > + return mesh_gatt_write(prov->prov_in, out, 7,
>> > + prov_start_cmplt, node);
>> > +
>> > +
>> > + case PROV_PUB_KEY:
>> > + if (buf[0] == PROV_PUB_KEY &&
>> > + !prov->conf_in.start.pub_key) {
>> > +
>> > + memcpy(prov->conf_in.dev_pub_key, buf + 1, 64);
>> > + prov_calc_ecdh(NULL, node);
>> > + return true;
>> > +
>> > + } else if (buf[0] == PROV_INP_CMPLT) {
>> > + agent_output_request_cancel();
>> > + return prov_send_confirm(node);
>> > + } else
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + case PROV_CONFIRM:
>> > + if (buf[0] != PROV_CONFIRM)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + memcpy(prov->mesh_conf, buf + 1, 16);
>> > +
>> > + out[1] = PROV_RANDOM;
>> > + memcpy(out + 2, prov->rand_auth, 16);
>> > +
>> > + prov->state = PROV_RANDOM;
>> > + return mesh_gatt_write(prov->prov_in, out, 18,
>> > + NULL, node);
>> > +
>> > + case PROV_RANDOM:
>> > + if (buf[0] != PROV_RANDOM)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + /* Calculate New Salt while we still have
>> > + * both random values */
>> > + mesh_crypto_prov_prov_salt(prov->salt,
>> > + prov->rand_auth,
>> > + buf + 1,
>> > + prov->salt);
>> > +
>> > + /* Calculate meshs Conf Value */
>> > + memcpy(prov->rand_auth, buf + 1, 16);
>> > + mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
>> > + sizeof(prov->rand_auth), out + 1);
>> > +
>> > + /* Validate Mesh confirmation */
>> > + if (memcmp(out + 1, prov->mesh_conf, 16) != 0)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + rl_printf("Confirmation Validated\n");
>> > +
>> > + prov_send_prov_data(node);
>> > +
>> > + return true;
>> > +
>> > + case PROV_DATA:
>> > + if (buf[0] != PROV_COMPLETE)
>> > + return prov_complete(node,
>> > + PROV_ERR_INVALID_PDU);
>> > +
>> > + return prov_complete(node, 0);
>> > + }
>> > +
>> > +
>> > +
>> > + /* Compose appropriate reply for the prov state message */
>> > + /* Send reply via mesh_gatt_write() */
>> > + /* If done, call prov_done calllback and free prov housekeeping data
>> */
>> > + rl_printf("Got provisioning data (%d bytes)\n", len);
>> > + print_byte_array("\t", buf, len);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +bool prov_complete(struct mesh_node *node, uint8_t status)
>> > +{
>> > + struct prov_data *prov = node_get_prov(node);
>> > + void *user_data;
>> > + provision_done_cb cb;
>> > +
>> > + if (prov == NULL) return false;
>> > +
>> > + if (status && prov->new_addr && prov->conf_in.caps.num_ele) {
>> > + net_release_address(prov->new_addr, prov-
>> >conf_in.caps.num_ele);
>> > + }
>> > +
>> > + if (!status) {
>> > + node_set_num_elements(node, prov->conf_in.caps.num_ele);
>> > + node_set_primary(node, prov->new_addr);
>> > + node_set_device_key(node, prov->dev_key);
>> > + node_net_key_add(node, prov->net_idx);
>> > + }
>> > +
>> > + user_data = prov->user_data;
>> > + cb = prov->prov_done;
>> > + g_free(prov);
>> > + node_set_prov(node, NULL);
>> > + if (cb) cb(user_data, status);
>> > +
>> > + return true;
>> > +}
>> > diff --git a/mesh/util.c b/mesh/util.c
>> > new file mode 100644
>> > index 0000000..cb241b3
>> > --- /dev/null
>> > +++ b/mesh/util.c
>> > @@ -0,0 +1,369 @@
>> > +/*
>> > + *
>> > + * BlueZ - Bluetooth protocol stack for Linux
>> > + *
>> > + * Copyright (C) 2017 Intel Corporation. All rights reserved.
>> > + *
>> > + *
>> > + * This library is free software; you can redistribute it and/or
>> > + * modify it under the terms of the GNU Lesser General Public
>> > + * License as published by the Free Software Foundation; either
>> > + * version 2.1 of the License, or (at your option) any later version.
>> > + *
>> > + * This library is distributed in the hope that it will be useful,
>> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> GNU
>> > + * Lesser General Public License for more details.
>> > + *
>> > + * You should have received a copy of the GNU Lesser General Public
>> > + * License along with this library; if not, write to the Free Software
>> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
>> USA
>> > + *
>> > + */
>> > +
>> > +#ifdef HAVE_CONFIG_H
>> > +#include <config.h>
>> > +#endif
>> > +
>> > +#include <stdio.h>
>> > +#include <stdbool.h>
>> > +#include <inttypes.h>
>> > +#include <readline/readline.h>
>> > +#include <glib.h>
>> > +
>> > +#include "client/display.h"
>> > +#include "src/shared/util.h"
>> > +#include "mesh-net.h"
>> > +#include "util.h"
>> > +
>> > +struct cmd_menu {
>> > + const char *name;
>> > + const struct menu_entry *table;
>> > +};
>> > +
>> > +static struct menu_entry *main_cmd_table;
>> > +static struct menu_entry *current_cmd_table;
>> > +static GList *menu_list;
>> > +
>> > +static char *main_menu_prompt;
>> > +static int main_menu_point;
>> > +
>> > +static int match_menu_name(const void *a, const void *b)
>> > +{
>> > + const struct cmd_menu *menu = a;
>> > + const char *name = b;
>> > +
>> > + return strcasecmp(menu->name, name);
>> > +}
>> > +
>> > +bool cmd_menu_init(const struct menu_entry *cmd_table)
>> > +{
>> > + struct cmd_menu *menu;
>> > +
>> > + if (main_cmd_table) {
>> > + rl_printf("Main menu already registered\n");
>> > + return false;
>> > + }
>> > +
>> > + menu = g_malloc(sizeof(struct cmd_menu));
>> > + if (!menu)
>> > + return false;
>> > +
>> > + menu->name = "meshctl";
>> > + menu->table = cmd_table;
>> > + menu_list = g_list_append(menu_list, menu);
>> > + main_cmd_table = (struct menu_entry *) cmd_table;
>> > + current_cmd_table = (struct menu_entry *) main_cmd_table;
>> > +
>> > + return true;
>> > +}
>> > +
>> > +void cmd_menu_main(bool forced)
>> > +{
>> > + current_cmd_table = main_cmd_table;
>> > +
>> > + if (!forced) {
>> > + rl_set_prompt(main_menu_prompt);
>> > + rl_replace_line("", 0);
>> > + rl_point = main_menu_point;
>> > + rl_redisplay();
>> > + }
>> > +
>> > + g_free(main_menu_prompt);
>> > + main_menu_prompt = NULL;
>> > +}
>> > +
>> > +bool add_cmd_menu(const char *name, const struct menu_entry
>> *cmd_table)
>> > +{
>> > + struct cmd_menu *menu;
>> > + GList *l;
>> > +
>> > + l = g_list_find_custom(menu_list, name, match_menu_name);
>> > + if (l) {
>> > + menu = l->data;
>> > + rl_printf("menu \"%s\" already registered\n", menu->name);
>> > + return false;
>> > + }
>> > +
>> > + menu = g_malloc(sizeof(struct cmd_menu));
>> > + if (!menu)
>> > + return false;
>> > +
>> > + menu->name = name;
>> > + menu->table = cmd_table;
>> > + menu_list = g_list_append(menu_list, menu);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +void set_menu_prompt(const char *name, const char *id)
>> > +{
>> > + char *prompt;
>> > +
>> > + prompt = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ",
>> name,
>> > + id ? ": Target = " : "", id ? id : "");
>> > + rl_set_prompt(prompt);
>> > + g_free(prompt);
>> > + rl_on_new_line();
>> > +}
>> > +
>> > +bool switch_cmd_menu(const char *name)
>> > +{
>> > + GList *l;
>> > + struct cmd_menu *menu;
>> > +
>> > + l = g_list_find_custom(menu_list, name, match_menu_name);
>> > + if(!l)
>> > + return false;
>> > +
>> > + menu = l->data;
>> > + current_cmd_table = (struct menu_entry *) menu->table;
>> > +
>> > + main_menu_point = rl_point;
>> > + main_menu_prompt = g_strdup(rl_prompt);
>> > +
>> > + return true;
>> > +}
>> > +
>> > +void process_menu_cmd(const char *cmd, const char *arg)
>> > +{
>> > + int i;
>> > + int len;
>> > + struct menu_entry *cmd_table = current_cmd_table;
>> > +
>> > + if (!current_cmd_table)
>> > + return;
>> > +
>> > + len = strlen(cmd);
>> > +
>> > + for (i = 0; cmd_table[i].cmd; i++) {
>> > + if (strncmp(cmd, cmd_table[i].cmd, len))
>> > + continue;
>> > +
>> > + if (cmd_table[i].func) {
>> > + cmd_table[i].func(arg);
>> > + return;
>> > + }
>> > + }
>> > +
>> > + if (strncmp(cmd, "help", len)) {
>> > + rl_printf("Invalid command\n");
>> > + return;
>> > + }
>> > +
>> > + print_cmd_menu(cmd_table);
>> > +}
>> > +
>> > +void print_cmd_menu(const struct menu_entry *cmd_table)
>> > +{
>> > + int i;
>> > +
>> > + rl_printf("Available commands:\n");
>> > +
>> > + for (i = 0; cmd_table[i].cmd; i++) {
>> > + if (cmd_table[i].desc)
>> > + rl_printf(" %s %-*s %s\n", cmd_table[i].cmd,
>> > + (int)(40 - strlen(cmd_table[i].cmd)),
>> > + cmd_table[i].arg ? : "",
>> > + cmd_table[i].desc ? : "");
>> > + }
>> > +
>> > +}
>> > +
>> > +void cmd_menu_cleanup(void)
>> > +{
>> > + main_cmd_table = NULL;
>> > + current_cmd_table = NULL;
>> > +
>> > + g_list_free_full(menu_list, g_free);
>> > +}
>> > +
>> > +void print_byte_array(const char *prefix, const void *ptr, int len)
>> > +{
>> > + const uint8_t *data = ptr;
>> > + char *line, *bytes;
>> > + int i;
>> > +
>> > + line = g_malloc(strlen(prefix) + (16 * 3) + 2);
>> > + sprintf(line, "%s ", prefix);
>> > + bytes = line + strlen(prefix) + 1;
>> > +
>> > + for (i = 0; i < len; ++i) {
>> > + sprintf(bytes, "%2.2x ", data[i]);
>> > + if ((i + 1) % 16) {
>> > + bytes += 3;
>> > + } else {
>> > + rl_printf("\r%s\n", line);
>> > + bytes = line + strlen(prefix) + 1;
>> > + }
>> > + }
>> > +
>> > + if (i % 16)
>> > + rl_printf("\r%s\n", line);
>> > +
>> > + g_free(line);
>> > +}
>> > +
>> > +bool str2hex(const char *str, uint16_t in_len, uint8_t *out,
>> > + uint16_t out_len)
>> > +{
>> > + uint16_t i;
>> > +
>> > + if (in_len < out_len * 2)
>> > + return false;
>> > +
>> > + for (i = 0; i < out_len; i++) {
>> > + if (sscanf(&str[i * 2], "%02hhx", &out[i]) != 1)
>> > + return false;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +size_t hex2str(uint8_t *in, size_t in_len, char *out,
>> > + size_t out_len)
>> > +{
>> > + static const char hexdigits[] = "0123456789abcdef";
>> > + size_t i;
>> > +
>> > + if(in_len * 2 > out_len - 1)
>> > + return 0;
>> > +
>> > + for (i = 0; i < in_len; i++) {
>> > + out[i * 2] = hexdigits[in[i] >> 4];
>> > + out[i * 2 + 1] = hexdigits[in[i] & 0xf];
>> > + }
>> > +
>> > + out[in_len * 2] = '\0';
>> > + return i;
>> > +}
>> > +
>> > +uint16_t mesh_opcode_set(uint32_t opcode, uint8_t *buf)
>> > +{
>> > + if (opcode <= 0x7e) {
>> > + buf[0] = opcode;
>> > + return 1;
>> > + } else if (opcode >= 0x8000 && opcode <= 0xbfff) {
>> > + put_be16(opcode, buf);
>> > + return 2;
>> > + } else if (opcode >= 0xc00000 && opcode <= 0xffffff) {
>> > + buf[0] = (opcode >> 16) & 0xff;
>> > + put_be16(opcode, buf + 1);
>> > + return 3;
>> > + } else {
>> > + rl_printf("Illegal Opcode %x", opcode);
>> > + return 0;
>> > + }
>> > +}
>> > +
>> > +bool mesh_opcode_get(const uint8_t *buf, uint16_t sz, uint32_t
>> *opcode, int *n)
>> > +{
>> > + if (!n || !opcode || sz < 1) return false;
>> > +
>> > + switch (buf[0] & 0xc0) {
>> > + case 0x00:
>> > + case 0x40:
>> > + /* RFU */
>> > + if (buf[0] == 0x7f)
>> > + return false;
>> > +
>> > + *n = 1;
>> > + *opcode = buf[0];
>> > + break;
>> > +
>> > + case 0x80:
>> > + if (sz < 2)
>> > + return false;
>> > +
>> > + *n = 2;
>> > + *opcode = get_be16(buf);
>> > + break;
>> > +
>> > + case 0xc0:
>> > + if (sz < 3)
>> > + return false;
>> > +
>> > + *n = 3;
>> > + *opcode = get_be16(buf + 1);
>> > + *opcode |= buf[0] << 16;
>> > + break;
>> > +
>> > + default:
>> > + rl_printf("Bad Packet:\n");
>> > + print_byte_array("\t", (void *) buf, sz);
>> > + return false;
>> > + }
>> > +
>> > + return true;
>> > +}
>> > +
>> > +const char *mesh_status_str(uint8_t status)
>> > +{
>> > + switch (status) {
>> > + case MESH_STATUS_SUCCESS: return "Success";
>> > + case MESH_STATUS_INVALID_ADDRESS: return "Invalid Address";
>> > + case MESH_STATUS_INVALID_MODEL: return "Invalid Model";
>> > + case MESH_STATUS_INVALID_APPKEY: return "Invalid AppKey";
>> > + case MESH_STATUS_INVALID_NETKEY: return "Invalid NetKey";
>> > + case MESH_STATUS_INSUFF_RESOURCES: return "Insufficient
>> Resources";
>> > + case MESH_STATUS_IDX_ALREADY_STORED: return "Key Idx Already
>> Stored";
>> > + case MESH_STATUS_INVALID_PUB_PARAM: return "Invalid Publish
>> Parameters";
>> > + case MESH_STATUS_NOT_SUB_MOD: return "Not a Subscribe
>> Model";
>> > + case MESH_STATUS_STORAGE_FAIL: return "Storage Failure";
>> > + case MESH_STATUS_FEAT_NOT_SUP: return "Feature Not
>> Supported";
>> > + case MESH_STATUS_CANNOT_UPDATE: return "Cannot Update";
>> > + case MESH_STATUS_CANNOT_REMOVE: return "Cannot Remove";
>> > + case MESH_STATUS_CANNOT_BIND: return "Cannot bind";
>> > + case MESH_STATUS_UNABLE_CHANGE_STATE: return "Unable to
>> change state";
>> > + case MESH_STATUS_CANNOT_SET: return "Cannot set";
>> > + case MESH_STATUS_UNSPECIFIED_ERROR: return "Unspecified
>> error";
>> > + case MESH_STATUS_INVALID_BINDING: return "Invalid Binding";
>> > +
>> > + default: return "Unknown";
>> > + }
>> > +}
>> > +
>> > +void print_model_pub(uint16_t ele_addr, uint32_t mod_id,
>> > + struct mesh_publication *pub)
>> > +{
>> > + rl_printf("\tElement: %4.4x\n", ele_addr);
>> > + rl_printf("\tPub Addr: %4.4x", pub->u.addr16);
>> > + if (mod_id > 0xffff0000)
>> > + rl_printf("\tModel: %8.8x \n", mod_id);
>> > + else
>> > + rl_printf("\tModel: %4.4x \n", (uint16_t) (mod_id & 0xffff));
>> > + rl_printf("\tApp Key Idx: %4.4x", pub->app_idx);
>> > + rl_printf("\tTTL: %2.2x", pub->ttl);
>> > +}
>> > +
>> > +void swap_u256_bytes(uint8_t *u256)
>> > +{
>> > + int i;
>> > +
>> > + /* End-to-End byte reflection of 32 octet buffer */
>> > + for (i = 0; i < 16; i++) {
>> > + u256[i] ^= u256[31 - i];
>> > + u256[31 - i] ^= u256[i];
>> > + u256[i] ^= u256[31 - i];
>> > + }
>> > +}
>> > --
>> > 2.9.5
>> >
>>
>>
>>
>> --
>> Luiz Augusto von Dentz



--
Luiz Augusto von Dentz

2017-08-16 12:28:42

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner

Hi Brian,

On Monday, 14 August 2017 21:01:14 CEST Brian Gix wrote:
> With the recent adoption of the Bluetooth Mesh Profile, we offer this
> GATT Client provisioner tool (meshctl).
>
> Brian Gix / Inga Stotland` (5):
> mesh: Add BT SIG reserved numbers for Mesh
> mesh: define APIs for Bluetooth Mesh
> mesh: Baseline Mesh runtime configuration files
> mesh: Baseline Mesh implementation
> mesh: Add mesh to main bluez build
>
> Makefile.tools | 24 +
> bootstrap-configure | 1 +
> configure.ac | 18 +
> lib/uuid.h | 10 +
> mesh/README | 26 +
> mesh/agent.c | 276 ++++++
> mesh/agent.h | 58 ++
> mesh/config-client.c | 667 +++++++++++++++
> mesh/config-model.h | 119 +++
> mesh/config-server.c | 165 ++++
> mesh/crypto.c | 1168 ++++++++++++++++++++++++++
> mesh/crypto.h | 133 +++
> mesh/gatt.c | 609 ++++++++++++++
> mesh/gatt.h | 47 ++
> mesh/keys.h | 43 +
> mesh/local_node.json | 61 ++
> mesh/main.c | 2269
> ++++++++++++++++++++++++++++++++++++++++++++++++++ mesh/mesh-net.h |
> 174 ++++
> mesh/net.c | 2184
> ++++++++++++++++++++++++++++++++++++++++++++++++ mesh/net.h |
> 72 ++
> mesh/node.c | 879 +++++++++++++++++++
> mesh/node.h | 146 ++++
> mesh/onoff-model.c | 306 +++++++
> mesh/onoff-model.h | 50 ++
> mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
> mesh/prov-db.h | 52 ++
> mesh/prov.c | 664 +++++++++++++++
> mesh/prov.h | 43 +
> mesh/prov_db.json | 37 +
> mesh/util.c | 369 ++++++++
> mesh/util.h | 71 ++
> 31 files changed, 12340 insertions(+)
> create mode 100644 mesh/README
> create mode 100644 mesh/agent.c
> create mode 100644 mesh/agent.h
> create mode 100644 mesh/config-client.c
> create mode 100644 mesh/config-model.h
> create mode 100644 mesh/config-server.c
> create mode 100644 mesh/crypto.c
> create mode 100644 mesh/crypto.h
> create mode 100644 mesh/gatt.c
> create mode 100644 mesh/gatt.h
> create mode 100644 mesh/keys.h
> create mode 100644 mesh/local_node.json
> create mode 100644 mesh/main.c
> create mode 100644 mesh/mesh-net.h
> create mode 100644 mesh/net.c
> create mode 100644 mesh/net.h
> create mode 100644 mesh/node.c
> create mode 100644 mesh/node.h
> create mode 100644 mesh/onoff-model.c
> create mode 100644 mesh/onoff-model.h
> create mode 100644 mesh/prov-db.c
> create mode 100644 mesh/prov-db.h
> create mode 100644 mesh/prov.c
> create mode 100644 mesh/prov.h
> create mode 100644 mesh/prov_db.json
> create mode 100644 mesh/util.c
> create mode 100644 mesh/util.h

Seems like 4th patch didn't make it to the list. Looking at code size it seems
like it is too big and was rejected by vger. Would it be possible to upload
this code eg to gihub?

--
pozdrawiam
Szymon Janc

2017-08-15 15:36:58

by Gix, Brian

[permalink] [raw]
Subject: RE: [PATCH 4/5] mesh: Baseline Mesh implementation

SGkgTHVpeiwNCg0KV2UgYWN0dWFsbHkgdXNlIHRoZSBhZ2VudC5jIGNvZGUgZm9yIE91dC1PZi1C
YW5kIGRhdGEgaW5wdXQgZHVyaW5nIFByb3Zpc2lvbmluZy4NCg0KPiAtLS0tLU9yaWdpbmFsIE1l
c3NhZ2UtLS0tLQ0KPiBGcm9tOiBMdWl6IEF1Z3VzdG8gdm9uIERlbnR6IFttYWlsdG86bHVpei5k
ZW50ekBnbWFpbC5jb21dDQo+IFNlbnQ6IFR1ZXNkYXksIEF1Z3VzdCAxNSwgMjAxNyAyOjA3IEFN
DQo+IFRvOiBHaXgsIEJyaWFuIDxicmlhbi5naXhAaW50ZWwuY29tPg0KPiBDYzogbGludXgtYmx1
ZXRvb3RoQHZnZXIua2VybmVsLm9yZzsgTWFyY2VsIEhvbHRtYW5uDQo+IDxtYXJjZWxAaG9sdG1h
bm4ub3JnPg0KPiBTdWJqZWN0OiBSZTogW1BBVENIIDQvNV0gbWVzaDogQmFzZWxpbmUgTWVzaCBp
bXBsZW1lbnRhdGlvbg0KPiANCj4gSGkgQnJpYW4sDQo+IA0KPiBPbiBNb24sIEF1ZyAxNCwgMjAx
NyBhdCAxMDowMSBQTSwgQnJpYW4gR2l4IDxicmlhbi5naXhAaW50ZWwuY29tPiB3cm90ZToNCj4g
PiAtLS0NCj4gPiAgbWVzaC9hZ2VudC5jICAgICAgICAgfCAgMjc2ICsrKysrKw0KPiA+ICBtZXNo
L2NvbmZpZy1jbGllbnQuYyB8ICA2NjcgKysrKysrKysrKysrKysrDQo+ID4gIG1lc2gvY29uZmln
LXNlcnZlci5jIHwgIDE2NSArKysrDQo+ID4gIG1lc2gvY3J5cHRvLmMgICAgICAgIHwgMTE2OCAr
KysrKysrKysrKysrKysrKysrKysrKysrKw0KPiA+ICBtZXNoL2dhdHQuYyAgICAgICAgICB8ICA2
MDkgKysrKysrKysrKysrKysNCj4gPiAgbWVzaC9tYWluLmMgICAgICAgICAgfCAyMjY5DQo+ICsr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrDQo+ID4gIG1l
c2gvbmV0LmMgICAgICAgICAgIHwgMjE4NA0KPiArKysrKysrKysrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysNCj4gPiAgbWVzaC9ub2RlLmMgICAgICAgICAgfCAgODc5ICsr
KysrKysrKysrKysrKysrKysNCj4gPiAgbWVzaC9vbm9mZi1tb2RlbC5jICAgfCAgMzA2ICsrKysr
KysNCj4gPiAgbWVzaC9wcm92LWRiLmMgICAgICAgfCAxNTk5ICsrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysrDQo+ID4gIG1lc2gvcHJvdi5jICAgICAgICAgIHwgIDY2NCArKysrKysr
KysrKysrKysNCj4gPiAgbWVzaC91dGlsLmMgICAgICAgICAgfCAgMzY5ICsrKysrKysrDQo+ID4g
IDEyIGZpbGVzIGNoYW5nZWQsIDExMTU1IGluc2VydGlvbnMoKykNCj4gPiAgY3JlYXRlIG1vZGUg
MTAwNjQ0IG1lc2gvYWdlbnQuYw0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgbWVzaC9jb25maWct
Y2xpZW50LmMNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IG1lc2gvY29uZmlnLXNlcnZlci5jDQo+
ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBtZXNoL2NyeXB0by5jDQo+ID4gIGNyZWF0ZSBtb2RlIDEw
MDY0NCBtZXNoL2dhdHQuYw0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgbWVzaC9tYWluLmMNCj4g
PiAgY3JlYXRlIG1vZGUgMTAwNjQ0IG1lc2gvbmV0LmMNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0
IG1lc2gvbm9kZS5jDQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBtZXNoL29ub2ZmLW1vZGVsLmMN
Cj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IG1lc2gvcHJvdi1kYi5jDQo+ID4gIGNyZWF0ZSBtb2Rl
IDEwMDY0NCBtZXNoL3Byb3YuYw0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgbWVzaC91dGlsLmMN
Cj4gPg0KPiA+IGRpZmYgLS1naXQgYS9tZXNoL2FnZW50LmMgYi9tZXNoL2FnZW50LmMNCj4gPiBu
ZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGluZGV4IDAwMDAwMDAuLjA5NDQ4NjINCj4gPiAtLS0g
L2Rldi9udWxsDQo+ID4gKysrIGIvbWVzaC9hZ2VudC5jDQo+ID4gQEAgLTAsMCArMSwyNzYgQEAN
Cj4gPiArLyoNCj4gPiArICoNCj4gPiArICogIEJsdWVaIC0gQmx1ZXRvb3RoIHByb3RvY29sIHN0
YWNrIGZvciBMaW51eA0KPiA+ICsgKg0KPiA+ICsgKiAgQ29weXJpZ2h0IChDKSAyMDE3ICBJbnRl
bCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gPiArICoNCj4gPiArICoNCj4g
PiArICogIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0
ZSBpdCBhbmQvb3INCj4gPiArICogIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdO
VSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5
IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlcg0KPiA+ICsgKiAgdmVyc2lvbiAy
LjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24u
DQo+ID4gKyAqDQo+ID4gKyAqICBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhv
cGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwNCj4gPiArICogIGJ1dCBXSVRIT1VUIEFOWSBXQVJS
QU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQo+ID4gKyAqICBNRVJD
SEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhl
DQo+IEdOVQ0KPiA+ICsgKiAgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUg
ZGV0YWlscy4NCj4gPiArICoNCj4gPiArICogIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNv
cHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExpY2Vuc2UgYWxv
bmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUN
Cj4gPiArICogIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0LCBGaWZ0aCBGbG9vciwg
Qm9zdG9uLCBNQSAgMDIxMTAtMTMwMQ0KPiBVU0ENCj4gPiArICoNCj4gPiArICovDQo+ID4gKw0K
PiA+ICsjaWZkZWYgSEFWRV9DT05GSUdfSA0KPiA+ICsjaW5jbHVkZSA8Y29uZmlnLmg+DQo+ID4g
KyNlbmRpZg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgPHN0ZGlvLmg+DQo+ID4gKyNpbmNsdWRlIDxz
dGRsaWIuaD4NCj4gPiArI2luY2x1ZGUgPHN0ZGJvb2wuaD4NCj4gPiArI2luY2x1ZGUgPGludHR5
cGVzLmg+DQo+ID4gKyNpbmNsdWRlIDxyZWFkbGluZS9yZWFkbGluZS5oPg0KPiA+ICsNCj4gPiAr
I2luY2x1ZGUgPGdsaWIuaD4NCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxsaWIvYmx1ZXRvb3RoLmg+
DQo+ID4gKyNpbmNsdWRlICJjbGllbnQvZGlzcGxheS5oIg0KPiA+ICsjaW5jbHVkZSAidXRpbC5o
Ig0KPiA+ICsjaW5jbHVkZSAiYWdlbnQuaCINCj4gPiArDQo+ID4gKyNkZWZpbmUgQUdFTlRfUFJP
TVBUICAgQ09MT1JfUkVEICJbYWdlbnRdIiBDT0xPUl9PRkYgIiAiDQo+ID4gKw0KPiA+ICtzdGF0
aWMgY2hhciAqYWdlbnRfc2F2ZWRfcHJvbXB0ID0gTlVMTDsNCj4gPiArc3RhdGljIGludCBhZ2Vu
dF9zYXZlZF9wb2ludCA9IDA7DQo+ID4gKw0KPiA+ICtzdHJ1Y3QgaW5wdXRfcmVxdWVzdCB7DQo+
ID4gKyAgICAgICBvb2JfdHlwZV90IHR5cGU7DQo+ID4gKyAgICAgICB1aW50MTZfdCBsZW47DQo+
ID4gKyAgICAgICBhZ2VudF9pbnB1dF9jYiBjYjsNCj4gPiArICAgICAgIHZvaWQgKnVzZXJfZGF0
YTsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgaW5wdXRfcmVxdWVzdCBwZW5k
aW5nX3JlcXVlc3QgPSB7Tk9ORSwgMCwgTlVMTCwgTlVMTH07DQo+ID4gKw0KPiA+ICtzdGF0aWMg
dm9pZCBhZ2VudF9wcm9tcHQoY29uc3QgY2hhciAqbXNnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBj
aGFyICpwcm9tcHQ7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogTm9ybWFsIHVzZSBzaG91bGQgbm90
IHByb21wdCBmb3IgdXNlciBpbnB1dCB0byB0aGUgYWdlbnQgYSBzZWNvbmQNCj4gPiArICAgICAg
ICAqIHRpbWUgYmVmb3JlIGl0IHJlbGVhc2VzIHRoZSBwcm9tcHQsIGJ1dCB3ZSB0YWtlIGEgc2Fm
ZSBhY3Rpb24uICovDQo+ID4gKyAgICAgICBpZiAoYWdlbnRfc2F2ZWRfcHJvbXB0KQ0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgYWdlbnRfc2F2ZWRfcG9p
bnQgPSBybF9wb2ludDsNCj4gPiArICAgICAgIGFnZW50X3NhdmVkX3Byb21wdCA9IGdfc3RyZHVw
KHJsX3Byb21wdCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfc2V0X3Byb21wdCgiIik7DQo+ID4g
KyAgICAgICBybF9yZWRpc3BsYXkoKTsNCj4gPiArDQo+ID4gKyAgICAgICBwcm9tcHQgPSBnX3N0
cmR1cF9wcmludGYoQUdFTlRfUFJPTVBUICIlcyIsIG1zZyk7DQo+ID4gKyAgICAgICBybF9zZXRf
cHJvbXB0KHByb21wdCk7DQo+ID4gKyAgICAgICBnX2ZyZWUocHJvbXB0KTsNCj4gPiArDQo+ID4g
KyAgICAgICBybF9yZXBsYWNlX2xpbmUoIiIsIDApOw0KPiA+ICsgICAgICAgcmxfcmVkaXNwbGF5
KCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGFnZW50X3JlbGVhc2VfcHJvbXB0
KHZvaWQpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmICghYWdlbnRfc2F2ZWRfcHJvbXB0KQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgLyogVGhpcyB3aWxs
IGNhdXNlIHJsX2V4cGFuZF9wcm9tcHQgdG8gcmUtcnVuIG92ZXIgdGhlIGxhc3QgcHJvbXB0LA0K
PiBidXQNCj4gPiArICAgICAgICAqIG91ciBwcm9tcHQgZG9lc24ndCBleHBhbmQgYW55d2F5LiAq
Lw0KPiA+ICsgICAgICAgcmxfc2V0X3Byb21wdChhZ2VudF9zYXZlZF9wcm9tcHQpOw0KPiA+ICsg
ICAgICAgcmxfcmVwbGFjZV9saW5lKCIiLCAwKTsNCj4gPiArICAgICAgIHJsX3BvaW50ID0gYWdl
bnRfc2F2ZWRfcG9pbnQ7DQo+ID4gKyAgICAgICBybF9yZWRpc3BsYXkoKTsNCj4gPiArDQo+ID4g
KyAgICAgICBnX2ZyZWUoYWdlbnRfc2F2ZWRfcHJvbXB0KTsNCj4gPiArICAgICAgIGFnZW50X3Nh
dmVkX3Byb21wdCA9IE5VTEw7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgYWdlbnRfY29tcGxl
dGlvbih2b2lkKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAocGVuZGluZ19yZXF1ZXN0LnR5cGUg
PT0gTk9ORSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiAr
ICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCByZXNw
b25zZV9oZXhhZGVjaW1hbChjb25zdCBjaGFyICppbnB1dCkNCj4gPiArew0KPiA+ICsgICAgICAg
dWludDhfdCBidWZbTUFYX0hFWEFERUNJTUFMX09PQl9MRU5dOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmICghc3RyMmhleChpbnB1dCwgc3RybGVuKGlucHV0KSwgYnVmLCBwZW5kaW5nX3JlcXVlc3Qu
bGVuKSApIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJJbmNvcnJlY3QgaW5wdXQ6
IGV4cGVjdGluZyAlZCBoZXggb2N0ZXRzXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgcGVuZGluZ19yZXF1ZXN0Lmxlbik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxz
ZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAocGVuZGluZ19yZXF1ZXN0
LmNiKQ0KPiA+ICsgICAgICAgICAgICAgICBwZW5kaW5nX3JlcXVlc3QuY2IoSEVYQURFQ0lNQUws
IGJ1ZiwgcGVuZGluZ19yZXF1ZXN0LmxlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgcGVuZGluZ19yZXF1ZXN0LnVzZXJfZGF0YSk7DQo+ID4gKyAgICAgICBy
ZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgcmVzcG9uc2VfZGVj
aW1hbChjb25zdCBjaGFyICppbnB1dCkNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCBidWZb
REVDSU1BTF9PT0JfTEVOXTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc3RybGVuKGlucHV0KSA+
IHBlbmRpbmdfcmVxdWVzdC5sZW4pDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsN
Cj4gPiArDQo+ID4gKyAgICAgICBidF9wdXRfYmUzMihhdG9pKGlucHV0KSwgYnVmKTsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZiAocGVuZGluZ19yZXF1ZXN0LmNiKQ0KPiA+ICsgICAgICAgICAgICAg
ICBwZW5kaW5nX3JlcXVlc3QuY2IoREVDSU1BTCwgYnVmLCBERUNJTUFMX09PQl9MRU4sDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlbmRpbmdfcmVxdWVzdC51
c2VyX2RhdGEpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgdm9pZCByZXNwb25zZV9hc2NpaShjb25zdCBjaGFyICppbnB1dCkNCj4g
PiArew0KPiA+ICsgICAgICAgaWYgKHBlbmRpbmdfcmVxdWVzdC5jYikNCj4gPiArICAgICAgICAg
ICAgICAgcGVuZGluZ19yZXF1ZXN0LmNiKEFTQ0lJLCAodWludDhfdCAqKSBpbnB1dCwgc3RybGVu
KGlucHV0KSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVu
ZGluZ19yZXF1ZXN0LnVzZXJfZGF0YSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgYWdlbnRf
aW5wdXQoY29uc3QgY2hhciAqaW5wdXQpDQo+ID4gK3sNCj4gPiArICAgICAgIGJvb2wgcmVwZWF0
ID0gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHBlbmRpbmdfcmVxdWVzdC50eXBlID09
IE5PTkUpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAg
ICAgICBzd2l0Y2ggKHBlbmRpbmdfcmVxdWVzdC50eXBlKSB7DQo+ID4gKyAgICAgICBjYXNlIEhF
WEFERUNJTUFMOg0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIXJlc3BvbnNlX2hleGFkZWNpbWFs
KGlucHV0KSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXBlYXQgPSB0cnVlOw0KPiA+
ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgREVDSU1BTDoNCj4gPiAr
ICAgICAgICAgICAgICAgaWYgKCFyZXNwb25zZV9kZWNpbWFsKGlucHV0KSkNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICByZXBlYXQgPSB0cnVlOw0KPiA+ICsgICAgICAgICAgICAgICBicmVh
azsNCj4gPiArICAgICAgIGNhc2UgQVNDSUk6DQo+ID4gKyAgICAgICAgICAgICAgIHJlc3BvbnNl
X2FzY2lpKGlucHV0KTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICBj
YXNlIE9VVFBVVDoNCj4gPiArICAgICAgICAgICAgICAgcmVwZWF0ID0gdHJ1ZTsNCj4gPiArICAg
ICAgIGNhc2UgTk9ORToNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAgICAgICAg
IGJyZWFrOw0KPiA+ICsgICAgICAgfTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXJlcGVhdCkg
ew0KPiA+ICsgICAgICAgICAgICAgICBwZW5kaW5nX3JlcXVlc3QudHlwZSA9IE5PTkU7DQo+ID4g
KyAgICAgICAgICAgICAgIHBlbmRpbmdfcmVxdWVzdC5sZW4gPSAwOw0KPiA+ICsgICAgICAgICAg
ICAgICBwZW5kaW5nX3JlcXVlc3QuY2IgPSBOVUxMOw0KPiA+ICsgICAgICAgICAgICAgICBwZW5k
aW5nX3JlcXVlc3QudXNlcl9kYXRhID0gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IGFnZW50X3JlbGVhc2VfcHJvbXB0KCk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAg
ICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgYWdlbnRfcmVsZWFzZSh2
b2lkKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBhZ2VudF9yZWxlYXNlX3Byb21wdCgpOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCByZXF1ZXN0X2hleGFkZWNpbWFsKHVpbnQxNl90IGxl
bikNCj4gPiArew0KPiA+ICsgICAgICAgaWYgKGxlbiA+IE1BWF9IRVhBREVDSU1BTF9PT0JfTEVO
KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAg
cmxfcHJpbnRmKCJSZXF1ZXN0IGhleGFkZWNpbWFsIGtleSAoaGV4ICVkIG9jdGV0cylcbiIsIGxl
bik7DQo+ID4gKyAgICAgICBhZ2VudF9wcm9tcHQoIkVudGVyIGtleSAoaGV4IG51bWJlcik6ICIp
Ow0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtz
dGF0aWMgdWludDMyX3QgcG93ZXJfdGVuKHVpbnQ4X3QgcG93ZXIpDQo+ID4gK3sNCj4gPiArICAg
ICAgIHVpbnQzMl90IHJldCA9IDE7DQo+ID4gKw0KPiA+ICsgICAgICAgd2hpbGUgKHBvd2VyLS0p
DQo+ID4gKyAgICAgICAgICAgICAgIHJldCAqPSAxMDsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1
cm4gcmV0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCByZXF1ZXN0X2RlY2ltYWwo
dWludDE2X3QgbGVuKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBybF9wcmludGYoIlJlcXVlc3QgZGVj
aW1hbCBrZXkgKDAgLSAlZClcbiIsIHBvd2VyX3RlbihsZW4pIC0gMSk7DQo+ID4gKyAgICAgICBh
Z2VudF9wcm9tcHQoIkVudGVyIE51bWVyaWMga2V5OiAiKTsNCj4gPiArDQo+ID4gKyAgICAgICBy
ZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgcmVxdWVzdF9hc2Np
aSh1aW50MTZfdCBsZW4pDQo+ID4gK3sNCj4gPiArICAgICAgIGlmIChsZW4gIT0gTUFYX0FTQ0lJ
X09PQl9MRU4pDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4g
KyAgICAgICBybF9wcmludGYoIlJlcXVlc3QgQVNDSUkga2V5IChtYXggY2hhcmFjdGVycyAlZClc
biIsIGxlbik7DQo+ID4gKyAgICAgICBhZ2VudF9wcm9tcHQoIkVudGVyIGtleSAoYXNjaWkgc3Ry
aW5nKTogIik7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK2Jvb2wgYWdlbnRfaW5wdXRfcmVxdWVzdChvb2JfdHlwZV90IHR5cGUsIHVpbnQxNl90
IG1heF9sZW4sDQo+IGFnZW50X2lucHV0X2NiIGNiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgdm9pZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBib29sIHJl
c3VsdDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocGVuZGluZ19yZXF1ZXN0LnR5cGUgIT0gTk9O
RSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIEZBTFNFOw0KPiA+ICsNCj4gPiArICAgICAg
IHN3aXRjaCAodHlwZSkgew0KPiA+ICsgICAgICAgY2FzZSBIRVhBREVDSU1BTDoNCj4gPiArICAg
ICAgICAgICAgICAgcmVzdWx0ID0gcmVxdWVzdF9oZXhhZGVjaW1hbChtYXhfbGVuKTsNCj4gPiAr
ICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICBjYXNlIERFQ0lNQUw6DQo+ID4gKyAg
ICAgICAgICAgICAgIHJlc3VsdCA9IHJlcXVlc3RfZGVjaW1hbChtYXhfbGVuKTsNCj4gPiArICAg
ICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICBjYXNlIEFTQ0lJOg0KPiA+ICsgICAgICAg
ICAgICAgICByZXN1bHQgPSByZXF1ZXN0X2FzY2lpKG1heF9sZW4pOw0KPiA+ICsgICAgICAgICAg
ICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgTk9ORToNCj4gPiArICAgICAgIGNhc2UgT1VU
UFVUOg0KPiA+ICsgICAgICAgZGVmYXVsdDoNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZh
bHNlOw0KPiA+ICsgICAgICAgfTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocmVzdWx0KSB7DQo+
ID4gKyAgICAgICAgICAgICAgIHBlbmRpbmdfcmVxdWVzdC50eXBlID0gdHlwZTsNCj4gPiArICAg
ICAgICAgICAgICAgcGVuZGluZ19yZXF1ZXN0LmxlbiA9IG1heF9sZW47DQo+ID4gKyAgICAgICAg
ICAgICAgIHBlbmRpbmdfcmVxdWVzdC5jYiA9IGNiOw0KPiA+ICsgICAgICAgICAgICAgICBwZW5k
aW5nX3JlcXVlc3QudXNlcl9kYXRhID0gdXNlcl9kYXRhOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0
dXJuIGZhbHNlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIGFnZW50X291dHB1dF9yZXF1ZXN0
KGNvbnN0IGNoYXIqIHN0cikNCj4gPiArew0KPiA+ICsgICAgICAgaWYgKHBlbmRpbmdfcmVxdWVz
dC50eXBlICE9IE5PTkUpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiAr
DQo+ID4gKyAgICAgICBwZW5kaW5nX3JlcXVlc3QudHlwZSA9IE9VVFBVVDsNCj4gPiArICAgICAg
IGFnZW50X3Byb21wdChzdHIpOw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3ZvaWQgYWdlbnRfb3V0cHV0X3JlcXVlc3RfY2FuY2VsKHZvaWQpDQo+ID4gK3sN
Cj4gPiArICAgICAgIGlmIChwZW5kaW5nX3JlcXVlc3QudHlwZSAhPSBPVVRQVVQpDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIHBlbmRpbmdfcmVxdWVzdC50eXBlID0g
Tk9ORTsNCj4gPiArICAgICAgIGFnZW50X3JlbGVhc2VfcHJvbXB0KCk7DQo+ID4gK30NCj4gDQo+
IFRoZSB3aG9sZSBhZ2VudC5jIGNhbiBiZSByZW1vdmVkIGFzIHdlbGwuDQo+IA0KPiA+IGRpZmYg
LS1naXQgYS9tZXNoL2NvbmZpZy1jbGllbnQuYyBiL21lc2gvY29uZmlnLWNsaWVudC5jDQo+ID4g
bmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi5hMGY2ZWVlDQo+ID4gLS0t
IC9kZXYvbnVsbA0KPiA+ICsrKyBiL21lc2gvY29uZmlnLWNsaWVudC5jDQo+ID4gQEAgLTAsMCAr
MSw2NjcgQEANCj4gPiArLyoNCj4gPiArICoNCj4gPiArICogIEJsdWVaIC0gQmx1ZXRvb3RoIHBy
b3RvY29sIHN0YWNrIGZvciBMaW51eA0KPiA+ICsgKg0KPiA+ICsgKiAgQ29weXJpZ2h0IChDKSAy
MDE3ICBJbnRlbCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gPiArICoNCj4g
PiArICoNCj4gPiArICogIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJl
ZGlzdHJpYnV0ZSBpdCBhbmQvb3INCj4gPiArICogIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMg
b2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExpY2Vuc2UgYXMgcHVi
bGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlcg0KPiA+ICsgKiAg
dmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVy
IHZlcnNpb24uDQo+ID4gKyAqDQo+ID4gKyAqICBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQg
aW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwNCj4gPiArICogIGJ1dCBXSVRIT1VU
IEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQo+ID4g
KyAqICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0Uu
ICBTZWUgdGhlDQo+IEdOVQ0KPiA+ICsgKiAgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2Ug
Zm9yIG1vcmUgZGV0YWlscy4NCj4gPiArICoNCj4gPiArICogIFlvdSBzaG91bGQgaGF2ZSByZWNl
aXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExp
Y2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUg
U29mdHdhcmUNCj4gPiArICogIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0LCBGaWZ0
aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMQ0KPiBVU0ENCj4gPiArICoNCj4gPiArICov
DQo+ID4gKw0KPiA+ICsjaWZkZWYgSEFWRV9DT05GSUdfSA0KPiA+ICsjaW5jbHVkZSA8Y29uZmln
Lmg+DQo+ID4gKyNlbmRpZg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgPHN0ZGlvLmg+DQo+ID4gKyNp
bmNsdWRlIDxlcnJuby5oPg0KPiA+ICsjaW5jbHVkZSA8dW5pc3RkLmg+DQo+ID4gKyNpbmNsdWRl
IDxzdGRsaWIuaD4NCj4gPiArI2luY2x1ZGUgPHN0ZGJvb2wuaD4NCj4gPiArI2luY2x1ZGUgPGlu
dHR5cGVzLmg+DQo+ID4gKyNpbmNsdWRlIDxzdGRib29sLmg+DQo+ID4gKyNpbmNsdWRlIDxzeXMv
dWlvLmg+DQo+ID4gKyNpbmNsdWRlIDx3b3JkZXhwLmg+DQo+ID4gKyNpbmNsdWRlIDxyZWFkbGlu
ZS9yZWFkbGluZS5oPg0KPiA+ICsjaW5jbHVkZSA8cmVhZGxpbmUvaGlzdG9yeS5oPg0KPiA+ICsj
aW5jbHVkZSA8Z2xpYi5oPg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgInNyYy9zaGFyZWQvdXRpbC5o
Ig0KPiA+ICsjaW5jbHVkZSAiY2xpZW50L2Rpc3BsYXkuaCINCj4gPiArI2luY2x1ZGUgIm1lc2gt
bmV0LmgiDQo+ID4gKyNpbmNsdWRlICJrZXlzLmgiDQo+ID4gKyNpbmNsdWRlICJuZXQuaCINCj4g
PiArI2luY2x1ZGUgIm5vZGUuaCINCj4gPiArI2luY2x1ZGUgInByb3YtZGIuaCINCj4gPiArI2lu
Y2x1ZGUgInV0aWwuaCINCj4gPiArI2luY2x1ZGUgImNvbmZpZy1tb2RlbC5oIg0KPiA+ICsNCj4g
PiArI2RlZmluZSBNSU5fQ09NUE9TSVRJT05fTEVOIDE2DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9v
bCBjbGllbnRfbXNnX3JlY3ZkKHVpbnQxNl90IHNyYywgdWludDhfdCAqZGF0YSwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQxNl90IGxlbiwgdm9pZCAqdXNlcl9kYXRh
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50MzJfdCBvcGNvZGU7DQo+ID4gKyAgICAgICBzdHJ1
Y3QgbWVzaF9ub2RlICpub2RlOw0KPiA+ICsgICAgICAgdWludDE2X3QgYXBwX2lkeCwgbmV0X2lk
eCwgYWRkcjsNCj4gPiArICAgICAgIHVpbnQzMl90IG1vZF9pZDsNCj4gPiArICAgICAgIHVpbnQx
Nl90IHByaW1hcnk7DQo+ID4gKyAgICAgICB1aW50MTZfdCBlbGVfYWRkcjsNCj4gPiArICAgICAg
IHVpbnQ4X3QgZWxlX2lkeDsNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX3B1YmxpY2F0aW9uIHB1
YjsNCj4gPiArICAgICAgIGludCBuOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChtZXNoX29wY29k
ZV9nZXQoZGF0YSwgbGVuLCAmb3Bjb2RlLCAmbikpIHsNCj4gPiArICAgICAgICAgICAgICAgbGVu
IC09IG47DQo+ID4gKyAgICAgICAgICAgICAgIGRhdGEgKz0gbjsNCj4gPiArICAgICAgIH0gZWxz
ZQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKElTX1VOSUNBU1Qoc3JjKSkgew0KPiA+ICsgICAgICAgICAgICAgICBub2RlID0gbm9kZV9m
aW5kX2J5X2FkZHIoc3JjKTsNCj4gPiArICAgICAgIH0gZWxzZQ0KPiA+ICsgICAgICAgICAgICAg
ICBub2RlID0gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW5vZGUpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBwcmltYXJ5ID0gbm9k
ZV9nZXRfcHJpbWFyeShub2RlKTsNCj4gPiArICAgICAgIGlmIChwcmltYXJ5ICE9IHNyYykNCj4g
PiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHN3aXRj
aCAob3Bjb2RlICYgfk9QX1VOUkVMSUFCTEUpIHsNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBjYXNlIE9Q
X0RFVl9DT01QX1NUQVRVUzoNCj4gPiArICAgICAgICAgICAgICAgaWYgKGxlbiA8IE1JTl9DT01Q
T1NJVElPTl9MRU4gfHwgIW5vZGUpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7
DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChub2RlX3BhcnNlX2NvbXBvc2l0aW9uKG5vZGUsIGRh
dGEsIGxlbikpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXByb3ZfZGJfYWRk
X25vZGVfY29tcG9zaXRpb24obm9kZSwgZGF0YSwgbGVuKSkNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICBpZiAobm9kZV9nZXRfY29tcG9zaXRpb24obm9kZSkpDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgcHJvdl9kYl9wcmludF9ub2RlX2NvbXBvc2l0aW9uKG5vZGUp
Ow0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiArDQo+ID4gKyAgICAgICBjYXNlIE9Q
X0FQUEtFWV9TVEFUVVM6DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChsZW4gIT0gNCkNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IHJsX3ByaW50ZigiTm9kZSAlNC40eCBBcHBLZXkgU3RhdHVzICVzXG4iLCBzcmMsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzaF9zdGF0dXNf
c3RyKGRhdGFbMF0pKTsNCj4gPiArICAgICAgICAgICAgICAgbmV0X2lkeCA9IGdldF9sZTE2KGRh
dGEgKyAxKSAmIDB4ZmZmOw0KPiA+ICsgICAgICAgICAgICAgICBhcHBfaWR4ID0gZ2V0X2xlMTYo
ZGF0YSArIDIpID4+IDQ7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlx0
TmV0S2V5ICUzLjN4LCBBcHBLZXkgJTMuM3hcbiIsIG5ldF9pZHgsIGFwcF9pZHgpOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgaWYgKGRhdGFbMF0gIT0gTUVTSF9TVEFUVVNfU1VDQ0VTUyAm
Jg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVswXSAhPSBNRVNIX1NU
QVRVU19JRFhfQUxSRUFEWV9TVE9SRUQgJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIG5vZGVfYXBwX2tleV9kZWxldGUobm9kZSwgbmV0X2lkeCwgYXBwX2lkeCkpDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgcHJvdl9kYl9ub2RlX2tleXMobm9kZSwgbm9kZV9nZXRf
YXBwX2tleXMobm9kZSksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhcHBLZXlzIik7DQo+ID4gKyAgICAgICAgICAg
ICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgIGNhc2UgT1BfTkVUS0VZX1NUQVRVUzoNCj4g
PiArICAgICAgICAgICAgICAgaWYgKGxlbiAhPSAzKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJOb2RlICU0
LjR4IE5ldEtleSBTdGF0dXMgJXNcbiIsIHNyYywNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNoX3N0YXR1c19zdHIoZGF0YVswXSkpOw0KPiA+
ICsgICAgICAgICAgICAgICBuZXRfaWR4ID0gZ2V0X2xlMTYoZGF0YSArIDEpICYgMHhmZmY7DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlx0TmV0S2V5ICUzLjN4XG4iLCBu
ZXRfaWR4KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChkYXRhWzBdICE9IE1FU0hf
U1RBVFVTX1NVQ0NFU1MgJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRh
dGFbMF0gIT0gTUVTSF9TVEFUVVNfSURYX0FMUkVBRFlfU1RPUkVEICYmDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGVfbmV0X2tleV9kZWxldGUobm9kZSwg
bmV0X2lkeCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHJvdl9kYl9ub2RlX2tleXMo
bm9kZSwgbm9kZV9nZXRfbmV0X2tleXMobm9kZSksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJuZXRLZXlzIik7DQo+
ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgIGNhc2UgT1BfTU9E
RUxfQVBQX1NUQVRVUzoNCj4gPiArICAgICAgICAgICAgICAgaWYgKGxlbiAhPSA3ICYmIGxlbiAh
PSA5KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAgcmxfcHJpbnRmKCJOb2RlICU0LjR4IE1vZGVsIEFwcCBTdGF0dXMgJXNcbiIs
IHNyYywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBtZXNoX3N0YXR1c19zdHIoZGF0YVswXSkpOw0KPiA+ICsgICAgICAgICAgICAgICBhZGRyID0g
Z2V0X2xlMTYoZGF0YSArIDEpOw0KPiA+ICsgICAgICAgICAgICAgICBhcHBfaWR4ID0gZ2V0X2xl
MTYoZGF0YSArIDMpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJcdEVs
ZW1lbnQgJTQuNHggQXBwSWR4ICUzLjN4XG4gIiwgYWRkciwgYXBwX2lkeCk7DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICBpZiAobGVuID09IDcpIHsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICBtb2RfaWQgPSBnZXRfbGUxNihkYXRhICsgNSk7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgcmxfcHJpbnRmKCJNb2RlbElkICU0LjR4XG4iLCBtb2RfaWQpOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIG1vZF9pZCA9IDB4ZmZmZjAwMDAgfCBtb2RfaWQ7DQo+ID4gKyAgICAg
ICAgICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbW9kX2lkID0g
Z2V0X2xlMTYoZGF0YSArIDcpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50
ZigiTW9kZWxJZCAlNC40eCAlNC40eFxuIiwgZ2V0X2xlMTYoZGF0YSArIDUpLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIG1vZF9pZCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbW9kX2lkID0g
Z2V0X2xlMTYoZGF0YSArIDUpIDw8IDE2IHwgbW9kX2lkOw0KPiA+ICsgICAgICAgICAgICAgICB9
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZGF0YVswXSA9PSBNRVNIX1NUQVRVU19T
VUNDRVNTICYmDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbm9kZV9hZGRfYmluZGluZyhu
b2RlLCBhZGRyIC0gc3JjLCBtb2RfaWQsIGFwcF9pZHgpKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHByb3ZfZGJfYWRkX2JpbmRpbmcobm9kZSwgYWRkciAtIHNyYywgbW9kX2lkLCBhcHBf
aWR4KTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKw0KPiA+ICsgICAgICAgY2Fz
ZSBPUF9DT05GSUdfREVGQVVMVF9UVExfU1RBVFVTOg0KPiA+ICsgICAgICAgICAgICAgICBpZiAo
bGVuICE9IDEpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiTm9kZSAlNC40eCBEZWZhdWx0IFRUTCAlZFxuIiwg
c3JjLCBkYXRhWzBdKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKG5vZGVfc2V0X2RlZmF1bHRf
dHRsIChub2RlLCBkYXRhWzBdKSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcm92X2Ri
X25vZGVfc2V0X3R0bChub2RlLCBkYXRhWzBdKTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7
DQo+ID4gKw0KPiA+ICsgICAgICAgY2FzZSBPUF9DT05GSUdfTU9ERUxfUFVCX1NUQVRVUzoNCj4g
PiArICAgICAgICAgICAgICAgaWYgKGxlbiAhPSAxMiAmJiBsZW4gIT0gMTQpDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAg
ICBybF9wcmludGYoIlxuU2V0IHB1YmxpY2F0aW9uIGZvciBub2RlICU0LjR4IHN0YXR1czogJXNc
biIsIHNyYywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFbMF0gPT0g
TUVTSF9TVEFUVVNfU1VDQ0VTUyA/ICJTdWNjZXNzIiA6DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzaF9zdGF0dXNfc3RyKGRhdGFbMF0pKTsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChkYXRhWzBdICE9IE1FU0hfU1RBVFVTX1NV
Q0NFU1MpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBlbGVfYWRkciA9IGdldF9sZTE2KGRhdGEgKyAxKTsNCj4gPiAr
ICAgICAgICAgICAgICAgbW9kX2lkID0gZ2V0X2xlMTYoZGF0YSArIDEwKTsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKGxlbiA9PSAxNCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtb2Rf
aWQgPSAobW9kX2lkIDw8IDE2KSAgfCBnZXRfbGUxNihkYXRhICsgMTIpOw0KPiA+ICsgICAgICAg
ICAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbW9kX2lkIHw9IDB4ZmZm
ZjAwMDA7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBwdWIudS5hZGRyMTYgPSBnZXRfbGUx
NihkYXRhICsgMyk7DQo+ID4gKyAgICAgICAgICAgICAgIHB1Yi5hcHBfaWR4ID0gZ2V0X2xlMTYo
ZGF0YSArIDUpOw0KPiA+ICsgICAgICAgICAgICAgICBwdWIudHRsID0gZGF0YVs3XTsNCj4gPiAr
ICAgICAgICAgICAgICAgcHViLnBlcmlvZCA9IGRhdGFbOF07DQo+ID4gKyAgICAgICAgICAgICAg
IG4gPSAoZGF0YVs4XSAmIDB4M2YpOw0KPiA+ICsgICAgICAgICAgICAgICBzd2l0Y2ggKGRhdGFb
OF0gPj4gNikgew0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIDA6DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgcmxfcHJpbnRmKCJQZXJpb2Q6ICVkIG1zXG4iLCBuICogMTAwKTsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSAy
Og0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG4gKj0gMTA7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgLyogZmFsbCB0aHJvdWdoICovDQo+ID4gKyAgICAgICAgICAgICAgIGNhc2Ug
MToNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIlBlcmlvZDogJWQgc2Vj
XG4iLCBuKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAg
ICAgICAgICAgY2FzZSAzOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50Zigi
UGVyaW9kOiAlZCBtaW5cbiIsIG4gKiAxMCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
YnJlYWs7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IHB1Yi5yZXRyYW5zbWl0ID0gZGF0YVs5XTsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRm
KCJSZXRyYW5zbWl0IGNvdW50OiAlZFxuIiwgZGF0YVs5XSA+PiA1KTsNCj4gPiArICAgICAgICAg
ICAgICAgcmxfcHJpbnRmKCJSZXRyYW5zbWl0IEludGVydmFsIFN0ZXBzOiAlZFxuIiwgZGF0YVs5
XSAmIDB4MWYpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgZWxlX2lkeCA9IGVsZV9hZGRy
IC0gbm9kZV9nZXRfcHJpbWFyeShub2RlKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8q
IExvY2FsIGNvbmZpZ3VyYXRpb24gaXMgc2F2ZWQgYnkgc2VydmVyICovDQo+ID4gKyAgICAgICAg
ICAgICAgIGlmIChub2RlID09IG5vZGVfZ2V0X2xvY2FsX25vZGUoKSkNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBicmVhazsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChub2Rl
X21vZGVsX3B1Yl9zZXQobm9kZSwgZWxlX2lkeCwgbW9kX2lkLCAmcHViKSkNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBwcm92X2RiX25vZGVfc2V0X21vZGVsX3B1Yihub2RlLCBlbGVfaWR4
LCBtb2RfaWQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGVf
bW9kZWxfcHViX2dldChub2RlLCBlbGVfaWR4LCBtb2RfaWQpKTsNCj4gPiArICAgICAgICAgICAg
ICAgYnJlYWs7DQo+ID4gKyAgICAgICB9DQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiAr
fQ0KPiA+ICsNCj4gPiArc3RhdGljIHVpbnQzMl90IHRhcmdldDsNCj4gPiArc3RhdGljIHVpbnQz
Ml90IHBhcm1zWzhdOw0KPiA+ICsNCj4gPiArc3RhdGljIHVpbnQzMl90IHJlYWRfaW5wdXRfcGFy
YW1ldGVycyhjb25zdCBjaGFyICphcmdzKQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50MzJfdCBp
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmICghYXJncykNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuIDA7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtc2V0KHBhcm1zLCAweGZmLCBzaXplb2YocGFy
bXMpKTsNCj4gPiArDQo+ID4gKyAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2l6ZW9mKHBhcm1zKS9z
aXplb2YocGFybXNbMF0pOyBpKyspIHsNCj4gPiArICAgICAgICAgICAgICAgaW50IG47DQo+ID4g
Kw0KPiA+ICsgICAgICAgICAgICAgICBzc2NhbmYoYXJncywgIiV4IiwgJnBhcm1zW2ldKTsNCj4g
PiArICAgICAgICAgICAgICAgaWYgKHBhcm1zW2ldID09IDB4ZmZmZmZmZmYpDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBuID0g
c3RyY3NwbihhcmdzLCAiIFx0Iik7DQo+ID4gKyAgICAgICAgICAgICAgIGFyZ3MgPSBhcmdzICsg
biArIHN0cnNwbihhcmdzICsgbiwgIiBcdCIpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiAr
ICAgICAgIHJldHVybiBpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfc2V0
X25vZGUoY29uc3QgY2hhciAqYXJncykNCj4gPiArew0KPiA+ICsgICAgICAgdWludDMyX3QgZHN0
Ow0KPiA+ICsgICAgICAgY2hhciAqZW5kOw0KPiA+ICsNCj4gPiArICAgICAgIGRzdCA9IHN0cnRv
bChhcmdzLCAmZW5kLCAxNik7DQo+ID4gKyAgICAgICBpZiAoZW5kICE9IChhcmdzICsgNCkpIHsN
Cj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJCYWQgdW5pY2FzdCBhZGRyZXNzICVzOiAi
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJleHBlY3RlZCBm
b3JtYXQgNCBkaWdpdCBoZXhcbiIsIGFyZ3MpOw0KPiA+ICsgICAgICAgICAgICAgICB0YXJnZXQg
PSBVTkFTU0lHTkVEX0FERFJFU1M7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAg
ICAgICAgICBybF9wcmludGYoIkNvbmZpZ3VyaW5nIG5vZGUgJTQuNHhcbiIsIGRzdCk7DQo+ID4g
KyAgICAgICAgICAgICAgIHRhcmdldCA9IGRzdDsNCj4gPiArICAgICAgICAgICAgICAgc2V0X21l
bnVfcHJvbXB0KCJjb25maWciLCBhcmdzKTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gK30N
Cj4gPiArDQo+ID4gK3N0YXRpYyBib29sIGNvbmZpZ19zZW5kKHVpbnQ4X3QgKmJ1ZiwgdWludDE2
X3QgbGVuKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2RlID0gbm9k
ZV9nZXRfbG9jYWxfbm9kZSgpOw0KPiA+ICsgICAgICAgdWludDE2X3QgcHJpbWFyeTsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZighbm9kZSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNl
Ow0KPiA+ICsNCj4gPiArICAgICAgIHByaW1hcnkgPSBub2RlX2dldF9wcmltYXJ5KG5vZGUpOw0K
PiA+ICsgICAgICAgaWYgKHRhcmdldCAhPSBwcmltYXJ5KQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gbmV0X2FjY2Vzc19sYXllcl9zZW5kKERFRkFVTFRfVFRMLCBwcmltYXJ5LA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldCwgQVBQ
X0lEWF9ERVYsIGJ1ZiwgbGVuKTsNCj4gPiArDQo+ID4gKyAgICAgICBub2RlX2xvY2FsX2RhdGFf
aGFuZGxlcihwcmltYXJ5LCB0YXJnZXQsIG5vZGVfZ2V0X2l2X2luZGV4KG5vZGUpLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9kZV9nZXRfc2VxdWVuY2VfbnVtYmVyKG5v
ZGUpLCBBUFBfSURYX0RFViwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1
ZiwgbGVuKTsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiArc3RhdGljIHZvaWQgY21kX2dldF9jb21wb3NpdGlvbihjb25zdCBjaGFyICphcmdzKQ0K
PiA+ICt7DQo+ID4gKyAgICAgICB1aW50MTZfdCBuOw0KPiA+ICsgICAgICAgdWludDhfdCBtc2db
MzJdOw0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbm9kZSAqbm9kZTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAoSVNfVU5BU1NJR05FRCh0YXJnZXQpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJs
X3ByaW50ZigiRGVzdGluYXRpb24gbm90IHNldFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBub2RlID0gbm9kZV9maW5k
X2J5X2FkZHIodGFyZ2V0KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW5vZGUpDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBuID0gbWVzaF9vcGNvZGVf
c2V0KE9QX0RFVl9DT01QX0dFVCwgbXNnKTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBCeSBkZWZh
dWx0LCB1c2UgcGFnZSAwICovDQo+ID4gKyAgICAgICBtc2dbbisrXSA9IChyZWFkX2lucHV0X3Bh
cmFtZXRlcnMoYXJncykgPT0gMSkgPyBwYXJtc1swXSA6IDA7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKCFjb25maWdfc2VuZChtc2csIG4pKQ0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYo
IkZhaWxlZCB0byBzZW5kIFwiR0VUIE5PREUgQ09NUE9TSVRJT05cIlxuIik7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9uZXRfa2V5KGNvbnN0IGNoYXIgKmFyZ3MsIHVpbnQz
Ml90IG9wY29kZSkNCj4gPiArew0KPiA+ICsgICAgICAgdWludDE2X3QgbjsNCj4gPiArICAgICAg
IHVpbnQ4X3QgbXNnWzMyXTsNCj4gPiArICAgICAgIHVpbnQxNl90IG5ldF9pZHg7DQo+ID4gKyAg
ICAgICB1aW50OF90ICprZXk7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2RlOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChJU19VTkFTU0lHTkVEKHRhcmdldCkpIHsNCj4gPiArICAg
ICAgICAgICAgICAgcmxfcHJpbnRmKCJEZXN0aW5hdGlvbiBub3Qgc2V0XG4iKTsNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIG4g
PSBtZXNoX29wY29kZV9zZXQob3Bjb2RlLCBtc2cpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChy
ZWFkX2lucHV0X3BhcmFtZXRlcnMoYXJncykgIT0gMSkgew0KPiA+ICsgICAgICAgICAgICAgICBy
bF9wcmludGYoIkJhZCBhcmd1bWVudHMgJXNcbiIsIGFyZ3MpOw0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgbm9kZSA9IG5vZGVf
ZmluZF9ieV9hZGRyKHRhcmdldCk7DQo+ID4gKyAgICAgICBpZiAoIW5vZGUpIHsNCj4gPiArICAg
ICAgICAgICAgICAgcmxfcHJpbnRmKCJOb2RlICU0LjR4XG4gbm90IGZvdW5kIiwgdGFyZ2V0KTsN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiAr
ICAgICAgIG5ldF9pZHggPSBwYXJtc1swXTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAob3Bjb2Rl
ICE9IE9QX05FVEtFWV9ERUxFVEUpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGtleSA9
IGtleXNfbmV0X2tleV9nZXQobmV0X2lkeCwgdHJ1ZSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlm
ICgha2V5KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJOZXR3b3Jr
IGtleSB3aXRoIGluZGV4ICU0LjR4IG5vdCBmb3VuZFxuIiwNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV0X2lkeCk7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgICAgICAg
ICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBwdXRfbGUxNihuZXRfaWR4LCAmbXNnW25d
KTsNCj4gPiArICAgICAgICAgICAgICAgbiArPSAyOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgbWVtY3B5KG1zZyArIG4sIGtleSwgMTYpOw0KPiA+ICsgICAgICAgICAgICAgICBuICs9IDE2
Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmICghY29uZmlnX3NlbmQobXNn
LCBuKSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkZhaWxlZCB0byBzZW5kIFwi
JXMgTkVUIEtFWVwiXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3Bj
b2RlID09IE9QX05FVEtFWV9BREQgPyAiQUREIiA6ICJERUwiKTsNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmIChvcGNvZGUg
IT0gT1BfTkVUS0VZX0RFTEVURSkgew0KPiA+ICsgICAgICAgICAgICAgICBpZiAobm9kZV9uZXRf
a2V5X2FkZChub2RlLCBuZXRfaWR4KSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcm92
X2RiX25vZGVfa2V5cyhub2RlLCBub2RlX2dldF9uZXRfa2V5cyhub2RlKSwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
Im5ldEtleXMiKTsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlm
IChub2RlX25ldF9rZXlfZGVsZXRlKG5vZGUsIG5ldF9pZHgpKQ0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIHByb3ZfZGJfbm9kZV9rZXlzKG5vZGUsIG5vZGVfZ2V0X25ldF9rZXlzKG5vZGUp
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAibmV0S2V5cyIpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21kX2FkZF9uZXRfa2V5KGNvbnN0IGNoYXIgKmFyZ3Mp
DQo+ID4gK3sNCj4gPiArICAgICAgIGNtZF9uZXRfa2V5KGFyZ3MsIE9QX05FVEtFWV9BREQpOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfZGVsX25ldF9rZXkoY29uc3QgY2hh
ciAqYXJncykNCj4gPiArew0KPiA+ICsgICAgICAgY21kX25ldF9rZXkoYXJncywgT1BfTkVUS0VZ
X0RFTEVURSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9hcHBfa2V5KGNv
bnN0IGNoYXIgKmFyZ3MsIHVpbnQzMl90IG9wY29kZSkNCj4gPiArew0KPiA+ICsgICAgICAgdWlu
dDE2X3QgbjsNCj4gPiArICAgICAgIHVpbnQ4X3QgbXNnWzMyXTsNCj4gPiArICAgICAgIHVpbnQx
Nl90IG5ldF9pZHg7DQo+ID4gKyAgICAgICB1aW50MTZfdCBhcHBfaWR4Ow0KPiA+ICsgICAgICAg
dWludDhfdCAqa2V5Ow0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbm9kZSAqbm9kZTsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZiAoSVNfVU5BU1NJR05FRCh0YXJnZXQpKSB7DQo+ID4gKyAgICAgICAg
ICAgICAgIHJsX3ByaW50ZigiRGVzdGluYXRpb24gbm90IHNldFxuIik7DQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAocmVh
ZF9pbnB1dF9wYXJhbWV0ZXJzKGFyZ3MpICE9IDEpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxf
cHJpbnRmKCJCYWQgYXJndW1lbnRzICVzXG4iLCBhcmdzKTsNCj4gPiArICAgICAgICAgICAgICAg
cmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIG5vZGUgPSBub2RlX2Zp
bmRfYnlfYWRkcih0YXJnZXQpOw0KPiA+ICsgICAgICAgaWYgKCFub2RlKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgIHJsX3ByaW50ZigiTm9kZSAlNC40eFxuIG5vdCBmb3VuZCIsIHRhcmdldCk7DQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICBuID0gbWVzaF9vcGNvZGVfc2V0KG9wY29kZSwgbXNnKTsNCj4gPiArDQo+ID4gKyAgICAg
ICBhcHBfaWR4ID0gcGFybXNbMF07DQo+ID4gKyAgICAgICBuZXRfaWR4ID0ga2V5c19hcHBfa2V5
X2dldF9ib3VuZChhcHBfaWR4KTsNCj4gPiArICAgICAgIGlmIChuZXRfaWR4ID09IE5FVF9JRFhf
SU5WQUxJRCkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkFwcCBrZXkgd2l0aCBp
bmRleCAlNC40eCBub3QgZm91bmRcbiIsIGFwcF9pZHgpOw0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgbXNnW24rK10gPSBuZXRf
aWR4ICYgMHhmOw0KPiA+ICsgICAgICAgbXNnW24rK10gPSAoKG5ldF9pZHggPj4gOCkgJiAweGYp
IHwNCj4gPiArICAgICAgICAgICAgICAgKChhcHBfaWR4IDw8IDQpICYgMHhmMCk7DQo+ID4gKyAg
ICAgICBtc2dbbisrXSA9IGFwcF9pZHggPj4gNDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAob3Bj
b2RlICE9IE9QX0FQUEtFWV9ERUxFVEUpIHsNCj4gPiArICAgICAgICAgICAgICAga2V5ID0ga2V5
c19hcHBfa2V5X2dldChhcHBfaWR4LCB0cnVlKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFr
ZXkpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIkFwcCBrZXkgJTQu
NHggbm90IGZvdW5kXG4iLCBuZXRfaWR4KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBy
ZXR1cm47DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IG1lbWNweShtc2cgKyBuLCBrZXksIDE2KTsNCj4gPiArICAgICAgICAgICAgICAgbiArPSAxNjsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWNvbmZpZ19zZW5kKG1zZywg
bikpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gc2VuZCBcIkFE
RCAlcyBLRVlcIlxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wY29k
ZSA9PSBPUF9BUFBLRVlfQUREID8gIkFERCIgOiAiREVMIik7DQo+ID4gKyAgICAgICAgICAgICAg
IHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAob3Bjb2RlICE9
IE9QX0FQUEtFWV9ERUxFVEUpIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKG5vZGVfYXBwX2tl
eV9hZGQobm9kZSwgYXBwX2lkeCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHJvdl9k
Yl9ub2RlX2tleXMobm9kZSwgbm9kZV9nZXRfYXBwX2tleXMobm9kZSksDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJh
cHBLZXlzIik7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBpZiAo
bm9kZV9hcHBfa2V5X2RlbGV0ZShub2RlLCBuZXRfaWR4LCBhcHBfaWR4KSkNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBwcm92X2RiX25vZGVfa2V5cyhub2RlLCBub2RlX2dldF9hcHBfa2V5
cyhub2RlKSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgImFwcEtleXMiKTsNCj4gPiArICAgICAgIH0NCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21kX2FkZF9hcHBfa2V5KGNvbnN0IGNoYXIgKmFyZ3Mp
DQo+ID4gK3sNCj4gPiArICAgICAgIGNtZF9hcHBfa2V5KGFyZ3MsIE9QX0FQUEtFWV9BREQpOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfZGVsX2FwcF9rZXkoY29uc3QgY2hh
ciAqYXJncykNCj4gPiArew0KPiA+ICsgICAgICAgY21kX2FwcF9rZXkoYXJncywgT1BfQVBQS0VZ
X0RFTEVURSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9iaW5kKGNvbnN0
IGNoYXIgKmFyZ3MpDQo+ID4gK3sNCj4gPiArICAgICAgIHVpbnQxNl90IG47DQo+ID4gKyAgICAg
ICB1aW50OF90IG1zZ1szMl07DQo+ID4gKyAgICAgICBpbnQgcGFybV9jbnQ7DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKElTX1VOQVNTSUdORUQodGFyZ2V0KSkgew0KPiA+ICsgICAgICAgICAgICAg
ICBybF9wcmludGYoIkRlc3RpbmF0aW9uIG5vdCBzZXRcbiIpOw0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcGFybV9jbnQgPSBy
ZWFkX2lucHV0X3BhcmFtZXRlcnMoYXJncyk7DQo+ID4gKyAgICAgICBpZiAocGFybV9jbnQgIT0g
MyAmJiBwYXJtX2NudCAhPSA0KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiQmFk
IGFyZ3VtZW50cyAlc1xuIiwgYXJncyk7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4g
PiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBuID0gbWVzaF9vcGNvZGVfc2V0KE9QX01P
REVMX0FQUF9CSU5ELCBtc2cpOw0KPiA+ICsNCj4gPiArICAgICAgIHB1dF9sZTE2KHRhcmdldCAr
IHBhcm1zWzBdLCBtc2cgKyBuKTsNCj4gPiArICAgICAgIG4gKz0gMjsNCj4gPiArICAgICAgIHB1
dF9sZTE2KHBhcm1zWzFdLCBtc2cgKyBuKTsNCj4gPiArICAgICAgIG4gKz0gMjsNCj4gPiArICAg
ICAgIGlmIChwYXJtX2NudCA9PSA0KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHB1dF9sZTE2KHBh
cm1zWzNdLCBtc2cgKyBuKTsNCj4gPiArICAgICAgICAgICAgICAgcHV0X2xlMTYocGFybXNbMl0s
IG1zZyArIG4gKyAyKTsNCj4gPiArICAgICAgICAgICAgICAgbiArPSA0Ow0KPiA+ICsgICAgICAg
fSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgcHV0X2xlMTYocGFybXNbMl0sIG1zZyArIG4p
Ow0KPiA+ICsgICAgICAgICAgICAgICBuICs9IDI7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKCFjb25maWdfc2VuZChtc2csIG4pKQ0KPiA+ICsgICAgICAgICAgICAgICBy
bF9wcmludGYoIkZhaWxlZCB0byBzZW5kIFwiTU9ERUwgQVBQIEJJTkRcIlxuIik7DQo+ID4gK30N
Cj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9zZXRfdHRsKGNvbnN0IGNoYXIgKmFyZ3MpDQo+
ID4gK3sNCj4gPiArICAgICAgIHVpbnQxNl90IG47DQo+ID4gKyAgICAgICB1aW50OF90IG1zZ1sz
Ml07DQo+ID4gKyAgICAgICBpbnQgcGFybV9jbnQ7DQo+ID4gKyAgICAgICB1aW50OF90IHR0bDsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAoSVNfVU5BU1NJR05FRCh0YXJnZXQpKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIHJsX3ByaW50ZigiRGVzdGluYXRpb24gbm90IHNldFxuIik7DQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBu
ID0gbWVzaF9vcGNvZGVfc2V0KE9QX0NPTkZJR19ERUZBVUxUX1RUTF9TRVQsIG1zZyk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgcGFybV9jbnQgPSByZWFkX2lucHV0X3BhcmFtZXRlcnMoYXJncyk7DQo+
ID4gKyAgICAgICBpZiAocGFybV9jbnQpIHsNCj4gPiArICAgICAgICAgICAgICAgdHRsID0gcGFy
bXNbMF0gJiBUVExfTUFTSzsNCj4gPiArICAgICAgIH0gZWxzZQ0KPiA+ICsgICAgICAgICAgICAg
ICB0dGwgPSBub2RlX2dldF9kZWZhdWx0X3R0bChub2RlX2dldF9sb2NhbF9ub2RlKCkpOw0KPiA+
ICsNCj4gPiArICAgICAgIG1zZ1tuKytdID0gdHRsOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICgh
Y29uZmlnX3NlbmQobXNnLCBuKSkNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWls
ZWQgdG8gc2VuZCBcIlNFVF9ERUZBVUxUIFRUTFwiXG4iKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
c3RhdGljIHZvaWQgY21kX3NldF9wdWIoY29uc3QgY2hhciAqYXJncykNCj4gPiArew0KPiA+ICsg
ICAgICAgdWludDE2X3QgbjsNCj4gPiArICAgICAgIHVpbnQ4X3QgbXNnWzMyXTsNCj4gPiArICAg
ICAgIGludCBwYXJtX2NudDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoSVNfVU5BU1NJR05FRCh0
YXJnZXQpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRGVzdGluYXRpb24gbm90
IHNldFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gKyAgICAgICBuID0gbWVzaF9vcGNvZGVfc2V0KE9QX0NPTkZJR19NT0RFTF9QVUJf
U0VULCBtc2cpOw0KPiA+ICsNCj4gPiArICAgICAgIHBhcm1fY250ID0gcmVhZF9pbnB1dF9wYXJh
bWV0ZXJzKGFyZ3MpOw0KPiA+ICsgICAgICAgaWYgKHBhcm1fY250ICE9IDUpIHsNCj4gPiArICAg
ICAgICAgICAgICAgcmxfcHJpbnRmKCJCYWQgYXJndW1lbnRzOiAlc1xuIiwgYXJncyk7DQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAg
ICBwdXRfbGUxNihwYXJtc1swXSwgbXNnICsgbik7DQo+ID4gKyAgICAgICBuICs9IDI7DQo+ID4g
KyAgICAgICAvKiBQdWJsaXNoIGFkZHJlc3MgKi8NCj4gPiArICAgICAgIHB1dF9sZTE2KHBhcm1z
WzFdLCBtc2cgKyBuKTsNCj4gPiArICAgICAgIG4gKz0gMjsNCj4gPiArICAgICAgIC8qIEFwcCBr
ZXkgaW5kZXggKyBjcmVkZW50aWFsIChzZXQgdG8gMCkgKi8NCj4gPiArICAgICAgIHB1dF9sZTE2
KHBhcm1zWzJdLCBtc2cgKyBuKTsNCj4gPiArICAgICAgIG4gKz0gMjsNCj4gPiArICAgICAgIC8q
IFRUTCAqLw0KPiA+ICsgICAgICAgbXNnW24rK10gPSBERUZBVUxUX1RUTDsNCj4gPiArICAgICAg
IC8qIFB1Ymxpc2ggcGVyaW9kICBzdGVwIGNvdW50IGFuZCBzdGVwIHJlc29sdXRpb24gKi8NCj4g
PiArICAgICAgIG1zZ1tuKytdID0gcGFybXNbM107DQo+ID4gKyAgICAgICAvKiBQdWJsaXNoIHJl
dHJhbnNtaXQgY291bnQgJiBpbnRlcnZhbCBzdGVwcyAqLw0KPiA+ICsgICAgICAgbXNnW24rK10g
PSAoMSA8PCA1KSArIDI7DQo+ID4gKyAgICAgICAvKiBNb2RlbCBJZCAqLw0KPiA+ICsgICAgICAg
aWYgKHBhcm1zWzRdID4gMHhmZmZmKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHB1dF9sZTE2KHBh
cm1zWzRdID4+IDE2LCBtc2cgKyBuKTsNCj4gPiArICAgICAgICAgICAgICAgcHV0X2xlMTYocGFy
bXNbNF0sIG1zZyArIG4gKyAyKTsNCj4gPiArICAgICAgICAgICAgICAgbiArPSA0Ow0KPiA+ICsg
ICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgcHV0X2xlMTYocGFybXNbNF0sIG1z
ZyArIG4pOw0KPiA+ICsgICAgICAgICAgICAgICBuICs9IDI7DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKCFjb25maWdfc2VuZChtc2csIG4pKQ0KPiA+ICsgICAgICAgICAg
ICAgICBybF9wcmludGYoIkZhaWxlZCB0byBzZW5kIFwiU0VUIE1PREVMIFBVQkxJQ0FUSU9OXCJc
biIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfZGVmYXVsdCh1aW50MzJf
dCBvcGNvZGUpDQo+ID4gK3sNCj4gPiArICAgICAgIHVpbnQxNl90IG47DQo+ID4gKyAgICAgICB1
aW50OF90IG1zZ1szMl07DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKElTX1VOQVNTSUdORUQodGFy
Z2V0KSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkRlc3RpbmF0aW9uIG5vdCBz
ZXRcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgbiA9IG1lc2hfb3Bjb2RlX3NldChvcGNvZGUsIG1zZyk7DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYgKCFjb25maWdfc2VuZChtc2csIG4pKQ0KPiA+ICsgICAgICAgICAgICAg
ICBybF9wcmludGYoIkZhaWxlZCB0byBzZW5kIGNvbW1hbmQgKG9wY29kZSAweCV4KVxuIiwgb3Bj
b2RlKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21kX2dldF90dGwoY29uc3Qg
Y2hhciAqYXJncykNCj4gPiArew0KPiA+ICsgICAgICAgY21kX2RlZmF1bHQoT1BfQ09ORklHX0RF
RkFVTFRfVFRMX0dFVCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9iYWNr
KGNvbnN0IGNoYXIgKmFyZ3MpDQo+ID4gK3sNCj4gPiArICAgICAgIGNtZF9tZW51X21haW4oZmFs
c2UpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfaGVscChjb25zdCBjaGFy
ICphcmdzKTsNCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgbWVudV9lbnRyeSBjZmdf
bWVudVtdID0gew0KPiA+ICsgICAgICAgeyJ0YXJnZXQiLCAgICAgICAgICAgICAgIjx1bmljYXN0
PiIsICAgICAgICAgICAgICAgICAgICBjbWRfc2V0X25vZGUsDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNldCB0YXJnZXQgbm9kZSB0byBjb25m
aWd1cmUifSwNCj4gPiArICAgICAgIHsiZ2V0LWNvbXBvc2l0aW9uIiwgICAgICJbPHBhZ2VfbnVt
Pl0iLCAgICAgICAgIGNtZF9nZXRfY29tcG9zaXRpb24sDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdldCBDb21wb3NpdGlvbiBEYXRhIn0sDQo+
ID4gKyAgICAgICB7ImFkZC1uZXRrZXkiLCAgICAgICAgICAiPG5ldF9pZHg+IiwgICAgICAgICAg
ICAgICAgICAgIGNtZF9hZGRfbmV0X2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAiQWRkIG5ldHdvcmsga2V5In0sDQo+ID4gKyAgICAgICB7
ImRlbC1uZXRrZXkiLCAgICAgICAgICAiPG5ldF9pZHg+IiwgICAgICAgICAgICAgICAgICAgIGNt
ZF9kZWxfbmV0X2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAiRGVsZXRlIG5ldHdvcmsga2V5In0sDQo+ID4gKyAgICAgICB7ImFkZC1hcHBr
ZXkiLCAgICAgICAgICAiPGFwcF9pZHg+IiwgICAgICAgICAgICAgICAgICAgIGNtZF9hZGRfYXBw
X2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAiQWRkIGFwcGxpY2F0aW9uIGtleSJ9LA0KPiA+ICsgICAgICAgeyJkZWwtYXBwa2V5IiwgICAg
ICAgICAgIjxhcHBfaWR4PiIsICAgICAgICAgICAgICAgICAgICBjbWRfZGVsX2FwcF9rZXksDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRlbGV0
ZSBhcHBsaWNhdGlvbiBrZXkifSwNCj4gPiArICAgICAgIHsiYmluZCIsICAgICAgICAgICAgICAg
ICI8ZWxlX2lkeD4gPGFwcF9pZHg+IDxtb2RfaWQ+IFtjaWRdIiwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIGNtZF9iaW5kLCAgICAgICAiQmluZCBhcHAga2V5IHRvIGEgbW9k
ZWwifSwNCj4gPiArICAgICAgIHsic2V0LXR0bCIsICAgICAgICAgICAgICI8dHRsPiIsICAgICAg
ICAgICAgICAgICAgICAgICAgY21kX3NldF90dGwsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNldCBkZWZhdWx0IFRUTCJ9LA0KPiA+ICsgICAg
ICAgeyJnZXQtdHRsIiwgICAgICAgICAgICAgTlVMTCwgICAgICAgICAgICAgICAgICAgY21kX2dl
dF90dGwsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIkdldCBkZWZhdWx0IFRUTCJ9LA0KPiA+ICsgICAgICAgeyJzZXQtcHViIiwgIjxlbGVfYWRk
cj4gPHB1Yl9hZGRyPiA8YXBwX2lkeD4gIg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICI8cGVyaW9kIChzdGVwfHJlcyk+IDxtb2RlbD4iLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY21kX3NldF9wdWIsICAgICJTZXQgcHVi
bGljYXRpb24ifSwNCj4gPiArICAgICAgIHsiYmFjayIsICAgICAgICAgICAgICAgIE5VTEwsICAg
ICAgICAgICAgICAgICAgICAgICAgICAgY21kX2JhY2ssDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJhY2sgdG8gbWFpbiBtZW51In0sDQo+ID4g
KyAgICAgICB7ImhlbHAiLCAgICAgICAgICAgICAgICBOVUxMLCAgICAgICAgICAgICAgICAgICAg
ICAgICAgIGNtZF9oZWxwLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICJDb25maWcgQ29tbWFuZHMifSwNCj4gPiArICAgICAgIHt9DQo+ID4gK307
DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfaGVscChjb25zdCBjaGFyICphcmdzKQ0KPiA+
ICt7DQo+ID4gKyAgICAgICBybF9wcmludGYoIkNsaWVudCBDb25maWd1cmF0aW9uIE1lbnVcbiIp
Ow0KPiA+ICsgICAgICAgcHJpbnRfY21kX21lbnUoY2ZnX21lbnUpOw0KPiA+ICt9DQo+ID4gKw0K
PiA+ICt2b2lkIGNvbmZpZ19zZXRfbm9kZShjb25zdCBjaGFyICphcmdzKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICBjbWRfc2V0X25vZGUoYXJncyk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgY29u
ZmlnX2NsaWVudF9nZXRfY29tcG9zaXRpb24odWludDMyX3QgZHN0KQ0KPiA+ICt7DQo+ID4gKyAg
ICAgICB1aW50MzJfdCB0bXAgPSB0YXJnZXQ7DQo+ID4gKw0KPiA+ICsgICAgICAgdGFyZ2V0ID0g
ZHN0Ow0KPiA+ICsgICAgICAgY21kX2dldF9jb21wb3NpdGlvbigiIik7DQo+ID4gKyAgICAgICB0
YXJnZXQgPSB0bXA7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgbWVzaF9tb2Rl
bF9vcHMgY2xpZW50X2NicyA9IHsNCj4gPiArICAgICAgIGNsaWVudF9tc2dfcmVjdmQsDQo+ID4g
KyAgICAgICAgICAgICAgIE5VTEwsDQo+ID4gKyAgICAgICAgICAgICAgIE5VTEwsDQo+ID4gKyAg
ICAgICAgICAgICAgIE5VTEwNCj4gPiArfTsNCj4gPiArDQo+ID4gK2Jvb2wgY29uZmlnX2NsaWVu
dF9pbml0KHZvaWQpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmICghbm9kZV9sb2NhbF9tb2RlbF9y
ZWdpc3RlcihQUklNQVJZX0VMRU1FTlRfSURYLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIENPTkZJR19DTElFTlRfTU9ERUxfSUQsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJmNsaWVudF9jYnMs
IE5VTEwpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsg
ICAgICAgYWRkX2NtZF9tZW51KCJjb25maWd1cmUiLCBjZmdfbWVudSk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiBkaWZmIC0tZ2l0IGEvbWVzaC9jb25maWct
c2VydmVyLmMgYi9tZXNoL2NvbmZpZy1zZXJ2ZXIuYw0KPiA+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0
DQo+ID4gaW5kZXggMDAwMDAwMC4uMTRlNWQ3Yg0KPiA+IC0tLSAvZGV2L251bGwNCj4gPiArKysg
Yi9tZXNoL2NvbmZpZy1zZXJ2ZXIuYw0KPiA+IEBAIC0wLDAgKzEsMTY1IEBADQo+ID4gKy8qDQo+
ID4gKyAqDQo+ID4gKyAqICBCbHVlWiAtIEJsdWV0b290aCBwcm90b2NvbCBzdGFjayBmb3IgTGlu
dXgNCj4gPiArICoNCj4gPiArICogIENvcHlyaWdodCAoQykgMjAxNyAgSW50ZWwgQ29ycG9yYXRp
b24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQo+ID4gKyAqDQo+ID4gKyAqDQo+ID4gKyAqICBUaGlz
IGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29y
DQo+ID4gKyAqICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdl
bmVyYWwgUHVibGljDQo+ID4gKyAqICBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBT
b2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXINCj4gPiArICogIHZlcnNpb24gMi4xIG9mIHRoZSBM
aWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLg0KPiA+ICsgKg0K
PiA+ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQg
d2lsbCBiZSB1c2VmdWwsDQo+ID4gKyAqICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhv
dXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZg0KPiA+ICsgKiAgTUVSQ0hBTlRBQklMSVRZ
IG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQ0KPiBHTlUNCj4g
PiArICogIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuDQo+
ID4gKyAqDQo+ID4gKyAqICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBH
TlUgTGVzc2VyIEdlbmVyYWwgUHVibGljDQo+ID4gKyAqICBMaWNlbnNlIGFsb25nIHdpdGggdGhp
cyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlDQo+ID4gKyAqICBG
b3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEg
IDAyMTEwLTEzMDENCj4gVVNBDQo+ID4gKyAqDQo+ID4gKyAqLw0KPiA+ICsNCj4gPiArI2lmZGVm
IEhBVkVfQ09ORklHX0gNCj4gPiArI2luY2x1ZGUgPGNvbmZpZy5oPg0KPiA+ICsjZW5kaWYNCj4g
PiArDQo+ID4gKyNpbmNsdWRlIDxzdGRpby5oPg0KPiA+ICsjaW5jbHVkZSA8ZXJybm8uaD4NCj4g
PiArI2luY2x1ZGUgPHVuaXN0ZC5oPg0KPiA+ICsjaW5jbHVkZSA8c3RkbGliLmg+DQo+ID4gKyNp
bmNsdWRlIDxzdGRib29sLmg+DQo+ID4gKyNpbmNsdWRlIDxpbnR0eXBlcy5oPg0KPiA+ICsjaW5j
bHVkZSA8c3RkYm9vbC5oPg0KPiA+ICsjaW5jbHVkZSA8c3lzL3Vpby5oPg0KPiA+ICsjaW5jbHVk
ZSA8d29yZGV4cC5oPg0KPiA+ICsjaW5jbHVkZSA8cmVhZGxpbmUvcmVhZGxpbmUuaD4NCj4gPiAr
I2luY2x1ZGUgPHJlYWRsaW5lL2hpc3RvcnkuaD4NCj4gPiArI2luY2x1ZGUgPGdsaWIuaD4NCj4g
PiArDQo+ID4gKyNpbmNsdWRlICJzcmMvc2hhcmVkL3V0aWwuaCINCj4gPiArI2luY2x1ZGUgImNs
aWVudC9kaXNwbGF5LmgiDQo+ID4gKyNpbmNsdWRlICJtZXNoLW5ldC5oIg0KPiA+ICsjaW5jbHVk
ZSAia2V5cy5oIg0KPiA+ICsjaW5jbHVkZSAibmV0LmgiDQo+ID4gKyNpbmNsdWRlICJub2RlLmgi
DQo+ID4gKyNpbmNsdWRlICJwcm92LWRiLmgiDQo+ID4gKyNpbmNsdWRlICJ1dGlsLmgiDQo+ID4g
KyNpbmNsdWRlICJjb25maWctbW9kZWwuaCINCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHNlcnZl
cl9tc2dfcmVjdmQodWludDE2X3Qgc3JjLCB1aW50OF90ICpkYXRhLA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgdWludDE2X3QgbGVuLCB2b2lkICp1c2VyX2RhdGEpDQo+ID4g
K3sNCj4gPiArICAgICAgIHVpbnQzMl90IG9wY29kZTsNCj4gPiArICAgICAgIHVpbnQ4X3QgbXNn
WzMyXTsNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX25vZGUgKm5vZGU7DQo+ID4gKyAgICAgICB1
aW50MTZfdCBwcmltYXJ5Ow0KPiA+ICsgICAgICAgdWludDMyX3QgbW9kX2lkOw0KPiA+ICsgICAg
ICAgdWludDE2X3QgZWxlX2FkZHI7DQo+ID4gKyAgICAgICB1aW50OF90IGVsZV9pZHg7DQo+ID4g
KyAgICAgICBzdHJ1Y3QgbWVzaF9wdWJsaWNhdGlvbiBwdWI7DQo+ID4gKw0KPiA+ICsgICAgICAg
aW50IG47DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKG1lc2hfb3Bjb2RlX2dldChkYXRhLCBsZW4s
ICZvcGNvZGUsICZuKSkgew0KPiA+ICsgICAgICAgICAgICAgICBsZW4gLT0gbjsNCj4gPiArICAg
ICAgICAgICAgICAgZGF0YSArPSBuOw0KPiA+ICsgICAgICAgfSBlbHNlDQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBub2RlID0gbm9kZV9nZXRf
bG9jYWxfbm9kZSgpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbm9kZSkNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAgc3dpdGNoIChvcGNvZGUg
JiB+T1BfVU5SRUxJQUJMRSkgew0KPiA+ICsgICAgICAgZGVmYXVsdDoNCj4gPiArICAgICAgICAg
ICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGNhc2UgT1BfQ09ORklHX0RF
RkFVTFRfVFRMX1NFVDoNCj4gPiArICAgICAgICAgICAgICAgaWYgKGxlbiAhPSAxIHx8IGRhdGFb
MF0gPiBUVExfTUFTSyB8fCBkYXRhWzBdID09IDEpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZGF0YVswXSA8
PSBUVExfTUFTSykgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG5vZGVfc2V0X2RlZmF1
bHRfdHRsKG5vZGUsIGRhdGFbMF0pOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHByb3Zf
ZGJfbm9kZV9zZXRfdHRsKG5vZGUsIGRhdGFbMF0pOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAvKiBGYWxsIFRocm91Z2ggKi8NCj4gPiArDQo+ID4g
KyAgICAgICBjYXNlIE9QX0NPTkZJR19ERUZBVUxUX1RUTF9HRVQ6DQo+ID4gKyAgICAgICAgICAg
ICAgIG4gPSBtZXNoX29wY29kZV9zZXQoT1BfQ09ORklHX0RFRkFVTFRfVFRMX1NUQVRVUywgbXNn
KTsNCj4gPiArICAgICAgICAgICAgICAgbXNnW24rK10gPSBub2RlX2dldF9kZWZhdWx0X3R0bChu
b2RlKTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKw0KPiA+ICsgICAgICAgY2Fz
ZSBPUF9DT05GSUdfTU9ERUxfUFVCX1NFVDoNCj4gPiArICAgICAgICAgICAgICAgaWYgKGxlbiAh
PSAxMSAmJiBsZW4gIT0gMTMpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRy
dWU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlNldCBwdWJsaWNhdGlv
blxuIik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBlbGVfYWRkciA9IGdldF9sZTE2KGRh
dGEpOw0KPiA+ICsgICAgICAgICAgICAgICBtb2RfaWQgPSBnZXRfbGUxNihkYXRhICsgOSk7DQo+
ID4gKyAgICAgICAgICAgICAgIGlmIChsZW4gPT0gMTQpDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgbW9kX2lkID0gKG1vZF9pZCA8PCAxNikgIHwgZ2V0X2xlMTYoZGF0YSArIDExKTsNCj4g
PiArICAgICAgICAgICAgICAgZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1vZF9p
ZCB8PSAweGZmZmYwMDAwOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcHViLnUuYWRkcjE2
ID0gZ2V0X2xlMTYoZGF0YSArIDIpOw0KPiA+ICsgICAgICAgICAgICAgICBwdWIuYXBwX2lkeCA9
IGdldF9sZTE2KGRhdGEgKyA0KTsNCj4gPiArICAgICAgICAgICAgICAgcHViLnR0bCA9IGRhdGFb
Nl07DQo+ID4gKyAgICAgICAgICAgICAgIHB1Yi5wZXJpb2QgPSBkYXRhWzddOw0KPiA+ICsgICAg
ICAgICAgICAgICBuID0gKGRhdGFbN10gJiAweDNmKTsNCj4gPiArICAgICAgICAgICAgICAgc3dp
dGNoIChkYXRhWzddID4+IDYpIHsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSAwOg0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50ZigiUGVyaW9kOiAlZCBtc1xuIiwgbiAqIDEw
MCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICAgICAg
ICAgIGNhc2UgMjoNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBuICo9IDEwOw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIC8qIGZhbGwgdGhyb3VnaCAqLw0KPiA+ICsgICAgICAgICAg
ICAgICBjYXNlIDE6DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJQZXJp
b2Q6ICVkIHNlY1xuIiwgbik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+
ID4gKyAgICAgICAgICAgICAgIGNhc2UgMzoNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBy
bF9wcmludGYoIlBlcmlvZDogJWQgbWluXG4iLCBuICogMTApOw0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICBwdWIucmV0cmFuc21pdCA9IGRhdGFbOF07DQo+ID4gKyAgICAgICAgICAgICAg
IHJsX3ByaW50ZigiUmV0cmFuc21pdCBjb3VudDogJWRcbiIsIGRhdGFbOF0gPj4gNSk7DQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiUmV0cmFuc21pdCBJbnRlcnZhbCBTdGVwczogJWRc
biIsIGRhdGFbOF0gJiAweDFmKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGVsZV9pZHgg
PSBlbGVfYWRkciAtIG5vZGVfZ2V0X3ByaW1hcnkobm9kZSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBpZiAobm9kZV9tb2RlbF9wdWJfc2V0KG5vZGUsIGVsZV9pZHgsIG1vZF9pZCwgJnB1
YikpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcm92X2RiX25vZGVfc2V0X21vZGVs
X3B1Yihub2RlLCBlbGVfaWR4LCBtb2RfaWQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIG5vZGVfbW9kZWxfcHViX2dldChub2RlLCBlbGVfaWR4LCBtb2RfaWQpKTsN
Cj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiAr
ICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBwcmltYXJ5ID0gbm9kZV9nZXRfcHJpbWFyeShu
b2RlKTsNCj4gPiArICAgICAgIGlmIChzcmMgIT0gcHJpbWFyeSkNCj4gPiArICAgICAgICAgICAg
ICAgbmV0X2FjY2Vzc19sYXllcl9zZW5kKG5vZGVfZ2V0X2RlZmF1bHRfdHRsKG5vZGUpLCBwcmlt
YXJ5LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcmMsIEFQ
UF9JRFhfREVWLCBtc2csIGxlbik7DQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgbWVzaF9tb2RlbF9vcHMgc2VydmVyX2Ni
cyA9IHsNCj4gPiArICAgICAgIHNlcnZlcl9tc2dfcmVjdmQsDQo+ID4gKyAgICAgICAgICAgICAg
IE5VTEwsDQo+ID4gKyAgICAgICAgICAgICAgIE5VTEwsDQo+ID4gKyAgICAgICAgICAgICAgIE5V
TEwNCj4gPiArfTsNCj4gPiArDQo+ID4gK2Jvb2wgY29uZmlnX3NlcnZlcl9pbml0KHZvaWQpDQo+
ID4gK3sNCj4gPiArICAgICAgIGlmICghbm9kZV9sb2NhbF9tb2RlbF9yZWdpc3RlcihQUklNQVJZ
X0VMRU1FTlRfSURYLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIENPTkZJR19TRVJWRVJfTU9ERUxfSUQsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJnNlcnZlcl9jYnMsIE5VTEwpKQ0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRy
dWU7DQo+ID4gK30NCj4gPiBkaWZmIC0tZ2l0IGEvbWVzaC9jcnlwdG8uYyBiL21lc2gvY3J5cHRv
LmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGluZGV4IDAwMDAwMDAuLjE4OTYyNGUN
Cj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvbWVzaC9jcnlwdG8uYw0KPiA+IEBAIC0wLDAg
KzEsMTE2OCBAQA0KPiA+ICsvKg0KPiA+ICsgKg0KPiA+ICsgKiAgQmx1ZVogLSBCbHVldG9vdGgg
cHJvdG9jb2wgc3RhY2sgZm9yIExpbnV4DQo+ID4gKyAqDQo+ID4gKyAqICBDb3B5cmlnaHQgKEMp
IDIwMTcgIEludGVsIENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KPiA+ICsgKg0K
PiA+ICsgKg0KPiA+ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4g
cmVkaXN0cmlidXRlIGl0IGFuZC9vcg0KPiA+ICsgKiAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJt
cyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhcyBw
dWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyDQo+ID4gKyAq
ICB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0
ZXIgdmVyc2lvbi4NCj4gPiArICoNCj4gPiArICogIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRl
ZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLA0KPiA+ICsgKiAgYnV0IFdJVEhP
VVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YNCj4g
PiArICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
RS4gIFNlZSB0aGUNCj4gR05VDQo+ID4gKyAqICBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5z
ZSBmb3IgbW9yZSBkZXRhaWxzLg0KPiA+ICsgKg0KPiA+ICsgKiAgWW91IHNob3VsZCBoYXZlIHJl
Y2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsgKiAg
TGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJl
ZSBTb2Z0d2FyZQ0KPiA+ICsgKiAgRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3QsIEZp
ZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxDQo+IFVTQQ0KPiA+ICsgKg0KPiA+ICsg
Ki8NCj4gPiArDQo+ID4gKyNpZmRlZiBIQVZFX0NPTkZJR19IDQo+ID4gKyNpbmNsdWRlIDxjb25m
aWcuaD4NCj4gPiArI2VuZGlmDQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8ZmNudGwuaD4NCj4gPiAr
I2luY2x1ZGUgPHVuaXN0ZC5oPg0KPiA+ICsjaW5jbHVkZSA8c3RyaW5nLmg+DQo+ID4gKyNpbmNs
dWRlIDxzeXMvc29ja2V0Lmg+DQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8bGludXgvaWZfYWxnLmg+
DQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8Z2xpYi5oPg0KPiA+ICsNCj4gPiArI2lmbmRlZiBTT0xf
QUxHDQo+ID4gKyNkZWZpbmUgU09MX0FMRyAgICAgICAgICAgICAgICAyNzkNCj4gPiArI2VuZGlm
DQo+ID4gKw0KPiA+ICsjaWZuZGVmIEFMR19TRVRfQUVBRF9BVVRIU0laRQ0KPiA+ICsjZGVmaW5l
IEFMR19TRVRfQUVBRF9BVVRIU0laRSAgNQ0KPiA+ICsjZW5kaWYNCj4gPiArDQo+ID4gKyNpbmNs
dWRlICJzcmMvc2hhcmVkL3V0aWwuaCINCj4gPiArI2luY2x1ZGUgIm1lc2gtbmV0LmgiDQo+ID4g
KyNpbmNsdWRlICJjcnlwdG8uaCINCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgYWxnX25ldyhpbnQg
ZmQsIGNvbnN0IHZvaWQgKmtleXZhbCwgc29ja2xlbl90IGtleWxlbiwNCj4gPiArICAgICAgICAg
ICAgICAgc2l6ZV90IG1pY19zaXplKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoc2V0c29ja29w
dChmZCwgU09MX0FMRywgQUxHX1NFVF9LRVksIGtleXZhbCwga2V5bGVuKSA8IDApIHsNCj4gPiAr
ICAgICAgICAgICAgICAgZ19wcmludGVycigia2V5Iik7DQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiAtMTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAobWljX3NpemUg
JiYNCj4gPiArICAgICAgICAgICAgICAgc2V0c29ja29wdChmZCwgU09MX0FMRywNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBBTEdfU0VUX0FFQURfQVVUSFNJWkUsIE5VTEwsIG1pY19zaXpl
KSA8IDApIHsNCj4gPiArICAgICAgICAgICAgICAgZ19wcmludGVycigidGFnbGVuIik7DQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiAtMTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICAvKiBGSVhNRTogVGhpcyBzaG91bGQgdXNlIGFjY2VwdDQoKSB3aXRoIFNPQ0tfQ0xPRVhF
QyAqLw0KPiA+ICsgICAgICAgcmV0dXJuIGFjY2VwdChmZCwgTlVMTCwgMCk7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3N0YXRpYyBib29sIGFsZ19lbmNyeXB0KGludCBmZCwgY29uc3Qgdm9pZCAqaW5i
dWYsIHNpemVfdCBpbmxlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICB2b2lkICpvdXRidWYsIHNpemVfdCBvdXRsZW4pDQo+ID4gK3sNCj4gPiAr
ICAgICAgIF9fdTMyIGFsZ19vcCA9IEFMR19PUF9FTkNSWVBUOw0KPiA+ICsgICAgICAgY2hhciBj
YnVmW0NNU0dfU1BBQ0Uoc2l6ZW9mKGFsZ19vcCkpXTsNCj4gPiArICAgICAgIHN0cnVjdCBjbXNn
aGRyICpjbXNnOw0KPiA+ICsgICAgICAgc3RydWN0IG1zZ2hkciBtc2c7DQo+ID4gKyAgICAgICBz
dHJ1Y3QgaW92ZWMgaW92Ow0KPiA+ICsgICAgICAgc3NpemVfdCBsZW47DQo+ID4gKw0KPiA+ICsg
ICAgICAgbWVtc2V0KGNidWYsIDAsIHNpemVvZihjYnVmKSk7DQo+ID4gKyAgICAgICBtZW1zZXQo
Jm1zZywgMCwgc2l6ZW9mKG1zZykpOw0KPiA+ICsNCj4gPiArICAgICAgIG1zZy5tc2dfY29udHJv
bCA9IGNidWY7DQo+ID4gKyAgICAgICBtc2cubXNnX2NvbnRyb2xsZW4gPSBzaXplb2YoY2J1Zik7
DQo+ID4gKw0KPiA+ICsgICAgICAgY21zZyA9IENNU0dfRklSU1RIRFIoJm1zZyk7DQo+ID4gKyAg
ICAgICBjbXNnLT5jbXNnX2xldmVsID0gU09MX0FMRzsNCj4gPiArICAgICAgIGNtc2ctPmNtc2df
dHlwZSA9IEFMR19TRVRfT1A7DQo+ID4gKyAgICAgICBjbXNnLT5jbXNnX2xlbiA9IENNU0dfTEVO
KHNpemVvZihhbGdfb3ApKTsNCj4gPiArICAgICAgIG1lbWNweShDTVNHX0RBVEEoY21zZyksICZh
bGdfb3AsIHNpemVvZihhbGdfb3ApKTsNCj4gPiArDQo+ID4gKyAgICAgICBpb3YuaW92X2Jhc2Ug
PSAodm9pZCAqKSBpbmJ1ZjsNCj4gPiArICAgICAgIGlvdi5pb3ZfbGVuID0gaW5sZW47DQo+ID4g
Kw0KPiA+ICsgICAgICAgbXNnLm1zZ19pb3YgPSAmaW92Ow0KPiA+ICsgICAgICAgbXNnLm1zZ19p
b3ZsZW4gPSAxOw0KPiA+ICsNCj4gPiArICAgICAgIGxlbiA9IHNlbmRtc2coZmQsICZtc2csIDAp
Ow0KPiA+ICsgICAgICAgaWYgKGxlbiA8IDApDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBm
YWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBsZW4gPSByZWFkKGZkLCBvdXRidWYsIG91dGxlbik7
DQo+ID4gKyAgICAgICBpZiAobGVuIDwgMCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZh
bHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtzdGF0aWMgaW50IGFlc19lY2Jfc2V0dXAoY29uc3QgdWludDhfdCBrZXlbMTZdKQ0KPiA+ICt7
DQo+ID4gKyAgICAgICBzdHJ1Y3Qgc29ja2FkZHJfYWxnIHNhbGc7DQo+ID4gKyAgICAgICBpbnQg
ZmQsIG5mZDsNCj4gPiArDQo+ID4gKyAgICAgICBmZCA9IHNvY2tldChQRl9BTEcsIFNPQ0tfU0VR
UEFDS0VUIHwgU09DS19DTE9FWEVDLCAwKTsNCj4gPiArICAgICAgIGlmIChmZCA8IDApDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiAtMTsNCj4gPiArDQo+ID4gKyAgICAgICBtZW1zZXQoJnNh
bGcsIDAsIHNpemVvZihzYWxnKSk7DQo+ID4gKyAgICAgICBzYWxnLnNhbGdfZmFtaWx5ID0gQUZf
QUxHOw0KPiA+ICsgICAgICAgc3RyY3B5KChjaGFyICopIHNhbGcuc2FsZ190eXBlLCAic2tjaXBo
ZXIiKTsNCj4gPiArICAgICAgIHN0cmNweSgoY2hhciAqKSBzYWxnLnNhbGdfbmFtZSwgImVjYihh
ZXMpIik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGJpbmQoZmQsIChzdHJ1Y3Qgc29ja2FkZHIg
KikgJnNhbGcsIHNpemVvZihzYWxnKSkgPCAwKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGNsb3Nl
KGZkKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIC0xOw0KPiA+ICsgICAgICAgfQ0KPiA+
ICsNCj4gPiArICAgICAgIG5mZCA9IGFsZ19uZXcoZmQsIGtleSwgMTYsIDApOw0KPiA+ICsNCj4g
PiArICAgICAgIGNsb3NlKGZkKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbmZkOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBhZXNfZWNiKGludCBmZCwgY29uc3QgdWludDhf
dCBwbGFpbnRleHRbMTZdLCB1aW50OF90DQo+IGVuY3J5cHRlZFsxNl0pDQo+ID4gK3sNCj4gPiAr
ICAgICAgIHJldHVybiBhbGdfZW5jcnlwdChmZCwgcGxhaW50ZXh0LCAxNiwgZW5jcnlwdGVkLCAx
Nik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGFlc19lY2JfZGVzdHJveShpbnQg
ZmQpDQo+ID4gK3sNCj4gPiArICAgICAgIGNsb3NlKGZkKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
c3RhdGljIGJvb2wgYWVzX2VjYl9vbmUoY29uc3QgdWludDhfdCBrZXlbMTZdLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4X3QgcGxhaW50ZXh0WzE2XSwgdWludDhfdCBl
bmNyeXB0ZWRbMTZdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBib29sIHJlc3VsdDsNCj4gPiArICAg
ICAgIGludCBmZDsNCj4gPiArDQo+ID4gKyAgICAgICBmZCA9IGFlc19lY2Jfc2V0dXAoa2V5KTsN
Cj4gPiArICAgICAgIGlmIChmZCA8IDApDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxz
ZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXN1bHQgPSBhZXNfZWNiKGZkLCBwbGFpbnRleHQsIGVu
Y3J5cHRlZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgYWVzX2VjYl9kZXN0cm95KGZkKTsNCj4gPiAr
DQo+ID4gKyAgICAgICByZXR1cm4gcmVzdWx0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICsvKiBNYXhp
bXVtIG1lc3NhZ2UgbGVuZ3RoIHRoYXQgY2FuIGJlIHBhc3NlZCB0byBhZXNfY21hYyAqLw0KPiA+
ICsjZGVmaW5lIENNQUNfTVNHX01BWCAgICg2NCArIDY0ICsgMTcpDQo+ID4gKw0KPiA+ICtzdGF0
aWMgaW50IGFlc19jbWFjX3NldHVwKGNvbnN0IHVpbnQ4X3Qga2V5WzE2XSkNCj4gPiArew0KPiA+
ICsgICAgICAgc3RydWN0IHNvY2thZGRyX2FsZyBzYWxnOw0KPiA+ICsgICAgICAgaW50IGZkLCBu
ZmQ7DQo+ID4gKw0KPiA+ICsgICAgICAgZmQgPSBzb2NrZXQoUEZfQUxHLCBTT0NLX1NFUVBBQ0tF
VCB8IFNPQ0tfQ0xPRVhFQywgMCk7DQo+ID4gKyAgICAgICBpZiAoZmQgPCAwKQ0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm4gLTE7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtc2V0KCZzYWxnLCAw
LCBzaXplb2Yoc2FsZykpOw0KPiA+ICsgICAgICAgc2FsZy5zYWxnX2ZhbWlseSA9IEFGX0FMRzsN
Cj4gPiArICAgICAgIHN0cmNweSgoY2hhciAqKSBzYWxnLnNhbGdfdHlwZSwgImhhc2giKTsNCj4g
PiArICAgICAgIHN0cmNweSgoY2hhciAqKSBzYWxnLnNhbGdfbmFtZSwgImNtYWMoYWVzKSIpOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChiaW5kKGZkLCAoc3RydWN0IHNvY2thZGRyICopICZzYWxn
LCBzaXplb2Yoc2FsZykpIDwgMCkgew0KPiA+ICsgICAgICAgICAgICAgICBjbG9zZShmZCk7DQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiAtMTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4g
KyAgICAgICBuZmQgPSBhbGdfbmV3KGZkLCBrZXksIDE2LCAwKTsNCj4gPiArDQo+ID4gKyAgICAg
ICBjbG9zZShmZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIG5mZDsNCj4gPiArfQ0KPiA+
ICsNCj4gPiArc3RhdGljIGJvb2wgYWVzX2NtYWMoaW50IGZkLCBjb25zdCB1aW50OF90ICptc2cs
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVfdCBtc2df
bGVuLCB1aW50OF90IHJlc1sxNl0pDQo+ID4gK3sNCj4gPiArICAgICAgIHNzaXplX3QgbGVuOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChtc2dfbGVuID4gQ01BQ19NU0dfTUFYKQ0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbGVuID0gc2VuZChm
ZCwgbXNnLCBtc2dfbGVuLCAwKTsNCj4gPiArICAgICAgIGlmIChsZW4gPCAwKQ0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbGVuID0gcmVhZChm
ZCwgcmVzLCAxNik7DQo+ID4gKyAgICAgICBpZiAobGVuIDwgMCkNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBhZXNfY21hY19kZXN0cm95KGludCBmZCkNCj4gPiAr
ew0KPiA+ICsgICAgICAgY2xvc2UoZmQpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50
IGFlc19jbWFjX05fc3RhcnQoY29uc3QgdWludDhfdCBOWzE2XSkNCj4gPiArew0KPiA+ICsgICAg
ICAgaW50IGZkOw0KPiA+ICsNCj4gPiArICAgICAgIGZkID0gYWVzX2NtYWNfc2V0dXAoTik7DQo+
ID4gKyAgICAgICByZXR1cm4gZmQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIGFl
c19jbWFjX29uZShjb25zdCB1aW50OF90IGtleVsxNl0sIGNvbnN0IHZvaWQgKm1zZywNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZV90IG1zZ19sZW4sIHVp
bnQ4X3QgcmVzWzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAgYm9vbCByZXN1bHQ7DQo+ID4gKyAg
ICAgICBpbnQgZmQ7DQo+ID4gKw0KPiA+ICsgICAgICAgZmQgPSBhZXNfY21hY19zZXR1cChrZXkp
Ow0KPiA+ICsgICAgICAgaWYgKGZkIDwgMCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZh
bHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHJlc3VsdCA9IGFlc19jbWFjKGZkLCBtc2csIG1zZ19s
ZW4sIHJlcyk7DQo+ID4gKw0KPiA+ICsgICAgICAgYWVzX2NtYWNfZGVzdHJveShmZCk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgcmV0dXJuIHJlc3VsdDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBt
ZXNoX2NyeXB0b19hZXNfY21hYyhjb25zdCB1aW50OF90IGtleVsxNl0sIGNvbnN0IHVpbnQ4X3Qg
Km1zZywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZV90
IG1zZ19sZW4sIHVpbnQ4X3QgcmVzWzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAgcmV0dXJuIGFl
c19jbWFjX29uZShrZXksIG1zZywgbXNnX2xlbiwgcmVzKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
Ym9vbCBtZXNoX2NyeXB0b19hZXNfY2NtX2VuY3J5cHQoY29uc3QgdWludDhfdCBub25jZVsxM10s
IGNvbnN0DQo+IHVpbnQ4X3Qga2V5WzE2XSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgY29uc3QgdWludDhfdCAqYWFkLCB1aW50MTZfdCBhYWRfbGVuLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1aW50OF90ICpt
c2csIHVpbnQxNl90IG1zZ19sZW4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHVpbnQ4X3QgKm91dF9tc2csIHZvaWQgKm91dF9taWMsDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVfdCBtaWNfc2l6ZSkNCj4gPiArew0K
PiA+ICsgICAgICAgdWludDhfdCBwbXNnWzE2XSwgY21pY1sxNl0sIGNtc2dbMTZdOw0KPiA+ICsg
ICAgICAgdWludDhfdCBtaWNbMTZdLCBYblsxNl07DQo+ID4gKyAgICAgICB1aW50MTZfdCBibGtf
Y250LCBsYXN0X2JsazsNCj4gPiArICAgICAgIGJvb2wgcmVzdWx0Ow0KPiA+ICsgICAgICAgc2l6
ZV90IGksIGo7DQo+ID4gKyAgICAgICBpbnQgZmQ7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGFh
ZF9sZW4gPj0gMHhmZjAwKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGdfcHJpbnRlcnIoIlVuc3Vw
cG9ydGVkIEFBRCBzaXplIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4g
PiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBmZCA9IGFlc19lY2Jfc2V0dXAoa2V5KTsN
Cj4gPiArICAgICAgIGlmIChmZCA8IDApDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxz
ZTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBDX21pYyA9IGUoQXBwS2V5LCAweDAxIHx8IG5vbmNl
IHx8IDB4MDAwMCkgKi8NCj4gPiArICAgICAgIHBtc2dbMF0gPSAweDAxOw0KPiA+ICsgICAgICAg
bWVtY3B5KHBtc2cgKyAxLCBub25jZSwgMTMpOw0KPiA+ICsgICAgICAgcHV0X2JlMTYoMHgwMDAw
LCBwbXNnICsgMTQpOw0KPiA+ICsNCj4gPiArICAgICAgIHJlc3VsdCA9IGFlc19lY2IoZmQsIHBt
c2csIGNtaWMpOw0KPiA+ICsgICAgICAgaWYgKCFyZXN1bHQpDQo+ID4gKyAgICAgICAgICAgICAg
IGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBYXzAgPSBlKEFwcEtleSwgMHgwOSB8
fCBub25jZSB8fCBsZW5ndGgpICovDQo+ID4gKyAgICAgICBpZiAobWljX3NpemUgPT0gc2l6ZW9m
KHVpbnQ2NF90KSkNCj4gPiArICAgICAgICAgICAgICAgcG1zZ1swXSA9IDB4MTkgfCAoYWFkX2xl
biA/IDB4NDAgOiAweDAwKTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAg
cG1zZ1swXSA9IDB4MDkgfCAoYWFkX2xlbiA/IDB4NDAgOiAweDAwKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBtZW1jcHkocG1zZyArIDEsIG5vbmNlLCAxMyk7DQo+ID4gKyAgICAgICBwdXRfYmUxNiht
c2dfbGVuLCBwbXNnICsgMTQpOw0KPiA+ICsNCj4gPiArICAgICAgIHJlc3VsdCA9IGFlc19lY2Io
ZmQsIHBtc2csIFhuKTsNCj4gPiArICAgICAgIGlmICghcmVzdWx0KQ0KPiA+ICsgICAgICAgICAg
ICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogSWYgQUFEIGlzIGJlaW5nIHVz
ZWQgdG8gYXV0aGVudGljYXRlLCBpbmNsdWRlIGl0IGhlcmUgKi8NCj4gPiArICAgICAgIGlmIChh
YWRfbGVuKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHB1dF9iZTE2KGFhZF9sZW4sIHBtc2cpOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IHNpemVvZih1aW50MTZf
dCk7IGkrKykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwbXNnW2ldID0gWG5baV0gXiBw
bXNnW2ldOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaiA9IDA7DQo+ID4gKyAgICAgICAg
ICAgICAgIGFhZF9sZW4gKz0gc2l6ZW9mKHVpbnQxNl90KTsNCj4gPiArICAgICAgICAgICAgICAg
d2hpbGUgKGFhZF9sZW4gPiAxNikgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGRvIHsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtc2dbaV0gPSBYbltpXSBeIGFh
ZFtqXTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkrKywgaisrOw0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKGkgPCAxNik7DQo+ID4gKw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIGFhZF9sZW4gLT0gMTY7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgaSA9IDA7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJlc3Vs
dCA9IGFlc19lY2IoZmQsIHBtc2csIFhuKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBp
ZiAoIXJlc3VsdCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9u
ZTsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgZm9y
IChpID0gMDsgaSA8IGFhZF9sZW47IGkrKywgaisrKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIHBtc2dbaV0gPSBYbltpXSBeIGFhZFtqXTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IGZvciAoaSA9IGFhZF9sZW47IGkgPCAxNjsgaSsrKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIHBtc2dbaV0gPSBYbltpXTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHJlc3VsdCA9
IGFlc19lY2IoZmQsIHBtc2csIFhuKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQp
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgfQ0K
PiA+ICsNCj4gPiArICAgICAgIGxhc3RfYmxrID0gbXNnX2xlbiAlIDE2Ow0KPiA+ICsgICAgICAg
YmxrX2NudCA9IChtc2dfbGVuICsgMTUpIC8gMTY7DQo+ID4gKyAgICAgICBpZiAoIWxhc3RfYmxr
KQ0KPiA+ICsgICAgICAgICAgICAgICBsYXN0X2JsayA9IDE2Ow0KPiA+ICsNCj4gPiArICAgICAg
IGZvciAoaiA9IDA7IGogPCBibGtfY250OyBqKyspIHsNCj4gPiArICAgICAgICAgICAgICAgaWYg
KGogKyAxID09IGJsa19jbnQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAvKiBYXzEg
PSBlKEFwcEtleSwgWF8wIF4gUGF5bG9hZFswLTE1XSkgKi8NCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGFzdF9ibGs7IGkrKykNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHBtc2dbaV0gPSBYbltpXSBeIG1zZ1soaiAqIDE2KSArIGldOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaSA9IGxhc3RfYmxrOyBpIDwgMTY7IGkr
KykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtc2dbaV0gPSBYbltpXSBe
IDB4MDA7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGFlc19l
Y2IoZmQsIHBtc2csIFhuKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3Vs
dCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiAr
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLyogTUlDID0gQ19taWMgXiBYXzEgKi8NCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2l6ZW9mKG1pYyk7IGkr
KykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pY1tpXSA9IGNtaWNbaV0g
XiBYbltpXTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLyogQ18xID0gZShB
cHBLZXksIDB4MDEgfHwgbm9uY2UgfHwgMHgwMDAxKSAqLw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHBtc2dbMF0gPSAweDAxOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1lbWNw
eShwbXNnICsgMSwgbm9uY2UsIDEzKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwdXRf
YmUxNihqICsgMSwgcG1zZyArIDE0KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgcmVzdWx0ID0gYWVzX2VjYihmZCwgcG1zZywgY21zZyk7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgaWYgKCFyZXN1bHQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChvdXRf
bXNnKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBFbmNyeXB0ZWQg
PSBQYXlsb2FkWzAtMTVdIF4gQ18xICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBmb3IgKGkgPSAwOyBpIDwgbGFzdF9ibGs7IGkrKykNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgb3V0X21zZ1soaiAqIDE2KSArIGldID0NCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2dbKGogKiAxNikg
KyBpXSBeIGNtc2dbaV07DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIH0NCj4g
PiArICAgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAv
KiBYXzEgPSBlKEFwcEtleSwgWF8wIF4gUGF5bG9hZFswLTE1XSkgKi8NCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgMTY7IGkrKykNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHBtc2dbaV0gPSBYbltpXSBeIG1zZ1soaiAqIDE2KSArIGldOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBhZXNfZWNiKGZkLCBw
bXNnLCBYbik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQpDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIC8qIENfMSA9IGUoQXBwS2V5LCAweDAxIHx8IG5vbmNlIHx8
IDB4MDAwMSkgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwbXNnWzBdID0gMHgwMTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtZW1jcHkocG1zZyArIDEsIG5vbmNlLCAxMyk7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHV0X2JlMTYoaiArIDEsIHBtc2cgKyAxNCk7
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGFlc19lY2IoZmQs
IHBtc2csIGNtc2cpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmICghcmVzdWx0KQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBpZiAob3V0X21zZykgew0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgLyogRW5jcnlwdGVkID0gUGF5bG9hZFswLTE1XSBeIENfTiAq
Lw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IDE2
OyBpKyspDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dF9t
c2dbKGogKiAxNikgKyBpXSA9DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgbXNnWyhqICogMTYpICsgaV0gXiBjbXNnW2ldOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAob3V0X21zZykNCj4gPiArICAgICAgICAgICAg
ICAgbWVtY3B5KG91dF9tc2cgKyBtc2dfbGVuLCBtaWMsIG1pY19zaXplKTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAob3V0X21pYykgew0KPiA+ICsgICAgICAgICAgICAgICBzd2l0Y2ggKG1pY19z
aXplKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGNhc2Ugc2l6ZW9mKHVpbnQzMl90KToNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAqKHVpbnQzMl90ICopb3V0X21pYyA9IGdldF9iZTMyKG1p
Yyk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICAgICAg
ICAgIGNhc2Ugc2l6ZW9mKHVpbnQ2NF90KToNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAq
KHVpbnQ2NF90ICopb3V0X21pYyA9IGdldF9iZTY0KG1pYyk7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICAgICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgZ19wcmludGVycigiVW5zdXBwb3J0ZWQgTUlDIHNpemUiKTsNCj4g
PiArICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArZG9uZToNCj4g
PiArICAgICAgIGFlc19lY2JfZGVzdHJveShmZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJu
IHJlc3VsdDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBtZXNoX2NyeXB0b19hZXNfY2NtX2Rl
Y3J5cHQoY29uc3QgdWludDhfdCBub25jZVsxM10sIGNvbnN0DQo+IHVpbnQ4X3Qga2V5WzE2XSwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4X3QgKmFhZCwg
dWludDE2X3QgYWFkX2xlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNv
bnN0IHVpbnQ4X3QgKmVuY19tc2csIHVpbnQxNl90IGVuY19tc2dfbGVuLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgdWludDhfdCAqb3V0X21zZywgdm9pZCAqb3V0X21pYywN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemVfdCBtaWNfc2l6ZSkNCj4g
PiArew0KPiA+ICsgICAgICAgdWludDhfdCBtc2dbMTZdLCBwbXNnWzE2XSwgY21pY1sxNl0sIGNt
c2dbMTZdLCBYblsxNl07DQo+ID4gKyAgICAgICB1aW50OF90IG1pY1sxNl07DQo+ID4gKyAgICAg
ICB1aW50MTZfdCBtc2dfbGVuID0gZW5jX21zZ19sZW4gLSBtaWNfc2l6ZTsNCj4gPiArICAgICAg
IHVpbnQxNl90IGxhc3RfYmxrLCBibGtfY250Ow0KPiA+ICsgICAgICAgYm9vbCByZXN1bHQ7DQo+
ID4gKyAgICAgICBzaXplX3QgaSwgajsNCj4gPiArICAgICAgIGludCBmZDsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoZW5jX21zZ19sZW4gPCA1IHx8IGFhZF9sZW4gPj0gMHhmZjAwKQ0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgZmQgPSBhZXNf
ZWNiX3NldHVwKGtleSk7DQo+ID4gKyAgICAgICBpZiAoZmQgPCAwKQ0KPiA+ICsgICAgICAgICAg
ICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogQ19taWMgPSBlKEFwcEtl
eSwgMHgwMSB8fCBub25jZSB8fCAweDAwMDApICovDQo+ID4gKyAgICAgICBwbXNnWzBdID0gMHgw
MTsNCj4gPiArICAgICAgIG1lbWNweShwbXNnICsgMSwgbm9uY2UsIDEzKTsNCj4gPiArICAgICAg
IHB1dF9iZTE2KDB4MDAwMCwgcG1zZyArIDE0KTsNCj4gPiArDQo+ID4gKyAgICAgICByZXN1bHQg
PSBhZXNfZWNiKGZkLCBwbXNnLCBjbWljKTsNCj4gPiArICAgICAgIGlmICghcmVzdWx0KQ0KPiA+
ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogWF8wID0g
ZShBcHBLZXksIDB4MDkgfHwgbm9uY2UgfHwgbGVuZ3RoKSAqLw0KPiA+ICsgICAgICAgaWYgKG1p
Y19zaXplID09IHNpemVvZih1aW50NjRfdCkpDQo+ID4gKyAgICAgICAgICAgICAgIHBtc2dbMF0g
PSAweDE5IHwgKGFhZF9sZW4gPyAweDQwIDogMHgwMCk7DQo+ID4gKyAgICAgICBlbHNlDQo+ID4g
KyAgICAgICAgICAgICAgIHBtc2dbMF0gPSAweDA5IHwgKGFhZF9sZW4gPyAweDQwIDogMHgwMCk7
DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KHBtc2cgKyAxLCBub25jZSwgMTMpOw0KPiA+ICsg
ICAgICAgcHV0X2JlMTYobXNnX2xlbiwgcG1zZyArIDE0KTsNCj4gPiArDQo+ID4gKyAgICAgICBy
ZXN1bHQgPSBhZXNfZWNiKGZkLCBwbXNnLCBYbik7DQo+ID4gKyAgICAgICBpZiAoIXJlc3VsdCkN
Cj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIElm
IEFBRCBpcyBiZWluZyB1c2VkIHRvIGF1dGhlbnRpY2F0ZSwgaW5jbHVkZSBpdCBoZXJlICovDQo+
ID4gKyAgICAgICBpZiAoYWFkX2xlbikgew0KPiA+ICsgICAgICAgICAgICAgICBwdXRfYmUxNihh
YWRfbGVuLCBwbXNnKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkg
PCBzaXplb2YodWludDE2X3QpOyBpKyspDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcG1z
Z1tpXSA9IFhuW2ldIF4gcG1zZ1tpXTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGogPSAw
Ow0KPiA+ICsgICAgICAgICAgICAgICBhYWRfbGVuICs9IHNpemVvZih1aW50MTZfdCk7DQo+ID4g
KyAgICAgICAgICAgICAgIHdoaWxlIChhYWRfbGVuID4gMTYpIHsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBkbyB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbXNn
W2ldID0gWG5baV0gXiBhYWRbal07DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBpKyssIGorKzsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9IHdoaWxlIChpIDwgMTYp
Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBhYWRfbGVuIC09IDE2Ow0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIGkgPSAwOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICByZXN1bHQgPSBhZXNfZWNiKGZkLCBwbXNnLCBYbik7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhYWRfbGVuOyBpKyssIGorKykNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBwbXNnW2ldID0gWG5baV0gXiBhYWRbal07DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICBmb3IgKGkgPSBhYWRfbGVuOyBpIDwgMTY7IGkrKykNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBwbXNnW2ldID0gWG5baV07DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICByZXN1bHQgPSBhZXNfZWNiKGZkLCBwbXNnLCBYbik7DQo+ID4gKyAgICAgICAgICAg
ICAgIGlmICghcmVzdWx0KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBsYXN0X2JsayA9IG1zZ19sZW4gJSAx
NjsNCj4gPiArICAgICAgIGJsa19jbnQgPSAobXNnX2xlbiArIDE1KSAvIDE2Ow0KPiA+ICsgICAg
ICAgaWYgKCFsYXN0X2JsaykNCj4gPiArICAgICAgICAgICAgICAgbGFzdF9ibGsgPSAxNjsNCj4g
PiArDQo+ID4gKyAgICAgICBmb3IgKGogPSAwOyBqIDwgYmxrX2NudDsgaisrKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIGlmIChqICsgMSA9PSBibGtfY250KSB7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgLyogQ18xID0gZShBcHBLZXksIDB4MDEgfHwgbm9uY2UgfHwgMHgwMDAxKSAqLw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHBtc2dbMF0gPSAweDAxOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIG1lbWNweShwbXNnICsgMSwgbm9uY2UsIDEzKTsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBwdXRfYmUxNihqICsgMSwgcG1zZyArIDE0KTsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gYWVzX2VjYihmZCwgcG1zZywgY21zZyk7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQpDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIC8qIEVuY3J5cHRlZCA9IFBheWxvYWRbMC0xNV0gXiBDXzEgKi8NCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGFzdF9ibGs7IGkrKykNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZ1tpXSA9IGVuY19tc2dbKGogKiAx
NikgKyBpXSBeIGNtc2dbaV07DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlm
IChvdXRfbXNnKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVtY3B5KG91
dF9tc2cgKyAoaiAqIDE2KSwgbXNnLCBsYXN0X2Jsayk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIC8qIFhfMSA9IGUoQXBwS2V5LCBYXzAgXiBQYXlsb2FkWzAtMTVdKSAqLw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBsYXN0X2JsazsgaSsr
KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG1zZ1tpXSA9IFhuW2ldIF4g
bXNnW2ldOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaSA9IGxhc3RfYmxrOyBp
IDwgMTY7IGkrKykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtc2dbaV0g
PSBYbltpXSBeIDB4MDA7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJlc3Vs
dCA9IGFlc19lY2IoZmQsIHBtc2csIFhuKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBp
ZiAoIXJlc3VsdCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9u
ZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLyogTUlDID0gQ19taWMgXiBY
XzEgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc2l6ZW9m
KG1pYyk7IGkrKykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pY1tpXSA9
IGNtaWNbaV0gXiBYbltpXTsNCj4gPiArICAgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAvKiBDXzEgPSBlKEFwcEtleSwgMHgwMSB8fCBub25jZSB8fCAw
eDAwMDEpICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcG1zZ1swXSA9IDB4MDE7DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbWVtY3B5KHBtc2cgKyAxLCBub25jZSwgMTMpOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHB1dF9iZTE2KGogKyAxLCBwbXNnICsgMTQpOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBhZXNfZWNiKGZkLCBw
bXNnLCBjbXNnKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgLyogRW5jcnlwdGVkID0gUGF5bG9hZFswLTE1XSBeIENf
MSAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCAxNjsgaSsr
KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNnW2ldID0gZW5jX21zZ1so
aiAqIDE2KSArIGldIF4gY21zZ1tpXTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgaWYgKG91dF9tc2cpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZW1j
cHkob3V0X21zZyArIChqICogMTYpLCBtc2csIDE2KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgLyogWF8xID0gZShBcHBLZXksIFhfMCBeIFBheWxvYWRbMC0xNV0pICovDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IDE2OyBpKyspDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbXNnW2ldID0gWG5baV0gXiBtc2dbaV07
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IGFlc19lY2IoZmQs
IHBtc2csIFhuKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArICAgICAg
ICAgICAgICAgfQ0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHN3aXRjaCAobWlj
X3NpemUpIHsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSBzaXplb2YodWludDMyX3QpOg0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChvdXRfbWljKQ0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgKih1aW50MzJfdCAqKW91dF9taWMgPSBnZXRfYmUzMihtaWMpOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKGdldF9iZTMyKGVuY19tc2cgKyBl
bmNfbXNnX2xlbiAtIG1pY19zaXplKSAhPQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBnZXRfYmUzMihtaWMpKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgcmVzdWx0ID0gZmFsc2U7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJl
YWs7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIHNpemVvZih1aW50NjRfdCk6DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKG91dF9taWMpDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAqKHVpbnQ2NF90ICopb3V0X21pYyA9IGdldF9iZTY0KG1pYyk7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoZ2V0X2JlNjQoZW5jX21zZyAr
IGVuY19tc2dfbGVuIC0gbWljX3NpemUpICE9DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIGdldF9iZTY0KG1pYykpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICByZXN1bHQgPSBmYWxzZTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBi
cmVhazsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgZ19wcmludGVycigiVW5zdXBwb3J0ZWQgTUlDIHNpemUiKTsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBmYWxzZTsNCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gK2RvbmU6DQo+ID4gKyAgICAgICBhZXNfZWNiX2Rlc3Ryb3koZmQpOw0KPiA+ICsN
Cj4gPiArICAgICAgIHJldHVybiByZXN1bHQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgbWVz
aF9jcnlwdG9fazEoY29uc3QgdWludDhfdCBpa21bMTZdLCBjb25zdCB1aW50OF90IHNhbHRbMTZd
LA0KPiA+ICsgICAgICAgICAgICAgICBjb25zdCB2b2lkICppbmZvLCBzaXplX3QgaW5mb19sZW4s
IHVpbnQ4X3Qgb2ttWzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCByZXNbMTZdOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmICghYWVzX2NtYWNfb25lKHNhbHQsIGlrbSwgMTYsIHJlcykp
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBy
ZXR1cm4gYWVzX2NtYWNfb25lKHJlcywgaW5mbywgaW5mb19sZW4sIG9rbSk7DQo+ID4gK30NCj4g
PiArDQo+ID4gK2Jvb2wgbWVzaF9jcnlwdG9fazIoY29uc3QgdWludDhfdCBuWzE2XSwgY29uc3Qg
dWludDhfdCAqcCwgc2l6ZV90IHBfbGVuLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDhfdCBuZXRfaWRbMV0sDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50
OF90IGVuY19rZXlbMTZdLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgdWludDhfdCBwcml2X2tleVsxNl0pDQo+ID4gK3sNCj4gPiAr
ICAgICAgIGludCBmZDsNCj4gPiArICAgICAgIHVpbnQ4X3Qgb3V0cHV0WzE2XTsNCj4gPiArICAg
ICAgIHVpbnQ4X3QgdFsxNl07DQo+ID4gKyAgICAgICB1aW50OF90ICpzdGFnZTsNCj4gPiArICAg
ICAgIGJvb2wgc3VjY2VzcyA9IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHN0YWdlID0gZ19t
YWxsb2Moc2l6ZW9mKG91dHB1dCkgKyBwX2xlbiArIDEpOw0KPiA+ICsgICAgICAgaWYgKHN0YWdl
ID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoIW1lc2hfY3J5cHRvX3MxKCJzbWsyIiwgNCwgc3RhZ2UpKQ0KPiA+ICsgICAg
ICAgICAgICAgICBnb3RvIGZhaWw7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFhZXNfY21hY19v
bmUoc3RhZ2UsIG4sIDE2LCB0KSkNCj4gPiArICAgICAgICAgICAgICAgZ290byBmYWlsOw0KPiA+
ICsNCj4gPiArICAgICAgIGZkID0gYWVzX2NtYWNfTl9zdGFydCh0KTsNCj4gPiArICAgICAgIGlm
IChmZCA8IDApDQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZmFpbDsNCj4gPiArDQo+ID4gKyAg
ICAgICBtZW1jcHkoc3RhZ2UsIHAsIHBfbGVuKTsNCj4gPiArICAgICAgIHN0YWdlW3BfbGVuXSA9
IDE7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYoIWFlc19jbWFjKGZkLCBzdGFnZSwgcF9sZW4gKyAx
LCBvdXRwdXQpKQ0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsg
ICAgICAgbmV0X2lkWzBdID0gb3V0cHV0WzE1XSAmIDB4N2Y7DQo+ID4gKw0KPiA+ICsgICAgICAg
bWVtY3B5KHN0YWdlLCBvdXRwdXQsIDE2KTsNCj4gPiArICAgICAgIG1lbWNweShzdGFnZSArIDE2
LCBwLCBwX2xlbik7DQo+ID4gKyAgICAgICBzdGFnZVtwX2xlbiArIDE2XSA9IDI7DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYoIWFlc19jbWFjKGZkLCBzdGFnZSwgcF9sZW4gKyAxNiArIDEsIG91dHB1
dCkpDQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBt
ZW1jcHkoZW5jX2tleSwgb3V0cHV0LCAxNik7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KHN0
YWdlLCBvdXRwdXQsIDE2KTsNCj4gPiArICAgICAgIG1lbWNweShzdGFnZSArIDE2LCBwLCBwX2xl
bik7DQo+ID4gKyAgICAgICBzdGFnZVtwX2xlbiArIDE2XSA9IDM7DQo+ID4gKw0KPiA+ICsgICAg
ICAgaWYoIWFlc19jbWFjKGZkLCBzdGFnZSwgcF9sZW4gKyAxNiArIDEsIG91dHB1dCkpDQo+ID4g
KyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBtZW1jcHkocHJp
dl9rZXksIG91dHB1dCwgMTYpOw0KPiA+ICsgICAgICAgc3VjY2VzcyA9IHRydWU7DQo+ID4gKw0K
PiA+ICtkb25lOg0KPiA+ICsgICAgICAgYWVzX2NtYWNfZGVzdHJveShmZCk7DQo+ID4gK2ZhaWw6
DQo+ID4gKyAgICAgICBnX2ZyZWUoc3RhZ2UpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBz
dWNjZXNzOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBjcnlwdG9fMTI4KGNvbnN0
IHVpbnQ4X3QgblsxNl0sIGNvbnN0IGNoYXIgKnMsIHVpbnQ4X3QNCj4gb3V0MTI4WzE2XSkNCj4g
PiArew0KPiA+ICsgICAgICAgdWludDhfdCBpZDEyOFtdID0geyAnaScsICdkJywgJzEnLCAnMics
ICc4JywgMHgwMSB9Ow0KPiA+ICsgICAgICAgdWludDhfdCBzYWx0WzE2XTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoIW1lc2hfY3J5cHRvX3MxKHMsIDQsIHNhbHQpKQ0KPiA+ICsgICAgICAgICAg
ICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIG1lc2hfY3J5cHRv
X2sxKG4sIHNhbHQsIGlkMTI4LCBzaXplb2YoaWQxMjgpLCBvdXQxMjgpOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtib29sIG1lc2hfY3J5cHRvX25raWsoY29uc3QgdWludDhfdCBuWzE2XSwgdWludDhf
dCBpZGVudGl0eV9rZXlbMTZdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICByZXR1cm4gY3J5cHRvXzEy
OChuLCAibmtpayIsIGlkZW50aXR5X2tleSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBi
b29sIGlkZW50aXR5X2NhbGMoY29uc3QgdWludDhfdCBuZXRfa2V5WzE2XSwgdWludDE2X3QgYWRk
ciwNCj4gPiArICAgICAgICAgICAgICAgYm9vbCBjaGVjaywgdWludDhfdCBpZFsxNl0pDQo+ID4g
K3sNCj4gPiArICAgICAgIHVpbnQ4X3QgaWRfa2V5WzE2XTsNCj4gPiArICAgICAgIHVpbnQ4X3Qg
dG1wWzE2XTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW1lc2hfY3J5cHRvX25raWsobmV0X2tl
eSwgaWRfa2V5KSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4g
PiArICAgICAgIG1lbXNldCh0bXAsIDAsIHNpemVvZih0bXApKTsNCj4gPiArICAgICAgIHB1dF9i
ZTE2KGFkZHIsIHRtcCArIDE0KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoY2hlY2spIHsNCj4g
PiArICAgICAgICAgICAgICAgbWVtY3B5KHRtcCArIDYsIGlkICsgOCwgOCk7DQo+ID4gKyAgICAg
ICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBtZXNoX2dldF9yYW5kb21fYnl0ZXModG1w
ICsgNiwgOCk7DQo+ID4gKyAgICAgICAgICAgICAgIG1lbWNweShpZCArIDgsIHRtcCArIDYsIDgp
Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmICghYWVzX2VjYl9vbmUoaWRf
a2V5LCB0bXAsIHRtcCkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZiAoY2hlY2spDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAobWVt
Y21wKGlkLCB0bXAgKyA4LCA4KSA9PSAwKTsNCj4gPiArDQo+ID4gKyAgICAgICBtZW1jcHkoaWQs
IHRtcCArIDgsIDgpOw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+
ID4gK2Jvb2wgbWVzaF9jcnlwdG9faWRlbnRpdHkoY29uc3QgdWludDhfdCBuZXRfa2V5WzE2XSwg
dWludDE2X3QgYWRkciwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHVpbnQ4X3QgaWRbMTZdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBy
ZXR1cm4gaWRlbnRpdHlfY2FsYyhuZXRfa2V5LCBhZGRyLCBmYWxzZSwgaWQpOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtib29sIG1lc2hfY3J5cHRvX2lkZW50aXR5X2NoZWNrKGNvbnN0IHVpbnQ4X3Qg
bmV0X2tleVsxNl0sIHVpbnQxNl90DQo+IGFkZHIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50OF90IGlkWzE2XSkNCj4gPiAr
ew0KPiA+ICsgICAgICAgcmV0dXJuIGlkZW50aXR5X2NhbGMobmV0X2tleSwgYWRkciwgdHJ1ZSwg
aWQpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG1lc2hfY3J5cHRvX25rYmsoY29uc3QgdWlu
dDhfdCBuWzE2XSwgdWludDhfdCBiZWFjb25fa2V5WzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAg
cmV0dXJuIGNyeXB0b18xMjgobiwgIm5rYmsiLCBiZWFjb25fa2V5KTsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiArYm9vbCBtZXNoX2NyeXB0b19rMyhjb25zdCB1aW50OF90IG5bMTZdLCB1aW50OF90IG91
dDY0WzhdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50OF90IHRtcFsxNl07DQo+ID4gKyAgICAg
ICB1aW50OF90IHRbMTZdOw0KPiA+ICsgICAgICAgdWludDhfdCBpZDY0W10gPSB7ICdpJywgJ2Qn
LCAnNicsICc0JywgMHgwMSB9Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbWVzaF9jcnlwdG9f
czEoInNtazMiLCA0LCB0bXApKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKCFhZXNfY21hY19vbmUodG1wLCBuLCAxNiwgdCkpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWFl
c19jbWFjX29uZSh0LCBpZDY0LCBzaXplb2YoaWQ2NCksIHRtcCkpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBtZW1jcHkob3V0NjQsIHRtcCAr
IDgsIDgpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0K
PiA+ICtib29sIG1lc2hfY3J5cHRvX2s0KGNvbnN0IHVpbnQ4X3QgYVsxNl0sIHVpbnQ4X3Qgb3V0
NlsxXSkNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCB0bXBbMTZdOw0KPiA+ICsgICAgICAg
dWludDhfdCB0WzE2XTsNCj4gPiArICAgICAgIHVpbnQ4X3QgaWQ2W10gPSB7ICdpJywgJ2QnLCAn
NicsIDB4MDEgfTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW1lc2hfY3J5cHRvX3MxKCJzbWs0
IiwgNCwgdG1wKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4g
PiArICAgICAgIGlmICghYWVzX2NtYWNfb25lKHRtcCwgYSwgMTYsIHQpKQ0KPiA+ICsgICAgICAg
ICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFhZXNfY21hY19v
bmUodCwgaWQ2LCBzaXplb2YoaWQ2KSwgdG1wKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIG91dDZbMF0gPSB0bXBbMTVdICYgMHgzZjsNCj4g
PiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG1lc2hfY3J5
cHRvX2JlYWNvbl9jbWFjKGNvbnN0IHVpbnQ4X3QgZW5jcnlwdGlvbl9rZXlbMTZdLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdWludDhfdCBuZXR3b3JrX2lkWzhd
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDMyX3QgaXZfaW5kZXgs
IGJvb2wga3IsIGJvb2wgaXUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1
aW50NjRfdCAqY21hYykNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCBtc2dbMTNdLCB0bXBb
MTZdOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghY21hYykNCj4gPiArICAgICAgICAgICAgICAg
cmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIG1zZ1swXSA9IGtyID8gMHgwMSA6IDB4
MDA7DQo+ID4gKyAgICAgICBtc2dbMF0gfD0gaXUgPyAweDAyIDogMHgwMDsNCj4gPiArICAgICAg
IG1lbWNweShtc2cgKyAxLCBuZXR3b3JrX2lkLCA4KTsNCj4gPiArICAgICAgIHB1dF9iZTMyKGl2
X2luZGV4LCBtc2cgKyA5KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWFlc19jbWFjX29uZShl
bmNyeXB0aW9uX2tleSwgbXNnLCAxMywgdG1wKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICpjbWFjID0gZ2V0X2JlNjQodG1wKTsNCj4gPiAr
DQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBtZXNo
X2NyeXB0b19uZXR3b3JrX25vbmNlKGJvb2wgY3RsLCB1aW50OF90IHR0bCwgdWludDMyX3Qgc2Vx
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDE2X3Qgc3JjLCB1aW50
MzJfdCBpdl9pbmRleCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQ4
X3Qgbm9uY2VbMTNdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBub25jZVswXSA9IDA7DQo+ID4gKyAg
ICAgICBub25jZVsxXSA9ICh0dGwgJiBUVExfTUFTSykgfCAoY3RsID8gQ1RMIDogMHgwMCk7DQo+
ID4gKyAgICAgICBub25jZVsyXSA9IChzZXEgPj4gMTYpICYgMHhmZjsNCj4gPiArICAgICAgIG5v
bmNlWzNdID0gKHNlcSA+PiA4KSAmIDB4ZmY7DQo+ID4gKyAgICAgICBub25jZVs0XSA9IHNlcSAm
IDB4ZmY7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogU1JDICovDQo+ID4gKyAgICAgICBwdXRfYmUx
NihzcmMsIG5vbmNlICsgNSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcHV0X2JlMTYoMCwgbm9uY2Ug
KyA3KTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBJViBJbmRleCAqLw0KPiA+ICsgICAgICAgcHV0
X2JlMzIoaXZfaW5kZXgsIG5vbmNlICsgOSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRy
dWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgbWVzaF9jcnlwdG9fbmV0d29ya19lbmNyeXB0
KGJvb2wgY3RsLCB1aW50OF90IHR0bCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHVpbnQzMl90IHNlcSwgdWludDE2X3Qgc3JjLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgdWludDMyX3QgaXZfaW5kZXgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBjb25zdCB1aW50OF90IG5ldF9rZXlbMTZdLA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgY29uc3QgdWludDhfdCAqZW5jX21zZywgdWludDhfdCBlbmNfbXNn
X2xlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQ4X3QgKm91dCwg
dm9pZCAqbmV0X21pYykNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCBub25jZVsxM107DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKCFtZXNoX2NyeXB0b19uZXR3b3JrX25vbmNlKGN0bCwgdHRs
LCBzZXEsIHNyYywgaXZfaW5kZXgsIG5vbmNlKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBtZXNoX2NyeXB0b19hZXNfY2NtX2Vu
Y3J5cHQobm9uY2UsIG5ldF9rZXksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBOVUxMLCAwLCBlbmNfbXNnLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ZW5jX21zZ19sZW4sIG91dCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5l
dF9taWMsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdGwgPyBzaXplb2Yo
dWludDY0X3QpIDogc2l6ZW9mKHVpbnQzMl90KSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wg
bWVzaF9jcnlwdG9fbmV0d29ya19kZWNyeXB0KGJvb2wgY3RsLCB1aW50OF90IHR0bCwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQzMl90IHNlcSwgdWludDE2X3Qgc3Jj
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDMyX3QgaXZfaW5kZXgs
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1aW50OF90IG5ldF9r
ZXlbMTZdLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdWludDhf
dCAqZW5jX21zZywgdWludDhfdCBlbmNfbXNnX2xlbiwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIHVpbnQ4X3QgKm91dCwgdm9pZCAqbmV0X21pYywgc2l6ZV90IG1pY19zaXpl
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50OF90IG5vbmNlWzEzXTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAoIW1lc2hfY3J5cHRvX25ldHdvcmtfbm9uY2UoY3RsLCB0dGwsIHNlcSwgc3JjLCBp
dl9pbmRleCwgbm9uY2UpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4g
Kw0KPiA+ICsgICAgICAgcmV0dXJuIG1lc2hfY3J5cHRvX2Flc19jY21fZGVjcnlwdChub25jZSwg
bmV0X2tleSwgTlVMTCwgMCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBlbmNfbXNnLCBlbmNfbXNnX2xlbiwgb3V0LA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldF9taWMsIG1pY19zaXplKTsN
Cj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBtZXNoX2NyeXB0b19hcHBsaWNhdGlvbl9ub25jZSh1
aW50MzJfdCBzZXEsIHVpbnQxNl90IHNyYywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgdWludDE2X3QgZHN0LCB1aW50MzJfdCBpdl9pbmRleCwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vbCBhc3ptaWMsIHVpbnQ4X3Qg
bm9uY2VbMTNdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBub25jZVswXSA9IDB4MDE7DQo+ID4gKyAg
ICAgICBub25jZVsxXSA9IGFzem1pYyA/IDB4ODAgOiAweDAwOw0KPiA+ICsgICAgICAgbm9uY2Vb
Ml0gPSAoc2VxICYgMHgwMGZmMDAwMCkgPj4gMTY7DQo+ID4gKyAgICAgICBub25jZVszXSA9IChz
ZXEgJiAweDAwMDBmZjAwKSA+PiA4Ow0KPiA+ICsgICAgICAgbm9uY2VbNF0gPSAoc2VxICYgMHgw
MDAwMDBmZik7DQo+ID4gKyAgICAgICBub25jZVs1XSA9IChzcmMgJiAweGZmMDApID4+IDg7DQo+
ID4gKyAgICAgICBub25jZVs2XSA9IChzcmMgJiAweDAwZmYpOw0KPiA+ICsgICAgICAgbm9uY2Vb
N10gPSAoZHN0ICYgMHhmZjAwKSA+PiA4Ow0KPiA+ICsgICAgICAgbm9uY2VbOF0gPSAoZHN0ICYg
MHgwMGZmKTsNCj4gPiArICAgICAgIHB1dF9iZTMyKGl2X2luZGV4LCBub25jZSArIDkpOw0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG1l
c2hfY3J5cHRvX2RldmljZV9ub25jZSh1aW50MzJfdCBzZXEsIHVpbnQxNl90IHNyYywNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDE2X3QgZHN0LCB1aW50
MzJfdCBpdl9pbmRleCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgYm9vbCBhc3ptaWMsIHVpbnQ4X3Qgbm9uY2VbMTNdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBu
b25jZVswXSA9IDB4MDI7DQo+ID4gKyAgICAgICBub25jZVsxXSA9IGFzem1pYyA/IDB4ODAgOiAw
eDAwOw0KPiA+ICsgICAgICAgbm9uY2VbMl0gPSAoc2VxICYgMHgwMGZmMDAwMCkgPj4gMTY7DQo+
ID4gKyAgICAgICBub25jZVszXSA9IChzZXEgJiAweDAwMDBmZjAwKSA+PiA4Ow0KPiA+ICsgICAg
ICAgbm9uY2VbNF0gPSAoc2VxICYgMHgwMDAwMDBmZik7DQo+ID4gKyAgICAgICBub25jZVs1XSA9
IChzcmMgJiAweGZmMDApID4+IDg7DQo+ID4gKyAgICAgICBub25jZVs2XSA9IChzcmMgJiAweDAw
ZmYpOw0KPiA+ICsgICAgICAgbm9uY2VbN10gPSAoZHN0ICYgMHhmZjAwKSA+PiA4Ow0KPiA+ICsg
ICAgICAgbm9uY2VbOF0gPSAoZHN0ICYgMHgwMGZmKTsNCj4gPiArICAgICAgIHB1dF9iZTMyKGl2
X2luZGV4LCBub25jZSArIDkpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtib29sIG1lc2hfY3J5cHRvX2FwcGxpY2F0aW9uX2VuY3J5cHQodWlu
dDhfdCBrZXlfaWQsIHVpbnQzMl90IHNlcSwNCj4gdWludDE2X3Qgc3JjLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50MTZfdCBkc3QsIHVpbnQzMl90IGl2
X2luZGV4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25z
dCB1aW50OF90IGFwcF9rZXlbMTZdLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBjb25zdCB1aW50OF90ICphYWQsIHVpbnQ4X3QgYWFkX2xlbiwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdWludDhfdCAqbXNnLCB1
aW50OF90IG1zZ19sZW4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHVpbnQ4X3QgKm91dCwgdm9pZCAqYXBwX21pYywNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgc2l6ZV90IG1pY19zaXplKQ0KPiA+ICt7DQo+ID4gKyAgICAg
ICB1aW50OF90IG5vbmNlWzEzXTsNCj4gPiArICAgICAgIGJvb2wgYXN6bWljID0gKG1pY19zaXpl
ID09IHNpemVvZih1aW50NjRfdCkpID8gdHJ1ZSA6IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmICgha2V5X2lkICYmICFtZXNoX2NyeXB0b19kZXZpY2Vfbm9uY2Uoc2VxLCBzcmMsIGRzdCwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl2X2luZGV4LCBhc3ptaWMsIG5v
bmNlKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAg
ICAgIGlmIChrZXlfaWQgJiYgIW1lc2hfY3J5cHRvX2FwcGxpY2F0aW9uX25vbmNlKHNlcSwgc3Jj
LCBkc3QsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdl9pbmRleCwgYXN6
bWljLCBub25jZSkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+
ID4gKyAgICAgICByZXR1cm4gbWVzaF9jcnlwdG9fYWVzX2NjbV9lbmNyeXB0KG5vbmNlLCBhcHBf
a2V5LCBhYWQsDQo+IGFhZF9sZW4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgbXNnLCBtc2dfbGVuLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dCwgYXBwX21pYywgbWljX3NpemUpOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtib29sIG1lc2hfY3J5cHRvX2FwcGxpY2F0aW9uX2RlY3J5cHQodWlu
dDhfdCBrZXlfaWQsIHVpbnQzMl90IHNlcSwNCj4gdWludDE2X3Qgc3JjLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgdWludDE2X3QgZHN0LCB1aW50MzJfdCBpdl9pbmRleCwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4X3QgYXBwX2tl
eVsxNl0sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1aW50OF90
ICphYWQsIHVpbnQ4X3QgYWFkX2xlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIGNvbnN0IHVpbnQ4X3QgKmVuY19tc2csIHVpbnQ4X3QgZW5jX21zZ19sZW4sDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50OF90ICpvdXQsIHZvaWQgKmFwcF9taWMs
IHNpemVfdCBtaWNfc2l6ZSkNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCBub25jZVsxM107
DQo+ID4gKyAgICAgICBib29sIGFzem1pYyA9IChtaWNfc2l6ZSA9PSBzaXplb2YodWludDY0X3Qp
KSA/IHRydWUgOiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWtleV9pZCAmJiAhbWVz
aF9jcnlwdG9fZGV2aWNlX25vbmNlKHNlcSwgc3JjLCBkc3QsDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBpdl9pbmRleCwgYXN6bWljLCBub25jZSkpDQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoa2V5X2lkICYmICFt
ZXNoX2NyeXB0b19hcHBsaWNhdGlvbl9ub25jZShzZXEsIHNyYywgZHN0LA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgaXZfaW5kZXgsIGFzem1pYywgbm9uY2UpKQ0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIG1l
c2hfY3J5cHRvX2Flc19jY21fZGVjcnlwdChub25jZSwgYXBwX2tleSwNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhYWQsIGFhZF9sZW4sIGVuY19t
c2csDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ZW5jX21zZ19sZW4sIG91dCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBhcHBfbWljLCBtaWNfc2l6ZSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jv
b2wgbWVzaF9jcnlwdG9fc2Vzc2lvbl9rZXkoY29uc3QgdWludDhfdCBzZWNyZXRbMzJdLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1aW50OF90IHNh
bHRbMTZdLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50
OF90IHNlc3Npb25fa2V5WzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3QgdWludDhfdCBw
cnNrWzRdID0gInByc2siOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghYWVzX2NtYWNfb25lKHNh
bHQsIHNlY3JldCwgMzIsIHNlc3Npb25fa2V5KSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBhZXNfY21hY19vbmUoc2Vzc2lvbl9r
ZXksIHByc2ssIDQsIHNlc3Npb25fa2V5KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBtZXNo
X2NyeXB0b19ub25jZShjb25zdCB1aW50OF90IHNlY3JldFszMl0sDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4X3Qgc2FsdFsxNl0sDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQ4X3Qgbm9uY2VbMTNd
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjb25zdCB1aW50OF90IHByc25bNF0gPSAicHJzbiI7DQo+
ID4gKyAgICAgICB1aW50OF90IHRtcFsxNl07DQo+ID4gKyAgICAgICBib29sIHJlc3VsdDsNCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoIWFlc19jbWFjX29uZShzYWx0LCBzZWNyZXQsIDMyLCB0bXAp
KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAg
cmVzdWx0ID0gIGFlc19jbWFjX29uZSh0bXAsIHByc24sIDQsIHRtcCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKHJlc3VsdCkNCj4gPiArICAgICAgICAgICAgICAgbWVtY3B5KG5vbmNlLCB0bXAg
KyAzLCAxMyk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHJlc3VsdDsNCj4gPiArfQ0KPiA+
ICsNCj4gPiArYm9vbCBtZXNoX2NyeXB0b19zMShjb25zdCB2b2lkICppbmZvLCBzaXplX3QgbGVu
LCB1aW50OF90IHNhbHRbMTZdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjb25zdCB1aW50OF90IHpl
cm9bMTZdID0gezB9Ow0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBhZXNfY21hY19vbmUoemVy
bywgaW5mbywgbGVuLCBzYWx0KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBtZXNoX2NyeXB0
b19wcm92X3Byb3Zfc2FsdChjb25zdCB1aW50OF90IGNvbmZfc2FsdFsxNl0sDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4X3QgcHJvdl9yYW5k
WzE2XSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qg
dWludDhfdCBkZXZfcmFuZFsxNl0sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHVpbnQ4X3QgcHJvdl9zYWx0WzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAgY29u
c3QgdWludDhfdCB6ZXJvWzE2XSA9IHswfTsNCj4gPiArICAgICAgIHVpbnQ4X3QgdG1wWzE2ICog
M107DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KHRtcCwgY29uZl9zYWx0LCAxNik7DQo+ID4g
KyAgICAgICBtZW1jcHkodG1wICsgMTYsIHByb3ZfcmFuZCwgMTYpOw0KPiA+ICsgICAgICAgbWVt
Y3B5KHRtcCArIDMyLCBkZXZfcmFuZCwgMTYpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBh
ZXNfY21hY19vbmUoemVybywgdG1wLCBzaXplb2YodG1wKSwgcHJvdl9zYWx0KTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArYm9vbCBtZXNoX2NyeXB0b19wcm92X2NvbmZfa2V5KGNvbnN0IHVpbnQ4X3Qg
c2VjcmV0WzMyXSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
Y29uc3QgdWludDhfdCBzYWx0WzE2XSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgdWludDhfdCBjb25mX2tleVsxNl0pDQo+ID4gK3sNCj4gPiArICAgICAgIGNv
bnN0IHVpbnQ4X3QgcHJja1s0XSA9ICJwcmNrIjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWFl
c19jbWFjX29uZShzYWx0LCBzZWNyZXQsIDMyLCBjb25mX2tleSkpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gYWVzX2NtYWNfb25l
KGNvbmZfa2V5LCBwcmNrLCA0LCBjb25mX2tleSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wg
bWVzaF9jcnlwdG9fZGV2aWNlX2tleShjb25zdCB1aW50OF90IHNlY3JldFszMl0sDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdWludDhf
dCBzYWx0WzE2XSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICB1aW50OF90IGRldmljZV9rZXlbMTZdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjb25z
dCB1aW50OF90IHByZGtbNF0gPSAicHJkayI7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFhZXNf
Y21hY19vbmUoc2FsdCwgc2VjcmV0LCAzMiwgZGV2aWNlX2tleSkpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gYWVzX2NtYWNfb25l
KGRldmljZV9rZXksIHByZGssIDQsIGRldmljZV9rZXkpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICti
b29sIG1lc2hfY3J5cHRvX3ZpcnR1YWxfYWRkcihjb25zdCB1aW50OF90IHZpcnR1YWxfbGFiZWxb
MTZdLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IHVpbnQxNl90ICphZGRyKQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50OF90IHRtcFsxNl07DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKCFtZXNoX2NyeXB0b19zMSgidnRhZCIsIDQsIHRtcCkpDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
IWFkZHIgfHwgIWFlc19jbWFjX29uZSh0bXAsIHZpcnR1YWxfbGFiZWwsIDE2LCB0bXApKQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgKmFkZHIg
PSAoZ2V0X2JlMTYodG1wICsgMTQpICYgMHgzZmZmKSB8IDB4ODAwMDsNCj4gPiArDQo+ID4gKyAg
ICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBtZXNoX2NyeXB0b19w
YWNrZXRfZW5jb2RlKHVpbnQ4X3QgKnBhY2tldCwgdWludDhfdCBwYWNrZXRfbGVuLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdWludDhfdCBuZXR3b3JrX2tleVsx
Nl0sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50MzJfdCBpdl9pbmRl
eCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4X3QgcHJp
dmFjeV9rZXlbMTZdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50OF90IG5ldHdvcmtfbm9uY2Vb
MTNdID0geyAweDAwLCAweDAwIH07DQo+ID4gKyAgICAgICB1aW50OF90IHByaXZhY3lfY291bnRl
clsxNl0gPSB7IDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIDB4MDAsIH07DQo+ID4gKyAgICAgICB1
aW50OF90IHRtcFsxNl07DQo+ID4gKyAgICAgICBpbnQgaTsNCj4gPiArDQo+ID4gKyAgICAgICAv
KiBEZXRlY3QgUHJveHkgcGFja2V0IGJ5IENUTCA9PSB0cnVlICYmIERTVCA9PSAweDAwMDAgKi8N
Cj4gPiArICAgICAgIGlmICgocGFja2V0WzFdICYgQ1RMKSAmJiBnZXRfYmUxNihwYWNrZXQgKyA3
KSA9PSAwKQ0KPiA+ICsgICAgICAgICAgICAgICBuZXR3b3JrX25vbmNlWzBdID0gMHgwMzsNCj4g
PiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgLyogQ1RMICsgVFRMICovDQo+ID4g
KyAgICAgICAgICAgICAgIG5ldHdvcmtfbm9uY2VbMV0gPSBwYWNrZXRbMV07DQo+ID4gKw0KPiA+
ICsgICAgICAgLyogU2VxIE51bSAqLw0KPiA+ICsgICAgICAgbmV0d29ya19ub25jZVsyXSA9IHBh
Y2tldFsyXTsNCj4gPiArICAgICAgIG5ldHdvcmtfbm9uY2VbM10gPSBwYWNrZXRbM107DQo+ID4g
KyAgICAgICBuZXR3b3JrX25vbmNlWzRdID0gcGFja2V0WzRdOw0KPiA+ICsNCj4gPiArICAgICAg
IC8qIFNSQyAqLw0KPiA+ICsgICAgICAgbmV0d29ya19ub25jZVs1XSA9IHBhY2tldFs1XTsNCj4g
PiArICAgICAgIG5ldHdvcmtfbm9uY2VbNl0gPSBwYWNrZXRbNl07DQo+ID4gKw0KPiA+ICsgICAg
ICAgLyogRFNUIG5vdCBhdmFpbGFibGUgKi8NCj4gPiArICAgICAgIG5ldHdvcmtfbm9uY2VbN10g
PSAwOw0KPiA+ICsgICAgICAgbmV0d29ya19ub25jZVs4XSA9IDA7DQo+ID4gKw0KPiA+ICsgICAg
ICAgLyogSVYgSW5kZXggKi8NCj4gPiArICAgICAgIHB1dF9iZTMyKGl2X2luZGV4LCBuZXR3b3Jr
X25vbmNlICsgOSk7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogQ2hlY2sgZm9yIExvbmcgbmV0LU1J
QyAqLw0KPiA+ICsgICAgICAgaWYgKHBhY2tldFsxXSAmIENUTCkgew0KPiA+ICsgICAgICAgICAg
ICAgICBpZiAoIW1lc2hfY3J5cHRvX2Flc19jY21fZW5jcnlwdChuZXR3b3JrX25vbmNlLA0KPiBu
ZXR3b3JrX2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
TlVMTCwgMCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFj
a2V0ICsgNywgcGFja2V0X2xlbiAtIDcgLSA4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBwYWNrZXQgKyA3LCBOVUxMLCBzaXplb2YodWludDY0X3QpKSkNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICB9IGVs
c2Ugew0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIW1lc2hfY3J5cHRvX2Flc19jY21fZW5jcnlw
dChuZXR3b3JrX25vbmNlLA0KPiBuZXR3b3JrX2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgTlVMTCwgMCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgcGFja2V0ICsgNywgcGFja2V0X2xlbiAtIDcgLSA0LA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWNrZXQgKyA3LCBOVUxMLCBz
aXplb2YodWludDMyX3QpKSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFs
c2U7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcHV0X2JlMzIoaXZfaW5kZXgs
IHByaXZhY3lfY291bnRlciArIDUpOw0KPiA+ICsgICAgICAgbWVtY3B5KHByaXZhY3lfY291bnRl
ciArIDksIHBhY2tldCArIDcsIDcpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghYWVzX2VjYl9v
bmUocHJpdmFjeV9rZXksIHByaXZhY3lfY291bnRlciwgdG1wKSkNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCA2OyBp
KyspDQo+ID4gKyAgICAgICAgICAgICAgIHBhY2tldFsxICsgaV0gXj0gdG1wW2ldOw0KPiA+ICsN
Cj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG1lc2hf
Y3J5cHRvX3BhY2tldF9kZWNvZGUoY29uc3QgdWludDhfdCAqcGFja2V0LCB1aW50OF90DQo+IHBh
Y2tldF9sZW4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib29sIHByb3h5
LCB1aW50OF90ICpvdXQsIHVpbnQzMl90IGl2X2luZGV4LA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgY29uc3QgdWludDhfdCBuZXR3b3JrX2tleVsxNl0sDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB1aW50OF90IHByaXZhY3lfa2V5WzE2XSkN
Cj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCBwcml2YWN5X2NvdW50ZXJbMTZdID0geyAweDAw
LCAweDAwLCAweDAwLCAweDAwLCAweDAwLCB9Ow0KPiA+ICsgICAgICAgdWludDhfdCBuZXR3b3Jr
X25vbmNlWzEzXSA9IHsgMHgwMCwgMHgwMCwgfTsNCj4gPiArICAgICAgIHVpbnQ4X3QgdG1wWzE2
XTsNCj4gPiArICAgICAgIHVpbnQxNl90IHNyYzsNCj4gPiArICAgICAgIGludCBpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChwYWNrZXRfbGVuIDwgMTQpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBwdXRfYmUzMihpdl9pbmRleCwgcHJpdmFj
eV9jb3VudGVyICsgNSk7DQo+ID4gKyAgICAgICBtZW1jcHkocHJpdmFjeV9jb3VudGVyICsgOSwg
cGFja2V0ICsgNywgNyk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFhZXNfZWNiX29uZShwcml2
YWN5X2tleSwgcHJpdmFjeV9jb3VudGVyLCB0bXApKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1
cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KG91dCwgcGFja2V0LCBwYWNrZXRf
bGVuKTsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCA2OyBpKyspDQo+ID4gKyAgICAgICAg
ICAgICAgIG91dFsxICsgaV0gXj0gdG1wW2ldOw0KPiA+ICsNCj4gPiArICAgICAgIHNyYyAgPSBn
ZXRfYmUxNihvdXQgKyA1KTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBQcmUtY2hlY2sgU1JDIGFk
ZHJlc3MgZm9yIGlsbGVnYWwgdmFsdWVzICovDQo+ID4gKyAgICAgICBpZiAoIXNyYyB8fCBzcmMg
Pj0gMHg4MDAwKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+
ICsgICAgICAgLyogRGV0ZWN0IFByb3h5IHBhY2tldCBieSBDVEwgPT0gdHJ1ZSAmJiBwcm94eSA9
PSB0cnVlICovDQo+ID4gKyAgICAgICBpZiAoKG91dFsxXSAmIENUTCkgJiYgcHJveHkpDQo+ID4g
KyAgICAgICAgICAgICAgIG5ldHdvcmtfbm9uY2VbMF0gPSAweDAzOw0KPiA+ICsgICAgICAgZWxz
ZQ0KPiA+ICsgICAgICAgICAgICAgICAvKiBDVEwgKyBUVEwgKi8NCj4gPiArICAgICAgICAgICAg
ICAgbmV0d29ya19ub25jZVsxXSA9IG91dFsxXTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBTZXEg
TnVtICovDQo+ID4gKyAgICAgICBuZXR3b3JrX25vbmNlWzJdID0gb3V0WzJdOw0KPiA+ICsgICAg
ICAgbmV0d29ya19ub25jZVszXSA9IG91dFszXTsNCj4gPiArICAgICAgIG5ldHdvcmtfbm9uY2Vb
NF0gPSBvdXRbNF07DQo+ID4gKw0KPiA+ICsgICAgICAgLyogU1JDICovDQo+ID4gKyAgICAgICBu
ZXR3b3JrX25vbmNlWzVdID0gb3V0WzVdOw0KPiA+ICsgICAgICAgbmV0d29ya19ub25jZVs2XSA9
IG91dFs2XTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBEU1Qgbm90IGF2YWlsYWJsZSAqLw0KPiA+
ICsgICAgICAgbmV0d29ya19ub25jZVs3XSA9IDA7DQo+ID4gKyAgICAgICBuZXR3b3JrX25vbmNl
WzhdID0gMDsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBJViBJbmRleCAqLw0KPiA+ICsgICAgICAg
cHV0X2JlMzIoaXZfaW5kZXgsIG5ldHdvcmtfbm9uY2UgKyA5KTsNCj4gPiArDQo+ID4gKyAgICAg
ICAvKiBDaGVjayBmb3IgTG9uZyBNSUMgKi8NCj4gPiArICAgICAgIGlmIChvdXRbMV0gJiBDVEwp
IHsNCj4gPiArICAgICAgICAgICAgICAgdWludDY0X3QgbWljOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKCFtZXNoX2NyeXB0b19hZXNfY2NtX2RlY3J5cHQobmV0d29ya19ub25jZSwN
Cj4gbmV0d29ya19rZXksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIE5VTEwsIDAsIHBhY2tldCArIDcsIHBhY2tldF9sZW4gLSA3LA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXQgKyA3LCAmbWljLCBzaXplb2YobWljKSkp
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgbWljIF49IGdldF9iZTY0KG91dCArIHBhY2tldF9sZW4gLSA4KTsNCj4g
PiArICAgICAgICAgICAgICAgcHV0X2JlNjQobWljLCBvdXQgKyBwYWNrZXRfbGVuIC0gOCk7DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAobWljKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAg
ICAgICAgIHVpbnQzMl90IG1pYzsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmICghbWVz
aF9jcnlwdG9fYWVzX2NjbV9kZWNyeXB0KG5ldHdvcmtfbm9uY2UsDQo+IG5ldHdvcmtfa2V5LA0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOVUxMLCAwLCBwYWNr
ZXQgKyA3LCBwYWNrZXRfbGVuIC0gNywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgb3V0ICsgNywgJm1pYywgc2l6ZW9mKG1pYykpKQ0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIG1p
YyBePSBnZXRfYmUzMihvdXQgKyBwYWNrZXRfbGVuIC0gNCk7DQo+ID4gKyAgICAgICAgICAgICAg
IHB1dF9iZTMyKG1pYywgb3V0ICsgcGFja2V0X2xlbiAtIDQpOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKG1pYykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFs
c2U7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4g
K30NCj4gPiArDQo+ID4gK2Jvb2wgbWVzaF9nZXRfcmFuZG9tX2J5dGVzKHZvaWQgKmJ1Ziwgc2l6
ZV90IG51bV9ieXRlcykNCj4gPiArew0KPiA+ICsgICAgICAgc3NpemVfdCBsZW47DQo+ID4gKyAg
ICAgICBpbnQgZmQ7DQo+ID4gKw0KPiA+ICsgICAgICAgZmQgPSBvcGVuKCIvZGV2L3VyYW5kb20i
LCBPX1JET05MWSk7DQo+ID4gKyAgICAgICBpZiAoZmQgPCAwKQ0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbGVuID0gcmVhZChmZCwgYnVmLCBu
dW1fYnl0ZXMpOw0KPiA+ICsNCj4gPiArICAgICAgIGNsb3NlKGZkKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAobGVuIDwgMCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gZGlmZiAtLWdpdCBhL21l
c2gvZ2F0dC5jIGIvbWVzaC9nYXR0LmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGlu
ZGV4IDAwMDAwMDAuLmI5ODEwNTQNCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvbWVzaC9n
YXR0LmMNCj4gPiBAQCAtMCwwICsxLDYwOSBAQA0KPiA+ICsvKg0KPiA+ICsgKg0KPiA+ICsgKiAg
Qmx1ZVogLSBCbHVldG9vdGggcHJvdG9jb2wgc3RhY2sgZm9yIExpbnV4DQo+ID4gKyAqDQo+ID4g
KyAqICBDb3B5cmlnaHQgKEMpIDIwMTcgIEludGVsIENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJl
c2VydmVkLg0KPiA+ICsgKg0KPiA+ICsgKg0KPiA+ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGZyZWUg
c29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcg0KPiA+ICsgKiAgbW9kaWZ5
IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+
ICsgKiAgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlv
bjsgZWl0aGVyDQo+ID4gKyAqICB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlv
dXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4gPiArICoNCj4gPiArICogIFRoaXMgbGli
cmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLA0K
PiA+ICsgKiAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxp
ZWQgd2FycmFudHkgb2YNCj4gPiArICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBB
IFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUNCj4gR05VDQo+ID4gKyAqICBMZXNzZXIgR2Vu
ZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLg0KPiA+ICsgKg0KPiA+ICsgKiAg
WW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFs
IFB1YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90
LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQ0KPiA+ICsgKiAgRm91bmRhdGlvbiwgSW5jLiwg
NTEgRnJhbmtsaW4gU3QsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxDQo+IFVT
QQ0KPiA+ICsgKg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gKyNpZmRlZiBIQVZFX0NPTkZJR19IDQo+
ID4gKyNpbmNsdWRlIDxjb25maWcuaD4NCj4gPiArI2VuZGlmDQo+ID4gKw0KPiA+ICsjaW5jbHVk
ZSA8c3RkaW8uaD4NCj4gPiArI2luY2x1ZGUgPGVycm5vLmg+DQo+ID4gKyNpbmNsdWRlIDx1bmlz
dGQuaD4NCj4gPiArI2luY2x1ZGUgPHN0ZGxpYi5oPg0KPiA+ICsjaW5jbHVkZSA8c3RkYm9vbC5o
Pg0KPiA+ICsjaW5jbHVkZSA8c3lzL3Vpby5oPg0KPiA+ICsjaW5jbHVkZSA8d29yZGV4cC5oPg0K
PiA+ICsNCj4gPiArI2luY2x1ZGUgPHJlYWRsaW5lL3JlYWRsaW5lLmg+DQo+ID4gKyNpbmNsdWRl
IDxyZWFkbGluZS9oaXN0b3J5Lmg+DQo+ID4gKyNpbmNsdWRlIDxnbGliLmg+DQo+ID4gKw0KPiA+
ICsjaW5jbHVkZSAic3JjL3NoYXJlZC9pby5oIg0KPiA+ICsjaW5jbHVkZSAiZ2RidXMvZ2RidXMu
aCINCj4gPiArI2luY2x1ZGUgImxpYi9ibHVldG9vdGguaCINCj4gPiArI2luY2x1ZGUgImxpYi91
dWlkLmgiDQo+ID4gKyNpbmNsdWRlICJjbGllbnQvZGlzcGxheS5oIg0KPiA+ICsjaW5jbHVkZSAi
bm9kZS5oIg0KPiA+ICsjaW5jbHVkZSAidXRpbC5oIg0KPiA+ICsjaW5jbHVkZSAiZ2F0dC5oIg0K
PiA+ICsjaW5jbHVkZSAicHJvdi5oIg0KPiA+ICsjaW5jbHVkZSAibmV0LmgiDQo+ID4gKw0KPiA+
ICsjZGVmaW5lIE1FU0hfUFJPVl9EQVRBX09VVF9VVUlEX1NUUiAgICAiMDAwMDJhZGMtMDAwMC0x
MDAwLQ0KPiA4MDAwLTAwODA1ZjliMzRmYiINCj4gPiArI2RlZmluZSBNRVNIX1BST1hZX0RBVEFf
T1VUX1VVSURfU1RSICAgIjAwMDAyYWRlLTAwMDAtMTAwMC0NCj4gODAwMC0wMDgwNWY5YjM0ZmIi
DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IGlvICp3cml0ZV9pbzsNCj4gPiArc3RhdGljIHVp
bnQxNl90IHdyaXRlX210dTsNCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgaW8gKm5vdGlmeV9p
bzsNCj4gPiArc3RhdGljIHVpbnQxNl90IG5vdGlmeV9tdHU7DQo+ID4gKw0KPiA+ICtzdHJ1Y3Qg
d3JpdGVfZGF0YSB7DQo+ID4gKyAgICAgICBHREJ1c1Byb3h5ICpwcm94eTsNCj4gPiArICAgICAg
IHZvaWQgKnVzZXJfZGF0YTsNCj4gPiArICAgICAgIHN0cnVjdCBpb3ZlYyBpb3Y7DQo+ID4gKyAg
ICAgICBHREJ1c1JldHVybkZ1bmN0aW9uIGNiOw0KPiA+ICsgICAgICAgdWludDhfdCAqZ2F0dF9k
YXRhOw0KPiA+ICsgICAgICAgdWludDhfdCBnYXR0X2xlbjsNCj4gPiArfTsNCj4gPiArDQo+ID4g
K3N0cnVjdCBub3RpZnlfZGF0YSB7DQo+ID4gKyAgICAgICBHREJ1c1Byb3h5ICpwcm94eTsNCj4g
PiArICAgICAgIGJvb2wgZW5hYmxlOw0KPiA+ICsgICAgICAgR0RCdXNSZXR1cm5GdW5jdGlvbiBj
YjsNCj4gPiArICAgICAgIHZvaWQgKnVzZXJfZGF0YTsNCj4gPiArfTsNCj4gPiArDQo+ID4gK2Jv
b2wgbWVzaF9nYXR0X2lzX2NoaWxkKEdEQnVzUHJveHkgKnByb3h5LCBHREJ1c1Byb3h5ICpwYXJl
bnQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY2hhciAqbmFtZSkNCj4gPiAr
ew0KPiA+ICsgICAgICAgREJ1c01lc3NhZ2VJdGVyIGl0ZXI7DQo+ID4gKyAgICAgICBjb25zdCBj
aGFyICpwYXJlbnRfcGF0aDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXBhcmVudCkNCj4gPiAr
ICAgICAgICAgICAgICAgcmV0dXJuIEZBTFNFOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChnX2Ri
dXNfcHJveHlfZ2V0X3Byb3BlcnR5KHByb3h5LCBuYW1lLCAmaXRlcikgPT0gRkFMU0UpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBGQUxTRTsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX21l
c3NhZ2VfaXRlcl9nZXRfYmFzaWMoJml0ZXIsICZwYXJlbnRfcGF0aCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKCFzdHJjbXAocGFyZW50X3BhdGgsIGdfZGJ1c19wcm94eV9nZXRfcGF0aChwYXJl
bnQpKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIFRSVUU7DQo+ID4gKyAgICAgICBlbHNl
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBGQUxTRTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
LyogUmVmYWN0b3IgdGhpcyBvbmNlIGFjdHVhbCBNVFUgaXMgYXZhaWxhYmxlICovDQo+ID4gKyNk
ZWZpbmUgR0FUVF9NVFUgICAgICAgMjMNCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHdyaXRlX2Rh
dGFfZnJlZSh2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCB3cml0
ZV9kYXRhICpkYXRhID0gdXNlcl9kYXRhOw0KPiA+ICsNCj4gPiArICAgICAgIGdfZnJlZShkYXRh
LT5nYXR0X2RhdGEpOw0KPiA+ICsgICAgICAgZnJlZShkYXRhKTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArc3RhdGljIHZvaWQgd3JpdGVfc2V0dXAoREJ1c01lc3NhZ2VJdGVyICppdGVyLCB2b2lkICp1
c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCB3cml0ZV9kYXRhICpkYXRhID0g
dXNlcl9kYXRhOw0KPiA+ICsgICAgICAgc3RydWN0IGlvdmVjICppb3YgPSAmZGF0YS0+aW92Ow0K
PiA+ICsgICAgICAgREJ1c01lc3NhZ2VJdGVyIGFycmF5LCBkaWN0Ow0KPiA+ICsNCj4gPiArICAg
ICAgIGRidXNfbWVzc2FnZV9pdGVyX29wZW5fY29udGFpbmVyKGl0ZXIsIERCVVNfVFlQRV9BUlJB
WSwgInkiLA0KPiAmYXJyYXkpOw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfYXBwZW5k
X2ZpeGVkX2FycmF5KCZhcnJheSwgREJVU19UWVBFX0JZVEUsDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJmlvdi0+aW92X2Jhc2UsIGlvdi0+aW92
X2xlbik7DQo+ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9jbG9zZV9jb250YWluZXIoaXRl
ciwgJmFycmF5KTsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9vcGVuX2Nv
bnRhaW5lcihpdGVyLCBEQlVTX1RZUEVfQVJSQVksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIERCVVNfRElDVF9FTlRSWV9CRUdJTl9DSEFSX0FTX1NUUklORw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEQlVTX1RZUEVfU1RS
SU5HX0FTX1NUUklORw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBEQlVTX1RZUEVfVkFSSUFOVF9BU19TVFJJTkcNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgREJVU19ESUNUX0VOVFJZX0VORF9DSEFSX0FTX1NUUklORywNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJmRpY3QpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2Nsb3NlX2NvbnRhaW5lcihpdGVyLCAmZGlj
dCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQxNl90IG1lc2hfZ2F0dF9zYXIodWludDhfdCAq
KnBrdCwgdWludDE2X3Qgc2l6ZSkNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3QgdWludDhfdCAq
ZGF0YSA9ICpwa3Q7DQo+ID4gKyAgICAgICB1aW50OF90IGdhdHRfaGRyID0gKmRhdGErKzsNCj4g
PiArICAgICAgIHVpbnQ4X3QgdHlwZSA9IGdhdHRfaGRyICYgR0FUVF9UWVBFX01BU0s7DQo+ID4g
KyAgICAgICBzdGF0aWMgdWludDhfdCBnYXR0X3NpemU7DQo+ID4gKyAgICAgICBzdGF0aWMgdWlu
dDhfdCBnYXR0X3BrdFs2N107DQo+ID4gKw0KPiA+ICsgICAgICAgcHJpbnRfYnl0ZV9hcnJheSgi
R0FUVC1SWDpcdCIsICpwa3QsIHNpemUpOw0KPiA+ICsgICAgICAgaWYgKHNpemUgPCAxKSB7DQo+
ID4gKyAgICAgICAgICAgICAgIGdhdHRfcGt0WzBdID0gR0FUVF9UWVBFX0lOVkFMSUQ7DQo+ID4g
KyAgICAgICAgICAgICAgIC8qIFRPRE86IERpc2Nvbm5lY3QgR0FUVCBwZXIgbGFzdCBwYXJhZ3Jh
cGggc2VjIDYuNiAqLw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICBzaXplLS07DQo+ID4gKw0KPiA+ICsgICAgICAgc3dpdGNo
IChnYXR0X2hkciAmIEdBVFRfU0FSX01BU0spIHsNCj4gPiArICAgICAgIGNhc2UgR0FUVF9TQVJf
RklSU1Q6DQo+ID4gKyAgICAgICAgICAgICAgIGdhdHRfc2l6ZSA9IDE7DQo+ID4gKyAgICAgICAg
ICAgICAgIGdhdHRfcGt0WzBdID0gdHlwZTsNCj4gPiArICAgICAgICAgICAgICAgLyogVE9ETzog
U3RhcnQgUHJveHkgVGltZW91dCAqLw0KPiA+ICsgICAgICAgICAgICAgICAvKiBmYWxsIHRocm91
Z2ggKi8NCj4gPiArDQo+ID4gKyAgICAgICBjYXNlIEdBVFRfU0FSX0NPTlRJTlVFOg0KPiA+ICsg
ICAgICAgICAgICAgICBpZiAoZ2F0dF9wa3RbMF0gIT0gdHlwZSB8fA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgZ2F0dF9zaXplICsgc2l6ZSA+IE1BWF9HQVRUX1NJWkUpIHsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLyogSW52YWxpZGF0ZSBwYWNrZXQg
YW5kIHJldHVybiBmYWlsdXJlICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ2F0dF9w
a3RbMF0gPSBHQVRUX1RZUEVfSU5WQUxJRDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAv
KiBUT0RPOiBEaXNjb25uZWN0IEdBVFQgcGVyIGxhc3QgcGFyYWdyYXBoIHNlYyA2LjYgKi8NCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArICAgICAgICAgICAgICAg
fQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgbWVtY3B5KGdhdHRfcGt0ICsgZ2F0dF9zaXpl
LCBkYXRhLCBzaXplKTsNCj4gPiArICAgICAgICAgICAgICAgZ2F0dF9zaXplICs9IHNpemU7DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAvKiBXZSBhcmUgZ29vZCB0byB0aGlzIHBvaW50LCBi
dXQgaW5jb21wbGV0ZSAqLw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArDQo+
ID4gKyAgICAgICBkZWZhdWx0Og0KPiA+ICsgICAgICAgY2FzZSBHQVRUX1NBUl9DT01QTEVURToN
Cj4gPiArICAgICAgICAgICAgICAgZ2F0dF9zaXplID0gMTsNCj4gPiArICAgICAgICAgICAgICAg
Z2F0dF9wa3RbMF0gPSB0eXBlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogZmFsbCB0
aHJvdWdoICovDQo+ID4gKw0KPiA+ICsgICAgICAgY2FzZSBHQVRUX1NBUl9MQVNUOg0KPiA+ICsg
ICAgICAgICAgICAgICBpZiAoZ2F0dF9wa3RbMF0gIT0gdHlwZSB8fA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgZ2F0dF9zaXplICsgc2l6ZSA+IE1BWF9HQVRUX1NJWkUpIHsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLyogSW52YWxpZGF0ZSBwYWNrZXQg
YW5kIHJldHVybiBmYWlsdXJlICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ2F0dF9w
a3RbMF0gPSBHQVRUX1RZUEVfSU5WQUxJRDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAv
KiBEaXNjb25uZWN0IEdBVFQgcGVyIGxhc3QgcGFyYWdyYXBoIHNlYyA2LjYgKi8NCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgbWVtY3B5KGdhdHRfcGt0ICsgZ2F0dF9zaXplLCBkYXRh
LCBzaXplKTsNCj4gPiArICAgICAgICAgICAgICAgZ2F0dF9zaXplICs9IHNpemU7DQo+ID4gKyAg
ICAgICAgICAgICAgICpwa3QgPSBnYXR0X3BrdDsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IGdhdHRfc2l6ZTsNCj4gPiArICAgICAgIH0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJv
b2wgcGlwZV93cml0ZShzdHJ1Y3QgaW8gKmlvLCB2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4g
PiArICAgICAgIHN0cnVjdCB3cml0ZV9kYXRhICpkYXRhID0gdXNlcl9kYXRhOw0KPiA+ICsgICAg
ICAgc3RydWN0IGlvdmVjIGlvdlsyXTsNCj4gPiArICAgICAgIHVpbnQ4X3Qgc2FyOw0KPiA+ICsg
ICAgICAgdWludDhfdCBtYXhfbGVuID0gd3JpdGVfbXR1IC0gNDsNCj4gPiArDQo+ID4gKyAgICAg
ICBpZiAoZGF0YSA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsNCj4g
PiArDQo+ID4gKyAgICAgICBwcmludF9ieXRlX2FycmF5KCJHQVRULVRYOlx0IiwgZGF0YS0+Z2F0
dF9kYXRhLCBkYXRhLT5nYXR0X2xlbik7DQo+ID4gKw0KPiA+ICsgICAgICAgc2FyID0gZGF0YS0+
Z2F0dF9kYXRhWzBdOw0KPiA+ICsNCj4gPiArICAgICAgIGRhdGEtPmlvdi5pb3ZfYmFzZSA9IGRh
dGEtPmdhdHRfZGF0YSArIDE7DQo+ID4gKyAgICAgICBkYXRhLT5pb3YuaW92X2xlbi0tOw0KPiA+
ICsNCj4gPiArICAgICAgIGlvdlswXS5pb3ZfYmFzZSA9ICZzYXI7DQo+ID4gKyAgICAgICBpb3Zb
MF0uaW92X2xlbiA9IHNpemVvZihzYXIpOw0KPiA+ICsNCj4gPiArICAgICAgIHdoaWxlICgxKSB7
DQo+ID4gKyAgICAgICAgICAgICAgIGludCBlcnI7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAg
ICBpb3ZbMV0gPSBkYXRhLT5pb3Y7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBlcnIgPSBp
b19zZW5kKGlvLCBpb3YsIDIpOw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZXJyIDwgMCkgew0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRmFpbGVkIHRvIHdyaXRlOiAl
c1xuIiwgc3RyZXJyb3IoLWVycikpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHdyaXRl
X2RhdGFfZnJlZShkYXRhKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFs
c2U7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHN3
aXRjaCAoc2FyICYgR0FUVF9TQVJfTUFTSykgew0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIEdB
VFRfU0FSX0ZJUlNUOg0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIEdBVFRfU0FSX0NPTlRJTlVF
Og0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGRhdGEtPmdhdHRfbGVuIC09IG1heF9sZW47
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZGF0YS0+aW92Lmlvdl9iYXNlID0gZGF0YS0+
aW92Lmlvdl9iYXNlICsgbWF4X2xlbjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgc2FyICY9IEdBVFRfVFlQRV9NQVNLOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlm
IChtYXhfbGVuIDwgZGF0YS0+Z2F0dF9sZW4pIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIGRhdGEtPmlvdi5pb3ZfbGVuID0gbWF4X2xlbjsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHNhciB8PSBHQVRUX1NBUl9DT05USU5VRTsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgZGF0YS0+aW92Lmlvdl9sZW4gPSBkYXRhLT5nYXR0X2xlbjsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHNhciB8PSBHQVRUX1NBUl9MQVNUOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJl
YWs7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBkZWZhdWx0Og0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIGlmKGRhdGEtPmNiKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgZGF0YS0+Y2IoTlVMTCwgZGF0YS0+dXNlcl9kYXRhKTsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICB3cml0ZV9kYXRhX2ZyZWUoZGF0YSk7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgIH0N
Cj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgd3JpdGVfcmVwbHkoREJ1c01lc3NhZ2Ug
Km1lc3NhZ2UsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IHdy
aXRlX2RhdGEgKmRhdGEgPSB1c2VyX2RhdGE7DQo+ID4gKyAgICAgICBzdHJ1Y3Qgd3JpdGVfZGF0
YSAqdG1wOw0KPiA+ICsgICAgICAgdWludDhfdCAqZHB0ciA9IGRhdGEtPmdhdHRfZGF0YTsNCj4g
PiArICAgICAgIHVpbnQ4X3QgbWF4X2xlbiA9IEdBVFRfTVRVIC0gMzsNCj4gPiArICAgICAgIHVp
bnQ4X3QgbWF4X3NlZyA9IEdBVFRfTVRVIC0gNDsNCj4gPiArICAgICAgIERCdXNFcnJvciBlcnJv
cjsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX2Vycm9yX2luaXQoJmVycm9yKTsNCj4gPiArDQo+
ID4gKyAgICAgICBpZiAoZGJ1c19zZXRfZXJyb3JfZnJvbV9tZXNzYWdlKCZlcnJvciwgbWVzc2Fn
ZSkgPT0gVFJVRSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkZhaWxlZCB0byB3
cml0ZTogJXNcbiIsIGVycm9yLm5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX2Vycm9y
X2ZyZWUoJmVycm9yKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAg
fQ0KPiA+ICsNCj4gPiArICAgICAgIGlmIChkYXRhID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBzd2l0Y2ggKGRhdGEtPmdhdHRfZGF0YVsw
XSAmIEdBVFRfU0FSX01BU0spIHsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSBHQVRUX1NBUl9G
SVJTVDoNCj4gPiArICAgICAgICAgICAgICAgY2FzZSBHQVRUX1NBUl9DT05USU5VRToNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICB0bXAgPSBnX25ldzAoc3RydWN0IHdyaXRlX2RhdGEsIDEp
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmICghZGF0YSkNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgKnRtcCA9ICpkYXRhOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHRtcC0+
Z2F0dF9kYXRhID0gZ19tYWxsb2MoZGF0YS0+Z2F0dF9sZW4pOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBpZiAoIXRtcC0+Z2F0dF9kYXRhKSB7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBnX2ZyZWUodG1wKTsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHRtcC0+Z2F0dF9kYXRhWzBdID0gZHB0clsw
XTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdG1wOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIG1lbWNweShkYXRhLT5nYXR0X2RhdGEgKyAxLCBkcHRyICsgbWF4X2xl
biwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS0+Z2F0
dF9sZW4gLSBtYXhfc2VnKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBkYXRhLT5nYXR0
X2xlbiAtPSBtYXhfc2VnOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGRhdGEtPmdhdHRf
ZGF0YVswXSAmPSBHQVRUX1RZUEVfTUFTSzsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBk
YXRhLT5pb3YuaW92X2Jhc2UgPSBkYXRhLT5nYXR0X2RhdGE7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgaWYgKG1heF9sZW4gPCBkYXRhLT5nYXR0X2xlbikgew0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgZGF0YS0+aW92Lmlvdl9sZW4gPSBtYXhfbGVuOw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS0+Z2F0dF9kYXRhWzBdIHw9IEdBVFRf
U0FSX0NPTlRJTlVFOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLT5pb3YuaW92X2xlbiA9IGRhdGEt
PmdhdHRfbGVuOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS0+Z2F0
dF9kYXRhWzBdIHw9IEdBVFRfU0FSX0xBU1Q7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
fQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYo
ZGF0YS0+Y2IpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLT5jYiht
ZXNzYWdlLCBkYXRhLT51c2VyX2RhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJl
dHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5
X21ldGhvZF9jYWxsKGRhdGEtPnByb3h5LCAiV3JpdGVWYWx1ZSIsDQo+IHdyaXRlX3NldHVwLA0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd3JpdGVfcmVwbHksIGRhdGEsIHdy
aXRlX2RhdGFfZnJlZSkgPT0gRkFMU0UpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRm
KCJGYWlsZWQgdG8gd3JpdGVcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICB3cml0ZV9kYXRhX2Zy
ZWUoZGF0YSk7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHdyaXRlX2lvX2Rlc3Ryb3kodm9p
ZCkNCj4gPiArew0KPiA+ICsgICAgICAgaW9fZGVzdHJveSh3cml0ZV9pbyk7DQo+ID4gKyAgICAg
ICB3cml0ZV9pbyA9IE5VTEw7DQo+ID4gKyAgICAgICB3cml0ZV9tdHUgPSAwOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBub3RpZnlfaW9fZGVzdHJveSh2b2lkKQ0KPiA+ICt7DQo+
ID4gKyAgICAgICBpb19kZXN0cm95KG5vdGlmeV9pbyk7DQo+ID4gKyAgICAgICBub3RpZnlfaW8g
PSBOVUxMOw0KPiA+ICsgICAgICAgbm90aWZ5X210dSA9IDA7DQo+ID4gK30NCj4gPiArDQo+ID4g
K3N0YXRpYyBib29sIHBpcGVfaHVwKHN0cnVjdCBpbyAqaW8sIHZvaWQgKnVzZXJfZGF0YSkNCj4g
PiArew0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCIlcyBjbG9zZWRcbiIsIGlvID09IG5vdGlmeV9p
byA/ICJOb3RpZnkiIDogIldyaXRlIik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGlvID09IG5v
dGlmeV9pbykNCj4gPiArICAgICAgICAgICAgICAgbm90aWZ5X2lvX2Rlc3Ryb3koKTsNCj4gPiAr
ICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgd3JpdGVfaW9fZGVzdHJveSgpOw0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGlj
IHN0cnVjdCBpbyAqcGlwZV9pb19uZXcoaW50IGZkKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1
Y3QgaW8gKmlvOw0KPiA+ICsNCj4gPiArICAgICAgIGlvID0gaW9fbmV3KGZkKTsNCj4gPiArDQo+
ID4gKyAgICAgICBpb19zZXRfY2xvc2Vfb25fZGVzdHJveShpbywgdHJ1ZSk7DQo+ID4gKw0KPiA+
ICsgICAgICAgaW9fc2V0X2Rpc2Nvbm5lY3RfaGFuZGxlcihpbywgcGlwZV9odXAsIE5VTEwsIE5V
TEwpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBpbzsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
c3RhdGljIHZvaWQgYWNxdWlyZV93cml0ZV9yZXBseShEQnVzTWVzc2FnZSAqbWVzc2FnZSwgdm9p
ZA0KPiAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3Qgd3JpdGVfZGF0YSAq
ZGF0YSA9IHVzZXJfZGF0YTsNCj4gPiArICAgICAgIERCdXNFcnJvciBlcnJvcjsNCj4gPiArICAg
ICAgIGludCBmZDsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX2Vycm9yX2luaXQoJmVycm9yKTsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGJ1c19zZXRfZXJyb3JfZnJvbV9tZXNzYWdlKCZlcnJv
ciwgbWVzc2FnZSkgPT0gVFJVRSkgew0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX2Vycm9yX2Zy
ZWUoJmVycm9yKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGdfZGJ1c19wcm94eV9tZXRob2Rf
Y2FsbChkYXRhLT5wcm94eSwgIldyaXRlVmFsdWUiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgd3JpdGVfc2V0dXAsIHdyaXRlX3JlcGx5LCBkYXRhLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgd3JpdGVfZGF0YV9mcmVlKSA9PSBGQUxTRSkgew0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRmFpbGVkIHRvIHdyaXRlXG4iKTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICB3cml0ZV9kYXRhX2ZyZWUoZGF0YSk7DQo+ID4g
KyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAg
ICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmICgoZGJ1c19tZXNzYWdlX2dldF9hcmdzKG1lc3Nh
Z2UsIE5VTEwsIERCVVNfVFlQRV9VTklYX0ZELA0KPiAmZmQsDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIERCVVNfVFlQRV9VSU5UMTYsICZ3cml0ZV9tdHUsDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERCVVNfVFlQRV9JTlZB
TElEKSA9PSBmYWxzZSkpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJJbnZhbGlk
IEFjcXVpcmVXcml0ZSByZXNwb25zZVxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBybF9wcmludGYoIkFjcXVpcmVXcml0
ZSBzdWNjZXNzOiBmZCAlZCBNVFUgJXVcbiIsIGZkLCB3cml0ZV9tdHUpOw0KPiA+ICsNCj4gPiAr
ICAgICAgIHdyaXRlX2lvID0gcGlwZV9pb19uZXcoZmQpOw0KPiA+ICsNCj4gPiArICAgICAgIHBp
cGVfd3JpdGUod3JpdGVfaW8sIGRhdGEpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG1lc2hf
Z2F0dF93cml0ZShHREJ1c1Byb3h5ICpwcm94eSwgdWludDhfdCAqYnVmLCB1aW50MTZfdCBsZW4s
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgR0RCdXNSZXR1cm5GdW5jdGlvbiBjYiwgdm9p
ZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3Qgd3JpdGVfZGF0YSAqZGF0
YTsNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRlciBpdGVyOw0KPiA+ICsgICAgICAgdWludDhf
dCBtYXhfbGVuOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghYnVmIHx8ICFsZW4pDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAobGVuID4g
NjkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBkYXRhID0gZ19uZXcwKHN0cnVjdCB3cml0ZV9kYXRhLCAxKTsNCj4gPiArICAgICAgIGlmICgh
ZGF0YSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAg
ICAgIG1heF9sZW4gPSB3cml0ZV9tdHUgPyB3cml0ZV9tdHUgLSAzIDogR0FUVF9NVFUgLSAzOw0K
PiA+ICsNCj4gPiArICAgICAgIC8qIFRPRE86IHNob3VsZCBrZWVwIGluIHF1ZXVlIGluIGNhc2Ug
d2UgbmVlZCB0byBjYW5jZWwgd3JpdGU/ICovDQo+ID4gKw0KPiA+ICsgICAgICAgZGF0YS0+Z2F0
dF9sZW4gPSBsZW47DQo+ID4gKyAgICAgICBkYXRhLT5nYXR0X2RhdGEgPSBnX21lbWR1cChidWYs
IGxlbik7DQo+ID4gKyAgICAgICBkYXRhLT5nYXR0X2RhdGFbMF0gJj0gR0FUVF9UWVBFX01BU0s7
DQo+ID4gKyAgICAgICBpZiAobWF4X2xlbiA8IGxlbikgew0KPiA+ICsgICAgICAgICAgICAgICBs
ZW4gPSBtYXhfbGVuOw0KPiA+ICsgICAgICAgICAgICAgICBkYXRhLT5nYXR0X2RhdGFbMF0gfD0g
R0FUVF9TQVJfRklSU1Q7DQo+ID4gKyAgICAgICB9DQo+ID4gKyAgICAgICBkYXRhLT5pb3YuaW92
X2Jhc2UgPSBkYXRhLT5nYXR0X2RhdGE7DQo+ID4gKyAgICAgICBkYXRhLT5pb3YuaW92X2xlbiA9
IGxlbjsNCj4gPiArICAgICAgIGRhdGEtPnByb3h5ID0gcHJveHk7DQo+ID4gKyAgICAgICBkYXRh
LT51c2VyX2RhdGEgPSB1c2VyX2RhdGE7DQo+ID4gKyAgICAgICBkYXRhLT5jYiA9IGNiOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmICh3cml0ZV9pbykNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IHBpcGVfd3JpdGUod3JpdGVfaW8sIGRhdGEpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChnX2Ri
dXNfcHJveHlfZ2V0X3Byb3BlcnR5KHByb3h5LCAiV3JpdGVBY3F1aXJlZCIsICZpdGVyKSkgew0K
PiA+ICsgICAgICAgICAgICAgICBpZiAoZ19kYnVzX3Byb3h5X21ldGhvZF9jYWxsKHByb3h5LCAi
QWNxdWlyZVdyaXRlIiwgTlVMTCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IGFjcXVpcmVfd3JpdGVfcmVwbHksIGRhdGEsIE5VTEwpID09IEZBTFNFKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gQWNxdWlyZVdyaXRlXG4iKTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICB3cml0ZV9kYXRhX2ZyZWUoZGF0YSk7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAgICAgICAg
ICB9DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZ19kYnVz
X3Byb3h5X21ldGhvZF9jYWxsKGRhdGEtPnByb3h5LCAiV3JpdGVWYWx1ZSIsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICB3cml0ZV9zZXR1cCwgd3JpdGVfcmVwbHksIGRhdGEs
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3cml0ZV9kYXRhX2ZyZWUpID09
IEZBTFNFKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQg
dG8gd3JpdGVcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHdyaXRlX2RhdGFfZnJl
ZShkYXRhKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4g
KyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICAgICAgcHJpbnRfYnl0ZV9hcnJheSgi
R0FUVC1UWDogIiwgYnVmLCBsZW4pOw0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkF0
dGVtcHRpbmcgdG8gd3JpdGUgJXNcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgZ19kYnVzX3Byb3h5X2dldF9wYXRoKHByb3h5KSk7DQo+ID4g
KyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyB2b2lkIG5vdGlmeV9yZXBseShEQnVzTWVzc2FnZSAqbWVzc2FnZSwgdm9p
ZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3Qgbm90aWZ5X2RhdGEgKmRh
dGEgPSB1c2VyX2RhdGE7DQo+ID4gKyAgICAgICBEQnVzRXJyb3IgZXJyb3I7DQo+ID4gKw0KPiA+
ICsgICAgICAgZGJ1c19lcnJvcl9pbml0KCZlcnJvcik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYg
KGRidXNfc2V0X2Vycm9yX2Zyb21fbWVzc2FnZSgmZXJyb3IsIG1lc3NhZ2UpID09IFRSVUUpIHsN
Cj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gJXMgbm90aWZ5OiAlc1xu
IiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEtPmVuYWJsZSA/ICJz
dGFydCIgOiAic3RvcCIsIGVycm9yLm5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX2Vy
cm9yX2ZyZWUoJmVycm9yKTsNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsg
ICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50ZigiTm90aWZ5ICVzXG4iLCBkYXRh
LT5lbmFibGUgPyAic3RhcnRlZCIgOiAic3RvcHBlZCIpOw0KPiA+ICsNCj4gPiArZG9uZToNCj4g
PiArICAgICAgIGlmIChkYXRhLT5jYikNCj4gPiArICAgICAgICAgICAgICAgZGF0YS0+Y2IobWVz
c2FnZSwgZGF0YS0+dXNlcl9kYXRhKTsNCj4gPiArDQo+ID4gKyAgICAgICBnX2ZyZWUoZGF0YSk7
DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHBpcGVfcmVhZChzdHJ1Y3QgaW8gKmlv
LCBib29sIHByb3YsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0
IG1lc2hfbm9kZSAqbm9kZSA9IHVzZXJfZGF0YTsNCj4gPiArICAgICAgIHVpbnQ4X3QgYnVmWzUx
Ml07DQo+ID4gKyAgICAgICB1aW50OF90ICpyZXM7DQo+ID4gKyAgICAgICBpbnQgZmQgPSBpb19n
ZXRfZmQoaW8pOw0KPiA+ICsgICAgICAgc3NpemVfdCBsZW47DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKGlvICE9IG5vdGlmeV9pbykNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+
ID4gKw0KPiA+ICsgICAgICAgd2hpbGUgKChsZW4gPSByZWFkKGZkLCBidWYsIHNpemVvZihidWYp
KSkpIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGxlbiA8PSAwKQ0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmVzID0gYnVm
Ow0KPiA+ICsgICAgICAgICAgICAgICBtZXNoX2dhdHRfc2FyKCZyZXMsIGxlbik7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBpZiAocHJvdikNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBwcm92X2RhdGFfcmVhZHkobm9kZSwgcmVzLCBsZW4pOw0KPiA+ICsgICAgICAgICAgICAgICBl
bHNlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbmV0X2RhdGFfcmVhZHkocmVzLCBsZW4p
Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwaXBlX3JlYWRfcHJvdihzdHJ1Y3QgaW8gKmlvLCB2
b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHJldHVybiBwaXBlX3JlYWQoaW8s
IHRydWUsIHVzZXJfZGF0YSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHBpcGVf
cmVhZF9wcm94eShzdHJ1Y3QgaW8gKmlvLCB2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIHJldHVybiBwaXBlX3JlYWQoaW8sIGZhbHNlLCB1c2VyX2RhdGEpOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBhY3F1aXJlX25vdGlmeV9yZXBseShEQnVzTWVzc2FnZSAq
bWVzc2FnZSwgdm9pZA0KPiAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3Qg
bm90aWZ5X2RhdGEgKmRhdGEgPSB1c2VyX2RhdGE7DQo+ID4gKyAgICAgICBEQnVzTWVzc2FnZUl0
ZXIgaXRlcjsNCj4gPiArICAgICAgIERCdXNFcnJvciBlcnJvcjsNCj4gPiArICAgICAgIGludCBm
ZDsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKnV1aWQ7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1
c19lcnJvcl9pbml0KCZlcnJvcik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGRidXNfc2V0X2Vy
cm9yX2Zyb21fbWVzc2FnZSgmZXJyb3IsIG1lc3NhZ2UpID09IFRSVUUpIHsNCj4gPiArICAgICAg
ICAgICAgICAgZGJ1c19lcnJvcl9mcmVlKCZlcnJvcik7DQo+ID4gKyAgICAgICAgICAgICAgIGlm
IChnX2RidXNfcHJveHlfbWV0aG9kX2NhbGwoZGF0YS0+cHJveHksICJTdGFydE5vdGlmeSIsIE5V
TEwsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vdGlmeV9y
ZXBseSwgZGF0YSwgTlVMTCkgPT0gRkFMU0UpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBybF9wcmludGYoIkZhaWxlZCB0byBTdGFydE5vdGlmeVxuIik7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgZ19mcmVlKGRhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBp
ZiAobm90aWZ5X2lvKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlvX2Rlc3Ryb3kobm90aWZ5X2lv
KTsNCj4gPiArICAgICAgICAgICAgICAgbm90aWZ5X2lvID0gTlVMTDsNCj4gPiArICAgICAgIH0N
Cj4gPiArDQo+ID4gKyAgICAgICBub3RpZnlfbXR1ID0gMDsNCj4gPiArDQo+ID4gKyAgICAgICBp
ZiAoKGRidXNfbWVzc2FnZV9nZXRfYXJncyhtZXNzYWdlLCBOVUxMLCBEQlVTX1RZUEVfVU5JWF9G
RCwNCj4gJmZkLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBE
QlVTX1RZUEVfVUlOVDE2LCAmbm90aWZ5X210dSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgREJVU19UWVBFX0lOVkFMSUQpID09IGZhbHNlKSkgew0KPiA+ICsg
ICAgICAgICAgICAgICBpZiAoZ19kYnVzX3Byb3h5X21ldGhvZF9jYWxsKGRhdGEtPnByb3h5LCAi
U3RhcnROb3RpZnkiLCBOVUxMLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBub3RpZnlfcmVwbHksIGRhdGEsIE5VTEwpID09IEZBTFNFKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gU3RhcnROb3RpZnlcbiIpOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdfZnJlZShkYXRhKTsNCj4gPiArICAgICAgICAg
ICAgICAgfQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCJBY3F1aXJlTm90aWZ5IHN1Y2Nlc3M6IGZkICVkIE1U
VSAldVxuIiwgZmQsIG5vdGlmeV9tdHUpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChnX2RidXNf
cHJveHlfZ2V0X3Byb3BlcnR5KGRhdGEtPnByb3h5LCAiVVVJRCIsICZpdGVyKSA9PQ0KPiBGQUxT
RSkNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsNCj4gPiArICAgICAgIG5v
dGlmeV9pbyA9IHBpcGVfaW9fbmV3KGZkKTsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX21lc3Nh
Z2VfaXRlcl9nZXRfYmFzaWMoJml0ZXIsICZ1dWlkKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
IWJ0X3V1aWRfc3RyY21wKHV1aWQsIE1FU0hfUFJPVl9EQVRBX09VVF9VVUlEX1NUUikpDQo+ID4g
KyAgICAgICAgICAgICAgIGlvX3NldF9yZWFkX2hhbmRsZXIobm90aWZ5X2lvLCBwaXBlX3JlYWRf
cHJvdiwgZGF0YS0NCj4gPnVzZXJfZGF0YSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOVUxMKTsNCj4g
PiArICAgICAgIGVsc2UgaWYgKCFidF91dWlkX3N0cmNtcCh1dWlkLCBNRVNIX1BST1hZX0RBVEFf
T1VUX1VVSURfU1RSKSkNCj4gPiArICAgICAgICAgICAgICAgaW9fc2V0X3JlYWRfaGFuZGxlcihu
b3RpZnlfaW8sIHBpcGVfcmVhZF9wcm94eSwgZGF0YS0NCj4gPnVzZXJfZGF0YSwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBOVUxMKTsNCj4gPiArDQo+ID4gK2RvbmU6DQo+ID4gKyAgICAgICBpZiAoZGF0
YS0+Y2IpDQo+ID4gKyAgICAgICAgICAgICAgIGRhdGEtPmNiKG1lc3NhZ2UsIGRhdGEtPnVzZXJf
ZGF0YSk7DQo+ID4gKw0KPiA+ICsgICAgICAgZ19mcmVlKGRhdGEpOw0KPiA+ICt9DQo+ID4gKw0K
PiA+ICtib29sIG1lc2hfZ2F0dF9ub3RpZnkoR0RCdXNQcm94eSAqcHJveHksIGJvb2wgZW5hYmxl
LA0KPiBHREJ1c1JldHVybkZ1bmN0aW9uIGNiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG5vdGlmeV9kYXRh
ICpkYXRhOw0KPiA+ICsgICAgICAgREJ1c01lc3NhZ2VJdGVyIGl0ZXI7DQo+ID4gKyAgICAgICBj
b25zdCBjaGFyICptZXRob2Q7DQo+ID4gKw0KPiA+ICsgICAgICAgZGF0YSA9IGdfbmV3MChzdHJ1
Y3Qgbm90aWZ5X2RhdGEsIDEpOw0KPiA+ICsgICAgICAgZGF0YS0+cHJveHkgPSBwcm94eTsNCj4g
PiArICAgICAgIGRhdGEtPmVuYWJsZSA9IGVuYWJsZTsNCj4gPiArICAgICAgIGRhdGEtPmNiID0g
Y2I7DQo+ID4gKyAgICAgICBkYXRhLT51c2VyX2RhdGEgPSB1c2VyX2RhdGE7DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKGVuYWJsZSA9PSBUUlVFKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChn
X2RidXNfcHJveHlfZ2V0X3Byb3BlcnR5KHByb3h5LCAiTm90aWZ5QWNxdWlyZWQiLCAmaXRlcikp
IHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiQWNxdWlyZU5vdGlmeSI7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgY2IgPSBhY3F1aXJlX25vdGlmeV9yZXBseTsN
Cj4gPiArICAgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBtZXRob2QgPSAiU3RhcnROb3RpZnkiOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGNi
ID0gbm90aWZ5X3JlcGx5Ow0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKyAgICAgICB9IGVs
c2Ugew0KPiA+ICsgICAgICAgICAgICAgICBpZiAobm90aWZ5X2lvKSB7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgbm90aWZ5X2lvX2Rlc3Ryb3koKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBpZiAoY2IpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYihO
VUxMLCB1c2VyX2RhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVl
Ow0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIG1ldGhvZCA9ICJTdG9wTm90aWZ5IjsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBj
YiA9IG5vdGlmeV9yZXBseTsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgfQ0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChnX2RidXNfcHJveHlfbWV0aG9kX2NhbGwocHJveHksIG1l
dGhvZCwgTlVMTCwgY2IsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIGRhdGEsIE5VTEwpID09IEZBTFNFKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50
ZigiRmFpbGVkIHRvICVzXG4iLCBtZXRob2QpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4g
ZmFsc2U7DQo+ID4gKyAgICAgICB9DQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0K
PiA+IGRpZmYgLS1naXQgYS9tZXNoL21haW4uYyBiL21lc2gvbWFpbi5jDQo+ID4gbmV3IGZpbGUg
bW9kZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi5hMzQ3NDg0DQo+ID4gLS0tIC9kZXYvbnVs
bA0KPiA+ICsrKyBiL21lc2gvbWFpbi5jDQo+ID4gQEAgLTAsMCArMSwyMjY5IEBADQo+ID4gKy8q
DQo+ID4gKyAqDQo+ID4gKyAqICBCbHVlWiAtIEJsdWV0b290aCBwcm90b2NvbCBzdGFjayBmb3Ig
TGludXgNCj4gPiArICoNCj4gPiArICogIENvcHlyaWdodCAoQykgMjAxNyAgSW50ZWwgQ29ycG9y
YXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQo+ID4gKyAqDQo+ID4gKyAqDQo+ID4gKyAqICBU
aGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5k
L29yDQo+ID4gKyAqICBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2Vy
IEdlbmVyYWwgUHVibGljDQo+ID4gKyAqICBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJl
ZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXINCj4gPiArICogIHZlcnNpb24gMi4xIG9mIHRo
ZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLg0KPiA+ICsg
Kg0KPiA+ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQg
aXQgd2lsbCBiZSB1c2VmdWwsDQo+ID4gKyAqICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdp
dGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZg0KPiA+ICsgKiAgTUVSQ0hBTlRBQklM
SVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQ0KPiBHTlUN
Cj4gPiArICogIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMu
DQo+ID4gKyAqDQo+ID4gKyAqICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRo
ZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljDQo+ID4gKyAqICBMaWNlbnNlIGFsb25nIHdpdGgg
dGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlDQo+ID4gKyAq
ICBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdCwgRmlmdGggRmxvb3IsIEJvc3Rvbiwg
TUEgIDAyMTEwLTEzMDENCj4gVVNBDQo+ID4gKyAqDQo+ID4gKyAqLw0KPiA+ICsNCj4gPiArI2lm
ZGVmIEhBVkVfQ09ORklHX0gNCj4gPiArI2luY2x1ZGUgPGNvbmZpZy5oPg0KPiA+ICsjZW5kaWYN
Cj4gPiArDQo+ID4gKyNpbmNsdWRlIDxzdGRpby5oPg0KPiA+ICsjaW5jbHVkZSA8ZXJybm8uaD4N
Cj4gPiArI2luY2x1ZGUgPHVuaXN0ZC5oPg0KPiA+ICsjaW5jbHVkZSA8c3RkbGliLmg+DQo+ID4g
KyNpbmNsdWRlIDxzdGRib29sLmg+DQo+ID4gKyNpbmNsdWRlIDxzaWduYWwuaD4NCj4gPiArI2lu
Y2x1ZGUgPHN5cy9zaWduYWxmZC5oPg0KPiA+ICsjaW5jbHVkZSA8d29yZGV4cC5oPg0KPiA+ICsN
Cj4gPiArI2luY2x1ZGUgPGludHR5cGVzLmg+DQo+ID4gKyNpbmNsdWRlIDxjdHlwZS5oPg0KPiA+
ICsjaW5jbHVkZSA8c3lzL2ZpbGUuaD4NCj4gPiArI2luY2x1ZGUgPHN5cy9pb2N0bC5oPg0KPiA+
ICsjaW5jbHVkZSA8c3lzL3N0YXQuaD4NCj4gPiArI2luY2x1ZGUgImJsdWV0b290aC9ibHVldG9v
dGguaCINCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxyZWFkbGluZS9yZWFkbGluZS5oPg0KPiA+ICsj
aW5jbHVkZSA8cmVhZGxpbmUvaGlzdG9yeS5oPg0KPiA+ICsjaW5jbHVkZSA8Z2xpYi5oPg0KPiA+
ICsNCj4gPiArI2luY2x1ZGUgImxpYi9ibHVldG9vdGguaCINCj4gPiArI2luY2x1ZGUgImxpYi91
dWlkLmgiDQo+ID4gKyNpbmNsdWRlICJzcmMvc2hhcmVkL3V0aWwuaCINCj4gPiArI2luY2x1ZGUg
ImdkYnVzL2dkYnVzLmgiDQo+ID4gKyNpbmNsdWRlICJtb25pdG9yL3V1aWQuaCINCj4gPiArI2lu
Y2x1ZGUgImNsaWVudC9kaXNwbGF5LmgiDQo+ID4gKyNpbmNsdWRlICJtZXNoLW5ldC5oIg0KPiA+
ICsjaW5jbHVkZSAiZ2F0dC5oIg0KPiA+ICsjaW5jbHVkZSAiY3J5cHRvLmgiDQo+ID4gKyNpbmNs
dWRlICJub2RlLmgiDQo+ID4gKyNpbmNsdWRlICJuZXQuaCINCj4gPiArI2luY2x1ZGUgImtleXMu
aCINCj4gPiArI2luY2x1ZGUgInByb3YuaCINCj4gPiArI2luY2x1ZGUgInV0aWwuaCINCj4gPiAr
I2luY2x1ZGUgImFnZW50LmgiDQo+ID4gKyNpbmNsdWRlICJwcm92LWRiLmgiDQo+ID4gKyNpbmNs
dWRlICJjb25maWctbW9kZWwuaCINCj4gPiArI2luY2x1ZGUgIm9ub2ZmLW1vZGVsLmgiDQo+ID4g
Kw0KPiA+ICsvKiBTdHJpbmcgZGlzcGxheSBjb25zdGFudHMgKi8NCj4gPiArI2RlZmluZSBDT0xP
UkVEX05FVyAgICBDT0xPUl9HUkVFTiAiTkVXIiBDT0xPUl9PRkYNCj4gPiArI2RlZmluZSBDT0xP
UkVEX0NIRyAgICBDT0xPUl9ZRUxMT1cgIkNIRyIgQ09MT1JfT0ZGDQo+ID4gKyNkZWZpbmUgQ09M
T1JFRF9ERUwgICAgQ09MT1JfUkVEICJERUwiIENPTE9SX09GRg0KPiA+ICsNCj4gPiArI2RlZmlu
ZSBQUk9NUFRfT04gICAgICBDT0xPUl9CTFVFICJbbWVzaGN0bF0iIENPTE9SX09GRiAiIyAiDQo+
ID4gKyNkZWZpbmUgUFJPTVBUX09GRiAgICAgIldhaXRpbmcgdG8gY29ubmVjdCB0byBibHVldG9v
dGhkLi4uIg0KPiA+ICsNCj4gPiArI2RlZmluZSBNRVNIX1BST1ZfREFUQV9JTl9VVUlEX1NUUiAg
ICAgIjAwMDAyYWRiLTAwMDAtMTAwMC04MDAwLQ0KPiAwMDgwNWY5YjM0ZmIiDQo+ID4gKyNkZWZp
bmUgTUVTSF9QUk9WX0RBVEFfT1VUX1VVSURfU1RSICAgICIwMDAwMmFkYy0wMDAwLTEwMDAtDQo+
IDgwMDAtMDA4MDVmOWIzNGZiIg0KPiA+ICsjZGVmaW5lIE1FU0hfUFJPWFlfREFUQV9JTl9VVUlE
X1NUUiAgICAiMDAwMDJhZGQtMDAwMC0xMDAwLTgwMDAtDQo+IDAwODA1ZjliMzRmYiINCj4gPiAr
I2RlZmluZSBNRVNIX1BST1hZX0RBVEFfT1VUX1VVSURfU1RSICAgIjAwMDAyYWRlLTAwMDAtMTAw
MC0NCj4gODAwMC0wMDgwNWY5YjM0ZmIiDQo+ID4gKw0KPiA+ICtzdGF0aWMgR01haW5Mb29wICpt
YWluX2xvb3A7DQo+ID4gK3N0YXRpYyBEQnVzQ29ubmVjdGlvbiAqZGJ1c19jb25uOw0KPiA+ICsN
Cj4gPiArc3RydWN0IGFkYXB0ZXIgew0KPiA+ICtHREJ1c1Byb3h5ICpwcm94eTsNCj4gPiArICAg
ICAgIEdMaXN0ICptZXNoX2RldmljZXM7DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdHJ1Y3QgbWVz
aF9kZXZpY2Ugew0KPiA+ICsgICAgICAgR0RCdXNQcm94eSAqcHJveHk7DQo+ID4gKyAgICAgICB1
aW50OF90IGRldl91dWlkWzE2XTsNCj4gPiArICAgICAgIGdib29sZWFuIGhpZGU7DQo+ID4gK307
DQo+ID4gKw0KPiA+ICtHTGlzdCAqc2VydmljZV9saXN0Ow0KPiA+ICtHTGlzdCAqY2hhcl9saXN0
Ow0KPiA+ICsNCj4gPiArc3RhdGljIEdMaXN0ICpjdHJsX2xpc3Q7DQo+ID4gK3N0YXRpYyBzdHJ1
Y3QgYWRhcHRlciAqZGVmYXVsdF9jdHJsOw0KPiA+ICsNCj4gPiArc3RhdGljIGNoYXIgKm1lc2hf
cHJvdl9kYl9maWxlbmFtZTsNCj4gPiArc3RhdGljIGNoYXIgKm1lc2hfbG9jYWxfY29uZmlnX2Zp
bGVuYW1lOw0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgZGlzY292ZXJpbmcgPSBmYWxzZTsNCj4g
PiArc3RhdGljIGJvb2wgZGlzY292ZXJfbWVzaDsNCj4gPiArc3RhdGljIHVpbnQxNl90IHByb3Zf
bmV0X2tleV9pbmRleCA9IE5FVF9JRFhfUFJJTUFSWTsNCj4gPiArDQo+ID4gK3N0YXRpYyBndWlu
dCBpbnB1dCA9IDA7DQo+ID4gKw0KPiA+ICsjZGVmaW5lIENPTk5fVFlQRV9ORVRXT1JLICAgICAg
MHgwMA0KPiA+ICsjZGVmaW5lIENPTk5fVFlQRV9JREVOVElUWSAgICAgMHgwMQ0KPiA+ICsjZGVm
aW5lIENPTk5fVFlQRV9QUk9WSVNJT04gICAgMHgwMg0KPiA+ICsjZGVmaW5lIENPTk5fVFlQRV9J
TlZBTElEICAgICAgMHhmZg0KPiA+ICsNCj4gPiArI2RlZmluZSBORVRfSURYX0lOVkFMSUQgICAg
ICAgICAgICAgICAgMHhmZmZmDQo+ID4gKw0KPiA+ICtzdHJ1Y3Qgew0KPiA+ICsgICAgICAgR0RC
dXNQcm94eSAqZGV2aWNlOw0KPiA+ICsgICAgICAgR0RCdXNQcm94eSAqc2VydmljZTsNCj4gPiAr
ICAgICAgIEdEQnVzUHJveHkgKmRhdGFfaW47DQo+ID4gKyAgICAgICBHREJ1c1Byb3h5ICpkYXRh
X291dDsNCj4gPiArICAgICAgIGJvb2wgc2Vzc2lvbl9vcGVuOw0KPiA+ICsgICAgICAgdWludDE2
X3QgdW5pY2FzdDsNCj4gPiArICAgICAgIHVpbnQxNl90IG5ldF9pZHg7DQo+ID4gKyAgICAgICB1
aW50OF90IGRldl91dWlkWzE2XTsNCj4gPiArICAgICAgIHVpbnQ4X3QgdHlwZTsNCj4gPiArfSBj
b25uZWN0aW9uOw0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgc2VydmljZV9pc19tZXNoKEdEQnVz
UHJveHkgKnByb3h5LCBjb25zdCBjaGFyICp0YXJnZXRfdXVpZCkNCj4gPiArew0KPiA+ICsgICAg
ICAgREJ1c01lc3NhZ2VJdGVyIGl0ZXI7DQo+ID4gKyAgICAgICBjb25zdCBjaGFyICp1dWlkOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChnX2RidXNfcHJveHlfZ2V0X3Byb3BlcnR5KHByb3h5LCAi
VVVJRCIsICZpdGVyKSA9PSBGQUxTRSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNl
Ow0KPiA+ICsNCj4gPiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dldF9iYXNpYygmaXRlciwg
JnV1aWQpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICh0YXJnZXRfdXVpZCkNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuICghYnRfdXVpZF9zdHJjbXAodXVpZCwgdGFyZ2V0X3V1aWQpKTsNCj4g
PiArICAgICAgIGVsc2UgaWYgKGJ0X3V1aWRfc3RyY21wKHV1aWQsIE1FU0hfUFJPVl9TVkNfVVVJ
RCkgfHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ0X3V1aWRfc3RyY21w
KHV1aWQsIE1FU0hfUFJPWFlfU1ZDX1VVSUQpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4g
dHJ1ZTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNl
Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBjaGFyX2lzX21lc2goR0RCdXNQcm94
eSAqcHJveHksIGNvbnN0IGNoYXIgKnRhcmdldF91dWlkKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBE
QnVzTWVzc2FnZUl0ZXIgaXRlcjsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKnV1aWQ7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKGdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkocHJveHksICJVVUlE
IiwgJml0ZXIpID09IEZBTFNFKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+
ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2ljKCZpdGVyLCAmdXVp
ZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHRhcmdldF91dWlkKQ0KPiA+ICsgICAgICAgICAg
ICAgICByZXR1cm4gKCFidF91dWlkX3N0cmNtcCh1dWlkLCB0YXJnZXRfdXVpZCkpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmICghYnRfdXVpZF9zdHJjbXAodXVpZCwgTUVTSF9QUk9WX0RBVEFfSU5f
VVVJRF9TVFIpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoIWJ0X3V1aWRfc3RyY21wKHV1aWQsIE1FU0hfUFJPVl9EQVRBX09VVF9VVUlE
X1NUUikpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsNCj4gPiArICAg
ICAgIGlmICghYnRfdXVpZF9zdHJjbXAodXVpZCwgTUVTSF9QUk9YWV9EQVRBX0lOX1VVSURfU1RS
KSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKCFidF91dWlkX3N0cmNtcCh1dWlkLCBNRVNIX1BST1hZX0RBVEFfT1VUX1VVSURfU1RSKSkN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0
dXJuIGZhbHNlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgZ2Jvb2xlYW4gY2hlY2tfZGVm
YXVsdF9jdHJsKHZvaWQpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmICghZGVmYXVsdF9jdHJsKSB7
DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiTm8gZGVmYXVsdCBjb250cm9sbGVyIGF2
YWlsYWJsZVxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBGQUxTRTsNCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gVFJVRTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArc3RhdGljIHZvaWQgcHJveHlfbGVhayhncG9pbnRlciBkYXRhKQ0KPiA+ICt7DQo+ID4gKyAg
ICAgICBybF9wcmludGYoIkxlYWtpbmcgcHJveHkgJXBcbiIsIGRhdGEpOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgZ2Jvb2xlYW4gaW5wdXRfaGFuZGxlcihHSU9DaGFubmVsICpjaGFubmVs
LCBHSU9Db25kaXRpb24NCj4gY29uZGl0aW9uLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3BvaW50ZXIgdXNlcl9kYXRhKQ0KPiA+
ICt7DQo+ID4gKyAgICAgICBpZiAoY29uZGl0aW9uICYgR19JT19JTikgew0KPiA+ICsgICAgICAg
ICAgICAgICBybF9jYWxsYmFja19yZWFkX2NoYXIoKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuIFRSVUU7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGNvbmRpdGlv
biAmIChHX0lPX0hVUCB8IEdfSU9fRVJSIHwgR19JT19OVkFMKSkgew0KPiA+ICsgICAgICAgICAg
ICAgICBnX21haW5fbG9vcF9xdWl0KG1haW5fbG9vcCk7DQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBGQUxTRTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gVFJV
RTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGd1aW50IHNldHVwX3N0YW5kYXJkX2lucHV0
KHZvaWQpDQo+ID4gK3sNCj4gPiArICAgICAgIEdJT0NoYW5uZWwgKmNoYW5uZWw7DQo+ID4gKyAg
ICAgICBndWludCBzb3VyY2U7DQo+ID4gKw0KPiA+ICsgICAgICAgY2hhbm5lbCA9IGdfaW9fY2hh
bm5lbF91bml4X25ldyhmaWxlbm8oc3RkaW4pKTsNCj4gPiArDQo+ID4gKyAgICAgICBzb3VyY2Ug
PSBnX2lvX2FkZF93YXRjaChjaGFubmVsLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgR19JT19JTiB8IEdfSU9fSFVQIHwgR19JT19FUlIgfCBHX0lPX05WQUwsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dF9oYW5kbGVyLCBOVUxMKTsNCj4gPiAr
DQo+ID4gKyAgICAgICBnX2lvX2NoYW5uZWxfdW5yZWYoY2hhbm5lbCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgcmV0dXJuIHNvdXJjZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY29u
bmVjdF9oYW5kbGVyKERCdXNDb25uZWN0aW9uICpjb25uZWN0aW9uLCB2b2lkDQo+ICp1c2VyX2Rh
dGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHJsX3NldF9wcm9tcHQoUFJPTVBUX09OKTsNCj4gPiAr
ICAgICAgIHJsX3ByaW50ZigiXHIiKTsNCj4gPiArICAgICAgIHJsX29uX25ld19saW5lKCk7DQo+
ID4gKyAgICAgICBybF9yZWRpc3BsYXkoKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZv
aWQgZGlzY29ubmVjdF9oYW5kbGVyKERCdXNDb25uZWN0aW9uICpjb25uZWN0aW9uLCB2b2lkDQo+
ICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmIChpbnB1dCA+IDApIHsNCj4gPiAr
ICAgICAgICAgICAgICAgZ19zb3VyY2VfcmVtb3ZlKGlucHV0KTsNCj4gPiArICAgICAgICAgICAg
ICAgaW5wdXQgPSAwOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJsX3NldF9w
cm9tcHQoUFJPTVBUX09GRik7DQo+ID4gKyAgICAgICBybF9wcmludGYoIlxyIik7DQo+ID4gKyAg
ICAgICBybF9vbl9uZXdfbGluZSgpOw0KPiA+ICsgICAgICAgcmxfcmVkaXNwbGF5KCk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgZ19saXN0X2ZyZWVfZnVsbChjdHJsX2xpc3QsIHByb3h5X2xlYWspOw0K
PiA+ICsgICAgICAgY3RybF9saXN0ID0gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICBkZWZhdWx0
X2N0cmwgPSBOVUxMOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBwcmludF9hZGFw
dGVyKEdEQnVzUHJveHkgKnByb3h5LCBjb25zdCBjaGFyICpkZXNjcmlwdGlvbikNCj4gPiArew0K
PiA+ICsgICAgICAgREJ1c01lc3NhZ2VJdGVyIGl0ZXI7DQo+ID4gKyAgICAgICBjb25zdCBjaGFy
ICphZGRyZXNzLCAqbmFtZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5X2dl
dF9wcm9wZXJ0eShwcm94eSwgIkFkZHJlc3MiLCAmaXRlcikgPT0gRkFMU0UpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9n
ZXRfYmFzaWMoJml0ZXIsICZhZGRyZXNzKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVz
X3Byb3h5X2dldF9wcm9wZXJ0eShwcm94eSwgIkFsaWFzIiwgJml0ZXIpID09IFRSVUUpDQo+ID4g
KyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dldF9iYXNpYygmaXRlciwgJm5hbWUp
Ow0KPiA+ICsgICAgICAgZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICBuYW1lID0gIjx1bmtub3du
PiI7DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCIlcyVzJXNDb250cm9sbGVyICVzICVz
ICVzXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24g
PyAiWyIgOiAiIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0
aW9uID8gOiAiIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0
aW9uID8gIl0gIiA6ICIiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRk
cmVzcywgbmFtZSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHRf
Y3RybCAmJg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdF9jdHJs
LT5wcm94eSA9PSBwcm94eSA/DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAi
W2RlZmF1bHRdIiA6ICIiKTsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lk
IHByaW50X2RldmljZShHREJ1c1Byb3h5ICpwcm94eSwgY29uc3QgY2hhciAqZGVzY3JpcHRpb24p
DQo+ID4gK3sNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRlciBpdGVyOw0KPiA+ICsgICAgICAg
Y29uc3QgY2hhciAqYWRkcmVzcywgKm5hbWU7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGdfZGJ1
c19wcm94eV9nZXRfcHJvcGVydHkocHJveHksICJBZGRyZXNzIiwgJml0ZXIpID09IEZBTFNFKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNz
YWdlX2l0ZXJfZ2V0X2Jhc2ljKCZpdGVyLCAmYWRkcmVzcyk7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKGdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkocHJveHksICJBbGlhcyIsICZpdGVyKSA9PSBU
UlVFKQ0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9nZXRfYmFzaWMoJml0
ZXIsICZuYW1lKTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgbmFtZSA9
ICI8dW5rbm93bj4iOw0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50ZigiJXMlcyVzRGV2aWNl
ICVzICVzXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRp
b24gPyAiWyIgOiAiIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2Ny
aXB0aW9uID8gOiAiIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2Ny
aXB0aW9uID8gIl0gIiA6ICIiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
YWRkcmVzcywgbmFtZSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHByaW50X2l0
ZXIoY29uc3QgY2hhciAqbGFiZWwsIGNvbnN0IGNoYXIgKm5hbWUsDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgREJ1c01lc3NhZ2VJdGVyICppdGVy
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBkYnVzX2Jvb2xfdCB2YWxib29sOw0KPiA+ICsgICAgICAg
ZGJ1c191aW50MzJfdCB2YWx1MzI7DQo+ID4gKyAgICAgICBkYnVzX3VpbnQxNl90IHZhbHUxNjsN
Cj4gPiArICAgICAgIGRidXNfaW50MTZfdCB2YWxzMTY7DQo+ID4gKyAgICAgICB1bnNpZ25lZCBj
aGFyIGJ5dGU7DQo+ID4gKyAgICAgICBjb25zdCBjaGFyICp2YWxzdHI7DQo+ID4gKyAgICAgICBE
QnVzTWVzc2FnZUl0ZXIgc3ViaXRlcjsNCj4gPiArICAgICAgIGNoYXIgKmVudHJ5Ow0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChpdGVyID09IE5VTEwpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxf
cHJpbnRmKCIlcyVzIGlzIG5pbFxuIiwgbGFiZWwsIG5hbWUpOw0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgc3dpdGNoIChkYnVz
X21lc3NhZ2VfaXRlcl9nZXRfYXJnX3R5cGUoaXRlcikpIHsNCj4gPiArICAgICAgIGNhc2UgREJV
U19UWVBFX0lOVkFMSUQ6DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiJXMlcyBpcyBp
bnZhbGlkXG4iLCBsYWJlbCwgbmFtZSk7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+
ICsgICAgICAgY2FzZSBEQlVTX1RZUEVfU1RSSU5HOg0KPiA+ICsgICAgICAgY2FzZSBEQlVTX1RZ
UEVfT0JKRUNUX1BBVEg6DQo+ID4gKyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dl
dF9iYXNpYyhpdGVyLCAmdmFsc3RyKTsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCIl
cyVzOiAlc1xuIiwgbGFiZWwsIG5hbWUsIHZhbHN0cik7DQo+ID4gKyAgICAgICAgICAgICAgIGJy
ZWFrOw0KPiA+ICsgICAgICAgY2FzZSBEQlVTX1RZUEVfQk9PTEVBTjoNCj4gPiArICAgICAgICAg
ICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2ljKGl0ZXIsICZ2YWxib29sKTsNCj4gPiAr
ICAgICAgICAgICAgICAgcmxfcHJpbnRmKCIlcyVzOiAlc1xuIiwgbGFiZWwsIG5hbWUsDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbGJvb2wgPT0gVFJVRSA/
ICJ5ZXMiIDogIm5vIik7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAg
Y2FzZSBEQlVTX1RZUEVfVUlOVDMyOg0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2Vf
aXRlcl9nZXRfYmFzaWMoaXRlciwgJnZhbHUzMik7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3By
aW50ZigiJXMlczogMHglMDZ4XG4iLCBsYWJlbCwgbmFtZSwgdmFsdTMyKTsNCj4gPiArICAgICAg
ICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICBjYXNlIERCVVNfVFlQRV9VSU5UMTY6DQo+ID4g
KyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dldF9iYXNpYyhpdGVyLCAmdmFsdTE2
KTsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCIlcyVzOiAweCUwNHhcbiIsIGxhYmVs
LCBuYW1lLCB2YWx1MTYpOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAg
IGNhc2UgREJVU19UWVBFX0lOVDE2Og0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2Vf
aXRlcl9nZXRfYmFzaWMoaXRlciwgJnZhbHMxNik7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3By
aW50ZigiJXMlczogJWRcbiIsIGxhYmVsLCBuYW1lLCB2YWxzMTYpOw0KPiA+ICsgICAgICAgICAg
ICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgREJVU19UWVBFX0JZVEU6DQo+ID4gKyAgICAg
ICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dldF9iYXNpYyhpdGVyLCAmYnl0ZSk7DQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiJXMlczogMHglMDJ4XG4iLCBsYWJlbCwgbmFtZSwg
Ynl0ZSk7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgY2FzZSBEQlVT
X1RZUEVfVkFSSUFOVDoNCj4gPiArICAgICAgICAgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfcmVj
dXJzZShpdGVyLCAmc3ViaXRlcik7DQo+ID4gKyAgICAgICAgICAgICAgIHByaW50X2l0ZXIobGFi
ZWwsIG5hbWUsICZzdWJpdGVyKTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAg
ICAgICBjYXNlIERCVVNfVFlQRV9BUlJBWToNCj4gPiArICAgICAgICAgICAgICAgZGJ1c19tZXNz
YWdlX2l0ZXJfcmVjdXJzZShpdGVyLCAmc3ViaXRlcik7DQo+ID4gKyAgICAgICAgICAgICAgIHdo
aWxlIChkYnVzX21lc3NhZ2VfaXRlcl9nZXRfYXJnX3R5cGUoJnN1Yml0ZXIpICE9DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEQlVT
X1RZUEVfSU5WQUxJRCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHByaW50X2l0ZXIo
bGFiZWwsIG5hbWUsICZzdWJpdGVyKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBkYnVz
X21lc3NhZ2VfaXRlcl9uZXh0KCZzdWJpdGVyKTsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+
ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgREJVU19UWVBFX0RJQ1Rf
RU5UUlk6DQo+ID4gKyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX3JlY3Vyc2UoaXRl
ciwgJnN1Yml0ZXIpOw0KPiA+ICsgICAgICAgICAgICAgICBlbnRyeSA9IGdfc3RyY29uY2F0KG5h
bWUsICJLZXkiLCBOVUxMKTsNCj4gPiArICAgICAgICAgICAgICAgcHJpbnRfaXRlcihsYWJlbCwg
ZW50cnksICZzdWJpdGVyKTsNCj4gPiArICAgICAgICAgICAgICAgZ19mcmVlKGVudHJ5KTsNCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIGVudHJ5ID0gZ19zdHJjb25jYXQobmFtZSwgIiBWYWx1
ZSIsIE5VTEwpOw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9uZXh0KCZz
dWJpdGVyKTsNCj4gPiArICAgICAgICAgICAgICAgcHJpbnRfaXRlcihsYWJlbCwgZW50cnksICZz
dWJpdGVyKTsNCj4gPiArICAgICAgICAgICAgICAgZ19mcmVlKGVudHJ5KTsNCj4gPiArICAgICAg
ICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICBkZWZhdWx0Og0KPiA+ICsgICAgICAgICAgICAg
ICBybF9wcmludGYoIiVzJXMgaGFzIHVuc3VwcG9ydGVkIHR5cGVcbiIsIGxhYmVsLCBuYW1lKTsN
Cj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyB2b2lkIHByaW50X3Byb3BlcnR5KEdEQnVzUHJveHkgKnByb3h5LCBjb25z
dCBjaGFyICpuYW1lKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBEQnVzTWVzc2FnZUl0ZXIgaXRlcjsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5X2dldF9wcm9wZXJ0eShwcm94eSwg
bmFtZSwgJml0ZXIpID09IEZBTFNFKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4g
Kw0KPiA+ICsgICAgICAgcHJpbnRfaXRlcigiXHQiLCBuYW1lLCAmaXRlcik7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3N0YXRpYyB2b2lkIGZvcmdldF9tZXNoX2RldmljZXMoKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICBnX2xpc3RfZnJlZV9mdWxsKGRlZmF1bHRfY3RybC0+bWVzaF9kZXZpY2VzLCBnX2Zy
ZWUpOw0KPiA+ICsgICAgICAgZGVmYXVsdF9jdHJsLT5tZXNoX2RldmljZXMgPSBOVUxMOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lc2hfZGV2aWNlICpmaW5kX2RldmljZV9i
eV91dWlkKEdMaXN0ICpzb3VyY2UsIHVpbnQ4X3QNCj4gdXVpZFsxNl0pDQo+ID4gK3sNCj4gPiAr
ICAgICAgIEdMaXN0ICpsaXN0Ow0KPiA+ICsNCj4gPiArICAgICAgIGZvciAobGlzdCA9IGdfbGlz
dF9maXJzdChzb3VyY2UpOyBsaXN0OyBsaXN0ID0gZ19saXN0X25leHQobGlzdCkpIHsNCj4gPiAr
ICAgICAgICAgICAgICAgc3RydWN0IG1lc2hfZGV2aWNlICpkZXYgPSBsaXN0LT5kYXRhOw0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFtZW1jbXAoZGV2LT5kZXZfdXVpZCwgdXVpZCwg
MTYpKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBkZXY7DQo+ID4gKyAgICAg
ICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gK30NCj4gPiArDQo+ID4g
K3N0YXRpYyB2b2lkIHByaW50X3Byb3Zfc2VydmljZShzdHJ1Y3QgcHJvdl9zdmNfZGF0YSAqcHJv
dl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjb25zdCBjaGFyICpwcmVmaXggPSAiXHRcdCI7
DQo+ID4gKyAgICAgICBjaGFyIHR4dF91dWlkWzE2ICogMiArIDFdOw0KPiA+ICsgICAgICAgaW50
IGk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCIlc01lc2ggUHJvdmlzaW9uaW5nIFNl
cnZpY2UgKCVzKVxuIiwgcHJlZml4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgTUVTSF9QUk9WX1NWQ19VVUlEKTsNCj4gPiArICAg
ICAgIGZvciAoaSA9IDA7IGkgPCAxNjsgKytpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHNwcmlu
dGYodHh0X3V1aWQgKyAoaSAqIDIpLCAiJTIuMngiLCBwcm92X2RhdGEtPmRldl91dWlkW2ldKTsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBybF9wcmludGYoIiVzXHREZXZpY2Ug
VVVJRDogJXNcbiIsIHByZWZpeCwgdHh0X3V1aWQpOw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCIl
c1x0T09COiAlNC40eFxuIiwgcHJlZml4LCBwcm92X2RhdGEtPm9vYik7DQo+ID4gKw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwYXJzZV9wcm92X3NlcnZpY2VfZGF0YShjb25zdCBj
aGFyICp1dWlkLCB1aW50OF90ICpkYXRhLCBpbnQNCj4gbGVuLA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2b2lkICpk
YXRhX291dCkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IHByb3Zfc3ZjX2RhdGEgKnByb3Zf
ZGF0YSA9IGRhdGFfb3V0Ow0KPiA+ICsgICAgICAgaW50IGk7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKGxlbiA8IDE4KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0K
PiA+ICsgICAgICAgZm9yIChpID0gMDsgaSA8IDE2OyArK2kpIHsNCj4gPiArICAgICAgICAgICAg
ICAgcHJvdl9kYXRhLT5kZXZfdXVpZFtpXSA9IGRhdGFbaV07DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgcHJvdl9kYXRhLT5vb2IgPSBnZXRfYmUxNigmZGF0YVsxNl0pOw0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMg
Ym9vbCBwYXJzZV9tZXNoX3NlcnZpY2VfZGF0YShjb25zdCBjaGFyICp1dWlkLCB1aW50OF90ICpk
YXRhLCBpbnQNCj4gbGVuLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2b2lkICpkYXRhX291dCkNCj4gPiArew0KPiA+
ICsgICAgICAgY29uc3QgY2hhciAqcHJlZml4ID0gIlx0XHQiOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmICghKGxlbiA9PSA5ICYmIGRhdGFbMF0gPT0gMHgwMCkgJiYgIShsZW4gPT0gMTcgJiYgZGF0
YVswXSA9PSAweDAxKSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlVuZXhwZWN0
ZWQgbWVzaCBwcm94eSBzZXJ2aWNlIGRhdGEgbGVuZ3RoICVkXG4iLA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIGxlbik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGF0YVswXSAhPSBjb25uZWN0aW9uLnR5cGUpDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
ZGF0YVswXSA9PSBDT05OX1RZUEVfSURFTlRJVFkpIHsNCj4gPiArICAgICAgICAgICAgICAgdWlu
dDhfdCAqa2V5Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKElTX1VOQVNTSUdORUQo
Y29ubmVjdGlvbi51bmljYXN0KSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIC8qIFRo
aXMgd291bGQgYmUgYSBidWcgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmlu
dGYoIkVycm9yOiBTZWFyY2hpbmcgaWRlbnRpdHkgd2l0aCAiDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidW5pY2FzdCAwMDAwXG4i
KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAg
ICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGtleSA9IGtleXNfbmV0X2tl
eV9nZXQocHJvdl9uZXRfa2V5X2luZGV4LCB0cnVlKTsNCj4gPiArICAgICAgICAgICAgICAgaWYg
KCFrZXkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgaWYgKCFtZXNoX2NyeXB0b19pZGVudGl0eV9jaGVjayhrZXks
IGNvbm5lY3Rpb24udW5pY2FzdCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICZkYXRhWzFdKSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBy
ZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZGlzY292ZXJpbmcp
IHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIlxuJXNNZXNoIFByb3h5
IFNlcnZpY2UgKCVzKVxuIiwgcHJlZml4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHV1aWQpOw0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50ZigiJXNJZGVudGl0eSBmb3Igbm9kZSAl
NC40eFxuIiwgcHJlZml4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi51bmljYXN0KTsNCj4gPiArICAgICAgICAg
ICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIH0gZWxzZSBpZiAoZGF0YVswXSA9PSBDT05OX1RZ
UEVfTkVUV09SSykgew0KPiA+ICsgICAgICAgICAgICAgICB1aW50MTZfdCBuZXRfaWR4ID0gbmV0
X3ZhbGlkYXRlX3Byb3h5X2JlYWNvbihkYXRhICsgMSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICBpZiAobmV0X2lkeCA9PSBORVRfSURYX0lOVkFMSUQgfHwgbmV0X2lkeCAhPQ0KPiBjb25u
ZWN0aW9uLm5ldF9pZHgpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNl
Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGRpc2NvdmVyaW5nKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJcbiVzTWVzaCBQcm94eSBTZXJ2aWNlICgl
cylcbiIsIHByZWZpeCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1dWlkKTsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBybF9wcmludGYoIiVzTmV0d29yayBCZWFjb24gZm9yIG5ldCBpbmRleCAl
NC40eFxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIHByZWZpeCwgbmV0X2lkeCk7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4g
PiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+
ICsNCj4gPiArc3RhdGljIGJvb2wgcGFyc2Vfc2VydmljZV9kYXRhKEdEQnVzUHJveHkgKnByb3h5
LCBjb25zdCBjaGFyDQo+ICp0YXJnZXRfdXVpZCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgdm9pZCAqZGF0YV9vdXQpDQo+ID4gK3sNCj4gPiArICAgICAgIERC
dXNNZXNzYWdlSXRlciBpdGVyLCBlbnRyaWVzOw0KPiA+ICsgICAgICAgYm9vbCBtZXNoX3Byb3Yg
PSBmYWxzZTsNCj4gPiArICAgICAgIGJvb2wgbWVzaF9wcm94eSA9IGZhbHNlOw0KPiA+ICsNCj4g
PiArICAgICAgIGlmICh0YXJnZXRfdXVpZCkgew0KPiA+ICsgICAgICAgICAgICAgICBtZXNoX3By
b3YgPSAhc3RyY21wKHRhcmdldF91dWlkLCBNRVNIX1BST1ZfU1ZDX1VVSUQpOw0KPiA+ICsgICAg
ICAgICAgICAgICBtZXNoX3Byb3h5ID0gIXN0cmNtcCh0YXJnZXRfdXVpZCwgTUVTSF9QUk9YWV9T
VkNfVVVJRCk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFnX2RidXNf
cHJveHlfZ2V0X3Byb3BlcnR5KHByb3h5LCAiU2VydmljZURhdGEiLCAmaXRlcikpDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChkYnVzX21l
c3NhZ2VfaXRlcl9nZXRfYXJnX3R5cGUoJml0ZXIpICE9IERCVVNfVFlQRV9BUlJBWSkNCj4gPiAr
ICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGRidXNfbWVz
c2FnZV9pdGVyX3JlY3Vyc2UoJml0ZXIsICZlbnRyaWVzKTsNCj4gPiArDQo+ID4gKyAgICAgICB3
aGlsZSAoZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2FyZ190eXBlKCZlbnRyaWVzKQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID09IERCVVNfVFlQRV9E
SUNUX0VOVFJZKSB7DQo+ID4gKyAgICAgICAgICAgICAgIERCdXNNZXNzYWdlSXRlciB2YWx1ZSwg
ZW50cnksIGFycmF5Ow0KPiA+ICsgICAgICAgICAgICAgICBjb25zdCBjaGFyICp1dWlkX3N0cjsN
Cj4gPiArICAgICAgICAgICAgICAgYnRfdXVpZF90IHV1aWQ7DQo+ID4gKyAgICAgICAgICAgICAg
IHVpbnQ4X3QgKnNlcnZpY2VfZGF0YTsNCj4gPiArICAgICAgICAgICAgICAgaW50IGxlbjsNCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX3JlY3Vyc2UoJmVudHJp
ZXMsICZlbnRyeSk7DQo+ID4gKyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dldF9i
YXNpYygmZW50cnksICZ1dWlkX3N0cik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAo
YnRfc3RyaW5nX3RvX3V1aWQoJnV1aWQsIHV1aWRfc3RyKSA8IDApDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgZ290byBmYWlsOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgZGJ1c19t
ZXNzYWdlX2l0ZXJfbmV4dCgmZW50cnkpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYg
KGRidXNfbWVzc2FnZV9pdGVyX2dldF9hcmdfdHlwZSgmZW50cnkpICE9DQo+IERCVVNfVFlQRV9W
QVJJQU5UKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZmFpbDsNCj4gPiArDQo+
ID4gKyAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX3JlY3Vyc2UoJmVudHJ5LCAmdmFs
dWUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGRidXNfbWVzc2FnZV9pdGVyX2dl
dF9hcmdfdHlwZSgmdmFsdWUpICE9DQo+IERCVVNfVFlQRV9BUlJBWSkNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBnb3RvIGZhaWw7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBkYnVz
X21lc3NhZ2VfaXRlcl9yZWN1cnNlKCZ2YWx1ZSwgJmFycmF5KTsNCj4gPiArDQo+ID4gKyAgICAg
ICAgICAgICAgIGlmIChkYnVzX21lc3NhZ2VfaXRlcl9nZXRfYXJnX3R5cGUoJmFycmF5KSAhPQ0K
PiBEQlVTX1RZUEVfQllURSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGZhaWw7
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9nZXRfZml4ZWRf
YXJyYXkoJmFycmF5LCAmc2VydmljZV9kYXRhLA0KPiAmbGVuKTsNCj4gPiArDQo+ID4gKyAgICAg
ICAgICAgICAgIGlmIChtZXNoX3Byb3YgJiYgIXN0cmNtcCh1dWlkX3N0ciwgTUVTSF9QUk9WX1NW
Q19VVUlEKSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZV9wcm92
X3NlcnZpY2VfZGF0YSh1dWlkX3N0ciwgc2VydmljZV9kYXRhLA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW4sIGRh
dGFfb3V0KTsNCj4gPiArICAgICAgICAgICAgICAgfSBlbHNlIGlmIChtZXNoX3Byb3h5ICYmDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhc3RyY21wKHV1aWRfc3RyLCBNRVNI
X1BST1hZX1NWQ19VVUlEKSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBw
YXJzZV9tZXNoX3NlcnZpY2VfZGF0YSh1dWlkX3N0ciwgc2VydmljZV9kYXRhLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBsZW4sIGRhdGFfb3V0KTsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfbmV4dCgmZW50cmllcyk7DQo+ID4gKyAgICAg
ICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCF0YXJnZXRfdXVpZCkNCj4gPiArICAgICAgICAg
ICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK2ZhaWw6DQo+ID4gKyAgICAgICByZXR1cm4gZmFsc2U7
DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHByaW50X3V1aWRzKEdEQnVzUHJveHkg
KnByb3h5KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBEQnVzTWVzc2FnZUl0ZXIgaXRlciwgdmFsdWU7
DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkocHJveHks
ICJVVUlEcyIsICZpdGVyKSA9PSBGQUxTRSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0K
PiA+ICsNCj4gPiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX3JlY3Vyc2UoJml0ZXIsICZ2YWx1
ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgd2hpbGUgKGRidXNfbWVzc2FnZV9pdGVyX2dldF9hcmdf
dHlwZSgmdmFsdWUpID09DQo+IERCVVNfVFlQRV9TVFJJTkcpIHsNCj4gPiArICAgICAgICAgICAg
ICAgY29uc3QgY2hhciAqdXVpZCwgKnRleHQ7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBk
YnVzX21lc3NhZ2VfaXRlcl9nZXRfYmFzaWMoJnZhbHVlLCAmdXVpZCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgICAgICAgICB0ZXh0ID0gdXVpZHN0cl90b19zdHIodXVpZCk7DQo+ID4gKyAgICAgICAg
ICAgICAgIGlmICh0ZXh0KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgY2hhciBzdHJb
MjZdOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHVuc2lnbmVkIGludCBuOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzdHJbc2l6ZW9mKHN0cikgLSAxXSA9ICdcMCc7
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG4gPSBzbnByaW50ZihzdHIsIHNp
emVvZihzdHIpLCAiJXMiLCB0ZXh0KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAo
biA+IHNpemVvZihzdHIpIC0gMSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgc3RyW3NpemVvZihzdHIpIC0gMl0gPSAnLic7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBzdHJbc2l6ZW9mKHN0cikgLSAzXSA9ICcuJzsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIGlmIChzdHJbc2l6ZW9mKHN0cikgLSA0XSA9PSAnICcpDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cltzaXplb2Yoc3RyKSAt
IDRdID0gJy4nOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4g
PSBzaXplb2Yoc3RyKSAtIDE7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgfQ0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIlx0VVVJRDogJXMlKmMoJXMp
XG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IHN0ciwgMjYgLSBuLCAnICcsIHV1aWQpOw0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2UNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIlx0VVVJRDogJSpjKCVzKVxuIiwg
MjYsICcgJywgdXVpZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2Vf
aXRlcl9uZXh0KCZ2YWx1ZSk7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0
YXRpYyBnYm9vbGVhbiBkZXZpY2VfaXNfY2hpbGQoR0RCdXNQcm94eSAqZGV2aWNlLCBHREJ1c1By
b3h5DQo+ICptYXN0ZXIpDQo+ID4gK3sNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRlciBpdGVy
Ow0KPiA+ICsgICAgICAgY29uc3QgY2hhciAqYWRhcHRlciwgKnBhdGg7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKCFtYXN0ZXIpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBGQUxTRTsNCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5X2dldF9wcm9wZXJ0eShkZXZpY2UsICJB
ZGFwdGVyIiwgJml0ZXIpID09IEZBTFNFKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gRkFM
U0U7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2ljKCZpdGVy
LCAmYWRhcHRlcik7DQo+ID4gKyAgICAgICBwYXRoID0gZ19kYnVzX3Byb3h5X2dldF9wYXRoKG1h
c3Rlcik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFzdHJjbXAocGF0aCwgYWRhcHRlcikpDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBUUlVFOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVy
biBGQUxTRTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCBhZGFwdGVyICpmaW5k
X3BhcmVudChHREJ1c1Byb3h5ICpkZXZpY2UpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICps
aXN0Ow0KPiA+ICsNCj4gPiArICAgICAgIGZvciAobGlzdCA9IGdfbGlzdF9maXJzdChjdHJsX2xp
c3QpOyBsaXN0OyBsaXN0ID0gZ19saXN0X25leHQobGlzdCkpIHsNCj4gPiArICAgICAgICAgICAg
ICAgc3RydWN0IGFkYXB0ZXIgKmFkYXB0ZXIgPSBsaXN0LT5kYXRhOw0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAgaWYgKGRldmljZV9pc19jaGlsZChkZXZpY2UsIGFkYXB0ZXItPnByb3h5KSA9
PSBUUlVFKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBhZGFwdGVyOw0KPiA+
ICsgICAgICAgfQ0KPiA+ICsgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gK30NCj4gPiArDQo+ID4g
K3N0YXRpYyB2b2lkIHNldF9jb25uZWN0ZWRfZGV2aWNlKEdEQnVzUHJveHkgKnByb3h5KQ0KPiA+
ICt7DQo+ID4gKyAgICAgICBjaGFyICpkZXNjID0gTlVMTDsNCj4gPiArICAgICAgIERCdXNNZXNz
YWdlSXRlciBpdGVyOw0KPiA+ICsgICAgICAgY2hhciBidWZbMTBdOw0KPiA+ICsgICAgICAgYm9v
bCBtZXNoOw0KPiA+ICsNCj4gPiArICAgICAgIGNvbm5lY3Rpb24uZGV2aWNlID0gcHJveHk7DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKHByb3h5ID09IE5VTEwpIHsNCj4gPiArICAgICAgICAgICAg
ICAgbWVtc2V0KCZjb25uZWN0aW9uLCAwLCBzaXplb2YoY29ubmVjdGlvbikpOw0KPiA+ICsgICAg
ICAgICAgICAgICBjb25uZWN0aW9uLnR5cGUgPSBDT05OX1RZUEVfSU5WQUxJRDsNCj4gPiArICAg
ICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAg
IGlmIChjb25uZWN0aW9uLnR5cGUgPT0gQ09OTl9UWVBFX0lERU5USVRZKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgIG1lc2ggPSB0cnVlOw0KPiA+ICsgICAgICAgICAgICAgICBzbnByaW50ZihidWYs
IDEwLCAiTm9kZS0lNC40eCIsIGNvbm5lY3Rpb24udW5pY2FzdCk7DQo+ID4gKyAgICAgICB9IGVs
c2UgaWYgKGNvbm5lY3Rpb24udHlwZSA9PSBDT05OX1RZUEVfTkVUV09SSykgew0KPiA+ICsgICAg
ICAgICAgICAgICBtZXNoID0gdHJ1ZTsNCj4gPiArICAgICAgICAgICAgICAgc25wcmludGYoYnVm
LCA5LCAiTmV0LSU0LjR4IiwgY29ubmVjdGlvbi5uZXRfaWR4KTsNCj4gPiArICAgICAgIH0gZWxz
ZSB7DQo+ID4gKyAgICAgICAgICAgICAgIG1lc2ggPSBmYWxzZTsNCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoIWdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkocHJveHksICJB
bGlhcyIsICZpdGVyKSAmJiAhbWVzaCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBnb3Rv
IGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2ljKCZp
dGVyLCAmZGVzYyk7DQo+ID4gKyAgICAgICBkZXNjID0gZ19zdHJkdXBfcHJpbnRmKENPTE9SX0JM
VUUgIlslcyVzJXNdIiBDT0xPUl9PRkYgIiMgIiwNCj4gZGVzYywNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgKGRlc2MgJiYgbWVzaCkgPyAiLSIgOiAiIiwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIG1lc2ggPyBidWYgOiAiIik7DQo+ID4gKw0KPiA+ICtk
b25lOg0KPiA+ICsgICAgICAgcmxfc2V0X3Byb21wdChkZXNjID8gZGVzYyA6IFBST01QVF9PTik7
DQo+ID4gKyAgICAgICBybF9wcmludGYoIlxyIik7DQo+ID4gKyAgICAgICBybF9vbl9uZXdfbGlu
ZSgpOw0KPiA+ICsgICAgICAgZ19mcmVlKGRlc2MpOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIElm
IGRpc2Nvbm5lY3RlZCwgcmV0dXJuIHRvIG1haW4gbWVudSAqLw0KPiA+ICsgICAgICAgaWYgKHBy
b3h5ID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIGNtZF9tZW51X21haW4odHJ1ZSk7DQo+
ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNvbm5lY3RfcmVwbHkoREJ1c01lc3NhZ2Ug
Km1lc3NhZ2UsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgR0RCdXNQcm94
eSAqcHJveHkgPSB1c2VyX2RhdGE7DQo+ID4gKyAgICAgICBEQnVzRXJyb3IgZXJyb3I7DQo+ID4g
Kw0KPiA+ICsgICAgICAgZGJ1c19lcnJvcl9pbml0KCZlcnJvcik7DQo+ID4gKw0KPiA+ICsgICAg
ICAgaWYgKGRidXNfc2V0X2Vycm9yX2Zyb21fbWVzc2FnZSgmZXJyb3IsIG1lc3NhZ2UpID09IFRS
VUUpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gY29ubmVjdDog
JXNcbiIsIGVycm9yLm5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX2Vycm9yX2ZyZWUo
JmVycm9yKTsNCj4gPiArICAgICAgICAgICAgICAgc2V0X2Nvbm5lY3RlZF9kZXZpY2UoTlVMTCk7
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4g
KyAgICAgICBybF9wcmludGYoIkNvbm5lY3Rpb24gc3VjY2Vzc2Z1bFxuIik7DQo+ID4gKw0KPiA+
ICsgICAgICAgc2V0X2Nvbm5lY3RlZF9kZXZpY2UocHJveHkpOw0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtzdGF0aWMgdm9pZCB1cGRhdGVfZGV2aWNlX2luZm8oR0RCdXNQcm94eSAqcHJveHkpDQo+ID4g
K3sNCj4gPiArICAgICAgIHN0cnVjdCBhZGFwdGVyICphZGFwdGVyID0gZmluZF9wYXJlbnQocHJv
eHkpOw0KPiA+ICsgICAgICAgREJ1c01lc3NhZ2VJdGVyIGl0ZXI7DQo+ID4gKyAgICAgICBzdHJ1
Y3QgcHJvdl9zdmNfZGF0YSBwcm92X2RhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFhZGFw
dGVyKSB7DQo+ID4gKyAgICAgICAgICAgICAgIC8qIFRPRE86IEVycm9yICovDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
YWRhcHRlciAhPSBkZWZhdWx0X2N0cmwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoIWdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkocHJveHksICJB
ZGRyZXNzIiwgJml0ZXIpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKHBhcnNlX3NlcnZpY2VfZGF0YShwcm94eSwgTUVTSF9QUk9WX1NWQ19VVUlE
LCAmcHJvdl9kYXRhKSkNCj4gew0KPiA+ICsgICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF9kZXZp
Y2UgKmRldjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGRldiA9IGZpbmRfZGV2aWNlX2J5
X3V1aWQoYWRhcHRlci0+bWVzaF9kZXZpY2VzLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdl9kYXRhLmRldl91dWlkKTsNCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIERpc3BsYXkgcHJvdmlzaW9uaW5nIHNlcnZpY2Ug
b25jZSBwZXIgc2ljb3Zlcnkgc2Vzc2lvbiAqLw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZGlz
Y292ZXJpbmcgJiYgKCFkZXYgfHwgIWRldi0+aGlkZSkpDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnRfcHJvdl9zZXJ2aWNlKCZwcm92X2Rh
dGEpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGRldikgew0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIGRldi0+cHJveHkgPSBwcm94eTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBkZXYtPmhpZGUgPSBkaXNjb3ZlcmluZzsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICByZXR1cm47DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAg
ICAgICAgIGRldiA9IGdfbWFsbG9jMChzaXplb2Yoc3RydWN0IG1lc2hfZGV2aWNlKSk7DQo+ID4g
KyAgICAgICAgICAgICAgIGlmICghZGV2KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJl
dHVybjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGRldi0+cHJveHkgPSBwcm94eTsNCj4g
PiArICAgICAgICAgICAgICAgZGV2LT5oaWRlID0gZGlzY292ZXJpbmc7DQo+ID4gKw0KPiA+ICsg
ICAgICAgICAgICAgICBtZW1jcHkoZGV2LT5kZXZfdXVpZCwgcHJvdl9kYXRhLmRldl91dWlkLCAx
Nik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBhZGFwdGVyLT5tZXNoX2RldmljZXMgPSBn
X2xpc3RfYXBwZW5kKGFkYXB0ZXItDQo+ID5tZXNoX2RldmljZXMsDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXYpOw0KPiA+ICsg
ICAgICAgICAgICAgICBwcmludF9kZXZpY2UocHJveHksIENPTE9SRURfTkVXKTsNCj4gPiArDQo+
ID4gKyAgICAgICAgICAgICAgIG5vZGVfY3JlYXRlX25ldygmcHJvdl9kYXRhKTsNCj4gPiArDQo+
ID4gKyAgICAgICB9IGVsc2UgaWYgKHBhcnNlX3NlcnZpY2VfZGF0YShwcm94eSwgTUVTSF9QUk9Y
WV9TVkNfVVVJRCwgTlVMTCkNCj4gJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzY292ZXJfbWVzaCkgew0KPiA+
ICsgICAgICAgICAgICAgICBib29sIHJlczsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGdf
ZGJ1c19wcm94eV9tZXRob2RfY2FsbChkZWZhdWx0X2N0cmwtPnByb3h5LCAiU3RvcERpc2NvdmVy
eSIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
TlVMTCwgTlVMTCwgTlVMTCwgTlVMTCk7DQo+ID4gKyAgICAgICAgICAgICAgIGRpc2NvdmVyX21l
c2ggPSBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGZvcmdldF9tZXNoX2Rldmlj
ZXMoKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHJlcyA9IGdfZGJ1c19wcm94eV9tZXRo
b2RfY2FsbChwcm94eSwgIkNvbm5lY3QiLCBOVUxMLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3RfcmVwbHksIHByb3h5LCBOVUxMKTsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmICghcmVzKQ0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIHJsX3ByaW50ZigiRmFpbGVkIHRvIGNvbm5lY3QgdG8gbWVzaFxuIik7DQo+ID4g
Kw0KPiA+ICsgICAgICAgICAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
cmxfcHJpbnRmKCJUcnlpbmcgdG8gY29ubmVjdCB0byBtZXNoXG4iKTsNCj4gPiArDQo+ID4gKyAg
ICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGFkYXB0ZXJfYWRkZWQoR0RC
dXNQcm94eSAqcHJveHkpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBhZGFwdGVyICphZGFw
dGVyID0gZ19tYWxsb2MwKHNpemVvZihzdHJ1Y3QgYWRhcHRlcikpOw0KPiA+ICsNCj4gPiArICAg
ICAgIGFkYXB0ZXItPnByb3h5ID0gcHJveHk7DQo+ID4gKyAgICAgICBjdHJsX2xpc3QgPSBnX2xp
c3RfYXBwZW5kKGN0cmxfbGlzdCwgYWRhcHRlcik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFk
ZWZhdWx0X2N0cmwpDQo+ID4gKyAgICAgICAgICAgICAgIGRlZmF1bHRfY3RybCA9IGFkYXB0ZXI7
DQo+ID4gKw0KPiA+ICsgICAgICAgcHJpbnRfYWRhcHRlcihwcm94eSwgQ09MT1JFRF9ORVcpOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBkYXRhX291dF9ub3RpZnkoR0RCdXNQcm94
eSAqcHJveHksIGJvb2wgZW5hYmxlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgR0RCdXNSZXR1cm5GdW5jdGlvbiBjYikNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1l
c2hfbm9kZSAqbm9kZTsNCj4gPiArDQo+ID4gKyAgICAgICBub2RlID0gbm9kZV9maW5kX2J5X3V1
aWQoY29ubmVjdGlvbi5kZXZfdXVpZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFtZXNoX2dh
dHRfbm90aWZ5KHByb3h5LCBlbmFibGUsIGNiLCBub2RlKSkNCj4gPiArICAgICAgICAgICAgICAg
cmxfcHJpbnRmKCJGYWlsZWQgdG8gJXMgbm90aWZpY2F0aW9uIG9uICVzXG4iLCBlbmFibGUgPw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN0YXJ0IiA6ICJzdG9wIiwgZ19k
YnVzX3Byb3h5X2dldF9wYXRoKHByb3h5KSk7DQo+ID4gKyAgICAgICBlbHNlDQo+ID4gKyAgICAg
ICAgICAgICAgIHJsX3ByaW50ZigiJXMgbm90aWZpY2F0aW9uIG9uICVzXG4iLCBlbmFibGUgPw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgIlN0YXJ0IiA6ICJTdG9wIiwgZ19kYnVzX3By
b3h5X2dldF9wYXRoKHByb3h5KSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0cnVjdCBkaXNjb25u
ZWN0X2RhdGEgew0KPiA+ICsgICAgICAgR0RCdXNSZXR1cm5GdW5jdGlvbiBjYjsNCj4gPiArICAg
ICAgIHZvaWQgKmRhdGE7DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBkaXNjb25u
ZWN0KEdEQnVzUmV0dXJuRnVuY3Rpb24gY2IsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+
ICsgICAgICAgR0RCdXNQcm94eSAqcHJveHk7DQo+ID4gKyAgICAgICBEQnVzTWVzc2FnZUl0ZXIg
aXRlcjsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKmFkZHI7DQo+ID4gKw0KPiA+ICsgICAgICAg
cHJveHkgPSBjb25uZWN0aW9uLmRldmljZTsNCj4gPiArICAgICAgIGlmICghcHJveHkpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3By
b3h5X21ldGhvZF9jYWxsKHByb3h5LCAiRGlzY29ubmVjdCIsIE5VTEwsIGNiLA0KPiB1c2VyX2Rh
dGEsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBOVUxMKSA9PSBGQUxTRSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYo
IkZhaWxlZCB0byBkaXNjb25uZWN0XG4iKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0K
PiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmIChnX2RidXNfcHJveHlfZ2V0X3By
b3BlcnR5KHByb3h5LCAiQWRkcmVzcyIsICZpdGVyKSA9PSBUUlVFKQ0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2dldF9iYXNpYygmaXRlciwgJmFkZHIpOw0K
PiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50ZigiQXR0ZW1wdGluZyB0byBkaXNjb25uZWN0IGZy
b20gJXNcbiIsIGFkZHIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBkaXNjX25v
dGlmeV9jYihEQnVzTWVzc2FnZSAqbWVzc2FnZSwgdm9pZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+
ID4gKyAgICAgICBzdHJ1Y3QgZGlzY29ubmVjdF9kYXRhICpkaXNjX2RhdGEgPSB1c2VyX2RhdGE7
DQo+ID4gKw0KPiA+ICsgICAgICAgZGlzY29ubmVjdChkaXNjX2RhdGEtPmNiLCBkaXNjX2RhdGEt
PmRhdGEpOw0KPiA+ICsNCj4gPiArICAgICAgIGdfZnJlZSh1c2VyX2RhdGEpOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBkaXNjb25uZWN0X2RldmljZShHREJ1c1JldHVybkZ1bmN0
aW9uIGNiLCB2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIERCdXNNZXNzYWdl
SXRlciBpdGVyOw0KPiA+ICsNCj4gPiArICAgICAgIG5ldF9zZXNzaW9uX2Nsb3NlKGNvbm5lY3Rp
b24uZGF0YV9pbik7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogU3RvcCBub3RpZmljaWF0aW9uIG9u
IHByb3Zfb3V0IG9yIHByb3h5IG91dCBjaGFyYWN0ZXJpc3RpY3MgKi8NCj4gPiArICAgICAgIGlm
IChjb25uZWN0aW9uLmRhdGFfb3V0KSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChnX2RidXNf
cHJveHlfZ2V0X3Byb3BlcnR5KGNvbm5lY3Rpb24uZGF0YV9vdXQsICJOb3RpZnlpbmciLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
Jml0ZXIpID09IFRSVUUpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgZGlz
Y29ubmVjdF9kYXRhICpkaXNjX2RhdGE7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZGlz
Y19kYXRhID0gZ19tYWxsb2Moc2l6ZW9mKHN0cnVjdCBkaXNjb25uZWN0X2RhdGEpKTsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBkaXNjX2RhdGEtPmNiID0gY2I7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgZGlzY19kYXRhLT5kYXRhID0gdXNlcl9kYXRhOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBpZiAobWVzaF9nYXR0X25vdGlmeShjb25uZWN0aW9uLmRh
dGFfb3V0LCBmYWxzZSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICBkaXNjX25vdGlmeV9jYiwgZGlzY19kYXRhKSkNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsg
ICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGRpc2Nvbm5lY3QoY2IsIHVzZXJfZGF0YSk7DQo+
ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIG1lc2hfcHJvdl9kb25lKHZvaWQgKnVzZXJf
ZGF0YSwgaW50IHN0YXR1cyk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBub3RpZnlfcHJvdl9v
dXRfY2IoREJ1c01lc3NhZ2UgKm1lc3NhZ2UsIHZvaWQNCj4gKnVzZXJfZGF0YSkNCj4gPiArew0K
PiA+ICsgICAgICAgc3RydWN0IG1lc2hfbm9kZSAqbm9kZSA9IHVzZXJfZGF0YTsNCj4gPiArICAg
ICAgIERCdXNFcnJvciBlcnJvcjsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX2Vycm9yX2luaXQo
JmVycm9yKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGJ1c19zZXRfZXJyb3JfZnJvbV9tZXNz
YWdlKCZlcnJvciwgbWVzc2FnZSkgPT0gVFJVRSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9w
cmludGYoIkZhaWxlZCB0byBzdGFydCBub3RpZnk6ICVzXG4iLCBlcnJvci5uYW1lKTsNCj4gPiAr
ICAgICAgICAgICAgICAgZGJ1c19lcnJvcl9mcmVlKCZlcnJvcik7DQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBybF9wcmludGYo
Ik5vdGlmeSBmb3IgTWVzaCBQcm92aXNpb25pbmcgT3V0IERhdGEgc3RhcnRlZFxuIik7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKGNvbm5lY3Rpb24udHlwZSAhPSBDT05OX1RZUEVfUFJPVklTSU9O
KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRXJyb3I6IHdyb25nIGNvbm5lY3Rp
b24gdHlwZSAlZCAoZXhwZWN0ZWQgJWQpXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IGNvbm5lY3Rpb24udHlwZSwgQ09OTl9UWVBFX1BST1ZJU0lPTik7DQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWNvbm5l
Y3Rpb24uZGF0YV9pbikgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkVycm9yOiBk
b24ndCBoYXZlIG1lc2ggcHJvdmlzaW9uaW5nIGRhdGEgaW5cbiIpOw0KPiA+ICsgICAgICAgICAg
ICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFub2Rl
KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRXJyb3I6IHByb3Zpc2lvbmluZyBu
b2RlIG5vdCBwcmVzZW50XG4iKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsg
ICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmKCFwcm92X29wZW4obm9kZSwgY29ubmVjdGlv
bi5kYXRhX2luLCBwcm92X25ldF9rZXlfaW5kZXgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgbWVzaF9wcm92X2RvbmUsIG5vZGUpKQ0KPiA+ICsgICAgICAgew0KPiA+ICsgICAgICAgICAg
ICAgICBybF9wcmludGYoIkZhaWxlZCB0byBzdGFydCBwcm92aXNpb25pbmdcbiIpOw0KPiA+ICsg
ICAgICAgICAgICAgICBub2RlX2ZyZWUobm9kZSk7DQo+ID4gKyAgICAgICAgICAgICAgIGRpc2Nv
bm5lY3RfZGV2aWNlKE5VTEwsIE5VTEwpOw0KPiA+ICsgICAgICAgfSBlbHNlDQo+ID4gKyAgICAg
ICAgICAgICAgIHJsX3ByaW50ZigiSW5pdGlhdGVkIHByb3Zpc2lvbmluZ1xuIik7DQo+ID4gKw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBzZXNzaW9uX29wZW5fY2IgKGludCBzdGF0
dXMpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmIChzdGF0dXMpIHsNCj4gPiArICAgICAgICAgICAg
ICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gb3BlbiBNZXNoIHNlc3Npb25cbiIpOw0KPiA+ICsgICAg
ICAgICAgICAgICBkaXNjb25uZWN0X2RldmljZShOVUxMLCBOVUxMKTsNCj4gPiArICAgICAgICAg
ICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50
ZigiTWVzaCBzZXNzaW9uIGlzIG9wZW5cbiIpOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIEdldCBj
b21wb3NpdGlvbiBkYXRhIGZvciBhIG5ld2x5IHByb3Zpc2lvbmVkIG5vZGUgKi8NCj4gPiArICAg
ICAgIGlmIChjb25uZWN0aW9uLnR5cGUgPT0gQ09OTl9UWVBFX0lERU5USVRZKQ0KPiA+ICsgICAg
ICAgICAgICAgICBjb25maWdfY2xpZW50X2dldF9jb21wb3NpdGlvbihjb25uZWN0aW9uLnVuaWNh
c3QpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBub3RpZnlfcHJveHlfb3V0X2Ni
KERCdXNNZXNzYWdlICptZXNzYWdlLCB2b2lkDQo+ICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIERCdXNFcnJvciBlcnJvcjsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX2Vycm9yX2lu
aXQoJmVycm9yKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGJ1c19zZXRfZXJyb3JfZnJvbV9t
ZXNzYWdlKCZlcnJvciwgbWVzc2FnZSkgPT0gVFJVRSkgew0KPiA+ICsgICAgICAgICAgICAgICBy
bF9wcmludGYoIkZhaWxlZCB0byBzdGFydCBub3RpZnk6ICVzXG4iLCBlcnJvci5uYW1lKTsNCj4g
PiArICAgICAgICAgICAgICAgZGJ1c19lcnJvcl9mcmVlKCZlcnJvcik7DQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBybF9wcmlu
dGYoIk5vdGlmeSBmb3IgTWVzaCBQcm94eSBPdXQgRGF0YSBzdGFydGVkXG4iKTsNCj4gPiArDQo+
ID4gKyAgICAgICBpZiAoY29ubmVjdGlvbi50eXBlICE9IENPTk5fVFlQRV9JREVOVElUWSAmJg0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24udHlwZSAhPSBDT05OX1RZUEVf
TkVUV09SSykgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkVycm9yOiB3cm9uZyBj
b25uZWN0aW9uIHR5cGUgJWQgIg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IihleHBlY3RlZCAlZCBvciAlZClcbiIsIGNvbm5lY3Rpb24udHlwZSwNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIENPTk5fVFlQRV9JREVOVElUWSwgQ09OTl9UWVBFX05FVFdP
UkspOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYgKCFjb25uZWN0aW9uLmRhdGFfaW4pIHsNCj4gPiArICAgICAgICAgICAg
ICAgcmxfcHJpbnRmKCJFcnJvcjogZG9uJ3QgaGF2ZSBtZXNoIHByb3h5IGRhdGEgaW5cbiIpOw0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsg
ICAgICAgcmxfcHJpbnRmKCJUcnlpbmcgdG8gb3BlbiBtZXNoIHNlc3Npb25cbiIpOw0KPiA+ICsg
ICAgICAgbmV0X3Nlc3Npb25fb3Blbihjb25uZWN0aW9uLmRhdGFfaW4sIHRydWUsIHNlc3Npb25f
b3Blbl9jYik7DQo+ID4gKyAgICAgICBjb25uZWN0aW9uLnNlc3Npb25fb3BlbiA9IHRydWU7DQo+
ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBHREJ1c1Byb3h5ICpnZXRfY2hhcmFjdGVyaXN0aWMo
R0RCdXNQcm94eSAqZGV2aWNlLCBjb25zdCBjaGFyDQo+ICpjaGFyX3V1aWQpDQo+ID4gK3sNCj4g
PiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsgICAgICAgR0RCdXNQcm94eSAqc2VydmljZTsNCj4g
PiArICAgICAgIGNvbnN0IGNoYXIgKnN2Y191dWlkOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChj
b25uZWN0aW9uLnR5cGUgPT0gQ09OTl9UWVBFX1BST1ZJU0lPTikgew0KPiA+ICsgICAgICAgICAg
ICAgICBzdmNfdXVpZCA9IE1FU0hfUFJPVl9TVkNfVVVJRDsNCj4gPiArICAgICAgIH0gZWxzZSB7
DQo+ID4gKyAgICAgICAgICAgICAgIHN2Y191dWlkID0gTUVTSF9QUk9YWV9TVkNfVVVJRDsNCj4g
PiArICAgICAgIH0NCj4gPiArICAgICAgIGZvciAobCA9IHNlcnZpY2VfbGlzdDsgbDsgbCA9IGwt
Pm5leHQpIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKG1lc2hfZ2F0dF9pc19jaGlsZChsLT5k
YXRhLCBkZXZpY2UsICJEZXZpY2UiKSAmJg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBzZXJ2aWNlX2lzX21lc2gobC0+ZGF0YSwgc3ZjX3V1aWQpKQ0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmIChsKQ0KPiA+ICsgICAgICAgICAgICAgICBzZXJ2aWNlID0gbC0+ZGF0YTsNCj4g
PiArICAgICAgIGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIk1lc2ggc2Vy
dmljZSBub3QgZm91bmRcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gIE5VTEw7DQo+
ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yIChsID0gY2hhcl9saXN0OyBsOyBs
ID0gbC0+bmV4dCkgew0KPiA+ICsgICAgICAgICAgICAgICBpZiAobWVzaF9nYXR0X2lzX2NoaWxk
KGwtPmRhdGEsIHNlcnZpY2UsICJTZXJ2aWNlIikgJiYNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgY2hhcl9pc19tZXNoKGwtPmRhdGEsIGNoYXJfdXVpZCkpIHsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIkZvdW5kIG1hdGNoaW5nIGNo
YXI6IHBhdGggJXMsIHV1aWQgJXNcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBnX2RidXNfcHJveHlfZ2V0X3BhdGgobC0+ZGF0YSksIGNoYXJfdXVpZCk7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGwtPmRhdGE7DQo+ID4gKyAgICAgICAgICAgICAg
IH0NCj4gPiArICAgICAgIH0NCj4gPiArICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgdm9pZCBtZXNoX3Nlc3Npb25fc2V0dXAoR0RCdXNQcm94eSAqcHJveHkp
DQo+ID4gK3sNCj4gPiArICAgICAgIGlmIChjb25uZWN0aW9uLnR5cGUgPT0gQ09OTl9UWVBFX1BS
T1ZJU0lPTikgew0KPiA+ICsgICAgICAgICAgICAgICBjb25uZWN0aW9uLmRhdGFfaW4gPSBnZXRf
Y2hhcmFjdGVyaXN0aWMocHJveHksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgTUVTSF9QUk9WX0RBVEFfSU5fVVVJRF9TVFIpOw0KPiA+ICsgICAg
ICAgICAgICAgICBpZiAoIWNvbm5lY3Rpb24uZGF0YV9pbikNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBnb3RvIGZhaWw7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBjb25uZWN0aW9u
LmRhdGFfb3V0ID0gZ2V0X2NoYXJhY3RlcmlzdGljKHByb3h5LA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1FU0hfUFJPVl9EQVRBX09VVF9VVUlE
X1NUUik7DQo+ID4gKyAgICAgICAgICAgICAgIGlmICghY29ubmVjdGlvbi5kYXRhX291dCkNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGZhaWw7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBkYXRhX291dF9ub3RpZnkoY29ubmVjdGlvbi5kYXRhX291dCwgdHJ1ZSwgbm90aWZ5
X3Byb3Zfb3V0X2NiKTsNCj4gPiArDQo+ID4gKyAgICAgICB9IGVsc2UgaWYgKGNvbm5lY3Rpb24u
dHlwZSAhPSBDT05OX1RZUEVfSU5WQUxJRCl7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBj
b25uZWN0aW9uLmRhdGFfaW4gPSBnZXRfY2hhcmFjdGVyaXN0aWMocHJveHksDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTUVTSF9QUk9YWV9EQVRB
X0lOX1VVSURfU1RSKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFjb25uZWN0aW9uLmRhdGFf
aW4pDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ290byBmYWlsOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgY29ubmVjdGlvbi5kYXRhX291dCA9IGdldF9jaGFyYWN0ZXJpc3RpYyhw
cm94eSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBNRVNIX1BST1hZX0RBVEFfT1VUX1VVSURfU1RSKTsNCj4gPiArICAgICAgICAgICAgICAgaWYg
KCFjb25uZWN0aW9uLmRhdGFfb3V0KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdvdG8g
ZmFpbDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGRhdGFfb3V0X25vdGlmeShjb25uZWN0
aW9uLmRhdGFfb3V0LCB0cnVlLA0KPiBub3RpZnlfcHJveHlfb3V0X2NiKTsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICtmYWlsOg0KPiA+ICsN
Cj4gPiArICAgICAgIHJsX3ByaW50ZigiU2VydmljZXMgcmVzb2x2ZWQsIG1lc2ggY2hhcmFjdGVy
aXN0aWNzIG5vdCBmb3VuZFxuIik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHBy
b3h5X2FkZGVkKEdEQnVzUHJveHkgKnByb3h5LCB2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4g
PiArICAgICAgIGNvbnN0IGNoYXIgKmludGVyZmFjZTsNCj4gPiArDQo+ID4gKyAgICAgICBpbnRl
cmZhY2UgPSBnX2RidXNfcHJveHlfZ2V0X2ludGVyZmFjZShwcm94eSk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKCFzdHJjbXAoaW50ZXJmYWNlLCAib3JnLmJsdWV6LkRldmljZTEiKSkgew0KPiA+
ICsgICAgICAgICAgICAgICB1cGRhdGVfZGV2aWNlX2luZm8ocHJveHkpOw0KPiA+ICsNCj4gPiAr
ICAgICAgIH0gZWxzZSBpZiAoIXN0cmNtcChpbnRlcmZhY2UsICJvcmcuYmx1ZXouQWRhcHRlcjEi
KSkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgYWRhcHRlcl9hZGRlZChwcm94eSk7DQo+
ID4gKw0KPiA+ICsgICAgICAgfSBlbHNlIGlmICghc3RyY21wKGludGVyZmFjZSwgIm9yZy5ibHVl
ei5HYXR0U2VydmljZTEiKSAmJg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHNlcnZpY2VfaXNfbWVzaChwcm94eSwgTlVMTCkpIHsNCj4gPiArDQo+
ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiU2VydmljZSBhZGRlZCAlc1xuIiwgZ19kYnVz
X3Byb3h5X2dldF9wYXRoKHByb3h5KSk7DQo+ID4gKyAgICAgICAgICAgICAgIHNlcnZpY2VfbGlz
dCA9IGdfbGlzdF9hcHBlbmQoc2VydmljZV9saXN0LCBwcm94eSk7DQo+ID4gKw0KPiA+ICsgICAg
ICAgfSBlbHNlIGlmICghc3RyY21wKGludGVyZmFjZSwgIm9yZy5ibHVlei5HYXR0Q2hhcmFjdGVy
aXN0aWMxIikgJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBjaGFyX2lzX21lc2gocHJveHksIE5VTEwpKSB7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBybF9wcmludGYoIkNoYXIgYWRkZWQgJXM6XG4iLCBnX2RidXNfcHJveHlfZ2V0X3Bh
dGgocHJveHkpKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGNoYXJfbGlzdCA9IGdfbGlz
dF9hcHBlbmQoY2hhcl9saXN0LCBwcm94eSk7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyB2b2lkIHN0YXJ0X2Rpc2NvdmVyeV9yZXBseShEQnVzTWVzc2FnZSAqbWVz
c2FnZSwgdm9pZA0KPiAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBkYnVzX2Jvb2xf
dCBlbmFibGUgPSBHUE9JTlRFUl9UT19VSU5UKHVzZXJfZGF0YSk7DQo+ID4gKyAgICAgICBEQnVz
RXJyb3IgZXJyb3I7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19lcnJvcl9pbml0KCZlcnJvcik7
DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGRidXNfc2V0X2Vycm9yX2Zyb21fbWVzc2FnZSgmZXJy
b3IsIG1lc3NhZ2UpID09IFRSVUUpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJG
YWlsZWQgdG8gJXMgZGlzY292ZXJ5OiAlc1xuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIGVuYWJsZSA9PSBUUlVFID8gInN0YXJ0IiA6ICJzdG9wIiwgZXJyb3IubmFtZSk7
DQo+ID4gKyAgICAgICAgICAgICAgIGRidXNfZXJyb3JfZnJlZSgmZXJyb3IpOw0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmxf
cHJpbnRmKCJEaXNjb3ZlcnkgJXNcbiIsIGVuYWJsZSA9PSBUUlVFID8gInN0YXJ0ZWQiIDogInN0
b3BwZWQiKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCBtZXNoX2RldmljZSAq
ZmluZF9kZXZpY2VfYnlfcHJveHkoR0xpc3QgKnNvdXJjZSwNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdEQnVzUHJveHkgKnByb3h5
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBHTGlzdCAqbGlzdDsNCj4gPiArDQo+ID4gKyAgICAgICBm
b3IgKGxpc3QgPSBnX2xpc3RfZmlyc3Qoc291cmNlKTsgbGlzdDsgbGlzdCA9IGdfbGlzdF9uZXh0
KGxpc3QpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0cnVjdCBtZXNoX2RldmljZSAqZGV2ID0g
bGlzdC0+ZGF0YTsNCj4gPiArICAgICAgICAgICAgICAgR0RCdXNQcm94eSAqcHJveHkgPSBkZXYt
PnByb3h5Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGRldi0+cHJveHkgPT0gcHJv
eHkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRldjsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
c3RhdGljIHZvaWQgZGV2aWNlX3JlbW92ZWQoR0RCdXNQcm94eSAqcHJveHkpDQo+ID4gK3sNCj4g
PiArICAgICAgIHN0cnVjdCBhZGFwdGVyICphZGFwdGVyID0gZmluZF9wYXJlbnQocHJveHkpOw0K
PiA+ICsgICAgICAgc3RydWN0IG1lc2hfZGV2aWNlICpkZXY7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKCFhZGFwdGVyKSB7DQo+ID4gKyAgICAgICAgICAgICAgIC8qIFRPRE86IEVycm9yICovDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICBkZXYgPSBmaW5kX2RldmljZV9ieV9wcm94eShhZGFwdGVyLT5tZXNoX2RldmljZXMsIHBy
b3h5KTsNCj4gPiArICAgICAgIGlmIChkZXYpDQo+ID4gKyAgICAgICAgICAgICAgIGFkYXB0ZXIt
Pm1lc2hfZGV2aWNlcyA9IGdfbGlzdF9yZW1vdmUoYWRhcHRlci0NCj4gPm1lc2hfZGV2aWNlcywN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBkZXYpOw0KPiA+ICsNCj4gPiArICAgICAgIHByaW50X2Rldmlj
ZShwcm94eSwgQ09MT1JFRF9ERUwpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChjb25uZWN0aW9u
LmRldmljZSA9PSBwcm94eSkNCj4gPiArICAgICAgICAgICAgICAgc2V0X2Nvbm5lY3RlZF9kZXZp
Y2UoTlVMTCk7DQo+ID4gKw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBhZGFwdGVy
X3JlbW92ZWQoR0RCdXNQcm94eSAqcHJveHkpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICps
bDsNCj4gPiArICAgICAgIGZvciAobGwgPSBnX2xpc3RfZmlyc3QoY3RybF9saXN0KTsgbGw7IGxs
ID0gZ19saXN0X25leHQobGwpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0cnVjdCBhZGFwdGVy
ICphZGFwdGVyID0gbGwtPmRhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoYWRh
cHRlci0+cHJveHkgPT0gcHJveHkpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcmlu
dF9hZGFwdGVyKHByb3h5LCBDT0xPUkVEX0RFTCk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIGlmIChkZWZhdWx0X2N0cmwgJiYgZGVmYXVsdF9jdHJsLT5wcm94eSA9PSBwcm94
eSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdF9jdHJsID0g
TlVMTDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldF9jb25uZWN0ZWRf
ZGV2aWNlKE5VTEwpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgY3RybF9saXN0ID0gZ19saXN0X3JlbW92ZV9saW5rKGN0
cmxfbGlzdCwgbGwpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBnX2xpc3Rf
ZnJlZV9mdWxsKGFkYXB0ZXItPm1lc2hfZGV2aWNlcywgZ19mcmVlKTsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBnX2ZyZWUoYWRhcHRlcik7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgZ19saXN0X2ZyZWUobGwpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjsN
Cj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgfQ0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtzdGF0aWMgdm9pZCBwcm94eV9yZW1vdmVkKEdEQnVzUHJveHkgKnByb3h5LCB2b2lkICp1c2Vy
X2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKmludGVyZmFjZTsNCj4gPiAr
DQo+ID4gKyAgICAgICBpbnRlcmZhY2UgPSBnX2RidXNfcHJveHlfZ2V0X2ludGVyZmFjZShwcm94
eSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFzdHJjbXAoaW50ZXJmYWNlLCAib3JnLmJsdWV6
LkRldmljZTEiKSkgew0KPiA+ICsgICAgICAgICAgICAgICBkZXZpY2VfcmVtb3ZlZChwcm94eSk7
DQo+ID4gKyAgICAgICB9IGVsc2UgaWYgKCFzdHJjbXAoaW50ZXJmYWNlLCAib3JnLmJsdWV6LkFk
YXB0ZXIxIikpIHsNCj4gPiArICAgICAgICAgICAgICAgYWRhcHRlcl9yZW1vdmVkKHByb3h5KTsN
Cj4gPiArICAgICAgIH0gZWxzZSBpZiAoIXN0cmNtcChpbnRlcmZhY2UsICJvcmcuYmx1ZXouR2F0
dFNlcnZpY2UxIikpIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKHByb3h5ID09IGNvbm5lY3Rp
b24uc2VydmljZSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZXJ2aWNlX2lz
X21lc2gocHJveHksIE1FU0hfUFJPWFlfU1ZDX1VVSUQpKSB7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBkYXRhX291dF9ub3RpZnkoY29ubmVjdGlvbi5kYXRhX291dCwNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgZmFsc2UsIE5VTEwpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgbmV0X3Nlc3Npb25fY2xvc2UoY29ubmVjdGlvbi5kYXRhX2luKTsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICB9DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5z
ZXJ2aWNlID0gTlVMTDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmRh
dGFfaW4gPSBOVUxMOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZGF0
YV9vdXQgPSBOVUxMOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBzZXJ2aWNlX2xpc3QgPSBnX2xpc3RfcmVtb3ZlKHNlcnZpY2VfbGlzdCwgcHJveHkp
Ow0KPiA+ICsNCj4gPiArICAgICAgIH0gZWxzZSBpZiAoIXN0cmNtcChpbnRlcmZhY2UsICJvcmcu
Ymx1ZXouR2F0dENoYXJhY3RlcmlzdGljMSIpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGNoYXJf
bGlzdCA9IGdfbGlzdF9yZW1vdmUoY2hhcl9saXN0LCBwcm94eSk7DQo+ID4gKyAgICAgICB9DQo+
ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgZ2V0X2NoYXJhY3RlcmlzdGljX3ZhbHVlKERC
dXNNZXNzYWdlSXRlciAqdmFsdWUsIHVpbnQ4X3QgKmJ1ZikNCj4gPiArew0KPiA+ICsgICAgICAg
REJ1c01lc3NhZ2VJdGVyIGFycmF5Ow0KPiA+ICsgICAgICAgdWludDhfdCAqZGF0YTsNCj4gPiAr
ICAgICAgIGludCBsZW47DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGRidXNfbWVzc2FnZV9pdGVy
X2dldF9hcmdfdHlwZSh2YWx1ZSkgIT0gREJVU19UWVBFX0FSUkFZKQ0KPiA+ICsgICAgICAgICAg
ICAgICByZXR1cm4gMDsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9yZWN1
cnNlKHZhbHVlLCAmYXJyYXkpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChkYnVzX21lc3NhZ2Vf
aXRlcl9nZXRfYXJnX3R5cGUoJmFycmF5KSAhPSBEQlVTX1RZUEVfQllURSkNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIDA7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJf
Z2V0X2ZpeGVkX2FycmF5KCZhcnJheSwgJmRhdGEsICZsZW4pOw0KPiA+ICsgICAgICAgbWVtY3B5
KGJ1ZiwgZGF0YSwgbGVuKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbGVuOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwcm9jZXNzX21lc2hfY2hhcmFjdGVyaXN0aWMoR0RC
dXNQcm94eSAqcHJveHkpDQo+ID4gK3sNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRlciBpdGVy
Ow0KPiA+ICsgICAgICAgY29uc3QgY2hhciAqdXVpZDsNCj4gPiArICAgICAgIHVpbnQ4X3QgKnJl
czsNCj4gPiArICAgICAgIHVpbnQ4X3QgYnVmWzI1Nl07DQo+ID4gKyAgICAgICBib29sIGlzX3By
b3Y7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkocHJv
eHksICJVVUlEIiwgJml0ZXIpID09IEZBTFNFKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4g
ZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2ljKCZp
dGVyLCAmdXVpZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGdfZGJ1c19wcm94eV9nZXRfcHJv
cGVydHkocHJveHksICJWYWx1ZSIsICZpdGVyKSA9PSBGQUxTRSkNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGlzX3Byb3YgPSAhYnRfdXVpZF9z
dHJjbXAodXVpZCwNCj4gTUVTSF9QUk9WX0RBVEFfT1VUX1VVSURfU1RSKTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoaXNfcHJvdiB8fCAhYnRfdXVpZF9zdHJjbXAodXVpZCwNCj4gTUVTSF9QUk9Y
WV9EQVRBX09VVF9VVUlEX1NUUikpDQo+ID4gKyAgICAgICB7DQo+ID4gKyAgICAgICAgICAgICAg
IHN0cnVjdCBtZXNoX25vZGUgKm5vZGU7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQxNl90IGxl
bjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGxlbiA9IGdldF9jaGFyYWN0ZXJpc3RpY192
YWx1ZSgmaXRlciwgYnVmKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmICghbGVuIHx8
IGxlbiA+IDY5KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIHJlcyA9IGJ1ZjsNCj4gPiArICAgICAgICAgICAgICAg
bGVuID0gbWVzaF9nYXR0X3NhcigmcmVzLCBsZW4pOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgaWYgKCFsZW4pDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGlzX3Byb3YpIHsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBub2RlID0gbm9kZV9maW5kX2J5X3V1aWQoY29ubmVjdGlvbi5kZXZfdXVp
ZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmICghbm9kZSkgew0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJOb2RlIG5vdCBmb3Vu
ZD9cbiIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNl
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgcmV0dXJuIHByb3ZfZGF0YV9yZWFkeShub2RlLCByZXMsIGxlbik7DQo+ID4g
KyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBuZXRf
ZGF0YV9yZWFkeShyZXMsIGxlbik7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAg
cmV0dXJuIGZhbHNlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHJv
cGVydHlfY2hhbmdlZChHREJ1c1Byb3h5ICpwcm94eSwgY29uc3QgY2hhciAqbmFtZSwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgREJ1c01lc3NhZ2VJdGVyICpp
dGVyLCB2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKmlu
dGVyZmFjZTsNCj4gPiArDQo+ID4gKyAgICAgICBpbnRlcmZhY2UgPSBnX2RidXNfcHJveHlfZ2V0
X2ludGVyZmFjZShwcm94eSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFzdHJjbXAoaW50ZXJm
YWNlLCAib3JnLmJsdWV6LkRldmljZTEiKSkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
aWYgKGRlZmF1bHRfY3RybCAmJiBkZXZpY2VfaXNfY2hpbGQocHJveHksDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHRfY3RybC0+cHJveHkpID09IFRS
VUUpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKHN0cmNtcChuYW1l
LCAiQ29ubmVjdGVkIikgPT0gMCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgZGJ1c19ib29sX3QgY29ubmVjdGVkOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2ljKGl0ZXIsICZjb25uZWN0ZWQpOw0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjb25uZWN0ZWQgJiYg
Y29ubmVjdGlvbi5kZXZpY2UgPT0gTlVMTCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgc2V0X2Nvbm5lY3RlZF9kZXZpY2UocHJveHkpOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoIWNvbm5lY3RlZCAmJg0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZGV2
aWNlID09IHByb3h5KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBzZXRfY29ubmVjdGVkX2RldmljZShOVUxMKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICB9IGVsc2UgaWYgKChzdHJjbXAobmFtZSwgIkFsaWFzIikgPT0gMCkgJiYNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmRldmlj
ZSA9PSBwcm94eSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogUmUt
Z2VuZXJhdGUgcHJvbXB0ICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBz
ZXRfY29ubmVjdGVkX2RldmljZShwcm94eSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
fSBlbHNlIGlmICghc3RyY21wKG5hbWUsICJTZXJ2aWNlRGF0YSIpKSB7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVfZGV2aWNlX2luZm8ocHJveHkpOw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIXN0cmNtcChuYW1lLCAiU2VydmljZXNS
ZXNvbHZlZCIpKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnYm9vbGVh
biByZXNvbHZlZDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBk
YnVzX21lc3NhZ2VfaXRlcl9nZXRfYmFzaWMoaXRlciwgJnJlc29sdmVkKTsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIlNlcnZpY2VzIHJlc29s
dmVkICVzXG4iLCByZXNvbHZlZCA/DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZXMiIDogIm5vIik7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc29sdmVkKQ0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNoX3Nlc3Npb25fc2V0dXAo
Y29ubmVjdGlvbi5kZXZpY2UpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIH0NCj4gPiAr
DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgIH0gZWxzZSBpZiAoIXN0cmNtcChp
bnRlcmZhY2UsICJvcmcuYmx1ZXouQWRhcHRlcjEiKSkgew0KPiA+ICsgICAgICAgICAgICAgICBE
QnVzTWVzc2FnZUl0ZXIgYWRkcl9pdGVyOw0KPiA+ICsgICAgICAgICAgICAgICBjaGFyICpzdHI7
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkFkYXB0ZXIgcHJvcGVydHkg
Y2hhbmdlZCBcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZ19kYnVzX3Byb3h5X2dldF9w
cm9wZXJ0eShwcm94eSwgIkFkZHJlc3MiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICZhZGRyX2l0ZXIpID09IFRSVUUpIHsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBjb25zdCBjaGFyICphZGRyZXNzOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9nZXRfYmFzaWMoJmFkZHJfaXRlciwg
JmFkZHJlc3MpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHN0ciA9IGdfc3RyZHVwX3By
aW50ZigiWyIgQ09MT1JFRF9DSEcNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAiXSBDb250cm9sbGVyICVzICIsIGFkZHJlc3MpOw0KPiA+ICsgICAg
ICAgICAgICAgICB9IGVsc2UNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzdHIgPSBnX3N0
cmR1cCgiIik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoc3RyY21wKG5hbWUsICJE
aXNjb3ZlcmluZyIpID09IDApIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpbnQgdGVt
cDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJf
Z2V0X2Jhc2ljKGl0ZXIsICZ0ZW1wKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBkaXNj
b3ZlcmluZyA9ICEhdGVtcDsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAgcHJpbnRfaXRlcihzdHIsIG5hbWUsIGl0ZXIpOw0KPiA+ICsgICAgICAgICAg
ICAgICBnX2ZyZWUoc3RyKTsNCj4gPiArICAgICAgIH0gZWxzZSBpZiAoIXN0cmNtcChpbnRlcmZh
Y2UsICJvcmcuYmx1ZXouR2F0dFNlcnZpY2UxIikpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxf
cHJpbnRmKCJTZXJ2aWNlIHByb3BlcnR5IGNoYW5nZWQgJXNcbiIsDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ19kYnVzX3Byb3h5X2dldF9wYXRo
KHByb3h5KSk7DQo+ID4gKyAgICAgICB9IGVsc2UgaWYgKCFzdHJjbXAoaW50ZXJmYWNlLCAib3Jn
LmJsdWV6LkdhdHRDaGFyYWN0ZXJpc3RpYzEiKSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9w
cmludGYoIkNoYXJhY3RlcmlzdGljIHByb3BlcnR5IGNoYW5nZWQgJXNcbiIsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ19kYnVzX3Byb3h5X2dl
dF9wYXRoKHByb3h5KSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoKGNvbm5lY3Rp
b24udHlwZSA9PSBDT05OX1RZUEVfUFJPVklTSU9OKSB8fA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5zZXNzaW9u
X29wZW4pDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHJvY2Vzc19tZXNoX2NoYXJhY3Rl
cmlzdGljKHByb3h5KTsNCj4gPiArICAgICAgIH0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGlj
IHZvaWQgbWVzc2FnZV9oYW5kbGVyKERCdXNDb25uZWN0aW9uICpjb25uZWN0aW9uLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEQnVzTWVzc2FnZSAqbWVzc2Fn
ZSwgdm9pZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBybF9wcmludGYoIltTSUdO
QUxdICVzLiVzXG4iLA0KPiBkYnVzX21lc3NhZ2VfZ2V0X2ludGVyZmFjZShtZXNzYWdlKSwNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGJ1c19tZXNzYWdlX2dl
dF9tZW1iZXIobWVzc2FnZSkpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IGFk
YXB0ZXIgKmZpbmRfY3RybF9ieV9hZGRyZXNzKEdMaXN0ICpzb3VyY2UsIGNvbnN0IGNoYXINCj4g
KmFkZHJlc3MpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsaXN0Ow0KPiA+ICsNCj4gPiAr
ICAgICAgIGZvciAobGlzdCA9IGdfbGlzdF9maXJzdChzb3VyY2UpOyBsaXN0OyBsaXN0ID0gZ19s
aXN0X25leHQobGlzdCkpIHsNCj4gPiArICAgICAgICAgICAgICAgc3RydWN0IGFkYXB0ZXIgKmFk
YXB0ZXIgPSBsaXN0LT5kYXRhOw0KPiA+ICsgICAgICAgICAgICAgICBEQnVzTWVzc2FnZUl0ZXIg
aXRlcjsNCj4gPiArICAgICAgICAgICAgICAgY29uc3QgY2hhciAqc3RyOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgaWYgKGdfZGJ1c19wcm94eV9nZXRfcHJvcGVydHkoYWRhcHRlci0+cHJv
eHksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZGRyZXNz
IiwgJml0ZXIpID09IEZBTFNFKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVl
Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfZ2V0X2Jhc2lj
KCZpdGVyLCAmc3RyKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmICghc3RyY21wKHN0
ciwgYWRkcmVzcykpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFkYXB0ZXI7
DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gK30N
Cj4gPiArDQo+ID4gK3N0YXRpYyBnYm9vbGVhbiBwYXJzZV9hcmd1bWVudF9vbl9vZmYoY29uc3Qg
Y2hhciAqYXJnLCBkYnVzX2Jvb2xfdA0KPiAqdmFsdWUpDQo+ID4gK3sNCj4gPiArICAgICAgIGlm
ICghYXJnIHx8ICFzdHJsZW4oYXJnKSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYo
Ik1pc3Npbmcgb24vb2ZmIGFyZ3VtZW50XG4iKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
IEZBTFNFOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmICghc3RyY21wKGFy
ZywgIm9uIikgfHwgIXN0cmNtcChhcmcsICJ5ZXMiKSkgew0KPiA+ICsgICAgICAgICAgICAgICAq
dmFsdWUgPSBUUlVFOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gVFJVRTsNCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXN0cmNtcChhcmcsICJvZmYiKSB8fCAhc3Ry
Y21wKGFyZywgIm5vIikpIHsNCj4gPiArICAgICAgICAgICAgICAgKnZhbHVlID0gRkFMU0U7DQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBUUlVFOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4g
PiArICAgICAgIHJsX3ByaW50ZigiSW52YWxpZCBhcmd1bWVudCAlc1xuIiwgYXJnKTsNCj4gPiAr
ICAgICAgIHJldHVybiBGQUxTRTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21k
X2xpc3QoY29uc3QgY2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBHTGlzdCAqbGlzdDsN
Cj4gPiArDQo+ID4gKyAgICAgICBmb3IgKGxpc3QgPSBnX2xpc3RfZmlyc3QoY3RybF9saXN0KTsg
bGlzdDsgbGlzdCA9IGdfbGlzdF9uZXh0KGxpc3QpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0
cnVjdCBhZGFwdGVyICphZGFwdGVyID0gbGlzdC0+ZGF0YTsNCj4gPiArICAgICAgICAgICAgICAg
cHJpbnRfYWRhcHRlcihhZGFwdGVyLT5wcm94eSwgTlVMTCk7DQo+ID4gKyAgICAgICB9DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9zaG93KGNvbnN0IGNoYXIgKmFyZykNCj4g
PiArew0KPiA+ICsgICAgICAgc3RydWN0IGFkYXB0ZXIgKmFkYXB0ZXI7DQo+ID4gKyAgICAgICBH
REJ1c1Byb3h5ICpwcm94eTsNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRlciBpdGVyOw0KPiA+
ICsgICAgICAgY29uc3QgY2hhciAqYWRkcmVzczsNCj4gPiArDQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKCFhcmcgfHwgIXN0cmxlbihhcmcpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChjaGVj
a19kZWZhdWx0X2N0cmwoKSA9PSBGQUxTRSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBy
ZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBwcm94eSA9IGRlZmF1bHRfY3RybC0+
cHJveHk7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBhZGFwdGVy
ID0gZmluZF9jdHJsX2J5X2FkZHJlc3MoY3RybF9saXN0LCBhcmcpOw0KPiA+ICsgICAgICAgICAg
ICAgICBpZiAoIWFkYXB0ZXIpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmlu
dGYoIkNvbnRyb2xsZXIgJXMgbm90IGF2YWlsYWJsZVxuIiwgYXJnKTsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAg
ICAgICAgICAgcHJveHkgPSBhZGFwdGVyLT5wcm94eTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+
ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5X2dldF9wcm9wZXJ0eShwcm94eSwgIkFkZHJlc3Mi
LCAmaXRlcikgPT0gRkFMU0UpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+
ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9nZXRfYmFzaWMoJml0ZXIsICZhZGRyZXNzKTsN
Cj4gPiArICAgICAgIHJsX3ByaW50ZigiQ29udHJvbGxlciAlc1xuIiwgYWRkcmVzcyk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgcHJpbnRfcHJvcGVydHkocHJveHksICJOYW1lIik7DQo+ID4gKyAgICAg
ICBwcmludF9wcm9wZXJ0eShwcm94eSwgIkFsaWFzIik7DQo+ID4gKyAgICAgICBwcmludF9wcm9w
ZXJ0eShwcm94eSwgIkNsYXNzIik7DQo+ID4gKyAgICAgICBwcmludF9wcm9wZXJ0eShwcm94eSwg
IlBvd2VyZWQiKTsNCj4gPiArICAgICAgIHByaW50X3Byb3BlcnR5KHByb3h5LCAiRGlzY292ZXJh
YmxlIik7DQo+ID4gKyAgICAgICBwcmludF91dWlkcyhwcm94eSk7DQo+ID4gKyAgICAgICBwcmlu
dF9wcm9wZXJ0eShwcm94eSwgIk1vZGFsaWFzIik7DQo+ID4gKyAgICAgICBwcmludF9wcm9wZXJ0
eShwcm94eSwgIkRpc2NvdmVyaW5nIik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lk
IGNtZF9zZWxlY3QoY29uc3QgY2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3Qg
YWRhcHRlciAqYWRhcHRlcjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWFyZyB8fCAhc3RybGVu
KGFyZykpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJNaXNzaW5nIGNvbnRyb2xs
ZXIgYWRkcmVzcyBhcmd1bWVudFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4g
PiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBhZGFwdGVyID0gZmluZF9jdHJsX2J5X2Fk
ZHJlc3MoY3RybF9saXN0LCBhcmcpOw0KPiA+ICsgICAgICAgaWYgKCFhZGFwdGVyKSB7DQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiQ29udHJvbGxlciAlcyBub3QgYXZhaWxhYmxlXG4i
LCBhcmcpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKGRlZmF1bHRfY3RybCAmJiBkZWZhdWx0X2N0cmwtPnByb3h5ID09
IGFkYXB0ZXItPnByb3h5KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+
ICsgICAgICAgZm9yZ2V0X21lc2hfZGV2aWNlcygpOw0KPiA+ICsNCj4gPiArICAgICAgIGRlZmF1
bHRfY3RybCA9IGFkYXB0ZXI7DQo+ID4gKyAgICAgICBwcmludF9hZGFwdGVyKGFkYXB0ZXItPnBy
b3h5LCBOVUxMKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgZ2VuZXJpY19jYWxs
YmFjayhjb25zdCBEQnVzRXJyb3IgKmVycm9yLCB2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4g
PiArICAgICAgIGNoYXIgKnN0ciA9IHVzZXJfZGF0YTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
ZGJ1c19lcnJvcl9pc19zZXQoZXJyb3IpKQ0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYo
IkZhaWxlZCB0byBzZXQgJXM6ICVzXG4iLCBzdHIsIGVycm9yLT5uYW1lKTsNCj4gPiArICAgICAg
IGVsc2UNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJDaGFuZ2luZyAlcyBzdWNjZWVk
ZWRcbiIsIHN0cik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9wb3dlcihj
b25zdCBjaGFyICphcmcpDQo+ID4gK3sNCj4gPiArICAgICAgIGRidXNfYm9vbF90IHBvd2VyZWQ7
DQo+ID4gKyAgICAgICBjaGFyICpzdHI7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHBhcnNlX2Fy
Z3VtZW50X29uX29mZihhcmcsICZwb3dlcmVkKSA9PSBGQUxTRSkNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChjaGVja19kZWZhdWx0X2N0cmwoKSA9
PSBGQUxTRSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAg
IHN0ciA9IGdfc3RyZHVwX3ByaW50ZigicG93ZXIgJXMiLCBwb3dlcmVkID09IFRSVUUgPyAib24i
IDogIm9mZiIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChnX2RidXNfcHJveHlfc2V0X3Byb3Bl
cnR5X2Jhc2ljKGRlZmF1bHRfY3RybC0+cHJveHksDQo+ICJQb3dlcmVkIiwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgREJVU19UWVBFX0JPT0xFQU4sICZwb3dl
cmVkLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lcmlj
X2NhbGxiYWNrLCBzdHIsIGdfZnJlZSkgPT0gVFJVRSkNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIGdfZnJlZShzdHIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtzdGF0aWMgdm9pZCBjbWRfc2Nhbihjb25zdCBjaGFyICphcmcpDQo+ID4gK3sNCj4gPiArICAg
ICAgIGRidXNfYm9vbF90IGVuYWJsZTsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKm1ldGhvZDsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAocGFyc2VfYXJndW1lbnRfb25fb2ZmKGFyZywgJmVuYWJs
ZSkgPT0gRkFMU0UpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAoY2hlY2tfZGVmYXVsdF9jdHJsKCkgPT0gRkFMU0UpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZW5hYmxlID09IFRSVUUpIHsNCj4g
PiArICAgICAgICAgICAgICAgbWV0aG9kID0gIlN0YXJ0RGlzY292ZXJ5IjsNCj4gPiArICAgICAg
IH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIG1ldGhvZCA9ICJTdG9wRGlzY292ZXJ5IjsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5X21ldGhv
ZF9jYWxsKGRlZmF1bHRfY3RybC0+cHJveHksIG1ldGhvZCwNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIE5VTEwsIHN0YXJ0X2Rpc2NvdmVyeV9yZXBseSwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIEdVSU5UX1RPX1BPSU5URVIoZW5hYmxlKSwgTlVMTCkg
PT0gRkFMU0UpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gJXMg
ZGlzY292ZXJ5XG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBlbmFibGUgPT0gVFJVRSA/ICJzdGFydCIgOiAic3RvcCIpOw0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lk
IGFwcGVuZF92YXJpYW50KERCdXNNZXNzYWdlSXRlciAqaXRlciwgaW50IHR5cGUsIHZvaWQgKnZh
bCkNCj4gPiArew0KPiA+ICsgICAgICAgREJ1c01lc3NhZ2VJdGVyIHZhbHVlOw0KPiA+ICsgICAg
ICAgY2hhciBzaWdbMl0gPSB7IHR5cGUsICdcMCcgfTsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVz
X21lc3NhZ2VfaXRlcl9vcGVuX2NvbnRhaW5lcihpdGVyLCBEQlVTX1RZUEVfVkFSSUFOVCwgc2ln
LA0KPiAmdmFsdWUpOw0KPiA+ICsNCj4gPiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2FwcGVu
ZF9iYXNpYygmdmFsdWUsIHR5cGUsIHZhbCk7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNz
YWdlX2l0ZXJfY2xvc2VfY29udGFpbmVyKGl0ZXIsICZ2YWx1ZSk7DQo+ID4gK30NCj4gPiArDQo+
ID4gK3N0YXRpYyB2b2lkIGFwcGVuZF9hcnJheV92YXJpYW50KERCdXNNZXNzYWdlSXRlciAqaXRl
ciwgaW50IHR5cGUsIHZvaWQNCj4gKnZhbCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGludCBuX2VsZW1lbnRzKQ0KPiA+ICt7DQo+
ID4gKyAgICAgICBEQnVzTWVzc2FnZUl0ZXIgdmFyaWFudCwgYXJyYXk7DQo+ID4gKyAgICAgICBj
aGFyIHR5cGVfc2lnWzJdID0geyB0eXBlLCAnXDAnIH07DQo+ID4gKyAgICAgICBjaGFyIGFycmF5
X3NpZ1szXSA9IHsgREJVU19UWVBFX0FSUkFZLCB0eXBlLCAnXDAnIH07DQo+ID4gKw0KPiA+ICsg
ICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfb3Blbl9jb250YWluZXIoaXRlciwgREJVU19UWVBFX1ZB
UklBTlQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgYXJyYXlfc2lnLCAmdmFyaWFudCk7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdl
X2l0ZXJfb3Blbl9jb250YWluZXIoJnZhcmlhbnQsIERCVVNfVFlQRV9BUlJBWSwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlX3NpZywgJmFy
cmF5KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGJ1c190eXBlX2lzX2ZpeGVkKHR5cGUpID09
IFRSVUUpIHsNCj4gPiArICAgICAgICAgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfYXBwZW5kX2Zp
eGVkX2FycmF5KCZhcnJheSwgdHlwZSwgdmFsLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9lbGVtZW50cyk7DQo+ID4gKyAgICAg
ICB9IGVsc2UgaWYgKHR5cGUgPT0gREJVU19UWVBFX1NUUklORyB8fCB0eXBlID09DQo+IERCVVNf
VFlQRV9PQkpFQ1RfUEFUSCkgew0KPiA+ICsgICAgICAgICAgICAgICBjb25zdCBjaGFyICoqKnN0
cl9hcnJheSA9IHZhbDsNCj4gPiArICAgICAgICAgICAgICAgaW50IGk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbl9lbGVtZW50czsgaSsrKQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2FwcGVuZF9iYXNpYygmYXJyYXks
IHR5cGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAmKCgqc3RyX2FycmF5KVtpXSkpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4g
PiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX2Nsb3NlX2NvbnRhaW5lcigmdmFyaWFudCwgJmFy
cmF5KTsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9jbG9zZV9jb250YWlu
ZXIoaXRlciwgJnZhcmlhbnQpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBkaWN0
X2FwcGVuZF9lbnRyeShEQnVzTWVzc2FnZUl0ZXIgKmRpY3QsIGNvbnN0IGNoYXIgKmtleSwNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IGludCB0eXBlLCB2b2lkICp2YWwpDQo+ID4gK3sNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRl
ciBlbnRyeTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAodHlwZSA9PSBEQlVTX1RZUEVfU1RSSU5H
KSB7DQo+ID4gKyAgICAgICAgICAgICAgIGNvbnN0IGNoYXIgKnN0ciA9ICooKGNvbnN0IGNoYXIg
KiopIHZhbCk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoc3RyID09IE5VTEwpDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsN
Cj4gPiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX29wZW5fY29udGFpbmVyKGRpY3QsIERCVVNf
VFlQRV9ESUNUX0VOVFJZLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgTlVMTCwgJmVudHJ5KTsNCj4gPiArDQo+ID4gKyAgICAgICBk
YnVzX21lc3NhZ2VfaXRlcl9hcHBlbmRfYmFzaWMoJmVudHJ5LCBEQlVTX1RZUEVfU1RSSU5HLA0K
PiAma2V5KTsNCj4gPiArDQo+ID4gKyAgICAgICBhcHBlbmRfdmFyaWFudCgmZW50cnksIHR5cGUs
IHZhbCk7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfY2xvc2VfY29udGFp
bmVyKGRpY3QsICZlbnRyeSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGRpY3Rf
YXBwZW5kX2Jhc2ljX2FycmF5KERCdXNNZXNzYWdlSXRlciAqZGljdCwgaW50DQo+IGtleV90eXBl
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB2b2lk
ICprZXksIGludCB0eXBlLCB2b2lkICp2YWwsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIGludCBuX2VsZW1lbnRzKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBEQnVz
TWVzc2FnZUl0ZXIgZW50cnk7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJf
b3Blbl9jb250YWluZXIoZGljdCwgREJVU19UWVBFX0RJQ1RfRU5UUlksDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTlVMTCwgJmVudHJ5KTsNCj4g
PiArDQo+ID4gKyAgICAgICBkYnVzX21lc3NhZ2VfaXRlcl9hcHBlbmRfYmFzaWMoJmVudHJ5LCBr
ZXlfdHlwZSwga2V5KTsNCj4gPiArDQo+ID4gKyAgICAgICBhcHBlbmRfYXJyYXlfdmFyaWFudCgm
ZW50cnksIHR5cGUsIHZhbCwgbl9lbGVtZW50cyk7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19t
ZXNzYWdlX2l0ZXJfY2xvc2VfY29udGFpbmVyKGRpY3QsICZlbnRyeSk7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyB2b2lkIGRpY3RfYXBwZW5kX2FycmF5KERCdXNNZXNzYWdlSXRlciAqZGlj
dCwgY29uc3QgY2hhciAqa2V5LCBpbnQNCj4gdHlwZSwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2b2lkICp2YWwsIGludCBuX2VsZW1lbnRzKQ0K
PiA+ICt7DQo+ID4gKyAgICAgICBkaWN0X2FwcGVuZF9iYXNpY19hcnJheShkaWN0LCBEQlVTX1RZ
UEVfU1RSSU5HLCAma2V5LCB0eXBlLCB2YWwsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5fZWxlbWVudHMpOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICsjZGVmaW5lICAgICAgICBESVNUQU5DRV9WQUxfSU5WQUxJRCAgICAw
eDdGRkYNCj4gPiArDQo+ID4gK3N0cnVjdCBzZXRfZGlzY292ZXJ5X2ZpbHRlcl9hcmdzIHsNCj4g
PiArICAgICAgIGNoYXIgKnRyYW5zcG9ydDsNCj4gPiArICAgICAgIGRidXNfdWludDE2X3QgcnNz
aTsNCj4gPiArICAgICAgIGRidXNfaW50MTZfdCBwYXRobG9zczsNCj4gPiArICAgICAgIGNoYXIg
Kip1dWlkczsNCj4gPiArICAgICAgIHNpemVfdCB1dWlkc19sZW47DQo+ID4gKyAgICAgICBkYnVz
X2Jvb2xfdCByZXNldDsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHNldF9kaXNj
b3ZlcnlfZmlsdGVyX3NldHVwKERCdXNNZXNzYWdlSXRlciAqaXRlciwgdm9pZA0KPiAqdXNlcl9k
YXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3Qgc2V0X2Rpc2NvdmVyeV9maWx0ZXJfYXJn
cyAqYXJncyA9IHVzZXJfZGF0YTsNCj4gPiArICAgICAgIERCdXNNZXNzYWdlSXRlciBkaWN0Ow0K
PiA+ICsNCj4gPiArICAgICAgIGRidXNfbWVzc2FnZV9pdGVyX29wZW5fY29udGFpbmVyKGl0ZXIs
IERCVVNfVFlQRV9BUlJBWSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERC
VVNfRElDVF9FTlRSWV9CRUdJTl9DSEFSX0FTX1NUUklORw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgREJVU19UWVBFX1NUUklOR19BU19TVFJJTkcNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIERCVVNfVFlQRV9WQVJJQU5UX0FTX1NUUklORw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgREJVU19ESUNUX0VOVFJZX0VORF9DSEFSX0FT
X1NUUklORywgJmRpY3QpOw0KPiA+ICsNCj4gPiArICAgICAgIGRpY3RfYXBwZW5kX2FycmF5KCZk
aWN0LCAiVVVJRHMiLCBEQlVTX1RZUEVfU1RSSU5HLCAmYXJncy0NCj4gPnV1aWRzLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJn
cy0+dXVpZHNfbGVuKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoYXJncy0+cGF0aGxvc3MgIT0g
RElTVEFOQ0VfVkFMX0lOVkFMSUQpDQo+ID4gKyAgICAgICAgICAgICAgIGRpY3RfYXBwZW5kX2Vu
dHJ5KCZkaWN0LCAiUGF0aGxvc3MiLCBEQlVTX1RZUEVfVUlOVDE2LA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZhcmdzLT5wYXRobG9zcyk7DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKGFyZ3MtPnJzc2kgIT0gRElTVEFOQ0VfVkFMX0lOVkFMSUQp
DQo+ID4gKyAgICAgICAgICAgICAgIGRpY3RfYXBwZW5kX2VudHJ5KCZkaWN0LCAiUlNTSSIsIERC
VVNfVFlQRV9JTlQxNiwgJmFyZ3MtPnJzc2kpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChhcmdz
LT50cmFuc3BvcnQgIT0gTlVMTCkNCj4gPiArICAgICAgICAgICAgICAgZGljdF9hcHBlbmRfZW50
cnkoJmRpY3QsICJUcmFuc3BvcnQiLCBEQlVTX1RZUEVfU1RSSU5HLA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZhcmdzLT50cmFuc3BvcnQpOw0K
PiA+ICsgICAgICAgaWYgKGFyZ3MtPnJlc2V0KQ0KPiA+ICsgICAgICAgICAgICAgICBkaWN0X2Fw
cGVuZF9lbnRyeSgmZGljdCwgIlJlc2V0RGF0YSIsIERCVVNfVFlQRV9CT09MRUFOLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZhcmdzLT5yZXNl
dCk7DQo+ID4gKw0KPiA+ICsgICAgICAgZGJ1c19tZXNzYWdlX2l0ZXJfY2xvc2VfY29udGFpbmVy
KGl0ZXIsICZkaWN0KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHNl
dF9kaXNjb3ZlcnlfZmlsdGVyX3JlcGx5KERCdXNNZXNzYWdlICptZXNzYWdlLCB2b2lkDQo+ICp1
c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIERCdXNFcnJvciBlcnJvcjsNCj4gPiArDQo+
ID4gKyAgICAgICBkYnVzX2Vycm9yX2luaXQoJmVycm9yKTsNCj4gPiArICAgICAgIGlmIChkYnVz
X3NldF9lcnJvcl9mcm9tX21lc3NhZ2UoJmVycm9yLCBtZXNzYWdlKSA9PSBUUlVFKSB7DQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiU2V0RGlzY292ZXJ5RmlsdGVyIGZhaWxlZDogJXNc
biIsIGVycm9yLm5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICBkYnVzX2Vycm9yX2ZyZWUoJmVy
cm9yKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsN
Cj4gPiArICAgICAgIHJsX3ByaW50ZigiU2V0RGlzY292ZXJ5RmlsdGVyIHN1Y2Nlc3NcbiIpOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgZ2ludCBmaWx0ZXJlZF9zY2FuX3Jzc2kgPSBESVNU
QU5DRV9WQUxfSU5WQUxJRDsNCj4gPiArc3RhdGljIGdpbnQgZmlsdGVyZWRfc2Nhbl9wYXRobG9z
cyA9IERJU1RBTkNFX1ZBTF9JTlZBTElEOw0KPiA+ICtzdGF0aWMgY2hhciAqKmZpbHRlcmVkX3Nj
YW5fdXVpZHM7DQo+ID4gK3N0YXRpYyBzaXplX3QgZmlsdGVyZWRfc2Nhbl91dWlkc19sZW47DQo+
ID4gK3N0YXRpYyBjaGFyICpmaWx0ZXJlZF9zY2FuX3RyYW5zcG9ydCA9ICJsZSI7DQo+ID4gKw0K
PiA+ICtzdGF0aWMgdm9pZCBzZXRfc2Nhbl9maWx0ZXJfY29tbWl0KHZvaWQpDQo+ID4gK3sNCj4g
PiArICAgICAgIHN0cnVjdCBzZXRfZGlzY292ZXJ5X2ZpbHRlcl9hcmdzIGFyZ3M7DQo+ID4gKw0K
PiA+ICsgICAgICAgYXJncy5wYXRobG9zcyA9IGZpbHRlcmVkX3NjYW5fcGF0aGxvc3M7DQo+ID4g
KyAgICAgICBhcmdzLnJzc2kgPSBmaWx0ZXJlZF9zY2FuX3Jzc2k7DQo+ID4gKyAgICAgICBhcmdz
LnRyYW5zcG9ydCA9IGZpbHRlcmVkX3NjYW5fdHJhbnNwb3J0Ow0KPiA+ICsgICAgICAgYXJncy51
dWlkcyA9IGZpbHRlcmVkX3NjYW5fdXVpZHM7DQo+ID4gKyAgICAgICBhcmdzLnV1aWRzX2xlbiA9
IGZpbHRlcmVkX3NjYW5fdXVpZHNfbGVuOw0KPiA+ICsgICAgICAgYXJncy5yZXNldCA9IFRSVUU7
DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGNoZWNrX2RlZmF1bHRfY3RybCgpID09IEZBTFNFKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGdfZGJ1
c19wcm94eV9tZXRob2RfY2FsbChkZWZhdWx0X2N0cmwtPnByb3h5LA0KPiAiU2V0RGlzY292ZXJ5
RmlsdGVyIiwNCj4gPiArICAgICAgICAgICAgICAgc2V0X2Rpc2NvdmVyeV9maWx0ZXJfc2V0dXAs
IHNldF9kaXNjb3ZlcnlfZmlsdGVyX3JlcGx5LA0KPiA+ICsgICAgICAgICAgICAgICAmYXJncywg
TlVMTCkgPT0gRkFMU0UpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQg
dG8gc2V0IGRpc2NvdmVyeSBmaWx0ZXJcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47
DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHNldF9zY2Fu
X2ZpbHRlcl91dWlkcyhjb25zdCBjaGFyICphcmcpDQo+ID4gK3sNCj4gPiArICAgICAgIGdfc3Ry
ZnJlZXYoZmlsdGVyZWRfc2Nhbl91dWlkcyk7DQo+ID4gKyAgICAgICBmaWx0ZXJlZF9zY2FuX3V1
aWRzID0gTlVMTDsNCj4gPiArICAgICAgIGZpbHRlcmVkX3NjYW5fdXVpZHNfbGVuID0gMDsNCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoIWFyZyB8fCAhc3RybGVuKGFyZykpDQo+ID4gKyAgICAgICAg
ICAgICAgIGdvdG8gY29tbWl0Ow0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50Zigic2V0X3Nj
YW5fZmlsdGVyX3V1aWRzICVzXG4iLCBhcmcpOw0KPiA+ICsgICAgICAgZmlsdGVyZWRfc2Nhbl91
dWlkcyA9IGdfc3Ryc3BsaXQoYXJnLCAiICIsIC0xKTsNCj4gPiArICAgICAgIGlmICghZmlsdGVy
ZWRfc2Nhbl91dWlkcykgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkZhaWxlZCB0
byBwYXJzZSBpbnB1dFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBmaWx0ZXJlZF9zY2FuX3V1aWRzX2xlbiA9IGdfc3Ry
dl9sZW5ndGgoZmlsdGVyZWRfc2Nhbl91dWlkcyk7DQo+ID4gKw0KPiA+ICtjb21taXQ6DQo+ID4g
KyAgICAgICBzZXRfc2Nhbl9maWx0ZXJfY29tbWl0KCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0
YXRpYyB2b2lkIGNtZF9zY2FuX3VucHJvdmlzaW9uZWRfZGV2aWNlcyhjb25zdCBjaGFyICphcmcp
DQo+ID4gK3sNCj4gPiArICAgICAgIGRidXNfYm9vbF90IGVuYWJsZTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAocGFyc2VfYXJndW1lbnRfb25fb2ZmKGFyZywgJmVuYWJsZSkgPT0gRkFMU0UpDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZW5hYmxl
ID09IFRSVUUpIHsNCj4gPiArICAgICAgICAgICAgICAgZGlzY292ZXJfbWVzaCA9IGZhbHNlOw0K
PiA+ICsgICAgICAgICAgICAgICBzZXRfc2Nhbl9maWx0ZXJfdXVpZHMoTUVTSF9QUk9WX1NWQ19V
VUlEKTsNCj4gPiArICAgICAgIH0NCj4gPiArICAgICAgIGNtZF9zY2FuKGFyZyk7DQo+ID4gK30N
Cj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9pbmZvKGNvbnN0IGNoYXIgKmFyZykNCj4gPiAr
ew0KPiA+ICsgICAgICAgR0RCdXNQcm94eSAqcHJveHk7DQo+ID4gKyAgICAgICBEQnVzTWVzc2Fn
ZUl0ZXIgaXRlcjsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKmFkZHJlc3M7DQo+ID4gKw0KPiA+
ICsgICAgICAgcHJveHkgPSBjb25uZWN0aW9uLmRldmljZTsNCj4gPiArICAgICAgIGlmICghcHJv
eHkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
Z19kYnVzX3Byb3h5X2dldF9wcm9wZXJ0eShwcm94eSwgIkFkZHJlc3MiLCAmaXRlcikgPT0gRkFM
U0UpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVz
X21lc3NhZ2VfaXRlcl9nZXRfYmFzaWMoJml0ZXIsICZhZGRyZXNzKTsNCj4gPiArICAgICAgIHJs
X3ByaW50ZigiRGV2aWNlICVzXG4iLCBhZGRyZXNzKTsNCj4gPiArDQo+ID4gKyAgICAgICBwcmlu
dF9wcm9wZXJ0eShwcm94eSwgIk5hbWUiKTsNCj4gPiArICAgICAgIHByaW50X3Byb3BlcnR5KHBy
b3h5LCAiQWxpYXMiKTsNCj4gPiArICAgICAgIHByaW50X3Byb3BlcnR5KHByb3h5LCAiQ2xhc3Mi
KTsNCj4gPiArICAgICAgIHByaW50X3Byb3BlcnR5KHByb3h5LCAiQXBwZWFyYW5jZSIpOw0KPiA+
ICsgICAgICAgcHJpbnRfcHJvcGVydHkocHJveHksICJJY29uIik7DQo+ID4gKyAgICAgICBwcmlu
dF9wcm9wZXJ0eShwcm94eSwgIlRydXN0ZWQiKTsNCj4gPiArICAgICAgIHByaW50X3Byb3BlcnR5
KHByb3h5LCAiQmxvY2tlZCIpOw0KPiA+ICsgICAgICAgcHJpbnRfcHJvcGVydHkocHJveHksICJD
b25uZWN0ZWQiKTsNCj4gPiArICAgICAgIHByaW50X3V1aWRzKHByb3h5KTsNCj4gPiArICAgICAg
IHByaW50X3Byb3BlcnR5KHByb3h5LCAiTW9kYWxpYXMiKTsNCj4gPiArICAgICAgIHByaW50X3By
b3BlcnR5KHByb3h5LCAiTWFudWZhY3R1cmVyRGF0YSIpOw0KPiA+ICsgICAgICAgcHJpbnRfcHJv
cGVydHkocHJveHksICJTZXJ2aWNlRGF0YSIpOw0KPiA+ICsgICAgICAgcHJpbnRfcHJvcGVydHko
cHJveHksICJSU1NJIik7DQo+ID4gKyAgICAgICBwcmludF9wcm9wZXJ0eShwcm94eSwgIlR4UG93
ZXIiKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21kX2Nvbm5lY3QoY29uc3Qg
Y2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoY2hlY2tfZGVmYXVsdF9jdHJsKCkg
PT0gRkFMU0UpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAg
ICBtZW1zZXQoJmNvbm5lY3Rpb24sIDAsIHNpemVvZihjb25uZWN0aW9uKSk7DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKCFhcmcgfHwgIXN0cmxlbihhcmcpKSB7DQo+ID4gKyAgICAgICAgICAgICAg
IGNvbm5lY3Rpb24ubmV0X2lkeCA9IE5FVF9JRFhfUFJJTUFSWTsNCj4gPiArICAgICAgIH0gZWxz
ZSB7DQo+ID4gKyAgICAgICAgICAgICAgIGNoYXIgKmVuZDsNCj4gPiArICAgICAgICAgICAgICAg
Y29ubmVjdGlvbi5uZXRfaWR4ID0gc3RydG9sKGFyZywgJmVuZCwgMTYpOw0KPiA+ICsgICAgICAg
ICAgICAgICBpZiAoZW5kID09IGFyZykgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGNv
bm5lY3Rpb24ubmV0X2lkeCA9IE5FVF9JRFhfSU5WQUxJRDsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBybF9wcmludGYoIkludmFsaWQgbmV0d29yayBpbmRleCAlc1xuIiwgYXJnKTsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICAgICAgICAgIH0N
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGlzY292ZXJpbmcpDQo+ID4g
KyAgICAgICAgICAgICAgIGdfZGJ1c19wcm94eV9tZXRob2RfY2FsbChkZWZhdWx0X2N0cmwtPnBy
b3h5LCAiU3RvcERpc2NvdmVyeSIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgc2V0X3NjYW5fZmlsdGVyX3V1aWRzKE1FU0hfUFJPWFlfU1ZDX1VVSUQpOw0KPiA+ICsg
ICAgICAgZGlzY292ZXJfbWVzaCA9IHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAgY29ubmVjdGlv
bi50eXBlID0gQ09OTl9UWVBFX05FVFdPUks7DQo+ID4gKw0KPiA+ICsNCj4gPiArICAgICAgIHJs
X3ByaW50ZigiTG9va2luZyBmb3IgbWVzaCBuZXR3b3JrIHdpdGggbmV0IGluZGV4ICU0LjR4XG4i
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgY29ubmVjdGlvbi5uZXRfaWR4KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVz
X3Byb3h5X21ldGhvZF9jYWxsKGRlZmF1bHRfY3RybC0+cHJveHksDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgIlN0YXJ0RGlzY292ZXJ5IiwgTlVMTCwgc3RhcnRfZGlzY292ZXJ5X3JlcGx5
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1VJTlRfVE9fUE9JTlRFUihU
UlVFKSwgTlVMTCkgPT0gRkFMU0UpDQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRmFp
bGVkIHRvIHN0YXJ0IG1lc2ggcHJveHkgZGlzY292ZXJ5XG4iKTsNCj4gPiArDQo+ID4gKyAgICAg
ICBnX2RidXNfcHJveHlfbWV0aG9kX2NhbGwoZGVmYXVsdF9jdHJsLT5wcm94eSwgIlN0YXJ0RGlz
Y292ZXJ5IiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBOVUxMLCBOVUxMLCBOVUxMLCBOVUxMKTsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4g
K3N0YXRpYyB2b2lkIHByb3ZfZGlzY29ubl9yZXBseShEQnVzTWVzc2FnZSAqbWVzc2FnZSwgdm9p
ZA0KPiAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpu
b2RlID0gdXNlcl9kYXRhOw0KPiA+ICsgICAgICAgREJ1c0Vycm9yIGVycm9yOw0KPiA+ICsNCj4g
PiArICAgICAgIGRidXNfZXJyb3JfaW5pdCgmZXJyb3IpOw0KPiA+ICsNCj4gPiArICAgICAgIGlm
IChkYnVzX3NldF9lcnJvcl9mcm9tX21lc3NhZ2UoJmVycm9yLCBtZXNzYWdlKSA9PSBUUlVFKSB7
DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRmFpbGVkIHRvIGRpc2Nvbm5lY3Q6ICVz
XG4iLCBlcnJvci5uYW1lKTsNCj4gPiArICAgICAgICAgICAgICAgZGJ1c19lcnJvcl9mcmVlKCZl
cnJvcik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiAr
DQo+ID4gKyAgICAgICBzZXRfY29ubmVjdGVkX2RldmljZShOVUxMKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBzZXRfc2Nhbl9maWx0ZXJfdXVpZHMoTUVTSF9QUk9YWV9TVkNfVVVJRCk7DQo+ID4gKyAg
ICAgICBkaXNjb3Zlcl9tZXNoID0gdHJ1ZTsNCj4gPiArDQo+ID4gKyAgICAgICBjb25uZWN0aW9u
LnR5cGUgPSBDT05OX1RZUEVfSURFTlRJVFk7DQo+ID4gKyAgICAgICBjb25uZWN0aW9uLmRhdGFf
aW4gPSBOVUxMOw0KPiA+ICsgICAgICAgY29ubmVjdGlvbi5kYXRhX291dCA9IE5VTEw7DQo+ID4g
KyAgICAgICBjb25uZWN0aW9uLnVuaWNhc3QgPSBub2RlX2dldF9wcmltYXJ5KG5vZGUpOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmIChnX2RidXNfcHJveHlfbWV0aG9kX2NhbGwoZGVmYXVsdF9jdHJs
LT5wcm94eSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAiU3RhcnREaXNjb3ZlcnkiLCBO
VUxMLCBzdGFydF9kaXNjb3ZlcnlfcmVwbHksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBHVUlOVF9UT19QT0lOVEVSKFRSVUUpLCBOVUxMKSA9PSBGQUxTRSkNCj4gPiArICAg
ICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8gc3RhcnQgbWVzaCBwcm94eSBkaXNjb3Zl
cnlcbiIpOw0KPiA+ICsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgZGlzY29ubl9y
ZXBseShEQnVzTWVzc2FnZSAqbWVzc2FnZSwgdm9pZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICBHREJ1c1Byb3h5ICpwcm94eSA9IHVzZXJfZGF0YTsNCj4gPiArICAgICAgIERCdXNF
cnJvciBlcnJvcjsNCj4gPiArDQo+ID4gKyAgICAgICBkYnVzX2Vycm9yX2luaXQoJmVycm9yKTsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAoZGJ1c19zZXRfZXJyb3JfZnJvbV9tZXNzYWdlKCZlcnJv
ciwgbWVzc2FnZSkgPT0gVFJVRSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkZh
aWxlZCB0byBkaXNjb25uZWN0OiAlc1xuIiwgZXJyb3IubmFtZSk7DQo+ID4gKyAgICAgICAgICAg
ICAgIGRidXNfZXJyb3JfZnJlZSgmZXJyb3IpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47
DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCJTdWNjZXNzZnVs
bHkgZGlzY29ubmVjdGVkXG4iKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocHJveHkgIT0gY29u
bmVjdGlvbi5kZXZpY2UpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4g
KyAgICAgICBzZXRfY29ubmVjdGVkX2RldmljZShOVUxMKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
c3RhdGljIHZvaWQgY21kX2Rpc2Nvbm4oY29uc3QgY2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAg
ICAgICBpZiAoY29ubmVjdGlvbi50eXBlID09IENPTk5fVFlQRV9QUk9WSVNJT04pIHsNCj4gPiAr
ICAgICAgICAgICAgICAgc3RydWN0IG1lc2hfbm9kZSAqbm9kZSA9DQo+IG5vZGVfZmluZF9ieV91
dWlkKGNvbm5lY3Rpb24uZGV2X3V1aWQpOw0KPiA+ICsgICAgICAgICAgICAgICBpZiAobm9kZSkN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBub2RlX2ZyZWUobm9kZSk7DQo+ID4gKyAgICAg
ICB9DQo+ID4gKw0KPiA+ICsgICAgICAgZGlzY29ubmVjdF9kZXZpY2UoZGlzY29ubl9yZXBseSwg
Y29ubmVjdGlvbi5kZXZpY2UpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBtZXNo
X3Byb3ZfZG9uZSh2b2lkICp1c2VyX2RhdGEsIGludCBzdGF0dXMpDQo+ID4gK3sNCj4gPiArICAg
ICAgIHN0cnVjdCBtZXNoX25vZGUgKm5vZGUgPSB1c2VyX2RhdGE7DQo+ID4gKw0KPiA+ICsgICAg
ICAgaWYgKHN0YXR1cyl7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiUHJvdmlzaW9u
aW5nIGZhaWxlZFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIG5vZGVfZnJlZShub2RlKTsNCj4g
PiArICAgICAgICAgICAgICAgZGlzY29ubmVjdF9kZXZpY2UoTlVMTCwgTlVMTCk7DQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBy
bF9wcmludGYoIlByb3Zpc2lvbiBzdWNjZXNzLiBBc3NpZ25lZCBQcmltYXJ5IFVuaWNhc3QgJTQu
NHhcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgbm9kZV9nZXRfcHJpbWFyeShub2RlKSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFwcm92
X2RiX2FkZF9uZXdfbm9kZShub2RlKSkNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJG
YWlsZWQgdG8gYWRkIG5vZGUgdG8gcHJvdmlzaW9uaW5nIERCXG4iKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBkaXNjb25uZWN0X2RldmljZShwcm92X2Rpc2Nvbm5fcmVwbHksIG5vZGUpOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfc3RhcnRfcHJvdihjb25zdCBjaGFyICphcmcp
DQo+ID4gK3sNCj4gPiArICAgICAgIEdEQnVzUHJveHkgKnByb3h5Ow0KPiA+ICsgICAgICAgc3Ry
dWN0IG1lc2hfZGV2aWNlICpkZXY7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2Rl
Ow0KPiA+ICsgICAgICAgaW50IGxlbjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWFyZykgew0K
PiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIk1lc2ggRGV2aWNlIFVVSUQgaXMgcmVxdWly
ZWRcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgbGVuID0gc3RybGVuKGFyZyk7DQo+ID4gKyAgICAgICBpZiAoIGxlbiA+
IDMyIHx8IGxlbiAlIDIpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJJbmNvcnJl
Y3QgVVVJRCBzaXplICVkXG4iLCBsZW4pOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAg
ICAgIGRpc2Nvbm5lY3RfZGV2aWNlKE5VTEwsIE5VTEwpOw0KPiA+ICsNCj4gPiArICAgICAgIG1l
bXNldChjb25uZWN0aW9uLmRldl91dWlkLCAwLCAxNik7DQo+ID4gKyAgICAgICBzdHIyaGV4KGFy
ZywgbGVuLCBjb25uZWN0aW9uLmRldl91dWlkLCBsZW4vMik7DQo+ID4gKw0KPiA+ICsgICAgICAg
bm9kZSA9IG5vZGVfZmluZF9ieV91dWlkKGNvbm5lY3Rpb24uZGV2X3V1aWQpOw0KPiA+ICsgICAg
ICAgaWYgKCFub2RlKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRGV2aWNlIHdp
dGggVVVJRCAlcyBub3QgZm91bmQuXG4iLCBhcmcpOw0KPiA+ICsgICAgICAgICAgICAgICBybF9w
cmludGYoIlN0YWxlIHNlcnZpY2VzPyBSZW1vdmUgZGV2aWNlIGFuZCByZS1kaXNjb3ZlclxuIik7
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4g
KyAgICAgICAvKiBUT0RPOiBhZGQgY29tbWFuZCB0byByZW1vdmUgYSBub2RlIGZyb20gbWVzaCwg
aS5lLiwNCj4gInVucHJvdmlzaW9uIiAqLw0KPiA+ICsgICAgICAgaWYgKG5vZGVfaXNfcHJvdmlz
aW9uZWQobm9kZSkpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJBbHJlYWR5IHBy
b3Zpc2lvbmVkIHdpdGggdW5pY2FzdCAlNC40eFxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIG5vZGVfZ2V0X3ByaW1hcnkobm9kZSkpOw0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgZGV2ID0gZmluZF9k
ZXZpY2VfYnlfdXVpZChkZWZhdWx0X2N0cmwtPm1lc2hfZGV2aWNlcywNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGlvbi5kZXZfdXVpZCk7DQo+ID4gKyAgICAg
ICBpZiAoIWRldiB8fCAhZGV2LT5wcm94eSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmlu
dGYoIkNvdWxkIG5vdCBmaW5kIGRldmljZSBwcm94eVxuIik7DQo+ID4gKyAgICAgICAgICAgICAg
IG1lbXNldChjb25uZWN0aW9uLmRldl91dWlkLCAwLCAxNik7DQo+ID4gKyAgICAgICAgICAgICAg
IHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBwcm94eSA9IGRldi0+
cHJveHk7DQo+ID4gKyAgICAgICBpZiAoZGlzY292ZXJpbmcpDQo+ID4gKyAgICAgICAgICAgICAg
IGdfZGJ1c19wcm94eV9tZXRob2RfY2FsbChkZWZhdWx0X2N0cmwtPnByb3h5LCAiU3RvcERpc2Nv
dmVyeSIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgTlVMTCwgTlVMTCwgTlVMTCwgTlVMTCk7DQo+ID4gKyAgICAgICBmb3JnZXRfbWVzaF9kZXZp
Y2VzKCk7DQo+ID4gKw0KPiA+ICsgICAgICAgY29ubmVjdGlvbi50eXBlID0gQ09OTl9UWVBFX1BS
T1ZJU0lPTjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ19kYnVzX3Byb3h5X21ldGhvZF9jYWxs
KHByb3h5LCAiQ29ubmVjdCIsIE5VTEwsDQo+IGNvbm5lY3RfcmVwbHksDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm94eSwgTlVM
TCkgPT0gRkFMU0UpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJGYWlsZWQgdG8g
Y29ubmVjdCAiKTsNCj4gPiArICAgICAgICAgICAgICAgcHJpbnRfZGV2aWNlKHByb3h5LCBOVUxM
KTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfSBlbHNlIHsNCj4g
PiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJUcnlpbmcgdG8gY29ubmVjdCAiKTsNCj4gPiAr
ICAgICAgICAgICAgICAgcHJpbnRfZGV2aWNlKHByb3h5LCBOVUxMKTsNCj4gPiArICAgICAgIH0N
Cj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9jb25maWcoY29uc3Qg
Y2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBybF9wcmludGYoIlN3aXRjaGluZyB0byBN
ZXNoIENsaWVudCBjb25maWd1cmF0aW9uIG1lbnVcbiIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlm
ICghc3dpdGNoX2NtZF9tZW51KCJjb25maWd1cmUiKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIHNldF9tZW51X3Byb21wdCgiY29uZmlnIiwgTlVMTCk7
DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGFyZyAmJiBzdHJsZW4oYXJnKSkNCj4gPiArICAgICAg
ICAgICAgICAgY29uZmlnX3NldF9ub2RlKGFyZyk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRp
YyB2b2lkIGNtZF9vbm9mZl9jbGkoY29uc3QgY2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAg
ICBybF9wcmludGYoIlN3aXRjaGluZyB0byBNZXNoIEdlbmVyaWMgT04gT0ZGIENsaWVudCBtZW51
XG4iKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXN3aXRjaF9jbWRfbWVudSgib25vZmYiKSkN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIHNldF9tZW51
X3Byb21wdCgib24vb2ZmIiwgTlVMTCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGFyZyAmJiBz
dHJsZW4oYXJnKSkNCj4gPiArICAgICAgICAgICAgICAgb25vZmZfc2V0X25vZGUoYXJnKTsNCj4g
PiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21kX3ByaW50X21lc2goY29uc3QgY2hhciAq
YXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoIXByb3ZfZGJfc2hvdyhtZXNoX3Byb3ZfZGJf
ZmlsZW5hbWUpKQ0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlVuYXZhaWxhYmxlXG4i
KTsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gKyBzdGF0aWMgdm9pZCBjbWRfcHJpbnRfbG9j
YWwoY29uc3QgY2hhciAqYXJnKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoIXByb3ZfZGJfc2hv
dyhtZXNoX2xvY2FsX2NvbmZpZ19maWxlbmFtZSkpDQo+ID4gKyAgICAgICAgICAgICAgIHJsX3By
aW50ZigiVW5hdmFpbGFibGVcbiIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBk
aXNjX3F1aXRfY2IoREJ1c01lc3NhZ2UgKm1lc3NhZ2UsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiAr
ew0KPiA+ICsgICAgICAgZ19tYWluX2xvb3BfcXVpdChtYWluX2xvb3ApOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRfcXVpdChjb25zdCBjaGFyICphcmcpDQo+ID4gK3sNCj4g
PiArICAgICAgIGlmIChjb25uZWN0aW9uLmRldmljZSkgew0KPiA+ICsgICAgICAgICAgICAgICBk
aXNjb25uZWN0X2RldmljZShkaXNjX3F1aXRfY2IsIE5VTEwpOw0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgZ19tYWluX2xvb3Bf
cXVpdChtYWluX2xvb3ApOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgY29uc3Qgc3RydWN0
IG1lbnVfZW50cnkgbWVzaGN0bF9jbWRfdGFibGVbXSA9IHsNCj4gPiArICAgICAgIHsgImxpc3Qi
LCAgICAgICAgIE5VTEwsICAgICAgIGNtZF9saXN0LCAiTGlzdCBhdmFpbGFibGUgY29udHJvbGxl
cnMifSwNCj4gPiArICAgICAgIHsgInNob3ciLCAgICAgICAgICJbY3RybF0iLCAgIGNtZF9zaG93
LCAiQ29udHJvbGxlciBpbmZvcm1hdGlvbiJ9LA0KPiA+ICsgICAgICAgeyAic2VsZWN0IiwgICAg
ICAgIjxjdHJsPiIsICAgY21kX3NlbGVjdCwgIlNlbGVjdCBkZWZhdWx0IGNvbnRyb2xsZXIifSwN
Cj4gPiArICAgICAgIHsgImluZm8iLCAgICAgICAgICJbZGV2XSIsICAgIGNtZF9pbmZvLCAiRGV2
aWNlIGluZm9ybWF0aW9uIn0sDQo+ID4gKyAgICAgICB7ICJjb25uZWN0IiwgICAgICAiW25ldF9p
ZHhdIixjbWRfY29ubmVjdCwgIkNvbm5lY3QgdG8gbWVzaA0KPiBuZXR3b3JrIn0sDQo+ID4gKyAg
ICAgICB7ICJkaXNjb3Zlci11bnByb3Zpc2lvbmVkIiwgIjxvbi9vZmY+IiwNCj4gY21kX3NjYW5f
dW5wcm92aXNpb25lZF9kZXZpY2VzLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAiTG9vayBmb3IgZGV2aWNlcyB0byBwcm92aXNpb24iIH0sDQo+ID4gKyAgICAg
ICB7ICJwcm92aXNpb24iLCAgICAiPHV1aWQ+IiwgICBjbWRfc3RhcnRfcHJvdiwgIkluaXRpYXRl
IHByb3Zpc2lvbmluZyJ9LA0KPiA+ICsgICAgICAgeyAicG93ZXIiLCAgICAgICAgIjxvbi9vZmY+
IiwgY21kX3Bvd2VyLCAiU2V0IGNvbnRyb2xsZXIgcG93ZXIiIH0sDQo+ID4gKyAgICAgICB7ICJk
aXNjb25uZWN0IiwgICAiW2Rldl0iLCAgICBjbWRfZGlzY29ubiwgIkRpc2Nvbm5lY3QgZGV2aWNl
In0sDQo+ID4gKyAgICAgICB7ICJtZXNoLWluZm8iLCAgICBOVUxMLCAgICAgICBjbWRfcHJpbnRf
bWVzaCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lc2gg
bmV0d29ya2luZm8gKHByb3Zpc2lvbmVyKSIgfSwNCj4gPiArICAgICAgIHsgImxvY2FsLWluZm8i
LCAgICBOVUxMLCAgICAgIGNtZF9wcmludF9sb2NhbCwgIkxvY2FsIG1lc2ggbm9kZSBpbmZvIiB9
LA0KPiA+ICsgICAgICAgeyAiY29uZmlndXJlIiwgICAgIltkc3RdIiwgICAgY21kX2NvbmZpZywg
IkNvbmZpZyBjbGllbnQgbW9kZWwgbWVudSJ9LA0KPiA+ICsgICAgICAgeyAib25vZmYiLCAgICAg
ICAgIltkc3RdIiwgICAgY21kX29ub2ZmX2NsaSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAiR2VuZXJpYyBPbi9PZmYgbW9kZWwgbWVudSJ9LA0K
PiA+ICsgICAgICAgeyAicXVpdCIsICAgICAgICAgTlVMTCwgICAgICAgY21kX3F1aXQsICJRdWl0
IHByb2dyYW0iIH0sDQo+ID4gKyAgICAgICB7ICJleGl0IiwgICAgICAgICBOVUxMLCAgICAgICBj
bWRfcXVpdCB9LA0KPiA+ICsgICAgICAgeyAiaGVscCIgfSwNCj4gPiArICAgICAgIHsgfQ0KPiA+
ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcmxfaGFuZGxlcihjaGFyICppbnB1dCkNCj4g
PiArew0KPiA+ICsgICAgICAgY2hhciAqY21kLCAqYXJnOw0KPiA+ICsNCj4gPiArICAgICAgIGlm
ICghaW5wdXQpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfaW5zZXJ0X3RleHQoInF1aXQiKTsN
Cj4gPiArICAgICAgICAgICAgICAgcmxfcmVkaXNwbGF5KCk7DQo+ID4gKyAgICAgICAgICAgICAg
IHJsX2NybGYoKTsNCj4gPiArICAgICAgICAgICAgICAgZ19tYWluX2xvb3BfcXVpdChtYWluX2xv
b3ApOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYgKCFzdHJsZW4oaW5wdXQpKQ0KPiA+ICsgICAgICAgICAgICAgICBnb3Rv
IGRvbmU7DQo+ID4gKyAgICAgICBlbHNlIGlmICghc3RyY21wKGlucHV0LCAicSIpIHx8ICFzdHJj
bXAoaW5wdXQsICJxdWl0IikNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICB8fCAhc3RyY21wKGlucHV0LCAiZXhpdCIpKSB7DQo+ID4gKyAgICAgICAg
ICAgICAgIGNtZF9xdWl0KE5VTEwpOw0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+
ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGFnZW50X2lucHV0KGlucHV0KSA9
PSBUUlVFKQ0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAg
ICAgYWRkX2hpc3RvcnkoaW5wdXQpOw0KPiA+ICsNCj4gPiArICAgICAgIGNtZCA9IHN0cnRva19y
KGlucHV0LCAiIFx0XHJcbiIsICZhcmcpOw0KPiA+ICsgICAgICAgaWYgKCFjbWQpDQo+ID4gKyAg
ICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBwcm9jZXNzX21lbnVf
Y21kKGNtZCwgYXJnKTsNCj4gPiArDQo+ID4gK2RvbmU6DQo+ID4gKyAgICAgICBmcmVlKGlucHV0
KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGdib29sZWFuIHNpZ25hbF9oYW5kbGVyKEdJ
T0NoYW5uZWwgKmNoYW5uZWwsIEdJT0NvbmRpdGlvbg0KPiBjb25kaXRpb24sDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncG9pbnRl
ciB1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0YXRpYyBib29sIHRlcm1pbmF0ZWQg
PSBmYWxzZTsNCj4gPiArICAgICAgIHN0cnVjdCBzaWduYWxmZF9zaWdpbmZvIHNpOw0KPiA+ICsg
ICAgICAgc3NpemVfdCByZXN1bHQ7DQo+ID4gKyAgICAgICBpbnQgZmQ7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKGNvbmRpdGlvbiAmIChHX0lPX05WQUwgfCBHX0lPX0VSUiB8IEdfSU9fSFVQKSkg
ew0KPiA+ICsgICAgICAgICAgICAgICBnX21haW5fbG9vcF9xdWl0KG1haW5fbG9vcCk7DQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBGQUxTRTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4g
KyAgICAgICBmZCA9IGdfaW9fY2hhbm5lbF91bml4X2dldF9mZChjaGFubmVsKTsNCj4gPiArDQo+
ID4gKyAgICAgICByZXN1bHQgPSByZWFkKGZkLCAmc2ksIHNpemVvZihzaSkpOw0KPiA+ICsgICAg
ICAgaWYgKHJlc3VsdCAhPSBzaXplb2Yoc2kpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4g
RkFMU0U7DQo+ID4gKw0KPiA+ICsgICAgICAgc3dpdGNoIChzaS5zc2lfc2lnbm8pIHsNCj4gPiAr
ICAgICAgIGNhc2UgU0lHSU5UOg0KPiA+ICsgICAgICAgICAgICAgICBpZiAoaW5wdXQpIHsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBybF9yZXBsYWNlX2xpbmUoIiIsIDApOw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIHJsX2NybGYoKTsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICBybF9vbl9uZXdfbGluZSgpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3Jl
ZGlzcGxheSgpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAg
ICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAvKg0KPiA+ICsgICAgICAg
ICAgICAgICAgKiBJZiBpbnB1dCB3YXMgbm90IHlldCBzZXR1cCB1cCB0aGF0IG1lYW5zIHNpZ25h
bCB3YXMgcmVjZWl2ZWQNCj4gPiArICAgICAgICAgICAgICAgICogd2hpbGUgZGFlbW9uIHdhcyBu
b3QgeWV0IHJ1bm5pbmcuIFNpbmNlIHVzZXIgaXMgbm90IGFibGUNCj4gPiArICAgICAgICAgICAg
ICAgICogdG8gdGVybWluYXRlIGNsaWVudCBieSBDVFJMLUQgb3IgdHlwaW5nIGV4aXQgdHJlYXQg
dGhpcyBhcw0KPiA+ICsgICAgICAgICAgICAgICAgKiBleGl0IGFuZCBmYWxsIHRocm91Z2guDQo+
ID4gKyAgICAgICAgICAgICAgICAqLw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogZmFs
bCB0aHJvdWdoICovDQo+ID4gKyAgICAgICBjYXNlIFNJR1RFUk06DQo+ID4gKyAgICAgICAgICAg
ICAgIGlmICghdGVybWluYXRlZCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3Jl
cGxhY2VfbGluZSgiIiwgMCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmxfY3JsZigp
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdfbWFpbl9sb29wX3F1aXQobWFpbl9sb29w
KTsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgdGVy
bWluYXRlZCA9IHRydWU7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAg
fQ0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBUUlVFOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtz
dGF0aWMgZ3VpbnQgc2V0dXBfc2lnbmFsZmQodm9pZCkNCj4gPiArew0KPiA+ICsgICAgICAgR0lP
Q2hhbm5lbCAqY2hhbm5lbDsNCj4gPiArICAgICAgIGd1aW50IHNvdXJjZTsNCj4gPiArICAgICAg
IHNpZ3NldF90IG1hc2s7DQo+ID4gKyAgICAgICBpbnQgZmQ7DQo+ID4gKw0KPiA+ICsgICAgICAg
c2lnZW1wdHlzZXQoJm1hc2spOw0KPiA+ICsgICAgICAgc2lnYWRkc2V0KCZtYXNrLCBTSUdJTlQp
Ow0KPiA+ICsgICAgICAgc2lnYWRkc2V0KCZtYXNrLCBTSUdURVJNKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAoc2lncHJvY21hc2soU0lHX0JMT0NLLCAmbWFzaywgTlVMTCkgPCAwKSB7DQo+ID4g
KyAgICAgICAgICAgICAgIHBlcnJvcigiRmFpbGVkIHRvIHNldCBzaWduYWwgbWFzayIpOw0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICBmZCA9IHNpZ25hbGZkKC0xLCAmbWFzaywgMCk7DQo+ID4gKyAgICAgICBpZiAoZmQgPCAw
KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHBlcnJvcigiRmFpbGVkIHRvIGNyZWF0ZSBzaWduYWwg
ZGVzY3JpcHRvciIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICBjaGFubmVsID0gZ19pb19jaGFubmVsX3VuaXhfbmV3KGZk
KTsNCj4gPiArDQo+ID4gKyAgICAgICBnX2lvX2NoYW5uZWxfc2V0X2Nsb3NlX29uX3VucmVmKGNo
YW5uZWwsIFRSVUUpOw0KPiA+ICsgICAgICAgZ19pb19jaGFubmVsX3NldF9lbmNvZGluZyhjaGFu
bmVsLCBOVUxMLCBOVUxMKTsNCj4gPiArICAgICAgIGdfaW9fY2hhbm5lbF9zZXRfYnVmZmVyZWQo
Y2hhbm5lbCwgRkFMU0UpOw0KPiA+ICsNCj4gPiArICAgICAgIHNvdXJjZSA9IGdfaW9fYWRkX3dh
dGNoKGNoYW5uZWwsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHX0lPX0lO
IHwgR19JT19IVVAgfCBHX0lPX0VSUiB8IEdfSU9fTlZBTCwNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHNpZ25hbF9oYW5kbGVyLCBOVUxMKTsNCj4gPiArDQo+ID4gKyAgICAg
ICBnX2lvX2NoYW5uZWxfdW5yZWYoY2hhbm5lbCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJu
IHNvdXJjZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGdib29sZWFuIG9wdGlvbl92ZXJz
aW9uID0gRkFMU0U7DQo+ID4gK3N0YXRpYyBjb25zdCBjaGFyICptZXNoX2NvbmZpZ19kaXI7DQo+
ID4gKw0KPiA+ICtzdGF0aWMgR09wdGlvbkVudHJ5IG9wdGlvbnNbXSA9IHsNCj4gPiArICAgICAg
IHsgImNvbmZpZyIsICdjJywgMCwgR19PUFRJT05fQVJHX1NUUklORywgJm1lc2hfY29uZmlnX2Rp
ciwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAiUmVhZCBsb2NhbCBtZXNoIGNvbmZpZyBK
U09OIGZpbGVzIGZyb20gPGRpcmVjdG9yeT4iIH0sDQo+ID4gKyAgICAgICB7ICJ2ZXJzaW9uIiwg
J3YnLCAwLCBHX09QVElPTl9BUkdfTk9ORSwgJm9wdGlvbl92ZXJzaW9uLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIlNob3cgdmVyc2lvbiBpbmZvcm1hdGlvbiBhbmQgZXhp
dCIgfSwNCj4gPiArICAgICAgIHsgTlVMTCB9LA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGlj
IHZvaWQgY2xpZW50X3JlYWR5KEdEQnVzQ2xpZW50ICpjbGllbnQsIHZvaWQgKnVzZXJfZGF0YSkN
Cj4gPiArew0KPiA+ICsgICAgICAgaWYgKCFpbnB1dCkNCj4gPiArICAgICAgICAgICAgICAgaW5w
dXQgPSBzZXR1cF9zdGFuZGFyZF9pbnB1dCgpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtpbnQgbWFp
bihpbnQgYXJnYywgY2hhciAqYXJndltdKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBHT3B0aW9uQ29u
dGV4dCAqY29udGV4dDsNCj4gPiArICAgICAgIEdFcnJvciAqZXJyb3IgPSBOVUxMOw0KPiA+ICsg
ICAgICAgR0RCdXNDbGllbnQgKmNsaWVudDsNCj4gPiArICAgICAgIGd1aW50IHNpZ25hbDsNCj4g
PiArICAgICAgIGludCBsZW47DQo+ID4gKyAgICAgICBpbnQgZXh0cmE7DQo+ID4gKw0KPiA+ICsg
ICAgICAgY29udGV4dCA9IGdfb3B0aW9uX2NvbnRleHRfbmV3KE5VTEwpOw0KPiA+ICsgICAgICAg
Z19vcHRpb25fY29udGV4dF9hZGRfbWFpbl9lbnRyaWVzKGNvbnRleHQsIG9wdGlvbnMsIE5VTEwp
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmIChnX29wdGlvbl9jb250ZXh0X3BhcnNlKGNvbnRleHQs
ICZhcmdjLCAmYXJndiwgJmVycm9yKSA9PSBGQUxTRSkgew0KPiA+ICsgICAgICAgICAgICAgICBp
ZiAoZXJyb3IgIT0gTlVMTCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdfcHJpbnRl
cnIoIiVzXG4iLCBlcnJvci0+bWVzc2FnZSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
Z19lcnJvcl9mcmVlKGVycm9yKTsNCj4gPiArICAgICAgICAgICAgICAgfSBlbHNlDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgZ19wcmludGVycigiQW4gdW5rbm93biBlcnJvciBvY2N1cnJl
ZFxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIGV4aXQoMSk7DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgZ19vcHRpb25fY29udGV4dF9mcmVlKGNvbnRleHQpOw0KPiA+ICsNCj4g
PiArICAgICAgIGlmIChvcHRpb25fdmVyc2lvbiA9PSBUUlVFKSB7DQo+ID4gKyAgICAgICAgICAg
ICAgIHJsX3ByaW50ZigiJXNcbiIsIFZFUlNJT04pOw0KPiA+ICsgICAgICAgICAgICAgICBleGl0
KDApOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbWVzaF9jb25maWdf
ZGlyKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiTG9jYWwgY29uZmlnIGRpcmVj
dG9yeSBub3QgcHJvdmlkZWQuXG4iKTsNCj4gPiArICAgICAgICAgICAgICAgbWVzaF9jb25maWdf
ZGlyID0gIiI7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBybF9w
cmludGYoIlJlYWRpbmcgcHJvdl9kYi5qc29uIGFuZCBsb2NhbF9ub2RlLmpzb24gZnJvbSAlc1xu
IiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIG1lc2hfY29uZmlnX2Rpcik7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAg
ICAgbGVuID0gc3RybGVuKG1lc2hfY29uZmlnX2Rpcik7DQo+ID4gKyAgICAgICBpZiAobGVuICYm
IG1lc2hfY29uZmlnX2RpcltsZW4gLSAxXSAhPSAnLycpIHsNCj4gPiArICAgICAgICAgICAgICAg
ZXh0cmEgPSAxOw0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIm1lc2hfY29uZmlnX2Rp
clslZF0gJXNcbiIsIGxlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAmbWVzaF9jb25maWdfZGlyW2xlbiAtIDFdKTsNCj4gPiArICAgICAgIH0g
ZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIGV4dHJhID0gMDsNCj4gPiArICAgICAgIH0NCj4g
PiArICAgICAgIG1lc2hfbG9jYWxfY29uZmlnX2ZpbGVuYW1lID0gZ19tYWxsb2MobGVuICsNCj4g
c3RybGVuKCJsb2NhbF9ub2RlLmpzb24iKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgMik7DQo+ID4g
KyAgICAgICBpZiAoIW1lc2hfbG9jYWxfY29uZmlnX2ZpbGVuYW1lKQ0KPiA+ICsgICAgICAgICAg
ICAgICBleGl0KDEpOw0KPiA+ICsNCj4gPiArICAgICAgIG1lc2hfcHJvdl9kYl9maWxlbmFtZSA9
IGdfbWFsbG9jKGxlbiArIHN0cmxlbigicHJvdl9kYi5qc29uIikgKw0KPiAyKTsNCj4gPiArICAg
ICAgIGlmICghbWVzaF9wcm92X2RiX2ZpbGVuYW1lKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGV4
aXQoMSk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgc3ByaW50ZihtZXNoX2xv
Y2FsX2NvbmZpZ19maWxlbmFtZSwgIiVzIiwgbWVzaF9jb25maWdfZGlyKTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoZXh0cmEpDQo+ID4gKyAgICAgICAgICAgICAgIHNwcmludGYobWVzaF9sb2Nh
bF9jb25maWdfZmlsZW5hbWUgKyBsZW4gLCAiJWMiLCAnLycpOw0KPiA+ICsNCj4gPiArICAgICAg
IHNwcmludGYobWVzaF9sb2NhbF9jb25maWdfZmlsZW5hbWUgKyBsZW4gKyBleHRyYSwgIiVzIiwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICJsb2NhbF9ub2RlLmpzb24iKTsNCj4gPiArICAgICAgIGxlbiA9IGxlbiArIGV4dHJhICsg
c3RybGVuKCJsb2NhbF9ub2RlLmpzb24iKTsNCj4gPiArICAgICAgIHNwcmludGYobWVzaF9sb2Nh
bF9jb25maWdfZmlsZW5hbWUgKyBsZW4sICIlYyIsICdcMCcpOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmICghcHJvdl9kYl9yZWFkX2xvY2FsX25vZGUobWVzaF9sb2NhbF9jb25maWdfZmlsZW5hbWUs
IHRydWUpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGdfcHJpbnRlcnIoIkZhaWxlZCB0byBwYXJz
ZSBsb2NhbCBub2RlIGNvbmZpZ3VyYXRpb24gZmlsZSAlc1xuIiwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBtZXNoX2xvY2FsX2NvbmZpZ19maWxlbmFtZSk7DQo+ID4gKyAgICAgICAgICAg
ICAgIGV4aXQoMSk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgc3ByaW50Ziht
ZXNoX3Byb3ZfZGJfZmlsZW5hbWUsICIlcyIsIG1lc2hfY29uZmlnX2Rpcik7DQo+ID4gKyAgICAg
ICBsZW4gPSBzdHJsZW4obWVzaF9jb25maWdfZGlyKTsNCj4gPiArICAgICAgIGlmIChleHRyYSkN
Cj4gPiArICAgICAgICAgICAgICAgc3ByaW50ZihtZXNoX3Byb3ZfZGJfZmlsZW5hbWUgKyBsZW4g
LCAiJWMiLCAnLycpOw0KPiA+ICsNCj4gPiArICAgICAgIHNwcmludGYobWVzaF9wcm92X2RiX2Zp
bGVuYW1lICsgbGVuICsgZXh0cmEsICIlcyIsICJwcm92X2RiLmpzb24iKTsNCj4gPiArICAgICAg
IHNwcmludGYobWVzaF9wcm92X2RiX2ZpbGVuYW1lICsgbGVuICsgZXh0cmEgKw0KPiBzdHJsZW4o
InByb3ZfZGIuanNvbiIpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJWMiLCAnXDAnKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAoIXByb3ZfZGJfcmVhZChtZXNoX3Byb3ZfZGJfZmlsZW5hbWUpKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIGdfcHJpbnRlcnIoIkZhaWxlZCB0byBwYXJzZSBwcm92aXNpb25pbmcgZGF0
YWJhc2UgZmlsZSAlc1xuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtZXNoX3Byb3Zf
ZGJfZmlsZW5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICBleGl0KDEpOw0KPiA+ICsgICAgICAg
fQ0KPiA+ICsNCj4gPiArICAgICAgIG1haW5fbG9vcCA9IGdfbWFpbl9sb29wX25ldyhOVUxMLCBG
QUxTRSk7DQo+ID4gKyAgICAgICBkYnVzX2Nvbm4gPSBnX2RidXNfc2V0dXBfYnVzKERCVVNfQlVT
X1NZU1RFTSwgTlVMTCwgTlVMTCk7DQo+ID4gKw0KPiA+ICsgICAgICAgc2V0bGluZWJ1ZihzdGRv
dXQpOw0KPiA+ICsNCj4gPiArICAgICAgIHJsX2VyYXNlX2VtcHR5X2xpbmUgPSAxOw0KPiA+ICsg
ICAgICAgcmxfY2FsbGJhY2tfaGFuZGxlcl9pbnN0YWxsKE5VTEwsIHJsX2hhbmRsZXIpOw0KPiA+
ICsNCj4gPiArICAgICAgIHJsX3NldF9wcm9tcHQoUFJPTVBUX09GRik7DQo+ID4gKyAgICAgICBy
bF9yZWRpc3BsYXkoKTsNCj4gPiArDQo+ID4gKyAgICAgICBzaWduYWwgPSBzZXR1cF9zaWduYWxm
ZCgpOw0KPiA+ICsgICAgICAgY2xpZW50ID0gZ19kYnVzX2NsaWVudF9uZXcoZGJ1c19jb25uLCAi
b3JnLmJsdWV6IiwgIi9vcmcvYmx1ZXoiKTsNCj4gPiArDQo+ID4gKyAgICAgICBnX2RidXNfY2xp
ZW50X3NldF9jb25uZWN0X3dhdGNoKGNsaWVudCwgY29ubmVjdF9oYW5kbGVyLCBOVUxMKTsNCj4g
PiArICAgICAgIGdfZGJ1c19jbGllbnRfc2V0X2Rpc2Nvbm5lY3Rfd2F0Y2goY2xpZW50LCBkaXNj
b25uZWN0X2hhbmRsZXIsDQo+IE5VTEwpOw0KPiA+ICsgICAgICAgZ19kYnVzX2NsaWVudF9zZXRf
c2lnbmFsX3dhdGNoKGNsaWVudCwgbWVzc2FnZV9oYW5kbGVyLCBOVUxMKTsNCj4gPiArDQo+ID4g
KyAgICAgICBnX2RidXNfY2xpZW50X3NldF9wcm94eV9oYW5kbGVycyhjbGllbnQsIHByb3h5X2Fk
ZGVkLA0KPiBwcm94eV9yZW1vdmVkLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHlfY2hhbmdlZCwgTlVMTCk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgZ19kYnVzX2NsaWVudF9zZXRfcmVhZHlfd2F0Y2goY2xpZW50LCBjbGll
bnRfcmVhZHksIE5VTEwpOw0KPiA+ICsNCj4gPiArICAgICAgIGNtZF9tZW51X2luaXQobWVzaGN0
bF9jbWRfdGFibGUpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghY29uZmlnX2NsaWVudF9pbml0
KCkpDQo+ID4gKyAgICAgICAgICAgICAgIGdfcHJpbnRlcnIoIkZhaWxlZCB0byBpbml0aWFsaXpl
IG1lc2ggY29uZmlndXJhdGlvbiBjbGllbnRcbiIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICgh
Y29uZmlnX3NlcnZlcl9pbml0KCkpDQo+ID4gKyAgICAgICAgICAgICAgIGdfcHJpbnRlcnIoIkZh
aWxlZCB0byBpbml0aWFsaXplIG1lc2ggY29uZmlndXJhdGlvbiBzZXJ2ZXJcbiIpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmICghb25vZmZfY2xpZW50X2luaXQoUFJJTUFSWV9FTEVNRU5UX0lEWCkp
DQo+ID4gKyAgICAgICAgICAgICAgIGdfcHJpbnRlcnIoIkZhaWxlZCB0byBpbml0aWFsaXplIG1l
c2ggZ2VuZXJpYyBPbi9PZmYgY2xpZW50XG4iKTsNCj4gPiArDQo+ID4gKyAgICAgICBnX21haW5f
bG9vcF9ydW4obWFpbl9sb29wKTsNCj4gPiArDQo+ID4gKyAgICAgICBnX2RidXNfY2xpZW50X3Vu
cmVmKGNsaWVudCk7DQo+ID4gKyAgICAgICBnX3NvdXJjZV9yZW1vdmUoc2lnbmFsKTsNCj4gPiAr
ICAgICAgIGlmIChpbnB1dCA+IDApDQo+ID4gKyAgICAgICAgICAgICAgIGdfc291cmNlX3JlbW92
ZShpbnB1dCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfbWVzc2FnZSgiIik7DQo+ID4gKyAgICAg
ICBybF9jYWxsYmFja19oYW5kbGVyX3JlbW92ZSgpOw0KPiA+ICsNCj4gPiArICAgICAgIGRidXNf
Y29ubmVjdGlvbl91bnJlZihkYnVzX2Nvbm4pOw0KPiA+ICsgICAgICAgZ19tYWluX2xvb3BfdW5y
ZWYobWFpbl9sb29wKTsNCj4gPiArDQo+ID4gKyAgICAgICBub2RlX2NsZWFudXAoKTsNCj4gPiAr
DQo+ID4gKyAgICAgICBnX2xpc3RfZnJlZShjaGFyX2xpc3QpOw0KPiA+ICsgICAgICAgZ19saXN0
X2ZyZWUoc2VydmljZV9saXN0KTsNCj4gPiArICAgICAgIGdfbGlzdF9mcmVlX2Z1bGwoY3RybF9s
aXN0LCBwcm94eV9sZWFrKTsNCj4gPiArDQo+ID4gKyAgICAgICBhZ2VudF9yZWxlYXNlKCk7DQo+
ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIDA7DQo+ID4gK30NCj4gPiBkaWZmIC0tZ2l0IGEvbWVz
aC9uZXQuYyBiL21lc2gvbmV0LmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGluZGV4
IDAwMDAwMDAuLmZiMmQyMDANCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvbWVzaC9uZXQu
Yw0KPiA+IEBAIC0wLDAgKzEsMjE4NCBAQA0KPiA+ICsvKg0KPiA+ICsgKg0KPiA+ICsgKiAgQmx1
ZVogLSBCbHVldG9vdGggcHJvdG9jb2wgc3RhY2sgZm9yIExpbnV4DQo+ID4gKyAqDQo+ID4gKyAq
ICBDb3B5cmlnaHQgKEMpIDIwMTcgIEludGVsIENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2Vy
dmVkLg0KPiA+ICsgKg0KPiA+ICsgKg0KPiA+ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29m
dHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcg0KPiA+ICsgKiAgbW9kaWZ5IGl0
IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsg
KiAgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsg
ZWl0aGVyDQo+ID4gKyAqICB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIg
b3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4gPiArICoNCj4gPiArICogIFRoaXMgbGlicmFy
eSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLA0KPiA+
ICsgKiAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQg
d2FycmFudHkgb2YNCj4gPiArICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBB
UlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUNCj4gR05VDQo+ID4gKyAqICBMZXNzZXIgR2VuZXJh
bCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLg0KPiA+ICsgKg0KPiA+ICsgKiAgWW91
IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1
YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3
cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQ0KPiA+ICsgKiAgRm91bmRhdGlvbiwgSW5jLiwgNTEg
RnJhbmtsaW4gU3QsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxDQo+IFVTQQ0K
PiA+ICsgKg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gKyNpZmRlZiBIQVZFX0NPTkZJR19IDQo+ID4g
KyNpbmNsdWRlIDxjb25maWcuaD4NCj4gPiArI2VuZGlmDQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8
aW50dHlwZXMuaD4NCj4gPiArI2luY2x1ZGUgPGN0eXBlLmg+DQo+ID4gKyNpbmNsdWRlIDxzdGRi
b29sLmg+DQo+ID4gKyNpbmNsdWRlIDxzdGRpby5oPg0KPiA+ICsjaW5jbHVkZSA8c3RyaW5nLmg+
DQo+ID4gKyNpbmNsdWRlIDxnbGliLmg+DQo+ID4gKw0KPiA+ICsjaW5jbHVkZSAic3JjL3NoYXJl
ZC91dGlsLmgiDQo+ID4gKyNpbmNsdWRlICJjbGllbnQvZGlzcGxheS5oIg0KPiA+ICsNCj4gPiAr
I2luY2x1ZGUgImNyeXB0by5oIg0KPiA+ICsjaW5jbHVkZSAiZ2F0dC5oIg0KPiA+ICsjaW5jbHVk
ZSAibWVzaC1uZXQuaCINCj4gPiArI2luY2x1ZGUgInV0aWwuaCINCj4gPiArI2luY2x1ZGUgImtl
eXMuaCINCj4gPiArI2luY2x1ZGUgIm5vZGUuaCINCj4gPiArI2luY2x1ZGUgInByb3YtZGIuaCIN
Cj4gPiArI2luY2x1ZGUgIm5ldC5oIg0KPiA+ICsNCj4gPiArc3RydWN0IGFkZHJlc3NfcmFuZ2UN
Cj4gPiArew0KPiA+ICsgICAgICAgdWludDE2X3QgbWluOw0KPiA+ICsgICAgICAgdWludDE2X3Qg
bWF4Ow0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IG1lc2hfbmV0IHsNCj4gPiArICAgICAg
IHVpbnQzMl90IGl2X2luZGV4Ow0KPiA+ICsgICAgICAgdWludDMyX3Qgc2VxX251bTsNCj4gPiAr
ICAgICAgIHVpbnQzMl90IHNlcV9udW1fcmVzZXJ2ZWQ7DQo+ID4gKyAgICAgICB1aW50MTZfdCBw
cmltYXJ5X2FkZHI7DQo+ID4gKyAgICAgICB1aW50OF90IGl2X3VwZF9zdGF0ZTsNCj4gPiArICAg
ICAgIHVpbnQ4X3QgbnVtX2VsZW1lbnRzOw0KPiA+ICsgICAgICAgdWludDhfdCBkZWZhdWx0X3R0
bDsNCj4gPiArICAgICAgIGJvb2wgaXZfdXBkYXRlOw0KPiA+ICsgICAgICAgYm9vbCBwcm92aXNp
b25lcjsNCj4gPiArICAgICAgIGJvb2wgYmxhY2tsaXN0Ow0KPiA+ICsgICAgICAgZ3VpbnQgaXZf
dXBkYXRlX3RpbWVvdXQ7DQo+ID4gKyAgICAgICBHREJ1c1Byb3h5ICpwcm94eV9pbjsNCj4gPiAr
ICAgICAgIEdMaXN0ICphZGRyZXNzX3Bvb2w7DQo+ID4gKyAgICAgICBHTGlzdCAqZGVzdDsgICAg
LyogTGlzdCBvZiB2YWxpZCBsb2NhbCBkZXN0aW5hdGlvbnMgZm9yIFdoaXRlbGlzdCAqLw0KPiA+
ICsgICAgICAgR0xpc3QgKnNhcl9pbjsgIC8qIEluY29taW5nIHNlZ21lbnRlZCBtZXNzYWdlcyBp
biBwcm9ncmVzcyAqLw0KPiA+ICsgICAgICAgR0xpc3QgKm1zZ19vdXQ7IC8qIFByZS1OZXR3b3Jr
IGVuY29kZWQsIG1pZ2h0IGJlIG11bHRpLXNlZ21lbnQgKi8NCj4gPiArICAgICAgIEdMaXN0ICpw
a3Rfb3V0OyAvKiBGdWxseSBlbmNvZGVkIHBhY2tldHMgYXdhaXRpbmcgVHggaW4gb3JkZXIgKi8N
Cj4gPiArICAgICAgIG5ldF9tZXNoX3Nlc3Npb25fb3Blbl9jYWxsYmFjayBvcGVuX2NiOw0KPiA+
ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IGdlbmVyaWNfa2V5IHsNCj4gPiArICAgICAgIHVpbnQx
Nl90ICAgICAgICBpZHg7DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdHJ1Y3QgbmV0X2tleV9wYXJ0
cyB7DQo+ID4gKyAgICAgICB1aW50OF90IG5pZDsNCj4gPiArICAgICAgIHVpbnQ4X3QgZW5jX2tl
eVsxNl07DQo+ID4gKyAgICAgICB1aW50OF90IHByaXZhY3lfa2V5WzE2XTsNCj4gPiArICAgICAg
IHVpbnQ4X3QgbmV0X2tleVsxNl07DQo+ID4gKyAgICAgICB1aW50OF90IGJlYWNvbl9rZXlbMTZd
Ow0KPiA+ICsgICAgICAgdWludDhfdCBuZXRfaWRbOF07DQo+ID4gK307DQo+ID4gKw0KPiA+ICtz
dHJ1Y3QgbWVzaF9uZXRfa2V5IHsNCj4gPiArICAgICAgIHN0cnVjdCBnZW5lcmljX2tleSAgICAg
IGdlbmVyaWM7DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAgICAgICAgICAgICBwaGFzZTsNCj4g
PiArICAgICAgIHN0cnVjdCBuZXRfa2V5X3BhcnRzICAgIGN1cnJlbnQ7DQo+ID4gKyAgICAgICBz
dHJ1Y3QgbmV0X2tleV9wYXJ0cyAgICBuZXc7DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdHJ1Y3Qg
YXBwX2tleV9wYXJ0cyB7DQo+ID4gKyAgICAgICB1aW50OF90IGtleVsxNl07DQo+ID4gKyAgICAg
ICB1aW50OF90IGFrZl9haWQ7DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdHJ1Y3QgbWVzaF9hcHBf
a2V5IHsNCj4gPiArICAgICAgIHN0cnVjdCBnZW5lcmljX2tleSAgICAgIGdlbmVyaWM7DQo+ID4g
KyAgICAgICB1aW50MTZfdCAgICAgICAgICAgICAgICBuZXRfaWR4Ow0KPiA+ICsgICAgICAgc3Ry
dWN0IGFwcF9rZXlfcGFydHMgICAgY3VycmVudDsNCj4gPiArICAgICAgIHN0cnVjdCBhcHBfa2V5
X3BhcnRzICAgIG5ldzsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0cnVjdCBtZXNoX3ZpcnRfYWRk
ciB7DQo+ID4gKyAgICAgICB1aW50MTZfdCAgICAgICAgdmExNjsNCj4gPiArICAgICAgIHVpbnQz
Ml90ICAgICAgICB2YTMyOw0KPiA+ICsgICAgICAgdWludDhfdCAgICAgICAgIHZhMTI4WzE2XTsN
Cj4gPiArfTsNCj4gPiArDQo+ID4gK3N0cnVjdCBtZXNoX3BrdCB7DQo+ID4gKyAgICAgICB1aW50
OF90ICAgICAgICAgZGF0YVszMF07DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAgICAgbGVuOw0K
PiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IG1lc2hfc2FyX21zZyB7DQo+ID4gKyAgICAgICBn
dWludCAgICAgICAgICAgYWNrX3RvOw0KPiA+ICsgICAgICAgZ3VpbnQgICAgICAgICAgIG1zZ190
bzsNCj4gPiArICAgICAgIHVpbnQzMl90ICAgICAgICBpdl9pbmRleDsNCj4gPiArICAgICAgIHVp
bnQzMl90ICAgICAgICBzZXFBdXRoOw0KPiA+ICsgICAgICAgdWludDMyX3QgICAgICAgIGFjazsN
Cj4gPiArICAgICAgIHVpbnQzMl90ICAgICAgICBkc3Q7DQo+ID4gKyAgICAgICB1aW50MTZfdCAg
ICAgICAgc3JjOw0KPiA+ICsgICAgICAgdWludDE2X3QgICAgICAgIG5ldF9pZHg7DQo+ID4gKyAg
ICAgICB1aW50MTZfdCAgICAgICAgbGVuOw0KPiA+ICsgICAgICAgdWludDhfdCAgICAgICAgIGFr
Zl9haWQ7DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAgICAgdHRsOw0KPiA+ICsgICAgICAgdWlu
dDhfdCAgICAgICAgIHNlZ047DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAgICAgYWN0aXZpdHlf
Y250Ow0KPiA+ICsgICAgICAgYm9vbCAgICAgICAgICAgIGN0bDsNCj4gPiArICAgICAgIGJvb2wg
ICAgICAgICAgICBzZWdtZW50ZWQ7DQo+ID4gKyAgICAgICBib29sICAgICAgICAgICAgc3ptaWM7
DQo+ID4gKyAgICAgICBib29sICAgICAgICAgICAgcHJveHk7DQo+ID4gKyAgICAgICB1aW50OF90
ICAgICAgICAgZGF0YVsyMF07IC8qIE9wZW4gZW5kZWQsIG1pbiAyMCAqLw0KPiA+ICt9Ow0KPiA+
ICsNCj4gPiArc3RydWN0IG1lc2hfZGVzdGluYXRpb24gew0KPiA+ICsgICAgICAgdWludDE2X3Qg
ICAgICAgIGNudDsNCj4gPiArICAgICAgIHVpbnQxNl90ICAgICAgICBkc3Q7DQo+ID4gK307DQo+
ID4gKw0KPiA+ICsvKiBOZXR3b3JrIFBhY2tldCBMYXllciBiYXNlZCBPZmZzZXRzICovDQo+ID4g
KyNkZWZpbmUgQUtGX0JJVCAgICAgICAgICAgICAgICAgICAgICAgIDB4NDANCj4gPiArDQo+ID4g
KyNkZWZpbmUgUEtUX0lWSShwKSAgICAgICAgICAgICAhISgocClbMF0gJiAweDgwKQ0KPiA+ICsj
ZGVmaW5lIFNFVF9QS1RfSVZJKHAsdikgICAgICAgZG8geyhwKVswXSAmPSAweDdmOyBcDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwKVswXSB8PSAoKHYpID8g
MHg4MCA6IDApO30gd2hpbGUoMCkNCj4gPiArI2RlZmluZSBQS1RfTklEKHApICAgICAgICAgICAg
ICgocClbMF0gJiAweDdmKQ0KPiA+ICsjZGVmaW5lIFNFVF9QS1RfTklEKHAsdikgICAgICAgZG8g
eyhwKVswXSAmPSAweDgwOyAocClbMF0gfD0gKHYpO30gd2hpbGUoMCkNCj4gPiArI2RlZmluZSBQ
S1RfQ1RMKHApICAgICAgICAgICAgICghISgocClbMV0gJiAweDgwKSkNCj4gPiArI2RlZmluZSBT
RVRfUEtUX0NUTChwLHYpICAgICAgIGRvIHsocClbMV0gJj0gMHg3ZjsgXA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocClbMV0gfD0gKCh2KSA/IDB4ODAgOiAw
KTt9IHdoaWxlKDApDQo+ID4gKyNkZWZpbmUgUEtUX1RUTChwKSAgICAgICAgICAgICAoKHApWzFd
ICYgMHg3ZikNCj4gPiArI2RlZmluZSBTRVRfUEtUX1RUTChwLHYpICAgICAgIGRvIHsocClbMV0g
Jj0gMHg4MDsgKHApWzFdIHw9ICh2KTt9IHdoaWxlKDApDQo+ID4gKyNkZWZpbmUgUEtUX1NFUShw
KSAgICAgICAgICAgICAoZ2V0X2JlMzIoKHApICsgMSkgJiAweGZmZmZmZikNCj4gPiArI2RlZmlu
ZSBTRVRfUEtUX1NFUShwLHYpICAgICAgIHB1dF9iZTMyKCgocClbMV0gPDwgMjQpICsgKCh2KSAm
IDB4ZmZmZmZmKSwgXA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwKSArIDEpDQo+ID4gKyNkZWZpbmUg
UEtUX1NSQyhwKSAgICAgICAgICAgICBnZXRfYmUxNigocCkgKyA1KQ0KPiA+ICsjZGVmaW5lIFNF
VF9QS1RfU1JDKHAsdikgICAgICAgcHV0X2JlMTYodiwgKHApICsgNSkNCj4gPiArI2RlZmluZSBQ
S1RfRFNUKHApICAgICAgICAgICAgIGdldF9iZTE2KChwKSArIDcpDQo+ID4gKyNkZWZpbmUgU0VU
X1BLVF9EU1QocCx2KSAgICAgICBwdXRfYmUxNih2LCAocCkgKyA3KQ0KPiA+ICsjZGVmaW5lIFBL
VF9UUkFOUyhwKSAgICAgICAgICAgKChwKSArIDkpDQo+ID4gKyNkZWZpbmUgUEtUX1RSQU5TX0xF
TihsKSAgICAgICAoKGwpIC0gOSkNCj4gPiArDQo+ID4gKyNkZWZpbmUgUEtUX1NFR01FTlRFRChw
KSAgICAgICAoISEoKHApWzldICYgMHg4MCkpDQo+ID4gKyNkZWZpbmUgU0VUX1BLVF9TRUdNRU5U
RUQocCx2KSBkbyB7KHApWzldICY9IDB4N2Y7IFwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgKHApWzldIHw9ICgodikgPyAweDgwIDogMCk7fSB3aGlsZSgwKQ0K
PiA+ICsjZGVmaW5lIFBLVF9BS0ZfQUlEKHApICAgICAgICAgKChwKVs5XSAmIDB4N2YpDQo+ID4g
KyNkZWZpbmUgU0VUX1BLVF9BS0ZfQUlEKHAsdikgICBkbyB7KHApWzldICY9IDB4ODA7IChwKVs5
XSB8PSAodik7fQ0KPiB3aGlsZSgwKQ0KPiA+ICsjZGVmaW5lIFBLVF9PUENPREUocCkgICAgICAg
ICAgKChwKVs5XSAmIDB4N2YpDQo+ID4gKyNkZWZpbmUgU0VUX1BLVF9PUENPREUocCx2KSAgICBk
byB7KHApWzldICY9IDB4ODA7IChwKVs5XSB8PSAodik7fQ0KPiB3aGlsZSgwKQ0KPiA+ICsjZGVm
aW5lIFBLVF9PQk8ocCkgICAgICAgICAgICAgKCEhKChwKVsxMF0gJiAweDgwKSkNCj4gPiArI2Rl
ZmluZSBQS1RfU1pNSUMocCkgICAgICAgICAgICghIShQS1RfU0VHTUVOVEVEKHApID8gKChwKVsx
MF0gJiAweDQwKSA6DQo+IDApKQ0KPiA+ICsjZGVmaW5lIFNFVF9QS1RfU1pNSUMocCx2KSAgICAg
ZG8geyhwKVsxMF0gJj0gMHg3ZjsgXA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAocClbMTBdIHw9ICgodikgPyAweDgwIDogMCk7fSB3aGlsZSgwKQ0KPiA+ICsj
ZGVmaW5lIFBLVF9TRVEwKHApICAgICAgICAgICAgKChnZXRfYmUxNigocCkgKyAxMCkgPj4gMikg
JiAweDFmZmYpDQo+ID4gKyNkZWZpbmUgU0VUX1BLVF9TRVEwKHAsdikgICAgICBkbyB7cHV0X2Jl
MTYoKGdldF9iZTE2KChwKSArIDEwKSAmDQo+IDB4ODAwMykgXA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICB8ICgoKHYpICYgMHgxZmZmKSA8PCAyKSwgXA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocCkgKyAxMCk7fSB3aGls
ZSgwKQ0KPiA+ICsjZGVmaW5lIFNFVF9QS1RfU0VHTyhwLHYpICAgICAgZG8ge3B1dF9iZTE2KChn
ZXRfYmUxNiggXA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAo
cCkgKyAxMSkgJiAweGZjMWYpIHwgKCh2KSA8PCA1KSwgXA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAocCkgKyAxMSk7fSB3aGlsZSgwKQ0KPiA+ICsjZGVmaW5l
IFNFVF9QS1RfU0VHTihwLHYpICAgICAgZG8geyhwKVsxMl0gPSAoKHApWzEyXSAmIDB4ZTApIHwg
KHYpO30NCj4gd2hpbGUoMCkNCj4gPiArI2RlZmluZSBQS1RfQUNLKHApICAgICAgICAgICAgIChn
ZXRfYmUzMigocCkgKyAxMikpDQo+ID4gKyNkZWZpbmUgU0VUX1BLVF9BQ0socCx2KSAgICAgICAo
cHV0X2JlMzIoKHYpKHApICsgMTIpKQ0KPiA+ICsNCj4gPiArLyogVHJhbnNwb3J0IExheWVyIGJh
c2VkIG9mZnNldHMgKi8NCj4gPiArI2RlZmluZSBUUkFOU19TRUdNRU5URUQodCkgICAgICghISgo
dClbMF0gJiAweDgwKSkNCj4gPiArI2RlZmluZSBTRVRfVFJBTlNfU0VHTUVOVEQodCx2KSAgICAg
ICAgZG8geyh0KVswXSAmPSAweDdmOyBcDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICh0KVswXSB8PSAoKHYpID8gMHg4MCA6IDApO30gd2hpbGUoMCkNCj4gPiAr
I2RlZmluZSBUUkFOU19PUENPREUodCkgICAgICAgICAgICAgICAgKCh0KVswXSAmIDB4N2YpDQo+
ID4gKyNkZWZpbmUgU0VUX1RSQU5TX09QQ09ERSh0LHYpICBkbyB7KHQpWzBdICY9IDB4ODA7ICh0
KVswXSB8PSAodik7fQ0KPiB3aGlsZSgwKQ0KPiA+ICsjZGVmaW5lIFRSQU5TX0FLRl9BSUQodCkg
ICAgICAgICAgICAgICAoKHQpWzBdICYgMHg3ZikNCj4gPiArI2RlZmluZSBTRVRfVFJBTlNfQUtG
X0FJRCh0LHYpIGRvIHsodClbMF0gJj0gMHhjMDsgKHQpWzBdIHw9ICh2KTt9DQo+IHdoaWxlKDAp
DQo+ID4gKyNkZWZpbmUgVFJBTlNfQUtGKHQpICAgICAgICAgICAoISEoKHQpWzBdICYgQUtGX0JJ
VCkpDQo+ID4gKyNkZWZpbmUgVFJBTlNfU1pNSUModCkgICAgICAgICAoISEoVFJBTlNfU0VHTUVO
VEVEKHQpID8gKCh0KVsxXSAmIDB4ODApIDoNCj4gMCkpDQo+ID4gKyNkZWZpbmUgVFJBTlNfU0VR
MCh0KSAgICAgICAgICAoKGdldF9iZTE2KCh0KSArIDEpID4+IDIpICYgMHgxZmZmKQ0KPiA+ICsj
ZGVmaW5lIFNFVF9UUkFOU19TRVEwKHQsdikgICAgZG8ge3B1dF9iZTE2KChnZXRfYmUxNigodCkg
KyAxKSAmDQo+IDB4ODAwMykgXA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICB8ICgoKHYpICYgMHgxZmZmKSA8PCAyKSwgXA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAodCkgKyAxKTt9IHdoaWxlKDApDQo+ID4gKyNkZWZpbmUg
U0VUX1RSQU5TX0FDSyh0LHYpICAgICBwdXRfYmUzMigodiksICh0KSArIDMpDQo+ID4gKyNkZWZp
bmUgVFJBTlNfU0VHTyh0KSAgICAgICAgICAoKGdldF9iZTE2KCh0KSArIDIpID4+IDUpICYgMHgx
ZikNCj4gPiArI2RlZmluZSBUUkFOU19TRUdOKHQpICAgICAgICAgICgodClbM10gJiAweDFmKQ0K
PiA+ICsNCj4gPiArI2RlZmluZSBUUkFOU19QQVlMT0FEKHQpICAgICAgICgodCkgKyAoVFJBTlNf
U0VHTUVOVEVEKHQpID8gNCA6IDEpKQ0KPiA+ICsjZGVmaW5lIFRSQU5TX0xFTih0LGwpICAgICAg
ICAgKChsKSAtKFRSQU5TX1NFR01FTlRFRCh0KSA/IDQgOiAxKSkNCj4gPiArDQo+ID4gKy8qIFBy
b3h5IENvbmZpZyBPcGNvZGVzICovDQo+ID4gKyNkZWZpbmUgRklMVEVSX1NFVFVQICAgICAgICAg
ICAweDAwDQo+ID4gKyNkZWZpbmUgRklMVEVSX0FERCAgICAgICAgICAgICAweDAxDQo+ID4gKyNk
ZWZpbmUgRklMVEVSX0RFTCAgICAgICAgICAgICAweDAyDQo+ID4gKyNkZWZpbmUgRklMVEVSX1NU
QVRVUyAgICAgICAgICAweDAzDQo+ID4gKw0KPiA+ICsvKiBQcm94eSBGaWx0ZXIgVHlwZXMgKi8N
Cj4gPiArI2RlZmluZSBXSElURUxJU1RfRklMVEVSICAgICAgIDB4MDANCj4gPiArI2RlZmluZSBC
TEFDS0xJU1RfRklMVEVSICAgICAgIDB4MDENCj4gPiArDQo+ID4gKy8qIElWIFVwZGF0aW5nIHN0
YXRlcyBmb3IgdGltaW5nIGVuZm9yY2VtZW50ICovDQo+ID4gKyNkZWZpbmUgSVZfVVBEX0lOSVQg
ICAgICAgICAgICAwDQo+ID4gKyNkZWZpbmUgSVZfVVBEX05PUk1BTCAgICAgICAgICAxDQo+ID4g
KyNkZWZpbmUgSVZfVVBEX1VQREFUSU5HICAgICAgICAgICAgICAgIDINCj4gPiArI2RlZmluZSBJ
Vl9VUERfTk9STUFMX0hPTEQgICAgIDMNCj4gPiArDQo+ID4gKyNkZWZpbmUgSVZfSURYX0RJRkZf
UkFOR0UgICAgICA0Mg0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCBtZXNoX25ldCBuZXQ7DQo+
ID4gK3N0YXRpYyBHTGlzdCAqdmlydF9hZGRycyA9IE5VTEw7DQo+ID4gK3N0YXRpYyBHTGlzdCAq
bmV0X2tleXMgPSBOVUxMOw0KPiA+ICtzdGF0aWMgR0xpc3QgKmFwcF9rZXlzID0gTlVMTDsNCj4g
PiArDQo+ID4gKy8qIEZvcndhcmQgc3RhdGljIGRlY2xhcmF0aW9ucyAqLw0KPiA+ICtzdGF0aWMg
dm9pZCByZXNlbmRfc2VncyhzdHJ1Y3QgbWVzaF9zYXJfbXNnICpzYXIpOw0KPiA+ICsNCj4gPiAr
c3RhdGljIGludCBtYXRjaF9uZXRfaWQoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9pZCAqbmV0X2lk
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjb25zdCBzdHJ1Y3QgbWVzaF9uZXRfa2V5ICpuZXRfa2V5
ID0gYTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAobmV0X2tleS0+Y3VycmVudC5uaWQgIT0gMHhm
ZiAmJg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICFtZW1jbXAobmV0X2tleS0+Y3VycmVu
dC5uZXRfaWQsIG5ldF9pZCwgOCkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAwOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmIChuZXRfa2V5LT5uZXcubmlkICE9IDB4ZmYgJiYNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAhbWVtY21wKG5ldF9rZXktPm5ldy5uZXRfaWQsIG5ldF9pZCwg
OCkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAwOw0KPiA+ICsNCj4gPiArICAgICAgIHJl
dHVybiAtMTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCBtZXNoX25ldF9rZXkg
KmZpbmRfbmV0X2tleV9ieV9pZChjb25zdCB1aW50OF90ICpuZXRfaWQpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0
b20obmV0X2tleXMsIG5ldF9pZCwgbWF0Y2hfbmV0X2lkKTsNCj4gPiArDQo+ID4gKyAgICAgICBp
ZiAoIWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAg
ICAgIHJldHVybiBsLT5kYXRhOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICt1aW50MTZfdCBuZXRfdmFs
aWRhdGVfcHJveHlfYmVhY29uKGNvbnN0IHVpbnQ4X3QgKnByb3h5X2JlYWNvbikNCj4gPiArew0K
PiA+ICsgICAgICAgc3RydWN0IG1lc2hfbmV0X2tleSAqbmV0X2tleSA9DQo+IGZpbmRfbmV0X2tl
eV9ieV9pZChwcm94eV9iZWFjb24pOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChuZXRfa2V5ID09
IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBORVRfSURYX0lOVkFMSUQ7DQo+ID4g
Kw0KPiA+ICsgICAgICAgcmV0dXJuIG5ldF9rZXktPmdlbmVyaWMuaWR4Ow0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgaW50IG1hdGNoX3Nhcl9kc3QoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9p
ZCAqYikNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3Qgc3RydWN0IG1lc2hfc2FyX21zZyAqc2Fy
ID0gYTsNCj4gPiArICAgICAgIHVpbnQxNl90IGRzdCA9IEdQT0lOVEVSX1RPX1VJTlQoYik7DQo+
ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIChzYXItPmRzdCA9PSBkc3QpID8gMCA6IC0xOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lc2hfc2FyX21zZyAqZmluZF9zYXJfb3V0
X2J5X2RzdCh1aW50MTZfdCBkc3QpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+
ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20obmV0Lm1zZ19vdXQsIEdVSU5U
X1RPX1BPSU5URVIoZHN0KSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtYXRjaF9zYXJf
ZHN0KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBsLT5kYXRhOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtzdGF0aWMgaW50IG1hdGNoX3Nhcl9zcmMoY29uc3Qgdm9pZCAqYSwgY29uc3Qg
dm9pZCAqYikNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3Qgc3RydWN0IG1lc2hfc2FyX21zZyAq
c2FyID0gYTsNCj4gPiArICAgICAgIHVpbnQxNl90IHNyYyA9IEdQT0lOVEVSX1RPX1VJTlQoYik7
DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIChzYXItPnNyYyA9PSBzcmMpID8gMCA6IC0xOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lc2hfc2FyX21zZyAqZmluZF9zYXJf
aW5fYnlfc3JjKHVpbnQxNl90IHNyYykNCj4gPiArew0KPiA+ICsgICAgICAgR0xpc3QgKmw7DQo+
ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbShuZXQuc2FyX2luLCBHVUlO
VF9UT19QT0lOVEVSKHNyYyksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hfc2Fy
X3NyYyk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFsKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbC0+ZGF0YTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIGludCBtYXRjaF9rZXlfaW5kZXgoY29uc3Qgdm9pZCAqYSwgY29u
c3Qgdm9pZCAqYikNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3Qgc3RydWN0IGdlbmVyaWNfa2V5
ICpnZW5lcmljID0gYTsNCj4gPiArICAgICAgIHVpbnQxNl90IGluZGV4ID0gR1BPSU5URVJfVE9f
VUlOVChiKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gKGdlbmVyaWMtPmlkeCA9PSBpbmRl
eCkgPyAwIDogLTE7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIGRlbGV0ZV9rZXko
R0xpc3QgKipsaXN0LCB1aW50MTZfdCBpbmRleCkNCj4gPiArew0KPiA+ICsgICAgICAgR0xpc3Qg
Kmw7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbSgqbGlzdCwgR1VJ
TlRfVE9fUE9JTlRFUihpbmRleCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBtYXRjaF9rZXlfaW5kZXgpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbCkNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICpsaXN0ID0gZ19s
aXN0X2RlbGV0ZV9saW5rKCpsaXN0LCBsKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1
ZTsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB1aW50OF90ICpnZXRfa2V5KEdM
aXN0ICpsaXN0LCB1aW50MTZfdCBpbmRleCkNCj4gPiArew0KPiA+ICsgICAgICAgR0xpc3QgKmw7
DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9hcHBfa2V5ICphcHBfa2V5Ow0KPiA+ICsgICAgICAg
c3RydWN0IG1lc2hfbmV0X2tleSAqbmV0X2tleTsNCj4gPiArDQo+ID4gKyAgICAgICBsID0gZ19s
aXN0X2ZpbmRfY3VzdG9tKGxpc3QsIEdVSU5UX1RPX1BPSU5URVIoaW5kZXgpLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hfa2V5X2luZGV4KTsNCj4gPiArDQo+ID4g
KyAgICAgICBpZiAoIWwpIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChsaXN0
ID09IGFwcF9rZXlzKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGFwcF9rZXkgPSBsLT5kYXRhOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogQWxsIEFwcCBLZXlzIG11c3QgYmVsb25nIHRv
IGEgdmFsaWQgTmV0IEtleSAqLw0KPiA+ICsgICAgICAgICAgICAgICBsID0gZ19saXN0X2ZpbmRf
Y3VzdG9tKG5ldF9rZXlzLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1VJ
TlRfVE9fUE9JTlRFUihhcHBfa2V5LT5uZXRfaWR4KSwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIG1hdGNoX2tleV9pbmRleCk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAg
ICBpZiAoIWwpIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgbmV0X2tl
eSA9IGwtPmRhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAobmV0X2tleS0+cGhh
c2UgPT0gMiAmJiBhcHBfa2V5LT5uZXcuYWtmX2FpZCAhPSAweGZmKQ0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIHJldHVybiBhcHBfa2V5LT5uZXcua2V5Ow0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKGFwcF9rZXktPmN1cnJlbnQuYWtmX2FpZCAhPSAweGZmKQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIHJldHVybiBhcHBfa2V5LT5jdXJyZW50LmtleTsNCj4gPiArDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4g
PiArICAgICAgIG5ldF9rZXkgPSBsLT5kYXRhOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChuZXRf
a2V5LT5waGFzZSA9PSAyICYmIG5ldF9rZXktPm5ldy5uaWQgIT0gMHhmZikNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIG5ldF9rZXktPm5ldy5uZXRfa2V5Ow0KPiA+ICsNCj4gPiArICAgICAg
IGlmIChuZXRfa2V5LT5jdXJyZW50Lm5pZCAhPSAweGZmKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gbmV0X2tleS0+Y3VycmVudC5uZXRfa2V5Ow0KPiA+ICsNCj4gPiArICAgICAgIHJldHVy
biBOVUxMOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIGtleXNfYXBwX2tleV9hZGQodWludDE2
X3QgbmV0X2lkeCwgdWludDE2X3QgYXBwX2lkeCwgdWludDhfdA0KPiAqa2V5LA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIGJvb2wgdXBkYXRlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1
Y3QgbWVzaF9hcHBfa2V5ICphcHBfa2V5ID0gTlVMTDsNCj4gPiArICAgICAgIHVpbnQ4X3QgYWtm
X2FpZDsNCj4gPiArICAgICAgIEdMaXN0ICpsID0gZ19saXN0X2ZpbmRfY3VzdG9tKGFwcF9rZXlz
LA0KPiBHVUlOVF9UT19QT0lOVEVSKGFwcF9pZHgpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgbWF0Y2hfa2V5X2luZGV4KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW1l
c2hfY3J5cHRvX2s0KGtleSwgJmFrZl9haWQpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4g
ZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgYWtmX2FpZCB8PSBBS0ZfQklUOw0KPiA+ICsNCj4g
PiArICAgICAgIGlmIChsICYmIHVwZGF0ZSkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
YXBwX2tleSA9IGwtPmRhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoYXBwX2tl
eS0+bmV0X2lkeCAhPSBuZXRfaWR4KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVy
biBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIG1lbWNweShhcHBfa2V5LT5uZXcu
a2V5LCBrZXksIDE2KTsNCj4gPiArICAgICAgICAgICAgICAgYXBwX2tleS0+bmV3LmFrZl9haWQg
PSBha2ZfYWlkOw0KPiA+ICsNCj4gPiArICAgICAgIH0gZWxzZSBpZiAobCkgew0KPiA+ICsNCj4g
PiArICAgICAgICAgICAgICAgYXBwX2tleSA9IGwtPmRhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBpZiAobWVtY21wKGFwcF9rZXktPmN1cnJlbnQua2V5LCBrZXksIDE2KSB8fA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwX2tleS0+bmV0X2lkeCAhPSBuZXRf
aWR4KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+
ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgYXBwX2tleSA9
IGdfbmV3KHN0cnVjdCBtZXNoX2FwcF9rZXksIDEpOw0KPiA+ICsgICAgICAgICAgICAgICBtZW1j
cHkoYXBwX2tleS0+Y3VycmVudC5rZXksIGtleSwgMTYpOw0KPiA+ICsgICAgICAgICAgICAgICBh
cHBfa2V5LT5uZXRfaWR4ID0gbmV0X2lkeDsNCj4gPiArICAgICAgICAgICAgICAgYXBwX2tleS0+
Z2VuZXJpYy5pZHggPSBhcHBfaWR4Ow0KPiA+ICsgICAgICAgICAgICAgICBhcHBfa2V5LT5jdXJy
ZW50LmFrZl9haWQgPSBha2ZfYWlkOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogSW52
YWxpZGF0ZSAiTmV3IiB2ZXJzaW9uICovDQo+ID4gKyAgICAgICAgICAgICAgIGFwcF9rZXktPm5l
dy5ha2ZfYWlkID0gMHhmZjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGFwcF9rZXlzID0g
Z19saXN0X2FwcGVuZChhcHBfa2V5cywgYXBwX2tleSk7DQo+ID4gKw0KPiA+ICsgICAgICAgfQ0K
PiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29s
IGtleXNfbmV0X2tleV9hZGQodWludDE2X3QgbmV0X2lkeCwgdWludDhfdCAqa2V5LCBib29sIHVw
ZGF0ZSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbmV0X2tleSAqbmV0X2tleSA9
IE5VTEw7DQo+ID4gKyAgICAgICB1aW50OF90IHAgPSAwOw0KPiA+ICsgICAgICAgR0xpc3QgKmwg
PSBnX2xpc3RfZmluZF9jdXN0b20obmV0X2tleXMsDQo+IEdVSU5UX1RPX1BPSU5URVIobmV0X2lk
eCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaF9rZXlfaW5kZXgp
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmIChsICYmIHVwZGF0ZSkgew0KPiA+ICsgICAgICAgICAg
ICAgICBib29sIHJlc3VsdDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIG5ldF9rZXkgPSBs
LT5kYXRhOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgbWVtY3B5KG5ldF9rZXktPm5ldy5u
ZXRfa2V5LCBrZXksIDE2KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIENhbGN1bGF0
ZSB0aGUgbWFueSBjb21wb25lbnQgcGFydHMgKi8NCj4gPiArICAgICAgICAgICAgICAgcmVzdWx0
ID0gbWVzaF9jcnlwdG9fbmtiayhrZXksIG5ldF9rZXktPm5ldy5iZWFjb25fa2V5KTsNCj4gPiAr
ICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
cmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmVzdWx0ID0gbWVzaF9j
cnlwdG9fazMoa2V5LCBuZXRfa2V5LT5uZXcubmV0X2lkKTsNCj4gPiArICAgICAgICAgICAgICAg
aWYgKCFyZXN1bHQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmVzdWx0ID0gbWVzaF9jcnlwdG9fazIoa2V5LCAm
cCwgMSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZuZXRfa2V5LT5uZXcu
bmlkLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV0X2tleS0+bmV3LmVu
Y19rZXksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXRfa2V5LT5uZXcu
cHJpdmFjeV9rZXkpOw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBuZXRfa2V5LT5uZXcubmlkID0gMHhmZjsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7DQo+ID4gKw0KPiA+ICsgICAgICAgfSBlbHNl
IGlmIChsKSB7DQo+ID4gKyAgICAgICAgICAgICAgIG5ldF9rZXkgPSBsLT5kYXRhOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgaWYgKG1lbWNtcChuZXRfa2V5LT5jdXJyZW50Lm5ldF9rZXks
IGtleSwgMTYpKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4g
PiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIGJvb2wgcmVzdWx0Ow0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgbmV0X2tleSA9IGdfbmV3KHN0cnVjdCBtZXNoX25ldF9r
ZXksIDEpOw0KPiA+ICsgICAgICAgICAgICAgICBtZW1jcHkobmV0X2tleS0+Y3VycmVudC5uZXRf
a2V5LCBrZXksIDE2KTsNCj4gPiArICAgICAgICAgICAgICAgbmV0X2tleS0+Z2VuZXJpYy5pZHgg
PSBuZXRfaWR4Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogSW52YWxpZGF0ZSAiTmV3
IiB2ZXJzaW9uICovDQo+ID4gKyAgICAgICAgICAgICAgIG5ldF9rZXktPm5ldy5uaWQgPSAweGZm
Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogQ2FsY3VsYXRlIHRoZSBtYW55IGNvbXBv
bmVudCBwYXJ0cyAqLw0KPiA+ICsgICAgICAgICAgICAgICByZXN1bHQgPSBtZXNoX2NyeXB0b19u
a2JrKGtleSwgbmV0X2tleS0+Y3VycmVudC5iZWFjb25fa2V5KTsNCj4gPiArICAgICAgICAgICAg
ICAgaWYgKCFyZXN1bHQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBnX2ZyZWUobmV0
X2tleSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsg
ICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICByZXN1bHQgPSBtZXNo
X2NyeXB0b19rMyhrZXksIG5ldF9rZXktPmN1cnJlbnQubmV0X2lkKTsNCj4gPiArICAgICAgICAg
ICAgICAgaWYgKCFyZXN1bHQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBnX2ZyZWUo
bmV0X2tleSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+
ICsgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICByZXN1bHQgPSBt
ZXNoX2NyeXB0b19rMihrZXksICZwLCAxLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgJm5ldF9rZXktPmN1cnJlbnQubmlkLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgbmV0X2tleS0+Y3VycmVudC5lbmNfa2V5LA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgbmV0X2tleS0+Y3VycmVudC5wcml2YWN5X2tleSk7DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICBpZiAoIXJlc3VsdCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIGdfZnJlZShuZXRfa2V5KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4g
ZmFsc2U7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IG5ldF9rZXlzID0gZ19saXN0X2FwcGVuZChuZXRfa2V5cywgbmV0X2tleSk7DQo+ID4gKyAgICAg
ICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4g
K3N0YXRpYyBzdHJ1Y3QgbWVzaF9hcHBfa2V5ICpmaW5kX2FwcF9rZXlfYnlfaWR4KHVpbnQxNl90
IGFwcF9pZHgpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArICAg
ICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20oYXBwX2tleXMsIEdVSU5UX1RPX1BPSU5URVIoYXBw
X2lkeCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaF9rZXlfaW5k
ZXgpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbCkgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+
ICsgICAgICAgcmV0dXJuIGwtPmRhdGE7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1
Y3QgbWVzaF9uZXRfa2V5ICpmaW5kX25ldF9rZXlfYnlfaWR4KHVpbnQxNl90IG5ldF9pZHgpDQo+
ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArICAgICAgIGwgPSBnX2xp
c3RfZmluZF9jdXN0b20obmV0X2tleXMsIEdVSU5UX1RPX1BPSU5URVIobmV0X2lkeCksDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaF9rZXlfaW5kZXgpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmICghbCkgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0
dXJuIGwtPmRhdGE7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgbWF0Y2hfdmlydF9k
c3QoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9pZCAqYikNCj4gPiArew0KPiA+ICsgICAgICAgY29u
c3Qgc3RydWN0IG1lc2hfdmlydF9hZGRyICp2aXJ0ID0gYTsNCj4gPiArICAgICAgIHVpbnQzMl90
IGRzdCA9IEdQT0lOVEVSX1RPX1VJTlQoYik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGRzdCA8
IDB4MTAwMDAgJiYgZHN0ID09IHZpcnQtPnZhMTYpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVy
biAwOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChkc3QgPT0gdmlydC0+dmEzMikNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIDA7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIC0xOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lc2hfdmlydF9hZGRyICpmaW5kX3ZpcnRf
YnlfZHN0KHVpbnQzMl90IGRzdCkNCj4gPiArew0KPiA+ICsgICAgICAgR0xpc3QgKmw7DQo+ID4g
Kw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbSh2aXJ0X2FkZHJzLCBHVUlOVF9U
T19QT0lOVEVSKGRzdCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRj
aF92aXJ0X2RzdCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFsKSByZXR1cm4gTlVMTDsNCj4g
PiArDQo+ID4gKyAgICAgICByZXR1cm4gbC0+ZGF0YTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdWlu
dDhfdCAqa2V5c19uZXRfa2V5X2dldCh1aW50MTZfdCBuZXRfaWR4LCBib29sIGN1cnJlbnQpDQo+
ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArDQo+ID4gKyAgICAgICBs
ID0gZ19saXN0X2ZpbmRfY3VzdG9tKG5ldF9rZXlzLCBHVUlOVF9UT19QT0lOVEVSKG5ldF9pZHgp
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hfa2V5X2luZGV4KTsN
Cj4gPiArICAgICAgIGlmICghbCkgew0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gTlVMTDsN
Cj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0cnVjdCBtZXNoX25l
dF9rZXkgKmtleSA9IGwtPmRhdGE7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChjdXJyZW50KQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBrZXktPmN1cnJlbnQubmV0X2tleTsN
Cj4gPiArICAgICAgICAgICAgICAgZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJl
dHVybiBrZXktPm5ldy5uZXRfa2V5Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtib29sIGtleXNfYXBwX2tleV9kZWxldGUodWludDE2X3QgYXBwX2lkeCkNCj4gPiArew0KPiA+
ICsgICAgICAgLyogVE9ETzogcmVtb3ZlIGFsbCBhc3NvY2lhdGVkIGJpbmRpbmdzICovDQo+ID4g
KyAgICAgICByZXR1cm4gZGVsZXRlX2tleSgmYXBwX2tleXMsIGFwcF9pZHgpOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtib29sIGtleXNfbmV0X2tleV9kZWxldGUodWludDE2X3QgbmV0X2lkeCkNCj4g
PiArew0KPiA+ICsgICAgICAgLyogVE9ETzogcmVtb3ZlIGFsbCBhc3NvY2lhdGVkIGFwcCBrZXlz
IGFuZCBiaW5kaW5ncyAqLw0KPiA+ICsgICAgICAgcmV0dXJuIGRlbGV0ZV9rZXkoJm5ldF9rZXlz
LCBuZXRfaWR4KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdWludDhfdCBrZXlzX2dldF9rcl9waGFz
ZSh1aW50MTZfdCBuZXRfaWR4KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBHTGlzdCAqbDsNCj4gPiAr
ICAgICAgIHN0cnVjdCBtZXNoX25ldF9rZXkgKmtleTsNCj4gPiArDQo+ID4gKyAgICAgICBsID0g
Z19saXN0X2ZpbmRfY3VzdG9tKG5ldF9rZXlzLCBHVUlOVF9UT19QT0lOVEVSKG5ldF9pZHgpLA0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hfa2V5X2luZGV4KTsNCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoIWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBLUl9Q
SEFTRV9JTlZBTElEOw0KPiA+ICsNCj4gPiArICAgICAgIGtleSA9IGwtPmRhdGE7DQo+ID4gKw0K
PiA+ICsgICAgICAgcmV0dXJuIGtleS0+cGhhc2U7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wg
a2V5c19zZXRfa3JfcGhhc2UodWludDE2X3QgaW5kZXgsIHVpbnQ4X3QgcGhhc2UpDQo+ID4gK3sN
Cj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbmV0X2tleSAq
bmV0X2tleTsNCj4gPiArDQo+ID4gKyAgICAgICBsID0gZ19saXN0X2ZpbmRfY3VzdG9tKG5ldF9r
ZXlzLCBHVUlOVF9UT19QT0lOVEVSKGluZGV4KSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIG1hdGNoX2tleV9pbmRleCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFsKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbmV0
X2tleSA9IGwtPmRhdGE7DQo+ID4gKyAgICAgICBuZXRfa2V5LT5waGFzZSA9IHBoYXNlOw0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICt1aW50MTZf
dCBrZXlzX2FwcF9rZXlfZ2V0X2JvdW5kKHVpbnQxNl90IGFwcF9pZHgpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0
b20oYXBwX2tleXMsIEdVSU5UX1RPX1BPSU5URVIoYXBwX2lkeCksDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBtYXRjaF9rZXlfaW5kZXgpOw0KPiA+ICsgICAgICAgaWYgKCFs
KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gTkVUX0lEWF9JTlZBTElEOw0KPiA+ICsgICAg
ICAgZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0cnVjdCBtZXNoX2FwcF9rZXkgKmtleSA9
IGwtPmRhdGE7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBrZXktPm5ldF9pZHg7DQo+ID4g
KyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQ4X3QgKmtleXNfYXBwX2tleV9nZXQo
dWludDE2X3QgYXBwX2lkeCwgYm9vbCBjdXJyZW50KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBHTGlz
dCAqbDsNCj4gPiArDQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbShh
cHBfa2V5cywgR1VJTlRfVE9fUE9JTlRFUihhcHBfaWR4KSwNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIG1hdGNoX2tleV9pbmRleCk7DQo+ID4gKyAgICAgICBpZiAoIWwpIHsN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0K
PiA+ICsgICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF9hcHBfa2V5ICprZXkgPSBsLT5kYXRhOw0K
PiA+ICsgICAgICAgICAgICAgICBpZiAoY3VycmVudCkNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICByZXR1cm4ga2V5LT5jdXJyZW50LmtleTsNCj4gPiArICAgICAgICAgICAgICAgZWxzZQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBrZXktPm5ldy5rZXk7DQo+ID4gKyAg
ICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQga2V5c19jbGVhbnVwX2FsbCh2b2lkKQ0K
PiA+ICt7DQo+ID4gKyAgICAgICBnX2xpc3RfZnJlZV9mdWxsKGFwcF9rZXlzLCBnX2ZyZWUpOw0K
PiA+ICsgICAgICAgZ19saXN0X2ZyZWVfZnVsbChuZXRfa2V5cywgZ19mcmVlKTsNCj4gPiArICAg
ICAgIGFwcF9rZXlzID0gbmV0X2tleXMgPSBOVUxMOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29s
IG5ldF9nZXRfa2V5KHVpbnQxNl90IG5ldF9pZHgsIHVpbnQ4X3QgKmtleSkNCj4gPiArew0KPiA+
ICsgICAgICAgdWludDhfdCAqYnVmOw0KPiA+ICsNCj4gPiArICAgICAgIGJ1ZiA9IGdldF9rZXko
bmV0X2tleXMsIG5ldF9pZHgpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghYnVmKQ0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KGtl
eSwgYnVmLCAxNik7DQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArYm9vbCBuZXRfZ2V0X2ZsYWdzKHVpbnQxNl90IG5ldF9pZHgsIHVpbnQ4X3QgKm91dF9mbGFn
cykNCj4gPiArew0KPiA+ICsgICAgICAgdWludDhfdCBwaGFzZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBwaGFzZSA9IGtleXNfZ2V0X2tyX3BoYXNlKG5ldF9pZHgpOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmIChwaGFzZSA9PSBLUl9QSEFTRV9JTlZBTElEIHx8ICFvdXRfZmxhZ3MpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocGhhc2UgIT0g
S1JfUEhBU0VfTk9ORSkNCj4gPiArICAgICAgICAgICAgICAgKm91dF9mbGFncyA9IDB4MDE7DQo+
ID4gKyAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgICpvdXRfZmxhZ3MgPSAweDAwOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChuZXQuaXZfdXBkYXRlKQ0KPiA+ICsgICAgICAgICAgICAg
ICAqb3V0X2ZsYWdzIHw9IDB4MDI7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+
ID4gK30NCj4gPiArDQo+ID4gK3VpbnQzMl90IG5ldF9nZXRfaXZfaW5kZXgoYm9vbCAqdXBkYXRl
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAodXBkYXRlKQ0KPiA+ICsgICAgICAgICAgICAgICAq
dXBkYXRlID0gbmV0Lml2X3VwZGF0ZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbmV0Lml2
X2luZGV4Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICt2b2lkIG5ldF9zZXRfaXZfaW5kZXgodWludDMy
X3QgaXZfaW5kZXgsIGJvb2wgdXBkYXRlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBuZXQuaXZfaW5k
ZXggPSBpdl9pbmRleDsNCj4gPiArICAgICAgIG5ldC5pdl91cGRhdGUgPSB1cGRhdGU7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3ZvaWQgc2V0X3NlcXVlbmNlX251bWJlcih1aW50MzJfdCBzZXFfbnVt
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBuZXQuc2VxX251bSA9IHNlcV9udW07DQo+ID4gK30NCj4g
PiArDQo+ID4gK3VpbnQzMl90IGdldF9zZXF1ZW5jZV9udW1iZXIodm9pZCkNCj4gPiArew0KPiA+
ICsgICAgICAgcmV0dXJuIG5ldC5zZXFfbnVtOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG5l
dF9hZGRfYWRkcmVzc19wb29sKHVpbnQxNl90IG1pbiwgdWludDE2X3QgbWF4KQ0KPiA+ICt7DQo+
ID4gKyAgICAgICB1aW50MzJfdCByYW5nZTsNCj4gPiArICAgICAgIGlmIChtYXggPCBtaW4pDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgIHJhbmdlID0gbWlu
ICsgKG1heCA8PCAxNik7DQo+ID4gKyAgICAgICBuZXQuYWRkcmVzc19wb29sID0gZ19saXN0X2Fw
cGVuZChuZXQuYWRkcmVzc19wb29sLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIEdVSU5UX1RPX1BPSU5URVIocmFuZ2UpKTsNCj4gPiArICAgICAg
IHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IG1hdGNoX2FkZHJl
c3NfcmFuZ2UoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9pZCAqYikNCj4gPiArew0KPiA+ICsgICAg
ICAgdWludDMyX3QgcmFuZ2UgPSBHUE9JTlRFUl9UT19VSU5UKGEpOw0KPiA+ICsgICAgICAgdWlu
dDhfdCBudW1fZWxlbWVudHMgPSAodWludDhfdCkgKEdQT0lOVEVSX1RPX1VJTlQoYikpOw0KPiA+
ICsgICAgICAgdWludDE2X3QgbWF4ID0gcmFuZ2UgPj4gMTY7DQo+ID4gKyAgICAgICB1aW50MTZf
dCBtaW4gPSByYW5nZSAmIDB4ZmZmZjsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gKChtYXgg
LSBtaW4pID49IChudW1fZWxlbWVudHMgLSAxKSkgPyAwIDogLTE7DQo+ID4gKw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICt1aW50MTZfdCBuZXRfb2J0YWluX2FkZHJlc3ModWludDhfdCBudW1fZWxlcykN
Cj4gPiArew0KPiA+ICsgICAgICAgdWludDE2X3QgYWRkcjsNCj4gPiArICAgICAgIEdMaXN0ICps
Ow0KPiA+ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20obmV0LmFkZHJlc3Nf
cG9vbCwNCj4gR1VJTlRfVE9fUE9JTlRFUihudW1fZWxlcyksDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBtYXRjaF9hZGRyZXNzX3JhbmdlKTsNCj4gPiArICAgICAgIGlmIChs
KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQzMl90IHJhbmdlID0gR1BPSU5URVJfVE9fVUlO
VChsLT5kYXRhKTsNCj4gPiArICAgICAgICAgICAgICAgdWludDE2X3QgbWF4ID0gcmFuZ2UgPj4g
MTY7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQxNl90IG1pbiA9IHJhbmdlICYgMHhmZmZmOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgYWRkciA9IG1pbjsNCj4gPiArICAgICAgICAgICAg
ICAgbWluICs9IG51bV9lbGVzOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKG1pbiA+
IG1heCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBuZXQuYWRkcmVzc19wb29sID0gZ19s
aXN0X2RlbGV0ZV9saW5rKG5ldC5hZGRyZXNzX3Bvb2wsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGwpOw0KPiA+ICsg
ICAgICAgICAgICAgICBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByYW5nZSA9
IG1pbiArIChtYXggPDwgMTYpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGwtPmRhdGEg
PSBHVUlOVF9UT19QT0lOVEVSKHJhbmdlKTsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gYWRkcjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICByZXR1cm4gVU5BU1NJR05FRF9BRERSRVNTOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgaW50IHJhbmdlX2NtcChjb25zdCB2b2lkICphLCBjb25zdCB2b2lkICpiKQ0KPiA+ICt7DQo+
ID4gKyAgICAgICB1aW50MzJfdCByYW5nZTEgPSBHUE9JTlRFUl9UT19VSU5UKGEpOw0KPiA+ICsg
ICAgICAgdWludDMyX3QgcmFuZ2UyID0gR1BPSU5URVJfVE9fVUlOVChiKTsNCj4gPiArDQo+ID4g
KyAgICAgICByZXR1cm4gcmFuZ2UyIC0gcmFuZ2UxOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICt2b2lk
IG5ldF9yZWxlYXNlX2FkZHJlc3ModWludDE2X3QgYWRkciwgdWludDhfdCBudW1fZWxlbWVudHMp
DQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsgICAgICAgdWludDMyX3QgcmFu
Z2U7DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yIChsID0gbmV0LmFkZHJlc3NfcG9vbDsgbCAhPSBO
VUxMOyBsID0gbC0+bmV4dCkNCj4gPiArICAgICAgIHsNCj4gPiArICAgICAgICAgICAgICAgdWlu
dDE2X3QgbWF4Ow0KPiA+ICsgICAgICAgICAgICAgICB1aW50MTZfdCBtaW47DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICByYW5nZSA9IEdQT0lOVEVSX1RPX1VJTlQobC0+ZGF0YSk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgICAgICAgICBtYXggPSByYW5nZSA+PiAxNjsNCj4gPiArICAgICAgICAg
ICAgICAgbWluID0gcmFuZ2UgJiAweGZmZmY7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBp
ZiAobWluID09IChhZGRyICsgbnVtX2VsZW1lbnRzICsgMSkpDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgbWluICA9IGFkZHI7DQo+ID4gKyAgICAgICAgICAgICAgIGVsc2UgaWYgKGFkZHIg
JiYgbWF4ID09IChhZGRyIC0gMSkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbWF4ID0g
YWRkciArIG51bV9lbGVtZW50cyArIDE7DQo+ID4gKyAgICAgICAgICAgICAgIGVsc2UNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgIHJhbmdlID0gbWluICsgKG1heCA8PCAxNik7DQo+ID4gKyAgICAgICAgICAgICAgIGwtPmRh
dGEgPSBHVUlOVF9UT19QT0lOVEVSKHJhbmdlKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJhbmdlID0gYWRkciArICgoYWRk
ciArIG51bV9lbGVtZW50cyAtIDEpIDw8IDE2KTsNCj4gPiArICAgICAgIG5ldC5hZGRyZXNzX3Bv
b2wgPSBnX2xpc3RfaW5zZXJ0X3NvcnRlZChuZXQuYWRkcmVzc19wb29sLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdVSU5UX1RPX1BPSU5URVIo
cmFuZ2UpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHJhbmdlX2NtcCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgbmV0X3Jlc2VydmVfYWRk
cmVzc19yYW5nZSh1aW50MTZfdCBiYXNlLCB1aW50OF90IG51bV9lbGVtZW50cykNCj4gPiArew0K
PiA+ICsgICAgICAgR0xpc3QgKmw7DQo+ID4gKyAgICAgICB1aW50MzJfdCByYW5nZTsNCj4gPiAr
ICAgICAgIHVpbnQxNl90IG1heDsNCj4gPiArICAgICAgIHVpbnQxNl90IG1pbjsNCj4gPiArICAg
ICAgIGJvb2wgc2hyaW5rOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAobCA9IG5ldC5hZGRyZXNz
X3Bvb2w7IGwgIT0gTlVMTDsgbCA9IGwtPm5leHQpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgIHJhbmdlID0gR1BPSU5URVJfVE9fVUlOVChsLT5kYXRhKTsNCj4gPiArDQo+ID4gKyAgICAg
ICAgICAgICAgIG1heCA9IHJhbmdlID4+IDE2Ow0KPiA+ICsgICAgICAgICAgICAgICBtaW4gPSBy
YW5nZSAmIDB4ZmZmZjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChiYXNlID49IG1p
biAmJiAoYmFzZSArIG51bV9lbGVtZW50cyAtIDEpIDw9IG1heCkNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
IWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBuZXQuYWRkcmVzc19wb29sID0gZ19saXN0X2RlbGV0ZV9saW5rKG5ldC5hZGRyZXNzX3Bvb2ws
IGwpOw0KPiA+ICsNCj4gPiArICAgICAgIHNocmluayA9IGZhbHNlOw0KPiA+ICsNCj4gPiArICAg
ICAgIGlmIChiYXNlID09IG1pbikgew0KPiA+ICsgICAgICAgICAgICAgICBzaHJpbmsgPSB0cnVl
Ow0KPiA+ICsgICAgICAgICAgICAgICBtaW4gPSBiYXNlICsgbnVtX2VsZW1lbnRzOw0KPiA+ICsg
ICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmIChtYXggPT0gYmFzZSArIG51bV9lbGVtZW50
cyAtIDEpIHsNCj4gPiArICAgICAgICAgICAgICAgc2hyaW5rID0gdHJ1ZTsNCj4gPiArICAgICAg
ICAgICAgICAgbWF4IC09IG51bV9lbGVtZW50czsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4g
KyAgICAgICBpZiAobWluID4gbWF4KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAoc2hyaW5rKQ0KPiA+ICsgICAgICAgICAgICAgICByYW5n
ZSA9IG1pbiArIChtYXggPDwgMTYpOw0KPiA+ICsgICAgICAgZWxzZQ0KPiA+ICsgICAgICAgICAg
ICAgICByYW5nZSA9IG1pbiArICgoYmFzZSAtIDEpIDw8IDE2KTsNCj4gPiArDQo+ID4gKyAgICAg
ICBuZXQuYWRkcmVzc19wb29sID0gZ19saXN0X2luc2VydF9zb3J0ZWQobmV0LmFkZHJlc3NfcG9v
bCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBH
VUlOVF9UT19QT0lOVEVSKHJhbmdlKSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICByYW5nZV9jbXApOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChz
aHJpbmspDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsNCj4gPiArICAg
ICAgIHJhbmdlID0gKGJhc2UgKyBudW1fZWxlbWVudHMpICsgKG1heCA8PCAxNik7DQo+ID4gKyAg
ICAgICBuZXQuYWRkcmVzc19wb29sID0gZ19saXN0X2luc2VydF9zb3J0ZWQobmV0LmFkZHJlc3Nf
cG9vbCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBHVUlOVF9UT19QT0lOVEVSKHJhbmdlKSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICByYW5nZV9jbXApOw0KPiA+ICsNCj4gPiArICAgICAgIHJl
dHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IG1hdGNoX2Rlc3RpbmF0
aW9uKGNvbnN0IHZvaWQgKmEsIGNvbnN0IHZvaWQgKmIpDQo+ID4gK3sNCj4gPiArICAgICAgIGNv
bnN0IHN0cnVjdCBtZXNoX2Rlc3RpbmF0aW9uICpkZXN0ID0gYTsNCj4gPiArICAgICAgIHVpbnQx
Nl90IGRzdCA9IEdQT0lOVEVSX1RPX1VJTlQoYik7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJu
IChkZXN0LT5kc3QgPT0gZHN0KSA/IDAgOiAtMTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBu
ZXRfZGVzdF9yZWYodWludDE2X3QgZHN0KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVz
aF9kZXN0aW5hdGlvbiAqZGVzdDsNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmICghZHN0KSByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9m
aW5kX2N1c3RvbShuZXQuZGVzdCwgR1VJTlRfVE9fUE9JTlRFUihkc3QpLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIG1hdGNoX2Rlc3RpbmF0aW9uKTsNCj4gPiArDQo+ID4gKyAgICAgICBp
ZiAobCkgew0KPiA+ICsgICAgICAgICAgICAgICBkZXN0ID0gbC0+ZGF0YTsNCj4gPiArICAgICAg
ICAgICAgICAgZGVzdC0+Y250Kys7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiAr
ICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBkZXN0ID0gZ19uZXcwKHN0cnVjdCBtZXNoX2Rl
c3RpbmF0aW9uLCAxKTsNCj4gPiArICAgICAgIGRlc3QtPmRzdCA9IGRzdDsNCj4gPiArICAgICAg
IGRlc3QtPmNudCsrOw0KPiA+ICsgICAgICAgbmV0LmRlc3QgPSBnX2xpc3RfYXBwZW5kKG5ldC5k
ZXN0LCBkZXN0KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBuZXRfZGVzdF91bnJlZih1aW50
MTZfdCBkc3QpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX2Rlc3RpbmF0aW9uICpk
ZXN0Ow0KPiA+ICsgICAgICAgR0xpc3QgKmw7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlz
dF9maW5kX2N1c3RvbShuZXQuZGVzdCwgR1VJTlRfVE9fUE9JTlRFUihkc3QpLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIG1hdGNoX2Rlc3RpbmF0aW9uKTsNCj4gPiArDQo+ID4gKyAgICAg
ICBpZiAoIWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAg
ICBkZXN0ID0gbC0+ZGF0YTsNCj4gPiArICAgICAgIGRlc3QtPmNudC0tOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmIChkZXN0LT5jbnQgPT0gMCkgew0KPiA+ICsgICAgICAgICAgICAgICBuZXQuZGVz
dCA9IGdfbGlzdF9yZW1vdmUobmV0LmRlc3QsIGRlc3QpOw0KPiA+ICsgICAgICAgICAgICAgICBn
X2ZyZWUoZGVzdCk7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0cnVjdCBi
dWlsZF93aGl0ZWxpc3Qgew0KPiA+ICsgICAgICAgdWludDhfdCBsZW47DQo+ID4gKyAgICAgICB1
aW50OF90IGRhdGFbMTJdOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgd2hpdGVm
aWx0ZXJfYWRkKGdwb2ludGVyIGRhdGEsIGdwb2ludGVyIHVzZXJfZGF0YSkNCj4gPiArew0KPiA+
ICsgICAgICAgc3RydWN0IG1lc2hfZGVzdGluYXRpb24gKmRlc3QgPSBkYXRhOw0KPiA+ICsgICAg
ICAgc3RydWN0IGJ1aWxkX3doaXRlbGlzdCAqd2hpdGUgPSB1c2VyX2RhdGE7DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKHdoaXRlLT5sZW4gPT0gMCkNCj4gPiArICAgICAgICAgICAgICAgd2hpdGUt
PmRhdGFbd2hpdGUtPmxlbisrXSA9IEZJTFRFUl9BREQ7DQo+ID4gKw0KPiA+ICsgICAgICAgcHV0
X2JlMTYoZGVzdC0+ZHN0LCB3aGl0ZS0+ZGF0YSArIHdoaXRlLT5sZW4pOw0KPiA+ICsgICAgICAg
d2hpdGUtPmxlbiArPSAyOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICh3aGl0ZS0+bGVuID4gKHNp
emVvZih3aGl0ZS0+ZGF0YSkgLSBzaXplb2YodWludDE2X3QpKSkgew0KPiA+ICsgICAgICAgICAg
ICAgICBuZXRfY3RsX21zZ19zZW5kKDAsIDAsIDAsIHdoaXRlLT5kYXRhLCB3aGl0ZS0+bGVuKTsN
Cj4gPiArICAgICAgICAgICAgICAgd2hpdGUtPmxlbiA9IDA7DQo+ID4gKyAgICAgICB9DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHNldHVwX3doaXRlbGlzdCgpDQo+ID4gK3sNCj4g
PiArICAgICAgIHN0cnVjdCBidWlsZF93aGl0ZWxpc3Qgd2hpdGU7DQo+ID4gKw0KPiA+ICsgICAg
ICAgd2hpdGUubGVuID0gMDsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBFbmFibGUgKGFuZCBDbGVh
cikgUHJveHkgV2hpdGVsaXN0ICovDQo+ID4gKyAgICAgICB3aGl0ZS5kYXRhW3doaXRlLmxlbisr
XSA9IEZJTFRFUl9TRVRVUDsNCj4gPiArICAgICAgIHdoaXRlLmRhdGFbd2hpdGUubGVuKytdID0g
V0hJVEVMSVNUX0ZJTFRFUjsNCj4gPiArDQo+ID4gKyAgICAgICBuZXRfY3RsX21zZ19zZW5kKDAs
IDAsIDAsIHdoaXRlLmRhdGEsIHdoaXRlLmxlbik7DQo+ID4gKw0KPiA+ICsgICAgICAgd2hpdGUu
bGVuID0gMDsNCj4gPiArICAgICAgIGdfbGlzdF9mb3JlYWNoKG5ldC5kZXN0LCB3aGl0ZWZpbHRl
cl9hZGQsICZ3aGl0ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHdoaXRlLmxlbikNCj4gPiAr
ICAgICAgICAgICAgICAgbmV0X2N0bF9tc2dfc2VuZCgwLCAwLCAwLCB3aGl0ZS5kYXRhLCB3aGl0
ZS5sZW4pOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBiZWFjb25fdXBkYXRlKGJv
b2wgZmlyc3QsIGJvb2wgaXZfdXBkYXRlLCB1aW50MzJfdCBpdl9pbmRleCkNCj4gPiArew0KPiA+
ICsNCj4gPiArICAgICAgIC8qIEVuZm9yY2VtZW50IG9mIDk2IGhvdXIgYW5kIDE5MiBob3VyIElW
VSB0aW1lIHdpbmRvd3MgKi8NCj4gPiArICAgICAgIGlmIChpdl91cGRhdGUgJiYgIW5ldC5pdl91
cGRhdGUpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJpdl91cGRfc3RhdGUgPSBJ
Vl9VUERfVVBEQVRJTkdcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICBuZXQuaXZfdXBkX3N0YXRl
ID0gSVZfVVBEX1VQREFUSU5HOw0KPiA+ICsgICAgICAgICAgICAgICAvKiBUT0RPOiBTdGFydCB0
aW1lciB0byBlbmZvcmNlIElWIFVwZGF0ZSBwYXJhbWV0ZXJzICovDQo+ID4gKyAgICAgICB9IGVs
c2UgaWYgKGZpcnN0KSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChpdl91cGRhdGUpDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgbmV0Lml2X3VwZF9zdGF0ZSA9IElWX1VQRF9VUERBVElO
RzsNCj4gPiArICAgICAgICAgICAgICAgZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IG5ldC5pdl91cGRfc3RhdGUgPSBJVl9VUERfTk9STUFMOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgcmxfcHJpbnRmKCJpdl91cGRfc3RhdGUgPSBJVl9VUERfJXNcbiIsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBpdl91cGRhdGUgPyAiVVBEQVRJTkciIDogIk5PUk1B
TCIpOw0KPiA+ICsNCj4gPiArICAgICAgIH0gZWxzZSBpZiAoaXZfdXBkYXRlICYmIGl2X2luZGV4
ICE9IG5ldC5pdl9pbmRleCkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIklWIFVw
ZGF0ZSB0b28gc29vbiAtLSBSZWplY3RpbmdcbiIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1
cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGl2X2luZGV4ID4gbmV0
Lml2X2luZGV4IHx8DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaXZfdXBkYXRlICE9IG5l
dC5pdl91cGRhdGUpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIERvbid0IHJlc2V0
IG91ciBzZXFfbnVtIHVubGVzcw0KPiA+ICsgICAgICAgICAgICAgICAgKiB3ZSBzdGFydCB1c2lu
ZyBuZXcgaXZfaW5kZXggKi8NCj4gPiArICAgICAgICAgICAgICAgaWYgKCEoaXZfdXBkYXRlICYm
IChuZXQuaXZfaW5kZXggKyAxID09IGl2X2luZGV4KSkpIHsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBuZXQuc2VxX251bSA9IDA7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbmV0
LnNlcV9udW1fcmVzZXJ2ZWQgPSAxMDA7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW5ldC5zZXFfbnVtIHx8IG5ldC5pdl9pbmRl
eCAhPSBpdl9pbmRleCB8fA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG5ldC5pdl91cGRh
dGUgIT0gaXZfdXBkYXRlKSB7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAobmV0LnNl
cV9udW1fcmVzZXJ2ZWQgPD0gbmV0LnNlcV9udW0pDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgbmV0LnNlcV9udW1fcmVzZXJ2ZWQgPSBuZXQuc2VxX251bSArIDEwMDsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgIHByb3ZfZGJfbG9jYWxfc2V0X2l2X2luZGV4KGl2X2luZGV4LCBpdl91
cGRhdGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXQucHJvdmlzaW9u
ZXIpOw0KPiA+ICsgICAgICAgICAgICAgICBwcm92X2RiX2xvY2FsX3NldF9zZXFfbnVtKG5ldC5z
ZXFfbnVtX3Jlc2VydmVkKTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBuZXQu
aXZfaW5kZXggPSBpdl9pbmRleDsNCj4gPiArICAgICAgIG5ldC5pdl91cGRhdGUgPSBpdl91cGRh
dGU7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGZpcnN0KSB7DQo+ID4gKyAgICAgICAgICAgICAg
IC8qIE11c3QgYmUgZG9uZSBvbmNlIHBlciBQcm94eSBDb25uZWN0aW9uIGFmdGVyIEJlYWNvbiBS
WGVkICovDQo+ID4gKyAgICAgICAgICAgICAgIHNldHVwX3doaXRlbGlzdCgpOw0KPiA+ICsgICAg
ICAgICAgICAgICBpZiAobmV0Lm9wZW5fY2IpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
bmV0Lm9wZW5fY2IoMCk7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRp
YyBib29sIHByb2Nlc3NfYmVhY29uKHVpbnQ4X3QgKmRhdGEsIHVpbnQ4X3Qgc2l6ZSkNCj4gPiAr
ew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbmV0X2tleSAqbmV0X2tleTsNCj4gPiArICAgICAg
IHN0cnVjdCBuZXRfa2V5X3BhcnRzICprZXlfcGFydDsNCj4gPiArICAgICAgIGJvb2wgcnhlZF9p
dl91cGRhdGUsIHJ4ZWRfa2V5X3JlZnJlc2gsIGl2X3VwZGF0ZTsNCj4gPiArICAgICAgIGJvb2wg
IG15X2tyZjsNCj4gPiArICAgICAgIHVpbnQzMl90IHJ4ZWRfaXZfaW5kZXgsIGl2X2luZGV4Ow0K
PiA+ICsgICAgICAgdWludDY0X3QgY21hYzsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc2l6ZSAh
PSAyMikNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAg
ICAgIHJ4ZWRfa2V5X3JlZnJlc2ggPSAoZGF0YVsxXSAmIDB4MDEpID09IDB4MDE7DQo+ID4gKyAg
ICAgICBpdl91cGRhdGUgPSByeGVkX2l2X3VwZGF0ZSA9IChkYXRhWzFdICYgMHgwMikgPT0gMHgw
MjsNCj4gPiArICAgICAgIGl2X2luZGV4ID0gcnhlZF9pdl9pbmRleCA9IGdldF9iZTMyKGRhdGEg
KyAxMCk7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogSW5oaWJpdCByZWNvZ25pemluZyBpdl91cGRh
dGUgdHJ1ZS0tPmZhbHNlDQo+ID4gKyAgICAgICAgKiBpZiB3ZSBoYXZlIG91dGJvdW5kIFNBUiBt
ZXNzYWdlcyBpbiBmbGlnaHQgKi8NCj4gPiArICAgICAgIGlmIChuZXQubXNnX291dCAhPSBOVUxM
KSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChuZXQuaXZfdXBkYXRlICYmICFyeGVkX2l2X3Vw
ZGF0ZSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpdl91cGRhdGUgPSB0cnVlOw0KPiA+
ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIC8qIERvbid0IGJvdGhlciBnb2luZyBmdXJ0
aGVyIGlmIG5vdGhpbmcgaGFzIGNoYW5nZWQgKi8NCj4gPiArICAgICAgIGlmIChpdl9pbmRleCA9
PSBuZXQuaXZfaW5kZXggJiYgaXZfdXBkYXRlID09IG5ldC5pdl91cGRhdGUgJiYNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBuZXQuaXZfdXBkX3N0YXRlICE9IElWX1VQRF9JTklUKQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBGaW5k
IGtleSB3ZSBhcmUgdXNpbmcgZm9yIFNOQnMgKi8NCj4gPiArICAgICAgIG5ldF9rZXkgPSBmaW5k
X25ldF9rZXlfYnlfaWQoZGF0YSArIDIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChuZXRfa2V5
ID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4g
KyAgICAgICAvKiBXZSBhcmUgUHJvdmlzaW9uZXIsIGFuZCBjb250cm9sIHRoZSBrZXlfcmVmcmVz
aCBmbGFnICovDQo+ID4gKyAgICAgICBpZiAocnhlZF9rZXlfcmVmcmVzaCAhPSAhIShuZXRfa2V5
LT5waGFzZSA9PSAyKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChuZXRfa2V5LT5waGFzZSAhPSAyKSB7DQo+ID4gKyAgICAgICAgICAg
ICAgIG15X2tyZiA9IGZhbHNlOw0KPiA+ICsgICAgICAgICAgICAgICBrZXlfcGFydCA9ICZuZXRf
a2V5LT5jdXJyZW50Ow0KPiA+ICsgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAg
bXlfa3JmID0gdHJ1ZTsNCj4gPiArICAgICAgICAgICAgICAga2V5X3BhcnQgPSAmbmV0X2tleS0+
bmV3Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIC8qIElnbm9yZSBmb3IgaW5j
b3JyZWN0IEtSIHN0YXRlICovDQo+ID4gKyAgICAgICBpZiAobWVtY21wKGtleV9wYXJ0LT5uZXRf
aWQsIGRhdGEgKyAyLCA4KSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmICgobmV0Lml2X2luZGV4ICsgSVZfSURYX0RJRkZfUkFOR0UgPCBp
dl9pbmRleCkgfHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAoaXZfaW5kZXggPCBuZXQu
aXZfaW5kZXgpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiaXYgaW5kZXggb3V0
c2lkZSByYW5nZVxuIik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiAr
ICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAvKiBBbnkgYmVoYXZpb3JhbCBjaGFuZ2VzIG11
c3QgcGFzcyBDTUFDIHRlc3QgKi8NCj4gPiArICAgICAgIGlmICghbWVzaF9jcnlwdG9fYmVhY29u
X2NtYWMoa2V5X3BhcnQtPmJlYWNvbl9rZXksIGtleV9wYXJ0LQ0KPiA+bmV0X2lkLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnhlZF9pdl9pbmRleCwgbXlfa3JmLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnhlZF9pdl91cGRhdGUsICZjbWFjKSkg
ew0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKGNtYWMgIT0gZ2V0X2JlNjQoZGF0YSArIDE0KSkNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChpdl91cGRh
dGUgJiYgKG5ldC5pdl91cGRfc3RhdGUgPiBJVl9VUERfVVBEQVRJTkcpKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgIGlmIChpdl9pbmRleCAhPSBuZXQuaXZfaW5kZXgpIHsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBybF9wcmludGYoIlVwZGF0ZSB0b28gc29vbiAtLSBSZWplY3RpbmdcbiIp
Ow0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKyAgICAgICAgICAgICAgIC8qIFNpbGVudGx5
IGlnbm9yZSBvbGQgYmVhY29ucyAqLw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBiZWFjb25fdXBkYXRlKG5ldC5pdl91
cGRfc3RhdGUgPT0gSVZfVVBEX0lOSVQsIGl2X3VwZGF0ZSwNCj4gaXZfaW5kZXgpOw0KPiA+ICsN
Cj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdHJ1Y3QgZGVj
b2RlX3BhcmFtcyB7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9uZXRfa2V5ICAgICAqbmV0X2tl
eTsNCj4gPiArICAgICAgIHVpbnQ4X3QgICAgICAgICAgICAgICAgICpwYWNrZXQ7DQo+ID4gKyAg
ICAgICB1aW50MzJfdCAgICAgICAgICAgICAgICBpdl9pbmRleDsNCj4gPiArICAgICAgIHVpbnQ4
X3QgICAgICAgICAgICAgICAgIHNpemU7DQo+ID4gKyAgICAgICBib29sICAgICAgICAgICAgICAg
ICAgICBwcm94eTsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHRyeV9kZWNvZGUo
Z3BvaW50ZXIgZGF0YSwgZ3BvaW50ZXIgdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBz
dHJ1Y3QgbWVzaF9uZXRfa2V5ICpuZXRfa2V5ID0gZGF0YTsNCj4gPiArICAgICAgIHN0cnVjdCBk
ZWNvZGVfcGFyYW1zICpkZWNvZGUgPSB1c2VyX2RhdGE7DQo+ID4gKyAgICAgICB1aW50OF90IG5p
ZCA9IGRlY29kZS0+cGFja2V0WzBdICYgMHg3ZjsNCj4gPiArICAgICAgIHVpbnQ4X3QgdG1wWzI5
XTsNCj4gPiArICAgICAgIGJvb2wgc3RhdHVzID0gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKGRlY29kZS0+bmV0X2tleSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChuZXRfa2V5LT5jdXJyZW50Lm5pZCA9PSBuaWQpDQo+ID4gKyAgICAg
ICAgICAgICAgIHN0YXR1cyA9IG1lc2hfY3J5cHRvX3BhY2tldF9kZWNvZGUoZGVjb2RlLT5wYWNr
ZXQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNvZGUtPnNpemUsIGRl
Y29kZS0+cHJveHksIHRtcCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRl
Y29kZS0+aXZfaW5kZXgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXRf
a2V5LT5jdXJyZW50LmVuY19rZXksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBuZXRfa2V5LT5jdXJyZW50LnByaXZhY3lfa2V5KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
IXN0YXR1cyAmJiBuZXRfa2V5LT5uZXcubmlkID09IG5pZCkNCj4gPiArICAgICAgICAgICAgICAg
c3RhdHVzID0gbWVzaF9jcnlwdG9fcGFja2V0X2RlY29kZShkZWNvZGUtPnBhY2tldCwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY29kZS0+c2l6ZSwgZGVjb2RlLT5wcm94
eSwgdG1wLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjb2RlLT5pdl9p
bmRleCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldF9rZXktPm5ldy5l
bmNfa2V5LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV0X2tleS0+bmV3
LnByaXZhY3lfa2V5KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc3RhdHVzKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIGRlY29kZS0+bmV0X2tleSA9IG5ldF9rZXk7DQo+ID4gKyAgICAgICAgICAg
ICAgIG1lbWNweShkZWNvZGUtPnBhY2tldCwgdG1wLCBkZWNvZGUtPnNpemUpOw0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0
YXRpYyBzdHJ1Y3QgbWVzaF9uZXRfa2V5ICpuZXRfcGFja2V0X2RlY29kZShib29sIHByb3h5LCB1
aW50MzJfdA0KPiBpdl9pbmRleCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IHVpbnQ4X3QgKnBhY2tldCwgdWludDhfdCBzaXplKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1
Y3QgZGVjb2RlX3BhcmFtcyBkZWNvZGUgPSB7DQo+ID4gKyAgICAgICAgICAgICAgIC5wcm94eSA9
IHByb3h5LA0KPiA+ICsgICAgICAgICAgICAgICAuaXZfaW5kZXggPSBpdl9pbmRleCwNCj4gPiAr
ICAgICAgICAgICAgICAgLnBhY2tldCA9IHBhY2tldCwNCj4gPiArICAgICAgICAgICAgICAgLnNp
emUgPSBzaXplLA0KPiA+ICsgICAgICAgICAgICAgICAubmV0X2tleSA9IE5VTEwsDQo+ID4gKyAg
ICAgICB9Ow0KPiA+ICsNCj4gPiArICAgICAgIGdfbGlzdF9mb3JlYWNoKG5ldF9rZXlzLCB0cnlf
ZGVjb2RlLCAmZGVjb2RlKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gZGVjb2RlLm5ldF9r
ZXk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGZsdXNoX3NhcihHTGlzdCAqKmxp
c3QsIHN0cnVjdCBtZXNoX3Nhcl9tc2cgKnNhcikNCj4gPiArew0KPiA+ICsgICAgICAgKmxpc3Qg
PSBnX2xpc3RfcmVtb3ZlKCpsaXN0LCBzYXIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChzYXIt
Pm1zZ190bykNCj4gPiArICAgICAgICAgICAgICAgZ19zb3VyY2VfcmVtb3ZlKHNhci0+bXNnX3Rv
KTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc2FyLT5hY2tfdG8pDQo+ID4gKyAgICAgICAgICAg
ICAgIGdfc291cmNlX3JlbW92ZShzYXItPmFja190byk7DQo+ID4gKw0KPiA+ICsgICAgICAgZ19m
cmVlKHNhcik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGZsdXNoX3Nhcl9saXN0
KEdMaXN0ICoqbGlzdCkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfc2FyX21zZyAq
c2FyOw0KPiA+ICsgICAgICAgR0xpc3QgKmwgPSBnX2xpc3RfZmlyc3QoKmxpc3QpOw0KPiA+ICsN
Cj4gPiArICAgICAgIHdoaWxlIChsKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHNhciA9IGwtPmRh
dGE7DQo+ID4gKyAgICAgICAgICAgICAgIGZsdXNoX3NhcihsaXN0LCBzYXIpOw0KPiA+ICsgICAg
ICAgICAgICAgICBsID0gZ19saXN0X2ZpcnN0KCpsaXN0KTsNCj4gPiArICAgICAgIH0NCj4gPiAr
fQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgZmx1c2hfcGt0X2xpc3QoR0xpc3QgKipsaXN0KQ0K
PiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9wa3QgKnBrdDsNCj4gPiArICAgICAgIEdM
aXN0ICpsID0gZ19saXN0X2ZpcnN0KCpsaXN0KTsNCj4gPiArDQo+ID4gKyAgICAgICB3aGlsZSAo
bCkgew0KPiA+ICsgICAgICAgICAgICAgICBwa3QgPSBsLT5kYXRhOw0KPiA+ICsgICAgICAgICAg
ICAgICAqbGlzdCA9IGdfbGlzdF9yZW1vdmUoKmxpc3QsIHBrdCk7DQo+ID4gKyAgICAgICAgICAg
ICAgIGdfZnJlZShwa3QpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgdm9pZCByZXNlbmRfdW5hY2tlZF9zZWdzKGdwb2ludGVyIGRhdGEsIGdwb2ludGVyIHVzZXJf
ZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfc2FyX21zZyAqc2FyID0gZGF0
YTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc2FyLT5hY3Rpdml0eV9jbnQpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJlc2VuZF9zZWdzKHNhcik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2
b2lkIHNlbmRfcGt0X2NtcGx0KERCdXNNZXNzYWdlICptZXNzYWdlLCB2b2lkICp1c2VyX2RhdGEp
DQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX3BrdCAqcGt0ID0gdXNlcl9kYXRhOw0K
PiA+ICsgICAgICAgR0xpc3QgKmwgPSBnX2xpc3RfZmlyc3QobmV0LnBrdF9vdXQpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChsICYmIHVzZXJfZGF0YSA9PSBsLT5kYXRhKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgIG5ldC5wa3Rfb3V0ID0gZ19saXN0X2RlbGV0ZV9saW5rKG5ldC5wa3Rfb3V0LCBs
KTsNCj4gPiArICAgICAgICAgICAgICAgZ19mcmVlKHBrdCk7DQo+ID4gKyAgICAgICB9IGVsc2Ug
ew0KPiA+ICsgICAgICAgICAgICAgICAvKiBUaGlzIGlzIGEgc2VyaW91cyBlcnJvciwgYW5kIHBy
b2JhYmxlIG1lbW9yeSBsZWFrICovDQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRVJS
OiBzZW5kX3BrdF9jbXBsdCAlcCBub3QgaGVhZCBvZiBxdWV1ZVxuIiwgcGt0KTsNCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBsID0gZ19saXN0X2ZpcnN0KG5ldC5wa3Rfb3V0KTsN
Cj4gPiArDQo+ID4gKyAgICAgICBpZiAobCA9PSBOVUxMKSB7DQo+ID4gKyAgICAgICAgICAgICAg
IC8qIElmIHF1ZXVlIGlzIG5ld2x5IGVtcHR5LCByZXNlbmQgYWxsIFNBUiBvdXRib3VuZCBwYWNr
ZXRzICovDQo+ID4gKyAgICAgICAgICAgICAgIGdfbGlzdF9mb3JlYWNoKG5ldC5tc2dfb3V0LCBy
ZXNlbmRfdW5hY2tlZF9zZWdzLCBOVUxMKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0K
PiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHBrdCA9IGwtPmRhdGE7DQo+ID4gKw0K
PiA+ICsgICAgICAgbWVzaF9nYXR0X3dyaXRlKG5ldC5wcm94eV9pbiwgcGt0LT5kYXRhLCBwa3Qt
PmxlbiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzZW5kX3BrdF9jbXBsdCwgcGt0KTsN
Cj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgc2VuZF9tZXNoX3BrdChzdHJ1Y3QgbWVz
aF9wa3QgKnBrdCkNCj4gPiArew0KPiA+ICsgICAgICAgYm9vbCBxdWV1ZWQgPSAhIShuZXQucGt0
X291dCk7DQo+ID4gKw0KPiA+ICsgICAgICAgbmV0LnBrdF9vdXQgPSBnX2xpc3RfYXBwZW5kKG5l
dC5wa3Rfb3V0LCBwa3QpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChxdWV1ZWQpDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBtZXNoX2dhdHRfd3JpdGUo
bmV0LnByb3h5X2luLCBwa3QtPmRhdGEsIHBrdC0+bGVuLA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHNlbmRfcGt0X2NtcGx0LCBwa3QpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMg
dWludDMyX3QgZ2V0X25leHRfc2VxKCkNCj4gPiArew0KPiA+ICsgICAgICAgdWludDMyX3QgdGhp
c19zZXEgPSBuZXQuc2VxX251bSsrOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChuZXQuc2VxX251
bSArIDMyID49IG5ldC5zZXFfbnVtX3Jlc2VydmVkKSB7DQo+ID4gKyAgICAgICAgICAgICAgIG5l
dC5zZXFfbnVtX3Jlc2VydmVkID0gbmV0LnNlcV9udW0gKyAxMDA7DQo+ID4gKyAgICAgICAgICAg
ICAgIHByb3ZfZGJfbG9jYWxfc2V0X3NlcV9udW0obmV0LnNlcV9udW1fcmVzZXJ2ZWQpOw0KPiA+
ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0aGlzX3NlcTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIHZvaWQgc2VuZF9zZWcoc3RydWN0IG1lc2hfc2FyX21zZyAqc2Fy
LCB1aW50OF90IHNlZykNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbmV0X2tleSAq
bmV0X2tleTsNCj4gPiArICAgICAgIHN0cnVjdCBuZXRfa2V5X3BhcnRzICpwYXJ0Ow0KPiA+ICsg
ICAgICAgc3RydWN0IG1lc2hfcGt0ICpwa3Q7DQo+ID4gKyAgICAgICB1aW50OF90ICpkYXRhOw0K
PiA+ICsNCj4gPiArICAgICAgIG5ldF9rZXkgPSBmaW5kX25ldF9rZXlfYnlfaWR4KHNhci0+bmV0
X2lkeCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKG5ldF9rZXkgPT0gTlVMTCkNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIENob29zZSB3aGljaCBj
b21wb25lbnRzIHRvIHVzZSB0byBzZWN1cmUgcGt0ICovDQo+ID4gKyAgICAgICBpZiAobmV0X2tl
eS0+cGhhc2UgPT0gMiAmJiBuZXRfa2V5LT5uZXcubmlkICE9IDB4ZmYpDQo+ID4gKyAgICAgICAg
ICAgICAgIHBhcnQgPSAmbmV0X2tleS0+bmV3Ow0KPiA+ICsgICAgICAgZWxzZQ0KPiA+ICsgICAg
ICAgICAgICAgICBwYXJ0ID0gJm5ldF9rZXktPmN1cnJlbnQ7DQo+ID4gKw0KPiA+ICsgICAgICAg
cGt0ID0gZ19uZXcwKHN0cnVjdCBtZXNoX3BrdCwgMSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYg
KHBrdCA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICsg
ICAgICAgLyogbGVhdmUgZXh0cmEgYnl0ZSBhdCBzdGFydCBmb3IgR0FUVCBQcm94eSB0eXBlICov
DQo+ID4gKyAgICAgICBkYXRhID0gcGt0LT5kYXRhICsgMTsNCj4gPiArDQo+ID4gKyAgICAgICBT
RVRfUEtUX05JRChkYXRhLCBwYXJ0LT5uaWQpOw0KPiA+ICsgICAgICAgU0VUX1BLVF9JVkkoZGF0
YSwgc2FyLT5pdl9pbmRleCAmIDEpOw0KPiA+ICsgICAgICAgU0VUX1BLVF9DVEwoZGF0YSwgc2Fy
LT5jdGwpOw0KPiA+ICsgICAgICAgU0VUX1BLVF9UVEwoZGF0YSwgc2FyLT50dGwpOw0KPiA+ICsg
ICAgICAgU0VUX1BLVF9TRVEoZGF0YSwgZ2V0X25leHRfc2VxKCkpOw0KPiA+ICsgICAgICAgU0VU
X1BLVF9TUkMoZGF0YSwgc2FyLT5zcmMpOw0KPiA+ICsgICAgICAgU0VUX1BLVF9EU1QoZGF0YSwg
c2FyLT5kc3QpOw0KPiA+ICsgICAgICAgU0VUX1BLVF9TRUdNRU5URUQoZGF0YSwgc2FyLT5zZWdt
ZW50ZWQpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChzYXItPmN0bCkNCj4gPiArICAgICAgICAg
ICAgICAgU0VUX1BLVF9PUENPREUoZGF0YSwgc2FyLT5kYXRhWzBdKTsNCj4gPiArICAgICAgIGVs
c2UNCj4gPiArICAgICAgICAgICAgICAgU0VUX1BLVF9BS0ZfQUlEKGRhdGEsIHNhci0+YWtmX2Fp
ZCk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHNhci0+c2VnbWVudGVkKSB7DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICBpZiAoIXNhci0+Y3RsKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIFNFVF9QS1RfU1pNSUMoZGF0YSwgc2FyLT5zem1pYyk7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBTRVRfUEtUX1NFUTAoZGF0YSwgc2FyLT5zZXFBdXRoKTsNCj4gPiArICAgICAgICAg
ICAgICAgU0VUX1BLVF9TRUdPKGRhdGEsIHNlZyk7DQo+ID4gKyAgICAgICAgICAgICAgIFNFVF9Q
S1RfU0VHTihkYXRhLCBzYXItPnNlZ04pOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgbWVt
Y3B5KFBLVF9UUkFOUyhkYXRhKSArIDQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBzYXItPmRhdGEgKyBzYXItPmN0bCArIChzZWcgKiAxMiksIDEyKTsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgIHBrdC0+bGVuID0gOSArIDQ7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICBpZiAoc2FyLT5zZWdOID09IHNlZykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBw
a3QtPmxlbiArPSAoc2FyLT5sZW4gLSBzYXItPmN0bCkgJSAxMjsNCj4gPiArDQo+ID4gKyAgICAg
ICAgICAgICAgIGlmIChwa3QtPmxlbiA9PSAoOSArIDQpKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHBrdC0+bGVuICs9IDEyOw0KPiA+ICsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4g
KyAgICAgICAgICAgICAgIG1lbWNweShQS1RfVFJBTlMoZGF0YSkgKyAxLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgc2FyLT5kYXRhICsgc2FyLT5jdGwsIDE1KTsNCj4gPiAr
DQo+ID4gKyAgICAgICAgICAgICAgIHBrdC0+bGVuID0gOSArIDEgKyBzYXItPmxlbiAtIHNhci0+
Y3RsOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHBrdC0+bGVuICs9IChzYXIt
PmN0bCA/IDggOiA0KTsNCj4gPiArICAgICAgIG1lc2hfY3J5cHRvX3BhY2tldF9lbmNvZGUoZGF0
YSwgcGt0LT5sZW4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcGFydC0+ZW5jX2tleSwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzYXItPml2X2luZGV4LA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIHBhcnQtPnByaXZhY3lfa2V5KTsNCj4gPiArDQo+ID4gKw0KPiA+ICsg
ICAgICAgLyogUHJlcGVuZCBHQVRUX1Byb3h5IHBhY2tldCB0eXBlICovDQo+ID4gKyAgICAgICBp
ZiAoc2FyLT5wcm94eSkNCj4gPiArICAgICAgICAgICAgICAgcGt0LT5kYXRhWzBdID0gUFJPWFlf
Q09ORklHX1BEVTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgcGt0LT5k
YXRhWzBdID0gUFJPWFlfTkVUV09SS19QRFU7DQo+ID4gKw0KPiA+ICsgICAgICAgcGt0LT5sZW4r
KzsNCj4gPiArDQo+ID4gKyAgICAgICBzZW5kX21lc2hfcGt0KHBrdCk7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyB2b2lkIHJlc2VuZF9zZWdzKHN0cnVjdCBtZXNoX3Nhcl9tc2cgKnNhcikN
Cj4gPiArew0KPiA+ICsgICAgICAgdWludDMyX3QgYWNrID0gMTsNCj4gPiArICAgICAgIHVpbnQ4
X3QgaTsNCj4gPiArDQo+ID4gKyAgICAgICBzYXItPmFjdGl2aXR5X2NudCA9IDA7DQo+ID4gKw0K
PiA+ICsgICAgICAgZm9yIChpID0gMDsgaSA8PSBzYXItPnNlZ047IGkrKywgYWNrIDw8PSAxKSB7
DQo+ID4gKyAgICAgICAgICAgICAgIGlmICghKGFjayAmIHNhci0+YWNrKSkNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBzZW5kX3NlZyhzYXIsIGkpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBhY2tfcnhlZChib29sIHRvLCB1aW50MTZfdCBzcmMs
IHVpbnQxNl90IGRzdCwgYm9vbCBvYm8sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICB1aW50MTZfdCBzZXEwLCB1aW50MzJfdCBhY2tfZmxhZ3MpDQo+ID4gK3sNCj4gPiArICAg
ICAgIHN0cnVjdCBtZXNoX3Nhcl9tc2cgKnNhciA9IGZpbmRfc2FyX291dF9ieV9kc3Qoc3JjKTsN
Cj4gPiArICAgICAgIHVpbnQzMl90IGZ1bGxfYWNrOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIFNp
bGVudGx5IGlnbm9yZSB1bmtub3duIChzdGFsZT8pIEFDS3MgKi8NCj4gPiArICAgICAgIGlmIChz
YXIgPT0gTlVMTCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+
ICsgICAgICAgZnVsbF9hY2sgPSAweGZmZmZmZmZmID4+ICgzMSAtIHNhci0+c2VnTik7DQo+ID4g
Kw0KPiA+ICsgICAgICAgc2FyLT5hY2sgfD0gKGFja19mbGFncyAmIGZ1bGxfYWNrKTsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZiAoc2FyLT5hY2sgPT0gZnVsbF9hY2spIHsNCj4gPiArICAgICAgICAg
ICAgICAgLyogT3V0Ym91bmQgbWVzc2FnZSAxMDAlIHJlY2VpdmVkIGJ5IHJlbW90ZSBub2RlICov
DQo+ID4gKyAgICAgICAgICAgICAgIGZsdXNoX3NhcigmbmV0Lm1zZ19vdXQsIHNhcik7DQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiAr
ICAgICAgIC8qIEJlY2F1c2Ugd2UgYXJlIEdBVFQsIGFuZCBzbG93LCBvbmx5IHJlc2VuZCBQS1Rz
IGlmIGl0IGlzDQo+ID4gKyAgICAgICAgKiB0aW1lICphbmQqIG91ciBvdXRib3VuZCBQS1QgcXVl
dWUgaXMgZW1wdHkuICAqLw0KPiA+ICsgICAgICAgc2FyLT5hY3Rpdml0eV9jbnQrKzsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZiAobmV0LnBrdF9vdXQgPT0gTlVMTCkNCj4gPiArICAgICAgICAgICAg
ICAgcmVzZW5kX3NlZ3Moc2FyKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4g
PiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgcHJveHlfY3RsX3J4ZWQodWludDE2X3QgbmV0
X2lkeCwgdWludDMyX3QgaXZfaW5kZXgsDQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQ4X3QgdHRs
LCB1aW50MzJfdCBzZXFfbnVtLCB1aW50MTZfdCBzcmMsIHVpbnQxNl90IGRzdCwNCj4gPiArICAg
ICAgICAgICAgICAgdWludDhfdCAqdHJhbnMsIHVpbnQxNl90IGxlbikNCj4gPiArew0KPiA+ICsg
ICAgICAgaWYgKGxlbiA8IDEpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4g
PiArDQo+ID4gKyAgICAgICBzd2l0Y2godHJhbnNbMF0pIHsNCj4gPiArICAgICAgICAgICAgICAg
Y2FzZSBGSUxURVJfU1RBVFVTOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChsZW4g
IT0gNCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbmV0LmJsYWNrbGlzdCA9ICEhKHRy
YW5zWzFdID09IEJMQUNLTElTVF9GSUxURVIpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IHJsX3ByaW50ZigiUHJveHkgJXNsaXN0IGZpbHRlciBsZW5ndGg6ICVkXG4iLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXQuYmxhY2tsaXN0ID8gIkJsYWNr
IiA6ICJXaGl0ZSIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IGdldF9iZTE2KHRyYW5zICsgMikpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICByZXR1cm4gdHJ1ZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGRlZmF1bHQ6DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAgfQ0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGlj
IGJvb2wgY3RsX3J4ZWQodWludDE2X3QgbmV0X2lkeCwgdWludDMyX3QgaXZfaW5kZXgsDQo+ID4g
KyAgICAgICAgICAgICAgIHVpbnQ4X3QgdHRsLCB1aW50MzJfdCBzZXFfbnVtLCB1aW50MTZfdCBz
cmMsIHVpbnQxNl90IGRzdCwNCj4gPiArICAgICAgICAgICAgICAgdWludDhfdCAqdHJhbnMsIHVp
bnQxNl90IGxlbikNCj4gPiArew0KPiA+ICsgICAgICAgLyogVE9ETzogSGFuZGxlIGNvbnRyb2wg
bWVzc2FnZXMgKi8NCj4gPiArICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArc3RydWN0IGRlY3J5cHRfcGFyYW1zIHsNCj4gPiArICAgICAgIHVpbnQ4X3QgICAgICAgICAq
bm9uY2U7DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAgICAgKmFhZDsNCj4gPiArICAgICAgIHVp
bnQ4X3QgICAgICAgICAqb3V0X21zZzsNCj4gPiArICAgICAgIHVpbnQ4X3QgICAgICAgICAqdHJh
bnM7DQo+ID4gKyAgICAgICB1aW50MzJfdCAgICAgICAgaXZfaW5kZXg7DQo+ID4gKyAgICAgICB1
aW50MzJfdCAgICAgICAgc2VxX251bTsNCj4gPiArICAgICAgIHVpbnQxNl90ICAgICAgICBzcmM7
DQo+ID4gKyAgICAgICB1aW50MTZfdCAgICAgICAgZHN0Ow0KPiA+ICsgICAgICAgdWludDE2X3Qg
ICAgICAgIGxlbjsNCj4gPiArICAgICAgIHVpbnQxNl90ICAgICAgICBuZXRfaWR4Ow0KPiA+ICsg
ICAgICAgdWludDE2X3QgICAgICAgIGFwcF9pZHg7DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAg
ICAgYWtmX2FpZDsNCj4gPiArICAgICAgIGJvb2wgICAgICAgICAgICBzem1pYzsNCj4gPiArfTsN
Cj4gPiArDQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCB0cnlfZGVjcnlwdChncG9pbnRlciBkYXRh
LCBncG9pbnRlciB1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX2Fw
cF9rZXkgKmFwcF9rZXkgPSBkYXRhOw0KPiA+ICsgICAgICAgc3RydWN0IGRlY3J5cHRfcGFyYW1z
ICpkZWNyeXB0ID0gdXNlcl9kYXRhOw0KPiA+ICsgICAgICAgc2l6ZV90IG1pY19zaXplID0gZGVj
cnlwdC0+c3ptaWMgPyBzaXplb2YodWludDY0X3QpIDogc2l6ZW9mKHVpbnQzMl90KTsNCj4gPiAr
ICAgICAgIGJvb2wgc3RhdHVzID0gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogQWxyZWFk
eSBkb25lLi4uIE5vdGhpbmcgdG8gZG8gKi8NCj4gPiArICAgICAgIGlmIChkZWNyeXB0LT5hcHBf
aWR4ICE9IEFQUF9JRFhfSU5WQUxJRCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+
ICsNCj4gPiArICAgICAgIC8qIERvbid0IGRlY3J5cHQgb24gQXBwa2V5cyBub3Qgb3duZWQgYnkg
dGhpcyBOZXRLZXkgKi8NCj4gPiArICAgICAgIGlmIChhcHBfa2V5LT5uZXRfaWR4ICE9IGRlY3J5
cHQtPm5ldF9pZHgpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAg
ICAgICAvKiBUZXN0IGFuZCBkZWNyeXB0IGFnYWluc3QgY3VycmVudCBrZXkgY29weSAqLw0KPiA+
ICsgICAgICAgaWYgKGFwcF9rZXktPmN1cnJlbnQuYWtmX2FpZCA9PSBkZWNyeXB0LT5ha2ZfYWlk
KQ0KPiA+ICsgICAgICAgICAgICAgICBzdGF0dXMgPSBtZXNoX2NyeXB0b19hZXNfY2NtX2RlY3J5
cHQoZGVjcnlwdC0+bm9uY2UsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBh
cHBfa2V5LT5jdXJyZW50LmtleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IGRlY3J5cHQtPmFhZCwgZGVjcnlwdC0+YWFkID8gMTYgOiAwLA0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgZGVjcnlwdC0+dHJhbnMsIGRlY3J5cHQtPmxlbiwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3J5cHQtPm91dF9tc2csIE5VTEwsIG1pY19z
aXplKTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBUZXN0IGFuZCBkZWNyeXB0IGFnYWluc3QgbmV3
IGtleSBjb3B5ICovDQo+ID4gKyAgICAgICBpZiAoIXN0YXR1cyAmJiBhcHBfa2V5LT5uZXcuYWtm
X2FpZCA9PSBkZWNyeXB0LT5ha2ZfYWlkKQ0KPiA+ICsgICAgICAgICAgICAgICBzdGF0dXMgPSBt
ZXNoX2NyeXB0b19hZXNfY2NtX2RlY3J5cHQoZGVjcnlwdC0+bm9uY2UsDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICBhcHBfa2V5LT5uZXcua2V5LA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgZGVjcnlwdC0+YWFkLCBkZWNyeXB0LT5hYWQgPyAxNiA6IDAs
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyeXB0LT50cmFucywgZGVj
cnlwdC0+bGVuLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcnlwdC0+
b3V0X21zZywgTlVMTCwgbWljX3NpemUpOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIElmIHN1Y2Nl
c3NmdWwsIHRlcm1pbmF0ZSB3aXRoIHN1Y2Nlc3NmdWwgQXBwIElEWCAqLw0KPiA+ICsgICAgICAg
aWYgKHN0YXR1cykNCj4gPiArICAgICAgICAgICAgICAgZGVjcnlwdC0+YXBwX2lkeCA9IGFwcF9r
ZXktPmdlbmVyaWMuaWR4Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdWludDE2X3QgYWNj
ZXNzX3BrdF9kZWNyeXB0KHVpbnQ4X3QgKm5vbmNlLCB1aW50OF90ICphYWQsDQo+ID4gKyAgICAg
ICAgICAgICAgIHVpbnQxNl90IG5ldF9pZHgsIHVpbnQ4X3QgYWtmX2FpZCwgYm9vbCBzem1pYywN
Cj4gPiArICAgICAgICAgICAgICAgdWludDhfdCAqdHJhbnMsIHVpbnQxNl90IGxlbikNCj4gPiAr
ew0KPiA+ICsgICAgICAgdWludDhfdCAqb3V0X21zZzsNCj4gPiArICAgICAgIHN0cnVjdCBkZWNy
eXB0X3BhcmFtcyBkZWNyeXB0ID0gew0KPiA+ICsgICAgICAgICAgICAgICAubm9uY2UgPSBub25j
ZSwNCj4gPiArICAgICAgICAgICAgICAgLmFhZCA9IGFhZCwNCj4gPiArICAgICAgICAgICAgICAg
Lm5ldF9pZHggPSBuZXRfaWR4LA0KPiA+ICsgICAgICAgICAgICAgICAuYWtmX2FpZCA9IGFrZl9h
aWQsDQo+ID4gKyAgICAgICAgICAgICAgIC5zem1pYyA9IHN6bWljLA0KPiA+ICsgICAgICAgICAg
ICAgICAudHJhbnMgPSB0cmFucywNCj4gPiArICAgICAgICAgICAgICAgLmxlbiA9IGxlbiwNCj4g
PiArICAgICAgICAgICAgICAgLmFwcF9pZHggPSBBUFBfSURYX0lOVkFMSUQsDQo+ID4gKyAgICAg
ICB9Ow0KPiA+ICsNCj4gPiArICAgICAgIG91dF9tc2cgPSBnX21hbGxvYyhsZW4pOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChvdXRfbXNnID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBkZWNyeXB0Lm91dF9tc2cgPSBvdXRfbXNn
Ow0KPiA+ICsNCj4gPiArICAgICAgIGdfbGlzdF9mb3JlYWNoKGFwcF9rZXlzLCB0cnlfZGVjcnlw
dCwgJmRlY3J5cHQpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChkZWNyeXB0LmFwcF9pZHggIT0g
QVBQX0lEWF9JTlZBTElEKQ0KPiA+ICsgICAgICAgICAgICAgICBtZW1jcHkodHJhbnMsIG91dF9t
c2csIGxlbik7DQo+ID4gKw0KPiA+ICsgICAgICAgZ19mcmVlKG91dF9tc2cpOw0KPiA+ICsNCj4g
PiArICAgICAgIHJldHVybiBkZWNyeXB0LmFwcF9pZHg7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0
YXRpYyBib29sIGFjY2Vzc19yeGVkKHVpbnQ4X3QgKm5vbmNlLCB1aW50MTZfdCBuZXRfaWR4LA0K
PiA+ICsgICAgICAgICAgICAgICB1aW50MzJfdCBpdl9pbmRleCwgdWludDMyX3Qgc2VxX251bSwN
Cj4gPiArICAgICAgICAgICAgICAgdWludDE2X3Qgc3JjLCB1aW50MTZfdCBkc3QsDQo+ID4gKyAg
ICAgICAgICAgICAgIHVpbnQ4X3QgYWtmX2FpZCwgYm9vbCBzem1pYywgdWludDhfdCAqdHJhbnMs
IHVpbnQxNl90IGxlbikNCj4gPiArew0KPiA+ICsgICAgICAgdWludDE2X3QgYXBwX2lkeCA9IGFj
Y2Vzc19wa3RfZGVjcnlwdChub25jZSwgTlVMTCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBuZXRfaWR4LCBha2ZfYWlkLCBzem1pYywgdHJhbnMsIGxlbik7DQo+ID4gKw0KPiA+ICsgICAg
ICAgaWYgKGFwcF9pZHggIT0gQVBQX0lEWF9JTlZBTElEKSB7DQo+ID4gKyAgICAgICAgICAgICAg
IGxlbiAtPSBzem1pYyA/IHNpemVvZih1aW50NjRfdCkgOiBzaXplb2YodWludDMyX3QpOw0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgbm9kZV9sb2NhbF9kYXRhX2hhbmRsZXIoc3JjLCBkc3Qs
IGl2X2luZGV4LCBzZXFfbnVtLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
YXBwX2lkeCwgdHJhbnMsIGxlbik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiB0cnVlOw0K
PiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIHZvaWQgdHJ5X3ZpcnRfZGVjcnlwdChncG9pbnRlciBkYXRhLCBn
cG9pbnRlciB1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX3ZpcnRf
YWRkciAqdmlydCA9IGRhdGE7DQo+ID4gKyAgICAgICBzdHJ1Y3QgZGVjcnlwdF9wYXJhbXMgKmRl
Y3J5cHQgPSB1c2VyX2RhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGRlY3J5cHQtPmFwcF9p
ZHggIT0gQVBQX0lEWF9JTlZBTElEIHx8IGRlY3J5cHQtPmRzdCAhPSB2aXJ0LQ0KPiA+dmExNikN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIGRlY3J5cHQt
PmFwcF9pZHggPSBhY2Nlc3NfcGt0X2RlY3J5cHQoZGVjcnlwdC0+bm9uY2UsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgdmlydC0+dmExMjgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgZGVjcnlwdC0+bmV0X2lkeCwgZGVjcnlwdC0+YWtmX2FpZCwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBkZWNyeXB0LT5zem1pYywgZGVjcnlwdC0+dHJhbnMsIGRlY3J5cHQtPmxlbik7
DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGRlY3J5cHQtPmFwcF9pZHggIT0gQVBQX0lEWF9JTlZB
TElEKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQxNl90IGxlbiA9IGRlY3J5cHQtPmxlbjsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGxlbiAtPSBkZWNyeXB0LT5zem1pYyA/IHNpemVv
Zih1aW50NjRfdCkgOiBzaXplb2YodWludDMyX3QpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgbm9kZV9sb2NhbF9kYXRhX2hhbmRsZXIoZGVjcnlwdC0+c3JjLCB2aXJ0LT52YTMyLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcnlwdC0+aXZfaW5kZXgsIGRlY3J5
cHQtPnNlcV9udW0sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyeXB0
LT5hcHBfaWR4LCBkZWNyeXB0LT50cmFucywgbGVuKTsNCj4gPiArICAgICAgIH0NCj4gPiArfQ0K
PiA+ICsNCj4gPiArc3RhdGljIGJvb2wgdmlydHVhbF9yeGVkKHVpbnQ4X3QgKm5vbmNlLCB1aW50
MTZfdCBuZXRfaWR4LA0KPiA+ICsgICAgICAgICAgICAgICB1aW50MzJfdCBpdl9pbmRleCwgdWlu
dDMyX3Qgc2VxX251bSwNCj4gPiArICAgICAgICAgICAgICAgdWludDE2X3Qgc3JjLCB1aW50MTZf
dCBkc3QsDQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQ4X3QgYWtmX2FpZCwgYm9vbCBzem1pYywg
dWludDhfdCAqdHJhbnMsIHVpbnQxNl90IGxlbikNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0
IGRlY3J5cHRfcGFyYW1zIGRlY3J5cHQgPSB7DQo+ID4gKyAgICAgICAgICAgICAgIC5ub25jZSA9
IG5vbmNlLA0KPiA+ICsgICAgICAgICAgICAgICAubmV0X2lkeCA9IG5ldF9pZHgsDQo+ID4gKyAg
ICAgICAgICAgICAgIC5pdl9pbmRleCA9IGl2X2luZGV4LA0KPiA+ICsgICAgICAgICAgICAgICAu
c2VxX251bSA9IHNlcV9udW0sDQo+ID4gKyAgICAgICAgICAgICAgIC5zcmMgPSBkc3QsDQo+ID4g
KyAgICAgICAgICAgICAgIC5kc3QgPSBkc3QsDQo+ID4gKyAgICAgICAgICAgICAgIC5ha2ZfYWlk
ID0gYWtmX2FpZCwNCj4gPiArICAgICAgICAgICAgICAgLnN6bWljID0gc3ptaWMsDQo+ID4gKyAg
ICAgICAgICAgICAgIC50cmFucyA9IHRyYW5zLA0KPiA+ICsgICAgICAgICAgICAgICAubGVuID0g
bGVuLA0KPiA+ICsgICAgICAgICAgICAgICAuYXBwX2lkeCA9IEFQUF9JRFhfSU5WQUxJRCwNCj4g
PiArICAgICAgIH07DQo+ID4gKw0KPiA+ICsgICAgICAgLyogQ3ljbGUgdGhyb3VnaCBrbm93biB2
aXJ0dWFsIGFkZHJlc3NlcyAqLw0KPiA+ICsgICAgICAgZ19saXN0X2ZvcmVhY2godmlydF9hZGRy
cywgdHJ5X3ZpcnRfZGVjcnlwdCwgJmRlY3J5cHQpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChk
ZWNyeXB0LmFwcF9pZHggIT0gQVBQX0lEWF9JTlZBTElEKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gdHJ1ZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3N0YXRpYyBib29sIG1zZ19yeGVkKHVpbnQxNl90IG5ldF9pZHgsIHVpbnQzMl90
IGl2X2luZGV4LCBib29sIHN6bWljLA0KPiA+ICsgICAgICAgICAgICAgICB1aW50OF90IHR0bCwg
dWludDMyX3Qgc2VxX251bSwgdWludDMyX3Qgc2VxX2F1dGgsDQo+ID4gKyAgICAgICAgICAgICAg
IHVpbnQxNl90IHNyYywgdWludDE2X3QgZHN0LA0KPiA+ICsgICAgICAgICAgICAgICB1aW50OF90
ICp0cmFucywgdWludDE2X3QgbGVuKQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50OF90IGFrZl9h
aWQgPSBUUkFOU19BS0ZfQUlEKHRyYW5zKTsNCj4gPiArICAgICAgIGJvb2wgcmVzdWx0Ow0KPiA+
ICsgICAgICAgc2l6ZV90IG1pY19zaXplID0gc3ptaWMgPyBzaXplb2YodWludDY0X3QpIDogc2l6
ZW9mKHVpbnQzMl90KTsNCj4gPiArICAgICAgIHVpbnQ4X3Qgbm9uY2VbMTNdOw0KPiA+ICsgICAg
ICAgdWludDhfdCAqZGV2X2tleTsNCj4gPiArICAgICAgIHVpbnQ4X3QgKm91dCA9IE5VTEw7DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKCFUUkFOU19BS0YodHJhbnMpKSB7DQo+ID4gKyAgICAgICAg
ICAgICAgIC8qIENvbXBvc2UgTm9uY2UgKi8NCj4gPiArICAgICAgICAgICAgICAgcmVzdWx0ID0g
bWVzaF9jcnlwdG9fZGV2aWNlX25vbmNlKHNlcV9hdXRoLCBzcmMsIGRzdCwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIGl2X2luZGV4LCBzem1pYywgbm9uY2UpOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgaWYgKCFyZXN1bHQpIHJldHVybiBmYWxzZTsNCj4gPiArDQo+
ID4gKyAgICAgICAgICAgICAgIG91dCA9IGdfbWFsbG9jMChUUkFOU19MRU4odHJhbnMsIGxlbikp
Ow0KPiA+ICsgICAgICAgICAgICAgICBpZiAob3V0ID09IE5VTEwpIHJldHVybiBmYWxzZTsNCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIElmIHdlIGFyZSBwcm92aXNpb25lciwgd2UgcHJv
YmFibHkgUlhlZCBvbiByZW1vdGUgRGV2IEtleSAqLw0KPiA+ICsgICAgICAgICAgICAgICBpZiAo
bmV0LnByb3Zpc2lvbmVyKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZGV2X2tleSA9
IG5vZGVfZ2V0X2RldmljZV9rZXkobm9kZV9maW5kX2J5X2FkZHIoc3JjKSk7DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChkZXZfa2V5ID09IE5VTEwpDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGxvY2FsX2Rldl9rZXk7DQo+ID4gKyAgICAg
ICAgICAgICAgIH0gZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gbG9jYWxf
ZGV2X2tleTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHJlc3VsdCA9IG1lc2hfY3J5cHRv
X2Flc19jY21fZGVjcnlwdChub25jZSwgZGV2X2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIE5VTEwsIDAsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBUUkFOU19QQVlMT0FEKHRyYW5zKSwgVFJBTlNfTEVOKHRyYW5zLCBsZW4pLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0LCBOVUxMLCBtaWNfc2l6ZSk7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBpZiAocmVzdWx0KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgbm9kZV9sb2NhbF9kYXRhX2hhbmRsZXIoc3JjLCBkc3QsDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl2X2luZGV4LCBzZXFfbnVtLCBBUFBfSURYX0RF
ViwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0LCBUUkFO
U19MRU4odHJhbnMsIGxlbikgLSBtaWNfc2l6ZSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICtsb2NhbF9k
ZXZfa2V5Og0KPiA+ICsgICAgICAgICAgICAgICAvKiBBbHdheXMgZmFsbGJhY2sgdG8gdGhlIGxv
Y2FsIERldiBLZXkgKi8NCj4gPiArICAgICAgICAgICAgICAgZGV2X2tleSA9IG5vZGVfZ2V0X2Rl
dmljZV9rZXkobm9kZV9nZXRfbG9jYWxfbm9kZSgpKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgIGlmIChkZXZfa2V5ID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ290
byBkb25lOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmVzdWx0ID0gbWVzaF9jcnlwdG9f
YWVzX2NjbV9kZWNyeXB0KG5vbmNlLCBkZXZfa2V5LA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgTlVMTCwgMCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IFRSQU5TX1BBWUxPQUQodHJhbnMpLCBUUkFOU19MRU4odHJhbnMsIGxlbiksDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBvdXQsIE5VTEwsIG1pY19zaXplKTsNCj4gPiArDQo+
ID4gKyAgICAgICAgICAgICAgIGlmIChyZXN1bHQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICBub2RlX2xvY2FsX2RhdGFfaGFuZGxlcihzcmMsIGRzdCwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgaXZfaW5kZXgsIHNlcV9udW0sIEFQUF9JRFhfREVW
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXQsIFRSQU5T
X0xFTih0cmFucywgbGVuKSAtIG1pY19zaXplKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBnb3RvIGRvbmU7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAg
ICAgICAgIGdvdG8gZG9uZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXN1
bHQgPSBtZXNoX2NyeXB0b19hcHBsaWNhdGlvbl9ub25jZShzZXFfYXV0aCwgc3JjLCBkc3QsDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaXZfaW5kZXgsIHN6bWljLCBub25jZSk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKCFyZXN1bHQpIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAg
ICAvKiBJZiBWaXJ0dWFsIGRlc3RpbmF0aW9uIHdyYXAgdGhlIEFjY2VzcyBkZWNvZGVyIHdpdGgg
VmlydHVhbCAqLw0KPiA+ICsgICAgICAgaWYgKElTX1ZJUlRVQUwoZHN0KSkgew0KPiA+ICsgICAg
ICAgICAgICAgICByZXN1bHQgPSB2aXJ0dWFsX3J4ZWQobm9uY2UsIG5ldF9pZHgsIGl2X2luZGV4
LCBzZXFfbnVtLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3JjLCBkc3Qs
IGFrZl9haWQsIHN6bWljLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJB
TlNfUEFZTE9BRCh0cmFucyksIFRSQU5TX0xFTih0cmFucywgbGVuKSk7DQo+ID4gKyAgICAgICAg
ICAgICAgIGdvdG8gZG9uZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAvKiBU
cnkgYWxsIG1hdGNoaW5nIEFwcCBLZXlzIHVudGlsIHN1Y2Nlc3Mgb3IgZXhoYXVzdGlvbiAqLw0K
PiA+ICsgICAgICAgcmVzdWx0ID0gYWNjZXNzX3J4ZWQobm9uY2UsIG5ldF9pZHgsIGl2X2luZGV4
LCBzZXFfbnVtLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHNyYywgZHN0LCBha2ZfYWlk
LCBzem1pYywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBUUkFOU19QQVlMT0FEKHRyYW5z
KSwgVFJBTlNfTEVOKHRyYW5zLCBsZW4pKTsNCj4gPiArDQo+ID4gK2RvbmU6DQo+ID4gKyAgICAg
ICBpZiAob3V0ICE9IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIGdfZnJlZShvdXQpOw0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiByZXN1bHQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRp
YyB2b2lkIHNlbmRfc2FyX2FjayhzdHJ1Y3QgbWVzaF9zYXJfbXNnICpzYXIpDQo+ID4gK3sNCj4g
PiArICAgICAgIHVpbnQ4X3QgYWNrWzddOw0KPiA+ICsNCj4gPiArICAgICAgIHNhci0+YWN0aXZp
dHlfY250ID0gMDsNCj4gPiArDQo+ID4gKyAgICAgICBtZW1zZXQoYWNrLCAwLCBzaXplb2YoYWNr
KSk7DQo+ID4gKyAgICAgICBTRVRfVFJBTlNfT1BDT0RFKGFjaywgTkVUX09QX1NFR19BQ0tOT1dM
RURHRSk7DQo+ID4gKyAgICAgICBTRVRfVFJBTlNfU0VRMChhY2ssIHNhci0+c2VxQXV0aCk7DQo+
ID4gKyAgICAgICBTRVRfVFJBTlNfQUNLKGFjaywgc2FyLT5hY2spOw0KPiA+ICsNCj4gPiArICAg
ICAgIG5ldF9jdGxfbXNnX3NlbmQoMHhmZiwgc2FyLT5kc3QsIHNhci0+c3JjLCBhY2ssIHNpemVv
ZihhY2spKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGdib29sZWFuIHNhcl9vdXRfYWNr
X3RpbWVvdXQodm9pZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVz
aF9zYXJfbXNnICpzYXIgPSB1c2VyX2RhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgc2FyLT5hY3Rp
dml0eV9jbnQrKzsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBCZWNhdXNlIHdlIGFyZSBHQVRULCBh
bmQgc2xvdywgb25seSByZXNlbmQgUEtUcyBpZiBpdCBpcw0KPiA+ICsgICAgICAgICogdGltZSAq
YW5kKiBvdXIgb3V0Ym91bmQgUEtUIHF1ZXVlIGlzIGVtcHR5LiAgKi8NCj4gPiArICAgICAgIGlm
IChuZXQucGt0X291dCA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICByZXNlbmRfc2Vncyhz
YXIpOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIE9ubHkgYWRkIHJlc2VudCBTQVIgcGt0cyB0byBl
bXB0eSBxdWV1ZSAqLw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+
ID4gK3N0YXRpYyBnYm9vbGVhbiBzYXJfb3V0X21zZ190aW1lb3V0KHZvaWQgKnVzZXJfZGF0YSkN
Cj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfc2FyX21zZyAqc2FyID0gdXNlcl9kYXRh
Ow0KPiA+ICsNCj4gPiArICAgICAgIC8qIG1zZ190byB3aWxsIGV4cGlyZSB3aGVuIHdlIHJldHVy
biBmYWxzZSAqLw0KPiA+ICsgICAgICAgc2FyLT5tc2dfdG8gPSAwOw0KPiA+ICsNCj4gPiArICAg
ICAgIGZsdXNoX3NhcigmbmV0Lm1zZ19vdXQsIHNhcik7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0
dXJuIGZhbHNlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgZ2Jvb2xlYW4gc2FyX2luX2Fj
a190aW1lb3V0KHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1l
c2hfc2FyX21zZyAqc2FyID0gdXNlcl9kYXRhOw0KPiA+ICsgICAgICAgdWludDMyX3QgZnVsbF9h
Y2sgPSAweGZmZmZmZmZmID4+ICgzMSAtIHNhci0+c2VnTik7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKHNhci0+YWN0aXZpdHlfY250IHx8IHNhci0+YWNrICE9IGZ1bGxfYWNrKQ0KPiA+ICsgICAg
ICAgICAgICAgICBzZW5kX3Nhcl9hY2soc2FyKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4g
dHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGdib29sZWFuIHNhcl9pbl9tc2dfdGlt
ZW91dCh2b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX3Nh
cl9tc2cgKnNhciA9IHVzZXJfZGF0YTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBtc2dfdG8gd2ls
bCBleHBpcmUgd2hlbiB3ZSByZXR1cm4gZmFsc2UgKi8NCj4gPiArICAgICAgIHNhci0+bXNnX3Rv
ID0gMDsNCj4gPiArDQo+ID4gKyAgICAgICBmbHVzaF9zYXIoJm5ldC5zYXJfaW4sIHNhcik7DQo+
ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgdWludDMyX3QgY2FsY19zZXFBdXRoKHVpbnQzMl90IHNlcV9udW0sIHVpbnQ4X3QgKnRyYW5z
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50MzJfdCBzZXFBdXRoID0gc2VxX251bSAmIH4weDFm
ZmY7DQo+ID4gKw0KPiA+ICsgICAgICAgc2VxQXV0aCB8PSBUUkFOU19TRVEwKHRyYW5zKTsNCj4g
PiArDQo+ID4gKyAgICAgICByZXR1cm4gc2VxQXV0aDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3Rh
dGljIGJvb2wgc2VnX3J4ZWQodWludDE2X3QgbmV0X2lkeCwgdWludDMyX3QgaXZfaW5kZXgsIGJv
b2wgY3RsLA0KPiA+ICsgICAgICAgICAgICAgICB1aW50OF90IHR0bCwgdWludDMyX3Qgc2VxX251
bSwgdWludDE2X3Qgc3JjLCB1aW50MTZfdCBkc3QsDQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQ4
X3QgKnRyYW5zLCB1aW50MTZfdCBsZW4pDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNo
X3Nhcl9tc2cgKnNhcjsNCj4gPiArICAgICAgIHVpbnQzMl90IHNlcUF1dGggPSBjYWxjX3NlcUF1
dGgoc2VxX251bSwgdHJhbnMpOw0KPiA+ICsgICAgICAgdWludDhfdCBzZWdOLCBzZWdPOw0KPiA+
ICsgICAgICAgdWludDMyX3Qgb2xkX2FjaywgZnVsbF9hY2ssIGxhc3RfYWNrX21hc2s7DQo+ID4g
KyAgICAgICBib29sIHNlbmRfYWNrLCByZXN1bHQgPSBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBzZWdOID0gVFJBTlNfU0VHTih0cmFucyk7DQo+ID4gKyAgICAgICBzZWdPID0gVFJBTlNfU0VH
Tyh0cmFucyk7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogT25seSBzdXBwb3J0IHNpbmdsZSBpbmNv
bWluZyBTQVInZCBtZXNzYWdlIHBlciBTUkMgKi8NCj4gPiArICAgICAgIHNhciA9IGZpbmRfc2Fy
X2luX2J5X3NyYyhzcmMpOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIFJldXNlIGV4aXN0aW5nIFNB
UiBzdHJ1Y3R1cmUgaWYgYXBwcm9wcmlhdGUgKi8NCj4gPiArICAgICAgIGlmIChzYXIpIHsNCj4g
PiArICAgICAgICAgICAgICAgdWludDY0X3QgaXZfc2VxQXV0aCA9ICh1aW50NjRfdClpdl9pbmRl
eCA8PCAzMiB8IHNlcUF1dGg7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQ2NF90IG9sZF9pdl9z
ZXFBdXRoID0gKHVpbnQ2NF90KXNhci0+aXZfaW5kZXggPDwgMzIgfA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgIHNhci0+c2VxQXV0aDsNCj4gPiArICAgICAgICAgICAgICAgaWYgKG9sZF9p
dl9zZXFBdXRoIDwgaXZfc2VxQXV0aCkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICBmbHVzaF9zYXIoJm5ldC5zYXJfaW4sIHNhcik7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgc2FyID0gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIH0gZWxzZSBpZiAo
b2xkX2l2X3NlcUF1dGggPiBpdl9zZXFBdXRoKSB7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIC8qIE5ldyBzZWdtZW50IGlzIFN0YWxlLiBTaWxlbnRseSBpZ25vcmUgKi8NCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICB9IGVsc2UgaWYgKHNlZ04gIT0gc2FyLT5zZWdOKSB7DQo+ID4gKw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIC8qIFJlbW90ZSBzaWRlIHNlbnQgY29uZmxpY3RpbmcgZGF0
YTogYWJhbmRvbiAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGZsdXNoX3NhcigmbmV0
LnNhcl9pbiwgc2FyKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBzYXIgPSBOVUxMOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmIChzYXIgPT0gTlVMTCkgew0KPiA+ICsgICAgICAgICAgICAgICBzYXIgPSBnX21h
bGxvYzAoc2l6ZW9mKCpzYXIpICsgKDEyICogc2VnTikpOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgaWYgKHNhciA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVy
biBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHNhci0+bmV0X2lkeCA9IG5ldF9p
ZHg7DQo+ID4gKyAgICAgICAgICAgICAgIHNhci0+aXZfaW5kZXggPSBpdl9pbmRleDsNCj4gPiAr
ICAgICAgICAgICAgICAgc2FyLT5jdGwgPSBjdGw7DQo+ID4gKyAgICAgICAgICAgICAgIHNhci0+
dHRsID0gdHRsOw0KPiA+ICsgICAgICAgICAgICAgICBzYXItPnNlcUF1dGggPSBzZXFBdXRoOw0K
PiA+ICsgICAgICAgICAgICAgICBzYXItPnNyYyA9IHNyYzsNCj4gPiArICAgICAgICAgICAgICAg
c2FyLT5kc3QgPSBkc3Q7DQo+ID4gKyAgICAgICAgICAgICAgIHNhci0+c2VnbWVudGVkID0gdHJ1
ZTsNCj4gPiArICAgICAgICAgICAgICAgc2FyLT5zem1pYyA9IFRSQU5TX1NaTUlDKHRyYW5zKTsN
Cj4gPiArICAgICAgICAgICAgICAgc2FyLT5zZWdOID0gc2VnTjsNCj4gPiArDQo+ID4gKyAgICAg
ICAgICAgICAgIC8qIEluIGFsbCBjYXNlcywgdGhlIHJlYXNzZW1ibGVkIHBhY2tldCBzaG91bGQg
YmVnaW4gd2l0aCB0aGUNCj4gPiArICAgICAgICAgICAgICAgICogc2FtZSBmaXJzdCBvY3RldCBv
ZiBhbGwgc2VnbWVudHMsIG1pbnVzIHRoZSBTRUdNRU5URUQgZmxhZyAqLw0KPiA+ICsgICAgICAg
ICAgICAgICBzYXItPmRhdGFbMF0gPSB0cmFuc1swXSAmIDB4N2Y7DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICBuZXQuc2FyX2luID0gZ19saXN0X2FwcGVuZChuZXQuc2FyX2luLCBzYXIpOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgLyogU2V0dXAgZXhwaXJhdGlvbiB0aW1lcnMgKi8N
Cj4gPiArICAgICAgICAgICAgICAgaWYgKElTX1VOSUNBU1QoZHN0KSkNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBzYXItPmFja190byA9IGdfdGltZW91dF9hZGQoNTAwMCwNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FyX2luX2Fja190aW1lb3V0LCBz
YXIpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgc2FyLT5tc2dfdG8gPSBnX3RpbWVvdXRf
YWRkKDYwMDAwLCBzYXJfaW5fbXNnX3RpbWVvdXQsIHNhcik7DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgLyogSWYgbGFzdCBzZWdtZW50LCBjYWxjdWxhdGUgZnVsbCBtc2cgc2l6
ZSAqLw0KPiA+ICsgICAgICAgaWYgKHNlZ04gPT0gc2VnTykNCj4gPiArICAgICAgICAgICAgICAg
c2FyLT5sZW4gPSAoc2VnTiAqIDEyKSArIGxlbiAtIDM7DQo+ID4gKw0KPiA+ICsgICAgICAgLyog
Q29weSB0byBjb3JyZWN0IG9mZnNldCAqLw0KPiA+ICsgICAgICAgbWVtY3B5KHNhci0+ZGF0YSAr
IDEgKyAoMTIgKiBzZWdPKSwgdHJhbnMgKyA0LCAxMik7DQo+ID4gKw0KPiA+ICsgICAgICAgZnVs
bF9hY2sgPSAweGZmZmZmZmZmID4+ICgzMSAtIHNlZ04pOw0KPiA+ICsgICAgICAgbGFzdF9hY2tf
bWFzayA9IDB4ZmZmZmZmZmYgPDwgc2VnTzsNCj4gPiArICAgICAgIG9sZF9hY2sgPSBzYXItPmFj
azsNCj4gPiArICAgICAgIHNhci0+YWNrIHw9IDEgPDwgc2VnTzsNCj4gPiArICAgICAgIHNlbmRf
YWNrID0gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogRGV0ZXJtaW5lIGlmIHdlIHNob3Vs
ZCBmb3J3YXJkIG1lc3NhZ2UgKi8NCj4gPiArICAgICAgIGlmIChzYXItPmFjayA9PSBmdWxsX2Fj
ayAmJiBvbGRfYWNrICE9IGZ1bGxfYWNrKSB7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAv
KiBGaXJzdCB0aW1lIHdlIGhhdmUgc2VlbiB0aGlzIGNvbXBsZXRlIG1lc3NhZ2UgKi8NCj4gPiAr
ICAgICAgICAgICAgICAgc2VuZF9hY2sgPSB0cnVlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgaWYgKGN0bCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBjdGxfcnhl
ZChzYXItPm5ldF9pZHgsIHNhci0+aXZfaW5kZXgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHNhci0+dHRsLCBzYXItPnNlcUF1dGgsIHNhci0+c3JjLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYXItPmRzdCwgc2FyLT5k
YXRhLCBzYXItPmxlbik7DQo+ID4gKyAgICAgICAgICAgICAgIGVsc2UNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICByZXN1bHQgPSBtc2dfcnhlZChzYXItPm5ldF9pZHgsIHNhci0+aXZfaW5k
ZXgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhci0+c3pt
aWMsIHNhci0+dHRsLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBzZXFfbnVtLCBzYXItPnNlcUF1dGgsIHNhci0+c3JjLA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICBzYXItPmRzdCwgc2FyLT5kYXRhLCBzYXItPmxlbik7DQo+
ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgLyogTmV2ZXIgQWNrIEdyb3VwIGFkZHJl
c3NlZCBTQVIgbWVzc2FnZXMgKi8NCj4gPiArICAgICAgIGlmICghSVNfVU5JQ0FTVChkc3QpKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0Ow0KPiA+ICsNCj4gPiArICAgICAgIC8q
IFRpY2tsZSB0aGUgQUNLIHN5c3RlbSBzbyBpdCBrbm93cyB3ZSBhcmUgc3RpbGwgUlhpbmcgc2Vn
bWVudHMgKi8NCj4gPiArICAgICAgIHNhci0+YWN0aXZpdHlfY250Kys7DQo+ID4gKw0KPiA+ICsg
ICAgICAgLyogRGV0ZXJtaW5lIGlmIHdlIHNob3VsZCBBQ0sgKi8NCj4gPiArICAgICAgIGlmIChv
bGRfYWNrID09IHNhci0+YWNrKQ0KPiA+ICsgICAgICAgICAgICAgICAvKiBMZXQgdGhlIHRpbWVy
IGdlbmVyYXRlIHJlcGVhdCBBQ0tzIGFzIG5lZWRlZCAqLw0KPiA+ICsgICAgICAgICAgICAgICBz
ZW5kX2FjayA9IGZhbHNlOw0KPiA+ICsgICAgICAgZWxzZSBpZiAoKGxhc3RfYWNrX21hc2sgJiBz
YXItPmFjaykgPT0gKGxhc3RfYWNrX21hc2sgJiBmdWxsX2FjaykpDQo+ID4gKyAgICAgICAgICAg
ICAgIC8qIElmIHRoaXMgd2FzIGxhcmdlc3Qgc2VnTyBvdXRzdGFuZGluZyBzZWdtZW50LCB3ZSBB
Q0sgKi8NCj4gPiArICAgICAgICAgICAgICAgc2VuZF9hY2sgPSB0cnVlOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmIChzZW5kX2FjaykNCj4gPiArICAgICAgICAgICAgICAgc2VuZF9zYXJfYWNrKHNh
cik7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHJlc3VsdDsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArYm9vbCBuZXRfZGF0YV9yZWFkeSh1aW50OF90ICptc2csIHVpbnQ4X3QgbGVuKQ0KPiA+ICt7
DQo+ID4gKyAgICAgICB1aW50OF90IHR5cGUgPSAqbXNnKys7DQo+ID4gKyAgICAgICB1aW50MzJf
dCBpdl9pbmRleCA9IG5ldC5pdl9pbmRleDsNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX25ldF9r
ZXkgKm5ldF9rZXk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGxlbi0tIDwgMTApIHJldHVybiBm
YWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAodHlwZSA9PSBQUk9YWV9NRVNIX0JFQUNPTikN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHByb2Nlc3NfYmVhY29uKG1zZywgbGVuKTsNCj4g
PiArICAgICAgIGVsc2UgaWYgKHR5cGUgPiBQUk9YWV9DT05GSUdfUERVKQ0KPiA+ICsgICAgICAg
ICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogUlhlZCBpdl9pbmRl
eCBtdXN0IGJlIGVxdWFsIG9yIDEgbGVzcyB0aGFuIGxvY2FsIGl2X2luZGV4ICovDQo+ID4gKyAg
ICAgICAvKiBXaXRoIHRoZSBjbHVlIGJlaW5nIGhpZ2gtb3JkZXIgYml0IG9mIGZpcnN0IG9jdGV0
ICovDQo+ID4gKyAgICAgICBpZiAoISEoaXZfaW5kZXggJiAweDAxKSAhPSAhIShtc2dbMF0gJiAw
eDgwKSkgew0KPiA+ICsgICAgICAgICAgICAgICBpZiAoaXZfaW5kZXgpDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgaXZfaW5kZXgtLTsNCj4gPiArICAgICAgICAgICAgICAgZWxzZQ0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gKyAgICAgICBuZXRfa2V5ID0gbmV0X3BhY2tldF9kZWNvZGUodHlwZSA9PSBQUk9Y
WV9DT05GSUdfUERVLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGl2X2luZGV4LCBtc2cs
IGxlbik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKG5ldF9rZXkgPT0gTlVMTCkNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIENUTCBwYWNr
ZXRzIGhhdmUgNjQgYml0IG5ldHdvcmsgTUlDLCBvdGhlcndpc2UgMzIgYml0IE1JQyAqLw0KPiA+
ICsgICAgICAgbGVuIC09IFBLVF9DVEwobXNnKSA/IHNpemVvZih1aW50NjRfdCkgOiBzaXplb2Yo
dWludDMyX3QpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICh0eXBlID09IFBST1hZX0NPTkZJR19Q
RFUpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIFByb3h5IENvbmZpZ3VyYXRpb24g
RFNUIG1lc3NhZ2VzIG11c3QgYmUgMHgwMDAwICovDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChQ
S1RfRFNUKG1zZykpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHByb3h5X2N0bF9yeGVkKG5ldF9rZXkt
PmdlbmVyaWMuaWR4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXZfaW5k
ZXgsIFBLVF9UVEwobXNnKSwgUEtUX1NFUShtc2cpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgUEtUX1NSQyhtc2cpLCBQS1RfRFNUKG1zZyksDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBQS1RfVFJBTlMobXNnKSwgUEtUX1RSQU5TX0xFTihsZW4pKTsN
Cj4gPiArDQo+ID4gKyAgICAgICB9IGlmIChQS1RfQ1RMKG1zZykgJiYgUEtUX09QQ09ERShtc2cp
ID09DQo+IE5FVF9PUF9TRUdfQUNLTk9XTEVER0UpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiBhY2tfcnhlZChmYWxzZSwgUEtUX1NSQyhtc2cpLCBQS1RfRFNUKG1zZyksDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQS1RfT0JPKG1zZyksIFBLVF9TRVEw
KG1zZyksIFBLVF9BQ0sobXNnKSk7DQo+ID4gKw0KPiA+ICsgICAgICAgfSBlbHNlIGlmIChQS1Rf
U0VHTUVOVEVEKG1zZykpIHsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBzZWdf
cnhlZChuZXRfa2V5LT5nZW5lcmljLmlkeCwgaXZfaW5kZXgsIFBLVF9DVEwobXNnKSwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBLVF9UVEwobXNnKSwgUEtUX1NFUShtc2cp
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUEtUX1NSQyhtc2cpLCBQS1Rf
RFNUKG1zZyksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQS1RfVFJBTlMo
bXNnKSwgUEtUX1RSQU5TX0xFTihsZW4pKTsNCj4gPiArDQo+ID4gKyAgICAgICB9IGVsc2UgaWYg
KCFQS1RfQ1RMKG1zZykpew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIG1zZ19y
eGVkKG5ldF9rZXktPmdlbmVyaWMuaWR4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgaXZfaW5kZXgsIGZhbHNlLCBQS1RfVFRMKG1zZyksIFBLVF9TRVEobXNnKSwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBLVF9TRVEobXNnKSwgUEtUX1NSQyhtc2cp
LCBQS1RfRFNUKG1zZyksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQS1Rf
VFJBTlMobXNnKSwgUEtUX1RSQU5TX0xFTihsZW4pKTsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gY3RsX3J4ZWQobmV0X2tleS0+Z2VuZXJp
Yy5pZHgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdl9pbmRleCwgUEtU
X1RUTChtc2cpLCBQS1RfU0VRKG1zZyksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBQS1RfU1JDKG1zZyksIFBLVF9EU1QobXNnKSwNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIFBLVF9UUkFOUyhtc2cpLCBQS1RfVFJBTlNfTEVOKGxlbikpOw0KPiA+ICsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gK30N
Cj4gPiArDQo+ID4gK2Jvb2wgbmV0X3Nlc3Npb25fb3BlbihHREJ1c1Byb3h5ICpkYXRhX2luLCBi
b29sIHByb3Zpc2lvbmVyLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBuZXRfbWVzaF9zZXNzaW9uX29wZW5fY2FsbGJhY2sgY2IpDQo+ID4gK3sNCj4gPiArICAg
ICAgIGlmIChuZXQucHJveHlfaW4pDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsN
Cj4gPiArDQo+ID4gKyAgICAgICBuZXQucHJveHlfaW4gPSBkYXRhX2luOw0KPiA+ICsgICAgICAg
bmV0Lml2X3VwZF9zdGF0ZSA9IElWX1VQRF9JTklUOw0KPiA+ICsgICAgICAgbmV0LmJsYWNrbGlz
dCA9IGZhbHNlOw0KPiA+ICsgICAgICAgbmV0LnByb3Zpc2lvbmVyID0gcHJvdmlzaW9uZXI7DQo+
ID4gKyAgICAgICBuZXQub3Blbl9jYiA9IGNiOw0KPiA+ICsgICAgICAgZmx1c2hfcGt0X2xpc3Qo
Jm5ldC5wa3Rfb3V0KTsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0K
PiA+ICt2b2lkIG5ldF9zZXNzaW9uX2Nsb3NlKEdEQnVzUHJveHkgKmRhdGFfaW4pDQo+ID4gK3sN
Cj4gPiArICAgICAgIGlmIChuZXQucHJveHlfaW4gPT0gZGF0YV9pbikNCj4gPiArICAgICAgICAg
ICAgICAgbmV0LnByb3h5X2luID0gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICBmbHVzaF9zYXJf
bGlzdCgmbmV0LnNhcl9pbik7DQo+ID4gKyAgICAgICBmbHVzaF9zYXJfbGlzdCgmbmV0Lm1zZ19v
dXQpOw0KPiA+ICsgICAgICAgZmx1c2hfcGt0X2xpc3QoJm5ldC5wa3Rfb3V0KTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArYm9vbCBuZXRfcmVnaXN0ZXJfdW5pY2FzdCh1aW50MTZfdCB1bmljYXN0LCB1
aW50OF90IGNvdW50KQ0KPiA+ICt7DQo+ID4gKyAgICAgICAvKiBUT0RPICovDQo+ID4gKyAgICAg
ICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBuZXRfcmVnaXN0ZXJfZ3Jv
dXAodWludDE2X3QgZ3JvdXBfYWRkcikNCj4gPiArew0KPiA+ICsgICAgICAgLyogVE9ETyAqLw0K
PiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQzMl90IG5l
dF9yZWdpc3Rlcl92aXJ0dWFsKHVpbnQ4X3QgYnVmWzE2XSkNCj4gPiArew0KPiA+ICsgICAgICAg
LyogVE9ETyAqLw0KPiA+ICsgICAgICAgcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0
YXRpYyBib29sIGdldF9lbmNfa2V5cyh1aW50MTZfdCBhcHBfaWR4LCB1aW50MTZfdCBkc3QsDQo+
ID4gKyAgICAgICAgICAgICAgIHVpbnQ4X3QgKmFrZl9haWQsIHVpbnQ4X3QgKiphcHBfZW5jX2tl
eSwNCj4gPiArICAgICAgICAgICAgICAgdWludDE2X3QgKm5ldF9pZHgpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIGlmIChhcHBfaWR4ID09IEFQUF9JRFhfREVWKSB7DQo+ID4gKyAgICAgICAgICAgICAg
IHN0cnVjdCBtZXNoX25vZGUgKm5vZGU7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQ4X3QgKmVu
Y19rZXkgPSBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKG5ldC5wcm92aXNp
b25lcikgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIC8qIERlZmF1bHQgdG8gUmVtb3Rl
IERldmljZSBLZXkgd2hlbiBQcm92aXNpb25lciAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIG5vZGUgPSBub2RlX2ZpbmRfYnlfYWRkcihkc3QpOw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIGVuY19rZXkgPSBub2RlX2dldF9kZXZpY2Vfa2V5KG5vZGUpOw0KPiA+ICsgICAgICAg
ICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoZW5jX2tleSA9PSBOVUxM
KSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgLyogVXNlIExvY2FsIG5vZGUgRGV2aWNl
IEtleSAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG5vZGUgPSBub2RlX2dldF9sb2Nh
bF9ub2RlKCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZW5jX2tleSA9IG5vZGVfZ2V0
X2RldmljZV9rZXkobm9kZSk7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICAgICAgICAgIGlmIChlbmNfa2V5ID09IE5VTEwgfHwgbm9kZSA9PSBOVUxMKQ0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAg
ICAgICAgIGlmIChha2ZfYWlkKSAqYWtmX2FpZCA9IDA7DQo+ID4gKyAgICAgICAgICAgICAgIGlm
IChhcHBfZW5jX2tleSkgKmFwcF9lbmNfa2V5ID0gZW5jX2tleTsNCj4gPiArICAgICAgICAgICAg
ICAgaWYgKG5ldF9pZHgpICpuZXRfaWR4ID0gbm9kZV9nZXRfcHJpbWFyeV9uZXRfaWR4KG5vZGUp
Ow0KPiA+ICsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0cnVj
dCBtZXNoX2FwcF9rZXkgKmFwcF9rZXkgPQ0KPiBmaW5kX2FwcF9rZXlfYnlfaWR4KGFwcF9pZHgp
Ow0KPiA+ICsgICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF9uZXRfa2V5ICpuZXRfa2V5Ow0KPiA+
ICsgICAgICAgICAgICAgICBib29sIHBoYXNlX3R3bzsNCj4gPiArDQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICBpZiAoYXBwX2tleSA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIG5ldF9rZXkgPSBm
aW5kX25ldF9rZXlfYnlfaWR4KGFwcF9rZXktPm5ldF9pZHgpOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKG5ldF9rZXkgPT0gTlVMTCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAobmV0X2lkeCkg
Km5ldF9pZHggPSBhcHBfa2V5LT5uZXRfaWR4Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
cGhhc2VfdHdvID0gISEobmV0X2tleS0+cGhhc2UgPT0gMik7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBpZiAocGhhc2VfdHdvICYmIGFwcF9rZXktPm5ldy5ha2ZfYWlkICE9IDB4ZmYpIHsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoYXBwX2VuY19rZXkpICphcHBfZW5jX2tl
eSA9IGFwcF9rZXktPm5ldy5rZXk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFr
Zl9haWQpICpha2ZfYWlkID0gYXBwX2tleS0+bmV3LmFrZl9haWQ7DQo+ID4gKyAgICAgICAgICAg
ICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFwcF9lbmNfa2V5
KSAqYXBwX2VuY19rZXkgPSBhcHBfa2V5LT5jdXJyZW50LmtleTsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBpZiAoYWtmX2FpZCkgKmFrZl9haWQgPSBhcHBfa2V5LT5jdXJyZW50LmFrZl9h
aWQ7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBuZXRfY3RsX21zZ19z
ZW5kKHVpbnQ4X3QgdHRsLCB1aW50MTZfdCBzcmMsIHVpbnQxNl90IGRzdCwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDhfdCAqYnVmLCB1aW50MTZfdCBs
ZW4pDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX25vZGUgKm5vZGUgPSBub2RlX2dl
dF9sb2NhbF9ub2RlKCk7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9zYXJfbXNnIHNhcl9jdGw7
DQo+ID4gKw0KPiA+ICsgICAgICAgLyogRm9yIHNpbXBsaWNpdHksIHdlIHdpbGwgcmVqZWN0IHNl
Z21lbnRlZCBPQiBDVEwgbWVzc2FnZXMgKi8NCj4gPiArICAgICAgIGlmIChsZW4gPiAxMiB8fCBu
b2RlID09IE5VTEwgfHwgYnVmID09IE5VTEwgfHwgYnVmWzBdICYgMHg4MCkNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghc3JjKSB7DQo+
ID4gKyAgICAgICAgICAgICAgIHNyYyA9IG5vZGVfZ2V0X3ByaW1hcnkobm9kZSk7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBpZiAoIXNyYykNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHR0
bCA9PSAweGZmKQ0KPiA+ICsgICAgICAgICAgICAgICB0dGwgPSBuZXQuZGVmYXVsdF90dGw7DQo+
ID4gKw0KPiA+ICsgICAgICAgbWVtc2V0KCZzYXJfY3RsLCAwLCBzaXplb2Yoc2FyX2N0bCkpOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmICghZHN0KQ0KPiA+ICsgICAgICAgICAgICAgICBzYXJfY3Rs
LnByb3h5ID0gdHJ1ZTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBHZXQgdGhlIGRlZmF1bHQgbmV0
X2lkeCBmb3IgcmVtb3RlIGRldmljZSAob3IgbG9jYWwpICovDQo+ID4gKyAgICAgICBnZXRfZW5j
X2tleXMoQVBQX0lEWF9ERVYsIGRzdCwgTlVMTCwgTlVMTCwgJnNhcl9jdGwubmV0X2lkeCk7DQo+
ID4gKyAgICAgICBzYXJfY3RsLmN0bCA9IHRydWU7DQo+ID4gKyAgICAgICBzYXJfY3RsLml2X2lu
ZGV4ID0gbmV0Lml2X2luZGV4IC0gbmV0Lml2X3VwZGF0ZTsNCj4gPiArICAgICAgIHNhcl9jdGwu
dHRsID0gdHRsOw0KPiA+ICsgICAgICAgc2FyX2N0bC5zcmMgPSBzcmM7DQo+ID4gKyAgICAgICBz
YXJfY3RsLmRzdCA9IGRzdDsNCj4gPiArICAgICAgIHNhcl9jdGwubGVuID0gbGVuOw0KPiA+ICsg
ICAgICAgbWVtY3B5KHNhcl9jdGwuZGF0YSwgYnVmLCBsZW4pOw0KPiA+ICsgICAgICAgc2VuZF9z
ZWcoJnNhcl9jdGwsIDApOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtib29sIG5ldF9hY2Nlc3NfbGF5ZXJfc2VuZCh1aW50OF90IHR0bCwgdWlu
dDE2X3Qgc3JjLCB1aW50MzJfdCBkc3QsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICB1aW50MTZfdCBhcHBfaWR4LCB1aW50OF90ICpidWYsIHVpbnQxNl90IGxlbikNCj4gPiAr
ew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbm9kZSAqbm9kZSA9IG5vZGVfZ2V0X2xvY2FsX25v
ZGUoKTsNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX3Nhcl9tc2cgKnNhcjsNCj4gPiArICAgICAg
IHVpbnQ4X3QgKmFwcF9lbmNfa2V5ID0gTlVMTDsNCj4gPiArICAgICAgIHVpbnQ4X3QgKmFhZCA9
IE5VTEw7DQo+ID4gKyAgICAgICB1aW50MzJfdCBtaWMzMjsNCj4gPiArICAgICAgIHVpbnQ4X3Qg
YWFkX2xlbiA9IDA7DQo+ID4gKyAgICAgICB1aW50OF90IGksIGosIGFja2xlc3NfcmV0cmllcyA9
IDA7DQo+ID4gKyAgICAgICB1aW50OF90IHNlZ04sIGFrZl9haWQ7DQo+ID4gKyAgICAgICB1aW50
MTZfdCBuZXRfaWR4Ow0KPiA+ICsgICAgICAgYm9vbCByZXN1bHQ7DQo+ID4gKw0KPiA+ICsgICAg
ICAgaWYgKGxlbiA+IDM4NCB8fCBub2RlID09IE5VTEwpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXNyYykNCj4gPiArICAgICAgICAg
ICAgICAgc3JjID0gbm9kZV9nZXRfcHJpbWFyeShub2RlKTsNCj4gPiArDQo+ID4gKyAgICAgICBp
ZiAoIXNyYyB8fCAhZHN0KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKHR0bCA9PSAweGZmKQ0KPiA+ICsgICAgICAgICAgICAgICB0dGwg
PSBuZXQuZGVmYXVsdF90dGw7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKElTX1ZJUlRVQUwoZHN0
KSkgew0KPiA+ICsgICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF92aXJ0X2FkZHIgKnZpcnQgPSBm
aW5kX3ZpcnRfYnlfZHN0KGRzdCk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAodmly
dCA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIGRzdCA9IHZpcnQtPnZhMTY7DQo+ID4gKyAgICAgICAg
ICAgICAgIGFhZCA9IHZpcnQtPnZhMTI4Ow0KPiA+ICsgICAgICAgICAgICAgICBhYWRfbGVuID0g
c2l6ZW9mKHZpcnQtPnZhMTI4KTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBy
ZXN1bHQgPSBnZXRfZW5jX2tleXMoYXBwX2lkeCwgZHN0LA0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICZha2ZfYWlkLCAmYXBwX2VuY19rZXksICZuZXRfaWR4KTsNCj4gPiArDQo+ID4gKyAg
ICAgICBpZiAoIXJlc3VsdCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+
ICsNCj4gPiArICAgICAgIHNlZ04gPSBTRUdfTUFYKGxlbik7DQo+ID4gKw0KPiA+ICsgICAgICAg
LyogT25seSBvbmUgQUNLIHJlcXVpcmVkIFNBUiBtZXNzYWdlIHBlciBkZXN0aW5hdGlvbiBhdCBh
IHRpbWUgKi8NCj4gPiArICAgICAgIGlmIChzZWdOICYmIElTX1VOSUNBU1QoZHN0KSkgew0KPiA+
ICsgICAgICAgICAgICAgICBzYXIgPSBmaW5kX3Nhcl9vdXRfYnlfZHN0KGRzdCk7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBpZiAoc2FyKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IGZsdXNoX3NhcigmbmV0Lm1zZ19vdXQsIHNhcik7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+
ICsgICAgICAgc2FyID0gZ19tYWxsb2MwKHNpemVvZihzdHJ1Y3QgbWVzaF9zYXJfbXNnKSArIChz
ZWdOICogMTIpKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc2FyID09IE5VTEwpDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc2VnTikN
Cj4gPiArICAgICAgICAgICAgICAgc2FyLT5zZWdtZW50ZWQgPSB0cnVlOw0KPiA+ICsNCj4gPiAr
ICAgICAgIHNhci0+dHRsID0gdHRsOw0KPiA+ICsgICAgICAgc2FyLT5zZWdOID0gc2VnTjsNCj4g
PiArICAgICAgIHNhci0+c2VxQXV0aCA9IG5ldC5zZXFfbnVtOw0KPiA+ICsgICAgICAgc2FyLT5p
dl9pbmRleCA9IG5ldC5pdl9pbmRleCAtIG5ldC5pdl91cGRhdGU7DQo+ID4gKyAgICAgICBzYXIt
Pm5ldF9pZHggPSBuZXRfaWR4Ow0KPiA+ICsgICAgICAgc2FyLT5zcmMgPSBzcmM7DQo+ID4gKyAg
ICAgICBzYXItPmRzdCA9IGRzdDsNCj4gPiArICAgICAgIHNhci0+YWtmX2FpZCA9IGFrZl9haWQ7
DQo+ID4gKyAgICAgICBzYXItPmxlbiA9IGxlbiArIHNpemVvZih1aW50MzJfdCk7DQo+ID4gKw0K
PiA+ICsgICAgICAgbWVzaF9jcnlwdG9fYXBwbGljYXRpb25fZW5jcnlwdChha2ZfYWlkLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgIHNhci0+c2VxQXV0aCwgc3JjLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIGRzdCwgc2FyLT5pdl9pbmRleCwNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBhcHBfZW5jX2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBhYWQsIGFh
ZF9sZW4sDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnVmLCBsZW4sDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgc2FyLT5kYXRhLCAmbWljMzIsDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgc2l6ZW9mKHVpbnQzMl90KSk7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogSWYgc2Vu
ZGluZyBhcyBhIHNlZ21lbnRlZCBtZXNzYWdlIHRvIGEgbm9uLVVuaWNhc3QgKHRodXMgbm9uLQ0K
PiBBQ0tpbmcpDQo+ID4gKyAgICAgICAgKiBkZXN0aW5hdGlvbiwgc2VuZCBlYWNoIHNlZ21lbnRz
IG11bHRpcGxlIHRpbWVzLiAqLw0KPiA+ICsgICAgICAgaWYgKCFJU19VTklDQVNUKGRzdCkgJiYg
c2VnTikNCj4gPiArICAgICAgICAgICAgICAgYWNrbGVzc19yZXRyaWVzID0gNDsNCj4gPiArDQo+
ID4gKyAgICAgICBmb3IgKGogPSAwOyBqIDw9IGFja2xlc3NfcmV0cmllczsgaisrKSB7DQo+ID4g
KyAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPD0gc2VnTjsgaSsrKQ0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIHNlbmRfc2VnKHNhciwgaSk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYgKElTX1VOSUNBU1QoZHN0KSAmJiBzZWdOKSB7DQo+ID4gKyAgICAgICAg
ICAgICAgIG5ldC5tc2dfb3V0ID0gZ19saXN0X2FwcGVuZChuZXQubXNnX291dCwgc2FyKTsNCj4g
PiArICAgICAgICAgICAgICAgc2FyLT5hY2tfdG8gPSBnX3RpbWVvdXRfYWRkKDIwMDAsIHNhcl9v
dXRfYWNrX3RpbWVvdXQsIHNhcik7DQo+ID4gKyAgICAgICAgICAgICAgIHNhci0+bXNnX3RvID0g
Z190aW1lb3V0X2FkZCg2MDAwMCwgc2FyX291dF9tc2dfdGltZW91dCwgc2FyKTsNCj4gPiArICAg
ICAgIH0gZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICBnX2ZyZWUoc2FyKTsNCj4gPiArDQo+ID4g
KyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBuZXRfc2V0X2Rl
ZmF1bHRfdHRsKHVpbnQ4X3QgdHRsKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAodHRsID4gMHg3
ZikNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAg
IG5ldC5kZWZhdWx0X3R0bCA9IHR0bDsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICt1aW50OF90IG5ldF9nZXRfZGVmYXVsdF90dGwoKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICByZXR1cm4gbmV0LmRlZmF1bHRfdHRsOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29s
IG5ldF9zZXRfc2VxX251bSh1aW50MzJfdCBzZXFfbnVtKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBp
ZiAoc2VxX251bSA+IDB4ZmZmZmZmKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7
DQo+ID4gKw0KPiA+ICsgICAgICAgbmV0LnNlcV9udW0gPSBzZXFfbnVtOw0KPiA+ICsgICAgICAg
cmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQzMl90IG5ldF9nZXRfc2VxX251
bSgpDQo+ID4gK3sNCj4gPiArICAgICAgIHJldHVybiBuZXQuc2VxX251bTsNCj4gPiArfQ0KPiA+
IGRpZmYgLS1naXQgYS9tZXNoL25vZGUuYyBiL21lc2gvbm9kZS5jDQo+ID4gbmV3IGZpbGUgbW9k
ZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi5iYThkNGI2DQo+ID4gLS0tIC9kZXYvbnVsbA0K
PiA+ICsrKyBiL21lc2gvbm9kZS5jDQo+ID4gQEAgLTAsMCArMSw4NzkgQEANCj4gPiArLyoNCj4g
PiArICoNCj4gPiArICogIEJsdWVaIC0gQmx1ZXRvb3RoIHByb3RvY29sIHN0YWNrIGZvciBMaW51
eA0KPiA+ICsgKg0KPiA+ICsgKiAgQ29weXJpZ2h0IChDKSAyMDE3ICBJbnRlbCBDb3Jwb3JhdGlv
bi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gPiArICoNCj4gPiArICoNCj4gPiArICogIFRoaXMg
bGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IN
Cj4gPiArICogIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2Vu
ZXJhbCBQdWJsaWMNCj4gPiArICogIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNv
ZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlcg0KPiA+ICsgKiAgdmVyc2lvbiAyLjEgb2YgdGhlIExp
Y2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uDQo+ID4gKyAqDQo+
ID4gKyAqICBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3
aWxsIGJlIHVzZWZ1bCwNCj4gPiArICogIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91
dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQo+ID4gKyAqICBNRVJDSEFOVEFCSUxJVFkg
b3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlDQo+IEdOVQ0KPiA+
ICsgKiAgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4NCj4g
PiArICoNCj4gPiArICogIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdO
VSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlz
IGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmUNCj4gPiArICogIEZv
dW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAg
MDIxMTAtMTMwMQ0KPiBVU0ENCj4gPiArICoNCj4gPiArICovDQo+ID4gKw0KPiA+ICsjaWZkZWYg
SEFWRV9DT05GSUdfSA0KPiA+ICsjaW5jbHVkZSA8Y29uZmlnLmg+DQo+ID4gKyNlbmRpZg0KPiA+
ICsNCj4gPiArI2luY2x1ZGUgPHN0ZGlvLmg+DQo+ID4gKyNpbmNsdWRlIDxlcnJuby5oPg0KPiA+
ICsjaW5jbHVkZSA8dW5pc3RkLmg+DQo+ID4gKyNpbmNsdWRlIDxzdGRsaWIuaD4NCj4gPiArI2lu
Y2x1ZGUgPHN0ZGJvb2wuaD4NCj4gPiArI2luY2x1ZGUgPHN5cy91aW8uaD4NCj4gPiArI2luY2x1
ZGUgPHdvcmRleHAuaD4NCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxyZWFkbGluZS9yZWFkbGluZS5o
Pg0KPiA+ICsjaW5jbHVkZSA8cmVhZGxpbmUvaGlzdG9yeS5oPg0KPiA+ICsjaW5jbHVkZSA8Z2xp
Yi5oPg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgImNsaWVudC9kaXNwbGF5LmgiDQo+ID4gKyNpbmNs
dWRlICJzcmMvc2hhcmVkL3V0aWwuaCINCj4gPiArI2luY2x1ZGUgImdkYnVzL2dkYnVzLmgiDQo+
ID4gKyNpbmNsdWRlICJtb25pdG9yL3V1aWQuaCINCj4gPiArI2luY2x1ZGUgIm1lc2gtbmV0Lmgi
DQo+ID4gKyNpbmNsdWRlICJjb25maWctbW9kZWwuaCINCj4gPiArI2luY2x1ZGUgIm5vZGUuaCIN
Cj4gPiArI2luY2x1ZGUgImtleXMuaCINCj4gPiArI2luY2x1ZGUgImdhdHQuaCINCj4gPiArI2lu
Y2x1ZGUgIm5ldC5oIg0KPiA+ICsjaW5jbHVkZSAicHJvdi1kYi5oIg0KPiA+ICsjaW5jbHVkZSAi
dXRpbC5oIg0KPiA+ICsNCj4gPiArc3RydWN0IG1lc2hfbW9kZWwgew0KPiA+ICsgICAgICAgc3Ry
dWN0IG1lc2hfbW9kZWxfb3BzIGNiczsNCj4gPiArICAgICAgIHZvaWQgKnVzZXJfZGF0YTsNCj4g
PiArICAgICAgIEdMaXN0ICpiaW5kaW5nczsNCj4gPiArICAgICAgIEdMaXN0ICpzdWJzY3JpcHRp
b25zOw0KPiA+ICsgICAgICAgdWludDMyX3QgaWQ7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9w
dWJsaWNhdGlvbiAqcHViOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IG1lc2hfZWxlbWVu
dCB7DQo+ID4gKyAgICAgICBHTGlzdCAqbW9kZWxzOw0KPiA+ICsgICAgICAgdWludDE2X3QgbG9j
Ow0KPiA+ICsgICAgICAgdWludDhfdCBpbmRleDsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0cnVj
dCBtZXNoX25vZGUgew0KPiA+ICsgICAgICAgY29uc3QgY2hhciAqbmFtZTsNCj4gPiArICAgICAg
IEdMaXN0ICpuZXRfa2V5czsNCj4gPiArICAgICAgIEdMaXN0ICphcHBfa2V5czsNCj4gPiArICAg
ICAgIHZvaWQgKnByb3Y7DQo+ID4gKyAgICAgICBHTGlzdCAqZWxlbWVudHM7DQo+ID4gKyAgICAg
ICB1aW50MzJfdCBpdl9pbmRleDsNCj4gPiArICAgICAgIHVpbnQzMl90IHNlcV9udW1iZXI7DQo+
ID4gKyAgICAgICB1aW50MTZfdCBwcmltYXJ5X25ldF9pZHg7DQo+ID4gKyAgICAgICB1aW50MTZf
dCBwcmltYXJ5Ow0KPiA+ICsgICAgICAgdWludDE2X3Qgb29iOw0KPiA+ICsgICAgICAgdWludDE2
X3QgZmVhdHVyZXM7DQo+ID4gKyAgICAgICB1aW50OF90IGdhdHRfcGt0W01BWF9HQVRUX1NJWkVd
Ow0KPiA+ICsgICAgICAgdWludDhfdCBkZXZfdXVpZFsxNl07DQo+ID4gKyAgICAgICB1aW50OF90
IGRldl9rZXlbMTZdOw0KPiA+ICsgICAgICAgdWludDhfdCBudW1fZWxlOw0KPiA+ICsgICAgICAg
dWludDhfdCB0dGw7DQo+ID4gKyAgICAgICB1aW50OF90IGdhdHRfc2l6ZTsNCj4gPiArICAgICAg
IGJvb2wgcHJvdmlzaW9uZXI7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlX2NvbXBvc2l0
aW9uICpjb21wOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RhdGljIEdMaXN0ICpub2RlczsNCj4g
PiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgbWVzaF9ub2RlICpsb2NhbF9ub2RlOw0KPiA+ICsNCj4g
PiArc3RhdGljIGludCBtYXRjaF9ub2RlX3VuaWNhc3QoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9p
ZCAqYikNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3Qgc3RydWN0IG1lc2hfbm9kZSAqbm9kZSA9
IGE7DQo+ID4gKyAgICAgICB1aW50MTZfdCBkc3QgPSBHUE9JTlRFUl9UT19VSU5UKGIpOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmIChkc3QgPj0gbm9kZS0+cHJpbWFyeSAmJg0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgZHN0IDw9IChub2RlLT5wcmltYXJ5ICsgbm9kZS0+bnVt
X2VsZSAtIDEpKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMDsNCj4gPiArDQo+ID4gKyAg
ICAgICByZXR1cm4gLTE7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgbWF0Y2hfZGV2
aWNlX3V1aWQoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9pZCAqYikNCj4gPiArew0KPiA+ICsgICAg
ICAgY29uc3Qgc3RydWN0IG1lc2hfbm9kZSAqbm9kZSA9IGE7DQo+ID4gKyAgICAgICBjb25zdCB1
aW50OF90ICp1dWlkID0gYjsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbWVtY21wKG5vZGUt
PmRldl91dWlkLCB1dWlkLCAxNik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgbWF0
Y2hfZWxlbWVudF9pZHgoY29uc3Qgdm9pZCAqYSwgY29uc3Qgdm9pZCAqYikNCj4gPiArew0KPiA+
ICsgICAgICAgY29uc3Qgc3RydWN0IG1lc2hfZWxlbWVudCAqZWxlbWVudCA9IGE7DQo+ID4gKyAg
ICAgICB1aW50MzJfdCBpbmRleCA9IEdQT0lOVEVSX1RPX1VJTlQoYik7DQo+ID4gKw0KPiA+ICsg
ICAgICAgcmV0dXJuIChlbGVtZW50LT5pbmRleCA9PSBpbmRleCkgPyAwIDogLTE7DQo+ID4gK30N
Cj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgbWF0Y2hfbW9kZWxfaWQoY29uc3Qgdm9pZCAqYSwgY29u
c3Qgdm9pZCAqYikNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3Qgc3RydWN0IG1lc2hfbW9kZWwg
Km1vZGVsID0gYTsNCj4gPiArICAgICAgIHVpbnQzMl90IGlkID0gR1BPSU5URVJfVE9fVUlOVChi
KTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gKG1vZGVsLT5pZCA9PSBpZCkgPyAwIDogLTE7
DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0cnVjdCBtZXNoX25vZGUgKm5vZGVfZmluZF9ieV9hZGRy
KHVpbnQxNl90IGFkZHIpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4g
PiArICAgICAgIGlmICghSVNfVU5JQ0FTVChhZGRyKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbShub2Rl
cywgR1VJTlRfVE9fUE9JTlRFUihhZGRyKSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBt
YXRjaF9ub2RlX3VuaWNhc3QpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChsKQ0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm4gbC0+ZGF0YTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0cnVjdCBtZXNoX25v
ZGUgKm5vZGVfZmluZF9ieV91dWlkKHVpbnQ4X3QgdXVpZFsxNl0pDQo+ID4gK3sNCj4gPiArICAg
ICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20o
bm9kZXMsIHV1aWQsIG1hdGNoX2RldmljZV91dWlkKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
bCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGwtPmRhdGE7DQo+ID4gKyAgICAgICBlbHNl
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtz
dHJ1Y3QgbWVzaF9ub2RlICpub2RlX2NyZWF0ZV9uZXcoc3RydWN0IHByb3Zfc3ZjX2RhdGEgKnBy
b3YpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX25vZGUgKm5vZGU7DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYgKG5vZGVfZmluZF9ieV91dWlkKHByb3YtPmRldl91dWlkKSkNCj4gPiAr
ICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgbm9kZSA9IGdf
bWFsbG9jMChzaXplb2Yoc3RydWN0IG1lc2hfbm9kZSkpOw0KPiA+ICsgICAgICAgaWYgKCFub2Rl
KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICBt
ZW1jcHkobm9kZS0+ZGV2X3V1aWQsIHByb3YtPmRldl91dWlkLCAxNik7DQo+ID4gKyAgICAgICBu
b2RlLT5vb2IgPSBwcm92LT5vb2I7DQo+ID4gKyAgICAgICBub2RlcyA9IGdfbGlzdF9hcHBlbmQo
bm9kZXMsIG5vZGUpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBub2RlOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtzdHJ1Y3QgbWVzaF9ub2RlICpub2RlX25ldyh2b2lkKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2RlOw0KPiA+ICsNCj4gPiArICAgICAgIG5vZGUg
PSBnX21hbGxvYzAoc2l6ZW9mKHN0cnVjdCBtZXNoX25vZGUpKTsNCj4gPiArICAgICAgIGlmICgh
bm9kZSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAg
ICAgbm9kZXMgPSBnX2xpc3RfYXBwZW5kKG5vZGVzLCBub2RlKTsNCj4gPiArDQo+ID4gKyAgICAg
ICByZXR1cm4gbm9kZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgbW9kZWxfZnJl
ZSh2b2lkICpkYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9tb2RlbCAqbW9k
ZWwgPSBkYXRhOw0KPiA+ICsNCj4gPiArICAgICAgIGdfbGlzdF9mcmVlKG1vZGVsLT5iaW5kaW5n
cyk7DQo+ID4gKyAgICAgICBnX2xpc3RfZnJlZShtb2RlbC0+c3Vic2NyaXB0aW9ucyk7DQo+ID4g
KyAgICAgICBnX2ZyZWUobW9kZWwtPnB1Yik7DQo+ID4gKyAgICAgICBnX2ZyZWUobW9kZWwpOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBlbGVtZW50X2ZyZWUodm9pZCAqZGF0YSkN
Cj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfZWxlbWVudCAqZWxlbWVudCA9IGRhdGE7
DQo+ID4gKw0KPiA+ICsgICAgICAgZ19saXN0X2ZyZWVfZnVsbChlbGVtZW50LT5tb2RlbHMsIG1v
ZGVsX2ZyZWUpOw0KPiA+ICsgICAgICAgZ19mcmVlKGVsZW1lbnQpOw0KPiA+ICt9DQo+ID4gKw0K
PiA+ICtzdGF0aWMgdm9pZCBmcmVlX25vZGVfcmVzb3VyY2VzKHZvaWQgKmRhdGEpDQo+ID4gK3sN
Cj4gPiArICAgICAgIHN0cnVjdCBtZXNoX25vZGUgKm5vZGUgPSBkYXRhOw0KPiA+ICsgICAgICAg
Z19saXN0X2ZyZWUobm9kZS0+bmV0X2tleXMpOw0KPiA+ICsgICAgICAgZ19saXN0X2ZyZWUobm9k
ZS0+YXBwX2tleXMpOw0KPiA+ICsNCj4gPiArICAgICAgIGdfbGlzdF9mcmVlX2Z1bGwobm9kZS0+
ZWxlbWVudHMsIGVsZW1lbnRfZnJlZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYobm9kZS0+Y29t
cCkNCj4gPiArICAgICAgICAgICAgICAgZ19mcmVlKG5vZGUtPmNvbXApOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGdfZnJlZShub2RlKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBub2RlX2ZyZWUo
c3RydWN0IG1lc2hfbm9kZSAqbm9kZSkNCj4gPiArew0KPiA+ICsgICAgICAgaWYgKCFub2RlKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICBub2RlcyA9IGdfbGlzdF9y
ZW1vdmUobm9kZXMsIG5vZGUpOw0KPiA+ICsgICAgICAgZnJlZV9ub2RlX3Jlc291cmNlcyhub2Rl
KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBub2RlX2NsZWFudXAodm9pZCkNCj4gPiArew0K
PiA+ICsgICAgICAgZ19saXN0X2ZyZWVfZnVsbChub2RlcywgZnJlZV9ub2RlX3Jlc291cmNlcyk7
DQo+ID4gKyAgICAgICBsb2NhbF9ub2RlID0gTlVMTDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9v
bCBub2RlX2lzX3Byb3Zpc2lvbmVkKHN0cnVjdCBtZXNoX25vZGUgKm5vZGUpDQo+ID4gK3sNCj4g
PiArICAgICAgIHJldHVybiAoIUlTX1VOQVNTSUdORUQobm9kZS0+cHJpbWFyeSkpOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICt2b2lkICpub2RlX2dldF9wcm92KHN0cnVjdCBtZXNoX25vZGUgKm5vZGUp
DQo+ID4gK3sNCj4gPiArICAgICAgIHJldHVybiBub2RlLT5wcm92Ow0KPiA+ICt9DQo+ID4gKw0K
PiA+ICt2b2lkIG5vZGVfc2V0X3Byb3Yoc3RydWN0IG1lc2hfbm9kZSAqbm9kZSwgdm9pZCAqcHJv
dikNCj4gPiArew0KPiA+ICsgICAgICAgbm9kZS0+cHJvdiA9IHByb3Y7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK2Jvb2wgbm9kZV9hcHBfa2V5X2FkZChzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCB1aW50
MTZfdCBpZHgpDQo+ID4gK3sNCj4gPiArICAgICAgIHVpbnQzMl90IGluZGV4Ow0KPiA+ICsgICAg
ICAgdWludDE2X3QgbmV0X2lkeDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIW5vZGUpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBuZXRfaWR4
ID0ga2V5c19hcHBfa2V5X2dldF9ib3VuZChpZHgpOw0KPiA+ICsgICAgICAgaWYgKG5ldF9pZHgg
PT0gTkVUX0lEWF9JTlZBTElEKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKCFnX2xpc3RfZmluZChub2RlLT5uZXRfa2V5cywgR1VJTlRf
VE9fUE9JTlRFUihuZXRfaWR4KSkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsN
Cj4gPiArDQo+ID4gKyAgICAgICBpbmRleCA9IChuZXRfaWR4IDw8IDE2KSArIGlkeDsNCj4gPiAr
DQo+ID4gKyAgICAgICBpZiAoZ19saXN0X2ZpbmQobm9kZS0+YXBwX2tleXMsIEdVSU5UX1RPX1BP
SU5URVIoaW5kZXgpKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsN
Cj4gPiArICAgICAgIG5vZGUtPmFwcF9rZXlzID0gZ19saXN0X2FwcGVuZChub2RlLT5hcHBfa2V5
cywNCj4gR1VJTlRfVE9fUE9JTlRFUihpbmRleCkpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVy
biB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG5vZGVfbmV0X2tleV9hZGQoc3RydWN0
IG1lc2hfbm9kZSAqbm9kZSwgdWludDE2X3QgaW5kZXgpDQo+ID4gK3sNCj4gPiArICAgICAgIGlm
KCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKGdfbGlzdF9maW5kKG5vZGUtPm5ldF9rZXlzLCBHVUlOVF9UT19QT0lOVEVSKGlu
ZGV4KSkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAg
ICAgICBub2RlLT5uZXRfa2V5cyA9IGdfbGlzdF9hcHBlbmQobm9kZS0+bmV0X2tleXMsDQo+IEdV
SU5UX1RPX1BPSU5URVIoaW5kZXgpKTsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtib29sIG5vZGVfbmV0X2tleV9kZWxldGUoc3RydWN0IG1lc2hfbm9kZSAq
bm9kZSwgdWludDE2X3QgaW5kZXgpDQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmKCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFs
c2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kKG5vZGUtPm5ldF9rZXlzLCBH
VUlOVF9UT19QT0lOVEVSKGluZGV4KSk7DQo+ID4gKyAgICAgICBpZiAoIWwpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBub2RlLT5uZXRfa2V5
cyA9IGdfbGlzdF9yZW1vdmUobm9kZS0+bmV0X2tleXMsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1VJTlRfVE9fUE9JTlRFUihpbmRleCkpOw0K
PiA+ICsgICAgICAgLyogVE9ETzogcmVtb3ZlIGFsbCBhc3NvY2lhdGVkIGFwcCBrZXlzIGFuZCBi
aW5kaW5ncyAqLw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4g
K2Jvb2wgbm9kZV9hcHBfa2V5X2RlbGV0ZShzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCB1aW50MTZf
dCBuZXRfaWR4LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDE2X3Qg
aWR4KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBHTGlzdCAqbDsNCj4gPiArICAgICAgIHVpbnQzMl90
IGluZGV4Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmKCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgaW5kZXggPSAobmV0X2lkeCA8PCAx
NikgKyBpZHg7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlzdF9maW5kKG5vZGUtPmFwcF9r
ZXlzLCBHVUlOVF9UT19QT0lOVEVSKGluZGV4KSk7DQo+ID4gKyAgICAgICBpZiAoIWwpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBub2RlLT5h
cHBfa2V5cyA9IGdfbGlzdF9yZW1vdmUobm9kZS0+YXBwX2tleXMsDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdVSU5UX1RPX1BPSU5URVIoaW5kZXgpKTsNCj4g
PiArICAgICAgIC8qIFRPRE86IHJlbW92ZSBhbGwgYXNzb2NpYXRlZCBiaW5kaW5ncyAqLw0KPiA+
ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgbm9kZV9zZXRf
cHJpbWFyeShzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCB1aW50MTZfdCB1bmljYXN0KQ0KPiA+ICt7
DQo+ID4gKyAgICAgICBub2RlLT5wcmltYXJ5ID0gdW5pY2FzdDsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArdWludDE2X3Qgbm9kZV9nZXRfcHJpbWFyeShzdHJ1Y3QgbWVzaF9ub2RlICpub2RlKQ0KPiA+
ICt7DQo+ID4gKyAgICAgICBpZiAoIW5vZGUpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBV
TkFTU0lHTkVEX0FERFJFU1M7DQo+ID4gKyAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAg
IHJldHVybiBub2RlLT5wcmltYXJ5Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICt2b2lkIG5vZGVfc2V0
X2RldmljZV9rZXkoc3RydWN0IG1lc2hfbm9kZSAqbm9kZSwgdWludDhfdCAqa2V5KQ0KPiA+ICsN
Cj4gPiArew0KPiA+ICsgICAgICAgaWYgKCFub2RlIHx8ICFrZXkpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBtZW1jcHkobm9kZS0+ZGV2X2tleSwga2V5
LCAxNik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQ4X3QgKm5vZGVfZ2V0X2RldmljZV9rZXko
c3RydWN0IG1lc2hfbm9kZSAqbm9kZSkNCj4gPiArew0KPiA+ICsgICAgICAgaWYgKCFub2RlKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArICAgICAgIGVsc2UNCj4gPiAr
ICAgICAgICAgICAgICAgcmV0dXJuIG5vZGUtPmRldl9rZXk7DQo+ID4gK30NCj4gPiArDQo+ID4g
K3ZvaWQgbm9kZV9zZXRfbnVtX2VsZW1lbnRzKHN0cnVjdCBtZXNoX25vZGUgKm5vZGUsIHVpbnQ4
X3QNCj4gbnVtX2VsZSkNCj4gPiArew0KPiA+ICsgICAgICAgbm9kZS0+bnVtX2VsZSA9IG51bV9l
bGU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQ4X3Qgbm9kZV9nZXRfbnVtX2VsZW1lbnRzKHN0
cnVjdCBtZXNoX25vZGUgKm5vZGUpDQo+ID4gK3sNCj4gPiArICAgICAgIHJldHVybiBub2RlLT5u
dW1fZWxlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtHTGlzdCAqbm9kZV9nZXRfbmV0X2tleXMoc3Ry
dWN0IG1lc2hfbm9kZSAqbm9kZSkNCj4gPiArew0KPiA+ICsgICAgICAgaWYgKCFub2RlKQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIG5vZGUtPm5ldF9rZXlzOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtH
TGlzdCAqbm9kZV9nZXRfYXBwX2tleXMoc3RydWN0IG1lc2hfbm9kZSAqbm9kZSkNCj4gPiArew0K
PiA+ICsgICAgICAgaWYgKCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gTlVMTDsN
Cj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIG5vZGUtPmFwcF9r
ZXlzOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG5vZGVfcGFyc2VfY29tcG9zaXRpb24oc3Ry
dWN0IG1lc2hfbm9kZSAqbm9kZSwgdWludDhfdCAqZGF0YSwNCj4gdWludDE2X3QgbGVuKQ0KPiA+
ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlX2NvbXBvc2l0aW9uICpjb21wOw0KPiA+
ICsgICAgICAgdWludDE2X3QgZmVhdHVyZXM7DQo+ID4gKyAgICAgICBpbnQgaTsNCj4gPiArDQo+
ID4gKyAgICAgICBjb21wID0gZ19tYWxsb2MwKHNpemVvZihzdHJ1Y3QgbWVzaF9ub2RlX2NvbXBv
c2l0aW9uKSk7DQo+ID4gKyAgICAgICBpZiAoIWNvbXApDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBza2lwIHBhZ2UgLS0gV2Ugb25seSBz
dXBwb3J0IFBhZ2UgWmVybyAqLw0KPiA+ICsgICAgICAgZGF0YSsrOw0KPiA+ICsgICAgICAgbGVu
LS07DQo+ID4gKw0KPiA+ICsgICAgICAgY29tcC0+Y2lkID0gZ2V0X2xlMTYoJmRhdGFbMF0pOw0K
PiA+ICsgICAgICAgY29tcC0+cGlkID0gZ2V0X2xlMTYoJmRhdGFbMl0pOw0KPiA+ICsgICAgICAg
Y29tcC0+dmlkID0gZ2V0X2xlMTYoJmRhdGFbNF0pOw0KPiA+ICsgICAgICAgY29tcC0+Y3JwbCA9
IGdldF9sZTE2KCZkYXRhWzZdKTsNCj4gPiArICAgICAgIGZlYXR1cmVzID0gZ2V0X2xlMTYoJmRh
dGFbOF0pOw0KPiA+ICsgICAgICAgZGF0YSArPSAxMDsNCj4gPiArICAgICAgIGxlbiAtPSAxMDsN
Cj4gPiArDQo+ID4gKyAgICAgICBjb21wLT5yZWxheSA9ICEhKGZlYXR1cmVzICYgTUVTSF9GRUFU
VVJFX1JFTEFZKTsNCj4gPiArICAgICAgIGNvbXAtPnByb3h5ID0gISEoZmVhdHVyZXMgJiBNRVNI
X0ZFQVRVUkVfUFJPWFkpOw0KPiA+ICsgICAgICAgY29tcC0+ZnJpZW5kID0gISEoZmVhdHVyZXMg
JiBNRVNIX0ZFQVRVUkVfRlJJRU5EKTsNCj4gPiArICAgICAgIGNvbXAtPmxwbiA9ICAhIShmZWF0
dXJlcyAmIE1FU0hfRkVBVFVSRV9MUE4pOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7
ICBpPCBub2RlLT5udW1fZWxlOyBpKyspIHsNCj4gPiArICAgICAgICAgICAgICAgdWludDhfdCBt
LCB2Ow0KPiA+ICsgICAgICAgICAgICAgICB1aW50MzJfdCBtb2RfaWQ7DQo+ID4gKyAgICAgICAg
ICAgICAgIHVpbnQxNl90IHZlbmRvcl9pZDsNCj4gPiArICAgICAgICAgICAgICAgc3RydWN0IG1l
c2hfZWxlbWVudCAqZWxlOw0KPiA+ICsgICAgICAgICAgICAgICBlbGUgPSBnX21hbGxvYzAoc2l6
ZW9mKHN0cnVjdCBtZXNoX2VsZW1lbnQpKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFlbGUp
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgZWxlLT5pbmRleCA9IGk7DQo+ID4gKyAgICAgICAgICAgICAgIGVsZS0+
bG9jID0gZ2V0X2xlMTYoZGF0YSk7DQo+ID4gKyAgICAgICAgICAgICAgIGRhdGEgKz0gMjsNCj4g
PiArICAgICAgICAgICAgICAgbm9kZS0+ZWxlbWVudHMgPSBnX2xpc3RfYXBwZW5kKG5vZGUtPmVs
ZW1lbnRzLCBlbGUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgbSA9ICpkYXRhKys7DQo+
ID4gKyAgICAgICAgICAgICAgIHYgPSAqZGF0YSsrOw0KPiA+ICsgICAgICAgICAgICAgICBsZW4g
LT0gNDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHdoaWxlIChsZW4gPj0gMiAmJiBtLS0p
IHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtb2RfaWQgPSBnZXRfbGUxNihkYXRhKTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAvKiBpbml0aWFsaXplIHVwcHBlciAxNiBiaXRz
IHRvIDB4ZmZmZiBmb3IgU0lHIG1vZGVscyAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IG1vZF9pZCB8PSAweGZmZmYwMDAwOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmICgh
bm9kZV9zZXRfbW9kZWwobm9kZSwgZWxlLT5pbmRleCwgbW9kX2lkKSkNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBkYXRhICs9IDI7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbGVuIC09IDI7
DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgICAgICAgICAgd2hpbGUgKGxlbiA+
PSA0ICYmIHYtLSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1vZF9pZCA9IGdldF9s
ZTE2KGRhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHZlbmRvcl9pZCA9IGdldF9s
ZTE2KGRhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1vZF9pZCB8PSAodmVuZG9y
X2lkIDw8IDE2KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW5vZGVfc2V0X21v
ZGVsKG5vZGUsIGVsZS0+aW5kZXgsIG1vZF9pZCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZGF0
YSArPSA0Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGxlbiAtPSA0Ow0KPiA+ICsgICAg
ICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIG5v
ZGUtPmNvbXAgPSBjb21wOw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK2Jvb2wgbm9kZV9zZXRfbG9jYWxfbm9kZShzdHJ1Y3QgbWVzaF9ub2RlICpub2RlKQ0K
PiA+ICt7DQo+ID4gKyAgICAgICBpZiAobG9jYWxfbm9kZSkgew0KPiA+ICsgICAgICAgICAgICAg
ICBybF9wcmludGYoIkxvY2FsIG5vZGUgYWxyZWFkeSByZWdpc3RlcmVkXG4iKTsNCj4gPiArICAg
ICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsgICAgICAgbmV0
X3JlZ2lzdGVyX3VuaWNhc3Qobm9kZS0+cHJpbWFyeSwgbm9kZS0+bnVtX2VsZSk7DQo+ID4gKw0K
PiA+ICsgICAgICAgbG9jYWxfbm9kZSA9IG5vZGU7DQo+ID4gKyAgICAgICBsb2NhbF9ub2RlLT5w
cm92aXNpb25lciA9IHRydWU7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0cnVjdCBtZXNoX25vZGUgKm5vZGVfZ2V0X2xvY2FsX25vZGUoKQ0K
PiA+ICt7DQo+ID4gKyAgICAgICByZXR1cm4gbG9jYWxfbm9kZTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArdWludDE2X3Qgbm9kZV9nZXRfcHJpbWFyeV9uZXRfaWR4KHN0cnVjdCBtZXNoX25vZGUgKm5v
ZGUpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmIChub2RlID09IE5VTEwpDQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiBORVRfSURYX0lOVkFMSUQ7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJu
IG5vZGUtPnByaW1hcnlfbmV0X2lkeDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wg
ZGVsaXZlcl9tb2RlbF9kYXRhKHN0cnVjdCBtZXNoX2VsZW1lbnQqIGVsZW1lbnQsIHVpbnQxNl90
DQo+IHNyYywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQxNl90IGFw
cF9pZHgsIHVpbnQ4X3QgKmRhdGEsIHVpbnQxNl90IGxlbikNCj4gPiArew0KPiA+ICsgICAgICAg
R0xpc3QgKmw7DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yKGwgPSBlbGVtZW50LT5tb2RlbHM7IGw7
IGwgPSBsLT5uZXh0KSB7DQo+ID4gKyAgICAgICAgICAgICAgIHN0cnVjdCBtZXNoX21vZGVsICpt
b2RlbCA9IGwtPmRhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIWdfbGlzdF9m
aW5kKG1vZGVsLT5iaW5kaW5ncywgR1VJTlRfVE9fUE9JTlRFUihhcHBfaWR4KSkpDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgY29udGludWU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAg
ICBpZiAobW9kZWwtPmNicy5yZWN2ICYmDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbW9k
ZWwtPmNicy5yZWN2KHNyYywgZGF0YSwgbGVuLCBtb2RlbC0+dXNlcl9kYXRhKSkNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+
ID4gKyAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgbm9kZV9s
b2NhbF9kYXRhX2hhbmRsZXIodWludDE2X3Qgc3JjLCB1aW50MzJfdCBkc3QsDQo+ID4gKyAgICAg
ICAgICAgICAgIHVpbnQzMl90IGl2X2luZGV4LCB1aW50MzJfdCBzZXFfbnVtLA0KPiA+ICsgICAg
ICAgICAgICAgICB1aW50MTZfdCBhcHBfaWR4LCB1aW50OF90ICpkYXRhLCB1aW50MTZfdCBsZW4p
DQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsgICAgICAgYm9vbCByZXM7DQo+
ID4gKyAgICAgICB1aW50NjRfdCBpdl9zZXE7DQo+ID4gKyAgICAgICB1aW50NjRfdCBpdl9zZXFf
cmVtb3RlOw0KPiA+ICsgICAgICAgdWludDhfdCBlbGVfaWR4Ow0KPiA+ICsgICAgICAgc3RydWN0
IG1lc2hfZWxlbWVudCAqZWxlbWVudDsNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX25vZGUgKnJl
bW90ZTsNCj4gPiArICAgICAgIGJvb2wgbG9vcGJhY2s7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYg
KCFsb2NhbF9ub2RlIHx8IHNlcV9udW0gPiAweGZmZmZmZikNCj4gPiArICAgICAgICAgICAgICAg
cmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIGl2X3NlcSA9IGl2X2luZGV4IDw8IDI0Ow0KPiA+
ICsgICAgICAgaXZfc2VxIHw9IHNlcV9udW07DQo+ID4gKw0KPiA+ICsgICAgICAgcmVtb3RlID0g
bm9kZV9maW5kX2J5X2FkZHIoc3JjKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXJlbW90ZSkg
ew0KPiA+ICsgICAgICAgICAgICAgICBpZiAobG9jYWxfbm9kZS0+cHJvdmlzaW9uZXIpIHsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIlJlbW90ZSBub2RlIHVua25vd24g
KCU0LjR4KVxuIiwgc3JjKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47DQo+
ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHJlbW90ZSA9
IGdfbmV3MChzdHJ1Y3QgbWVzaF9ub2RlLCAxKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFy
ZW1vdGUpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgLyogTm90IFByb3Zpc2lvbmVyOyBBc3N1bWUgYWxsIFNSQyBlbGVtZW50
cyBzdGFuZCBhbG9uZSAqLw0KPiA+ICsgICAgICAgICAgICAgICByZW1vdGUtPnByaW1hcnkgPSBz
cmM7DQo+ID4gKyAgICAgICAgICAgICAgIHJlbW90ZS0+bnVtX2VsZSA9IDE7DQo+ID4gKyAgICAg
ICAgICAgICAgIG5vZGVzID0gZ19saXN0X2FwcGVuZChub2RlcywgcmVtb3RlKTsNCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBsb29wYmFjayA9IChzcmMgPCAobG9jYWxfbm9kZS0+
cHJpbWFyeSArIGxvY2FsX25vZGUtPm51bV9lbGUpICYmDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3JjID49IGxvY2FsX25vZGUtPnByaW1hcnkp
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbG9vcGJhY2spIHsNCj4gPiArICAgICAgICAgICAg
ICAgaXZfc2VxX3JlbW90ZSA9IHJlbW90ZS0+aXZfaW5kZXggPDwgMjQ7DQo+ID4gKyAgICAgICAg
ICAgICAgIGl2X3NlcSB8PSByZW1vdGUtPnNlcV9udW1iZXI7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBpZiAoaXZfc2VxX3JlbW90ZSA+PSBpdl9zZXEpIHsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBybF9wcmludGYoIlJlcGxheWVkIG1lc3NhZ2UgZGV0ZWN0ZWQgIg0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIigl
MTRseCA+PSAlMTRseClcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICBpdl9zZXFfcmVtb3RlLCBpdl9zZXEpOw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsg
ICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGlmIChJU19HUk9VUChkc3QpIHx8IElTX1ZJUlRV
QUwoZHN0KSkgew0KPiA+ICsgICAgICAgICAgICAgICAvKiBUT0RPOiBpZiBzdWJzY3JpcHRpb24g
YWRkcmVzcywgZGVsaXZlciB0byBzdWJzY3JpYmVycyAqLw0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKElTX0FMTF9OT0RF
Uyhkc3QpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGVsZV9pZHggPSAwOw0KPiA+ICsgICAgICAg
fSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGRzdCA+PSAobG9jYWxfbm9kZS0+cHJp
bWFyeSArIGxvY2FsX25vZGUtPm51bV9lbGUpIHx8DQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgZHN0IDwgbG9jYWxfbm9kZS0+cHJpbWFyeSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGVsZV9pZHggPSBk
c3QgLSBsb2NhbF9ub2RlLT5wcmltYXJ5Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAg
ICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20obG9jYWxfbm9kZS0+ZWxlbWVudHMsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHVUlOVF9UT19QT0lOVEVSKGVsZV9pZHgpLCBt
YXRjaF9lbGVtZW50X2lkeCk7DQo+ID4gKw0KPiA+ICsgICAgICAgLyogVGhpcyBzaG91bGQgbm90
IGhhcHBlbiAqLw0KPiA+ICsgICAgICAgaWYgKCFsKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1
cm47DQo+ID4gKw0KPiA+ICsgICAgICAgZWxlbWVudCA9IGwtPmRhdGE7DQo+ID4gKyAgICAgICBy
ZXMgPSBkZWxpdmVyX21vZGVsX2RhdGEoZWxlbWVudCwgc3JjLCBhcHBfaWR4LCBkYXRhLCBsZW4p
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmIChyZXMgJiYgIWxvb3BiYWNrKSB7DQo+ID4gKyAgICAg
ICAgICAgICAgIC8qIFRPRE86IFNhdmUgcmVtb3RlIGluIFJlcGxheSBQcm90ZWN0aW9uIGRiICov
DQo+ID4gKyAgICAgICAgICAgICAgIHJlbW90ZS0+aXZfaW5kZXggPSBpdl9pbmRleDsNCj4gPiAr
ICAgICAgICAgICAgICAgcmVtb3RlLT5zZXFfbnVtYmVyID0gc2VxX251bTsNCj4gPiArICAgICAg
ICAgICAgICAgcHJvdl9kYl9ub2RlX3NldF9pdl9zZXEocmVtb3RlLCBpdl9pbmRleCwgc2VxX251
bSk7DQo+ID4gKyAgICAgICB9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBnYm9vbGVhbiBy
ZXN0b3JlX21vZGVsX3N0YXRlKGdwb2ludGVyIGRhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0
cnVjdCBtZXNoX21vZGVsICptb2RlbCA9IGRhdGE7DQo+ID4gKyAgICAgICBHTGlzdCAqbDsNCj4g
PiArICAgICAgIHN0cnVjdCBtZXNoX21vZGVsX29wcyAqb3BzOw0KPiA+ICsNCj4gPiArICAgICAg
IG9wcyA9ICZtb2RlbC0+Y2JzOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChtb2RlbC0+YmluZGlu
Z3MgJiYgb3BzLT5iaW5kKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGZvciAobCA9IG1vZGVsLT5i
aW5kaW5nczsgbDsgbCA9IGwtPm5leHQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBp
ZiAob3BzLT5iaW5kKEdQT0lOVEVSX1RPX1VJTlQobC0+ZGF0YSksIEFDVElPTl9BREQpICE9DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNRVNIX1NUQVRVU19TVUNDRVNTKQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICAg
ICAgICAgIH0NCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBpZiAobW9kZWwtPnB1
YiAmJiBvcHMtPnB1YikNCj4gPiArICAgICAgICAgICAgICAgb3BzLT5wdWIobW9kZWwtPnB1Yik7
DQo+ID4gKw0KPiA+ICsgICAgICAgZ19pZGxlX3JlbW92ZV9ieV9kYXRhKGRhdGEpOw0KPiA+ICsN
Cj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9v
bCBub2RlX2xvY2FsX21vZGVsX3JlZ2lzdGVyKHVpbnQ4X3QgZWxlX2lkeCwgdWludDE2X3QgbW9k
ZWxfaWQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF9t
b2RlbF9vcHMgKm9wcywgdm9pZCAqdXNlcl9kYXRhKQ0KPiA+ICt7DQo+ID4gKyAgICAgICB1aW50
MzJfdCBpZCA9IDB4ZmZmZjAwMDAgfCBtb2RlbF9pZDsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1
cm4gbm9kZV9sb2NhbF92ZW5kb3JfbW9kZWxfcmVnaXN0ZXIoZWxlX2lkeCwgaWQsIG9wcywNCj4g
dXNlcl9kYXRhKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBub2RlX2xvY2FsX3ZlbmRvcl9t
b2RlbF9yZWdpc3Rlcih1aW50OF90IGVsZV9pZHgsIHVpbnQzMl90DQo+IG1vZGVsX2lkLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RydWN0IG1lc2hfbW9kZWxfb3BzICpv
cHMsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfZWxl
bWVudCAqZWxlOw0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfbW9kZWwgKm1vZGVsOw0KPiA+ICsg
ICAgICAgR0xpc3QgKmw7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFsb2NhbF9ub2RlKQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdf
bGlzdF9maW5kX2N1c3RvbShsb2NhbF9ub2RlLT5lbGVtZW50cywNCj4gR1VJTlRfVE9fUE9JTlRF
UihlbGVfaWR4KSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoX2Vs
ZW1lbnRfaWR4KTsNCj4gPiArICAgICAgIGlmICghbCkNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGVsZSA9IGwtPmRhdGE7DQo+ID4gKw0KPiA+
ICsgICAgICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbShlbGUtPm1vZGVscywgR1VJTlRfVE9fUE9J
TlRFUihtb2RlbF9pZCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRj
aF9tb2RlbF9pZCk7DQo+ID4gKyAgICAgICBpZiAoIWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBtb2RlbCA9IGwtPmRhdGE7DQo+ID4gKyAg
ICAgICBtb2RlbC0+Y2JzID0gKm9wczsNCj4gPiArICAgICAgIG1vZGVsLT51c2VyX2RhdGEgPSB1
c2VyX2RhdGE7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKG1vZGVsX2lkID49IDB4ZmZmZjAwMDAp
DQo+ID4gKyAgICAgICAgICAgICAgIG1vZGVsX2lkID0gbW9kZWxfaWQgJiAweGZmZmY7DQo+ID4g
Kw0KPiA+ICsgICAgICAgLyogU2lsZW50bHkgYXNzaWduIGRldmljZSBrZXkgYmluZGluZyB0byBj
b25maWd1cmF0aW9uIG1vZGVscyAqLw0KPiA+ICsgICAgICAgaWYgKG1vZGVsX2lkID09IENPTkZJ
R19TRVJWRVJfTU9ERUxfSUQgfHwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgbW9kZWxfaWQgPT0gQ09ORklHX0NMSUVOVF9NT0RFTF9JRCkgew0KPiA+ICsgICAg
ICAgICAgICAgICBtb2RlbC0+YmluZGluZ3MgPSBnX2xpc3RfYXBwZW5kKG1vZGVsLT5iaW5kaW5n
cywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBH
VUlOVF9UT19QT0lOVEVSKEFQUF9JRFhfREVWKSk7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+
ICsgICAgICAgICAgICAgICBnX2lkbGVfYWRkKHJlc3RvcmVfbW9kZWxfc3RhdGUsIG1vZGVsKTsN
Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0K
PiA+ICsNCj4gPiArYm9vbCBub2RlX3NldF9lbGVtZW50KHN0cnVjdCBtZXNoX25vZGUgKm5vZGUs
IHVpbnQ4X3QgZWxlX2lkeCkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfZWxlbWVu
dCAqZWxlOw0KPiA+ICsgICAgICAgR0xpc3QgKmw7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFu
b2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAg
ICAgbCA9IGdfbGlzdF9maW5kX2N1c3RvbShub2RlLT5lbGVtZW50cywNCj4gR1VJTlRfVE9fUE9J
TlRFUihlbGVfaWR4KSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNo
X2VsZW1lbnRfaWR4KTsNCj4gPiArICAgICAgIGlmIChsKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgZWxlID0gZ19tYWxsb2MwKHNpemVvZihz
dHJ1Y3QgbWVzaF9lbGVtZW50KSk7DQo+ID4gKyAgICAgICBpZiAoIWVsZSkNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGVsZS0+aW5kZXggPSBl
bGVfaWR4Ow0KPiA+ICsgICAgICAgbm9kZS0+ZWxlbWVudHMgPSBnX2xpc3RfYXBwZW5kKG5vZGUt
PmVsZW1lbnRzLCBlbGUpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtib29sIG5vZGVfc2V0X21vZGVsKHN0cnVjdCBtZXNoX25vZGUgKm5vZGUs
IHVpbnQ4X3QgZWxlX2lkeCwNCj4gdWludDMyX3QgaWQpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0
cnVjdCBtZXNoX2VsZW1lbnQgKmVsZTsNCj4gPiArICAgICAgIHN0cnVjdCBtZXNoX21vZGVsICpt
b2RlbDsNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbm9k
ZSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAg
IGwgPSBnX2xpc3RfZmluZF9jdXN0b20obm9kZS0+ZWxlbWVudHMsDQo+IEdVSU5UX1RPX1BPSU5U
RVIoZWxlX2lkeCksDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRjaF9l
bGVtZW50X2lkeCk7DQo+ID4gKyAgICAgICBpZiAoIWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBlbGUgPSBsLT5kYXRhOw0KPiA+ICsNCj4g
PiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20oZWxlLT5tb2RlbHMsIEdVSU5UX1RPX1BP
SU5URVIoaWQpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hfbW9k
ZWxfaWQpOw0KPiA+ICsgICAgICAgaWYgKGwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBm
YWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBtb2RlbCA9IGdfbWFsbG9jMChzaXplb2Yoc3RydWN0
IG1lc2hfbW9kZWwpKTsNCj4gPiArICAgICAgIGlmICghbW9kZWwpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBtb2RlbC0+aWQgPSBpZDsNCj4g
PiArICAgICAgIGVsZS0+bW9kZWxzID0gZ19saXN0X2FwcGVuZChlbGUtPm1vZGVscywgbW9kZWwp
Ow0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICti
b29sIG5vZGVfc2V0X2NvbXBvc2l0aW9uKHN0cnVjdCBtZXNoX25vZGUgKm5vZGUsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlX2NvbXBvc2l0aW9u
ICpjb21wKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoIW5vZGUgfHwgIWNvbXAgfHwgbm9kZS0+
Y29tcCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAg
ICAgIG5vZGUtPmNvbXAgPSBnX21hbGxvYzAoc2l6ZW9mKHN0cnVjdCBtZXNoX25vZGVfY29tcG9z
aXRpb24pKTsNCj4gPiArICAgICAgIGlmICghbm9kZS0+Y29tcCkNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICoobm9kZS0+Y29tcCkgPSAqY29t
cDsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdHJ1Y3Qg
bWVzaF9ub2RlX2NvbXBvc2l0aW9uICpub2RlX2dldF9jb21wb3NpdGlvbihzdHJ1Y3QNCj4gbWVz
aF9ub2RlICpub2RlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoIW5vZGUpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBub2RlLT5j
b21wOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lc2hfbW9kZWwgKmdldF9t
b2RlbChzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCB1aW50OF90DQo+IGVsZV9pZHgsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50
MzJfdCBtb2RlbF9pZCkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IG1lc2hfZWxlbWVudCAq
ZWxlOw0KPiA+ICsgICAgICAgR0xpc3QgKmw7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFub2Rl
KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICBs
ID0gZ19saXN0X2ZpbmRfY3VzdG9tKG5vZGUtPmVsZW1lbnRzLA0KPiBHVUlOVF9UT19QT0lOVEVS
KGVsZV9pZHgpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hfZWxl
bWVudF9pZHgpOw0KPiA+ICsgICAgICAgaWYgKCFsKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1
cm4gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICBlbGUgPSBsLT5kYXRhOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20oZWxlLT5tb2RlbHMsIEdVSU5UX1RPX1BPSU5U
RVIobW9kZWxfaWQpLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hf
bW9kZWxfaWQpOw0KPiA+ICsgICAgICAgaWYgKCFsKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1
cm4gTlVMTDsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbC0+ZGF0YTsNCj4gPiArDQo+ID4g
K30NCj4gPiArDQo+ID4gK2Jvb2wgbm9kZV9hZGRfYmluZGluZyhzdHJ1Y3QgbWVzaF9ub2RlICpu
b2RlLCB1aW50OF90IGVsZV9pZHgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgdWludDMy
X3QgbW9kZWxfaWQsIHVpbnQxNl90IGFwcF9pZHgpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVj
dCBtZXNoX21vZGVsICptb2RlbDsNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsNCj4gPiAr
ICAgICAgIG1vZGVsID0gZ2V0X21vZGVsKG5vZGUsIGVsZV9pZHgsIG1vZGVsX2lkKTsNCj4gPiAr
ICAgICAgIGlmKCFtb2RlbCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+
ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZChtb2RlbC0+YmluZGluZ3MsIEdVSU5UX1RP
X1BPSU5URVIoYXBwX2lkeCkpOw0KPiA+ICsgICAgICAgaWYgKGwpDQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoKG5vZGUgPT0gbG9jYWxf
bm9kZSkgJiYgbW9kZWwtPmNicy5iaW5kKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmICghbW9k
ZWwtPmNicy5iaW5kKGFwcF9pZHgsIEFDVElPTl9BREQpKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBt
b2RlbC0+YmluZGluZ3MgPSBnX2xpc3RfYXBwZW5kKG1vZGVsLT5iaW5kaW5ncywNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1VJTlRfVE9fUE9JTlRFUihhcHBf
aWR4KSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+
ID4gK3VpbnQ4X3Qgbm9kZV9nZXRfZGVmYXVsdF90dGwoc3RydWN0IG1lc2hfbm9kZSAqbm9kZSkN
Cj4gPiArew0KPiA+ICsgICAgICAgaWYgKCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1
cm4gREVGQVVMVF9UVEw7DQo+ID4gKyAgICAgICBlbHNlIGlmIChub2RlID09IGxvY2FsX25vZGUp
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBuZXRfZ2V0X2RlZmF1bHRfdHRsKCk7DQo+ID4g
KyAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBub2RlLT50dGw7DQo+ID4g
K30NCj4gPiArDQo+ID4gK2Jvb2wgbm9kZV9zZXRfZGVmYXVsdF90dGwoc3RydWN0IG1lc2hfbm9k
ZSAqbm9kZSwgdWludDhfdCB0dGwpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmICghbm9kZSkNCj4g
PiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIG5vZGUt
PnR0bCA9IHR0bDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAobm9kZSA9PSBsb2NhbF9ub2RlIHx8
IGxvY2FsX25vZGUgPT0gTlVMTCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIG5ldF9zZXRf
ZGVmYXVsdF90dGwodHRsKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiAr
fQ0KPiA+ICsNCj4gPiArYm9vbCBub2RlX3NldF9zZXF1ZW5jZV9udW1iZXIoc3RydWN0IG1lc2hf
bm9kZSAqbm9kZSwgdWludDMyX3QNCj4gc2VxKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoIW5v
ZGUpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBub2RlLT5zZXFfbnVtYmVyID0gc2VxOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChub2RlID09
IGxvY2FsX25vZGUgfHwgbG9jYWxfbm9kZSA9PSBOVUxMKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gbmV0X3NldF9zZXFfbnVtKHNlcSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRy
dWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3VpbnQzMl90IG5vZGVfZ2V0X3NlcXVlbmNlX251bWJl
cihzdHJ1Y3QgbWVzaF9ub2RlICpub2RlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpZiAoIW5vZGUp
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAweGZmZmZmZmZmOw0KPiA+ICsgICAgICAgZWxz
ZSBpZiAobm9kZSA9PSBsb2NhbF9ub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gbmV0
X2dldF9zZXFfbnVtKCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIG5vZGUtPnNlcV9udW1i
ZXI7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgbm9kZV9zZXRfaXZfaW5kZXgoc3RydWN0IG1l
c2hfbm9kZSAqbm9kZSwgdWludDMyX3QgaXZfaW5kZXgpDQo+ID4gK3sNCj4gPiArICAgICAgIGlm
ICghbm9kZSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiAr
ICAgICAgIG5vZGUtPml2X2luZGV4ID0gaXZfaW5kZXg7DQo+ID4gKyAgICAgICByZXR1cm4gdHJ1
ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdWludDMyX3Qgbm9kZV9nZXRfaXZfaW5kZXgoc3RydWN0
IG1lc2hfbm9kZSAqbm9kZSkNCj4gPiArew0KPiA+ICsgICAgICAgYm9vbCB1cGRhdGU7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMHhm
ZmZmZmZmZjsNCj4gPiArICAgICAgIGVsc2UgaWYgKG5vZGUgPT0gbG9jYWxfbm9kZSkNCj4gPiAr
ICAgICAgICAgICAgICAgcmV0dXJuIG5ldF9nZXRfaXZfaW5kZXgoJnVwZGF0ZSk7DQo+ID4gKyAg
ICAgICByZXR1cm4gbm9kZS0+aXZfaW5kZXg7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgbm9k
ZV9tb2RlbF9wdWJfc2V0KHN0cnVjdCBtZXNoX25vZGUgKm5vZGUsIHVpbnQ4X3QgZWxlLA0KPiB1
aW50MzJfdCBtb2RlbF9pZCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBzdHJ1Y3QgbWVzaF9wdWJsaWNhdGlvbiAqcHViKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICBzdHJ1Y3QgbWVzaF9tb2RlbCAqbW9kZWw7DQo+ID4gKw0KPiA+ICsgICAgICAgbW9k
ZWwgPSBnZXRfbW9kZWwobm9kZSwgZWxlLCBtb2RlbF9pZCk7DQo+ID4gKyAgICAgICBpZighbW9k
ZWwpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBpZiAoIW1vZGVsLT5wdWIpDQo+ID4gKyAgICAgICAgICAgICAgIG1vZGVsLT5wdWIgPSBnX21h
bGxvYzAoc2l6ZW9mKHN0cnVjdCBtZXNoX3B1YmxpY2F0aW9uKSk7DQo+ID4gKyAgICAgICBpZiAo
IW1vZGVsKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsg
ICAgICAgbWVtY3B5KG1vZGVsLT5wdWIsIHB1YiwgKHNpemVvZihzdHJ1Y3QgbWVzaF9wdWJsaWNh
dGlvbikpKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZigobm9kZSA9PSBsb2NhbF9ub2RlKSAmJiBt
b2RlbC0+Y2JzLnB1YikNCj4gPiArICAgICAgICAgICAgICAgbW9kZWwtPmNicy5wdWIocHViKTsN
Cj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdHJ1Y3QgbWVz
aF9wdWJsaWNhdGlvbiAqbm9kZV9tb2RlbF9wdWJfZ2V0KHN0cnVjdCBtZXNoX25vZGUNCj4gKm5v
ZGUsIHVpbnQ4X3QgZWxlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgdWludDMyX3QgbW9kZWxfaWQpDQo+ID4gK3sNCj4gPiArICAg
ICAgIHN0cnVjdCBtZXNoX21vZGVsICptb2RlbDsNCj4gPiArDQo+ID4gKyAgICAgICBtb2RlbCA9
IGdldF9tb2RlbChub2RlLCBlbGUsIG1vZGVsX2lkKTsNCj4gPiArICAgICAgIGlmKCFtb2RlbCkN
Cj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKyAgICAgICBlbHNlDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBtb2RlbC0+cHViOw0KPiA+ICt9DQo+ID4gZGlmZiAtLWdp
dCBhL21lc2gvb25vZmYtbW9kZWwuYyBiL21lc2gvb25vZmYtbW9kZWwuYw0KPiA+IG5ldyBmaWxl
IG1vZGUgMTAwNjQ0DQo+ID4gaW5kZXggMDAwMDAwMC4uNjFjNmVkNg0KPiA+IC0tLSAvZGV2L251
bGwNCj4gPiArKysgYi9tZXNoL29ub2ZmLW1vZGVsLmMNCj4gPiBAQCAtMCwwICsxLDMwNiBAQA0K
PiA+ICsvKg0KPiA+ICsgKg0KPiA+ICsgKiAgQmx1ZVogLSBCbHVldG9vdGggcHJvdG9jb2wgc3Rh
Y2sgZm9yIExpbnV4DQo+ID4gKyAqDQo+ID4gKyAqICBDb3B5cmlnaHQgKEMpIDIwMTcgIEludGVs
IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KPiA+ICsgKg0KPiA+ICsgKg0KPiA+
ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRl
IGl0IGFuZC9vcg0KPiA+ICsgKiAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05V
IExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkg
dGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyDQo+ID4gKyAqICB2ZXJzaW9uIDIu
MSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4N
Cj4gPiArICoNCj4gPiArICogIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9w
ZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLA0KPiA+ICsgKiAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJB
TlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YNCj4gPiArICogIE1FUkNI
QU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUN
Cj4gR05VDQo+ID4gKyAqICBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBk
ZXRhaWxzLg0KPiA+ICsgKg0KPiA+ICsgKiAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29w
eSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhbG9u
ZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQ0K
PiA+ICsgKiAgRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3QsIEZpZnRoIEZsb29yLCBC
b3N0b24sIE1BICAwMjExMC0xMzAxDQo+IFVTQQ0KPiA+ICsgKg0KPiA+ICsgKi8NCj4gPiArDQo+
ID4gKyNpZmRlZiBIQVZFX0NPTkZJR19IDQo+ID4gKyNpbmNsdWRlIDxjb25maWcuaD4NCj4gPiAr
I2VuZGlmDQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8c3RkaW8uaD4NCj4gPiArI2luY2x1ZGUgPGVy
cm5vLmg+DQo+ID4gKyNpbmNsdWRlIDx1bmlzdGQuaD4NCj4gPiArI2luY2x1ZGUgPHN0ZGxpYi5o
Pg0KPiA+ICsjaW5jbHVkZSA8c3RkYm9vbC5oPg0KPiA+ICsjaW5jbHVkZSA8aW50dHlwZXMuaD4N
Cj4gPiArI2luY2x1ZGUgPHN0ZGJvb2wuaD4NCj4gPiArI2luY2x1ZGUgPHN5cy91aW8uaD4NCj4g
PiArI2luY2x1ZGUgPHdvcmRleHAuaD4NCj4gPiArI2luY2x1ZGUgPHJlYWRsaW5lL3JlYWRsaW5l
Lmg+DQo+ID4gKyNpbmNsdWRlIDxyZWFkbGluZS9oaXN0b3J5Lmg+DQo+ID4gKyNpbmNsdWRlIDxn
bGliLmg+DQo+ID4gKw0KPiA+ICsjaW5jbHVkZSAiY2xpZW50L2Rpc3BsYXkuaCINCj4gPiArI2lu
Y2x1ZGUgInNyYy9zaGFyZWQvdXRpbC5oIg0KPiA+ICsjaW5jbHVkZSAibWVzaC1uZXQuaCINCj4g
PiArI2luY2x1ZGUgImtleXMuaCINCj4gPiArI2luY2x1ZGUgIm5ldC5oIg0KPiA+ICsjaW5jbHVk
ZSAibm9kZS5oIg0KPiA+ICsjaW5jbHVkZSAicHJvdi1kYi5oIg0KPiA+ICsjaW5jbHVkZSAidXRp
bC5oIg0KPiA+ICsjaW5jbHVkZSAib25vZmYtbW9kZWwuaCINCj4gPiArDQo+ID4gK3N0YXRpYyB1
aW50OF90IHRyYW5zX2lkOw0KPiA+ICtzdGF0aWMgdWludDE2X3Qgb25vZmZfYXBwX2lkeCA9IEFQ
UF9JRFhfSU5WQUxJRDsNCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgY2xpZW50X2JpbmQodWludDE2
X3QgYXBwX2lkeCwgaW50IGFjdGlvbikNCj4gPiArew0KPiA+ICsgICAgICAgaWYgKGFjdGlvbiA9
PSBBQ1RJT05fQUREKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChvbm9mZl9hcHBfaWR4ICE9
IEFQUF9JRFhfSU5WQUxJRCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBN
RVNIX1NUQVRVU19JTlNVRkZfUkVTT1VSQ0VTOw0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2Ug
ew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG9ub2ZmX2FwcF9pZHggPSBhcHBfaWR4Ow0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50ZigiT24vT2ZmIGNsaWVudCBtb2Rl
bDogbmV3IGJpbmRpbmcgJTQuNHhcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFwcF9pZHgpOw0KPiA+ICsgICAg
ICAgICAgICAgICB9DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICBp
ZiAob25vZmZfYXBwX2lkeCA9PSBhcHBfaWR4KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IG9ub2ZmX2FwcF9pZHggPSBBUFBfSURYX0lOVkFMSUQ7DQo+ID4gKyAgICAgICB9DQo+ID4gKyAg
ICAgICByZXR1cm4gTUVTSF9TVEFUVVNfU1VDQ0VTUzsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3Rh
dGljIHZvaWQgcHJpbnRfcmVtYWluaW5nX3RpbWUodWludDhfdCByZW1haW5pbmdfdGltZSkNCj4g
PiArew0KPiA+ICsgICAgICAgdWludDhfdCBzdGVwID0gKHJlbWFpbmluZ190aW1lICYgMHhjMCkg
Pj4gNjsNCj4gPiArICAgICAgIHVpbnQ4X3QgY291bnQgPSByZW1haW5pbmdfdGltZSAmIDB4M2Y7
DQo+ID4gKyAgICAgICBpbnQgc2VjcyA9IDAsIG1zZWNzID0gMCwgbWludXRlcyA9IDAsIGhvdXJz
ID0gMDsNCj4gPiArDQo+ID4gKyAgICAgICBzd2l0Y2ggKHN0ZXApIHsNCj4gPiArICAgICAgIGNh
c2UgMDoNCj4gPiArICAgICAgICAgICAgICAgbXNlY3MgPSAxMDAgKiBjb3VudDsNCj4gPiArICAg
ICAgICAgICAgICAgc2VjcyA9IG1zZWNzIC8gNjA7DQo+ID4gKyAgICAgICAgICAgICAgIG1zZWNz
IC09IChzZWNzICogNjApOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAg
IGNhc2UgMToNCj4gPiArICAgICAgICAgICAgICAgc2VjcyA9IDEgKiBjb3VudDsNCj4gPiArICAg
ICAgICAgICAgICAgbWludXRlcyA9IHNlY3MgLyA2MDsNCj4gPiArICAgICAgICAgICAgICAgc2Vj
cyAtPSAobWludXRlcyAqIDYwKTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKw0K
PiA+ICsgICAgICAgY2FzZSAyOg0KPiA+ICsgICAgICAgICAgICAgICBzZWNzID0gMTAgKiBjb3Vu
dDsNCj4gPiArICAgICAgICAgICAgICAgbWludXRlcyA9IHNlY3MgLyA2MDsNCj4gPiArICAgICAg
ICAgICAgICAgc2VjcyAtPSAobWludXRlcyAqIDYwKTsNCj4gPiArICAgICAgICAgICAgICAgYnJl
YWs7DQo+ID4gKyAgICAgICBjYXNlIDM6DQo+ID4gKyAgICAgICAgICAgICAgIG1pbnV0ZXMgPSAx
MCAqIGNvdW50Ow0KPiA+ICsgICAgICAgICAgICAgICBob3VycyA9IG1pbnV0ZXMgLyA2MDsNCj4g
PiArICAgICAgICAgICAgICAgbWludXRlcyAtPSAoaG91cnMgKiA2MCk7DQo+ID4gKyAgICAgICAg
ICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAg
ICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50
ZigiXG5cdFx0UmVtYWluaW5nIHRpbWU6ICVkIGhycyAlZCBtaW5zICVkIHNlY3MgJWQNCj4gbXNl
Y3NcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgaG91cnMsIG1pbnV0ZXMsIHNlY3MsIG1zZWNzKTsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+
ID4gK3N0YXRpYyBib29sIGNsaWVudF9tc2dfcmVjdmQodWludDE2X3Qgc3JjLCB1aW50OF90ICpk
YXRhLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdWludDE2X3QgbGVuLCB2
b2lkICp1c2VyX2RhdGEpDQo+ID4gK3sNCj4gPiArICAgICAgIHVpbnQzMl90IG9wY29kZTsNCj4g
PiArICAgICAgIGludCBuOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChtZXNoX29wY29kZV9nZXQo
ZGF0YSwgbGVuLCAmb3Bjb2RlLCAmbikpIHsNCj4gPiArICAgICAgICAgICAgICAgbGVuIC09IG47
DQo+ID4gKyAgICAgICAgICAgICAgIGRhdGEgKz0gbjsNCj4gPiArICAgICAgIH0gZWxzZQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfcHJp
bnRmKCJPbiBPZmYgTW9kZWwgTWVzc2FnZSByZWNlaXZlZCAoJWQpIG9wY29kZSAleFxuIiwNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgbGVuLCBvcGNvZGUpOw0KPiA+ICsgICAgICAgcHJpbnRfYnl0ZV9hcnJheSgiXHQi
LGRhdGEsIGxlbik7DQo+ID4gKw0KPiA+ICsgICAgICAgc3dpdGNoIChvcGNvZGUgJiB+T1BfVU5S
RUxJQUJMRSkgew0KPiA+ICsgICAgICAgZGVmYXVsdDoNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGNhc2UgT1BfR0VORVJJQ19PTk9GRl9TVEFU
VVM6DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChsZW4gIT0gMSAmJiBsZW4gIT0gMykNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
IHJsX3ByaW50ZigiTm9kZSAlNC40eDogT2ZmIFN0YXR1cyBwcmVzZW50ID0gJXMiLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyYywgZGF0YVsw
XSA/ICJPTiIgOiAiT0ZGIik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAobGVuID09
IDMpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIiwgdGFyZ2V0ID0g
JXMiLCBkYXRhWzFdID8gIk9OIiA6ICJPRkYiKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBwcmludF9yZW1haW5pbmdfdGltZShkYXRhWzJdKTsNCj4gPiArICAgICAgICAgICAgICAgfSBl
bHNlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJcbiIpOw0KPiA+ICsg
ICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBy
ZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArDQo+ID4gK3N0YXRpYyB1aW50MzJfdCB0
YXJnZXQ7DQo+ID4gK3N0YXRpYyB1aW50MzJfdCBwYXJtc1s4XTsNCj4gPiArDQo+ID4gK3N0YXRp
YyB1aW50MzJfdCByZWFkX2lucHV0X3BhcmFtZXRlcnMoY29uc3QgY2hhciAqYXJncykNCj4gPiAr
ew0KPiA+ICsgICAgICAgdWludDMyX3QgaTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWFyZ3Mp
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAwOw0KPiA+ICsNCj4gPiArICAgICAgIG1lbXNl
dChwYXJtcywgMHhmZiwgc2l6ZW9mKHBhcm1zKSk7DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yIChp
ID0gMDsgaSA8IHNpemVvZihwYXJtcykvc2l6ZW9mKHBhcm1zWzBdKTsgaSsrKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIGludCBuOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgc3NjYW5mKGFy
Z3MsICIleCIsICZwYXJtc1tpXSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChwYXJtc1tpXSA9
PSAweGZmZmZmZmZmKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgbiA9IHN0cmNzcG4oYXJncywgIiBcdCIpOw0KPiA+ICsgICAg
ICAgICAgICAgICBhcmdzID0gYXJncyArIG4gKyBzdHJzcG4oYXJncyArIG4sICIgXHQiKTsNCj4g
PiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gaTsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiArc3RhdGljIHZvaWQgY21kX3NldF9ub2RlKGNvbnN0IGNoYXIgKmFyZ3MpDQo+ID4gK3sN
Cj4gPiArICAgICAgIHVpbnQzMl90IGRzdDsNCj4gPiArICAgICAgIGNoYXIgKmVuZDsNCj4gPiAr
DQo+ID4gKyAgICAgICBkc3QgPSBzdHJ0b2woYXJncywgJmVuZCwgMTYpOw0KPiA+ICsgICAgICAg
aWYgKGVuZCAhPSAoYXJncyArIDQpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50Zigi
QmFkIHVuaWNhc3QgYWRkcmVzcyAlczogIg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICJleHBlY3RlZCBmb3JtYXQgNCBkaWdpdCBoZXhcbiIsDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYXJncyk7DQo+ID4gKyAgICAgICAgICAgICAgIHRh
cmdldCA9IFVOQVNTSUdORURfQUREUkVTUzsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIHJsX3ByaW50ZigiQ29udHJvbGxpbmcgT04vT0ZGIGZvciBub2RlICU0LjR4
XG4iLCBkc3QpOw0KPiA+ICsgICAgICAgICAgICAgICB0YXJnZXQgPSBkc3Q7DQo+ID4gKyAgICAg
ICAgICAgICAgIHNldF9tZW51X3Byb21wdCgib24vb2ZmIiwgYXJncyk7DQo+ID4gKyAgICAgICB9
DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHNlbmRfY21kKHVpbnQ4X3QgKmJ1Ziwg
dWludDE2X3QgbGVuKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2Rl
ID0gbm9kZV9nZXRfbG9jYWxfbm9kZSgpOw0KPiA+ICsgICAgICAgdWludDhfdCB0dGw7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYoIW5vZGUpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxz
ZTsNCj4gPiArDQo+ID4gKyAgICAgICB0dGwgPSBub2RlX2dldF9kZWZhdWx0X3R0bChub2RlKTsN
Cj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbmV0X2FjY2Vzc19sYXllcl9zZW5kKHR0bCwgbm9k
ZV9nZXRfcHJpbWFyeShub2RlKSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgdGFyZ2V0LCBvbm9mZl9hcHBfaWR4LCBidWYsIGxlbik7DQo+ID4gK30NCj4gPiAr
DQo+ID4gK3N0YXRpYyB2b2lkIGNtZF9nZXRfc3RhdHVzKGNvbnN0IGNoYXIgKmFyZ3MpDQo+ID4g
K3sNCj4gPiArICAgICAgIHVpbnQxNl90IG47DQo+ID4gKyAgICAgICB1aW50OF90IG1zZ1szMl07
DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2RlOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmIChJU19VTkFTU0lHTkVEKHRhcmdldCkpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJp
bnRmKCJEZXN0aW5hdGlvbiBub3Qgc2V0XG4iKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJu
Ow0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIG5vZGUgPSBub2RlX2ZpbmRfYnlf
YWRkcih0YXJnZXQpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbm9kZSkNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIG4gPSBtZXNoX29wY29kZV9zZXQo
T1BfR0VORVJJQ19PTk9GRl9HRVQsIG1zZyk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFzZW5k
X2NtZChtc2csIG4pKQ0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkZhaWxlZCB0byBz
ZW5kIFwiR0VORVJJQyBPTi9PRkYgR0VUXCJcbiIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgdm9pZCBjbWRfc2V0KGNvbnN0IGNoYXIgKmFyZ3MpDQo+ID4gK3sNCj4gPiArICAgICAgIHVp
bnQxNl90IG47DQo+ID4gKyAgICAgICB1aW50OF90IG1zZ1szMl07DQo+ID4gKyAgICAgICBzdHJ1
Y3QgbWVzaF9ub2RlICpub2RlOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChJU19VTkFTU0lHTkVE
KHRhcmdldCkpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJEZXN0aW5hdGlvbiBu
b3Qgc2V0XG4iKTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsgICAgICAgfQ0K
PiA+ICsNCj4gPiArICAgICAgIG5vZGUgPSBub2RlX2ZpbmRfYnlfYWRkcih0YXJnZXQpOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmICghbm9kZSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmICgocmVhZF9pbnB1dF9wYXJhbWV0ZXJzKGFyZ3MpICE9IDEp
ICYmDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcm1zWzBd
ICE9IDAgJiYgcGFybXNbMF0gIT0gMSkgew0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYo
IkJhZCBhcmd1bWVudHMgJXMuIEV4cGVjdGluZyBcIjBcIiBvciBcIjFcIlxuIiwgYXJncyk7DQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAg
ICAgICBuID0gbWVzaF9vcGNvZGVfc2V0KE9QX0dFTkVSSUNfT05PRkZfU0VULCBtc2cpOw0KPiA+
ICsgICAgICAgbXNnW24rK10gPSBwYXJtc1swXTsNCj4gPiArICAgICAgIG1zZ1tuKytdID0gdHJh
bnNfaWQrKzsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIXNlbmRfY21kKG1zZywgbikpDQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiRmFpbGVkIHRvIHNlbmQgXCJHRU5FUklDIE9OL09G
RiBTRVRcIlxuIik7DQo+ID4gKw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjbWRf
YmFjayhjb25zdCBjaGFyICphcmdzKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjbWRfbWVudV9tYWlu
KGZhbHNlKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgY21kX2hlbHAoY29uc3Qg
Y2hhciAqYXJncyk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG1lbnVfZW50cnkg
Y2ZnX21lbnVbXSA9IHsNCj4gPiArICAgICAgIHsidGFyZ2V0IiwgICAgICAgICAgICAgICI8dW5p
Y2FzdD4iLCAgICAgICAgICAgICAgICAgICAgY21kX3NldF9ub2RlLA0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZXQgbm9kZSB0byBjb25maWd1
cmUifSwNCj4gPiArICAgICAgIHsiZ2V0IiwgICAgICAgICAgICAgICAgIE5VTEwsICAgICAgICAg
ICAgICAgICAgICAgICAgICAgY21kX2dldF9zdGF0dXMsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdldCBPTi9PRkYgc3RhdHVzIn0sDQo+ID4g
KyAgICAgICB7Im9ub2ZmIiwgICAgICAgICAgICAgICAiPDAvMT4iLCAgICAgICAgICAgICAgICAg
ICAgICAgIGNtZF9zZXQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIlNlbmQgXCJTRVQgT04vT0ZGXCIgY29tbWFuZCJ9LA0KPiA+ICsgICAgICAg
eyJiYWNrIiwgICAgICAgICAgICAgICAgTlVMTCwgICAgICAgICAgICAgICAgICAgICAgICAgICBj
bWRfYmFjaywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAiQmFjayB0byBtYWluIG1lbnUifSwNCj4gPiArICAgICAgIHsiaGVscCIsICAgICAgICAg
ICAgICAgIE5VTEwsICAgICAgICAgICAgICAgICAgICAgICAgICAgY21kX2hlbHAsDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbmZpZyBDb21t
YW5kcyJ9LA0KPiA+ICsgICAgICAge30NCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lk
IGNtZF9oZWxwKGNvbnN0IGNoYXIgKmFyZ3MpDQo+ID4gK3sNCj4gPiArICAgICAgIHJsX3ByaW50
ZigiQ2xpZW50IENvbmZpZ3VyYXRpb24gTWVudVxuIik7DQo+ID4gKyAgICAgICBwcmludF9jbWRf
bWVudShjZmdfbWVudSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgb25vZmZfc2V0X25vZGUo
Y29uc3QgY2hhciAqYXJncykgew0KPiA+ICsgICAgICAgY21kX3NldF9ub2RlKGFyZ3MpOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lc2hfbW9kZWxfb3BzIGNsaWVudF9jYnMg
PSB7DQo+ID4gKyAgICAgICBjbGllbnRfbXNnX3JlY3ZkLA0KPiA+ICsgICAgICAgY2xpZW50X2Jp
bmQsDQo+ID4gKyAgICAgICBOVUxMLA0KPiA+ICsgICAgICAgTlVMTA0KPiA+ICt9Ow0KPiA+ICsN
Cj4gPiArYm9vbCBvbm9mZl9jbGllbnRfaW5pdCh1aW50OF90IGVsZSkNCj4gPiArew0KPiA+ICsg
ICAgICAgaWYgKCFub2RlX2xvY2FsX21vZGVsX3JlZ2lzdGVyKGVsZSwNCj4gR0VORVJJQ19PTk9G
Rl9DTElFTlRfTU9ERUxfSUQsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICZjbGllbnRfY2JzLCBOVUxMKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZh
bHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGFkZF9jbWRfbWVudSgib25vZmYiLCBjZmdfbWVudSk7
DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiBkaWZmIC0tZ2l0
IGEvbWVzaC9wcm92LWRiLmMgYi9tZXNoL3Byb3YtZGIuYw0KPiA+IG5ldyBmaWxlIG1vZGUgMTAw
NjQ0DQo+ID4gaW5kZXggMDAwMDAwMC4uYWFkNjE0NQ0KPiA+IC0tLSAvZGV2L251bGwNCj4gPiAr
KysgYi9tZXNoL3Byb3YtZGIuYw0KPiA+IEBAIC0wLDAgKzEsMTU5OSBAQA0KPiA+ICsvKg0KPiA+
ICsgKg0KPiA+ICsgKiAgQmx1ZVogLSBCbHVldG9vdGggcHJvdG9jb2wgc3RhY2sgZm9yIExpbnV4
DQo+ID4gKyAqDQo+ID4gKyAqICBDb3B5cmlnaHQgKEMpIDIwMTcgIEludGVsIENvcnBvcmF0aW9u
LiBBbGwgcmlnaHRzIHJlc2VydmVkLg0KPiA+ICsgKg0KPiA+ICsgKg0KPiA+ICsgKiAgVGhpcyBs
aWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcg0K
PiA+ICsgKiAgbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5l
cmFsIFB1YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29m
dHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyDQo+ID4gKyAqICB2ZXJzaW9uIDIuMSBvZiB0aGUgTGlj
ZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4gPiArICoNCj4g
PiArICogIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdp
bGwgYmUgdXNlZnVsLA0KPiA+ICsgKiAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0
IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YNCj4gPiArICogIE1FUkNIQU5UQUJJTElUWSBv
ciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUNCj4gR05VDQo+ID4g
KyAqICBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLg0KPiA+
ICsgKg0KPiA+ICsgKiAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05V
IExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMg
bGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQ0KPiA+ICsgKiAgRm91
bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3QsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAw
MjExMC0xMzAxDQo+IFVTQQ0KPiA+ICsgKg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gKyNpZmRlZiBI
QVZFX0NPTkZJR19IDQo+ID4gKyNpbmNsdWRlIDxjb25maWcuaD4NCj4gPiArI2VuZGlmDQo+ID4g
Kw0KPiA+ICsjaW5jbHVkZSA8ZXJybm8uaD4NCj4gPiArI2luY2x1ZGUgPGZjbnRsLmg+DQo+ID4g
KyNpbmNsdWRlIDxnbGliLmg+DQo+ID4gKyNpbmNsdWRlIDxzdGRib29sLmg+DQo+ID4gKyNpbmNs
dWRlIDxzdGRpby5oPg0KPiA+ICsjaW5jbHVkZSA8c3RkbGliLmg+DQo+ID4gKyNpbmNsdWRlIDxz
dHJpbmcuaD4NCj4gPiArI2luY2x1ZGUgPHVuaXN0ZC5oPg0KPiA+ICsNCj4gPiArI2luY2x1ZGUg
PGpzb24tYy9qc29uLmg+DQo+ID4gKyNpbmNsdWRlIDxzeXMvc3RhdC5oPg0KPiA+ICsNCj4gPiAr
I2luY2x1ZGUgPHJlYWRsaW5lL3JlYWRsaW5lLmg+DQo+ID4gKyNpbmNsdWRlIDxnbGliLmg+DQo+
ID4gKw0KPiA+ICsjaW5jbHVkZSAic3JjL3NoYXJlZC91dGlsLmgiDQo+ID4gKyNpbmNsdWRlICJj
bGllbnQvZGlzcGxheS5oIg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgIm1lc2gtbmV0LmgiDQo+ID4g
KyNpbmNsdWRlICJjcnlwdG8uaCINCj4gPiArI2luY2x1ZGUgImtleXMuaCINCj4gPiArI2luY2x1
ZGUgIm5ldC5oIg0KPiA+ICsjaW5jbHVkZSAibm9kZS5oIg0KPiA+ICsjaW5jbHVkZSAidXRpbC5o
Ig0KPiA+ICsjaW5jbHVkZSAicHJvdi1kYi5oIg0KPiA+ICsNCj4gPiArI2RlZmluZSBDSEVDS19L
RVlfSURYX1JBTkdFKHgpICgoKHgpID49IDApICYmICgoeCkgPD0gNDA5NSkpDQo+ID4gKw0KPiA+
ICtzdGF0aWMgY29uc3QgY2hhciAqcHJvdl9maWxlbmFtZTsNCj4gPiArc3RhdGljIGNvbnN0IGNo
YXIgKmxvY2FsX2ZpbGVuYW1lOw0KPiA+ICsNCj4gPiArc3RhdGljIGNoYXIqIHByb3ZfZmlsZV9y
ZWFkKGNvbnN0IGNoYXIgKmZpbGVuYW1lKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpbnQgZmQ7DQo+
ID4gKyAgICAgICBjaGFyICpzdHI7DQo+ID4gKyAgICAgICBzdHJ1Y3Qgc3RhdCBzdDsNCj4gPiAr
ICAgICAgIHNzaXplX3Qgc3o7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFmaWxlbmFtZSkNCj4g
PiArICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgZmQgPSBv
cGVuKGZpbGVuYW1lLE9fUkRPTkxZKTsNCj4gPiArICAgICAgIGlmICghZmQpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChmc3RhdChmZCwg
JnN0KSA9PSAtMSkgew0KPiA+ICsgICAgICAgICAgICAgICBjbG9zZShmZCk7DQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAg
IHN0ciA9IChjaGFyICopIGdfbWFsbG9jMChzdC5zdF9zaXplICsgMSk7DQo+ID4gKyAgICAgICBp
ZiAoIXN0cikgew0KPiA+ICsgICAgICAgICAgICAgICBjbG9zZShmZCk7DQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHN6
ID0gcmVhZChmZCwgc3RyLCBzdC5zdF9zaXplKTsNCj4gPiArICAgICAgIGlmIChzeiAhPSBzdC5z
dF9zaXplKQ0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIkluY29tcGxldGUgcmVhZDog
JWQgdnMgJWRcbiIsIChpbnQpc3osDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAoaW50KShzdC5zdF9zaXplKSk7DQo+ID4gKw0KPiA+
ICsgICAgICAgY2xvc2UoZmQpOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiBzdHI7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHByb3ZfZmlsZV93cml0ZShqc29uX29iamVjdCAq
am1haW4sIGJvb2wgbG9jYWwpDQo+ID4gK3sNCj4gPiArICAgICAgIEZJTEUgKm91dGZpbGU7DQo+
ID4gKyAgICAgICBjb25zdCBjaGFyICpvdXRfc3RyOw0KPiA+ICsgICAgICAgY29uc3QgY2hhciAq
b3V0X2ZpbGVuYW1lOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChsb2NhbCkNCj4gPiArICAgICAg
ICAgICAgICAgb3V0X2ZpbGVuYW1lID0gbG9jYWxfZmlsZW5hbWU7DQo+ID4gKyAgICAgICBlbHNl
DQo+ID4gKyAgICAgICAgICAgICAgIG91dF9maWxlbmFtZSA9IHByb3ZfZmlsZW5hbWU7DQo+ID4g
Kw0KPiA+ICsgICAgICAgb3V0ZmlsZSA9IGZvcGVuKG91dF9maWxlbmFtZSwgIndyIik7DQo+ID4g
KyAgICAgICBpZiAoIW91dGZpbGUpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJG
YWlsZWQgdG8gb3BlbiBmaWxlICVzIGZvciB3cml0aW5nXG4iLCBvdXRfZmlsZW5hbWUpOw0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAg
ICAgb3V0X3N0ciA9IGpzb25fb2JqZWN0X3RvX2pzb25fc3RyaW5nX2V4dChqbWFpbiwNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBKU09OX0NfVE9f
U1RSSU5HX1BSRVRUWSk7DQo+ID4gKw0KPiA+ICsgICAgICAgZndyaXRlKG91dF9zdHIsIHNpemVv
ZihjaGFyKSwgc3RybGVuKG91dF9zdHIpLCBvdXRmaWxlKTsNCj4gPiArICAgICAgIGZjbG9zZShv
dXRmaWxlKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHV0X3VpbnQxNihqc29u
X29iamVjdCAqam9iamVjdCwgY29uc3QgY2hhciAqZGVzYywgdWludDE2X3QNCj4gdmFsdWUpDQo+
ID4gK3sNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqc3RyaW5nOw0KPiA+ICsgICAgICAgY2hh
ciBidWZbNV07DQo+ID4gKw0KPiA+ICsgICAgICAgc25wcmludGYoYnVmLCA1LCAiJTQuNHgiLCB2
YWx1ZSk7DQo+ID4gKyAgICAgICBqc3RyaW5nID0ganNvbl9vYmplY3RfbmV3X3N0cmluZyhidWYp
Ow0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2FkZChqb2JqZWN0LCBkZXNjLCBqc3Ry
aW5nKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHV0X3VpbnQzMihqc29uX29i
amVjdCAqam9iamVjdCwgY29uc3QgY2hhciAqZGVzYywgdWludDMyX3QNCj4gdmFsdWUpDQo+ID4g
K3sNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqc3RyaW5nOw0KPiA+ICsgICAgICAgY2hhciBi
dWZbOV07DQo+ID4gKw0KPiA+ICsgICAgICAgc25wcmludGYoYnVmLCA5LCAiJTguOHgiLCB2YWx1
ZSk7DQo+ID4gKyAgICAgICBqc3RyaW5nID0ganNvbl9vYmplY3RfbmV3X3N0cmluZyhidWYpOw0K
PiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2FkZChqb2JqZWN0LCBkZXNjLCBqc3RyaW5n
KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHV0X3VpbnQxNl9hcnJheV9lbnRy
eShqc29uX29iamVjdCAqamFycmF5LCB1aW50MTZfdCB2YWx1ZSkNCj4gPiArew0KPiA+ICsgICAg
ICAganNvbl9vYmplY3QgKmpzdHJpbmc7DQo+ID4gKyAgICAgICBjaGFyIGJ1Zls1XTsNCj4gPiAr
DQo+ID4gKyAgICAgICBzbnByaW50ZihidWYsIDUsICIlNC40eCIsIHZhbHVlKTsNCj4gPiArICAg
ICAgIGpzdHJpbmcgPSBqc29uX29iamVjdF9uZXdfc3RyaW5nKGJ1Zik7DQo+ID4gKyAgICAgICBq
c29uX29iamVjdF9hcnJheV9hZGQoamFycmF5LCBqc3RyaW5nKTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArc3RhdGljIHZvaWQgcHV0X3VpbnQzMl9hcnJheV9lbnRyeShqc29uX29iamVjdCAqamFycmF5
LCB1aW50MzJfdCB2YWx1ZSkNCj4gPiArew0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmpzdHJp
bmc7DQo+ID4gKyAgICAgICBjaGFyIGJ1Zls5XTsNCj4gPiArDQo+ID4gKyAgICAgICBzbnByaW50
ZihidWYsIDksICIlOC44eCIsIHZhbHVlKTsNCj4gPiArICAgICAgIGpzdHJpbmcgPSBqc29uX29i
amVjdF9uZXdfc3RyaW5nKGJ1Zik7DQo+ID4gKyAgICAgICBqc29uX29iamVjdF9hcnJheV9hZGQo
amFycmF5LCBqc3RyaW5nKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHV0X3Vp
bnQxNl9saXN0KGpzb25fb2JqZWN0ICpqYXJyYXksIEdMaXN0ICpsaXN0KQ0KPiA+ICt7DQo+ID4g
KyAgICAgICBHTGlzdCAqbDsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoIWxpc3QpDQo+ID4gKyAg
ICAgICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBmb3IgKGwgPSBsaXN0OyBs
OyBsID0gbC0+bmV4dCkgew0KPiA+ICsgICAgICAgICAgICAgICB1aW50MzJfdCBpdmFsdWUgPSBH
UE9JTlRFUl9UT19VSU5UKGwtPmRhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICBwdXRfdWludDE2
X2FycmF5X2VudHJ5KGphcnJheSwgaXZhbHVlKTsNCj4gPiArICAgICAgIH0NCj4gPiArfQ0KPiA+
ICsNCj4gPiArc3RhdGljIHZvaWQgYWRkX25vZGVfaWR4cyhqc29uX29iamVjdCAqam5vZGUsIGNv
bnN0IGNoYXIgKmRlc2MsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHTGlz
dCAqaWR4cykNCj4gPiArew0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmphcnJheTsNCj4gPiAr
DQo+ID4gKyAgICAgICBqYXJyYXkgPSBqc29uX29iamVjdF9uZXdfYXJyYXkoKTsNCj4gPiArDQo+
ID4gKyAgICAgICBwdXRfdWludDE2X2xpc3QoamFycmF5LCBpZHhzKTsNCj4gPiArDQo+ID4gKyAg
ICAgICBqc29uX29iamVjdF9vYmplY3RfYWRkKGpub2RlLCBkZXNjLCBqYXJyYXkpOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwYXJzZV91bmljYXN0X3JhbmdlKGpzb25fb2JqZWN0
ICpqb2JqZWN0KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBpbnQgY250Ow0KPiA+ICsgICAgICAgaW50
IGk7DQo+ID4gKw0KPiA+ICsgICAgICAgY250ID0ganNvbl9vYmplY3RfYXJyYXlfbGVuZ3RoKGpv
YmplY3QpOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBjbnQ7ICsraSkgew0K
PiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVjdCAqanJhbmdlOw0KPiA+ICsgICAgICAgICAg
ICAgICBqc29uX29iamVjdCAqanZhbHVlOw0KPiA+ICsgICAgICAgICAgICAgICB1aW50MTZfdCBs
b3csIGhpZ2g7DQo+ID4gKyAgICAgICAgICAgICAgIGNoYXIgKnN0cjsNCj4gPiArDQo+ID4gKyAg
ICAgICAgICAgICAgIGpyYW5nZSA9IGpzb25fb2JqZWN0X2FycmF5X2dldF9pZHgoam9iamVjdCwg
aSk7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoanJhbmdl
LCAibG93QWRkcmVzcyIsICZqdmFsdWUpOw0KPiA+ICsgICAgICAgICAgICAgICBzdHIgPSAoY2hh
ciAqKWpzb25fb2JqZWN0X2dldF9zdHJpbmcoanZhbHVlKTsNCj4gPiArICAgICAgICAgICAgICAg
aWYgKHNzY2FuZihzdHIsICIlMDRoeCIsICZsb3cpICE9IDEpDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAganNvbl9v
YmplY3Rfb2JqZWN0X2dldF9leChqcmFuZ2UsICJoaWdoQWRkcmVzcyIsICZqdmFsdWUpOw0KPiA+
ICsgICAgICAgICAgICAgICBzdHIgPSAoY2hhciAqKWpzb25fb2JqZWN0X2dldF9zdHJpbmcoanZh
bHVlKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKHNzY2FuZihzdHIsICIlMDRoeCIsICZoaWdo
KSAhPSAxKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiAr
DQo+ID4gKyAgICAgICAgICAgICAgIGlmKGhpZ2ggPCBsb3cpDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgbmV0X2Fk
ZF9hZGRyZXNzX3Bvb2wobG93LCBoaWdoKTsNCj4gPiArICAgICAgIH0NCj4gPiArICAgICAgIHJl
dHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IHBhcnNlX25vZGVfa2V5
cyhzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCBqc29uX29iamVjdCAqamlkeHMsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBib29sIGlzX2FwcF9rZXkpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIGludCBpZHhfY250Ow0KPiA+ICsgICAgICAgaW50IGk7DQo+ID4gKw0KPiA+ICsgICAg
ICAgaWR4X2NudCA9IGpzb25fb2JqZWN0X2FycmF5X2xlbmd0aChqaWR4cyk7DQo+ID4gKyAgICAg
ICBmb3IgKGkgPSAwOyBpIDwgaWR4X2NudDsgKytpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlu
dCBpZHg7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0ICpqdmFsdWU7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBqdmFsdWUgPSBqc29uX29iamVjdF9hcnJheV9nZXRfaWR4KGpp
ZHhzLCBpKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFqdmFsdWUpDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICAgICAgICAgIGlkeCA9IGpzb25fb2Jq
ZWN0X2dldF9pbnQoanZhbHVlKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFDSEVDS19LRVlf
SURYX1JBTkdFKGlkeCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4g
Kw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoaXNfYXBwX2tleSkNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBub2RlX2FwcF9rZXlfYWRkKG5vZGUsIGlkeCk7DQo+ID4gKyAgICAgICAgICAg
ICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBub2RlX25ldF9rZXlfYWRkKG5v
ZGUsIGlkeCk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIGk7DQo+
ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHBhcnNlX2NvbXBvc2l0aW9uX21vZGVscyhz
dHJ1Y3QgbWVzaF9ub2RlICpub2RlLCBpbnQNCj4gaW5kZXgsDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIGpzb25fb2JqZWN0ICpqbW9kZWxzKQ0KPiA+ICt7DQo+
ID4gKyAgICAgICBpbnQgbW9kZWxfY250Ow0KPiA+ICsgICAgICAgaW50IGk7DQo+ID4gKw0KPiA+
ICsgICAgICAgbW9kZWxfY250ID0ganNvbl9vYmplY3RfYXJyYXlfbGVuZ3RoKGptb2RlbHMpOw0K
PiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBtb2RlbF9jbnQ7ICsraSkgew0KPiA+
ICsgICAgICAgICAgICAgICBqc29uX29iamVjdCAqam1vZGVsOw0KPiA+ICsgICAgICAgICAgICAg
ICBjaGFyICpzdHI7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQzMl90IG1vZGVsX2lkOw0KPiA+
ICsgICAgICAgICAgICAgICBpbnQgbGVuOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgam1v
ZGVsID0ganNvbl9vYmplY3RfYXJyYXlfZ2V0X2lkeChqbW9kZWxzLCBpKTsNCj4gPiArICAgICAg
ICAgICAgICAgc3RyID0gKGNoYXIgKilqc29uX29iamVjdF9nZXRfc3RyaW5nKGptb2RlbCk7DQo+
ID4gKyAgICAgICAgICAgICAgIGxlbiA9IHN0cmxlbihzdHIpOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKGxlbiAhPSA0ICYmIGxlbiAhPSA4KQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChzc2Nh
bmYoc3RyLCAiJTA4eCIsICZtb2RlbF9pZCkgIT0gMSkNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChsZW4gPT0gNCkNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBtb2RlbF9pZCArPSAweGZmZmYwMDAwOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgbm9kZV9zZXRfbW9kZWwobm9kZSwgaW5kZXgsIG1vZGVsX2lk
KTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiAr
fQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgcGFyc2VfY29tcG9zaXRpb25fZWxlbWVudHMoc3Ry
dWN0IG1lc2hfbm9kZSAqbm9kZSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAganNvbl9vYmplY3QgKmplbGVtZW50cykNCj4gPiArew0KPiA+ICsgICAgICAgaW50
IGVsX2NudDsNCj4gPiArICAgICAgIGludCBpOw0KPiA+ICsNCj4gPiArICAgICAgIGVsX2NudCA9
IGpzb25fb2JqZWN0X2FycmF5X2xlbmd0aChqZWxlbWVudHMpOw0KPiA+ICsgICAgICAgbm9kZV9z
ZXRfbnVtX2VsZW1lbnRzKG5vZGUsIGVsX2NudCk7DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yIChp
ID0gMDsgaSA8IGVsX2NudDsgKytpKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0
ICpqZWxlbWVudDsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmptb2RlbHM7DQo+
ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0ICpqdmFsdWU7DQo+ID4gKyAgICAgICAgICAg
ICAgIGludCBpbmRleDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGplbGVtZW50ID0ganNv
bl9vYmplY3RfYXJyYXlfZ2V0X2lkeChqZWxlbWVudHMsIGkpOw0KPiA+ICsgICAgICAgICAgICAg
ICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGplbGVtZW50LCAiZWxlbWVudEluZGV4IiwgJmp2
YWx1ZSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChqdmFsdWUpIHsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBpbmRleCA9IGpzb25fb2JqZWN0X2dldF9pbnQoanZhbHVlKTsNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW5kZXggPj0gZWxfY250KSB7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2UNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBp
ZiAoIW5vZGVfc2V0X2VsZW1lbnQobm9kZSwgaW5kZXgpKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2Jq
ZWN0X29iamVjdF9nZXRfZXgoamVsZW1lbnQsICJtb2RlbHMiLCAmam1vZGVscyk7DQo+ID4gKyAg
ICAgICAgICAgICAgIGlmICgham1vZGVscykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBj
b250aW51ZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmKCFwYXJzZV9jb21wb3NpdGlv
bl9tb2RlbHMobm9kZSwgaW5kZXgsIGptb2RlbHMpKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgIH0NCj4gPiArICAgICAgIHJldHVybiB0cnVl
Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwYXJzZV9tb2RlbF9wdWIoc3RydWN0
IG1lc2hfbm9kZSAqbm9kZSwgaW50IGVsZV9pZHgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICB1aW50MzJfdCBtb2RlbF9pZCwganNvbl9vYmplY3QgKmpwdWIpDQo+ID4gK3sN
Cj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqdmFsdWU7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVz
aF9wdWJsaWNhdGlvbiBwdWI7DQo+ID4gKyAgICAgICBjaGFyICpzdHI7DQo+ID4gKw0KPiA+ICsg
ICAgICAgbWVtc2V0KCZwdWIsIDAsIHNpemVvZihzdHJ1Y3QgbWVzaF9wdWJsaWNhdGlvbikpOw0K
PiA+ICsNCj4gPiArICAgICAgIC8qIFJlYWQgb25seSByZXF1aXJlZCBmaWVsZHMgKi8NCj4gPiAr
ICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoanB1YiwgImFkZHJlc3MiLCAmanZhbHVl
KTsNCj4gPiArICAgICAgIGlmICghanZhbHVlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4g
ZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgc3RyID0gKGNoYXIgKilqc29uX29iamVjdF9nZXRf
c3RyaW5nKGp2YWx1ZSk7DQo+ID4gKyAgICAgICBpZiAoc3NjYW5mKHN0ciwgIiUwNGh4IiwgJnB1
Yi51LmFkZHIxNikgIT0gMSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+
ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoanB1YiwgImluZGV4Iiwg
Jmp2YWx1ZSk7DQo+ID4gKyAgICAgICBpZiAoIWp2YWx1ZSkNCj4gPiArICAgICAgICAgICAgICAg
cmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHN0ciA9IChjaGFyICopanNvbl9vYmpl
Y3RfZ2V0X3N0cmluZyhqdmFsdWUpOw0KPiA+ICsgICAgICAgaWYgKHNzY2FuZihzdHIsICIlMDRo
eCIsICZwdWIuYXBwX2lkeCkgIT0gMSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNl
Ow0KPiA+ICsNCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGpw
dWIsICJ0dGwiLCAmanZhbHVlKTsNCj4gPiArICAgICAgIHB1Yi50dGwgPSBqc29uX29iamVjdF9n
ZXRfaW50KGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFub2RlX21vZGVsX3B1Yl9z
ZXQobm9kZSwgZWxlX2lkeCwgbW9kZWxfaWQsICZwdWIpKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4g
PiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGJvb2wgcGFyc2VfYmluZGluZ3Moc3RydWN0IG1lc2hf
bm9kZSAqbm9kZSwgaW50IGVsZV9pZHgsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICB1aW50MzJfdCBtb2RlbF9pZCwganNvbl9vYmplY3QgKmpiaW5kaW5ncykNCj4gPiArew0K
PiA+ICsgICAgICAgaW50IGNudDsNCj4gPiArICAgICAgIGludCBpOw0KPiA+ICsNCj4gPiArICAg
ICAgIGNudCA9IGpzb25fb2JqZWN0X2FycmF5X2xlbmd0aChqYmluZGluZ3MpOw0KPiA+ICsNCj4g
PiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBjbnQ7ICsraSkgew0KPiA+ICsgICAgICAgICAgICAg
ICBpbnQga2V5X2lkeDsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmp2YWx1ZTsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGp2YWx1ZSA9IGpzb25fb2JqZWN0X2FycmF5X2dl
dF9pZHgoamJpbmRpbmdzLCBpKTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFqdmFsdWUpDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICBrZXlfaWR4ID0ganNvbl9vYmplY3RfZ2V0X2ludChqdmFsdWUpOw0KPiA+ICsg
ICAgICAgICAgICAgICBpZiAoIUNIRUNLX0tFWV9JRFhfUkFOR0Uoa2V5X2lkeCkpDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgaWYgKCFub2RlX2FkZF9iaW5kaW5nKG5vZGUsIGVsZV9pZHgsIG1vZGVsX2lkLCBrZXlf
aWR4KSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAg
ICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+
ID4gK3N0YXRpYyBib29sIHBhcnNlX2NvbmZpZ3VyYXRpb25fbW9kZWxzKHN0cnVjdCBtZXNoX25v
ZGUgKm5vZGUsIGludA0KPiBlbGVfaWR4LA0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVj
dCAqam1vZGVscywgdWludDMyX3QgdGFyZ2V0X2lkLCBqc29uX29iamVjdCAqKmp0YXJnZXQpDQo+
ID4gK3sNCj4gPiArICAgICAgIGludCBtb2RlbF9jbnQ7DQo+ID4gKyAgICAgICBpbnQgaTsNCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoanRhcmdldCkNCj4gPiArICAgICAgICAgICAgICAgKmp0YXJn
ZXQgPSBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgIG1vZGVsX2NudCA9IGpzb25fb2JqZWN0X2Fy
cmF5X2xlbmd0aChqbW9kZWxzKTsNCj4gPiArDQo+ID4gKyAgICAgICBmb3IgKGkgPSAwOyBpIDwg
bW9kZWxfY250OyArK2kpIHsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmptb2Rl
bDsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmp2YWx1ZTsNCj4gPiArICAgICAg
ICAgICAgICAganNvbl9vYmplY3QgKmphcnJheTsNCj4gPiArICAgICAgICAgICAgICAgY2hhciAq
c3RyOw0KPiA+ICsgICAgICAgICAgICAgICBpbnQgbGVuOw0KPiA+ICsgICAgICAgICAgICAgICB1
aW50MzJfdCBtb2RlbF9pZDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGptb2RlbCA9IGpz
b25fb2JqZWN0X2FycmF5X2dldF9pZHgoam1vZGVscywgaSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGptb2RlbCwgIm1vZGVsSWQiLCAmanZh
bHVlKTsNCj4gPiArICAgICAgICAgICAgICAgc3RyID0gKGNoYXIgKilqc29uX29iamVjdF9nZXRf
c3RyaW5nKGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBsZW4gPSBzdHJsZW4o
c3RyKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChsZW4gIT0gNCAmJiBsZW4gIT0g
OCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+
ICsgICAgICAgICAgICAgICBpZiAoc3NjYW5mKHN0ciwgIiUwOHgiLCAmbW9kZWxfaWQpICE9IDEp
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAg
ICAgICAgICBpZiAobGVuID09IDQpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxf
aWQgKz0gMHhmZmZmMDAwMDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChqdGFyZ2V0
ICYmIG1vZGVsX2lkID09IHRhcmdldF9pZCkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICpqdGFyZ2V0ID0gam1vZGVsOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0
cnVlOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBq
c29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGptb2RlbCwgImJpbmQiLCAmamFycmF5KTsNCj4gPiAr
ICAgICAgICAgICAgICAgaWYgKGphcnJheSAmJiAhcGFyc2VfYmluZGluZ3Mobm9kZSwgZWxlX2lk
eCwgbW9kZWxfaWQsIGphcnJheSkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJu
IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dl
dF9leChqbW9kZWwsICJwdWJsaXNoIiwgJmp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICBpZiAoanZhbHVlICYmICFwYXJzZV9tb2RlbF9wdWIobm9kZSwgZWxlX2lkeCwgbW9kZWxf
aWQsIGp2YWx1ZSkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0K
PiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwYXJzZV9jb25maWd1cmF0aW9uX2VsZW1lbnRzKHN0cnVj
dCBtZXNoX25vZGUgKm5vZGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBq
c29uX29iamVjdCAqamVsZW1lbnRzLCBib29sIGxvY2FsKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBp
bnQgZWxfY250Ow0KPiA+ICsgICAgICAgaW50IGk7DQo+ID4gKw0KPiA+ICsgICAgICAgZWxfY250
ID0ganNvbl9vYmplY3RfYXJyYXlfbGVuZ3RoKGplbGVtZW50cyk7DQo+ID4gKyAgICAgICBub2Rl
X3NldF9udW1fZWxlbWVudHMobm9kZSwgZWxfY250KTsNCj4gPiArDQo+ID4gKyAgICAgICBmb3Ig
KGkgPSAwOyBpIDwgZWxfY250OyArK2kpIHsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmpl
Y3QgKmplbGVtZW50Ow0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVjdCAqam1vZGVsczsN
Cj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmp2YWx1ZTsNCj4gPiArICAgICAgICAg
ICAgICAgaW50IGluZGV4Ow0KPiA+ICsgICAgICAgICAgICAgICB1aW50MTZfdCBhZGRyOw0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgamVsZW1lbnQgPSBqc29uX29iamVjdF9hcnJheV9nZXRf
aWR4KGplbGVtZW50cywgaSk7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVj
dF9nZXRfZXgoamVsZW1lbnQsICJlbGVtZW50SW5kZXgiLCAmanZhbHVlKTsNCj4gPiArICAgICAg
ICAgICAgICAgaWYgKGp2YWx1ZSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGluZGV4
ID0ganNvbl9vYmplY3RfZ2V0X2ludChqdmFsdWUpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIGlmIChpbmRleCA+PSBlbF9jbnQpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9DQo+ID4g
KyAgICAgICAgICAgICAgIH0gZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVy
biBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmIChpbmRleCA9PSAwKSB7DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgY2hhciAqc3RyOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGplbGVtZW50LCAidW5p
Y2FzdEFkZHJlc3MiLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgJmp2YWx1ZSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
c3RyID0gKGNoYXIgKilqc29uX29iamVjdF9nZXRfc3RyaW5nKGp2YWx1ZSk7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgaWYgKHNzY2FuZihzdHIsICIlMDRoeCIsICZhZGRyKSAhPSAxKQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWxvY2FsICYmICFuZXRfcmVzZXJ2ZV9h
ZGRyZXNzX3JhbmdlKGFkZHIsIGVsX2NudCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IG5vZGVfc2V0X3ByaW1hcnkobm9kZSwgYWRkcik7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4g
PiArDQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoamVsZW1l
bnQsICJtb2RlbHMiLCAmam1vZGVscyk7DQo+ID4gKyAgICAgICAgICAgICAgIGlmICgham1vZGVs
cykNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsNCj4gPiArDQo+ID4gKyAg
ICAgICAgICAgICAgIGlmKCFwYXJzZV9jb25maWd1cmF0aW9uX21vZGVscyhub2RlLCBpbmRleCwg
am1vZGVscywgMCwgTlVMTCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZh
bHNlOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4g
PiArDQo+ID4gK3N0YXRpYyB2b2lkIGFkZF9rZXkoanNvbl9vYmplY3QgKmpvYmplY3QsIGNvbnN0
IGNoYXIgKmRlc2MsIHVpbnQ4X3QqIGtleSkNCj4gPiArew0KPiA+ICsgICAgICAganNvbl9vYmpl
Y3QgKmpzdHJpbmc7DQo+ID4gKyAgICAgICBjaGFyIGhleHN0clszM107DQo+ID4gKw0KPiA+ICsg
ICAgICAgaGV4MnN0cihrZXksIDE2LCBoZXhzdHIsIDMzKTsNCj4gPiArICAgICAgIGpzdHJpbmcg
PSBqc29uX29iamVjdF9uZXdfc3RyaW5nKGhleHN0cik7DQo+ID4gKyAgICAgICBqc29uX29iamVj
dF9vYmplY3RfYWRkKGpvYmplY3QsIGRlc2MsIGpzdHJpbmcpOw0KPiA+ICt9DQo+ID4gKw0KPiA+
ICtzdGF0aWMganNvbl9vYmplY3QgKmZpbmRfbm9kZV9ieV9wcmltYXJ5KGpzb25fb2JqZWN0ICpq
bWFpbiwgdWludDE2X3QNCj4gcHJpbWFyeSkNCj4gPiArew0KPiA+ICsgICAgICAganNvbl9vYmpl
Y3QgKmphcnJheTsNCj4gPiArICAgICAgIGludCBpLCBsZW47DQo+ID4gKw0KPiA+ICsgICAgICAg
anNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqbWFpbiwgIm5vZGVzIiwgJmphcnJheSk7DQo+ID4g
Kw0KPiA+ICsgICAgICAgaWYgKCFqYXJyYXkpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBO
VUxMOw0KPiA+ICsgICAgICAgbGVuID0ganNvbl9vYmplY3RfYXJyYXlfbGVuZ3RoKGphcnJheSk7
DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgKytpKSB7DQo+ID4gKyAg
ICAgICAgICAgICAgIGpzb25fb2JqZWN0ICpqbm9kZTsNCj4gPiArICAgICAgICAgICAgICAganNv
bl9vYmplY3QgKmpjb25maWc7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0ICpqZWxl
bWVudHM7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0ICpqZWxlbWVudDsNCj4gPiAr
ICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmp2YWx1ZTsNCj4gPiArICAgICAgICAgICAgICAg
Y2hhciAqc3RyOw0KPiA+ICsgICAgICAgICAgICAgICB1aW50MTZfdCBhZGRyOw0KPiA+ICsNCj4g
PiArICAgICAgICAgICAgICAgam5vZGUgPSBqc29uX29iamVjdF9hcnJheV9nZXRfaWR4KGphcnJh
eSwgaSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlmICgham5vZGUpDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBqc29u
X29iamVjdF9vYmplY3RfZ2V0X2V4KGpub2RlLCAiY29uZmlndXJhdGlvbiIsICZqY29uZmlnKTsN
Cj4gPiArICAgICAgICAgICAgICAgaWYgKCFqY29uZmlnKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiBOVUxMOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmpl
Y3Rfb2JqZWN0X2dldF9leChqY29uZmlnLCAiZWxlbWVudHMiLCAmamVsZW1lbnRzKTsNCj4gPiAr
ICAgICAgICAgICAgICAgaWYgKCFqZWxlbWVudHMpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgcmV0dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBqZWxlbWVudCA9IGpz
b25fb2JqZWN0X2FycmF5X2dldF9pZHgoamVsZW1lbnRzLCAwKTsNCj4gPiArICAgICAgICAgICAg
ICAgaWYgKCFqZWxlbWVudCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gTlVM
TDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgo
amVsZW1lbnQsICJ1bmljYXN0QWRkcmVzcyIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICZqdmFsdWUpOw0KPiA+ICsg
ICAgICAgICAgICAgICBzdHIgPSAoY2hhciAqKWpzb25fb2JqZWN0X2dldF9zdHJpbmcoanZhbHVl
KTsNCj4gPiArICAgICAgICAgICAgICAgaWYgKHNzY2FuZihzdHIsICIlMDRoeCIsICZhZGRyKSAh
PSAxKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIE5VTEw7DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoYWRkciA9PSBwcmltYXJ5KQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIHJldHVybiBqbm9kZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+
ID4gKyAgICAgICByZXR1cm4gTlVMTDsNCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQg
cHJvdl9kYl9wcmludF9ub2RlX2NvbXBvc2l0aW9uKHN0cnVjdCBtZXNoX25vZGUgKm5vZGUpDQo+
ID4gK3sNCj4gPiArICAgICAgIGNoYXIgKmluX3N0cjsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIg
KmNvbXBfc3RyOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmptYWluOw0KPiA+ICsgICAgICAg
anNvbl9vYmplY3QgKmpub2RlOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmpjb21wOw0KPiA+
ICsgICAgICAgdWludDE2X3QgcHJpbWFyeSA9IG5vZGVfZ2V0X3ByaW1hcnkobm9kZSk7DQo+ID4g
KyAgICAgICBjb25zdCBjaGFyICpmaWxlbmFtZTsNCj4gPiArICAgICAgIGJvb2wgcmVzID0gZmFs
c2U7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFub2RlIHx8ICFub2RlX2dldF9jb21wb3NpdGlv
bihub2RlKSkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmIChub2RlID09IG5vZGVfZ2V0X2xvY2FsX25vZGUoKSkNCj4gPiArICAgICAgICAgICAgICAg
ZmlsZW5hbWUgPSBsb2NhbF9maWxlbmFtZTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAg
ICAgICAgICAgZmlsZW5hbWUgPSBwcm92X2ZpbGVuYW1lOw0KPiA+ICsNCj4gPiArICAgICAgIGlu
X3N0ciA9IHByb3ZfZmlsZV9yZWFkKGZpbGVuYW1lKTsNCj4gPiArICAgICAgIGlmICghaW5fc3Ry
KQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgam1haW4g
PSBqc29uX3Rva2VuZXJfcGFyc2UoaW5fc3RyKTsNCj4gPiArICAgICAgIGlmICgham1haW4pDQo+
ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBqbm9kZSA9
IGZpbmRfbm9kZV9ieV9wcmltYXJ5KGptYWluLCBwcmltYXJ5KTsNCj4gPiArICAgICAgIGlmICgh
am5vZGUpDQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAg
ICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGpub2RlLCAiY29tcG9zaXRpb24iLCAmamNvbXAp
Ow0KPiA+ICsgICAgICAgaWYgKCFqY29tcCkNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25l
Ow0KPiA+ICsNCj4gPiArICAgICAgIGNvbXBfc3RyID0ganNvbl9vYmplY3RfdG9fanNvbl9zdHJp
bmdfZXh0KGpjb21wLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIEpTT05fQ19UT19TVFJJTkdfUFJFVFRZKTsNCj4gPiArDQo+ID4gKyAgICAgICBy
ZXMgPSB0cnVlOw0KPiA+ICsNCj4gPiArZG9uZToNCj4gPiArICAgICAgIGlmIChyZXMpDQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiXHRDb21wb3NpdGlvbiBkYXRhIGZvciBub2RlICU0
LjR4ICVzXG4iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgcHJpbWFyeSwgY29tcF9zdHIpOw0KPiA+ICsgICAgICAgZWxzZQ0KPiA+
ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlx0Q29tcG9zaXRpb24gZGF0YSBmb3Igbm9kZSAl
NC40eCBub3QgcHJlc2VudFxuIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbWFyeSk7DQo+ID4gKyAgICAgICBn
X2ZyZWUoaW5fc3RyKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoam1haW4pDQo+ID4gKyAgICAg
ICAgICAgICAgIGpzb25fb2JqZWN0X3B1dChqbWFpbik7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jv
b2wgcHJvdl9kYl9hZGRfbm9kZV9jb21wb3NpdGlvbihzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCB1
aW50OF90DQo+ICpkYXRhLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50MTZfdCBsZW4pDQo+ID4gK3sNCj4gPiAr
ICAgICAgIGNoYXIgKmluX3N0cjsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqbWFpbjsNCj4g
PiArICAgICAgIGpzb25fb2JqZWN0ICpqbm9kZTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpq
Y29tcDsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqYm9vbDsNCj4gPiArICAgICAgIGpzb25f
b2JqZWN0ICpqZmVhdHVyZXM7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqamVsZW1lbnRzOw0K
PiA+ICsgICAgICAgc3RydWN0IG1lc2hfbm9kZV9jb21wb3NpdGlvbiAqY29tcDsNCj4gPiArICAg
ICAgIHVpbnQ4X3QgbnVtX2VsZTsNCj4gPiArICAgICAgIGludCBpOw0KPiA+ICsgICAgICAgdWlu
dDE2X3QgcHJpbWFyeSA9IG5vZGVfZ2V0X3ByaW1hcnkobm9kZSk7DQo+ID4gKyAgICAgICBib29s
IHJlcyA9IE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgY29tcCA9IG5vZGVfZ2V0X2NvbXBvc2l0
aW9uKG5vZGUpOw0KPiA+ICsgICAgICAgaWYgKCFjb21wKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgaW5fc3RyID0gcHJvdl9maWxlX3JlYWQo
cHJvdl9maWxlbmFtZSk7DQo+ID4gKyAgICAgICBpZiAoIWluX3N0cikNCj4gPiArICAgICAgICAg
ICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGptYWluID0ganNvbl90b2tl
bmVyX3BhcnNlKGluX3N0cik7DQo+ID4gKyAgICAgICBpZiAoIWptYWluKQ0KPiA+ICsgICAgICAg
ICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgam5vZGUgPSBmaW5kX25vZGVf
YnlfcHJpbWFyeShqbWFpbiwgcHJpbWFyeSk7DQo+ID4gKyAgICAgICBpZiAoIWpub2RlKQ0KPiA+
ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgamNvbXAgPSBq
c29uX29iamVjdF9uZXdfb2JqZWN0KCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcHV0X3VpbnQxNihq
Y29tcCwgImNpZCIsIGNvbXAtPmNpZCk7DQo+ID4gKyAgICAgICBwdXRfdWludDE2KGpjb21wLCAi
cGlkIiwgY29tcC0+cGlkKTsNCj4gPiArICAgICAgIHB1dF91aW50MTYoamNvbXAsICJ2aWQiLCBj
b21wLT5waWQpOw0KPiA+ICsgICAgICAgcHV0X3VpbnQxNihqY29tcCwgImNycGwiLCBjb21wLT5j
cnBsKTsNCj4gPiArDQo+ID4gKyAgICAgICBqZmVhdHVyZXMgPSBqc29uX29iamVjdF9uZXdfb2Jq
ZWN0KCk7DQo+ID4gKyAgICAgICBqYm9vbCA9IGpzb25fb2JqZWN0X25ld19ib29sZWFuKGNvbXAt
PnJlbGF5KTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9hZGQoamZlYXR1cmVzLCAi
cmVsYXkiLCBqYm9vbCk7DQo+ID4gKyAgICAgICBqYm9vbCA9IGpzb25fb2JqZWN0X25ld19ib29s
ZWFuKGNvbXAtPnByb3h5KTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9hZGQoamZl
YXR1cmVzLCAicHJveHkiLCBqYm9vbCk7DQo+ID4gKyAgICAgICBqYm9vbCA9IGpzb25fb2JqZWN0
X25ld19ib29sZWFuKGNvbXAtPmZyaWVuZCk7DQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmpl
Y3RfYWRkKGpmZWF0dXJlcywgImZyaWVuZCIsIGpib29sKTsNCj4gPiArICAgICAgIGpib29sID0g
anNvbl9vYmplY3RfbmV3X2Jvb2xlYW4oY29tcC0+bHBuKTsNCj4gPiArICAgICAgIGpzb25fb2Jq
ZWN0X29iamVjdF9hZGQoamZlYXR1cmVzLCAibHBuIiwgamJvb2wpOw0KPiA+ICsgICAgICAganNv
bl9vYmplY3Rfb2JqZWN0X2FkZChqY29tcCwgImZlYXR1cmVzIiwgamZlYXR1cmVzKTsNCj4gPiAr
DQo+ID4gKyAgICAgICBkYXRhICs9IDExOw0KPiA+ICsgICAgICAgbGVuIC09IDExOw0KPiA+ICsN
Cj4gPiArICAgICAgIG51bV9lbGUgPSAgbm9kZV9nZXRfbnVtX2VsZW1lbnRzKG5vZGUpOw0KPiA+
ICsNCj4gPiArICAgICAgIGplbGVtZW50cyA9IGpzb25fb2JqZWN0X25ld19hcnJheSgpOw0KPiA+
ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBudW1fZWxlOyArK2kpIHsNCj4gPiArICAg
ICAgICAgICAgICAganNvbl9vYmplY3QgKmplbGVtZW50Ow0KPiA+ICsgICAgICAgICAgICAgICBq
c29uX29iamVjdCAqam1vZGVsczsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmpp
bnQ7DQo+ID4gKyAgICAgICAgICAgICAgIHVpbnQzMl90IG1vZF9pZDsNCj4gPiArICAgICAgICAg
ICAgICAgdWludDE2X3QgdmVuZG9yX2lkOw0KPiA+ICsgICAgICAgICAgICAgICB1aW50OF90IG0s
IHY7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBqZWxlbWVudCA9IGpzb25fb2JqZWN0X25l
d19vYmplY3QoKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIEVsZW1lbnQgSW5kZXgg
Ki8NCj4gPiArICAgICAgICAgICAgICAgamludCA9IGpzb25fb2JqZWN0X25ld19pbnQoaSk7DQo+
ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9hZGQoamVsZW1lbnQsICJlbGVt
ZW50SW5kZXgiLCBqaW50KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIC8qIExvY2F0aW9u
ICovDQo+ID4gKyAgICAgICAgICAgICAgIHB1dF91aW50MTYoamVsZW1lbnQsICJsb2NhdGlvbiIs
IGdldF9sZTE2KGRhdGEpKTsNCj4gPiArICAgICAgICAgICAgICAgZGF0YSArPSAyOw0KPiA+ICsg
ICAgICAgICAgICAgICBtID0gKmRhdGErKzsNCj4gPiArICAgICAgICAgICAgICAgdiA9ICpkYXRh
Kys7DQo+ID4gKyAgICAgICAgICAgICAgIGxlbiAtPSA0Ow0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgLyogTW9kZWxzICovDQo+ID4gKyAgICAgICAgICAgICAgIGptb2RlbHMgPSBqc29uX29i
amVjdF9uZXdfYXJyYXkoKTsNCj4gPiArICAgICAgICAgICAgICAgd2hpbGUgKGxlbiA+PSAyICYm
IG0tLSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1vZF9pZCA9IGdldF9sZTE2KGRh
dGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgKz0gMjsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICBsZW4gLT0gMjsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBw
dXRfdWludDE2X2FycmF5X2VudHJ5KGptb2RlbHMsICh1aW50MTZfdCkgbW9kX2lkKTsNCj4gPiAr
ICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgd2hpbGUgKGxlbiA+
PSA0ICYmIHYtLSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1vZF9pZCA9IGdldF9s
ZTE2KGRhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHZlbmRvcl9pZCA9IGdldF9s
ZTE2KGRhdGEpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1vZF9pZCB8PSAodmVuZG9y
X2lkIDw8IDE2KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBkYXRhICs9IDQ7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgbGVuIC09IDQ7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgcHV0X3VpbnQzMl9hcnJheV9lbnRyeShqbW9kZWxzLCBtb2RfaWQpOw0KPiA+ICsgICAg
ICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVjdF9vYmpl
Y3RfYWRkKGplbGVtZW50LCAibW9kZWxzIiwgam1vZGVscyk7DQo+ID4gKyAgICAgICAgICAgICAg
IGpzb25fb2JqZWN0X2FycmF5X2FkZChqZWxlbWVudHMsIGplbGVtZW50KTsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfYWRkKGpjb21wLCAiZWxl
bWVudHMiLCBqZWxlbWVudHMpOw0KPiA+ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVj
dF9hZGQoam5vZGUsICJjb21wb3NpdGlvbiIsIGpjb21wKTsNCj4gPiArDQo+ID4gKyAgICAgICBw
cm92X2ZpbGVfd3JpdGUoam1haW4sIGZhbHNlKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXMgPSB0
cnVlOzsNCj4gPiArZG9uZToNCj4gPiArDQo+ID4gKyAgICAgICBnX2ZyZWUoaW5fc3RyKTsNCj4g
PiArDQo+ID4gKyAgICAgICBpZihqbWFpbikNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmpl
Y3RfcHV0KGptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gcmVzOw0KPiA+ICt9DQo+
ID4gKw0KPiA+ICtib29sIHByb3ZfZGJfbm9kZV9zZXRfdHRsKHN0cnVjdCBtZXNoX25vZGUgKm5v
ZGUsIHVpbnQ4X3QgdHRsKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjaGFyICppbl9zdHI7DQo+ID4g
KyAgICAgICBqc29uX29iamVjdCAqam1haW47DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqam5v
ZGU7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqamNvbmZpZzsNCj4gPiArICAgICAgIGpzb25f
b2JqZWN0ICpqdmFsdWU7DQo+ID4gKyAgICAgICB1aW50MTZfdCBwcmltYXJ5ID0gbm9kZV9nZXRf
cHJpbWFyeShub2RlKTsNCj4gPiArICAgICAgIGNvbnN0IGNoYXIgKmZpbGVuYW1lOw0KPiA+ICsg
ICAgICAgYm9vbCBsb2NhbCA9IG5vZGUgPT0gbm9kZV9nZXRfbG9jYWxfbm9kZSgpOw0KPiA+ICsg
ICAgICAgYm9vbCByZXMgPSBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAobG9jYWwpDQo+
ID4gKyAgICAgICAgICAgICAgIGZpbGVuYW1lID0gbG9jYWxfZmlsZW5hbWU7DQo+ID4gKyAgICAg
ICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgIGZpbGVuYW1lID0gcHJvdl9maWxlbmFtZTsNCj4g
PiArDQo+ID4gKyAgICAgICBpbl9zdHIgPSBwcm92X2ZpbGVfcmVhZChmaWxlbmFtZSk7DQo+ID4g
KyAgICAgICBpZiAoIWluX3N0cikNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0K
PiA+ICsNCj4gPiArICAgICAgIGptYWluID0ganNvbl90b2tlbmVyX3BhcnNlKGluX3N0cik7DQo+
ID4gKyAgICAgICBpZiAoIWptYWluKQ0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKGxvY2FsKQ0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29i
amVjdF9vYmplY3RfZ2V0X2V4KGptYWluLCAibm9kZSIsICZqbm9kZSk7DQo+ID4gKyAgICAgICBl
bHNlDQo+ID4gKyAgICAgICAgICAgICAgIGpub2RlID0gZmluZF9ub2RlX2J5X3ByaW1hcnkoam1h
aW4sIHByaW1hcnkpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICgham5vZGUpDQo+ID4gKyAgICAg
ICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmpl
Y3RfZ2V0X2V4KGpub2RlLCAiY29uZmlndXJhdGlvbiIsICZqY29uZmlnKTsNCj4gPiArICAgICAg
IGlmICghamNvbmZpZykNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsNCj4g
PiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9kZWwoamNvbmZpZywgImRlZmF1bHRUVEwiKTsN
Cj4gPiArDQo+ID4gKyAgICAgICBqdmFsdWUgPSBqc29uX29iamVjdF9uZXdfaW50KHR0bCk7DQo+
ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfYWRkKGpjb25maWcsICJkZWZhdWx0VFRMIiwg
anZhbHVlKTsNCj4gPiArDQo+ID4gKyAgICAgICBwcm92X2ZpbGVfd3JpdGUoam1haW4sIGxvY2Fs
KTsNCj4gPiArDQo+ID4gKyAgICAgICByZXMgPSB0cnVlOw0KPiA+ICtkb25lOg0KPiA+ICsNCj4g
PiArICAgICAgIGdfZnJlZShpbl9zdHIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmKGptYWluKQ0K
PiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVjdF9wdXQoam1haW4pOw0KPiA+ICsNCj4gPiAr
ICAgICAgIHJldHVybiByZXM7DQo+ID4gKw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9p
ZCBzZXRfbG9jYWxfaXZfaW5kZXgoanNvbl9vYmplY3QgKmpvYmosIHVpbnQzMl90IGlkeCwgYm9v
bA0KPiB1cGRhdGUpDQo+ID4gK3sNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqdmFsdWU7DQo+
ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2RlbChqb2JqLCAiSVZpbmRleCIp
Ow0KPiA+ICsgICAgICAganZhbHVlID0ganNvbl9vYmplY3RfbmV3X2ludChpZHgpOw0KPiA+ICsg
ICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2FkZChqb2JqLCAiSVZpbmRleCIsIGp2YWx1ZSk7DQo+
ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2RlbChqb2JqLCAiSVZ1cGRhdGUi
KTsNCj4gPiArICAgICAgIGp2YWx1ZSA9IGpzb25fb2JqZWN0X25ld19pbnQoKHVwZGF0ZSkgPyAx
IDogMCk7DQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfYWRkKGpvYmosICJJVnVwZGF0
ZSIsIGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIHByb3ZfZGJfbG9j
YWxfc2V0X2l2X2luZGV4KHVpbnQzMl90IGl2X2luZGV4LCBib29sIHVwZGF0ZSwgYm9vbA0KPiBw
cm92KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjaGFyICppbl9zdHI7DQo+ID4gKyAgICAgICBqc29u
X29iamVjdCAqam1haW47DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqam5vZGU7DQo+ID4gKyAg
ICAgICBib29sIHJlcyA9IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGluX3N0ciA9IHByb3Zf
ZmlsZV9yZWFkKGxvY2FsX2ZpbGVuYW1lKTsNCj4gPiArICAgICAgIGlmICghaW5fc3RyKQ0KPiA+
ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgam1haW4g
PSBqc29uX3Rva2VuZXJfcGFyc2UoaW5fc3RyKTsNCj4gPiArICAgICAgIGlmICgham1haW4pDQo+
ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29i
amVjdF9vYmplY3RfZ2V0X2V4KGptYWluLCAibm9kZSIsICZqbm9kZSk7DQo+ID4gKyAgICAgICBz
ZXRfbG9jYWxfaXZfaW5kZXgoam5vZGUsIGl2X2luZGV4LCB1cGRhdGUpOw0KPiA+ICsgICAgICAg
cHJvdl9maWxlX3dyaXRlKGptYWluLCB0cnVlKTsNCj4gPiArDQo+ID4gKyAgICAgICBnX2ZyZWUo
aW5fc3RyKTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X3B1dChqbWFpbik7DQo+ID4gKw0KPiA+
ICsgICAgICAgLyogSWYgcHJvdmlzaW9uZXIsIHNhdmUgdG8gZ2xvYmFsIERCIGFzIHdlbGwgKi8N
Cj4gPiArICAgICAgIGlmIChwcm92KSB7DQo+ID4gKyAgICAgICAgICAgICAgIGluX3N0ciA9IHBy
b3ZfZmlsZV9yZWFkKHByb3ZfZmlsZW5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIWlu
X3N0cikNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0K
PiA+ICsgICAgICAgICAgICAgICBqbWFpbiA9IGpzb25fdG9rZW5lcl9wYXJzZShpbl9zdHIpOw0K
PiA+ICsgICAgICAgICAgICAgICBpZiAoIWptYWluKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIHNldF9sb2NhbF9pdl9p
bmRleChqbWFpbiwgaXZfaW5kZXgsIHVwZGF0ZSk7DQo+ID4gKyAgICAgICAgICAgICAgIHByb3Zf
ZmlsZV93cml0ZShqbWFpbiwgZmFsc2UpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAg
ICAgIHJlcyA9IHRydWU7DQo+ID4gK2RvbmU6DQo+ID4gKw0KPiA+ICsgICAgICAgZ19mcmVlKGlu
X3N0cik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYoam1haW4pDQo+ID4gKyAgICAgICAgICAgICAg
IGpzb25fb2JqZWN0X3B1dChqbWFpbik7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHJlczsN
Cj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgcHJvdl9kYl9sb2NhbF9zZXRfc2VxX251
bSh1aW50MzJfdCBzZXFfbnVtKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjaGFyICppbl9zdHI7DQo+
ID4gKyAgICAgICBqc29uX29iamVjdCAqam1haW47DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAq
am5vZGU7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqanZhbHVlOw0KPiA+ICsgICAgICAgYm9v
bCByZXMgPSBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpbl9zdHIgPSBwcm92X2ZpbGVfcmVh
ZChsb2NhbF9maWxlbmFtZSk7DQo+ID4gKyAgICAgICBpZiAoIWluX3N0cikNCj4gPiArICAgICAg
ICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGptYWluID0ganNvbl90
b2tlbmVyX3BhcnNlKGluX3N0cik7DQo+ID4gKyAgICAgICBpZiAoIWptYWluKQ0KPiA+ICsgICAg
ICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2Jq
ZWN0X2dldF9leChqbWFpbiwgIm5vZGUiLCAmam5vZGUpOw0KPiA+ICsNCj4gPiArICAgICAgIGpz
b25fb2JqZWN0X29iamVjdF9kZWwoam5vZGUsICJzZXF1ZW5jZU51bWJlciIpOw0KPiA+ICsgICAg
ICAganZhbHVlID0ganNvbl9vYmplY3RfbmV3X2ludChzZXFfbnVtKTsNCj4gPiArICAgICAgIGpz
b25fb2JqZWN0X29iamVjdF9hZGQoam5vZGUsICJzZXF1ZW5jZU51bWJlciIsIGp2YWx1ZSk7DQo+
ID4gKw0KPiA+ICsgICAgICAgcHJvdl9maWxlX3dyaXRlKGptYWluLCB0cnVlKTsNCj4gPiArDQo+
ID4gKyAgICAgICByZXMgPSB0cnVlOw0KPiA+ICtkb25lOg0KPiA+ICsNCj4gPiArICAgICAgIGdf
ZnJlZShpbl9zdHIpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmKGptYWluKQ0KPiA+ICsgICAgICAg
ICAgICAgICBqc29uX29iamVjdF9wdXQoam1haW4pOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVy
biByZXM7DQo+ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgcHJvdl9kYl9ub2RlX3NldF9pdl9zZXEo
c3RydWN0IG1lc2hfbm9kZSAqbm9kZSwgdWludDMyX3QgaXYsDQo+IHVpbnQzMl90IHNlcSkNCj4g
PiArew0KPiA+ICsgICAgICAgY2hhciAqaW5fc3RyOw0KPiA+ICsgICAgICAganNvbl9vYmplY3Qg
KmptYWluOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmpub2RlOw0KPiA+ICsgICAgICAganNv
bl9vYmplY3QgKmp2YWx1ZTsNCj4gPiArICAgICAgIHVpbnQxNl90IHByaW1hcnkgPSBub2RlX2dl
dF9wcmltYXJ5KG5vZGUpOw0KPiA+ICsgICAgICAgYm9vbCByZXMgPSBmYWxzZTsNCj4gPiArDQo+
ID4gKyAgICAgICBpbl9zdHIgPSBwcm92X2ZpbGVfcmVhZChwcm92X2ZpbGVuYW1lKTsNCj4gPiAr
ICAgICAgIGlmICghaW5fc3RyKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+
ID4gKw0KPiA+ICsgICAgICAgam1haW4gPSBqc29uX3Rva2VuZXJfcGFyc2UoaW5fc3RyKTsNCj4g
PiArICAgICAgIGlmICgham1haW4pDQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4g
PiArDQo+ID4gKyAgICAgICBqbm9kZSA9IGZpbmRfbm9kZV9ieV9wcmltYXJ5KGptYWluLCBwcmlt
YXJ5KTsNCj4gPiArICAgICAgIGlmICgham5vZGUpDQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8g
ZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfZGVsKGpub2RlLCAi
SVZpbmRleCIpOw0KPiA+ICsNCj4gPiArICAgICAgIGp2YWx1ZSA9IGpzb25fb2JqZWN0X25ld19p
bnQoaXYpOw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2FkZChqbm9kZSwgIklWaW5k
ZXgiLCBqdmFsdWUpOw0KPiA+ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9kZWwo
am5vZGUsICJzZXF1ZW5jZU51bWJlciIpOw0KPiA+ICsNCj4gPiArICAgICAgIGp2YWx1ZSA9IGpz
b25fb2JqZWN0X25ld19pbnQoc2VxKTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9h
ZGQoam5vZGUsICJzZXF1ZW5jZU51bWJlciIsIGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
cHJvdl9maWxlX3dyaXRlKGptYWluLCBmYWxzZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmVzID0g
dHJ1ZTsNCj4gPiArZG9uZToNCj4gPiArDQo+ID4gKyAgICAgICBnX2ZyZWUoaW5fc3RyKTsNCj4g
PiArDQo+ID4gKyAgICAgICBpZihqbWFpbikNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmpl
Y3RfcHV0KGptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gcmVzOw0KPiA+ICsNCj4g
PiArfQ0KPiA+ICsNCj4gPiArYm9vbCBwcm92X2RiX25vZGVfa2V5cyhzdHJ1Y3QgbWVzaF9ub2Rl
ICpub2RlLCBHTGlzdCAqaWR4cywgY29uc3QNCj4gY2hhciAqZGVzYykNCj4gPiArew0KPiA+ICsg
ICAgICAgY2hhciAqaW5fc3RyOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmptYWluOw0KPiA+
ICsgICAgICAganNvbl9vYmplY3QgKmpub2RlOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmpj
b25maWc7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqamlkeHM7DQo+ID4gKyAgICAgICB1aW50
MTZfdCBwcmltYXJ5ID0gbm9kZV9nZXRfcHJpbWFyeShub2RlKTsNCj4gPiArICAgICAgIGNvbnN0
IGNoYXIgKmZpbGVuYW1lOw0KPiA+ICsgICAgICAgYm9vbCBsb2NhbCA9IChub2RlID09IG5vZGVf
Z2V0X2xvY2FsX25vZGUoKSk7DQo+ID4gKyAgICAgICBib29sIHJlcyA9IGZhbHNlOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChsb2NhbCkNCj4gPiArICAgICAgICAgICAgICAgZmlsZW5hbWUgPSBs
b2NhbF9maWxlbmFtZTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgZmls
ZW5hbWUgPSBwcm92X2ZpbGVuYW1lOw0KPiA+ICsNCj4gPiArICAgICAgIGluX3N0ciA9IHByb3Zf
ZmlsZV9yZWFkKGZpbGVuYW1lKTsNCj4gPiArICAgICAgIGlmICghaW5fc3RyKQ0KPiA+ICsgICAg
ICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgam1haW4gPSBqc29u
X3Rva2VuZXJfcGFyc2UoaW5fc3RyKTsNCj4gPiArICAgICAgIGlmICgham1haW4pDQo+ID4gKyAg
ICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBqbm9kZSA9IGZpbmRf
bm9kZV9ieV9wcmltYXJ5KGptYWluLCBwcmltYXJ5KTsNCj4gPiArICAgICAgIGlmICgham5vZGUp
DQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBqc29u
X29iamVjdF9vYmplY3RfZ2V0X2V4KGpub2RlLCAiY29uZmlndXJhdGlvbiIsICZqY29uZmlnKTsN
Cj4gPiArICAgICAgIGlmICghamNvbmZpZykNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25l
Ow0KPiA+ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9kZWwoamNvbmZpZywgZGVz
Yyk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGlkeHMpIHsNCj4gPiArICAgICAgICAgICAgICAg
amlkeHMgPSBqc29uX29iamVjdF9uZXdfYXJyYXkoKTsNCj4gPiArICAgICAgICAgICAgICAgcHV0
X3VpbnQxNl9saXN0KGppZHhzLCBpZHhzKTsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmpl
Y3Rfb2JqZWN0X2FkZChqY29uZmlnLCBkZXNjLCBqaWR4cyk7DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAgcHJvdl9maWxlX3dyaXRlKGptYWluLCBsb2NhbCk7DQo+ID4gKw0KPiA+
ICsgICAgICAgcmVzID0gdHJ1ZTsNCj4gPiArZG9uZToNCj4gPiArDQo+ID4gKyAgICAgICBnX2Zy
ZWUoaW5fc3RyKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZihqbWFpbikNCj4gPiArICAgICAgICAg
ICAgICAganNvbl9vYmplY3RfcHV0KGptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4g
cmVzOw0KPiA+ICsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGpzb25fb2JqZWN0ICpnZXRf
am1vZGVsX29iaihzdHJ1Y3QgbWVzaF9ub2RlICpub2RlLCB1aW50OF90DQo+IGVsZV9pZHgsDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVpbnQzMl90IG1vZGVs
X2lkLCBqc29uX29iamVjdCAqKmptYWluKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjaGFyICppbl9z
dHI7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqam5vZGU7DQo+ID4gKyAgICAgICBqc29uX29i
amVjdCAqamNvbmZpZzsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqZWxlbWVudHMsICpqZWxl
bWVudDsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqbW9kZWxzLCAqam1vZGVsID0gTlVMTDsN
Cj4gPiArICAgICAgIHVpbnQxNl90IHByaW1hcnkgPSBub2RlX2dldF9wcmltYXJ5KG5vZGUpOw0K
PiA+ICsgICAgICAgY29uc3QgY2hhciAqZmlsZW5hbWU7DQo+ID4gKyAgICAgICBib29sIGxvY2Fs
ID0gKG5vZGUgPT0gbm9kZV9nZXRfbG9jYWxfbm9kZSgpKTsNCj4gPiArDQo+ID4gKyAgICAgICBp
ZiAobG9jYWwpDQo+ID4gKyAgICAgICAgICAgICAgIGZpbGVuYW1lID0gbG9jYWxfZmlsZW5hbWU7
DQo+ID4gKyAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgIGZpbGVuYW1lID0gcHJvdl9m
aWxlbmFtZTsNCj4gPiArDQo+ID4gKyAgICAgICBpbl9zdHIgPSBwcm92X2ZpbGVfcmVhZChmaWxl
bmFtZSk7DQo+ID4gKyAgICAgICBpZiAoIWluX3N0cikNCj4gPiArICAgICAgICAgICAgICAgcmV0
dXJuIE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAgKmptYWluID0ganNvbl90b2tlbmVyX3BhcnNl
KGluX3N0cik7DQo+ID4gKyAgICAgICBpZiAoISgqam1haW4pKQ0KPiA+ICsgICAgICAgICAgICAg
ICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGxvY2FsKQ0KPiA+ICsgICAgICAg
ICAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KCpqbWFpbiwgIm5vZGUiLCAmam5vZGUp
Ow0KPiA+ICsgICAgICAgZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICBqbm9kZSA9IGZpbmRfbm9k
ZV9ieV9wcmltYXJ5KCpqbWFpbiwgcHJpbWFyeSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFq
bm9kZSkNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsNCj4gPiArICAgICAg
IC8qIENvbmZpZ3VyYXRpb24gaXMgbWFuZGF0b3J5IGZvciBub2RlcyBpbiBwcm92aXNpb25pbmcg
ZGF0YWJhc2UgKi8NCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoam5vZGUs
ICJjb25maWd1cmF0aW9uIiwgJmpjb25maWcpOw0KPiA+ICsgICAgICAgaWYgKCFqY29uZmlnKQ0K
PiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9v
YmplY3Rfb2JqZWN0X2dldF9leChqY29uZmlnLCAiZWxlbWVudHMiLCAmamVsZW1lbnRzKTsNCj4g
PiArICAgICAgIGlmICghamVsZW1lbnRzKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9u
ZTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBqZWxlbWVudCA9IGpzb25fb2Jq
ZWN0X2FycmF5X2dldF9pZHgoamVsZW1lbnRzLCBlbGVfaWR4KTsNCj4gPiArICAgICAgIGlmICgh
amVsZW1lbnQpIHsNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAg
fQ0KPiA+ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoamVsZW1lbnQs
ICJtb2RlbHMiLCAmam1vZGVscyk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFqbW9kZWxzKSAg
ew0KPiA+ICsgICAgICAgICAgICAgICBqbW9kZWxzID0ganNvbl9vYmplY3RfbmV3X2FycmF5KCk7
DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9hZGQoamVsZW1lbnQsICJt
b2RlbHMiLCBqbW9kZWxzKTsNCj4gPiArICAgICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAg
ICAgIHBhcnNlX2NvbmZpZ3VyYXRpb25fbW9kZWxzKG5vZGUsIGVsZV9pZHgsIGptb2RlbHMsDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBtb2RlbF9pZCwgJmptb2RlbCk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKCFqbW9kZWwpIHsNCj4gPiArICAgICAgICAgICAgICAgam1vZGVsID0ganNvbl9vYmplY3Rf
bmV3X29iamVjdCgpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYgKChtb2RlbF9pZCAm
IDB4ZmZmZjAwMDApID09IDB4ZmZmZjAwMDApDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
cHV0X3VpbnQxNihqbW9kZWwsICJtb2RlbElkIiwgbW9kZWxfaWQgJiAweGZmZmYpOw0KPiA+ICsg
ICAgICAgICAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHV0X3VpbnQz
MihqbW9kZWwsICJtb2RlbElkIiwgbW9kZWxfaWQpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAganNvbl9vYmplY3RfYXJyYXlfYWRkKGptb2RlbHMsIGptb2RlbCk7DQo+ID4gKyAgICAgICB9
DQo+ID4gKw0KPiA+ICtkb25lOg0KPiA+ICsNCj4gPiArICAgICAgIGdfZnJlZShpbl9zdHIpOw0K
PiA+ICsNCj4gPiArICAgICAgIGlmKCFqbW9kZWwgJiYgKmptYWluKQ0KPiA+ICsgICAgICAgICAg
ICAgICBqc29uX29iamVjdF9wdXQoKmptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4g
am1vZGVsOw0KPiA+ICsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBwcm92X2RiX2FkZF9iaW5k
aW5nKHN0cnVjdCBtZXNoX25vZGUgKm5vZGUsIHVpbnQ4X3QgZWxlX2lkeCwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICB1aW50MzJfdCBtb2RlbF9pZCwgdWludDE2X3QgYXBwX2lkeCkNCj4g
PiArew0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmptYWluOw0KPiA+ICsgICAgICAganNvbl9v
YmplY3QgKmptb2RlbDsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqdmFsdWU7DQo+ID4gKyAg
ICAgICBqc29uX29iamVjdCAqamJpbmRpbmdzID0gTlVMTDsNCj4gPiArICAgICAgIGJvb2wgbG9j
YWwgPSAobm9kZSA9PSBub2RlX2dldF9sb2NhbF9ub2RlKCkpOw0KPiA+ICsNCj4gPiArICAgICAg
IGptb2RlbCA9IGdldF9qbW9kZWxfb2JqKG5vZGUsIGVsZV9pZHgsIG1vZGVsX2lkLCAmam1haW4p
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmICgham1vZGVsKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9l
eChqbW9kZWwsICJiaW5kIiwgJmpiaW5kaW5ncyk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFq
YmluZGluZ3MpIHsNCj4gPiArICAgICAgICAgICAgICAgamJpbmRpbmdzID0ganNvbl9vYmplY3Rf
bmV3X2FycmF5KCk7DQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9hZGQo
am1vZGVsLCAiYmluZCIsIGpiaW5kaW5ncyk7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsg
ICAgICAganZhbHVlID0ganNvbl9vYmplY3RfbmV3X2ludChhcHBfaWR4KTsNCj4gPiArICAgICAg
IGpzb25fb2JqZWN0X2FycmF5X2FkZChqYmluZGluZ3MsIGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgcHJvdl9maWxlX3dyaXRlKGptYWluLCBsb2NhbCk7DQo+ID4gKw0KPiA+ICsgICAgICAg
anNvbl9vYmplY3RfcHV0KGptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsN
Cj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBwcm92X2RiX25vZGVfc2V0X21vZGVsX3B1YihzdHJ1
Y3QgbWVzaF9ub2RlICpub2RlLCB1aW50OF90DQo+IGVsZV9pZHgsDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50MzJfdCBtb2Rl
bF9pZCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBzdHJ1Y3QgbWVzaF9wdWJsaWNhdGlvbiAqcHViKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBqc29u
X29iamVjdCAqam1haW47DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqam1vZGVsOw0KPiA+ICsg
ICAgICAganNvbl9vYmplY3QgKmpwdWI7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqanZhbHVl
Ow0KPiA+ICsgICAgICAgYm9vbCBsb2NhbCA9IChub2RlID09IG5vZGVfZ2V0X2xvY2FsX25vZGUo
KSk7DQo+ID4gKw0KPiA+ICsgICAgICAgam1vZGVsID0gZ2V0X2ptb2RlbF9vYmoobm9kZSwgZWxl
X2lkeCwgbW9kZWxfaWQsICZqbWFpbik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFqbW9kZWwp
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBq
c29uX29iamVjdF9vYmplY3RfZGVsKGptb2RlbCwgInB1Ymxpc2giKTsNCj4gPiArICAgICAgIGlm
ICghcHViKQ0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAg
ICAganB1YiA9IGpzb25fb2JqZWN0X25ld19vYmplY3QoKTsNCj4gPiArDQo+ID4gKyAgICAgICAv
KiBTYXZlIG9ubHkgcmVxdWlyZWQgZmllbGRzICovDQo+ID4gKyAgICAgICBwdXRfdWludDE2KGpw
dWIsICJhZGRyZXNzIiwgcHViLT51LmFkZHIxNik7DQo+ID4gKyAgICAgICBwdXRfdWludDE2KGpw
dWIsICJpbmRleCIsIHB1Yi0+YXBwX2lkeCk7DQo+ID4gKyAgICAgICBqdmFsdWUgPSBqc29uX29i
amVjdF9uZXdfaW50KHB1Yi0+dHRsKTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9h
ZGQoanB1YiwgInR0bCIsIGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rf
b2JqZWN0X2FkZChqbW9kZWwsICJwdWJsaXNoIiwganB1Yik7DQo+ID4gKw0KPiA+ICtkb25lOg0K
PiA+ICsgICAgICAgcHJvdl9maWxlX3dyaXRlKGptYWluLCBsb2NhbCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAganNvbl9vYmplY3RfcHV0KGptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4g
dHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBwcm92X2RiX2FkZF9uZXdfbm9kZShzdHJ1
Y3QgbWVzaF9ub2RlICpub2RlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjaGFyICppbl9zdHI7DQo+
ID4gKyAgICAgICBqc29uX29iamVjdCAqam1haW47DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAq
amFycmF5Ow0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmpub2RlOw0KPiA+ICsgICAgICAganNv
bl9vYmplY3QgKmpjb25maWc7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqamVsZW1lbnRzOw0K
PiA+ICsgICAgICAgdWludDhfdCBudW1fZWxlOw0KPiA+ICsgICAgICAgdWludDE2X3QgcHJpbWFy
eTsNCj4gPiArICAgICAgIGludCBpOw0KPiA+ICsgICAgICAgYm9vbCBmaXJzdF9ub2RlOw0KPiA+
ICsgICAgICAgYm9vbCByZXMgPSBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBpbl9zdHIgPSBw
cm92X2ZpbGVfcmVhZChwcm92X2ZpbGVuYW1lKTsNCj4gPiArICAgICAgIGlmICghaW5fc3RyKQ0K
PiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgam1h
aW4gPSBqc29uX3Rva2VuZXJfcGFyc2UoaW5fc3RyKTsNCj4gPiArICAgICAgIGlmICgham1haW4p
DQo+ID4gKyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0
X29iamVjdF9nZXRfZXgoam1haW4sICJub2RlcyIsICZqYXJyYXkpOw0KPiA+ICsNCj4gPiArICAg
ICAgIGlmICghamFycmF5KSB7DQo+ID4gKyAgICAgICAgICAgICAgIGphcnJheSA9IGpzb25fb2Jq
ZWN0X25ld19hcnJheSgpOw0KPiA+ICsgICAgICAgICAgICAgICBmaXJzdF9ub2RlID0gdHJ1ZTsN
Cj4gPiArICAgICAgIH0gZWxzZQ0KPiA+ICsgICAgICAgICAgICAgICBmaXJzdF9ub2RlID0gZmFs
c2U7DQo+ID4gKw0KPiA+ICsgICAgICAgam5vZGUgPSBqc29uX29iamVjdF9uZXdfb2JqZWN0KCk7
DQo+ID4gKw0KPiA+ICsgICAgICAgLyogRGV2aWNlIGtleSAqLw0KPiA+ICsgICAgICAgYWRkX2tl
eShqbm9kZSwgImRldmljZUtleSIsIG5vZGVfZ2V0X2RldmljZV9rZXkobm9kZSkpOw0KPiA+ICsN
Cj4gPiArICAgICAgIC8qIE5ldCBrZXkgKi8NCj4gPiArICAgICAgIGpjb25maWcgPSBqc29uX29i
amVjdF9uZXdfb2JqZWN0KCk7DQo+ID4gKyAgICAgICBhZGRfbm9kZV9pZHhzKGpjb25maWcsICJu
ZXRLZXlzIiwgbm9kZV9nZXRfbmV0X2tleXMobm9kZSkpOw0KPiA+ICsNCj4gPiArICAgICAgIG51
bV9lbGUgPSBub2RlX2dldF9udW1fZWxlbWVudHMobm9kZSk7DQo+ID4gKyAgICAgICBpZiAobnVt
X2VsZSA9PSAwKQ0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsg
ICAgICAgamVsZW1lbnRzID0ganNvbl9vYmplY3RfbmV3X2FycmF5KCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgcHJpbWFyeSA9IG5vZGVfZ2V0X3ByaW1hcnkobm9kZSk7DQo+ID4gKyAgICAgICBpZiAo
SVNfVU5BU1NJR05FRChwcmltYXJ5KSkNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0K
PiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBudW1fZWxlOyArK2kpIHsNCj4gPiAr
ICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmplbGVtZW50Ow0KPiA+ICsgICAgICAgICAgICAg
ICBqc29uX29iamVjdCAqamludDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGplbGVtZW50
ID0ganNvbl9vYmplY3RfbmV3X29iamVjdCgpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
LyogRWxlbWVudCBJbmRleCAqLw0KPiA+ICsgICAgICAgICAgICAgICBqaW50ID0ganNvbl9vYmpl
Y3RfbmV3X2ludChpKTsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2Fk
ZChqZWxlbWVudCwgImVsZW1lbnRJbmRleCIsIGppbnQpOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgLyogVW5pY2FzdCAqLw0KPiA+ICsgICAgICAgICAgICAgICBwdXRfdWludDE2KGplbGVt
ZW50LCAidW5pY2FzdEFkZHJlc3MiLCBwcmltYXJ5ICsgaSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICBqc29uX29iamVjdF9hcnJheV9hZGQoamVsZW1lbnRzLCBqZWxlbWVudCk7DQo+ID4g
KyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2FkZChqY29u
ZmlnLCAiZWxlbWVudHMiLCBqZWxlbWVudHMpOw0KPiA+ICsNCj4gPiArICAgICAgIGpzb25fb2Jq
ZWN0X29iamVjdF9hZGQoam5vZGUsICJjb25maWd1cmF0aW9uIiwgamNvbmZpZyk7DQo+ID4gKw0K
PiA+ICsgICAgICAganNvbl9vYmplY3RfYXJyYXlfYWRkKGphcnJheSwgam5vZGUpOw0KPiA+ICsN
Cj4gPiArICAgICAgIGlmIChmaXJzdF9ub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29i
amVjdF9vYmplY3RfYWRkKGptYWluLCAibm9kZXMiLCBqYXJyYXkpOw0KPiA+ICsNCj4gPiArICAg
ICAgIHByb3ZfZmlsZV93cml0ZShqbWFpbiwgZmFsc2UpOw0KPiA+ICsNCj4gPiArICAgICAgIHJl
cyA9IHRydWU7DQo+ID4gK2RvbmU6DQo+ID4gKw0KPiA+ICsgICAgICAgZ19mcmVlKGluX3N0cik7
DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKGptYWluKQ0KPiA+ICsgICAgICAgICAgICAgICBqc29u
X29iamVjdF9wdXQoam1haW4pOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiByZXM7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHBhcnNlX25vZGVfY29tcG9zaXRpb24oc3RydWN0
IG1lc2hfbm9kZSAqbm9kZSwNCj4ganNvbl9vYmplY3QgKmpjb21wKQ0KPiA+ICt7DQo+ID4gKyAg
ICAgICBqc29uX29iamVjdCAqanZhbHVlOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmplbGVt
ZW50czsNCj4gPiArICAgICAgIGpzb25fYm9vbCBlbmFibGU7DQo+ID4gKyAgICAgICBjaGFyICpz
dHI7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlX2NvbXBvc2l0aW9uIGNvbXA7DQo+ID4g
Kw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqY29tcCwgImNpZCIsICZq
dmFsdWUpOw0KPiA+ICsgICAgICAgaWYgKCFqdmFsdWUpDQo+ID4gKyAgICAgICAgICAgICAgIHJl
dHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBzdHIgPSAoY2hhciAqKWpzb25fb2JqZWN0
X2dldF9zdHJpbmcoanZhbHVlKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc3NjYW5mKHN0ciwg
IiUwNGh4IiwgJmNvbXAuY2lkKSAhPSAxKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFs
c2U7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqY29tcCwg
InBpZCIsICZqdmFsdWUpOw0KPiA+ICsgICAgICAgaWYgKCFqdmFsdWUpDQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBzdHIgPSAoY2hhciAqKWpz
b25fb2JqZWN0X2dldF9zdHJpbmcoanZhbHVlKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAoc3Nj
YW5mKHN0ciwgIiUwNGh4IiwgJmNvbXAudmlkKSAhPSAxKQ0KPiA+ICsgICAgICAgICAgICAgICBy
ZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9l
eChqY29tcCwgInZpZCIsICZqdmFsdWUpOw0KPiA+ICsgICAgICAgaWYgKCFqdmFsdWUpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBzdHIgPSAo
Y2hhciAqKWpzb25fb2JqZWN0X2dldF9zdHJpbmcoanZhbHVlKTsNCj4gPiArDQo+ID4gKyAgICAg
ICBpZiAoc3NjYW5mKHN0ciwgIiUwNGh4IiwgJmNvbXAudmlkKSAhPSAxKQ0KPiA+ICsgICAgICAg
ICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2Jq
ZWN0X2dldF9leChqY29tcCwgImNycGwiLCAmanZhbHVlKTsNCj4gPiArICAgICAgIGlmICghanZh
bHVlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAg
ICAgc3RyID0gKGNoYXIgKilqc29uX29iamVjdF9nZXRfc3RyaW5nKGp2YWx1ZSk7DQo+ID4gKw0K
PiA+ICsgICAgICAgaWYgKHNzY2FuZihzdHIsICIlMDRoeCIsICZjb21wLmNycGwpICE9IDEpDQo+
ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBF
eHRyYWN0IGZlYXR1cmVzICovDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4
KGpjb21wLCAicmVsYXkiLCAmanZhbHVlKTsNCj4gPiArICAgICAgIGVuYWJsZSA9IGpzb25fb2Jq
ZWN0X2dldF9ib29sZWFuKGp2YWx1ZSk7DQo+ID4gKyAgICAgICBjb21wLnJlbGF5ID0gKGVuYWJs
ZSkgPyB0cnVlIDogZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0
X2dldF9leChqY29tcCwgInByb3h5IiwgJmp2YWx1ZSk7DQo+ID4gKyAgICAgICBlbmFibGUgPSBq
c29uX29iamVjdF9nZXRfYm9vbGVhbihqdmFsdWUpOw0KPiA+ICsgICAgICAgY29tcC5wcm94eSA9
IChlbmFibGUpID8gdHJ1ZSA6IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0
X29iamVjdF9nZXRfZXgoamNvbXAsICJmcmllbmQiLCAmanZhbHVlKTsNCj4gPiArICAgICAgIGVu
YWJsZSA9IGpzb25fb2JqZWN0X2dldF9ib29sZWFuKGp2YWx1ZSk7DQo+ID4gKyAgICAgICBjb21w
LmZyaWVuZCA9IChlbmFibGUpID8gdHJ1ZSA6IGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGpz
b25fb2JqZWN0X29iamVjdF9nZXRfZXgoamNvbXAsICJsb3dQb3dlciIsICZqdmFsdWUpOw0KPiA+
ICsgICAgICAgZW5hYmxlID0ganNvbl9vYmplY3RfZ2V0X2Jvb2xlYW4oanZhbHVlKTsNCj4gPiAr
ICAgICAgIGNvbXAubHBuID0gKGVuYWJsZSkgPyB0cnVlIDogZmFsc2U7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKCFub2RlX3NldF9jb21wb3NpdGlvbihub2RlLCAmY29tcCkpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9v
YmplY3RfZ2V0X2V4KGpjb21wLCAiZWxlbWVudHMiLCAmamVsZW1lbnRzKTsNCj4gPiArICAgICAg
IGlmICghamVsZW1lbnRzKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4g
Kw0KPiA+ICsgICAgICAgcmV0dXJuIHBhcnNlX2NvbXBvc2l0aW9uX2VsZW1lbnRzKG5vZGUsIGpl
bGVtZW50cyk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIHBhcnNlX25vZGUoanNv
bl9vYmplY3QgKmpub2RlLCBib29sIGxvY2FsKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBqc29uX29i
amVjdCAqamNvbmZpZzsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqZWxlbWVudHM7DQo+ID4g
KyAgICAgICBqc29uX29iamVjdCAqamlkeHM7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqanZh
bHVlOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmppbnQ7DQo+ID4gKyAgICAgICB1aW50OF90
IGtleVsxNl07DQo+ID4gKyAgICAgICBjaGFyICp2YWx1ZV9zdHI7DQo+ID4gKyAgICAgICB1aW50
MzJfdCBpZHg7DQo+ID4gKyAgICAgICBzdHJ1Y3QgbWVzaF9ub2RlICpub2RlOw0KPiA+ICsNCj4g
PiArICAgICAgIC8qIERldmljZSBrZXkgKi8NCj4gPiArICAgICAgIGlmICghanNvbl9vYmplY3Rf
b2JqZWN0X2dldF9leChqbm9kZSwgImRldmljZUtleSIsICZqdmFsdWUpIHx8DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICFqdmFsdWUpIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKCFtZXNoX2dldF9yYW5kb21fYnl0
ZXMoa2V5LCAxNikpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgYWRkX2tleShqbm9kZSwgImRldmljZUtleSIsIGtl
eSk7DQo+ID4gKyAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAgICAgICAgICB2YWx1ZV9zdHIg
PSAoY2hhciAqKWpzb25fb2JqZWN0X2dldF9zdHJpbmcoanZhbHVlKTsNCj4gPiArICAgICAgICAg
ICAgICAgaWYgKCFzdHIyaGV4KHZhbHVlX3N0ciwgc3RybGVuKHZhbHVlX3N0ciksIGtleSwgMTYp
KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTs7DQo+ID4gKyAgICAg
ICB9DQo+ID4gKw0KPiA+ICsgICAgICAgbm9kZSA9IG5vZGVfbmV3KCk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgaWYgKCFub2RlKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4g
Kw0KPiA+ICsgICAgICAgbm9kZV9zZXRfZGV2aWNlX2tleShub2RlLCBrZXkpOw0KPiA+ICsNCj4g
PiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoam5vZGUsICJJVmluZGV4IiwgJmpp
bnQpOw0KPiA+ICsgICAgICAgaWYgKGppbnQpDQo+ID4gKyAgICAgICAgICAgICAgIGlkeCA9IGpz
b25fb2JqZWN0X2dldF9pbnQoamludCk7DQo+ID4gKyAgICAgICBlbHNlDQo+ID4gKyAgICAgICAg
ICAgICAgIGlkeCA9IDA7DQo+ID4gKw0KPiA+ICsgICAgICAgbm9kZV9zZXRfaXZfaW5kZXgobm9k
ZSwgaWR4KTsNCj4gPiArICAgICAgIGlmIChsb2NhbCkgew0KPiA+ICsgICAgICAgICAgICAgICBi
b29sIHVwZGF0ZSA9IGZhbHNlOw0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVjdF9vYmpl
Y3RfZ2V0X2V4KGpub2RlLCAiSVZ1cGRhdGUiLCAmamludCk7DQo+ID4gKyAgICAgICAgICAgICAg
IGlmIChqaW50KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZSA9IGpzb25fb2Jq
ZWN0X2dldF9pbnQoamludCkgPyB0cnVlIDogZmFsc2U7DQo+ID4gKyAgICAgICAgICAgICAgIG5l
dF9zZXRfaXZfaW5kZXgoaWR4LCB1cGRhdGUpOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmIChqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGpub2RlLCAic2VxdWVuY2VOdW1i
ZXIiLCAmamludCkgJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqaW50KSB7DQo+ID4gKyAgICAgICAg
ICAgICAgIGludCBzZXEgPSBqc29uX29iamVjdF9nZXRfaW50KGppbnQpOw0KPiA+ICsgICAgICAg
ICAgICAgICBub2RlX3NldF9zZXF1ZW5jZV9udW1iZXIobm9kZSwgc2VxKTsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICAvKiBDb21wb3NpdGlvbiBpcyBtYW5kYXRvcnkgZm9yIGxv
Y2FsIG5vZGUgKi8NCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoam5vZGUs
ICJjb21wb3NpdGlvbiIsICZqY29uZmlnKTsNCj4gPiArICAgICAgIGlmICgoamNvbmZpZyAmJiAh
cGFyc2Vfbm9kZV9jb21wb3NpdGlvbihub2RlLCBqY29uZmlnKSkgfHwNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICghamNvbmZpZyAm
JiBsb2NhbCkpIHsNCj4gPiArICAgICAgICAgICAgICAgbm9kZV9mcmVlKG5vZGUpOw0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsg
ICAgICAgLyogQ29uZmlndXJhdGlvbiBpcyBtYW5kYXRvcnkgZm9yIG5vZGVzIGluIHByb3Zpc2lv
bmluZyBkYXRhYmFzZSAqLw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChq
bm9kZSwgImNvbmZpZ3VyYXRpb24iLCAmamNvbmZpZyk7DQo+ID4gKyAgICAgICBpZiAoIWpjb25m
aWcpIHsNCj4gPiArICAgICAgICAgICAgICAgaWYgKGxvY2FsKSB7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgLyogVGhpcyBpcyBhbiB1bnByb3Zpc2lvbmVkIGxvY2FsIGRldmljZSAqLw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArICAgICAgICAgICAg
ICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBub2RlX2ZyZWUobm9kZSk7
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAg
ICAgICAgICB9DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rf
b2JqZWN0X2dldF9leChqY29uZmlnLCAiZWxlbWVudHMiLCAmamVsZW1lbnRzKTsNCj4gPiArICAg
ICAgIGlmICghamVsZW1lbnRzKSB7DQo+ID4gKyAgICAgICAgICAgICAgIG5vZGVfZnJlZShub2Rl
KTsNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAgfQ0KPiA+
ICsNCj4gPiArICAgICAgIGlmICghcGFyc2VfY29uZmlndXJhdGlvbl9lbGVtZW50cyhub2RlLCBq
ZWxlbWVudHMsIGxvY2FsKSkgew0KPiA+ICsgICAgICAgICAgICAgICBub2RlX2ZyZWUobm9kZSk7
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTs7DQo+ID4gKyAgICAgICB9DQo+ID4g
Kw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqY29uZmlnLCAibmV0S2V5
cyIsICZqaWR4cyk7DQo+ID4gKyAgICAgICBpZiAoIWppZHhzIHx8IChwYXJzZV9ub2RlX2tleXMo
bm9kZSwgamlkeHMsIGZhbHNlKSA9PSAwKSkgew0KPiA+ICsgICAgICAgICAgICAgICBub2RlX2Zy
ZWUobm9kZSk7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAg
IH0NCj4gPiArDQo+ID4gKyAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGpjb25maWcs
ICJhcHBLZXlzIiwgJmppZHhzKTsNCj4gPiArICAgICAgIGlmIChqaWR4cykNCj4gPiArICAgICAg
ICAgICAgICAgcGFyc2Vfbm9kZV9rZXlzKG5vZGUsIGppZHhzLCB0cnVlKTsNCj4gPiArDQo+ID4g
KyAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGpjb25maWcsICJkZWZhdWx0VFRMIiwg
Jmp2YWx1ZSk7DQo+ID4gKyAgICAgICBpZiAoanZhbHVlKSB7DQo+ID4gKyAgICAgICAgICAgICAg
IGludCB0dGwgPSBqc29uX29iamVjdF9nZXRfaW50KGp2YWx1ZSk7DQo+ID4gKyAgICAgICAgICAg
ICAgIG5vZGVfc2V0X2RlZmF1bHRfdHRsKG5vZGUsIHR0bCAmVFRMX01BU0spOw0KPiA+ICsgICAg
ICAgfQ0KPiA+ICsNCj4gPiArZG9uZToNCj4gPiArICAgICAgIGlmIChsb2NhbCAmJiAhbm9kZV9z
ZXRfbG9jYWxfbm9kZShub2RlKSkgew0KPiA+ICsgICAgICAgICAgICAgICBub2RlX2ZyZWUobm9k
ZSk7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gKyAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArYm9vbCBw
cm92X2RiX3Nob3coY29uc3QgY2hhciAqZmlsZW5hbWUpDQo+ID4gK3sNCj4gPiArICAgICAgIGNo
YXIgKnN0cjsNCj4gPiArDQo+ID4gKyAgICAgICBzdHIgPSBwcm92X2ZpbGVfcmVhZChmaWxlbmFt
ZSk7DQo+ID4gKyAgICAgICBpZiAoIXN0cikNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZh
bHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50ZigiJXNcbiIsIHN0cik7DQo+ID4gKyAg
ICAgICBnX2ZyZWUoc3RyKTsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtzdGF0aWMgYm9vbCByZWFkX2pzb25fZGIoY29uc3QgY2hhciAqZmlsZW5hbWUsIGJv
b2wgcHJvdmlzaW9uZXIsIGJvb2wNCj4gbG9jYWwpDQo+ID4gK3sNCj4gPiArICAgICAgIGNoYXIg
KnN0cjsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0ICpqbWFpbjsNCj4gPiArICAgICAgIGpzb25f
b2JqZWN0ICpqYXJyYXk7DQo+ID4gKyAgICAgICBqc29uX29iamVjdCAqanByb3Y7DQo+ID4gKyAg
ICAgICBqc29uX29iamVjdCAqanZhbHVlOw0KPiA+ICsgICAgICAganNvbl9vYmplY3QgKmp0ZW1w
Ow0KPiA+ICsgICAgICAgdWludDhfdCBrZXlbMTZdOw0KPiA+ICsgICAgICAgaW50IHZhbHVlX2lu
dDsNCj4gPiArICAgICAgIGNoYXIgKnZhbHVlX3N0cjsNCj4gPiArICAgICAgIGludCBsZW47DQo+
ID4gKyAgICAgICBpbnQgaTsNCj4gPiArICAgICAgIHVpbnQzMl90IGluZGV4Ow0KPiA+ICsgICAg
ICAgYm9vbCByZWZyZXNoID0gZmFsc2U7DQo+ID4gKyAgICAgICBib29sIHJlcyA9IGZhbHNlOw0K
PiA+ICsNCj4gPiArICAgICAgIHN0ciA9IHByb3ZfZmlsZV9yZWFkKGZpbGVuYW1lKTsNCj4gPiAr
ICAgICAgIGlmICghc3RyKSByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgam1haW4g
PSBqc29uX3Rva2VuZXJfcGFyc2Uoc3RyKTsNCj4gPiArICAgICAgIGlmICgham1haW4pDQo+ID4g
KyAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAobG9jYWwp
IHsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmpub2RlOw0KPiA+ICsgICAgICAg
ICAgICAgICBib29sIHJlc3VsdDsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGpzb25fb2Jq
ZWN0X29iamVjdF9nZXRfZXgoam1haW4sICJub2RlIiwgJmpub2RlKTsNCj4gPiArICAgICAgICAg
ICAgICAgaWYgKCFqbm9kZSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50
ZigiQ2Fubm90IGZpbmQgXCJub2RlXCIgb2JqZWN0Iik7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2UNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICByZXN1bHQgPSBwYXJzZV9ub2RlKGpub2RlLCB0cnVlKTsNCj4gPiAr
DQo+ID4gKyAgICAgICAgICAgICAgIC8qDQo+ID4gKyAgICAgICAgICAgICAgICogSWYgbG9jYWwg
bm9kZSBpcyBwcm92aXNpb25lciwgdGhlIHJlc3Qgb2YgbWVzaCBzZXR0aW5ncw0KPiA+ICsgICAg
ICAgICAgICAgICAqIGFyZSByZWFkIGZyb20gcHJvdmlzaW9uaW5nIGRhdGFiYXNlLg0KPiA+ICsg
ICAgICAgICAgICAgICAqLw0KPiA+ICsgICAgICAgICAgICAgICBpZiAocHJvdmlzaW9uZXIpIHsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICByZXMgPSByZXN1bHQ7DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKyAg
ICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgLyogSVYgaW5kZXggKi8NCj4gPiArICAgICAgIGpz
b25fb2JqZWN0X29iamVjdF9nZXRfZXgoam1haW4sICJJVmluZGV4IiwgJmp2YWx1ZSk7DQo+ID4g
KyAgICAgICBpZiAoIWp2YWx1ZSkNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+
ICsNCj4gPiArICAgICAgIGluZGV4ID0ganNvbl9vYmplY3RfZ2V0X2ludChqdmFsdWUpOw0KPiA+
ICsNCj4gPiArICAgICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoam1haW4sICJJVnVwZGF0
ZSIsICZqdmFsdWUpOw0KPiA+ICsgICAgICAgaWYgKCFqdmFsdWUpDQo+ID4gKyAgICAgICAgICAg
ICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICB2YWx1ZV9pbnQgPSBqc29uX29iamVj
dF9nZXRfaW50KGp2YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgbmV0X3NldF9pdl9pbmRleChp
bmRleCwgdmFsdWVfaW50KTsNCj4gPiArDQo+ID4gKyAgICAgICAvKiBOZXR3b3JrIGtleShzKSAq
Lw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqbWFpbiwgIm5ldEtleXMi
LCAmamFycmF5KTsNCj4gPiArICAgICAgIGlmICghamFycmF5KQ0KPiA+ICsgICAgICAgICAgICAg
ICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgbGVuID0ganNvbl9vYmplY3RfYXJyYXlf
bGVuZ3RoKGphcnJheSk7DQo+ID4gKyAgICAgICBybF9wcmludGYoIiMgbmV0a2V5cyA9ICVkXG4i
LCBsZW4pOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47ICsraSkgew0K
PiA+ICsgICAgICAgICAgICAgICB1aW50MzJfdCBpZHg7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICBqdGVtcCA9IGpzb25fb2JqZWN0X2FycmF5X2dldF9pZHgoamFycmF5LCBpKTsNCj4gPiAr
ICAgICAgICAgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqdGVtcCwgImluZGV4Iiwg
Jmp2YWx1ZSk7DQo+ID4gKyAgICAgICAgICAgICAgIGlmICghanZhbHVlKQ0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArICAgICAgICAgICAgICAgaWR4ID0ganNv
bl9vYmplY3RfZ2V0X2ludChqdmFsdWUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAganNv
bl9vYmplY3Rfb2JqZWN0X2dldF9leChqdGVtcCwgImtleSIsICZqdmFsdWUpOw0KPiA+ICsgICAg
ICAgICAgICAgICBpZiAoIWp2YWx1ZSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlm
ICghbWVzaF9nZXRfcmFuZG9tX2J5dGVzKGtleSwgMTYpKQ0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGFk
ZF9rZXkoanRlbXAsICJrZXkiLCBrZXkpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJl
ZnJlc2ggPSB0cnVlOw0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2Ugew0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIHZhbHVlX3N0ciA9IChjaGFyICopanNvbl9vYmplY3RfZ2V0X3N0cmlu
ZyhqdmFsdWUpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmICghc3RyMmhleCh2YWx1
ZV9zdHIsIHN0cmxlbih2YWx1ZV9zdHIpLCBrZXksIDE2KSkgew0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
IH0NCj4gPiArICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgaWYg
KCFrZXlzX25ldF9rZXlfYWRkKGlkeCwga2V5LCBmYWxzZSkpDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgZ290byBkb25lOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmpl
Y3Rfb2JqZWN0X2dldF9leChqdGVtcCwgImtleVJlZnJlc2giLCAmanZhbHVlKTsNCj4gPiArICAg
ICAgICAgICAgICAgaWYgKCFqdmFsdWUpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ290
byBkb25lOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAga2V5c19zZXRfa3JfcGhhc2UoaWR4
LCAodWludDhfdCkganNvbl9vYmplY3RfZ2V0X2ludChqdmFsdWUpKTsNCj4gPiArICAgICAgIH0N
Cj4gPiArDQo+ID4gKyAgICAgICAvKiBBcHAga2V5cyAqLw0KPiA+ICsgICAgICAganNvbl9vYmpl
Y3Rfb2JqZWN0X2dldF9leChqbWFpbiwgImFwcEtleXMiLCAmamFycmF5KTsNCj4gPiArICAgICAg
IGlmIChqYXJyYXkpIHsNCj4gPiArICAgICAgICAgICAgICAgbGVuID0ganNvbl9vYmplY3RfYXJy
YXlfbGVuZ3RoKGphcnJheSk7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiIyBhcHBr
ZXlzID0gJWRcbiIsIGxlbik7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBmb3IgKGkgPSAw
OyBpIDwgbGVuOyArK2kpIHsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpbnQgYXBwX2lk
eDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpbnQgbmV0X2lkeDsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAganRlbXAgPSBqc29uX29iamVjdF9hcnJheV9nZXRfaWR4
KGphcnJheSwgaSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAganNvbl9vYmplY3Rfb2Jq
ZWN0X2dldF9leChqdGVtcCwgImluZGV4IiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAmanZhbHVlKTsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICBpZiAoIWp2YWx1ZSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdv
dG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYXBwX2lkeCA9IGpz
b25fb2JqZWN0X2dldF9pbnQoanZhbHVlKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBp
ZiAoIUNIRUNLX0tFWV9JRFhfUkFOR0UoYXBwX2lkeCkpDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIGpzb25fb2JqZWN0X29iamVjdF9nZXRfZXgoanRlbXAsICJrZXkiLCAmanZhbHVlKTsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIWp2YWx1ZSkgew0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgaWYgKCFtZXNoX2dldF9yYW5kb21fYnl0ZXMoa2V5LCAxNikp
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvdG8gZG9uZTsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9rZXkoanRlbXAsICJrZXki
LCBrZXkpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmcmVzaCA9IHRy
dWU7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHZhbHVlX3N0ciA9DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIChjaGFyICopanNvbl9vYmplY3RfZ2V0X3N0cmluZyhqdmFs
dWUpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyMmhleCh2YWx1ZV9z
dHIsIHN0cmxlbih2YWx1ZV9zdHIpLCBrZXksIDE2KTsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGpzb25fb2JqZWN0X29i
amVjdF9nZXRfZXgoanRlbXAsICJib3VuZE5ldEtleSIsDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmanZhbHVlKTsNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICBpZiAoIWp2YWx1ZSkNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIGdvdG8gZG9uZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgbmV0X2lkeCA9IGpzb25fb2JqZWN0X2dldF9pbnQoanZhbHVlKTsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBpZiAoIUNIRUNLX0tFWV9JRFhfUkFOR0UobmV0X2lkeCkpDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIGtleXNfYXBwX2tleV9hZGQobmV0X2lkeCwgYXBwX2lkeCwga2V5
LCBmYWxzZSk7DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgIH0NCj4gPiArDQo+
ID4gKyAgICAgICAvKiBQcm92aXNpb25lciBpbmZvICovDQo+ID4gKyAgICAgICBqc29uX29iamVj
dF9vYmplY3RfZ2V0X2V4KGptYWluLCAicHJvdmlzaW9uZXJzIiwgJmphcnJheSk7DQo+ID4gKyAg
ICAgICBpZiAoIWphcnJheSkNCj4gPiArICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsN
Cj4gPiArICAgICAgIGxlbiA9IGpzb25fb2JqZWN0X2FycmF5X2xlbmd0aChqYXJyYXkpOw0KPiA+
ICsgICAgICAgcmxfcHJpbnRmKCIjIHByb3Zpc2lvbmVycyA9ICVkXG4iLCBsZW4pOw0KPiA+ICsN
Cj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47ICsraSkgew0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAganByb3YgPSBqc29uX29iamVjdF9hcnJheV9nZXRfaWR4KGphcnJheSwgaSk7
DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAvKiBBbGxvY2F0ZWQgdW5pY2FzdCByYW5nZSAq
Lw0KPiA+ICsgICAgICAgICAgICAgICBqc29uX29iamVjdF9vYmplY3RfZ2V0X2V4KGpwcm92LCAi
YWxsb2NhdGVkVW5pY2FzdFJhbmdlIiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAmanRlbXApOw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIWp0
ZW1wKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAg
ICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBpZiAoIXBhcnNlX3VuaWNh
c3RfcmFuZ2UoanRlbXApKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcmxfcHJpbnRm
KCJEb25lZWQgdG8gcGFyc2UgdW5pY2FzdCByYW5nZVxuIik7DQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgZ290byBkb25lOw0KPiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKyAgICAgICB9
DQo+ID4gKw0KPiA+ICsgICAgICAganNvbl9vYmplY3Rfb2JqZWN0X2dldF9leChqbWFpbiwgIm5v
ZGVzIiwgJmphcnJheSk7DQo+ID4gKyAgICAgICBpZiAoIWphcnJheSkgew0KPiA+ICsgICAgICAg
ICAgICAgICByZXMgPSB0cnVlOw0KPiA+ICsgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4g
KyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgbGVuID0ganNvbl9vYmplY3RfYXJyYXlfbGVu
Z3RoKGphcnJheSk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCIjIHByb3Zpc2lvbmVk
IG5vZGVzID0gJWRcbiIsIGxlbik7DQo+ID4gKyAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyAr
K2kpIHsNCj4gPiArICAgICAgICAgICAgICAganNvbl9vYmplY3QgKmpub2RlOw0KPiA+ICsgICAg
ICAgICAgICAgICBqbm9kZSA9IGpzb25fb2JqZWN0X2FycmF5X2dldF9pZHgoamFycmF5LCBpKTsN
Cj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGlmICgham5vZGUgfHwgIXBhcnNlX25vZGUoam5v
ZGUsIGZhbHNlKSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBnb3RvIGRvbmU7DQo+ID4g
KyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmVzID0gdHJ1ZTsNCj4gPiArZG9uZToNCj4g
PiArDQo+ID4gKyAgICAgICBnX2ZyZWUoc3RyKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocmVz
ICYmIHJlZnJlc2gpDQo+ID4gKyAgICAgICAgICAgICAgIHByb3ZfZmlsZV93cml0ZShqbWFpbiwg
ZmFsc2UpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChqbWFpbikNCj4gPiArICAgICAgICAgICAg
ICAganNvbl9vYmplY3RfcHV0KGptYWluKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gcmVz
Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIHByb3ZfZGJfcmVhZChjb25zdCBjaGFyICpmaWxl
bmFtZSkNCj4gPiArew0KPiA+ICsgICAgICAgcHJvdl9maWxlbmFtZSA9IGZpbGVuYW1lOw0KPiA+
ICsgICAgICAgcmV0dXJuIHJlYWRfanNvbl9kYihmaWxlbmFtZSwgdHJ1ZSwgZmFsc2UpOw0KPiA+
ICt9DQo+ID4gKw0KPiA+ICtib29sIHByb3ZfZGJfcmVhZF9sb2NhbF9ub2RlKGNvbnN0IGNoYXIg
KmZpbGVuYW1lLCBib29sIHByb3Zpc2lvbmVyKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBsb2NhbF9m
aWxlbmFtZSA9IGZpbGVuYW1lOw0KPiA+ICsgICAgICAgcmV0dXJuIHJlYWRfanNvbl9kYihmaWxl
bmFtZSwgcHJvdmlzaW9uZXIsIHRydWUpOw0KPiA+ICt9DQo+ID4gZGlmZiAtLWdpdCBhL21lc2gv
cHJvdi5jIGIvbWVzaC9wcm92LmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGluZGV4
IDAwMDAwMDAuLjg5ZmM4ODQNCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvbWVzaC9wcm92
LmMNCj4gPiBAQCAtMCwwICsxLDY2NCBAQA0KPiA+ICsvKg0KPiA+ICsgKg0KPiA+ICsgKiAgQmx1
ZVogLSBCbHVldG9vdGggcHJvdG9jb2wgc3RhY2sgZm9yIExpbnV4DQo+ID4gKyAqDQo+ID4gKyAq
ICBDb3B5cmlnaHQgKEMpIDIwMTcgIEludGVsIENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2Vy
dmVkLg0KPiA+ICsgKg0KPiA+ICsgKg0KPiA+ICsgKiAgVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29m
dHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcg0KPiA+ICsgKiAgbW9kaWZ5IGl0
IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYw0KPiA+ICsg
KiAgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsg
ZWl0aGVyDQo+ID4gKyAqICB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIg
b3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4gPiArICoNCj4gPiArICogIFRoaXMgbGlicmFy
eSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLA0KPiA+
ICsgKiAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQg
d2FycmFudHkgb2YNCj4gPiArICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBB
UlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUNCj4gR05VDQo+ID4gKyAqICBMZXNzZXIgR2VuZXJh
bCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLg0KPiA+ICsgKg0KPiA+ICsgKiAgWW91
IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1
YmxpYw0KPiA+ICsgKiAgTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3
cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZQ0KPiA+ICsgKiAgRm91bmRhdGlvbiwgSW5jLiwgNTEg
RnJhbmtsaW4gU3QsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxDQo+IFVTQQ0K
PiA+ICsgKg0KPiA+ICsgKi8NCj4gPiArI2lmZGVmIEhBVkVfQ09ORklHX0gNCj4gPiArI2luY2x1
ZGUgPGNvbmZpZy5oPg0KPiA+ICsjZW5kaWYNCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxzdGRpby5o
Pg0KPiA+ICsjaW5jbHVkZSA8ZXJybm8uaD4NCj4gPiArI2luY2x1ZGUgPHVuaXN0ZC5oPg0KPiA+
ICsjaW5jbHVkZSA8c3RkbGliLmg+DQo+ID4gKyNpbmNsdWRlIDxzdGRib29sLmg+DQo+ID4gKyNp
bmNsdWRlIDxzeXMvdWlvLmg+DQo+ID4gKyNpbmNsdWRlIDx3b3JkZXhwLmg+DQo+ID4gKw0KPiA+
ICsjaW5jbHVkZSA8cmVhZGxpbmUvcmVhZGxpbmUuaD4NCj4gPiArI2luY2x1ZGUgPHJlYWRsaW5l
L2hpc3RvcnkuaD4NCj4gPiArI2luY2x1ZGUgPGdsaWIuaD4NCj4gPiArDQo+ID4gKyNpbmNsdWRl
ICJzcmMvc2hhcmVkL3V0aWwuaCINCj4gPiArI2luY2x1ZGUgInNyYy9zaGFyZWQvZWNjLmgiDQo+
ID4gKw0KPiA+ICsjaW5jbHVkZSAiZ2RidXMvZ2RidXMuaCINCj4gPiArI2luY2x1ZGUgIm1vbml0
b3IvdXVpZC5oIg0KPiA+ICsjaW5jbHVkZSAiY2xpZW50L2Rpc3BsYXkuaCINCj4gPiArI2luY2x1
ZGUgIm5vZGUuaCINCj4gPiArI2luY2x1ZGUgImdhdHQuaCINCj4gPiArI2luY2x1ZGUgImNyeXB0
by5oIg0KPiA+ICsjaW5jbHVkZSAibWVzaC1uZXQuaCINCj4gPiArI2luY2x1ZGUgInV0aWwuaCIN
Cj4gPiArI2luY2x1ZGUgImFnZW50LmgiDQo+ID4gKyNpbmNsdWRlICJwcm92LmgiDQo+ID4gKyNp
bmNsdWRlICJuZXQuaCINCj4gPiArDQo+ID4gKy8qIFByb3Zpc2lvbmluZyBTZWN1cml0eSBMZXZl
bHMgKi8NCj4gPiArI2RlZmluZSBNRVNIX1BST1ZfU0VDX0hJR0ggICAgIDINCj4gPiArI2RlZmlu
ZSBNRVNIX1BST1ZfU0VDX01FRCAgICAgIDENCj4gPiArI2RlZmluZSBNRVNIX1BST1ZfU0VDX0xP
VyAgICAgIDANCj4gPiArDQo+ID4gKy8qIEZvciBEZXBsb3ltZW50LCBTZWN1cml0eSBsZXZlbHMg
YmVsb3cgSElHSCBhcmUgKm5vdCogcmVjb21lbmRlZCAqLw0KPiA+ICsjZGVmaW5lIG1lc2hfZ2F0
dF9wcm92X3NlY3VyaXR5KCkgICAgICBNRVNIX1BST1ZfU0VDX01FRA0KPiA+ICsNCj4gPiArI2Rl
ZmluZSBQUk9WX0lOVklURSAgICAweDAwDQo+ID4gKyNkZWZpbmUgUFJPVl9DQVBTICAgICAgMHgw
MQ0KPiA+ICsjZGVmaW5lIFBST1ZfU1RBUlQgICAgIDB4MDINCj4gPiArI2RlZmluZSBQUk9WX1BV
Ql9LRVkgICAweDAzDQo+ID4gKyNkZWZpbmUgUFJPVl9JTlBfQ01QTFQgMHgwNA0KPiA+ICsjZGVm
aW5lIFBST1ZfQ09ORklSTSAgIDB4MDUNCj4gPiArI2RlZmluZSBQUk9WX1JBTkRPTSAgICAweDA2
DQo+ID4gKyNkZWZpbmUgUFJPVl9EQVRBICAgICAgMHgwNw0KPiA+ICsjZGVmaW5lIFBST1ZfQ09N
UExFVEUgIDB4MDgNCj4gPiArI2RlZmluZSBQUk9WX0ZBSUxFRCAgICAweDA5DQo+ID4gKw0KPiA+
ICsjZGVmaW5lIFBST1ZfTk9fT09CICAgIDANCj4gPiArI2RlZmluZSBQUk9WX1NUQVRJQ19PT0Ig
ICAgICAgIDENCj4gPiArI2RlZmluZSBQUk9WX09VVFBVVF9PT0IgICAgICAgIDINCj4gPiArI2Rl
ZmluZSBQUk9WX0lOUFVUX09PQiAzDQo+ID4gKw0KPiA+ICsjZGVmaW5lIFBST1ZfRVJSX0lOVkFM
SURfUERVICAgICAgICAgICAweDAxDQo+ID4gKyNkZWZpbmUgUFJPVl9FUlJfSU5WQUxJRF9GT1JN
QVQgICAgICAgICAgICAgICAgMHgwMg0KPiA+ICsjZGVmaW5lIFBST1ZfRVJSX1VORVhQRUNURURf
UERVICAgICAgICAgICAgICAgIDB4MDMNCj4gPiArI2RlZmluZSBQUk9WX0VSUl9DT05GSVJNX0ZB
SUxFRCAgICAgICAgICAgICAgICAweDA0DQo+ID4gKyNkZWZpbmUgUFJPVl9FUlJfSU5TVUZfUkVT
T1VSQ0UgICAgICAgICAgICAgICAgMHgwNQ0KPiA+ICsjZGVmaW5lIFBST1ZfRVJSX0RFQ1JZUFRf
RkFJTEVEICAgICAgICAgICAgICAgIDB4MDYNCj4gPiArI2RlZmluZSBQUk9WX0VSUl9VTkVYUEVD
VEVEX0VSUiAgICAgICAgICAgICAgICAweDA3DQo+ID4gKyNkZWZpbmUgUFJPVl9FUlJfQ0FOVF9B
U1NJR05fQUREUiAgICAgIDB4MDgNCj4gPiArDQo+ID4gKy8qIEV4cGVjdGVkIFByb3Zpc2lvbmlu
ZyBQRFUgc2l6ZXMgKi8NCj4gPiArc3RhdGljIGNvbnN0IHVpbnQxNl90IGV4cGVjdGVkX3BkdV9z
aXplW10gPSB7DQo+ID4gKyAgICAgICAxICsgMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgLyogUFJPVl9JTlZJVEUgKi8NCj4gPiArICAgICAgIDEgKyAxICsgMiArIDEgKyAxICsg
MSArIDIgKyAxICsgMiwgICAgICAvKiBQUk9WX0NBUFMgKi8NCj4gPiArICAgICAgIDEgKyAxICsg
MSArIDEgKyAxICsgMSwgICAgICAgICAgICAgICAgICAvKiBQUk9WX1NUQVJUICovDQo+ID4gKyAg
ICAgICAxICsgNjQsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogUFJPVl9QVUJf
S0VZICovDQo+ID4gKyAgICAgICAxLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgLyogUFJPVl9JTlBfQ01QTFQgKi8NCj4gPiArICAgICAgIDEgKyAxNiwgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAvKiBQUk9WX0NPTkZJUk0gKi8NCj4gPiArICAgICAgIDEgKyAx
NiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBQUk9WX1JBTkRPTSAqLw0KPiA+
ICsgICAgICAgMSArIDE2ICsgMiArIDEgKyA0ICsgMiArIDgsICAgICAgICAgICAgIC8qIFBST1Zf
REFUQSAqLw0KPiA+ICsgICAgICAgMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIC8qIFBST1ZfQ09NUExFVEUgKi8NCj4gPiArICAgICAgIDEgKyAxLCAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAvKiBQUk9WX0ZBSUxFRCAqLw0KPiA+ICt9Ow0KPiA+ICsNCj4g
PiArdHlwZWRlZiBzdHJ1Y3QgX19wYWNrZWQgew0KPiA+ICsgICAgICAgdWludDhfdCBhdHRlbnRp
b247DQo+ID4gK30gX19hdHRyaWJ1dGVfXyAoKHBhY2tlZCkpICAgICBwcm92X2ludml0ZTsNCj4g
PiArDQo+ID4gK3R5cGVkZWYgc3RydWN0IHsNCj4gPiArICAgICAgIHVpbnQ4X3QgIG51bV9lbGU7
DQo+ID4gKyAgICAgICB1aW50MTZfdCBhbGdvcml0aG1zOw0KPiA+ICsgICAgICAgdWludDhfdCAg
cHViX3R5cGU7DQo+ID4gKyAgICAgICB1aW50OF90ICBzdGF0aWNfdHlwZTsNCj4gPiArICAgICAg
IHVpbnQ4X3QgIG91dHB1dF9zaXplOw0KPiA+ICsgICAgICAgdWludDE2X3Qgb3V0cHV0X2FjdGlv
bjsNCj4gPiArICAgICAgIHVpbnQ4X3QgIGlucHV0X3NpemU7DQo+ID4gKyAgICAgICB1aW50MTZf
dCBpbnB1dF9hY3Rpb247DQo+ID4gK30gX19hdHRyaWJ1dGVfXyAoKHBhY2tlZCkpICAgICBwcm92
X2NhcHM7DQo+ID4gKw0KPiA+ICt0eXBlZGVmIHN0cnVjdCB7DQo+ID4gKyAgICAgICB1aW50OF90
IGFsZ29yaXRobTsNCj4gPiArICAgICAgIHVpbnQ4X3QgcHViX2tleTsNCj4gPiArICAgICAgIHVp
bnQ4X3QgYXV0aF9tZXRob2Q7DQo+ID4gKyAgICAgICB1aW50OF90IGF1dGhfYWN0aW9uOw0KPiA+
ICsgICAgICAgdWludDhfdCBhdXRoX3NpemU7DQo+ID4gK30gX19hdHRyaWJ1dGVfXyAoKHBhY2tl
ZCkpICAgICBwcm92X3N0YXJ0Ow0KPiA+ICsNCj4gPiArdHlwZWRlZiBzdHJ1Y3Qgew0KPiA+ICsg
ICAgICAgcHJvdl9pbnZpdGUgICAgIGludml0ZTsNCj4gPiArICAgICAgIHByb3ZfY2FwcyAgICAg
ICBjYXBzOw0KPiA+ICsgICAgICAgcHJvdl9zdGFydCAgICAgIHN0YXJ0Ow0KPiA+ICsgICAgICAg
dWludDhfdCBwcnZfcHViX2tleVs2NF07DQo+ID4gKyAgICAgICB1aW50OF90IGRldl9wdWJfa2V5
WzY0XTsNCj4gPiArfSBfX2F0dHJpYnV0ZV9fICgocGFja2VkKSkgICAgIGNvbmZfaW5wdXQ7DQo+
ID4gKw0KPiA+ICtzdHJ1Y3QgcHJvdl9kYXRhIHsNCj4gPiArICAgICAgIEdEQnVzUHJveHkgICAg
ICAgICAgICAgICpwcm92X2luOw0KPiA+ICsgICAgICAgcHJvdmlzaW9uX2RvbmVfY2IgICAgICAg
cHJvdl9kb25lOw0KPiA+ICsgICAgICAgdm9pZCAgICAgICAgICAgICAgICAgICAgKnVzZXJfZGF0
YTsNCj4gPiArICAgICAgIHVpbnQxNl90ICAgICAgICAgICAgICAgIG5ldF9pZHg7DQo+ID4gKyAg
ICAgICB1aW50MTZfdCAgICAgICAgICAgICAgICBuZXdfYWRkcjsNCj4gPiArICAgICAgIHVpbnQ4
X3QgICAgICAgICAgICAgICAgIHN0YXRlOw0KPiA+ICsgICAgICAgdWludDhfdCAgICAgICAgICAg
ICAgICAgZXBoX3ByaXZfa2V5WzMyXTsNCj4gPiArICAgICAgIHVpbnQ4X3QgICAgICAgICAgICAg
ICAgIGVjZGhfc2VjcmV0WzMyXTsNCj4gPiArICAgICAgIGNvbmZfaW5wdXQgICAgICAgICAgICAg
IGNvbmZfaW47DQo+ID4gKyAgICAgICB1aW50OF90ICAgICAgICAgICAgICAgICByYW5kX2F1dGhb
MzJdOw0KPiA+ICsgICAgICAgdWludDhfdCAgICAgICAgICAgICAgICAgc2FsdFsxNl07DQo+ID4g
KyAgICAgICB1aW50OF90ICAgICAgICAgICAgICAgICBjb25mX2tleVsxNl07DQo+ID4gKyAgICAg
ICB1aW50OF90ICAgICAgICAgICAgICAgICBtZXNoX2NvbmZbMTZdOw0KPiA+ICsgICAgICAgdWlu
dDhfdCAgICAgICAgICAgICAgICAgZGV2X2tleVsxNl07DQo+ID4gK307DQo+ID4gKw0KPiA+ICtz
dGF0aWMgdWludDhfdCB1MTZfaGlnaGVzdF9iaXQodWludDE2X3QgbWFzaykNCj4gPiArew0KPiA+
ICsgICAgICAgdWludDhfdCBjbnQgPSAwOw0KPiA+ICsNCj4gPiArICAgICAgIGlmICghbWFzaykg
cmV0dXJuIDB4ZmY7DQo+ID4gKw0KPiA+ICsgICAgICAgd2hpbGUgKG1hc2sgJiAweGZmZmUpIHsN
Cj4gPiArICAgICAgICAgICAgICAgY250Kys7DQo+ID4gKyAgICAgICAgICAgICAgIG1hc2sgPj49
IDE7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIGNudDsNCj4gPiAr
fQ0KPiA+ICsNCj4gPiArYm9vbCBwcm92X29wZW4oc3RydWN0IG1lc2hfbm9kZSAqbm9kZSwgR0RC
dXNQcm94eSAqcHJvdl9pbiwNCj4gdWludDE2X3QgbmV0X2lkeCwNCj4gPiArICAgICAgICAgICAg
ICAgcHJvdmlzaW9uX2RvbmVfY2IgY2IsIHZvaWQgKnVzZXJfZGF0YSkNCj4gPiArew0KPiA+ICsg
ICAgICAgdWludDhfdCBpbnZpdGVbXSA9IHsgUFJPWFlfUFJPVklTSU9OSU5HX1BEVSwgUFJPVl9J
TlZJVEUsIDB4MTAgfTsNCj4gPiArICAgICAgIHN0cnVjdCBwcm92X2RhdGEgKnByb3YgPSBub2Rl
X2dldF9wcm92KG5vZGUpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChwcm92KSByZXR1cm4gZmFs
c2U7DQo+ID4gKw0KPiA+ICsgICAgICAgcHJvdiA9IGdfbmV3MChzdHJ1Y3QgcHJvdl9kYXRhLCAx
KTsNCj4gPiArICAgICAgIHByb3YtPnByb3ZfaW4gPSBwcm92X2luOw0KPiA+ICsgICAgICAgcHJv
di0+bmV0X2lkeCA9IG5ldF9pZHg7DQo+ID4gKyAgICAgICBwcm92LT5wcm92X2RvbmUgPSBjYjsN
Cj4gPiArICAgICAgIHByb3YtPnVzZXJfZGF0YSA9IHVzZXJfZGF0YTsNCj4gPiArICAgICAgIG5v
ZGVfc2V0X3Byb3Yobm9kZSwgcHJvdik7DQo+ID4gKyAgICAgICBwcm92LT5jb25mX2luLmludml0
ZS5hdHRlbnRpb24gPSBpbnZpdGVbMl07DQo+ID4gKyAgICAgICBwcm92LT5zdGF0ZSA9IFBST1Zf
SU5WSVRFOw0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50ZigiT3Blbi1Ob2RlOiAlcFxuIiwg
bm9kZSk7DQo+ID4gKyAgICAgICBybF9wcmludGYoIk9wZW4tUHJvdjogJXBcbiIsIHByb3YpOw0K
PiA+ICsgICAgICAgcmxfcHJpbnRmKCJPcGVuLVByb3Y6IHByb3h5ICVwXG4iLCBwcm92X2luKTsN
Cj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gbWVzaF9nYXR0X3dyaXRlKHByb3ZfaW4sIGludml0
ZSwgc2l6ZW9mKGludml0ZSksIE5VTEwsIG5vZGUpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0
aWMgYm9vbCBwcm92X3NlbmRfcHJvdl9kYXRhKHZvaWQgKm5vZGUpDQo+ID4gK3sNCj4gPiArICAg
ICAgIHN0cnVjdCBwcm92X2RhdGEgKnByb3YgPSBub2RlX2dldF9wcm92KG5vZGUpOw0KPiA+ICsg
ICAgICAgdWludDhfdCBvdXRbMzVdID0geyBQUk9YWV9QUk9WSVNJT05JTkdfUERVLCBQUk9WX0RB
VEEgfTsNCj4gPiArICAgICAgIHVpbnQ4X3Qga2V5WzE2XTsNCj4gPiArICAgICAgIHVpbnQ4X3Qg
bm9uY2VbMTNdOw0KPiA+ICsgICAgICAgdWludDY0X3QgbWljOw0KPiA+ICsNCj4gPiArICAgICAg
IGlmIChwcm92ID09IE5VTEwpIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBtZXNo
X2NyeXB0b19zZXNzaW9uX2tleShwcm92LT5lY2RoX3NlY3JldCwgcHJvdi0+c2FsdCwga2V5KTsN
Cj4gPiArICAgICAgIG1lc2hfY3J5cHRvX25vbmNlKHByb3YtPmVjZGhfc2VjcmV0LCBwcm92LT5z
YWx0LCBub25jZSk7DQo+ID4gKyAgICAgICBtZXNoX2NyeXB0b19kZXZpY2Vfa2V5KHByb3YtPmVj
ZGhfc2VjcmV0LCBwcm92LT5zYWx0LCBwcm92LQ0KPiA+ZGV2X2tleSk7DQo+ID4gKw0KPiA+ICsg
ICAgICAgcHJpbnRfYnl0ZV9hcnJheSgiUy1LZXlcdCIsIGtleSwgc2l6ZW9mKGtleSkpOw0KPiA+
ICsgICAgICAgcHJpbnRfYnl0ZV9hcnJheSgiUy1Ob25jZVx0Iiwgbm9uY2UsIHNpemVvZihub25j
ZSkpOw0KPiA+ICsgICAgICAgcHJpbnRfYnl0ZV9hcnJheSgiRGV2S2V5XHQiLCBwcm92LT5kZXZf
a2V5LCBzaXplb2YocHJvdi0NCj4gPmRldl9rZXkpKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
IW5ldF9nZXRfa2V5KHByb3YtPm5ldF9pZHgsIG91dCArIDIpKQ0KPiA+ICsgICAgICAgICAgICAg
ICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgcHV0X2JlMTYocHJvdi0+bmV0X2lk
eCwgb3V0ICsgMiArIDE2KTsNCj4gPiArICAgICAgIG5ldF9nZXRfZmxhZ3MocHJvdi0+bmV0X2lk
eCwgb3V0ICsgMiArIDE2ICsgMik7DQo+ID4gKyAgICAgICBwdXRfYmUzMihuZXRfZ2V0X2l2X2lu
ZGV4KE5VTEwpLCBvdXQgKyAyICsgMTYgKyAyICsgMSk7DQo+ID4gKyAgICAgICBwdXRfYmUxNihw
cm92LT5uZXdfYWRkciwgb3V0ICsgMiArIDE2ICsgMiArIDEgKyA0KTsNCj4gPiArDQo+ID4gKyAg
ICAgICBwcmludF9ieXRlX2FycmF5KCJEYXRhXHQiLCBvdXQgKyAyLCAxNiArIDIgKyAxICsgNCAr
IDIpOw0KPiA+ICsNCj4gPiArICAgICAgIG1lc2hfY3J5cHRvX2Flc19jY21fZW5jcnlwdChub25j
ZSwga2V5LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOVUxM
LCAwLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXQgKyAy
LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplb2Yob3V0
KSAtIDIgLSBzaXplb2YobWljKSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgb3V0ICsgMiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgJm1pYywgc2l6ZW9mKG1pYykpOw0KPiA+ICsNCj4gPiArICAgICAgIHByaW50X2J5dGVf
YXJyYXkoIkRhdGFFbmNyeXB0ZWQgKyBtaWNcdCIsIG91dCArIDIsIHNpemVvZihvdXQpIC0gMik7
DQo+ID4gKw0KPiA+ICsgICAgICAgcHJvdi0+c3RhdGUgPSBQUk9WX0RBVEE7DQo+ID4gKyAgICAg
ICByZXR1cm4gbWVzaF9nYXR0X3dyaXRlKHByb3YtPnByb3ZfaW4sIG91dCwgc2l6ZW9mKG91dCks
IE5VTEwsIG5vZGUpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgYm9vbCBwcm92X3NlbmRf
Y29uZmlybSh2b2lkICpub2RlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgcHJvdl9kYXRh
ICpwcm92ID0gbm9kZV9nZXRfcHJvdihub2RlKTsNCj4gPiArICAgICAgIHVpbnQ4X3Qgb3V0WzE4
XSA9IHsgUFJPWFlfUFJPVklTSU9OSU5HX1BEVSwgUFJPVl9DT05GSVJNIH07DQo+ID4gKw0KPiA+
ICsgICAgICAgaWYgKHByb3YgPT0gTlVMTCkgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAg
ICAgIG1lc2hfZ2V0X3JhbmRvbV9ieXRlcyhwcm92LT5yYW5kX2F1dGgsIDE2KTsNCj4gPiArDQo+
ID4gKyAgICAgICBtZXNoX2NyeXB0b19hZXNfY21hYyhwcm92LT5jb25mX2tleSwgcHJvdi0+cmFu
ZF9hdXRoLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZW9mKHByb3Yt
PnJhbmRfYXV0aCksIG91dCArIDIpOw0KPiA+ICsNCj4gPiArICAgICAgIHByb3YtPnN0YXRlID0g
UFJPVl9DT05GSVJNOw0KPiA+ICsgICAgICAgcmV0dXJuIG1lc2hfZ2F0dF93cml0ZShwcm92LT5w
cm92X2luLCBvdXQsIHNpemVvZihvdXQpLCBOVUxMLCBub2RlKTsNCj4gPiArfQ0KPiA+ICsNCj4g
PiArc3RhdGljIHZvaWQgcHJvdl9vdXRfb29iX2RvbmUob29iX3R5cGVfdCB0eXBlLCB2b2lkICpi
dWYsIHVpbnQxNl90IGxlbiwNCj4gPiArICAgICAgICAgICAgICAgdm9pZCAqbm9kZSkNCj4gPiAr
ew0KPiA+ICsgICAgICAgc3RydWN0IHByb3ZfZGF0YSAqcHJvdiA9IG5vZGVfZ2V0X3Byb3Yobm9k
ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHByb3YgPT0gTlVMTCkgcmV0dXJuOw0KPiA+ICsN
Cj4gPiArICAgICAgIHN3aXRjaCAodHlwZSkgew0KPiA+ICsgICAgICAgICAgICAgICBkZWZhdWx0
Og0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIE5PTkU6DQo+ID4gKyAgICAgICAgICAgICAgIGNh
c2UgT1VUUFVUOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHByb3ZfY29tcGxldGUobm9k
ZSwgUFJPVl9FUlJfSU5WQUxJRF9QRFUpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJl
dHVybjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGNhc2UgQVNDSUk6DQo+ID4gKyAgICAg
ICAgICAgICAgIGNhc2UgSEVYQURFQ0lNQUw6DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
aWYgKGxlbiA+IDE2KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdl9j
b21wbGV0ZShub2RlLCBQUk9WX0VSUl9JTlZBTElEX1BEVSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIG1lbWNweShwcm92LT5yYW5kX2F1dGggKyAxNiwgYnVmLCBsZW4pOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgY2FzZSBERUNJTUFMOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChsZW4g
IT0gNCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3ZfY29tcGxldGUo
bm9kZSwgUFJPVl9FUlJfSU5WQUxJRF9QRFUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBtZW1jcHkocHJvdi0+cmFuZF9hdXRoICsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgc2l6ZW9mKHByb3YtPnJhbmRfYXV0aCkgLQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplb2YodWludDMyX3QpLA0KPiA+
ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidWYsIGxlbik7DQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+
ICsgICAgICAgcHJvdl9zZW5kX2NvbmZpcm0obm9kZSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0
YXRpYyB1aW50MzJfdCBwb3dlcl90ZW4odWludDhfdCBwb3dlcikNCj4gPiArew0KPiA+ICsgICAg
ICAgdWludDMyX3QgcmV0ID0gMTsNCj4gPiArDQo+ID4gKyAgICAgICB3aGlsZSAocG93ZXItLSkN
Cj4gPiArICAgICAgICAgICAgICAgcmV0ICo9IDEwOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVy
biByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK2NoYXIgKmluX2FjdGlvblszXSA9IHsNCj4gPiAr
ICAgICAgICJQdXNoIiwNCj4gPiArICAgICAgICJUd2lzdCIsDQo+ID4gKyAgICAgICAiRW50ZXIi
DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBwcm92X2NhbGNfZWNkaChEQnVzTWVz
c2FnZSAqbWVzc2FnZSwgdm9pZCAqbm9kZSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IHBy
b3ZfZGF0YSAqcHJvdiA9IG5vZGVfZ2V0X3Byb3Yobm9kZSk7DQo+ID4gKyAgICAgICB1aW50OF90
IGFjdGlvbiA9IHByb3YtPmNvbmZfaW4uc3RhcnQuYXV0aF9hY3Rpb247DQo+ID4gKyAgICAgICB1
aW50OF90IHNpemUgPSBwcm92LT5jb25mX2luLnN0YXJ0LmF1dGhfc2l6ZTsNCj4gPiArICAgICAg
IGNoYXIgaW5fb29iX2Rpc3BsYXlbMTAwXTsNCj4gPiArICAgICAgIHVpbnQ4X3QgKnRtcCA9ICh2
b2lkICopIGluX29vYl9kaXNwbGF5Ow0KPiA+ICsgICAgICAgdWludDMyX3QgaW5fb29iOw0KPiA+
ICsNCj4gPiArICAgICAgIGlmIChwcm92ID09IE5VTEwpIHJldHVybjsNCj4gPiArDQo+ID4gKyAg
ICAgICAvKiBDb252ZXJ0IHRvIE1lc2ggYnl0ZSBvcmRlciAqLw0KPiA+ICsgICAgICAgbWVtY3B5
KHRtcCwgcHJvdi0+Y29uZl9pbi5kZXZfcHViX2tleSwgNjQpOw0KPiA+ICsgICAgICAgc3dhcF91
MjU2X2J5dGVzKHRtcCk7DQo+ID4gKyAgICAgICBzd2FwX3UyNTZfYnl0ZXModG1wICsgMzIpOw0K
PiA+ICsNCj4gPiArICAgICAgIGVjZGhfc2hhcmVkX3NlY3JldCh0bXAsIHByb3YtPmVwaF9wcml2
X2tleSwgcHJvdi0+ZWNkaF9zZWNyZXQpOw0KPiA+ICsNCj4gPiArICAgICAgIC8qIENvbnZlcnQg
dG8gTWVzaCBieXRlIG9yZGVyICovDQo+ID4gKyAgICAgICBzd2FwX3UyNTZfYnl0ZXMocHJvdi0+
ZWNkaF9zZWNyZXQpOw0KPiA+ICsNCj4gPiArICAgICAgIG1lc2hfY3J5cHRvX3MxKCZwcm92LT5j
b25mX2luLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHNpemVvZihwcm92LT5jb25mX2lu
KSwgcHJvdi0+c2FsdCk7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVzaF9jcnlwdG9fcHJvdl9jb25m
X2tleShwcm92LT5lY2RoX3NlY3JldCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcm92
LT5zYWx0LCBwcm92LT5jb25mX2tleSk7DQo+ID4gKw0KPiA+ICsgICAgICAgc3dpdGNoIChwcm92
LT5jb25mX2luLnN0YXJ0LmF1dGhfbWV0aG9kKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGRlZmF1
bHQ6DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHJvdl9jb21wbGV0ZShub2RlLCBQUk9W
X0VSUl9JTlZBTElEX1BEVSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQo+
ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIDA6IC8qIE5vIE9PQiAqLw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIHByb3Zfc2VuZF9jb25maXJtKG5vZGUpOw0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSAx
OiAvKiBTdGF0aWMgT09CICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYWdlbnRfaW5w
dXRfcmVxdWVzdChIRVhBREVDSU1BTCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgMTYsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIHByb3Zfb3V0X29vYl9kb25lLCBub2RlKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICBicmVhazsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGNhc2UgMjogLyogT3V0cHV0IE9P
QiAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChhY3Rpb24gPD0gMykNCj4gPiAr
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZW50X2lucHV0X3JlcXVlc3QoREVDSU1B
TCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBz
aXplLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IHByb3Zfb3V0X29vYl9kb25lLCBub2RlKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBl
bHNlDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2VudF9pbnB1dF9yZXF1
ZXN0KEFTQ0lJLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHNpemUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgcHJvdl9vdXRfb29iX2RvbmUsIG5vZGUpOw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSAzOiAvKiBJbnB1
dCBPT0IgKi8NCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKGFjdGlvbiA8
PSAyKSB7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNoX2dldF9yYW5k
b21fYnl0ZXMoJmluX29vYiwgc2l6ZW9mKGluX29vYikpOw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgaW5fb29iICU9IHBvd2VyX3RlbihzaXplKTsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoaW5fb29iX2Rpc3BsYXksICIlcyAlZCBvbiBk
ZXZpY2VcbiIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlu
X2FjdGlvblthY3Rpb25dLCBpbl9vb2IpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgcHV0X2JlMzIoaW5fb29iLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHByb3YtPnJhbmRfYXV0aCArDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZW9mKHByb3YtPnJhbmRfYXV0aCkg
LQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNp
emVvZih1aW50MzJfdCkpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7DQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1aW50OF90IGluX2FzY2lpWzldOw0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50IGkgPSBzaXplOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc2hfZ2V0X3JhbmRvbV9ieXRl
cyhpbl9hc2NpaSwgaSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgd2hpbGUgKGktLSkgew0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICBpbl9hc2NpaVtpXSA9DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgaW5fYXNjaWlbaV0gJSAoKDI2ICogMikgKyAxMCk7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpbl9hc2NpaVtpXSA+PSAxMCAr
IDI2KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IGluX2FzY2lpW2ldICs9ICdhJyAtICgxMCArIDI2KTsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoaW5fYXNjaWlbaV0gPj0gMTApDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5fYXNjaWlbaV0g
Kz0gJ0EnIC0gMTA7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IGVsc2UNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBpbl9hc2NpaVtpXSArPSAnMCc7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICB9DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbl9hc2NpaVtzaXplXSA9
ICdcMCc7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZW1jcHkocHJvdi0+
cmFuZF9hdXRoICsgMTYsIGluX2FzY2lpLCBzaXplKTsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIHNwcmludGYoaW5fb29iX2Rpc3BsYXksDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVudGVyICVzIG9uIGRldmljZVxuIiwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbl9h
c2NpaSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgfQ0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgIHJsX3ByaW50ZigiQWdlbnQgU3RyaW5nOiAlc1xuIiwgaW5fb29iX2Rpc3BsYXkp
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGFnZW50X291dHB1dF9yZXF1ZXN0KGluX29v
Yl9kaXNwbGF5KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAg
ICAgIH0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHJvdl9zZW5kX3B1Yl9rZXko
c3RydWN0IG1lc2hfbm9kZSAqbm9kZSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IHByb3Zf
ZGF0YSAqcHJvdiA9IG5vZGVfZ2V0X3Byb3Yobm9kZSk7DQo+ID4gKyAgICAgICB1aW50OF90IG91
dFs2Nl0gPSB7IFBST1hZX1BST1ZJU0lPTklOR19QRFUsIFBST1ZfUFVCX0tFWSB9Ow0KPiA+ICsg
ICAgICAgR0RCdXNSZXR1cm5GdW5jdGlvbiBjYiA9IE5VTEw7DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKHByb3YgPT0gTlVMTCkgcmV0dXJuOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChwcm92LT5j
b25mX2luLnN0YXJ0LnB1Yl9rZXkpDQo+ID4gKyAgICAgICAgICAgICAgIGNiID0gcHJvdl9jYWxj
X2VjZGg7DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KG91dCArIDIsIHByb3YtPmNvbmZfaW4u
cHJ2X3B1Yl9rZXksIDY0KTsNCj4gPiArICAgICAgIHByb3YtPnN0YXRlID0gUFJPVl9QVUJfS0VZ
Ow0KPiA+ICsgICAgICAgbWVzaF9nYXR0X3dyaXRlKHByb3YtPnByb3ZfaW4sIG91dCwgNjYsIGNi
LCBub2RlKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcHJvdl9vb2JfcHViX2tl
eShvb2JfdHlwZV90IHR5cGUsIHZvaWQgKmJ1ZiwgdWludDE2X3QgbGVuLA0KPiA+ICsgICAgICAg
ICAgICAgICB2b2lkICpub2RlKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgcHJvdl9kYXRh
ICpwcm92ID0gbm9kZV9nZXRfcHJvdihub2RlKTsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAocHJv
diA9PSBOVUxMKSByZXR1cm47DQo+ID4gKw0KPiA+ICsgICAgICAgbWVtY3B5KHByb3YtPmNvbmZf
aW4uZGV2X3B1Yl9rZXksIGJ1ZiwgNjQpOw0KPiA+ICsgICAgICAgcHJvdl9zZW5kX3B1Yl9rZXko
bm9kZSk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHByb3Zfc3RhcnRfY21wbHQo
REJ1c01lc3NhZ2UgKm1lc3NhZ2UsIHZvaWQgKm5vZGUpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0
cnVjdCBwcm92X2RhdGEgKnByb3YgPSBub2RlX2dldF9wcm92KG5vZGUpOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGlmIChwcm92ID09IE5VTEwpIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBpZiAo
cHJvdi0+Y29uZl9pbi5zdGFydC5wdWJfa2V5KQ0KPiA+ICsgICAgICAgICAgICAgICBhZ2VudF9p
bnB1dF9yZXF1ZXN0KEhFWEFERUNJTUFMLCA2NCwgcHJvdl9vb2JfcHViX2tleSwNCj4gbm9kZSk7
DQo+ID4gKyAgICAgICBlbHNlDQo+ID4gKyAgICAgICAgICAgICAgIHByb3Zfc2VuZF9wdWJfa2V5
KG5vZGUpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIHByb3ZfZGF0YV9yZWFkeShzdHJ1Y3Qg
bWVzaF9ub2RlICpub2RlLCB1aW50OF90ICpidWYsIHVpbnQ4X3QNCj4gbGVuKQ0KPiA+ICt7DQo+
ID4gKyAgICAgICBzdHJ1Y3QgcHJvdl9kYXRhICpwcm92ID0gbm9kZV9nZXRfcHJvdihub2RlKTsN
Cj4gPiArICAgICAgIHVpbnQ4X3Qgc2VjX2xldmVsID0gTUVTSF9QUk9WX1NFQ19ISUdIOw0KPiA+
ICsgICAgICAgdWludDhfdCBvdXRbMzVdID0geyBQUk9YWV9QUk9WSVNJT05JTkdfUERVIH07DQo+
ID4gKw0KPiA+ICsgICAgICAgaWYgKHByb3YgPT0gTlVMTCB8fCBsZW4gPCAyKSByZXR1cm4gZmFs
c2U7DQo+ID4gKw0KPiA+ICsgICAgICAgYnVmKys7DQo+ID4gKyAgICAgICBsZW4tLTsNCj4gPiAr
DQo+ID4gKyAgICAgICBybF9wcmludGYoIkdvdCBwcm92aXNpb25pbmcgZGF0YSAoJWQgYnl0ZXMp
XG4iLCBsZW4pOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChidWZbMF0gPiBQUk9WX0ZBSUxFRCB8
fCBleHBlY3RlZF9wZHVfc2l6ZVtidWZbMF1dICE9IGxlbikNCj4gPiArICAgICAgICAgICAgICAg
cmV0dXJuIHByb3ZfY29tcGxldGUobm9kZSwgUFJPVl9FUlJfSU5WQUxJRF9QRFUpOw0KPiA+ICsN
Cj4gPiArICAgICAgIHByaW50X2J5dGVfYXJyYXkoIlx0IiwgYnVmLCBsZW4pOw0KPiA+ICsNCj4g
PiArICAgICAgIGlmIChidWZbMF0gPT0gUFJPVl9GQUlMRUQpDQo+ID4gKyAgICAgICAgICAgICAg
IHJldHVybiBwcm92X2NvbXBsZXRlKG5vZGUsIGJ1ZlsxXSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
LyogQ2hlY2sgcHJvdmlzaW9uaW5nIHN0YXRlICovDQo+ID4gKyAgICAgICBzd2l0Y2ggKHByb3Yt
PnN0YXRlKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgcmV0dXJuIHByb3ZfY29tcGxldGUobm9kZSwgUFJPVl9FUlJfSU5WQUxJRF9Q
RFUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgY2FzZSBQUk9WX0lOVklURToNCj4gPiAr
DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKGJ1ZlswXSAhPSBQUk9WX0NBUFMpDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJvdl9jb21wbGV0ZShu
b2RlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
IFBST1ZfRVJSX0lOVkFMSURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgLyogTm9ybWFsaXplIHRvIGJlZ2lubmluZyBvZiBwYWNrZWQgUGFyYW0gc3RydWN0ICovDQo+
ID4gKyAgICAgICAgICAgICAgICAgICAgICAgYnVmKys7DQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgbGVuLS07DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIC8qIFNhdmUg
Q2FwYWJpbGl0eSB2YWx1ZXMgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtZW1jcHko
JnByb3YtPmNvbmZfaW4uY2FwcywgYnVmLCBsZW4pOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICBzZWNfbGV2ZWwgPSBtZXNoX2dhdHRfcHJvdl9zZWN1cml0eSgpOw0KPiA+ICsN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2VjX2xldmVsID09IE1FU0hfUFJPVl9T
RUNfSElHSCkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8q
IEVuZm9yY2UgSGlnaCBTZWN1cml0eSAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgaWYgKHByb3YtPmNvbmZfaW4uY2Fwcy5wdWJfdHlwZSAhPSAxICYmDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3YtPmNvbmZfaW4uY2Fwcy5zdGF0
aWNfdHlwZSAhPSAxKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICByZXR1cm4gcHJvdl9jb21wbGV0ZShub2RlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUFJPVl9FUlJfSU5WQUxJRF9QRFUpOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNlY19sZXZlbCA9
PSBNRVNIX1BST1ZfU0VDX01FRCkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIC8qIEVuZm9yY2UgTWVkaXVtIFNlY3VyaXR5ICovDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICBpZiAocHJvdi0+Y29uZl9pbi5jYXBzLnB1Yl90eXBlICE9IDEg
JiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdi0+Y29u
Zl9pbi5jYXBzLnN0YXRpY190eXBlICE9IDEgJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgcHJvdi0+Y29uZl9pbi5jYXBzLmlucHV0X3NpemUgPT0gMCAmJg0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm92LT5jb25mX2lu
LmNhcHMub3V0cHV0X3NpemUgPT0gMCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgcmV0dXJuIHByb3ZfY29tcGxldGUobm9kZSwNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBST1ZfRVJSX0lOVkFM
SURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgfQ0KPiA+ICsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAvKiBOdW0gRWxlbWVudHMgY2Fubm90IGJlIFplcm8g
Ki8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAocHJvdi0+Y29uZl9pbi5jYXBzLm51
bV9lbGUgPT0gMCkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBw
cm92X2NvbXBsZXRlKG5vZGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgUFJPVl9FUlJfSU5WQUxJRF9QRFUpOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAvKiBBbGwgbm9kZXMgbXVzdCBzdXBwb3J0IEFsZ29yaXRobSAweDAw
MDEgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAoIShnZXRfYmUxNihidWYgKyAx
KSAmIDB4MDAwMSkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4g
cHJvdl9jb21wbGV0ZShub2RlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIFBST1ZfRVJSX0lOVkFMSURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgLyogUHViIEtleSBhbmQgU3RhdGljIHR5cGUgbWF5IG5vdCBiZSA+
IDEgKi8NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBpZiAocHJvdi0+Y29uZl9pbi5jYXBz
LnB1Yl90eXBlID4gMHgwMSB8fA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICBwcm92LT5jb25mX2luLmNhcHMuc3RhdGljX3R5cGUgPiAweDAxKQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHByb3ZfY29tcGxldGUobm9kZSwNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQUk9WX0VS
Ul9JTlZBTElEX1BEVSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHByb3Yt
Pm5ld19hZGRyID0NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldF9vYnRh
aW5fYWRkcmVzcyhwcm92LT5jb25mX2luLmNhcHMubnVtX2VsZSk7DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIGlmICghcHJvdi0+bmV3X2FkZHIpDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJvdl9jb21wbGV0ZShub2RlLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBST1ZfRVJSX0lOVkFM
SURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgb3V0WzFdID0gUFJP
Vl9TVEFSVDsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcm92LT5jb25mX2luLnN0YXJ0
LmFsZ29yaXRobSA9IDA7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgcHJvdi0+Y29uZl9p
bi5zdGFydC5wdWJfa2V5ID0NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBy
b3YtPmNvbmZfaW4uY2Fwcy5wdWJfdHlwZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgLyogQ29tcG9zZSBTVEFSVCBiYXNlZCBvbiBtb3N0IHNlY3VyZSB2YWx1ZXMgKi8NCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBpZiAocHJvdi0+Y29uZl9pbi5jYXBzLnN0YXRpY190
eXBlKSB7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdi0+
Y29uZl9pbi5zdGFydC5hdXRoX21ldGhvZCA9DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIFBST1ZfU1RBVElDX09PQjsNCj4gPiArDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgfSBlbHNlIGlmIChwcm92LT5jb25mX2luLmNhcHMub3V0cHV0X3NpemUgPg0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm92LT5jb25mX2lu
LmNhcHMuaW5wdXRfc2l6ZSkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHByb3YtPmNvbmZfaW4uc3RhcnQuYXV0aF9tZXRob2QgPQ0KPiA+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQUk9WX09VVFBVVF9PT0I7DQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICBwcm92LT5jb25mX2luLnN0YXJ0LmF1dGhfYWN0aW9u
ID0NCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdTE2X2hpZ2hl
c3RfYml0KGdldF9iZTE2KGJ1ZiArIDYpKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHByb3YtPmNvbmZfaW4uc3RhcnQuYXV0aF9zaXplID0NCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdi0+Y29uZl9pbi5jYXBzLm91dHB1dF9zaXpl
Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHByb3YtPmNv
bmZfaW4uY2Fwcy5pbnB1dF9zaXplID4gMCkgew0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgIHByb3YtPmNvbmZfaW4uc3RhcnQuYXV0aF9tZXRob2QgPQ0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQUk9WX0lOUFVUX09PQjsNCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3YtPmNvbmZfaW4uc3RhcnQuYXV0
aF9hY3Rpb24gPQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1
MTZfaGlnaGVzdF9iaXQoZ2V0X2JlMTYoYnVmICsgOSkpOw0KPiA+ICsgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgcHJvdi0+Y29uZl9pbi5zdGFydC5hdXRoX3NpemUgPQ0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm92LT5jb25mX2luLmNhcHMuaW5w
dXRfc2l6ZTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgIC8qIFJhbmdlIENoZWNrIFNUQVJUIHZhbHVlcyAqLw0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIGlmIChwcm92LT5jb25mX2luLnN0YXJ0LmF1dGhfc2l6ZSA+
IDgpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJvdl9jb21w
bGV0ZShub2RlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIFBST1ZfRVJSX0lOVkFMSURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAg
ICAgICAgICAgcHJvdi0+c3RhdGUgPSBQUk9WX1NUQVJUOw0KPiA+ICsNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICBtZW1jcHkob3V0ICsgMiwgJnByb3YtPmNvbmZfaW4uc3RhcnQsIDUpOw0K
PiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBlY2NfbWFrZV9rZXkocHJvdi0+Y29u
Zl9pbi5wcnZfcHViX2tleSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgcHJvdi0+ZXBoX3ByaXZfa2V5KTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICAg
ICAgICAgLyogU3dhcCBwdWJsaWMga2V5IHRvIHNoYXJlIGludG8gTWVzaCBieXRlIG9yZGVyaW5n
ICovDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgc3dhcF91MjU2X2J5dGVzKHByb3YtPmNv
bmZfaW4ucHJ2X3B1Yl9rZXkpOw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHN3YXBfdTI1
Nl9ieXRlcyhwcm92LT5jb25mX2luLnBydl9wdWJfa2V5ICsgMzIpOw0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWVzaF9nYXR0X3dyaXRlKHByb3YtPnByb3ZfaW4s
IG91dCwgNywNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJv
dl9zdGFydF9jbXBsdCwgbm9kZSk7DQo+ID4gKw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAg
Y2FzZSBQUk9WX1BVQl9LRVk6DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgaWYgKGJ1Zlsw
XSA9PSBQUk9WX1BVQl9LRVkgJiYNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIXByb3YtPmNvbmZfaW4uc3RhcnQucHViX2tleSkgew0KPiA+ICsNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lbWNweShwcm92LT5jb25mX2luLmRldl9wdWJf
a2V5LCBidWYgKyAxLCA2NCk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBw
cm92X2NhbGNfZWNkaChOVUxMLCBub2RlKTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICB9
IGVsc2UgaWYgKGJ1ZlswXSA9PSBQUk9WX0lOUF9DTVBMVCkgew0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgYWdlbnRfb3V0cHV0X3JlcXVlc3RfY2FuY2VsKCk7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJvdl9zZW5kX2NvbmZpcm0obm9k
ZSk7DQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlDQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJvdl9jb21wbGV0ZShub2RlLA0KPiA+ICsgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBST1ZfRVJSX0lOVkFM
SURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGNhc2UgUFJPVl9DT05GSVJNOg0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChidWZbMF0gIT0gUFJPVl9DT05GSVJNKQ0K
PiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHByb3ZfY29tcGxldGUo
bm9kZSwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBQUk9WX0VSUl9JTlZBTElEX1BEVSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICAgICAg
ICAgIG1lbWNweShwcm92LT5tZXNoX2NvbmYsIGJ1ZiArIDEsIDE2KTsNCj4gPiArDQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgb3V0WzFdID0gUFJPVl9SQU5ET007DQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgbWVtY3B5KG91dCArIDIsIHByb3YtPnJhbmRfYXV0aCwgMTYpOw0KPiA+
ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBwcm92LT5zdGF0ZSA9IFBST1ZfUkFORE9N
Ow0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBtZXNoX2dhdHRfd3JpdGUocHJv
di0+cHJvdl9pbiwgb3V0LCAxOCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgTlVMTCwgbm9kZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgICBjYXNlIFBS
T1ZfUkFORE9NOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChidWZbMF0gIT0gUFJP
Vl9SQU5ET00pDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJv
dl9jb21wbGV0ZShub2RlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgIFBST1ZfRVJSX0lOVkFMSURfUERVKTsNCj4gPiArDQo+ID4gKyAgICAgICAg
ICAgICAgICAgICAgICAgLyogQ2FsY3VsYXRlIE5ldyBTYWx0IHdoaWxlIHdlIHN0aWxsIGhhdmUN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgKiBib3RoIHJhbmRvbSB2YWx1ZXMgKi8NCj4g
PiArICAgICAgICAgICAgICAgICAgICAgICBtZXNoX2NyeXB0b19wcm92X3Byb3Zfc2FsdChwcm92
LT5zYWx0LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgcHJvdi0+cmFuZF9hdXRoLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnVmICsgMSwNCj4gPiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3YtPnNhbHQp
Ow0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAvKiBDYWxjdWxhdGUgbWVzaHMg
Q29uZiBWYWx1ZSAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIG1lbWNweShwcm92LT5y
YW5kX2F1dGgsIGJ1ZiArIDEsIDE2KTsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBtZXNo
X2NyeXB0b19hZXNfY21hYyhwcm92LT5jb25mX2tleSwgcHJvdi0+cmFuZF9hdXRoLA0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZW9mKHByb3YtPnJhbmRfYXV0aCksIG91
dCArIDEpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAvKiBWYWxpZGF0ZSBN
ZXNoIGNvbmZpcm1hdGlvbiAqLw0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChtZW1j
bXAob3V0ICsgMSwgcHJvdi0+bWVzaF9jb25mLCAxNikgIT0gMCkNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgIHJldHVybiBwcm92X2NvbXBsZXRlKG5vZGUsDQo+ID4gKyAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUFJPVl9FUlJfSU5WQUxJ
RF9QRFUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIkNv
bmZpcm1hdGlvbiBWYWxpZGF0ZWRcbiIpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAgICAgICAg
ICAgICBwcm92X3NlbmRfcHJvdl9kYXRhKG5vZGUpOw0KPiA+ICsNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICByZXR1cm4gdHJ1ZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgIGNhc2Ug
UFJPVl9EQVRBOg0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGlmIChidWZbMF0gIT0gUFJP
Vl9DT01QTEVURSkNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBw
cm92X2NvbXBsZXRlKG5vZGUsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgUFJPVl9FUlJfSU5WQUxJRF9QRFUpOw0KPiA+ICsNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICByZXR1cm4gcHJvdl9jb21wbGV0ZShub2RlLCAwKTsNCj4gPiArICAg
ICAgIH0NCj4gPiArDQo+ID4gKw0KPiA+ICsNCj4gPiArICAgICAgIC8qIENvbXBvc2UgYXBwcm9w
cmlhdGUgcmVwbHkgZm9yIHRoZSBwcm92IHN0YXRlIG1lc3NhZ2UgKi8NCj4gPiArICAgICAgIC8q
IFNlbmQgcmVwbHkgdmlhIG1lc2hfZ2F0dF93cml0ZSgpICovDQo+ID4gKyAgICAgICAvKiBJZiBk
b25lLCBjYWxsIHByb3ZfZG9uZSBjYWxsbGJhY2sgYW5kIGZyZWUgcHJvdiBob3VzZWtlZXBpbmcg
ZGF0YQ0KPiAqLw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCJHb3QgcHJvdmlzaW9uaW5nIGRhdGEg
KCVkIGJ5dGVzKVxuIiwgbGVuKTsNCj4gPiArICAgICAgIHByaW50X2J5dGVfYXJyYXkoIlx0Iiwg
YnVmLCBsZW4pOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4g
Kw0KPiA+ICtib29sIHByb3ZfY29tcGxldGUoc3RydWN0IG1lc2hfbm9kZSAqbm9kZSwgdWludDhf
dCBzdGF0dXMpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBwcm92X2RhdGEgKnByb3YgPSBu
b2RlX2dldF9wcm92KG5vZGUpOw0KPiA+ICsgICAgICAgdm9pZCAqdXNlcl9kYXRhOw0KPiA+ICsg
ICAgICAgcHJvdmlzaW9uX2RvbmVfY2IgY2I7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHByb3Yg
PT0gTlVMTCkgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChzdGF0dXMgJiYg
cHJvdi0+bmV3X2FkZHIgJiYgcHJvdi0+Y29uZl9pbi5jYXBzLm51bV9lbGUpIHsNCj4gPiArICAg
ICAgICAgICAgICAgbmV0X3JlbGVhc2VfYWRkcmVzcyhwcm92LT5uZXdfYWRkciwgcHJvdi0NCj4g
PmNvbmZfaW4uY2Fwcy5udW1fZWxlKTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAg
ICBpZiAoIXN0YXR1cykgew0KPiA+ICsgICAgICAgICAgICAgICBub2RlX3NldF9udW1fZWxlbWVu
dHMobm9kZSwgcHJvdi0+Y29uZl9pbi5jYXBzLm51bV9lbGUpOw0KPiA+ICsgICAgICAgICAgICAg
ICBub2RlX3NldF9wcmltYXJ5KG5vZGUsIHByb3YtPm5ld19hZGRyKTsNCj4gPiArICAgICAgICAg
ICAgICAgbm9kZV9zZXRfZGV2aWNlX2tleShub2RlLCBwcm92LT5kZXZfa2V5KTsNCj4gPiArICAg
ICAgICAgICAgICAgbm9kZV9uZXRfa2V5X2FkZChub2RlLCBwcm92LT5uZXRfaWR4KTsNCj4gPiAr
ICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICB1c2VyX2RhdGEgPSBwcm92LT51c2VyX2RhdGE7
DQo+ID4gKyAgICAgICBjYiA9IHByb3YtPnByb3ZfZG9uZTsNCj4gPiArICAgICAgIGdfZnJlZShw
cm92KTsNCj4gPiArICAgICAgIG5vZGVfc2V0X3Byb3Yobm9kZSwgTlVMTCk7DQo+ID4gKyAgICAg
ICBpZiAoY2IpIGNiKHVzZXJfZGF0YSwgc3RhdHVzKTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1
cm4gdHJ1ZTsNCj4gPiArfQ0KPiA+IGRpZmYgLS1naXQgYS9tZXNoL3V0aWwuYyBiL21lc2gvdXRp
bC5jDQo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi5jYjI0MWIz
DQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL21lc2gvdXRpbC5jDQo+ID4gQEAgLTAsMCAr
MSwzNjkgQEANCj4gPiArLyoNCj4gPiArICoNCj4gPiArICogIEJsdWVaIC0gQmx1ZXRvb3RoIHBy
b3RvY29sIHN0YWNrIGZvciBMaW51eA0KPiA+ICsgKg0KPiA+ICsgKiAgQ29weXJpZ2h0IChDKSAy
MDE3ICBJbnRlbCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC4NCj4gPiArICoNCj4g
PiArICoNCj4gPiArICogIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJl
ZGlzdHJpYnV0ZSBpdCBhbmQvb3INCj4gPiArICogIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMg
b2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExpY2Vuc2UgYXMgcHVi
bGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlcg0KPiA+ICsgKiAg
dmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVy
IHZlcnNpb24uDQo+ID4gKyAqDQo+ID4gKyAqICBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQg
aW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwNCj4gPiArICogIGJ1dCBXSVRIT1VU
IEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQo+ID4g
KyAqICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0Uu
ICBTZWUgdGhlDQo+IEdOVQ0KPiA+ICsgKiAgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2Ug
Zm9yIG1vcmUgZGV0YWlscy4NCj4gPiArICoNCj4gPiArICogIFlvdSBzaG91bGQgaGF2ZSByZWNl
aXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMNCj4gPiArICogIExp
Y2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUg
U29mdHdhcmUNCj4gPiArICogIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0LCBGaWZ0
aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMQ0KPiBVU0ENCj4gPiArICoNCj4gPiArICov
DQo+ID4gKw0KPiA+ICsjaWZkZWYgSEFWRV9DT05GSUdfSA0KPiA+ICsjaW5jbHVkZSA8Y29uZmln
Lmg+DQo+ID4gKyNlbmRpZg0KPiA+ICsNCj4gPiArI2luY2x1ZGUgPHN0ZGlvLmg+DQo+ID4gKyNp
bmNsdWRlIDxzdGRib29sLmg+DQo+ID4gKyNpbmNsdWRlIDxpbnR0eXBlcy5oPg0KPiA+ICsjaW5j
bHVkZSA8cmVhZGxpbmUvcmVhZGxpbmUuaD4NCj4gPiArI2luY2x1ZGUgPGdsaWIuaD4NCj4gPiAr
DQo+ID4gKyNpbmNsdWRlICJjbGllbnQvZGlzcGxheS5oIg0KPiA+ICsjaW5jbHVkZSAic3JjL3No
YXJlZC91dGlsLmgiDQo+ID4gKyNpbmNsdWRlICJtZXNoLW5ldC5oIg0KPiA+ICsjaW5jbHVkZSAi
dXRpbC5oIg0KPiA+ICsNCj4gPiArc3RydWN0IGNtZF9tZW51IHsNCj4gPiArICAgICAgIGNvbnN0
IGNoYXIgKm5hbWU7DQo+ID4gKyAgICAgICBjb25zdCBzdHJ1Y3QgbWVudV9lbnRyeSAqdGFibGU7
DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lbnVfZW50cnkgKm1haW5fY21k
X3RhYmxlOw0KPiA+ICtzdGF0aWMgc3RydWN0IG1lbnVfZW50cnkgKmN1cnJlbnRfY21kX3RhYmxl
Ow0KPiA+ICtzdGF0aWMgR0xpc3QgKm1lbnVfbGlzdDsNCj4gPiArDQo+ID4gK3N0YXRpYyBjaGFy
ICptYWluX21lbnVfcHJvbXB0Ow0KPiA+ICtzdGF0aWMgaW50IG1haW5fbWVudV9wb2ludDsNCj4g
PiArDQo+ID4gK3N0YXRpYyBpbnQgbWF0Y2hfbWVudV9uYW1lKGNvbnN0IHZvaWQgKmEsIGNvbnN0
IHZvaWQgKmIpDQo+ID4gK3sNCj4gPiArICAgICAgIGNvbnN0IHN0cnVjdCBjbWRfbWVudSAqbWVu
dSA9IGE7DQo+ID4gKyAgICAgICBjb25zdCBjaGFyICpuYW1lID0gYjsNCj4gPiArDQo+ID4gKyAg
ICAgICByZXR1cm4gc3RyY2FzZWNtcChtZW51LT5uYW1lLCBuYW1lKTsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiArYm9vbCBjbWRfbWVudV9pbml0KGNvbnN0IHN0cnVjdCBtZW51X2VudHJ5ICpjbWRfdGFi
bGUpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCBjbWRfbWVudSAqbWVudTsNCj4gPiArDQo+
ID4gKyAgICAgICBpZiAobWFpbl9jbWRfdGFibGUpIHsNCj4gPiArICAgICAgICAgICAgICAgcmxf
cHJpbnRmKCJNYWluIG1lbnUgYWxyZWFkeSByZWdpc3RlcmVkXG4iKTsNCj4gPiArICAgICAgICAg
ICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIG1l
bnUgPSBnX21hbGxvYyhzaXplb2Yoc3RydWN0IGNtZF9tZW51KSk7DQo+ID4gKyAgICAgICBpZiAo
IW1lbnUpDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAg
ICAgICBtZW51LT5uYW1lID0gIm1lc2hjdGwiOw0KPiA+ICsgICAgICAgbWVudS0+dGFibGUgPSBj
bWRfdGFibGU7DQo+ID4gKyAgICAgICBtZW51X2xpc3QgPSBnX2xpc3RfYXBwZW5kKG1lbnVfbGlz
dCwgbWVudSk7DQo+ID4gKyAgICAgICBtYWluX2NtZF90YWJsZSA9IChzdHJ1Y3QgbWVudV9lbnRy
eSAqKSBjbWRfdGFibGU7DQo+ID4gKyAgICAgICBjdXJyZW50X2NtZF90YWJsZSA9IChzdHJ1Y3Qg
bWVudV9lbnRyeSAqKSBtYWluX2NtZF90YWJsZTsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4g
dHJ1ZTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBjbWRfbWVudV9tYWluKGJvb2wgZm9yY2Vk
KQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjdXJyZW50X2NtZF90YWJsZSA9IG1haW5fY21kX3RhYmxl
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmICghZm9yY2VkKSB7DQo+ID4gKyAgICAgICAgICAgICAg
IHJsX3NldF9wcm9tcHQobWFpbl9tZW51X3Byb21wdCk7DQo+ID4gKyAgICAgICAgICAgICAgIHJs
X3JlcGxhY2VfbGluZSgiIiwgMCk7DQo+ID4gKyAgICAgICAgICAgICAgIHJsX3BvaW50ID0gbWFp
bl9tZW51X3BvaW50Ow0KPiA+ICsgICAgICAgICAgICAgICBybF9yZWRpc3BsYXkoKTsNCj4gPiAr
ICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBnX2ZyZWUobWFpbl9tZW51X3Byb21wdCk7DQo+
ID4gKyAgICAgICBtYWluX21lbnVfcHJvbXB0ID0gTlVMTDsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
Ym9vbCBhZGRfY21kX21lbnUoY29uc3QgY2hhciAqbmFtZSwgY29uc3Qgc3RydWN0IG1lbnVfZW50
cnkNCj4gKmNtZF90YWJsZSkNCj4gPiArew0KPiA+ICsgICAgICAgc3RydWN0IGNtZF9tZW51ICpt
ZW51Ow0KPiA+ICsgICAgICAgR0xpc3QgKmw7DQo+ID4gKw0KPiA+ICsgICAgICAgbCA9IGdfbGlz
dF9maW5kX2N1c3RvbShtZW51X2xpc3QsIG5hbWUsIG1hdGNoX21lbnVfbmFtZSk7DQo+ID4gKyAg
ICAgICBpZiAobCkgew0KPiA+ICsgICAgICAgICAgICAgICBtZW51ID0gbC0+ZGF0YTsNCj4gPiAr
ICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJtZW51IFwiJXNcIiBhbHJlYWR5IHJlZ2lzdGVyZWRc
biIsIG1lbnUtPm5hbWUpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4g
KyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAgbWVudSA9IGdfbWFsbG9jKHNpemVvZihzdHJ1
Y3QgY21kX21lbnUpKTsNCj4gPiArICAgICAgIGlmICghbWVudSkNCj4gPiArICAgICAgICAgICAg
ICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIG1lbnUtPm5hbWUgPSBuYW1lOw0K
PiA+ICsgICAgICAgbWVudS0+dGFibGUgPSBjbWRfdGFibGU7DQo+ID4gKyAgICAgICBtZW51X2xp
c3QgPSBnX2xpc3RfYXBwZW5kKG1lbnVfbGlzdCwgbWVudSk7DQo+ID4gKw0KPiA+ICsgICAgICAg
cmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgc2V0X21lbnVfcHJvbXB0KGNv
bnN0IGNoYXIgKm5hbWUsIGNvbnN0IGNoYXIgKmlkKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBjaGFy
ICpwcm9tcHQ7DQo+ID4gKw0KPiA+ICsgICAgICAgcHJvbXB0ID0gZ19zdHJkdXBfcHJpbnRmKENP
TE9SX0JMVUUgIlslcyVzJXNdIiBDT0xPUl9PRkYgIiMgIiwNCj4gbmFtZSwNCj4gPiArICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQgPyAiOiBUYXJnZXQgPSAiIDogIiIs
IGlkID8gaWQgOiAiIik7DQo+ID4gKyAgICAgICBybF9zZXRfcHJvbXB0KHByb21wdCk7DQo+ID4g
KyAgICAgICBnX2ZyZWUocHJvbXB0KTsNCj4gPiArICAgICAgIHJsX29uX25ld19saW5lKCk7DQo+
ID4gK30NCj4gPiArDQo+ID4gK2Jvb2wgc3dpdGNoX2NtZF9tZW51KGNvbnN0IGNoYXIgKm5hbWUp
DQo+ID4gK3sNCj4gPiArICAgICAgIEdMaXN0ICpsOw0KPiA+ICsgICAgICAgc3RydWN0IGNtZF9t
ZW51ICptZW51Ow0KPiA+ICsNCj4gPiArICAgICAgIGwgPSBnX2xpc3RfZmluZF9jdXN0b20obWVu
dV9saXN0LCBuYW1lLCBtYXRjaF9tZW51X25hbWUpOw0KPiA+ICsgICAgICAgaWYoIWwpDQo+ID4g
KyAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICBtZW51ID0g
bC0+ZGF0YTsNCj4gPiArICAgICAgIGN1cnJlbnRfY21kX3RhYmxlID0gKHN0cnVjdCBtZW51X2Vu
dHJ5ICopIG1lbnUtPnRhYmxlOw0KPiA+ICsNCj4gPiArICAgICAgIG1haW5fbWVudV9wb2ludCA9
IHJsX3BvaW50Ow0KPiA+ICsgICAgICAgbWFpbl9tZW51X3Byb21wdCA9IGdfc3RyZHVwKHJsX3By
b21wdCk7DQo+ID4gKw0KPiA+ICsgICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+
ID4gK3ZvaWQgcHJvY2Vzc19tZW51X2NtZChjb25zdCBjaGFyICpjbWQsIGNvbnN0IGNoYXIgKmFy
ZykNCj4gPiArew0KPiA+ICsgICAgICAgaW50IGk7DQo+ID4gKyAgICAgICBpbnQgbGVuOw0KPiA+
ICsgICAgICAgc3RydWN0IG1lbnVfZW50cnkgKmNtZF90YWJsZSA9IGN1cnJlbnRfY21kX3RhYmxl
Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmICghY3VycmVudF9jbWRfdGFibGUpDQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybjsNCj4gPiArDQo+ID4gKyAgICAgICBsZW4gPSBzdHJsZW4oY21kKTsN
Cj4gPiArDQo+ID4gKyAgICAgICBmb3IgKGkgPSAwOyBjbWRfdGFibGVbaV0uY21kOyBpKyspIHsN
Cj4gPiArICAgICAgICAgICAgICAgaWYgKHN0cm5jbXAoY21kLCBjbWRfdGFibGVbaV0uY21kLCBs
ZW4pKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOw0KPiA+ICsNCj4gPiAr
ICAgICAgICAgICAgICAgaWYgKGNtZF90YWJsZVtpXS5mdW5jKSB7DQo+ID4gKyAgICAgICAgICAg
ICAgICAgICAgICAgY21kX3RhYmxlW2ldLmZ1bmMoYXJnKTsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICByZXR1cm47DQo+ID4gKyAgICAgICAgICAgICAgIH0NCj4gPiArICAgICAgIH0NCj4g
PiArDQo+ID4gKyAgICAgICBpZiAoc3RybmNtcChjbWQsICJoZWxwIiwgbGVuKSkgew0KPiA+ICsg
ICAgICAgICAgICAgICBybF9wcmludGYoIkludmFsaWQgY29tbWFuZFxuIik7DQo+ID4gKyAgICAg
ICAgICAgICAgIHJldHVybjsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBwcmlu
dF9jbWRfbWVudShjbWRfdGFibGUpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICt2b2lkIHByaW50X2Nt
ZF9tZW51KGNvbnN0IHN0cnVjdCBtZW51X2VudHJ5ICpjbWRfdGFibGUpDQo+ID4gK3sNCj4gPiAr
ICAgICAgIGludCBpOw0KPiA+ICsNCj4gPiArICAgICAgIHJsX3ByaW50ZigiQXZhaWxhYmxlIGNv
bW1hbmRzOlxuIik7DQo+ID4gKw0KPiA+ICsgICAgICAgZm9yIChpID0gMDsgY21kX3RhYmxlW2ld
LmNtZDsgaSsrKSB7DQo+ID4gKyAgICAgICAgICAgICAgIGlmIChjbWRfdGFibGVbaV0uZGVzYykN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICBybF9wcmludGYoIiAgJXMgJS0qcyAlc1xuIiwg
Y21kX3RhYmxlW2ldLmNtZCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgKGludCkoNDAgLSBzdHJsZW4oY21kX3RhYmxlW2ldLmNtZCkpLA0KPiA+ICsgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbWRfdGFibGVbaV0uYXJnID8gOiAiIiwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY21kX3RhYmxlW2ld
LmRlc2MgPyA6ICIiKTsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gK30NCj4gPiArDQo+ID4g
K3ZvaWQgY21kX21lbnVfY2xlYW51cCh2b2lkKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBtYWluX2Nt
ZF90YWJsZSA9IE5VTEw7DQo+ID4gKyAgICAgICBjdXJyZW50X2NtZF90YWJsZSA9IE5VTEw7DQo+
ID4gKw0KPiA+ICsgICAgICAgZ19saXN0X2ZyZWVfZnVsbChtZW51X2xpc3QsIGdfZnJlZSk7DQo+
ID4gK30NCj4gPiArDQo+ID4gK3ZvaWQgcHJpbnRfYnl0ZV9hcnJheShjb25zdCBjaGFyICpwcmVm
aXgsIGNvbnN0IHZvaWQgKnB0ciwgaW50IGxlbikNCj4gPiArew0KPiA+ICsgICAgICAgY29uc3Qg
dWludDhfdCAqZGF0YSA9IHB0cjsNCj4gPiArICAgICAgIGNoYXIgKmxpbmUsICpieXRlczsNCj4g
PiArICAgICAgIGludCBpOw0KPiA+ICsNCj4gPiArICAgICAgIGxpbmUgPSBnX21hbGxvYyhzdHJs
ZW4ocHJlZml4KSArICgxNiAqIDMpICsgMik7DQo+ID4gKyAgICAgICBzcHJpbnRmKGxpbmUsICIl
cyAiLCBwcmVmaXgpOw0KPiA+ICsgICAgICAgYnl0ZXMgPSBsaW5lICsgc3RybGVuKHByZWZpeCkg
KyAxOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47ICsraSkgew0KPiA+
ICsgICAgICAgICAgICAgICBzcHJpbnRmKGJ5dGVzLCAiJTIuMnggIiwgZGF0YVtpXSk7DQo+ID4g
KyAgICAgICAgICAgICAgIGlmICgoaSArIDEpICUgMTYpIHsNCj4gPiArICAgICAgICAgICAgICAg
ICAgICAgICBieXRlcyArPSAzOw0KPiA+ICsgICAgICAgICAgICAgICB9IGVsc2Ugew0KPiA+ICsg
ICAgICAgICAgICAgICAgICAgICAgIHJsX3ByaW50ZigiXHIlc1xuIiwgbGluZSk7DQo+ID4gKyAg
ICAgICAgICAgICAgICAgICAgICAgYnl0ZXMgPSBsaW5lICsgc3RybGVuKHByZWZpeCkgKyAxOw0K
PiA+ICsgICAgICAgICAgICAgICB9DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsgICAgICAg
aWYgKGkgJSAxNikNCj4gPiArICAgICAgICAgICAgICAgcmxfcHJpbnRmKCJcciVzXG4iLCBsaW5l
KTsNCj4gPiArDQo+ID4gKyAgICAgICBnX2ZyZWUobGluZSk7DQo+ID4gK30NCj4gPiArDQo+ID4g
K2Jvb2wgc3RyMmhleChjb25zdCBjaGFyICpzdHIsIHVpbnQxNl90IGluX2xlbiwgdWludDhfdCAq
b3V0LA0KPiA+ICsgICAgICAgICAgICAgICB1aW50MTZfdCBvdXRfbGVuKQ0KPiA+ICt7DQo+ID4g
KyAgICAgICB1aW50MTZfdCBpOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChpbl9sZW4gPCBvdXRf
bGVuICogMikNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiAr
ICAgICAgIGZvciAoaSA9IDA7IGkgPCBvdXRfbGVuOyBpKyspIHsNCj4gPiArICAgICAgICAgICAg
ICAgaWYgKHNzY2FuZigmc3RyW2kgKiAyXSwgIiUwMmhoeCIsICZvdXRbaV0pICE9IDEpDQo+ID4g
KyAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KPiA+ICsgICAgICAgfQ0KPiA+
ICsNCj4gPiArICAgICAgIHJldHVybiB0cnVlOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzaXplX3Qg
aGV4MnN0cih1aW50OF90ICppbiwgc2l6ZV90IGluX2xlbiwgY2hhciAqb3V0LA0KPiA+ICsgICAg
ICAgICAgICAgICBzaXplX3Qgb3V0X2xlbikNCj4gPiArew0KPiA+ICsgICAgICAgc3RhdGljIGNv
bnN0IGNoYXIgaGV4ZGlnaXRzW10gPSAiMDEyMzQ1Njc4OWFiY2RlZiI7DQo+ID4gKyAgICAgICBz
aXplX3QgaTsNCj4gPiArDQo+ID4gKyAgICAgICBpZihpbl9sZW4gKiAyID4gb3V0X2xlbiAtIDEp
DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAwOw0KPiA+ICsNCj4gPiArICAgICAgIGZvciAo
aSA9IDA7IGkgPCBpbl9sZW47IGkrKykgew0KPiA+ICsgICAgICAgICAgICAgICBvdXRbaSAqIDJd
ID0gaGV4ZGlnaXRzW2luW2ldID4+IDRdOw0KPiA+ICsgICAgICAgICAgICAgICBvdXRbaSAqIDIg
KyAxXSA9IGhleGRpZ2l0c1tpbltpXSAmIDB4Zl07DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+
ICsgICAgICAgb3V0W2luX2xlbiAqIDJdID0gJ1wwJzsNCj4gPiArICAgICAgIHJldHVybiBpOw0K
PiA+ICt9DQo+ID4gKw0KPiA+ICt1aW50MTZfdCBtZXNoX29wY29kZV9zZXQodWludDMyX3Qgb3Bj
b2RlLCB1aW50OF90ICpidWYpDQo+ID4gK3sNCj4gPiArICAgICAgIGlmIChvcGNvZGUgPD0gMHg3
ZSkgew0KPiA+ICsgICAgICAgICAgICAgICBidWZbMF0gPSBvcGNvZGU7DQo+ID4gKyAgICAgICAg
ICAgICAgIHJldHVybiAxOw0KPiA+ICsgICAgICAgfSBlbHNlIGlmIChvcGNvZGUgPj0gMHg4MDAw
ICYmIG9wY29kZSA8PSAweGJmZmYpIHsNCj4gPiArICAgICAgICAgICAgICAgcHV0X2JlMTYob3Bj
b2RlLCBidWYpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gMjsNCj4gPiArICAgICAgIH0g
ZWxzZSBpZiAob3Bjb2RlID49IDB4YzAwMDAwICYmIG9wY29kZSA8PSAweGZmZmZmZikgew0KPiA+
ICsgICAgICAgICAgICAgICBidWZbMF0gPSAob3Bjb2RlID4+IDE2KSAmIDB4ZmY7DQo+ID4gKyAg
ICAgICAgICAgICAgIHB1dF9iZTE2KG9wY29kZSwgYnVmICsgMSk7DQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiAzOw0KPiA+ICsgICAgICAgfSBlbHNlIHsNCj4gPiArICAgICAgICAgICAgICAg
cmxfcHJpbnRmKCJJbGxlZ2FsIE9wY29kZSAleCIsIG9wY29kZSk7DQo+ID4gKyAgICAgICAgICAg
ICAgIHJldHVybiAwOw0KPiA+ICsgICAgICAgfQ0KPiA+ICt9DQo+ID4gKw0KPiA+ICtib29sIG1l
c2hfb3Bjb2RlX2dldChjb25zdCB1aW50OF90ICpidWYsIHVpbnQxNl90IHN6LCB1aW50MzJfdA0K
PiAqb3Bjb2RlLCBpbnQgKm4pDQo+ID4gK3sNCj4gPiArICAgICAgIGlmICghbiB8fCAhb3Bjb2Rl
IHx8IHN6IDwgMSkgcmV0dXJuIGZhbHNlOw0KPiA+ICsNCj4gPiArICAgICAgIHN3aXRjaCAoYnVm
WzBdICYgMHhjMCkgew0KPiA+ICsgICAgICAgY2FzZSAweDAwOg0KPiA+ICsgICAgICAgY2FzZSAw
eDQwOg0KPiA+ICsgICAgICAgICAgICAgICAvKiBSRlUgKi8NCj4gPiArICAgICAgICAgICAgICAg
aWYgKGJ1ZlswXSA9PSAweDdmKQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBm
YWxzZTsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICAgICpuID0gMTsNCj4gPiArICAgICAgICAg
ICAgICAgKm9wY29kZSA9IGJ1ZlswXTsNCj4gPiArICAgICAgICAgICAgICAgYnJlYWs7DQo+ID4g
Kw0KPiA+ICsgICAgICAgY2FzZSAweDgwOg0KPiA+ICsgICAgICAgICAgICAgICBpZiAoc3ogPCAy
KQ0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCj4gPiArDQo+ID4g
KyAgICAgICAgICAgICAgICpuID0gMjsNCj4gPiArICAgICAgICAgICAgICAgKm9wY29kZSA9IGdl
dF9iZTE2KGJ1Zik7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAg
ICAgIGNhc2UgMHhjMDoNCj4gPiArICAgICAgICAgICAgICAgaWYgKHN6IDwgMykNCj4gPiArICAg
ICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKw0KPiA+ICsgICAgICAgICAg
ICAgICAqbiA9IDM7DQo+ID4gKyAgICAgICAgICAgICAgICpvcGNvZGUgPSBnZXRfYmUxNihidWYg
KyAxKTsNCj4gPiArICAgICAgICAgICAgICAgKm9wY29kZSB8PSBidWZbMF0gPDwgMTY7DQo+ID4g
KyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4g
KyAgICAgICAgICAgICAgIHJsX3ByaW50ZigiQmFkIFBhY2tldDpcbiIpOw0KPiA+ICsgICAgICAg
ICAgICAgICBwcmludF9ieXRlX2FycmF5KCJcdCIsICh2b2lkICopIGJ1Ziwgc3opOw0KPiA+ICsg
ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQo+ID4gKyAgICAgICB9DQo+ID4gKw0KPiA+ICsg
ICAgICAgcmV0dXJuIHRydWU7DQo+ID4gK30NCj4gPiArDQo+ID4gK2NvbnN0IGNoYXIgKm1lc2hf
c3RhdHVzX3N0cih1aW50OF90IHN0YXR1cykNCj4gPiArew0KPiA+ICsgICAgICAgc3dpdGNoIChz
dGF0dXMpIHsNCj4gPiArICAgICAgIGNhc2UgTUVTSF9TVEFUVVNfU1VDQ0VTUzogcmV0dXJuICJT
dWNjZXNzIjsNCj4gPiArICAgICAgIGNhc2UgTUVTSF9TVEFUVVNfSU5WQUxJRF9BRERSRVNTOiBy
ZXR1cm4gIkludmFsaWQgQWRkcmVzcyI7DQo+ID4gKyAgICAgICBjYXNlIE1FU0hfU1RBVFVTX0lO
VkFMSURfTU9ERUw6IHJldHVybiAiSW52YWxpZCBNb2RlbCI7DQo+ID4gKyAgICAgICBjYXNlIE1F
U0hfU1RBVFVTX0lOVkFMSURfQVBQS0VZOiByZXR1cm4gIkludmFsaWQgQXBwS2V5IjsNCj4gPiAr
ICAgICAgIGNhc2UgTUVTSF9TVEFUVVNfSU5WQUxJRF9ORVRLRVk6IHJldHVybiAiSW52YWxpZCBO
ZXRLZXkiOw0KPiA+ICsgICAgICAgY2FzZSBNRVNIX1NUQVRVU19JTlNVRkZfUkVTT1VSQ0VTOiBy
ZXR1cm4gIkluc3VmZmljaWVudA0KPiBSZXNvdXJjZXMiOw0KPiA+ICsgICAgICAgY2FzZSBNRVNI
X1NUQVRVU19JRFhfQUxSRUFEWV9TVE9SRUQ6IHJldHVybiAiS2V5IElkeCBBbHJlYWR5DQo+IFN0
b3JlZCI7DQo+ID4gKyAgICAgICBjYXNlIE1FU0hfU1RBVFVTX0lOVkFMSURfUFVCX1BBUkFNOiBy
ZXR1cm4gIkludmFsaWQgUHVibGlzaA0KPiBQYXJhbWV0ZXJzIjsNCj4gPiArICAgICAgIGNhc2Ug
TUVTSF9TVEFUVVNfTk9UX1NVQl9NT0Q6IHJldHVybiAiTm90IGEgU3Vic2NyaWJlDQo+IE1vZGVs
IjsNCj4gPiArICAgICAgIGNhc2UgTUVTSF9TVEFUVVNfU1RPUkFHRV9GQUlMOiByZXR1cm4gIlN0
b3JhZ2UgRmFpbHVyZSI7DQo+ID4gKyAgICAgICBjYXNlIE1FU0hfU1RBVFVTX0ZFQVRfTk9UX1NV
UDogcmV0dXJuICJGZWF0dXJlIE5vdA0KPiBTdXBwb3J0ZWQiOw0KPiA+ICsgICAgICAgY2FzZSBN
RVNIX1NUQVRVU19DQU5OT1RfVVBEQVRFOiByZXR1cm4gIkNhbm5vdCBVcGRhdGUiOw0KPiA+ICsg
ICAgICAgY2FzZSBNRVNIX1NUQVRVU19DQU5OT1RfUkVNT1ZFOiByZXR1cm4gIkNhbm5vdCBSZW1v
dmUiOw0KPiA+ICsgICAgICAgY2FzZSBNRVNIX1NUQVRVU19DQU5OT1RfQklORDogcmV0dXJuICJD
YW5ub3QgYmluZCI7DQo+ID4gKyAgICAgICBjYXNlIE1FU0hfU1RBVFVTX1VOQUJMRV9DSEFOR0Vf
U1RBVEU6IHJldHVybiAiVW5hYmxlIHRvDQo+IGNoYW5nZSBzdGF0ZSI7DQo+ID4gKyAgICAgICBj
YXNlIE1FU0hfU1RBVFVTX0NBTk5PVF9TRVQ6IHJldHVybiAiQ2Fubm90IHNldCI7DQo+ID4gKyAg
ICAgICBjYXNlIE1FU0hfU1RBVFVTX1VOU1BFQ0lGSUVEX0VSUk9SOiByZXR1cm4gIlVuc3BlY2lm
aWVkDQo+IGVycm9yIjsNCj4gPiArICAgICAgIGNhc2UgTUVTSF9TVEFUVVNfSU5WQUxJRF9CSU5E
SU5HOiByZXR1cm4gIkludmFsaWQgQmluZGluZyI7DQo+ID4gKw0KPiA+ICsgICAgICAgZGVmYXVs
dDogcmV0dXJuICJVbmtub3duIjsNCj4gPiArICAgICAgIH0NCj4gPiArfQ0KPiA+ICsNCj4gPiAr
dm9pZCBwcmludF9tb2RlbF9wdWIodWludDE2X3QgZWxlX2FkZHIsIHVpbnQzMl90IG1vZF9pZCwN
Cj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJ1
Y3QgbWVzaF9wdWJsaWNhdGlvbiAqcHViKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBybF9wcmludGYo
Ilx0RWxlbWVudDogJTQuNHhcbiIsIGVsZV9hZGRyKTsNCj4gPiArICAgICAgIHJsX3ByaW50Zigi
XHRQdWIgQWRkcjogJTQuNHgiLCBwdWItPnUuYWRkcjE2KTsNCj4gPiArICAgICAgIGlmIChtb2Rf
aWQgPiAweGZmZmYwMDAwKQ0KPiA+ICsgICAgICAgICAgICAgICBybF9wcmludGYoIlx0TW9kZWw6
ICU4Ljh4IFxuIiwgbW9kX2lkKTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAg
ICAgcmxfcHJpbnRmKCJcdE1vZGVsOiAlNC40eCBcbiIsICh1aW50MTZfdCkgKG1vZF9pZCAmIDB4
ZmZmZikpOw0KPiA+ICsgICAgICAgcmxfcHJpbnRmKCJcdEFwcCBLZXkgSWR4OiAlNC40eCIsIHB1
Yi0+YXBwX2lkeCk7DQo+ID4gKyAgICAgICBybF9wcmludGYoIlx0VFRMOiAlMi4yeCIsIHB1Yi0+
dHRsKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBzd2FwX3UyNTZfYnl0ZXModWludDhfdCAq
dTI1NikNCj4gPiArew0KPiA+ICsgICAgICAgaW50IGk7DQo+ID4gKw0KPiA+ICsgICAgICAgLyog
RW5kLXRvLUVuZCBieXRlIHJlZmxlY3Rpb24gb2YgMzIgb2N0ZXQgYnVmZmVyICovDQo+ID4gKyAg
ICAgICBmb3IgKGkgPSAwOyBpIDwgMTY7IGkrKykgew0KPiA+ICsgICAgICAgICAgICAgICB1MjU2
W2ldIF49IHUyNTZbMzEgLSBpXTsNCj4gPiArICAgICAgICAgICAgICAgdTI1NlszMSAtIGldIF49
IHUyNTZbaV07DQo+ID4gKyAgICAgICAgICAgICAgIHUyNTZbaV0gXj0gdTI1NlszMSAtIGldOw0K
PiA+ICsgICAgICAgfQ0KPiA+ICt9DQo+ID4gLS0NCj4gPiAyLjkuNQ0KPiA+DQo+IA0KPiANCj4g
DQo+IC0tDQo+IEx1aXogQXVndXN0byB2b24gRGVudHoNCg==

2017-08-15 09:07:16

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 4/5] mesh: Baseline Mesh implementation

Hi Brian,

On Mon, Aug 14, 2017 at 10:01 PM, Brian Gix <[email protected]> wrote:
> ---
> mesh/agent.c | 276 ++++++
> mesh/config-client.c | 667 +++++++++++++++
> mesh/config-server.c | 165 ++++
> mesh/crypto.c | 1168 ++++++++++++++++++++++++++
> mesh/gatt.c | 609 ++++++++++++++
> mesh/main.c | 2269 ++++++++++++++++++++++++++++++++++++++++++++++++++
> mesh/net.c | 2184 ++++++++++++++++++++++++++++++++++++++++++++++++
> mesh/node.c | 879 +++++++++++++++++++
> mesh/onoff-model.c | 306 +++++++
> mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
> mesh/prov.c | 664 +++++++++++++++
> mesh/util.c | 369 ++++++++
> 12 files changed, 11155 insertions(+)
> create mode 100644 mesh/agent.c
> create mode 100644 mesh/config-client.c
> create mode 100644 mesh/config-server.c
> create mode 100644 mesh/crypto.c
> create mode 100644 mesh/gatt.c
> create mode 100644 mesh/main.c
> create mode 100644 mesh/net.c
> create mode 100644 mesh/node.c
> create mode 100644 mesh/onoff-model.c
> create mode 100644 mesh/prov-db.c
> create mode 100644 mesh/prov.c
> create mode 100644 mesh/util.c
>
> diff --git a/mesh/agent.c b/mesh/agent.c
> new file mode 100644
> index 0000000..0944862
> --- /dev/null
> +++ b/mesh/agent.c
> @@ -0,0 +1,276 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <readline/readline.h>
> +
> +#include <glib.h>
> +
> +#include <lib/bluetooth.h>
> +#include "client/display.h"
> +#include "util.h"
> +#include "agent.h"
> +
> +#define AGENT_PROMPT COLOR_RED "[agent]" COLOR_OFF " "
> +
> +static char *agent_saved_prompt = NULL;
> +static int agent_saved_point = 0;
> +
> +struct input_request {
> + oob_type_t type;
> + uint16_t len;
> + agent_input_cb cb;
> + void *user_data;
> +};
> +
> +static struct input_request pending_request = {NONE, 0, NULL, NULL};
> +
> +static void agent_prompt(const char *msg)
> +{
> + char *prompt;
> +
> + /* Normal use should not prompt for user input to the agent a second
> + * time before it releases the prompt, but we take a safe action. */
> + if (agent_saved_prompt)
> + return;
> +
> + agent_saved_point = rl_point;
> + agent_saved_prompt = g_strdup(rl_prompt);
> +
> + rl_set_prompt("");
> + rl_redisplay();
> +
> + prompt = g_strdup_printf(AGENT_PROMPT "%s", msg);
> + rl_set_prompt(prompt);
> + g_free(prompt);
> +
> + rl_replace_line("", 0);
> + rl_redisplay();
> +}
> +
> +static void agent_release_prompt(void)
> +{
> + if (!agent_saved_prompt)
> + return;
> +
> + /* This will cause rl_expand_prompt to re-run over the last prompt, but
> + * our prompt doesn't expand anyway. */
> + rl_set_prompt(agent_saved_prompt);
> + rl_replace_line("", 0);
> + rl_point = agent_saved_point;
> + rl_redisplay();
> +
> + g_free(agent_saved_prompt);
> + agent_saved_prompt = NULL;
> +}
> +
> +bool agent_completion(void)
> +{
> + if (pending_request.type == NONE)
> + return false;
> +
> + return true;
> +}
> +
> +static bool response_hexadecimal(const char *input)
> +{
> + uint8_t buf[MAX_HEXADECIMAL_OOB_LEN];
> +
> + if (!str2hex(input, strlen(input), buf, pending_request.len) ) {
> + rl_printf("Incorrect input: expecting %d hex octets\n",
> + pending_request.len);
> + return false;
> + }
> +
> + if (pending_request.cb)
> + pending_request.cb(HEXADECIMAL, buf, pending_request.len,
> + pending_request.user_data);
> + return true;
> +}
> +
> +static bool response_decimal(const char *input)
> +{
> + uint8_t buf[DECIMAL_OOB_LEN];
> +
> + if (strlen(input) > pending_request.len)
> + return false;
> +
> + bt_put_be32(atoi(input), buf);
> +
> + if (pending_request.cb)
> + pending_request.cb(DECIMAL, buf, DECIMAL_OOB_LEN,
> + pending_request.user_data);
> +
> + return true;
> +}
> +
> +static void response_ascii(const char *input)
> +{
> + if (pending_request.cb)
> + pending_request.cb(ASCII, (uint8_t *) input, strlen(input),
> + pending_request.user_data);
> +}
> +
> +bool agent_input(const char *input)
> +{
> + bool repeat = false;
> +
> + if (pending_request.type == NONE)
> + return false;
> +
> + switch (pending_request.type) {
> + case HEXADECIMAL:
> + if (!response_hexadecimal(input))
> + repeat = true;
> + break;
> + case DECIMAL:
> + if (!response_decimal(input))
> + repeat = true;
> + break;
> + case ASCII:
> + response_ascii(input);
> + break;
> + case OUTPUT:
> + repeat = true;
> + case NONE:
> + default:
> + break;
> + };
> +
> + if (!repeat) {
> + pending_request.type = NONE;
> + pending_request.len = 0;
> + pending_request.cb = NULL;
> + pending_request.user_data = NULL;
> +
> + agent_release_prompt();
> + }
> +
> + return true;
> +}
> +
> +void agent_release(void)
> +{
> + agent_release_prompt();
> +}
> +
> +static bool request_hexadecimal(uint16_t len)
> +{
> + if (len > MAX_HEXADECIMAL_OOB_LEN)
> + return false;
> +
> + rl_printf("Request hexadecimal key (hex %d octets)\n", len);
> + agent_prompt("Enter key (hex number): ");
> +
> + return true;
> +}
> +
> +static uint32_t power_ten(uint8_t power)
> +{
> + uint32_t ret = 1;
> +
> + while (power--)
> + ret *= 10;
> +
> + return ret;
> +}
> +
> +static bool request_decimal(uint16_t len)
> +{
> + rl_printf("Request decimal key (0 - %d)\n", power_ten(len) - 1);
> + agent_prompt("Enter Numeric key: ");
> +
> + return true;
> +}
> +
> +static bool request_ascii(uint16_t len)
> +{
> + if (len != MAX_ASCII_OOB_LEN)
> + return false;
> +
> + rl_printf("Request ASCII key (max characters %d)\n", len);
> + agent_prompt("Enter key (ascii string): ");
> +
> + return true;
> +}
> +
> +bool agent_input_request(oob_type_t type, uint16_t max_len, agent_input_cb cb,
> + void *user_data)
> +{
> + bool result;
> +
> + if (pending_request.type != NONE)
> + return FALSE;
> +
> + switch (type) {
> + case HEXADECIMAL:
> + result = request_hexadecimal(max_len);
> + break;
> + case DECIMAL:
> + result = request_decimal(max_len);
> + break;
> + case ASCII:
> + result = request_ascii(max_len);
> + break;
> + case NONE:
> + case OUTPUT:
> + default:
> + return false;
> + };
> +
> + if (result) {
> + pending_request.type = type;
> + pending_request.len = max_len;
> + pending_request.cb = cb;
> + pending_request.user_data = user_data;
> +
> + return true;
> + }
> +
> + return false;
> +}
> +
> +bool agent_output_request(const char* str)
> +{
> + if (pending_request.type != NONE)
> + return false;
> +
> + pending_request.type = OUTPUT;
> + agent_prompt(str);
> + return true;
> +}
> +
> +void agent_output_request_cancel(void)
> +{
> + if (pending_request.type != OUTPUT)
> + return;
> + pending_request.type = NONE;
> + agent_release_prompt();
> +}

The whole agent.c can be removed as well.

> diff --git a/mesh/config-client.c b/mesh/config-client.c
> new file mode 100644
> index 0000000..a0f6eee
> --- /dev/null
> +++ b/mesh/config-client.c
> @@ -0,0 +1,667 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <stdbool.h>
> +#include <sys/uio.h>
> +#include <wordexp.h>
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "src/shared/util.h"
> +#include "client/display.h"
> +#include "mesh-net.h"
> +#include "keys.h"
> +#include "net.h"
> +#include "node.h"
> +#include "prov-db.h"
> +#include "util.h"
> +#include "config-model.h"
> +
> +#define MIN_COMPOSITION_LEN 16
> +
> +static bool client_msg_recvd(uint16_t src, uint8_t *data,
> + uint16_t len, void *user_data)
> +{
> + uint32_t opcode;
> + struct mesh_node *node;
> + uint16_t app_idx, net_idx, addr;
> + uint32_t mod_id;
> + uint16_t primary;
> + uint16_t ele_addr;
> + uint8_t ele_idx;
> + struct mesh_publication pub;
> + int n;
> +
> + if (mesh_opcode_get(data, len, &opcode, &n)) {
> + len -= n;
> + data += n;
> + } else
> + return false;
> +
> + if (IS_UNICAST(src)) {
> + node = node_find_by_addr(src);
> + } else
> + node = NULL;
> +
> + if (!node)
> + return false;
> +
> + primary = node_get_primary(node);
> + if (primary != src)
> + return false;
> +
> + switch (opcode & ~OP_UNRELIABLE) {
> + default:
> + return false;
> +
> + case OP_DEV_COMP_STATUS:
> + if (len < MIN_COMPOSITION_LEN || !node)
> + break;
> + if (node_parse_composition(node, data, len)) {
> + if (!prov_db_add_node_composition(node, data, len))
> + break;
> + }
> +
> + if (node_get_composition(node))
> + prov_db_print_node_composition(node);
> + break;
> +
> + case OP_APPKEY_STATUS:
> + if (len != 4)
> + break;
> +
> + rl_printf("Node %4.4x AppKey Status %s\n", src,
> + mesh_status_str(data[0]));
> + net_idx = get_le16(data + 1) & 0xfff;
> + app_idx = get_le16(data + 2) >> 4;
> +
> + rl_printf("\tNetKey %3.3x, AppKey %3.3x\n", net_idx, app_idx);
> +
> + if (data[0] != MESH_STATUS_SUCCESS &&
> + data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
> + node_app_key_delete(node, net_idx, app_idx))
> + prov_db_node_keys(node, node_get_app_keys(node),
> + "appKeys");
> + break;
> +
> + case OP_NETKEY_STATUS:
> + if (len != 3)
> + break;
> +
> + rl_printf("Node %4.4x NetKey Status %s\n", src,
> + mesh_status_str(data[0]));
> + net_idx = get_le16(data + 1) & 0xfff;
> +
> + rl_printf("\tNetKey %3.3x\n", net_idx);
> +
> + if (data[0] != MESH_STATUS_SUCCESS &&
> + data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
> + node_net_key_delete(node, net_idx))
> + prov_db_node_keys(node, node_get_net_keys(node),
> + "netKeys");
> + break;
> +
> + case OP_MODEL_APP_STATUS:
> + if (len != 7 && len != 9)
> + break;
> +
> + rl_printf("Node %4.4x Model App Status %s\n", src,
> + mesh_status_str(data[0]));
> + addr = get_le16(data + 1);
> + app_idx = get_le16(data + 3);
> +
> + rl_printf("\tElement %4.4x AppIdx %3.3x\n ", addr, app_idx);
> +
> + if (len == 7) {
> + mod_id = get_le16(data + 5);
> + rl_printf("ModelId %4.4x\n", mod_id);
> + mod_id = 0xffff0000 | mod_id;
> + } else {
> + mod_id = get_le16(data + 7);
> + rl_printf("ModelId %4.4x %4.4x\n", get_le16(data + 5),
> + mod_id);
> + mod_id = get_le16(data + 5) << 16 | mod_id;
> + }
> +
> + if (data[0] == MESH_STATUS_SUCCESS &&
> + node_add_binding(node, addr - src, mod_id, app_idx))
> + prov_db_add_binding(node, addr - src, mod_id, app_idx);
> + break;
> +
> + case OP_CONFIG_DEFAULT_TTL_STATUS:
> + if (len != 1)
> + return true;
> + rl_printf("Node %4.4x Default TTL %d\n", src, data[0]);
> + if (node_set_default_ttl (node, data[0]))
> + prov_db_node_set_ttl(node, data[0]);
> + break;
> +
> + case OP_CONFIG_MODEL_PUB_STATUS:
> + if (len != 12 && len != 14)
> + return true;
> +
> + rl_printf("\nSet publication for node %4.4x status: %s\n", src,
> + data[0] == MESH_STATUS_SUCCESS ? "Success" :
> + mesh_status_str(data[0]));
> +
> + if (data[0] != MESH_STATUS_SUCCESS)
> + return true;
> +
> + ele_addr = get_le16(data + 1);
> + mod_id = get_le16(data + 10);
> + if (len == 14)
> + mod_id = (mod_id << 16) | get_le16(data + 12);
> + else
> + mod_id |= 0xffff0000;
> +
> + pub.u.addr16 = get_le16(data + 3);
> + pub.app_idx = get_le16(data + 5);
> + pub.ttl = data[7];
> + pub.period = data[8];
> + n = (data[8] & 0x3f);
> + switch (data[8] >> 6) {
> + case 0:
> + rl_printf("Period: %d ms\n", n * 100);
> + break;
> + case 2:
> + n *= 10;
> + /* fall through */
> + case 1:
> + rl_printf("Period: %d sec\n", n);
> + break;
> + case 3:
> + rl_printf("Period: %d min\n", n * 10);
> + break;
> + }
> +
> + pub.retransmit = data[9];
> + rl_printf("Retransmit count: %d\n", data[9] >> 5);
> + rl_printf("Retransmit Interval Steps: %d\n", data[9] & 0x1f);
> +
> + ele_idx = ele_addr - node_get_primary(node);
> +
> + /* Local configuration is saved by server */
> + if (node == node_get_local_node())
> + break;
> +
> + if (node_model_pub_set(node, ele_idx, mod_id, &pub))
> + prov_db_node_set_model_pub(node, ele_idx, mod_id,
> + node_model_pub_get(node, ele_idx, mod_id));
> + break;
> + }
> + return true;
> +}
> +
> +static uint32_t target;
> +static uint32_t parms[8];
> +
> +static uint32_t read_input_parameters(const char *args)
> +{
> + uint32_t i;
> +
> + if (!args)
> + return 0;
> +
> + memset(parms, 0xff, sizeof(parms));
> +
> + for (i = 0; i < sizeof(parms)/sizeof(parms[0]); i++) {
> + int n;
> +
> + sscanf(args, "%x", &parms[i]);
> + if (parms[i] == 0xffffffff)
> + break;
> +
> + n = strcspn(args, " \t");
> + args = args + n + strspn(args + n, " \t");
> + }
> +
> + return i;
> +}
> +
> +static void cmd_set_node(const char *args)
> +{
> + uint32_t dst;
> + char *end;
> +
> + dst = strtol(args, &end, 16);
> + if (end != (args + 4)) {
> + rl_printf("Bad unicast address %s: "
> + "expected format 4 digit hex\n", args);
> + target = UNASSIGNED_ADDRESS;
> + } else {
> + rl_printf("Configuring node %4.4x\n", dst);
> + target = dst;
> + set_menu_prompt("config", args);
> + }
> +
> +}
> +
> +static bool config_send(uint8_t *buf, uint16_t len)
> +{
> + struct mesh_node *node = node_get_local_node();
> + uint16_t primary;
> +
> + if(!node)
> + return false;
> +
> + primary = node_get_primary(node);
> + if (target != primary)
> + return net_access_layer_send(DEFAULT_TTL, primary,
> + target, APP_IDX_DEV, buf, len);
> +
> + node_local_data_handler(primary, target, node_get_iv_index(node),
> + node_get_sequence_number(node), APP_IDX_DEV,
> + buf, len);
> + return true;
> +
> +}
> +
> +static void cmd_get_composition(const char *args)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + struct mesh_node *node;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + node = node_find_by_addr(target);
> +
> + if (!node)
> + return;
> +
> + n = mesh_opcode_set(OP_DEV_COMP_GET, msg);
> +
> + /* By default, use page 0 */
> + msg[n++] = (read_input_parameters(args) == 1) ? parms[0] : 0;
> +
> + if (!config_send(msg, n))
> + rl_printf("Failed to send \"GET NODE COMPOSITION\"\n");
> +}
> +
> +static void cmd_net_key(const char *args, uint32_t opcode)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + uint16_t net_idx;
> + uint8_t *key;
> + struct mesh_node *node;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + n = mesh_opcode_set(opcode, msg);
> +
> + if (read_input_parameters(args) != 1) {
> + rl_printf("Bad arguments %s\n", args);
> + return;
> + }
> +
> + node = node_find_by_addr(target);
> + if (!node) {
> + rl_printf("Node %4.4x\n not found", target);
> + return;
> + }
> +
> + net_idx = parms[0];
> +
> + if (opcode != OP_NETKEY_DELETE) {
> +
> + key = keys_net_key_get(net_idx, true);
> + if (!key) {
> + rl_printf("Network key with index %4.4x not found\n",
> + net_idx);
> + return;
> + }
> +
> + put_le16(net_idx, &msg[n]);
> + n += 2;
> +
> + memcpy(msg + n, key, 16);
> + n += 16;
> + }
> +
> + if (!config_send(msg, n)) {
> + rl_printf("Failed to send \"%s NET KEY\"\n",
> + opcode == OP_NETKEY_ADD ? "ADD" : "DEL");
> + return;
> + }
> +
> + if (opcode != OP_NETKEY_DELETE) {
> + if (node_net_key_add(node, net_idx))
> + prov_db_node_keys(node, node_get_net_keys(node),
> + "netKeys");
> + } else {
> + if (node_net_key_delete(node, net_idx))
> + prov_db_node_keys(node, node_get_net_keys(node),
> + "netKeys");
> + }
> +
> +}
> +
> +static void cmd_add_net_key(const char *args)
> +{
> + cmd_net_key(args, OP_NETKEY_ADD);
> +}
> +
> +static void cmd_del_net_key(const char *args)
> +{
> + cmd_net_key(args, OP_NETKEY_DELETE);
> +}
> +
> +static void cmd_app_key(const char *args, uint32_t opcode)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + uint16_t net_idx;
> + uint16_t app_idx;
> + uint8_t *key;
> + struct mesh_node *node;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + if (read_input_parameters(args) != 1) {
> + rl_printf("Bad arguments %s\n", args);
> + return;
> + }
> +
> + node = node_find_by_addr(target);
> + if (!node) {
> + rl_printf("Node %4.4x\n not found", target);
> + return;
> + }
> +
> + n = mesh_opcode_set(opcode, msg);
> +
> + app_idx = parms[0];
> + net_idx = keys_app_key_get_bound(app_idx);
> + if (net_idx == NET_IDX_INVALID) {
> + rl_printf("App key with index %4.4x not found\n", app_idx);
> + return;
> + }
> +
> + msg[n++] = net_idx & 0xf;
> + msg[n++] = ((net_idx >> 8) & 0xf) |
> + ((app_idx << 4) & 0xf0);
> + msg[n++] = app_idx >> 4;
> +
> + if (opcode != OP_APPKEY_DELETE) {
> + key = keys_app_key_get(app_idx, true);
> + if (!key) {
> + rl_printf("App key %4.4x not found\n", net_idx);
> + return;
> + }
> +
> + memcpy(msg + n, key, 16);
> + n += 16;
> + }
> +
> + if (!config_send(msg, n)) {
> + rl_printf("Failed to send \"ADD %s KEY\"\n",
> + opcode == OP_APPKEY_ADD ? "ADD" : "DEL");
> + return;
> + }
> +
> + if (opcode != OP_APPKEY_DELETE) {
> + if (node_app_key_add(node, app_idx))
> + prov_db_node_keys(node, node_get_app_keys(node),
> + "appKeys");
> + } else {
> + if (node_app_key_delete(node, net_idx, app_idx))
> + prov_db_node_keys(node, node_get_app_keys(node),
> + "appKeys");
> + }
> +}
> +
> +static void cmd_add_app_key(const char *args)
> +{
> + cmd_app_key(args, OP_APPKEY_ADD);
> +}
> +
> +static void cmd_del_app_key(const char *args)
> +{
> + cmd_app_key(args, OP_APPKEY_DELETE);
> +}
> +
> +static void cmd_bind(const char *args)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + int parm_cnt;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + parm_cnt = read_input_parameters(args);
> + if (parm_cnt != 3 && parm_cnt != 4) {
> + rl_printf("Bad arguments %s\n", args);
> + return;
> + }
> +
> + n = mesh_opcode_set(OP_MODEL_APP_BIND, msg);
> +
> + put_le16(target + parms[0], msg + n);
> + n += 2;
> + put_le16(parms[1], msg + n);
> + n += 2;
> + if (parm_cnt == 4) {
> + put_le16(parms[3], msg + n);
> + put_le16(parms[2], msg + n + 2);
> + n += 4;
> + } else {
> + put_le16(parms[2], msg + n);
> + n += 2;
> + }
> +
> + if (!config_send(msg, n))
> + rl_printf("Failed to send \"MODEL APP BIND\"\n");
> +}
> +
> +static void cmd_set_ttl(const char *args)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + int parm_cnt;
> + uint8_t ttl;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_SET, msg);
> +
> + parm_cnt = read_input_parameters(args);
> + if (parm_cnt) {
> + ttl = parms[0] & TTL_MASK;
> + } else
> + ttl = node_get_default_ttl(node_get_local_node());
> +
> + msg[n++] = ttl;
> +
> + if (!config_send(msg, n))
> + rl_printf("Failed to send \"SET_DEFAULT TTL\"\n");
> +}
> +
> +static void cmd_set_pub(const char *args)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + int parm_cnt;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg);
> +
> + parm_cnt = read_input_parameters(args);
> + if (parm_cnt != 5) {
> + rl_printf("Bad arguments: %s\n", args);
> + return;
> + }
> +
> + put_le16(parms[0], msg + n);
> + n += 2;
> + /* Publish address */
> + put_le16(parms[1], msg + n);
> + n += 2;
> + /* App key index + credential (set to 0) */
> + put_le16(parms[2], msg + n);
> + n += 2;
> + /* TTL */
> + msg[n++] = DEFAULT_TTL;
> + /* Publish period step count and step resolution */
> + msg[n++] = parms[3];
> + /* Publish retransmit count & interval steps */
> + msg[n++] = (1 << 5) + 2;
> + /* Model Id */
> + if (parms[4] > 0xffff) {
> + put_le16(parms[4] >> 16, msg + n);
> + put_le16(parms[4], msg + n + 2);
> + n += 4;
> + } else {
> + put_le16(parms[4], msg + n);
> + n += 2;
> + }
> +
> + if (!config_send(msg, n))
> + rl_printf("Failed to send \"SET MODEL PUBLICATION\"\n");
> +}
> +
> +static void cmd_default(uint32_t opcode)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + n = mesh_opcode_set(opcode, msg);
> +
> + if (!config_send(msg, n))
> + rl_printf("Failed to send command (opcode 0x%x)\n", opcode);
> +}
> +
> +static void cmd_get_ttl(const char *args)
> +{
> + cmd_default(OP_CONFIG_DEFAULT_TTL_GET);
> +}
> +
> +static void cmd_back(const char *args)
> +{
> + cmd_menu_main(false);
> +}
> +
> +static void cmd_help(const char *args);
> +
> +static const struct menu_entry cfg_menu[] = {
> + {"target", "<unicast>", cmd_set_node,
> + "Set target node to configure"},
> + {"get-composition", "[<page_num>]", cmd_get_composition,
> + "Get Composition Data"},
> + {"add-netkey", "<net_idx>", cmd_add_net_key,
> + "Add network key"},
> + {"del-netkey", "<net_idx>", cmd_del_net_key,
> + "Delete network key"},
> + {"add-appkey", "<app_idx>", cmd_add_app_key,
> + "Add application key"},
> + {"del-appkey", "<app_idx>", cmd_del_app_key,
> + "Delete application key"},
> + {"bind", "<ele_idx> <app_idx> <mod_id> [cid]",
> + cmd_bind, "Bind app key to a model"},
> + {"set-ttl", "<ttl>", cmd_set_ttl,
> + "Set default TTL"},
> + {"get-ttl", NULL, cmd_get_ttl,
> + "Get default TTL"},
> + {"set-pub", "<ele_addr> <pub_addr> <app_idx> "
> + "<period (step|res)> <model>",
> + cmd_set_pub, "Set publication"},
> + {"back", NULL, cmd_back,
> + "Back to main menu"},
> + {"help", NULL, cmd_help,
> + "Config Commands"},
> + {}
> +};
> +
> +static void cmd_help(const char *args)
> +{
> + rl_printf("Client Configuration Menu\n");
> + print_cmd_menu(cfg_menu);
> +}
> +
> +void config_set_node(const char *args)
> +{
> + cmd_set_node(args);
> +}
> +
> +void config_client_get_composition(uint32_t dst)
> +{
> + uint32_t tmp = target;
> +
> + target = dst;
> + cmd_get_composition("");
> + target = tmp;
> +}
> +
> +static struct mesh_model_ops client_cbs = {
> + client_msg_recvd,
> + NULL,
> + NULL,
> + NULL
> +};
> +
> +bool config_client_init(void)
> +{
> + if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
> + CONFIG_CLIENT_MODEL_ID,
> + &client_cbs, NULL))
> + return false;
> +
> + add_cmd_menu("configure", cfg_menu);
> +
> + return true;
> +}
> diff --git a/mesh/config-server.c b/mesh/config-server.c
> new file mode 100644
> index 0000000..14e5d7b
> --- /dev/null
> +++ b/mesh/config-server.c
> @@ -0,0 +1,165 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <stdbool.h>
> +#include <sys/uio.h>
> +#include <wordexp.h>
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "src/shared/util.h"
> +#include "client/display.h"
> +#include "mesh-net.h"
> +#include "keys.h"
> +#include "net.h"
> +#include "node.h"
> +#include "prov-db.h"
> +#include "util.h"
> +#include "config-model.h"
> +
> +static bool server_msg_recvd(uint16_t src, uint8_t *data,
> + uint16_t len, void *user_data)
> +{
> + uint32_t opcode;
> + uint8_t msg[32];
> + struct mesh_node *node;
> + uint16_t primary;
> + uint32_t mod_id;
> + uint16_t ele_addr;
> + uint8_t ele_idx;
> + struct mesh_publication pub;
> +
> + int n;
> +
> + if (mesh_opcode_get(data, len, &opcode, &n)) {
> + len -= n;
> + data += n;
> + } else
> + return false;
> +
> + node = node_get_local_node();
> +
> + if (!node)
> + return true;
> +
> + switch (opcode & ~OP_UNRELIABLE) {
> + default:
> + return false;
> +
> + case OP_CONFIG_DEFAULT_TTL_SET:
> + if (len != 1 || data[0] > TTL_MASK || data[0] == 1)
> + return true;
> +
> + if (data[0] <= TTL_MASK) {
> + node_set_default_ttl(node, data[0]);
> + prov_db_node_set_ttl(node, data[0]);
> + }
> +
> + /* Fall Through */
> +
> + case OP_CONFIG_DEFAULT_TTL_GET:
> + n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_STATUS, msg);
> + msg[n++] = node_get_default_ttl(node);
> + break;
> +
> + case OP_CONFIG_MODEL_PUB_SET:
> + if (len != 11 && len != 13)
> + return true;
> +
> + rl_printf("Set publication\n");
> +
> + ele_addr = get_le16(data);
> + mod_id = get_le16(data + 9);
> + if (len == 14)
> + mod_id = (mod_id << 16) | get_le16(data + 11);
> + else
> + mod_id |= 0xffff0000;
> +
> + pub.u.addr16 = get_le16(data + 2);
> + pub.app_idx = get_le16(data + 4);
> + pub.ttl = data[6];
> + pub.period = data[7];
> + n = (data[7] & 0x3f);
> + switch (data[7] >> 6) {
> + case 0:
> + rl_printf("Period: %d ms\n", n * 100);
> + break;
> + case 2:
> + n *= 10;
> + /* fall through */
> + case 1:
> + rl_printf("Period: %d sec\n", n);
> + break;
> + case 3:
> + rl_printf("Period: %d min\n", n * 10);
> + break;
> + }
> +
> + pub.retransmit = data[8];
> + rl_printf("Retransmit count: %d\n", data[8] >> 5);
> + rl_printf("Retransmit Interval Steps: %d\n", data[8] & 0x1f);
> +
> + ele_idx = ele_addr - node_get_primary(node);
> +
> + if (node_model_pub_set(node, ele_idx, mod_id, &pub)) {
> + prov_db_node_set_model_pub(node, ele_idx, mod_id,
> + node_model_pub_get(node, ele_idx, mod_id));
> + }
> + break;
> + }
> +
> + primary = node_get_primary(node);
> + if (src != primary)
> + net_access_layer_send(node_get_default_ttl(node), primary,
> + src, APP_IDX_DEV, msg, len);
> + return true;
> +}
> +
> +
> +static struct mesh_model_ops server_cbs = {
> + server_msg_recvd,
> + NULL,
> + NULL,
> + NULL
> +};
> +
> +bool config_server_init(void)
> +{
> + if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
> + CONFIG_SERVER_MODEL_ID,
> + &server_cbs, NULL))
> + return false;
> +
> + return true;
> +}
> diff --git a/mesh/crypto.c b/mesh/crypto.c
> new file mode 100644
> index 0000000..189624e
> --- /dev/null
> +++ b/mesh/crypto.c
> @@ -0,0 +1,1168 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <sys/socket.h>
> +
> +#include <linux/if_alg.h>
> +
> +#include <glib.h>
> +
> +#ifndef SOL_ALG
> +#define SOL_ALG 279
> +#endif
> +
> +#ifndef ALG_SET_AEAD_AUTHSIZE
> +#define ALG_SET_AEAD_AUTHSIZE 5
> +#endif
> +
> +#include "src/shared/util.h"
> +#include "mesh-net.h"
> +#include "crypto.h"
> +
> +static int alg_new(int fd, const void *keyval, socklen_t keylen,
> + size_t mic_size)
> +{
> + if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, keyval, keylen) < 0) {
> + g_printerr("key");
> + return -1;
> + }
> +
> + if (mic_size &&
> + setsockopt(fd, SOL_ALG,
> + ALG_SET_AEAD_AUTHSIZE, NULL, mic_size) < 0) {
> + g_printerr("taglen");
> + return -1;
> + }
> +
> + /* FIXME: This should use accept4() with SOCK_CLOEXEC */
> + return accept(fd, NULL, 0);
> +}
> +
> +static bool alg_encrypt(int fd, const void *inbuf, size_t inlen,
> + void *outbuf, size_t outlen)
> +{
> + __u32 alg_op = ALG_OP_ENCRYPT;
> + char cbuf[CMSG_SPACE(sizeof(alg_op))];
> + struct cmsghdr *cmsg;
> + struct msghdr msg;
> + struct iovec iov;
> + ssize_t len;
> +
> + memset(cbuf, 0, sizeof(cbuf));
> + memset(&msg, 0, sizeof(msg));
> +
> + msg.msg_control = cbuf;
> + msg.msg_controllen = sizeof(cbuf);
> +
> + cmsg = CMSG_FIRSTHDR(&msg);
> + cmsg->cmsg_level = SOL_ALG;
> + cmsg->cmsg_type = ALG_SET_OP;
> + cmsg->cmsg_len = CMSG_LEN(sizeof(alg_op));
> + memcpy(CMSG_DATA(cmsg), &alg_op, sizeof(alg_op));
> +
> + iov.iov_base = (void *) inbuf;
> + iov.iov_len = inlen;
> +
> + msg.msg_iov = &iov;
> + msg.msg_iovlen = 1;
> +
> + len = sendmsg(fd, &msg, 0);
> + if (len < 0)
> + return false;
> +
> + len = read(fd, outbuf, outlen);
> + if (len < 0)
> + return false;
> +
> + return true;
> +}
> +
> +static int aes_ecb_setup(const uint8_t key[16])
> +{
> + struct sockaddr_alg salg;
> + int fd, nfd;
> +
> + fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
> + if (fd < 0)
> + return -1;
> +
> + memset(&salg, 0, sizeof(salg));
> + salg.salg_family = AF_ALG;
> + strcpy((char *) salg.salg_type, "skcipher");
> + strcpy((char *) salg.salg_name, "ecb(aes)");
> +
> + if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
> + close(fd);
> + return -1;
> + }
> +
> + nfd = alg_new(fd, key, 16, 0);
> +
> + close(fd);
> +
> + return nfd;
> +}
> +
> +static bool aes_ecb(int fd, const uint8_t plaintext[16], uint8_t encrypted[16])
> +{
> + return alg_encrypt(fd, plaintext, 16, encrypted, 16);
> +}
> +
> +static void aes_ecb_destroy(int fd)
> +{
> + close(fd);
> +}
> +
> +static bool aes_ecb_one(const uint8_t key[16],
> + const uint8_t plaintext[16], uint8_t encrypted[16])
> +{
> + bool result;
> + int fd;
> +
> + fd = aes_ecb_setup(key);
> + if (fd < 0)
> + return false;
> +
> + result = aes_ecb(fd, plaintext, encrypted);
> +
> + aes_ecb_destroy(fd);
> +
> + return result;
> +}
> +
> +/* Maximum message length that can be passed to aes_cmac */
> +#define CMAC_MSG_MAX (64 + 64 + 17)
> +
> +static int aes_cmac_setup(const uint8_t key[16])
> +{
> + struct sockaddr_alg salg;
> + int fd, nfd;
> +
> + fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
> + if (fd < 0)
> + return -1;
> +
> + memset(&salg, 0, sizeof(salg));
> + salg.salg_family = AF_ALG;
> + strcpy((char *) salg.salg_type, "hash");
> + strcpy((char *) salg.salg_name, "cmac(aes)");
> +
> + if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
> + close(fd);
> + return -1;
> + }
> +
> + nfd = alg_new(fd, key, 16, 0);
> +
> + close(fd);
> +
> + return nfd;
> +}
> +
> +static bool aes_cmac(int fd, const uint8_t *msg,
> + size_t msg_len, uint8_t res[16])
> +{
> + ssize_t len;
> +
> + if (msg_len > CMAC_MSG_MAX)
> + return false;
> +
> + len = send(fd, msg, msg_len, 0);
> + if (len < 0)
> + return false;
> +
> + len = read(fd, res, 16);
> + if (len < 0)
> + return false;
> +
> + return true;
> +}
> +
> +static void aes_cmac_destroy(int fd)
> +{
> + close(fd);
> +}
> +
> +static int aes_cmac_N_start(const uint8_t N[16])
> +{
> + int fd;
> +
> + fd = aes_cmac_setup(N);
> + return fd;
> +}
> +
> +static bool aes_cmac_one(const uint8_t key[16], const void *msg,
> + size_t msg_len, uint8_t res[16])
> +{
> + bool result;
> + int fd;
> +
> + fd = aes_cmac_setup(key);
> + if (fd < 0)
> + return false;
> +
> + result = aes_cmac(fd, msg, msg_len, res);
> +
> + aes_cmac_destroy(fd);
> +
> + return result;
> +}
> +
> +bool mesh_crypto_aes_cmac(const uint8_t key[16], const uint8_t *msg,
> + size_t msg_len, uint8_t res[16])
> +{
> + return aes_cmac_one(key, msg, msg_len, res);
> +}
> +
> +bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
> + const uint8_t *aad, uint16_t aad_len,
> + const uint8_t *msg, uint16_t msg_len,
> + uint8_t *out_msg, void *out_mic,
> + size_t mic_size)
> +{
> + uint8_t pmsg[16], cmic[16], cmsg[16];
> + uint8_t mic[16], Xn[16];
> + uint16_t blk_cnt, last_blk;
> + bool result;
> + size_t i, j;
> + int fd;
> +
> + if (aad_len >= 0xff00) {
> + g_printerr("Unsupported AAD size");
> + return false;
> + }
> +
> + fd = aes_ecb_setup(key);
> + if (fd < 0)
> + return false;
> +
> + /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
> + pmsg[0] = 0x01;
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(0x0000, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, cmic);
> + if (!result)
> + goto done;
> +
> + /* X_0 = e(AppKey, 0x09 || nonce || length) */
> + if (mic_size == sizeof(uint64_t))
> + pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
> + else
> + pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
> +
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(msg_len, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> +
> + /* If AAD is being used to authenticate, include it here */
> + if (aad_len) {
> + put_be16(aad_len, pmsg);
> +
> + for (i = 0; i < sizeof(uint16_t); i++)
> + pmsg[i] = Xn[i] ^ pmsg[i];
> +
> + j = 0;
> + aad_len += sizeof(uint16_t);
> + while (aad_len > 16) {
> + do {
> + pmsg[i] = Xn[i] ^ aad[j];
> + i++, j++;
> + } while (i < 16);
> +
> + aad_len -= 16;
> + i = 0;
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> + }
> +
> + for (i = 0; i < aad_len; i++, j++)
> + pmsg[i] = Xn[i] ^ aad[j];
> +
> + for (i = aad_len; i < 16; i++)
> + pmsg[i] = Xn[i];
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> + }
> +
> + last_blk = msg_len % 16;
> + blk_cnt = (msg_len + 15) / 16;
> + if (!last_blk)
> + last_blk = 16;
> +
> + for (j = 0; j < blk_cnt; j++) {
> + if (j + 1 == blk_cnt) {
> + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
> + for (i = 0; i < last_blk; i++)
> + pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
> + for (i = last_blk; i < 16; i++)
> + pmsg[i] = Xn[i] ^ 0x00;
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> +
> + /* MIC = C_mic ^ X_1 */
> + for (i = 0; i < sizeof(mic); i++)
> + mic[i] = cmic[i] ^ Xn[i];
> +
> + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
> + pmsg[0] = 0x01;
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(j + 1, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, cmsg);
> + if (!result)
> + goto done;
> +
> + if (out_msg) {
> + /* Encrypted = Payload[0-15] ^ C_1 */
> + for (i = 0; i < last_blk; i++)
> + out_msg[(j * 16) + i] =
> + msg[(j * 16) + i] ^ cmsg[i];
> +
> + }
> + } else {
> + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
> + for (i = 0; i < 16; i++)
> + pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> +
> + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
> + pmsg[0] = 0x01;
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(j + 1, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, cmsg);
> + if (!result)
> + goto done;
> +
> + if (out_msg) {
> + /* Encrypted = Payload[0-15] ^ C_N */
> + for (i = 0; i < 16; i++)
> + out_msg[(j * 16) + i] =
> + msg[(j * 16) + i] ^ cmsg[i];
> + }
> +
> + }
> + }
> +
> + if (out_msg)
> + memcpy(out_msg + msg_len, mic, mic_size);
> +
> + if (out_mic) {
> + switch (mic_size) {
> + case sizeof(uint32_t):
> + *(uint32_t *)out_mic = get_be32(mic);
> + break;
> + case sizeof(uint64_t):
> + *(uint64_t *)out_mic = get_be64(mic);
> + break;
> + default:
> + g_printerr("Unsupported MIC size");
> + }
> + }
> +
> +done:
> + aes_ecb_destroy(fd);
> +
> + return result;
> +}
> +
> +bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
> + const uint8_t *aad, uint16_t aad_len,
> + const uint8_t *enc_msg, uint16_t enc_msg_len,
> + uint8_t *out_msg, void *out_mic,
> + size_t mic_size)
> +{
> + uint8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16];
> + uint8_t mic[16];
> + uint16_t msg_len = enc_msg_len - mic_size;
> + uint16_t last_blk, blk_cnt;
> + bool result;
> + size_t i, j;
> + int fd;
> +
> + if (enc_msg_len < 5 || aad_len >= 0xff00)
> + return false;
> +
> + fd = aes_ecb_setup(key);
> + if (fd < 0)
> + return false;
> +
> + /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
> + pmsg[0] = 0x01;
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(0x0000, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, cmic);
> + if (!result)
> + goto done;
> +
> + /* X_0 = e(AppKey, 0x09 || nonce || length) */
> + if (mic_size == sizeof(uint64_t))
> + pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
> + else
> + pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
> +
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(msg_len, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> +
> + /* If AAD is being used to authenticate, include it here */
> + if (aad_len) {
> + put_be16(aad_len, pmsg);
> +
> + for (i = 0; i < sizeof(uint16_t); i++)
> + pmsg[i] = Xn[i] ^ pmsg[i];
> +
> + j = 0;
> + aad_len += sizeof(uint16_t);
> + while (aad_len > 16) {
> + do {
> + pmsg[i] = Xn[i] ^ aad[j];
> + i++, j++;
> + } while (i < 16);
> +
> + aad_len -= 16;
> + i = 0;
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> + }
> +
> + for (i = 0; i < aad_len; i++, j++)
> + pmsg[i] = Xn[i] ^ aad[j];
> +
> + for (i = aad_len; i < 16; i++)
> + pmsg[i] = Xn[i];
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> + }
> +
> + last_blk = msg_len % 16;
> + blk_cnt = (msg_len + 15) / 16;
> + if (!last_blk)
> + last_blk = 16;
> +
> + for (j = 0; j < blk_cnt; j++) {
> + if (j + 1 == blk_cnt) {
> + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
> + pmsg[0] = 0x01;
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(j + 1, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, cmsg);
> + if (!result)
> + goto done;
> +
> + /* Encrypted = Payload[0-15] ^ C_1 */
> + for (i = 0; i < last_blk; i++)
> + msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
> +
> + if (out_msg)
> + memcpy(out_msg + (j * 16), msg, last_blk);
> +
> + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
> + for (i = 0; i < last_blk; i++)
> + pmsg[i] = Xn[i] ^ msg[i];
> + for (i = last_blk; i < 16; i++)
> + pmsg[i] = Xn[i] ^ 0x00;
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> +
> + /* MIC = C_mic ^ X_1 */
> + for (i = 0; i < sizeof(mic); i++)
> + mic[i] = cmic[i] ^ Xn[i];
> + } else {
> + /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
> + pmsg[0] = 0x01;
> + memcpy(pmsg + 1, nonce, 13);
> + put_be16(j + 1, pmsg + 14);
> +
> + result = aes_ecb(fd, pmsg, cmsg);
> + if (!result)
> + goto done;
> +
> + /* Encrypted = Payload[0-15] ^ C_1 */
> + for (i = 0; i < 16; i++)
> + msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
> +
> + if (out_msg)
> + memcpy(out_msg + (j * 16), msg, 16);
> +
> + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
> + for (i = 0; i < 16; i++)
> + pmsg[i] = Xn[i] ^ msg[i];
> +
> + result = aes_ecb(fd, pmsg, Xn);
> + if (!result)
> + goto done;
> + }
> + }
> +
> + switch (mic_size) {
> + case sizeof(uint32_t):
> + if (out_mic)
> + *(uint32_t *)out_mic = get_be32(mic);
> + else if (get_be32(enc_msg + enc_msg_len - mic_size) !=
> + get_be32(mic))
> + result = false;
> + break;
> +
> + case sizeof(uint64_t):
> + if (out_mic)
> + *(uint64_t *)out_mic = get_be64(mic);
> + else if (get_be64(enc_msg + enc_msg_len - mic_size) !=
> + get_be64(mic))
> + result = false;
> + break;
> +
> + default:
> + g_printerr("Unsupported MIC size");
> + result = false;
> + }
> +
> +done:
> + aes_ecb_destroy(fd);
> +
> + return result;
> +}
> +
> +bool mesh_crypto_k1(const uint8_t ikm[16], const uint8_t salt[16],
> + const void *info, size_t info_len, uint8_t okm[16])
> +{
> + uint8_t res[16];
> +
> + if (!aes_cmac_one(salt, ikm, 16, res))
> + return false;
> +
> + return aes_cmac_one(res, info, info_len, okm);
> +}
> +
> +bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
> + uint8_t net_id[1],
> + uint8_t enc_key[16],
> + uint8_t priv_key[16])
> +{
> + int fd;
> + uint8_t output[16];
> + uint8_t t[16];
> + uint8_t *stage;
> + bool success = false;
> +
> + stage = g_malloc(sizeof(output) + p_len + 1);
> + if (stage == NULL)
> + return false;
> +
> + if (!mesh_crypto_s1("smk2", 4, stage))
> + goto fail;
> +
> + if (!aes_cmac_one(stage, n, 16, t))
> + goto fail;
> +
> + fd = aes_cmac_N_start(t);
> + if (fd < 0)
> + goto fail;
> +
> + memcpy(stage, p, p_len);
> + stage[p_len] = 1;
> +
> + if(!aes_cmac(fd, stage, p_len + 1, output))
> + goto done;
> +
> + net_id[0] = output[15] & 0x7f;
> +
> + memcpy(stage, output, 16);
> + memcpy(stage + 16, p, p_len);
> + stage[p_len + 16] = 2;
> +
> + if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
> + goto done;
> +
> + memcpy(enc_key, output, 16);
> +
> + memcpy(stage, output, 16);
> + memcpy(stage + 16, p, p_len);
> + stage[p_len + 16] = 3;
> +
> + if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
> + goto done;
> +
> + memcpy(priv_key, output, 16);
> + success = true;
> +
> +done:
> + aes_cmac_destroy(fd);
> +fail:
> + g_free(stage);
> +
> + return success;
> +}
> +
> +static bool crypto_128(const uint8_t n[16], const char *s, uint8_t out128[16])
> +{
> + uint8_t id128[] = { 'i', 'd', '1', '2', '8', 0x01 };
> + uint8_t salt[16];
> +
> + if (!mesh_crypto_s1(s, 4, salt))
> + return false;
> +
> + return mesh_crypto_k1(n, salt, id128, sizeof(id128), out128);
> +}
> +
> +bool mesh_crypto_nkik(const uint8_t n[16], uint8_t identity_key[16])
> +{
> + return crypto_128(n, "nkik", identity_key);
> +}
> +
> +static bool identity_calc(const uint8_t net_key[16], uint16_t addr,
> + bool check, uint8_t id[16])
> +{
> + uint8_t id_key[16];
> + uint8_t tmp[16];
> +
> + if (!mesh_crypto_nkik(net_key, id_key))
> + return false;
> +
> + memset(tmp, 0, sizeof(tmp));
> + put_be16(addr, tmp + 14);
> +
> + if (check) {
> + memcpy(tmp + 6, id + 8, 8);
> + } else {
> + mesh_get_random_bytes(tmp + 6, 8);
> + memcpy(id + 8, tmp + 6, 8);
> + }
> +
> + if (!aes_ecb_one(id_key, tmp, tmp))
> + return false;
> +
> + if (check)
> + return (memcmp(id, tmp + 8, 8) == 0);
> +
> + memcpy(id, tmp + 8, 8);
> + return true;
> +}
> +
> +bool mesh_crypto_identity(const uint8_t net_key[16], uint16_t addr,
> + uint8_t id[16])
> +{
> + return identity_calc(net_key, addr, false, id);
> +}
> +
> +bool mesh_crypto_identity_check(const uint8_t net_key[16], uint16_t addr,
> + uint8_t id[16])
> +{
> + return identity_calc(net_key, addr, true, id);
> +}
> +
> +bool mesh_crypto_nkbk(const uint8_t n[16], uint8_t beacon_key[16])
> +{
> + return crypto_128(n, "nkbk", beacon_key);
> +}
> +
> +bool mesh_crypto_k3(const uint8_t n[16], uint8_t out64[8])
> +{
> + uint8_t tmp[16];
> + uint8_t t[16];
> + uint8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
> +
> + if (!mesh_crypto_s1("smk3", 4, tmp))
> + return false;
> +
> + if (!aes_cmac_one(tmp, n, 16, t))
> + return false;
> +
> + if (!aes_cmac_one(t, id64, sizeof(id64), tmp))
> + return false;
> +
> + memcpy(out64, tmp + 8, 8);
> +
> + return true;
> +}
> +
> +bool mesh_crypto_k4(const uint8_t a[16], uint8_t out6[1])
> +{
> + uint8_t tmp[16];
> + uint8_t t[16];
> + uint8_t id6[] = { 'i', 'd', '6', 0x01 };
> +
> + if (!mesh_crypto_s1("smk4", 4, tmp))
> + return false;
> +
> + if (!aes_cmac_one(tmp, a, 16, t))
> + return false;
> +
> + if (!aes_cmac_one(t, id6, sizeof(id6), tmp))
> + return false;
> +
> + out6[0] = tmp[15] & 0x3f;
> + return true;
> +}
> +
> +bool mesh_crypto_beacon_cmac(const uint8_t encryption_key[16],
> + const uint8_t network_id[8],
> + uint32_t iv_index, bool kr, bool iu,
> + uint64_t *cmac)
> +{
> + uint8_t msg[13], tmp[16];
> +
> + if (!cmac)
> + return false;
> +
> + msg[0] = kr ? 0x01 : 0x00;
> + msg[0] |= iu ? 0x02 : 0x00;
> + memcpy(msg + 1, network_id, 8);
> + put_be32(iv_index, msg + 9);
> +
> + if (!aes_cmac_one(encryption_key, msg, 13, tmp))
> + return false;
> +
> + *cmac = get_be64(tmp);
> +
> + return true;
> +}
> +
> +bool mesh_crypto_network_nonce(bool ctl, uint8_t ttl, uint32_t seq,
> + uint16_t src, uint32_t iv_index,
> + uint8_t nonce[13])
> +{
> + nonce[0] = 0;
> + nonce[1] = (ttl & TTL_MASK) | (ctl ? CTL : 0x00);
> + nonce[2] = (seq >> 16) & 0xff;
> + nonce[3] = (seq >> 8) & 0xff;
> + nonce[4] = seq & 0xff;
> +
> + /* SRC */
> + put_be16(src, nonce + 5);
> +
> + put_be16(0, nonce + 7);
> +
> + /* IV Index */
> + put_be32(iv_index, nonce + 9);
> +
> + return true;
> +}
> +
> +bool mesh_crypto_network_encrypt(bool ctl, uint8_t ttl,
> + uint32_t seq, uint16_t src,
> + uint32_t iv_index,
> + const uint8_t net_key[16],
> + const uint8_t *enc_msg, uint8_t enc_msg_len,
> + uint8_t *out, void *net_mic)
> +{
> + uint8_t nonce[13];
> +
> + if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
> + return false;
> +
> + return mesh_crypto_aes_ccm_encrypt(nonce, net_key,
> + NULL, 0, enc_msg,
> + enc_msg_len, out,
> + net_mic,
> + ctl ? sizeof(uint64_t) : sizeof(uint32_t));
> +}
> +
> +bool mesh_crypto_network_decrypt(bool ctl, uint8_t ttl,
> + uint32_t seq, uint16_t src,
> + uint32_t iv_index,
> + const uint8_t net_key[16],
> + const uint8_t *enc_msg, uint8_t enc_msg_len,
> + uint8_t *out, void *net_mic, size_t mic_size)
> +{
> + uint8_t nonce[13];
> +
> + if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
> + return false;
> +
> + return mesh_crypto_aes_ccm_decrypt(nonce, net_key, NULL, 0,
> + enc_msg, enc_msg_len, out,
> + net_mic, mic_size);
> +}
> +
> +bool mesh_crypto_application_nonce(uint32_t seq, uint16_t src,
> + uint16_t dst, uint32_t iv_index,
> + bool aszmic, uint8_t nonce[13])
> +{
> + nonce[0] = 0x01;
> + nonce[1] = aszmic ? 0x80 : 0x00;
> + nonce[2] = (seq & 0x00ff0000) >> 16;
> + nonce[3] = (seq & 0x0000ff00) >> 8;
> + nonce[4] = (seq & 0x000000ff);
> + nonce[5] = (src & 0xff00) >> 8;
> + nonce[6] = (src & 0x00ff);
> + nonce[7] = (dst & 0xff00) >> 8;
> + nonce[8] = (dst & 0x00ff);
> + put_be32(iv_index, nonce + 9);
> +
> + return true;
> +}
> +
> +bool mesh_crypto_device_nonce(uint32_t seq, uint16_t src,
> + uint16_t dst, uint32_t iv_index,
> + bool aszmic, uint8_t nonce[13])
> +{
> + nonce[0] = 0x02;
> + nonce[1] = aszmic ? 0x80 : 0x00;
> + nonce[2] = (seq & 0x00ff0000) >> 16;
> + nonce[3] = (seq & 0x0000ff00) >> 8;
> + nonce[4] = (seq & 0x000000ff);
> + nonce[5] = (src & 0xff00) >> 8;
> + nonce[6] = (src & 0x00ff);
> + nonce[7] = (dst & 0xff00) >> 8;
> + nonce[8] = (dst & 0x00ff);
> + put_be32(iv_index, nonce + 9);
> +
> + return true;
> +}
> +
> +bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq, uint16_t src,
> + uint16_t dst, uint32_t iv_index,
> + const uint8_t app_key[16],
> + const uint8_t *aad, uint8_t aad_len,
> + const uint8_t *msg, uint8_t msg_len,
> + uint8_t *out, void *app_mic,
> + size_t mic_size)
> +{
> + uint8_t nonce[13];
> + bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
> +
> + if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
> + iv_index, aszmic, nonce))
> + return false;
> +
> + if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
> + iv_index, aszmic, nonce))
> + return false;
> +
> + return mesh_crypto_aes_ccm_encrypt(nonce, app_key, aad, aad_len,
> + msg, msg_len,
> + out, app_mic, mic_size);
> +}
> +
> +bool mesh_crypto_application_decrypt(uint8_t key_id, uint32_t seq, uint16_t src,
> + uint16_t dst, uint32_t iv_index,
> + const uint8_t app_key[16],
> + const uint8_t *aad, uint8_t aad_len,
> + const uint8_t *enc_msg, uint8_t enc_msg_len,
> + uint8_t *out, void *app_mic, size_t mic_size)
> +{
> + uint8_t nonce[13];
> + bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
> +
> + if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
> + iv_index, aszmic, nonce))
> + return false;
> +
> + if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
> + iv_index, aszmic, nonce))
> + return false;
> +
> + return mesh_crypto_aes_ccm_decrypt(nonce, app_key,
> + aad, aad_len, enc_msg,
> + enc_msg_len, out,
> + app_mic, mic_size);
> +}
> +
> +bool mesh_crypto_session_key(const uint8_t secret[32],
> + const uint8_t salt[16],
> + uint8_t session_key[16])
> +{
> + const uint8_t prsk[4] = "prsk";
> +
> + if (!aes_cmac_one(salt, secret, 32, session_key))
> + return false;
> +
> + return aes_cmac_one(session_key, prsk, 4, session_key);
> +}
> +
> +bool mesh_crypto_nonce(const uint8_t secret[32],
> + const uint8_t salt[16],
> + uint8_t nonce[13])
> +{
> + const uint8_t prsn[4] = "prsn";
> + uint8_t tmp[16];
> + bool result;
> +
> + if (!aes_cmac_one(salt, secret, 32, tmp))
> + return false;
> +
> + result = aes_cmac_one(tmp, prsn, 4, tmp);
> +
> + if (result)
> + memcpy(nonce, tmp + 3, 13);
> +
> + return result;
> +}
> +
> +bool mesh_crypto_s1(const void *info, size_t len, uint8_t salt[16])
> +{
> + const uint8_t zero[16] = {0};
> +
> + return aes_cmac_one(zero, info, len, salt);
> +}
> +
> +bool mesh_crypto_prov_prov_salt(const uint8_t conf_salt[16],
> + const uint8_t prov_rand[16],
> + const uint8_t dev_rand[16],
> + uint8_t prov_salt[16])
> +{
> + const uint8_t zero[16] = {0};
> + uint8_t tmp[16 * 3];
> +
> + memcpy(tmp, conf_salt, 16);
> + memcpy(tmp + 16, prov_rand, 16);
> + memcpy(tmp + 32, dev_rand, 16);
> +
> + return aes_cmac_one(zero, tmp, sizeof(tmp), prov_salt);
> +}
> +
> +bool mesh_crypto_prov_conf_key(const uint8_t secret[32],
> + const uint8_t salt[16],
> + uint8_t conf_key[16])
> +{
> + const uint8_t prck[4] = "prck";
> +
> + if (!aes_cmac_one(salt, secret, 32, conf_key))
> + return false;
> +
> + return aes_cmac_one(conf_key, prck, 4, conf_key);
> +}
> +
> +bool mesh_crypto_device_key(const uint8_t secret[32],
> + const uint8_t salt[16],
> + uint8_t device_key[16])
> +{
> + const uint8_t prdk[4] = "prdk";
> +
> + if (!aes_cmac_one(salt, secret, 32, device_key))
> + return false;
> +
> + return aes_cmac_one(device_key, prdk, 4, device_key);
> +}
> +
> +bool mesh_crypto_virtual_addr(const uint8_t virtual_label[16],
> + uint16_t *addr)
> +{
> + uint8_t tmp[16];
> +
> + if (!mesh_crypto_s1("vtad", 4, tmp))
> + return false;
> +
> + if (!addr || !aes_cmac_one(tmp, virtual_label, 16, tmp))
> + return false;
> +
> + *addr = (get_be16(tmp + 14) & 0x3fff) | 0x8000;
> +
> + return true;
> +}
> +
> +bool mesh_crypto_packet_encode(uint8_t *packet, uint8_t packet_len,
> + const uint8_t network_key[16],
> + uint32_t iv_index,
> + const uint8_t privacy_key[16])
> +{
> + uint8_t network_nonce[13] = { 0x00, 0x00 };
> + uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
> + uint8_t tmp[16];
> + int i;
> +
> + /* Detect Proxy packet by CTL == true && DST == 0x0000 */
> + if ((packet[1] & CTL) && get_be16(packet + 7) == 0)
> + network_nonce[0] = 0x03;
> + else
> + /* CTL + TTL */
> + network_nonce[1] = packet[1];
> +
> + /* Seq Num */
> + network_nonce[2] = packet[2];
> + network_nonce[3] = packet[3];
> + network_nonce[4] = packet[4];
> +
> + /* SRC */
> + network_nonce[5] = packet[5];
> + network_nonce[6] = packet[6];
> +
> + /* DST not available */
> + network_nonce[7] = 0;
> + network_nonce[8] = 0;
> +
> + /* IV Index */
> + put_be32(iv_index, network_nonce + 9);
> +
> + /* Check for Long net-MIC */
> + if (packet[1] & CTL) {
> + if (!mesh_crypto_aes_ccm_encrypt(network_nonce, network_key,
> + NULL, 0,
> + packet + 7, packet_len - 7 - 8,
> + packet + 7, NULL, sizeof(uint64_t)))
> + return false;
> + } else {
> + if (!mesh_crypto_aes_ccm_encrypt(network_nonce, network_key,
> + NULL, 0,
> + packet + 7, packet_len - 7 - 4,
> + packet + 7, NULL, sizeof(uint32_t)))
> + return false;
> + }
> +
> + put_be32(iv_index, privacy_counter + 5);
> + memcpy(privacy_counter + 9, packet + 7, 7);
> +
> + if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
> + return false;
> +
> + for (i = 0; i < 6; i++)
> + packet[1 + i] ^= tmp[i];
> +
> + return true;
> +}
> +
> +bool mesh_crypto_packet_decode(const uint8_t *packet, uint8_t packet_len,
> + bool proxy, uint8_t *out, uint32_t iv_index,
> + const uint8_t network_key[16],
> + const uint8_t privacy_key[16])
> +{
> + uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
> + uint8_t network_nonce[13] = { 0x00, 0x00, };
> + uint8_t tmp[16];
> + uint16_t src;
> + int i;
> +
> + if (packet_len < 14)
> + return false;
> +
> + put_be32(iv_index, privacy_counter + 5);
> + memcpy(privacy_counter + 9, packet + 7, 7);
> +
> + if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
> + return false;
> +
> + memcpy(out, packet, packet_len);
> + for (i = 0; i < 6; i++)
> + out[1 + i] ^= tmp[i];
> +
> + src = get_be16(out + 5);
> +
> + /* Pre-check SRC address for illegal values */
> + if (!src || src >= 0x8000)
> + return false;
> +
> + /* Detect Proxy packet by CTL == true && proxy == true */
> + if ((out[1] & CTL) && proxy)
> + network_nonce[0] = 0x03;
> + else
> + /* CTL + TTL */
> + network_nonce[1] = out[1];
> +
> + /* Seq Num */
> + network_nonce[2] = out[2];
> + network_nonce[3] = out[3];
> + network_nonce[4] = out[4];
> +
> + /* SRC */
> + network_nonce[5] = out[5];
> + network_nonce[6] = out[6];
> +
> + /* DST not available */
> + network_nonce[7] = 0;
> + network_nonce[8] = 0;
> +
> + /* IV Index */
> + put_be32(iv_index, network_nonce + 9);
> +
> + /* Check for Long MIC */
> + if (out[1] & CTL) {
> + uint64_t mic;
> +
> + if (!mesh_crypto_aes_ccm_decrypt(network_nonce, network_key,
> + NULL, 0, packet + 7, packet_len - 7,
> + out + 7, &mic, sizeof(mic)))
> + return false;
> +
> + mic ^= get_be64(out + packet_len - 8);
> + put_be64(mic, out + packet_len - 8);
> +
> + if (mic)
> + return false;
> + } else {
> + uint32_t mic;
> +
> + if (!mesh_crypto_aes_ccm_decrypt(network_nonce, network_key,
> + NULL, 0, packet + 7, packet_len - 7,
> + out + 7, &mic, sizeof(mic)))
> + return false;
> +
> + mic ^= get_be32(out + packet_len - 4);
> + put_be32(mic, out + packet_len - 4);
> +
> + if (mic)
> + return false;
> + }
> +
> + return true;
> +}
> +
> +bool mesh_get_random_bytes(void *buf, size_t num_bytes)
> +{
> + ssize_t len;
> + int fd;
> +
> + fd = open("/dev/urandom", O_RDONLY);
> + if (fd < 0)
> + return false;
> +
> + len = read(fd, buf, num_bytes);
> +
> + close(fd);
> +
> + if (len < 0)
> + return false;
> +
> + return true;
> +}
> diff --git a/mesh/gatt.c b/mesh/gatt.c
> new file mode 100644
> index 0000000..b981054
> --- /dev/null
> +++ b/mesh/gatt.c
> @@ -0,0 +1,609 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <sys/uio.h>
> +#include <wordexp.h>
> +
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "src/shared/io.h"
> +#include "gdbus/gdbus.h"
> +#include "lib/bluetooth.h"
> +#include "lib/uuid.h"
> +#include "client/display.h"
> +#include "node.h"
> +#include "util.h"
> +#include "gatt.h"
> +#include "prov.h"
> +#include "net.h"
> +
> +#define MESH_PROV_DATA_OUT_UUID_STR "00002adc-0000-1000-8000-00805f9b34fb"
> +#define MESH_PROXY_DATA_OUT_UUID_STR "00002ade-0000-1000-8000-00805f9b34fb"
> +
> +static struct io *write_io;
> +static uint16_t write_mtu;
> +
> +static struct io *notify_io;
> +static uint16_t notify_mtu;
> +
> +struct write_data {
> + GDBusProxy *proxy;
> + void *user_data;
> + struct iovec iov;
> + GDBusReturnFunction cb;
> + uint8_t *gatt_data;
> + uint8_t gatt_len;
> +};
> +
> +struct notify_data {
> + GDBusProxy *proxy;
> + bool enable;
> + GDBusReturnFunction cb;
> + void *user_data;
> +};
> +
> +bool mesh_gatt_is_child(GDBusProxy *proxy, GDBusProxy *parent,
> + const char *name)
> +{
> + DBusMessageIter iter;
> + const char *parent_path;
> +
> + if (!parent)
> + return FALSE;
> +
> + if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
> + return FALSE;
> +
> + dbus_message_iter_get_basic(&iter, &parent_path);
> +
> + if (!strcmp(parent_path, g_dbus_proxy_get_path(parent)))
> + return TRUE;
> + else
> + return FALSE;
> +}
> +
> +/* Refactor this once actual MTU is available */
> +#define GATT_MTU 23
> +
> +static void write_data_free(void *user_data)
> +{
> + struct write_data *data = user_data;
> +
> + g_free(data->gatt_data);
> + free(data);
> +}
> +
> +static void write_setup(DBusMessageIter *iter, void *user_data)
> +{
> + struct write_data *data = user_data;
> + struct iovec *iov = &data->iov;
> + DBusMessageIter array, dict;
> +
> + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
> + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
> + &iov->iov_base, iov->iov_len);
> + dbus_message_iter_close_container(iter, &array);
> +
> + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
> + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
> + DBUS_TYPE_STRING_AS_STRING
> + DBUS_TYPE_VARIANT_AS_STRING
> + DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
> + &dict);
> +
> + dbus_message_iter_close_container(iter, &dict);
> +}
> +
> +uint16_t mesh_gatt_sar(uint8_t **pkt, uint16_t size)
> +{
> + const uint8_t *data = *pkt;
> + uint8_t gatt_hdr = *data++;
> + uint8_t type = gatt_hdr & GATT_TYPE_MASK;
> + static uint8_t gatt_size;
> + static uint8_t gatt_pkt[67];
> +
> + print_byte_array("GATT-RX:\t", *pkt, size);
> + if (size < 1) {
> + gatt_pkt[0] = GATT_TYPE_INVALID;
> + /* TODO: Disconnect GATT per last paragraph sec 6.6 */
> + return 0;
> + }
> +
> + size--;
> +
> + switch (gatt_hdr & GATT_SAR_MASK) {
> + case GATT_SAR_FIRST:
> + gatt_size = 1;
> + gatt_pkt[0] = type;
> + /* TODO: Start Proxy Timeout */
> + /* fall through */
> +
> + case GATT_SAR_CONTINUE:
> + if (gatt_pkt[0] != type ||
> + gatt_size + size > MAX_GATT_SIZE) {
> +
> + /* Invalidate packet and return failure */
> + gatt_pkt[0] = GATT_TYPE_INVALID;
> + /* TODO: Disconnect GATT per last paragraph sec 6.6 */
> + return 0;
> + }
> +
> + memcpy(gatt_pkt + gatt_size, data, size);
> + gatt_size += size;
> +
> + /* We are good to this point, but incomplete */
> + return 0;
> +
> + default:
> + case GATT_SAR_COMPLETE:
> + gatt_size = 1;
> + gatt_pkt[0] = type;
> +
> + /* fall through */
> +
> + case GATT_SAR_LAST:
> + if (gatt_pkt[0] != type ||
> + gatt_size + size > MAX_GATT_SIZE) {
> +
> + /* Invalidate packet and return failure */
> + gatt_pkt[0] = GATT_TYPE_INVALID;
> + /* Disconnect GATT per last paragraph sec 6.6 */
> + return 0;
> + }
> +
> + memcpy(gatt_pkt + gatt_size, data, size);
> + gatt_size += size;
> + *pkt = gatt_pkt;
> + return gatt_size;
> + }
> +}
> +
> +static bool pipe_write(struct io *io, void *user_data)
> +{
> + struct write_data *data = user_data;
> + struct iovec iov[2];
> + uint8_t sar;
> + uint8_t max_len = write_mtu - 4;
> +
> + if (data == NULL)
> + return true;
> +
> + print_byte_array("GATT-TX:\t", data->gatt_data, data->gatt_len);
> +
> + sar = data->gatt_data[0];
> +
> + data->iov.iov_base = data->gatt_data + 1;
> + data->iov.iov_len--;
> +
> + iov[0].iov_base = &sar;
> + iov[0].iov_len = sizeof(sar);
> +
> + while (1) {
> + int err;
> +
> + iov[1] = data->iov;
> +
> + err = io_send(io, iov, 2);
> + if (err < 0) {
> + rl_printf("Failed to write: %s\n", strerror(-err));
> + write_data_free(data);
> + return false;
> + }
> +
> + switch (sar & GATT_SAR_MASK) {
> + case GATT_SAR_FIRST:
> + case GATT_SAR_CONTINUE:
> + data->gatt_len -= max_len;
> + data->iov.iov_base = data->iov.iov_base + max_len;
> +
> + sar &= GATT_TYPE_MASK;
> + if (max_len < data->gatt_len) {
> + data->iov.iov_len = max_len;
> + sar |= GATT_SAR_CONTINUE;
> + } else {
> + data->iov.iov_len = data->gatt_len;
> + sar |= GATT_SAR_LAST;
> + }
> +
> + break;
> +
> + default:
> + if(data->cb)
> + data->cb(NULL, data->user_data);
> + write_data_free(data);
> + return true;
> + }
> + }
> +}
> +
> +static void write_reply(DBusMessage *message, void *user_data)
> +{
> + struct write_data *data = user_data;
> + struct write_data *tmp;
> + uint8_t *dptr = data->gatt_data;
> + uint8_t max_len = GATT_MTU - 3;
> + uint8_t max_seg = GATT_MTU - 4;
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to write: %s\n", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + if (data == NULL)
> + return;
> +
> + switch (data->gatt_data[0] & GATT_SAR_MASK) {
> + case GATT_SAR_FIRST:
> + case GATT_SAR_CONTINUE:
> + tmp = g_new0(struct write_data, 1);
> + if (!data)
> + return;
> +
> + *tmp = *data;
> + tmp->gatt_data = g_malloc(data->gatt_len);
> +
> + if (!tmp->gatt_data) {
> + g_free(tmp);
> + return;
> + }
> +
> + tmp->gatt_data[0] = dptr[0];
> + data = tmp;
> + memcpy(data->gatt_data + 1, dptr + max_len,
> + data->gatt_len - max_seg);
> + data->gatt_len -= max_seg;
> + data->gatt_data[0] &= GATT_TYPE_MASK;
> + data->iov.iov_base = data->gatt_data;
> + if (max_len < data->gatt_len) {
> + data->iov.iov_len = max_len;
> + data->gatt_data[0] |= GATT_SAR_CONTINUE;
> + } else {
> + data->iov.iov_len = data->gatt_len;
> + data->gatt_data[0] |= GATT_SAR_LAST;
> + }
> +
> + break;
> +
> + default:
> + if(data->cb)
> + data->cb(message, data->user_data);
> + return;
> + }
> +
> + if (g_dbus_proxy_method_call(data->proxy, "WriteValue", write_setup,
> + write_reply, data, write_data_free) == FALSE) {
> + rl_printf("Failed to write\n");
> + write_data_free(data);
> + return;
> + }
> +
> +}
> +
> +static void write_io_destroy(void)
> +{
> + io_destroy(write_io);
> + write_io = NULL;
> + write_mtu = 0;
> +}
> +
> +static void notify_io_destroy(void)
> +{
> + io_destroy(notify_io);
> + notify_io = NULL;
> + notify_mtu = 0;
> +}
> +
> +static bool pipe_hup(struct io *io, void *user_data)
> +{
> + rl_printf("%s closed\n", io == notify_io ? "Notify" : "Write");
> +
> + if (io == notify_io)
> + notify_io_destroy();
> + else
> + write_io_destroy();
> +
> + return false;
> +}
> +
> +static struct io *pipe_io_new(int fd)
> +{
> + struct io *io;
> +
> + io = io_new(fd);
> +
> + io_set_close_on_destroy(io, true);
> +
> + io_set_disconnect_handler(io, pipe_hup, NULL, NULL);
> +
> + return io;
> +}
> +
> +static void acquire_write_reply(DBusMessage *message, void *user_data)
> +{
> + struct write_data *data = user_data;
> + DBusError error;
> + int fd;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + dbus_error_free(&error);
> + if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
> + write_setup, write_reply, data,
> + write_data_free) == FALSE) {
> + rl_printf("Failed to write\n");
> + write_data_free(data);
> + }
> + return;
> + }
> +
> + if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
> + DBUS_TYPE_UINT16, &write_mtu,
> + DBUS_TYPE_INVALID) == false)) {
> + rl_printf("Invalid AcquireWrite response\n");
> + return;
> + }
> +
> + rl_printf("AcquireWrite success: fd %d MTU %u\n", fd, write_mtu);
> +
> + write_io = pipe_io_new(fd);
> +
> + pipe_write(write_io, data);
> +}
> +
> +bool mesh_gatt_write(GDBusProxy *proxy, uint8_t *buf, uint16_t len,
> + GDBusReturnFunction cb, void *user_data)
> +{
> + struct write_data *data;
> + DBusMessageIter iter;
> + uint8_t max_len;
> +
> + if (!buf || !len)
> + return false;
> +
> + if (len > 69)
> + return false;
> +
> + data = g_new0(struct write_data, 1);
> + if (!data)
> + return false;
> +
> + max_len = write_mtu ? write_mtu - 3 : GATT_MTU - 3;
> +
> + /* TODO: should keep in queue in case we need to cancel write? */
> +
> + data->gatt_len = len;
> + data->gatt_data = g_memdup(buf, len);
> + data->gatt_data[0] &= GATT_TYPE_MASK;
> + if (max_len < len) {
> + len = max_len;
> + data->gatt_data[0] |= GATT_SAR_FIRST;
> + }
> + data->iov.iov_base = data->gatt_data;
> + data->iov.iov_len = len;
> + data->proxy = proxy;
> + data->user_data = user_data;
> + data->cb = cb;
> +
> + if (write_io)
> + return pipe_write(write_io, data);
> +
> + if (g_dbus_proxy_get_property(proxy, "WriteAcquired", &iter)) {
> + if (g_dbus_proxy_method_call(proxy, "AcquireWrite", NULL,
> + acquire_write_reply, data, NULL) == FALSE) {
> + rl_printf("Failed to AcquireWrite\n");
> + write_data_free(data);
> + return false;
> + }
> + } else {
> + if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
> + write_setup, write_reply, data,
> + write_data_free) == FALSE) {
> + rl_printf("Failed to write\n");
> + write_data_free(data);
> + return false;
> + }
> + print_byte_array("GATT-TX: ", buf, len);
> + rl_printf("Attempting to write %s\n",
> + g_dbus_proxy_get_path(proxy));
> + }
> +
> + return true;
> +}
> +
> +static void notify_reply(DBusMessage *message, void *user_data)
> +{
> + struct notify_data *data = user_data;
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to %s notify: %s\n",
> + data->enable ? "start" : "stop", error.name);
> + dbus_error_free(&error);
> + goto done;
> + }
> +
> + rl_printf("Notify %s\n", data->enable ? "started" : "stopped");
> +
> +done:
> + if (data->cb)
> + data->cb(message, data->user_data);
> +
> + g_free(data);
> +}
> +
> +static bool pipe_read(struct io *io, bool prov, void *user_data)
> +{
> + struct mesh_node *node = user_data;
> + uint8_t buf[512];
> + uint8_t *res;
> + int fd = io_get_fd(io);
> + ssize_t len;
> +
> + if (io != notify_io)
> + return true;
> +
> + while ((len = read(fd, buf, sizeof(buf)))) {
> + if (len <= 0)
> + break;
> +
> + res = buf;
> + mesh_gatt_sar(&res, len);
> +
> + if (prov)
> + prov_data_ready(node, res, len);
> + else
> + net_data_ready(res, len);
> + }
> +
> + return true;
> +}
> +
> +static bool pipe_read_prov(struct io *io, void *user_data)
> +{
> + return pipe_read(io, true, user_data);
> +}
> +
> +static bool pipe_read_proxy(struct io *io, void *user_data)
> +{
> + return pipe_read(io, false, user_data);
> +}
> +
> +static void acquire_notify_reply(DBusMessage *message, void *user_data)
> +{
> + struct notify_data *data = user_data;
> + DBusMessageIter iter;
> + DBusError error;
> + int fd;
> + const char *uuid;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + dbus_error_free(&error);
> + if (g_dbus_proxy_method_call(data->proxy, "StartNotify", NULL,
> + notify_reply, data, NULL) == FALSE) {
> + rl_printf("Failed to StartNotify\n");
> + g_free(data);
> + }
> + return;
> + }
> +
> + if (notify_io) {
> + io_destroy(notify_io);
> + notify_io = NULL;
> + }
> +
> + notify_mtu = 0;
> +
> + if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
> + DBUS_TYPE_UINT16, &notify_mtu,
> + DBUS_TYPE_INVALID) == false)) {
> + if (g_dbus_proxy_method_call(data->proxy, "StartNotify", NULL,
> + notify_reply, data, NULL) == FALSE) {
> + rl_printf("Failed to StartNotify\n");
> + g_free(data);
> + }
> + return;
> + }
> +
> + rl_printf("AcquireNotify success: fd %d MTU %u\n", fd, notify_mtu);
> +
> + if (g_dbus_proxy_get_property(data->proxy, "UUID", &iter) == FALSE)
> + goto done;
> +
> + notify_io = pipe_io_new(fd);
> +
> + dbus_message_iter_get_basic(&iter, &uuid);
> +
> + if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
> + io_set_read_handler(notify_io, pipe_read_prov, data->user_data,
> + NULL);
> + else if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
> + io_set_read_handler(notify_io, pipe_read_proxy, data->user_data,
> + NULL);
> +
> +done:
> + if (data->cb)
> + data->cb(message, data->user_data);
> +
> + g_free(data);
> +}
> +
> +bool mesh_gatt_notify(GDBusProxy *proxy, bool enable, GDBusReturnFunction cb,
> + void *user_data)
> +{
> + struct notify_data *data;
> + DBusMessageIter iter;
> + const char *method;
> +
> + data = g_new0(struct notify_data, 1);
> + data->proxy = proxy;
> + data->enable = enable;
> + data->cb = cb;
> + data->user_data = user_data;
> +
> + if (enable == TRUE) {
> + if (g_dbus_proxy_get_property(proxy, "NotifyAcquired", &iter)) {
> + method = "AcquireNotify";
> + cb = acquire_notify_reply;
> + } else {
> + method = "StartNotify";
> + cb = notify_reply;
> + }
> + } else {
> + if (notify_io) {
> + notify_io_destroy();
> + if (cb)
> + cb(NULL, user_data);
> + return true;
> + } else {
> + method = "StopNotify";
> + cb = notify_reply;
> + }
> + }
> +
> + if (g_dbus_proxy_method_call(proxy, method, NULL, cb,
> + data, NULL) == FALSE) {
> + rl_printf("Failed to %s\n", method);
> + return false;
> + }
> + return true;
> +}
> diff --git a/mesh/main.c b/mesh/main.c
> new file mode 100644
> index 0000000..a347484
> --- /dev/null
> +++ b/mesh/main.c
> @@ -0,0 +1,2269 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <sys/signalfd.h>
> +#include <wordexp.h>
> +
> +#include <inttypes.h>
> +#include <ctype.h>
> +#include <sys/file.h>
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include "bluetooth/bluetooth.h"
> +
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +#include "lib/uuid.h"
> +#include "src/shared/util.h"
> +#include "gdbus/gdbus.h"
> +#include "monitor/uuid.h"
> +#include "client/display.h"
> +#include "mesh-net.h"
> +#include "gatt.h"
> +#include "crypto.h"
> +#include "node.h"
> +#include "net.h"
> +#include "keys.h"
> +#include "prov.h"
> +#include "util.h"
> +#include "agent.h"
> +#include "prov-db.h"
> +#include "config-model.h"
> +#include "onoff-model.h"
> +
> +/* String display constants */
> +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
> +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
> +#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
> +
> +#define PROMPT_ON COLOR_BLUE "[meshctl]" COLOR_OFF "# "
> +#define PROMPT_OFF "Waiting to connect to bluetoothd..."
> +
> +#define MESH_PROV_DATA_IN_UUID_STR "00002adb-0000-1000-8000-00805f9b34fb"
> +#define MESH_PROV_DATA_OUT_UUID_STR "00002adc-0000-1000-8000-00805f9b34fb"
> +#define MESH_PROXY_DATA_IN_UUID_STR "00002add-0000-1000-8000-00805f9b34fb"
> +#define MESH_PROXY_DATA_OUT_UUID_STR "00002ade-0000-1000-8000-00805f9b34fb"
> +
> +static GMainLoop *main_loop;
> +static DBusConnection *dbus_conn;
> +
> +struct adapter {
> +GDBusProxy *proxy;
> + GList *mesh_devices;
> +};
> +
> +struct mesh_device {
> + GDBusProxy *proxy;
> + uint8_t dev_uuid[16];
> + gboolean hide;
> +};
> +
> +GList *service_list;
> +GList *char_list;
> +
> +static GList *ctrl_list;
> +static struct adapter *default_ctrl;
> +
> +static char *mesh_prov_db_filename;
> +static char *mesh_local_config_filename;
> +
> +static bool discovering = false;
> +static bool discover_mesh;
> +static uint16_t prov_net_key_index = NET_IDX_PRIMARY;
> +
> +static guint input = 0;
> +
> +#define CONN_TYPE_NETWORK 0x00
> +#define CONN_TYPE_IDENTITY 0x01
> +#define CONN_TYPE_PROVISION 0x02
> +#define CONN_TYPE_INVALID 0xff
> +
> +#define NET_IDX_INVALID 0xffff
> +
> +struct {
> + GDBusProxy *device;
> + GDBusProxy *service;
> + GDBusProxy *data_in;
> + GDBusProxy *data_out;
> + bool session_open;
> + uint16_t unicast;
> + uint16_t net_idx;
> + uint8_t dev_uuid[16];
> + uint8_t type;
> +} connection;
> +
> +static bool service_is_mesh(GDBusProxy *proxy, const char *target_uuid)
> +{
> + DBusMessageIter iter;
> + const char *uuid;
> +
> + if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> + return false;
> +
> + dbus_message_iter_get_basic(&iter, &uuid);
> +
> + if (target_uuid)
> + return (!bt_uuid_strcmp(uuid, target_uuid));
> + else if (bt_uuid_strcmp(uuid, MESH_PROV_SVC_UUID) ||
> + bt_uuid_strcmp(uuid, MESH_PROXY_SVC_UUID))
> + return true;
> + else
> + return false;
> +}
> +
> +static bool char_is_mesh(GDBusProxy *proxy, const char *target_uuid)
> +{
> + DBusMessageIter iter;
> + const char *uuid;
> +
> + if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> + return false;
> +
> + dbus_message_iter_get_basic(&iter, &uuid);
> +
> + if (target_uuid)
> + return (!bt_uuid_strcmp(uuid, target_uuid));
> +
> + if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_IN_UUID_STR))
> + return true;
> +
> + if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
> + return true;
> +
> + if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_IN_UUID_STR))
> + return true;
> +
> + if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
> + return true;
> +
> + return false;
> +}
> +
> +static gboolean check_default_ctrl(void)
> +{
> + if (!default_ctrl) {
> + rl_printf("No default controller available\n");
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +static void proxy_leak(gpointer data)
> +{
> + rl_printf("Leaking proxy %p\n", data);
> +}
> +
> +static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
> + gpointer user_data)
> +{
> + if (condition & G_IO_IN) {
> + rl_callback_read_char();
> + return TRUE;
> + }
> +
> + if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> + g_main_loop_quit(main_loop);
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +static guint setup_standard_input(void)
> +{
> + GIOChannel *channel;
> + guint source;
> +
> + channel = g_io_channel_unix_new(fileno(stdin));
> +
> + source = g_io_add_watch(channel,
> + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> + input_handler, NULL);
> +
> + g_io_channel_unref(channel);
> +
> + return source;
> +}
> +
> +static void connect_handler(DBusConnection *connection, void *user_data)
> +{
> + rl_set_prompt(PROMPT_ON);
> + rl_printf("\r");
> + rl_on_new_line();
> + rl_redisplay();
> +}
> +
> +static void disconnect_handler(DBusConnection *connection, void *user_data)
> +{
> + if (input > 0) {
> + g_source_remove(input);
> + input = 0;
> + }
> +
> + rl_set_prompt(PROMPT_OFF);
> + rl_printf("\r");
> + rl_on_new_line();
> + rl_redisplay();
> +
> + g_list_free_full(ctrl_list, proxy_leak);
> + ctrl_list = NULL;
> +
> + default_ctrl = NULL;
> +}
> +
> +static void print_adapter(GDBusProxy *proxy, const char *description)
> +{
> + DBusMessageIter iter;
> + const char *address, *name;
> +
> + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
> + return;
> +
> + dbus_message_iter_get_basic(&iter, &address);
> +
> + if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
> + dbus_message_iter_get_basic(&iter, &name);
> + else
> + name = "<unknown>";
> +
> + rl_printf("%s%s%sController %s %s %s\n",
> + description ? "[" : "",
> + description ? : "",
> + description ? "] " : "",
> + address, name,
> + default_ctrl &&
> + default_ctrl->proxy == proxy ?
> + "[default]" : "");
> +
> +}
> +
> +static void print_device(GDBusProxy *proxy, const char *description)
> +{
> + DBusMessageIter iter;
> + const char *address, *name;
> +
> + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
> + return;
> +
> + dbus_message_iter_get_basic(&iter, &address);
> +
> + if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
> + dbus_message_iter_get_basic(&iter, &name);
> + else
> + name = "<unknown>";
> +
> + rl_printf("%s%s%sDevice %s %s\n",
> + description ? "[" : "",
> + description ? : "",
> + description ? "] " : "",
> + address, name);
> +}
> +
> +static void print_iter(const char *label, const char *name,
> + DBusMessageIter *iter)
> +{
> + dbus_bool_t valbool;
> + dbus_uint32_t valu32;
> + dbus_uint16_t valu16;
> + dbus_int16_t vals16;
> + unsigned char byte;
> + const char *valstr;
> + DBusMessageIter subiter;
> + char *entry;
> +
> + if (iter == NULL) {
> + rl_printf("%s%s is nil\n", label, name);
> + return;
> + }
> +
> + switch (dbus_message_iter_get_arg_type(iter)) {
> + case DBUS_TYPE_INVALID:
> + rl_printf("%s%s is invalid\n", label, name);
> + break;
> + case DBUS_TYPE_STRING:
> + case DBUS_TYPE_OBJECT_PATH:
> + dbus_message_iter_get_basic(iter, &valstr);
> + rl_printf("%s%s: %s\n", label, name, valstr);
> + break;
> + case DBUS_TYPE_BOOLEAN:
> + dbus_message_iter_get_basic(iter, &valbool);
> + rl_printf("%s%s: %s\n", label, name,
> + valbool == TRUE ? "yes" : "no");
> + break;
> + case DBUS_TYPE_UINT32:
> + dbus_message_iter_get_basic(iter, &valu32);
> + rl_printf("%s%s: 0x%06x\n", label, name, valu32);
> + break;
> + case DBUS_TYPE_UINT16:
> + dbus_message_iter_get_basic(iter, &valu16);
> + rl_printf("%s%s: 0x%04x\n", label, name, valu16);
> + break;
> + case DBUS_TYPE_INT16:
> + dbus_message_iter_get_basic(iter, &vals16);
> + rl_printf("%s%s: %d\n", label, name, vals16);
> + break;
> + case DBUS_TYPE_BYTE:
> + dbus_message_iter_get_basic(iter, &byte);
> + rl_printf("%s%s: 0x%02x\n", label, name, byte);
> + break;
> + case DBUS_TYPE_VARIANT:
> + dbus_message_iter_recurse(iter, &subiter);
> + print_iter(label, name, &subiter);
> + break;
> + case DBUS_TYPE_ARRAY:
> + dbus_message_iter_recurse(iter, &subiter);
> + while (dbus_message_iter_get_arg_type(&subiter) !=
> + DBUS_TYPE_INVALID) {
> + print_iter(label, name, &subiter);
> + dbus_message_iter_next(&subiter);
> + }
> + break;
> + case DBUS_TYPE_DICT_ENTRY:
> + dbus_message_iter_recurse(iter, &subiter);
> + entry = g_strconcat(name, "Key", NULL);
> + print_iter(label, entry, &subiter);
> + g_free(entry);
> +
> + entry = g_strconcat(name, " Value", NULL);
> + dbus_message_iter_next(&subiter);
> + print_iter(label, entry, &subiter);
> + g_free(entry);
> + break;
> + default:
> + rl_printf("%s%s has unsupported type\n", label, name);
> + break;
> + }
> +}
> +
> +static void print_property(GDBusProxy *proxy, const char *name)
> +{
> + DBusMessageIter iter;
> +
> + if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
> + return;
> +
> + print_iter("\t", name, &iter);
> +}
> +
> +static void forget_mesh_devices()
> +{
> + g_list_free_full(default_ctrl->mesh_devices, g_free);
> + default_ctrl->mesh_devices = NULL;
> +}
> +
> +static struct mesh_device *find_device_by_uuid(GList *source, uint8_t uuid[16])
> +{
> + GList *list;
> +
> + for (list = g_list_first(source); list; list = g_list_next(list)) {
> + struct mesh_device *dev = list->data;
> +
> + if (!memcmp(dev->dev_uuid, uuid, 16))
> + return dev;
> + }
> +
> + return NULL;
> +}
> +
> +static void print_prov_service(struct prov_svc_data *prov_data)
> +{
> + const char *prefix = "\t\t";
> + char txt_uuid[16 * 2 + 1];
> + int i;
> +
> + rl_printf("%sMesh Provisioning Service (%s)\n", prefix,
> + MESH_PROV_SVC_UUID);
> + for (i = 0; i < 16; ++i) {
> + sprintf(txt_uuid + (i * 2), "%2.2x", prov_data->dev_uuid[i]);
> + }
> +
> + rl_printf("%s\tDevice UUID: %s\n", prefix, txt_uuid);
> + rl_printf("%s\tOOB: %4.4x\n", prefix, prov_data->oob);
> +
> +}
> +
> +static bool parse_prov_service_data(const char *uuid, uint8_t *data, int len,
> + void *data_out)
> +{
> + struct prov_svc_data *prov_data = data_out;
> + int i;
> +
> + if (len < 18)
> + return false;
> +
> + for (i = 0; i < 16; ++i) {
> + prov_data->dev_uuid[i] = data[i];
> + }
> +
> + prov_data->oob = get_be16(&data[16]);
> +
> + return true;
> +}
> +
> +static bool parse_mesh_service_data(const char *uuid, uint8_t *data, int len,
> + void *data_out)
> +{
> + const char *prefix = "\t\t";
> +
> + if (!(len == 9 && data[0] == 0x00) && !(len == 17 && data[0] == 0x01)) {
> + rl_printf("Unexpected mesh proxy service data length %d\n",
> + len);
> + return false;
> + }
> +
> + if (data[0] != connection.type)
> + return false;
> +
> + if (data[0] == CONN_TYPE_IDENTITY) {
> + uint8_t *key;
> +
> + if (IS_UNASSIGNED(connection.unicast)) {
> + /* This would be a bug */
> + rl_printf("Error: Searching identity with "
> + "unicast 0000\n");
> + return false;
> + }
> +
> + key = keys_net_key_get(prov_net_key_index, true);
> + if (!key)
> + return false;
> +
> + if (!mesh_crypto_identity_check(key, connection.unicast,
> + &data[1]))
> + return false;
> +
> + if (discovering) {
> + rl_printf("\n%sMesh Proxy Service (%s)\n", prefix,
> + uuid);
> + rl_printf("%sIdentity for node %4.4x\n", prefix,
> + connection.unicast);
> + }
> +
> + } else if (data[0] == CONN_TYPE_NETWORK) {
> + uint16_t net_idx = net_validate_proxy_beacon(data + 1);
> +
> + if (net_idx == NET_IDX_INVALID || net_idx != connection.net_idx)
> + return false;
> +
> + if (discovering) {
> + rl_printf("\n%sMesh Proxy Service (%s)\n", prefix,
> + uuid);
> + rl_printf("%sNetwork Beacon for net index %4.4x\n",
> + prefix, net_idx);
> + }
> + }
> +
> + return true;
> +}
> +
> +static bool parse_service_data(GDBusProxy *proxy, const char *target_uuid,
> + void *data_out)
> +{
> + DBusMessageIter iter, entries;
> + bool mesh_prov = false;
> + bool mesh_proxy = false;
> +
> + if (target_uuid) {
> + mesh_prov = !strcmp(target_uuid, MESH_PROV_SVC_UUID);
> + mesh_proxy = !strcmp(target_uuid, MESH_PROXY_SVC_UUID);
> + }
> +
> + if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
> + return true;
> +
> + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
> + return false;
> +
> + dbus_message_iter_recurse(&iter, &entries);
> +
> + while (dbus_message_iter_get_arg_type(&entries)
> + == DBUS_TYPE_DICT_ENTRY) {
> + DBusMessageIter value, entry, array;
> + const char *uuid_str;
> + bt_uuid_t uuid;
> + uint8_t *service_data;
> + int len;
> +
> + dbus_message_iter_recurse(&entries, &entry);
> + dbus_message_iter_get_basic(&entry, &uuid_str);
> +
> + if (bt_string_to_uuid(&uuid, uuid_str) < 0)
> + goto fail;
> +
> + dbus_message_iter_next(&entry);
> +
> + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
> + goto fail;
> +
> + dbus_message_iter_recurse(&entry, &value);
> +
> + if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
> + goto fail;
> +
> + dbus_message_iter_recurse(&value, &array);
> +
> + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
> + goto fail;
> +
> + dbus_message_iter_get_fixed_array(&array, &service_data, &len);
> +
> + if (mesh_prov && !strcmp(uuid_str, MESH_PROV_SVC_UUID)) {
> + return parse_prov_service_data(uuid_str, service_data,
> + len, data_out);
> + } else if (mesh_proxy &&
> + !strcmp(uuid_str, MESH_PROXY_SVC_UUID)) {
> + return parse_mesh_service_data(uuid_str, service_data,
> + len, data_out);
> + }
> +
> + dbus_message_iter_next(&entries);
> + }
> +
> + if (!target_uuid)
> + return true;
> +fail:
> + return false;
> +}
> +
> +static void print_uuids(GDBusProxy *proxy)
> +{
> + DBusMessageIter iter, value;
> +
> + if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
> + return;
> +
> + dbus_message_iter_recurse(&iter, &value);
> +
> + while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
> + const char *uuid, *text;
> +
> + dbus_message_iter_get_basic(&value, &uuid);
> +
> + text = uuidstr_to_str(uuid);
> + if (text) {
> + char str[26];
> + unsigned int n;
> +
> + str[sizeof(str) - 1] = '\0';
> +
> + n = snprintf(str, sizeof(str), "%s", text);
> + if (n > sizeof(str) - 1) {
> + str[sizeof(str) - 2] = '.';
> + str[sizeof(str) - 3] = '.';
> + if (str[sizeof(str) - 4] == ' ')
> + str[sizeof(str) - 4] = '.';
> +
> + n = sizeof(str) - 1;
> + }
> +
> + rl_printf("\tUUID: %s%*c(%s)\n",
> + str, 26 - n, ' ', uuid);
> + } else
> + rl_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
> +
> + dbus_message_iter_next(&value);
> + }
> +}
> +
> +static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
> +{
> + DBusMessageIter iter;
> + const char *adapter, *path;
> +
> + if (!master)
> + return FALSE;
> +
> + if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
> + return FALSE;
> +
> + dbus_message_iter_get_basic(&iter, &adapter);
> + path = g_dbus_proxy_get_path(master);
> +
> + if (!strcmp(path, adapter))
> + return TRUE;
> +
> + return FALSE;
> +}
> +
> +static struct adapter *find_parent(GDBusProxy *device)
> +{
> + GList *list;
> +
> + for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
> + struct adapter *adapter = list->data;
> +
> + if (device_is_child(device, adapter->proxy) == TRUE)
> + return adapter;
> + }
> + return NULL;
> +}
> +
> +static void set_connected_device(GDBusProxy *proxy)
> +{
> + char *desc = NULL;
> + DBusMessageIter iter;
> + char buf[10];
> + bool mesh;
> +
> + connection.device = proxy;
> +
> + if (proxy == NULL) {
> + memset(&connection, 0, sizeof(connection));
> + connection.type = CONN_TYPE_INVALID;
> + goto done;
> + }
> +
> + if (connection.type == CONN_TYPE_IDENTITY) {
> + mesh = true;
> + snprintf(buf, 10, "Node-%4.4x", connection.unicast);
> + } else if (connection.type == CONN_TYPE_NETWORK) {
> + mesh = true;
> + snprintf(buf, 9, "Net-%4.4x", connection.net_idx);
> + } else {
> + mesh = false;
> + }
> +
> + if (!g_dbus_proxy_get_property(proxy, "Alias", &iter) && !mesh)
> + goto done;
> +
> + dbus_message_iter_get_basic(&iter, &desc);
> + desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
> + (desc && mesh) ? "-" : "",
> + mesh ? buf : "");
> +
> +done:
> + rl_set_prompt(desc ? desc : PROMPT_ON);
> + rl_printf("\r");
> + rl_on_new_line();
> + g_free(desc);
> +
> + /* If disconnected, return to main menu */
> + if (proxy == NULL)
> + cmd_menu_main(true);
> +}
> +
> +static void connect_reply(DBusMessage *message, void *user_data)
> +{
> + GDBusProxy *proxy = user_data;
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to connect: %s\n", error.name);
> + dbus_error_free(&error);
> + set_connected_device(NULL);
> + return;
> + }
> +
> + rl_printf("Connection successful\n");
> +
> + set_connected_device(proxy);
> +}
> +
> +static void update_device_info(GDBusProxy *proxy)
> +{
> + struct adapter *adapter = find_parent(proxy);
> + DBusMessageIter iter;
> + struct prov_svc_data prov_data;
> +
> + if (!adapter) {
> + /* TODO: Error */
> + return;
> + }
> +
> + if (adapter != default_ctrl)
> + return;
> +
> + if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
> + return;
> +
> + if (parse_service_data(proxy, MESH_PROV_SVC_UUID, &prov_data)) {
> + struct mesh_device *dev;
> +
> + dev = find_device_by_uuid(adapter->mesh_devices,
> + prov_data.dev_uuid);
> +
> + /* Display provisioning service once per sicovery session */
> + if (discovering && (!dev || !dev->hide))
> + print_prov_service(&prov_data);
> +
> + if (dev) {
> + dev->proxy = proxy;
> + dev->hide = discovering;
> + return;
> + }
> +
> + dev = g_malloc0(sizeof(struct mesh_device));
> + if (!dev)
> + return;
> +
> + dev->proxy = proxy;
> + dev->hide = discovering;
> +
> + memcpy(dev->dev_uuid, prov_data.dev_uuid, 16);
> +
> + adapter->mesh_devices = g_list_append(adapter->mesh_devices,
> + dev);
> + print_device(proxy, COLORED_NEW);
> +
> + node_create_new(&prov_data);
> +
> + } else if (parse_service_data(proxy, MESH_PROXY_SVC_UUID, NULL) &&
> + discover_mesh) {
> + bool res;
> +
> + g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
> + NULL, NULL, NULL, NULL);
> + discover_mesh = false;
> +
> + forget_mesh_devices();
> +
> + res = g_dbus_proxy_method_call(proxy, "Connect", NULL,
> + connect_reply, proxy, NULL);
> +
> + if (!res)
> + rl_printf("Failed to connect to mesh\n");
> +
> + else
> + rl_printf("Trying to connect to mesh\n");
> +
> + }
> +}
> +
> +static void adapter_added(GDBusProxy *proxy)
> +{
> + struct adapter *adapter = g_malloc0(sizeof(struct adapter));
> +
> + adapter->proxy = proxy;
> + ctrl_list = g_list_append(ctrl_list, adapter);
> +
> + if (!default_ctrl)
> + default_ctrl = adapter;
> +
> + print_adapter(proxy, COLORED_NEW);
> +}
> +
> +static void data_out_notify(GDBusProxy *proxy, bool enable,
> + GDBusReturnFunction cb)
> +{
> + struct mesh_node *node;
> +
> + node = node_find_by_uuid(connection.dev_uuid);
> +
> + if (!mesh_gatt_notify(proxy, enable, cb, node))
> + rl_printf("Failed to %s notification on %s\n", enable ?
> + "start" : "stop", g_dbus_proxy_get_path(proxy));
> + else
> + rl_printf("%s notification on %s\n", enable ?
> + "Start" : "Stop", g_dbus_proxy_get_path(proxy));
> +}
> +
> +struct disconnect_data {
> + GDBusReturnFunction cb;
> + void *data;
> +};
> +
> +static void disconnect(GDBusReturnFunction cb, void *user_data)
> +{
> + GDBusProxy *proxy;
> + DBusMessageIter iter;
> + const char *addr;
> +
> + proxy = connection.device;
> + if (!proxy)
> + return;
> +
> + if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, cb, user_data,
> + NULL) == FALSE) {
> + rl_printf("Failed to disconnect\n");
> + return;
> + }
> +
> + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
> + dbus_message_iter_get_basic(&iter, &addr);
> +
> + rl_printf("Attempting to disconnect from %s\n", addr);
> +}
> +
> +static void disc_notify_cb(DBusMessage *message, void *user_data)
> +{
> + struct disconnect_data *disc_data = user_data;
> +
> + disconnect(disc_data->cb, disc_data->data);
> +
> + g_free(user_data);
> +}
> +
> +static void disconnect_device(GDBusReturnFunction cb, void *user_data)
> +{
> + DBusMessageIter iter;
> +
> + net_session_close(connection.data_in);
> +
> + /* Stop notificiation on prov_out or proxy out characteristics */
> + if (connection.data_out) {
> + if (g_dbus_proxy_get_property(connection.data_out, "Notifying",
> + &iter) == TRUE) {
> + struct disconnect_data *disc_data;
> + disc_data = g_malloc(sizeof(struct disconnect_data));
> + disc_data->cb = cb;
> + disc_data->data = user_data;
> +
> + if (mesh_gatt_notify(connection.data_out, false,
> + disc_notify_cb, disc_data))
> + return;
> + }
> + }
> +
> + disconnect(cb, user_data);
> +}
> +
> +static void mesh_prov_done(void *user_data, int status);
> +
> +static void notify_prov_out_cb(DBusMessage *message, void *user_data)
> +{
> + struct mesh_node *node = user_data;
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to start notify: %s\n", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + rl_printf("Notify for Mesh Provisioning Out Data started\n");
> +
> + if (connection.type != CONN_TYPE_PROVISION) {
> + rl_printf("Error: wrong connection type %d (expected %d)\n",
> + connection.type, CONN_TYPE_PROVISION);
> + return;
> + }
> +
> + if (!connection.data_in) {
> + rl_printf("Error: don't have mesh provisioning data in\n");
> + return;
> + }
> +
> + if (!node) {
> + rl_printf("Error: provisioning node not present\n");
> + return;
> + }
> +
> + if(!prov_open(node, connection.data_in, prov_net_key_index,
> + mesh_prov_done, node))
> + {
> + rl_printf("Failed to start provisioning\n");
> + node_free(node);
> + disconnect_device(NULL, NULL);
> + } else
> + rl_printf("Initiated provisioning\n");
> +
> +}
> +
> +static void session_open_cb (int status)
> +{
> + if (status) {
> + rl_printf("Failed to open Mesh session\n");
> + disconnect_device(NULL, NULL);
> + return;
> + }
> +
> + rl_printf("Mesh session is open\n");
> +
> + /* Get composition data for a newly provisioned node */
> + if (connection.type == CONN_TYPE_IDENTITY)
> + config_client_get_composition(connection.unicast);
> +}
> +
> +static void notify_proxy_out_cb(DBusMessage *message, void *user_data)
> +{
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to start notify: %s\n", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + rl_printf("Notify for Mesh Proxy Out Data started\n");
> +
> + if (connection.type != CONN_TYPE_IDENTITY &&
> + connection.type != CONN_TYPE_NETWORK) {
> + rl_printf("Error: wrong connection type %d "
> + "(expected %d or %d)\n", connection.type,
> + CONN_TYPE_IDENTITY, CONN_TYPE_NETWORK);
> + return;
> + }
> +
> + if (!connection.data_in) {
> + rl_printf("Error: don't have mesh proxy data in\n");
> + return;
> + }
> +
> + rl_printf("Trying to open mesh session\n");
> + net_session_open(connection.data_in, true, session_open_cb);
> + connection.session_open = true;
> +}
> +
> +static GDBusProxy *get_characteristic(GDBusProxy *device, const char *char_uuid)
> +{
> + GList *l;
> + GDBusProxy *service;
> + const char *svc_uuid;
> +
> + if (connection.type == CONN_TYPE_PROVISION) {
> + svc_uuid = MESH_PROV_SVC_UUID;
> + } else {
> + svc_uuid = MESH_PROXY_SVC_UUID;
> + }
> + for (l = service_list; l; l = l->next) {
> + if (mesh_gatt_is_child(l->data, device, "Device") &&
> + service_is_mesh(l->data, svc_uuid))
> + break;
> + }
> +
> + if (l)
> + service = l->data;
> + else {
> + rl_printf("Mesh service not found\n");
> + return NULL;
> + }
> +
> + for (l = char_list; l; l = l->next) {
> + if (mesh_gatt_is_child(l->data, service, "Service") &&
> + char_is_mesh(l->data, char_uuid)) {
> + rl_printf("Found matching char: path %s, uuid %s\n",
> + g_dbus_proxy_get_path(l->data), char_uuid);
> + return l->data;
> + }
> + }
> + return NULL;
> +}
> +
> +static void mesh_session_setup(GDBusProxy *proxy)
> +{
> + if (connection.type == CONN_TYPE_PROVISION) {
> + connection.data_in = get_characteristic(proxy,
> + MESH_PROV_DATA_IN_UUID_STR);
> + if (!connection.data_in)
> + goto fail;
> +
> + connection.data_out = get_characteristic(proxy,
> + MESH_PROV_DATA_OUT_UUID_STR);
> + if (!connection.data_out)
> + goto fail;
> +
> + data_out_notify(connection.data_out, true, notify_prov_out_cb);
> +
> + } else if (connection.type != CONN_TYPE_INVALID){
> +
> + connection.data_in = get_characteristic(proxy,
> + MESH_PROXY_DATA_IN_UUID_STR);
> + if (!connection.data_in)
> + goto fail;
> +
> + connection.data_out = get_characteristic(proxy,
> + MESH_PROXY_DATA_OUT_UUID_STR);
> + if (!connection.data_out)
> + goto fail;
> +
> + data_out_notify(connection.data_out, true, notify_proxy_out_cb);
> + }
> +
> + return;
> +
> +fail:
> +
> + rl_printf("Services resolved, mesh characteristics not found\n");
> +}
> +
> +static void proxy_added(GDBusProxy *proxy, void *user_data)
> +{
> + const char *interface;
> +
> + interface = g_dbus_proxy_get_interface(proxy);
> +
> + if (!strcmp(interface, "org.bluez.Device1")) {
> + update_device_info(proxy);
> +
> + } else if (!strcmp(interface, "org.bluez.Adapter1")) {
> +
> + adapter_added(proxy);
> +
> + } else if (!strcmp(interface, "org.bluez.GattService1") &&
> + service_is_mesh(proxy, NULL)) {
> +
> + rl_printf("Service added %s\n", g_dbus_proxy_get_path(proxy));
> + service_list = g_list_append(service_list, proxy);
> +
> + } else if (!strcmp(interface, "org.bluez.GattCharacteristic1") &&
> + char_is_mesh(proxy, NULL)) {
> +
> + rl_printf("Char added %s:\n", g_dbus_proxy_get_path(proxy));
> +
> + char_list = g_list_append(char_list, proxy);
> + }
> +}
> +
> +static void start_discovery_reply(DBusMessage *message, void *user_data)
> +{
> + dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to %s discovery: %s\n",
> + enable == TRUE ? "start" : "stop", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + rl_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
> +}
> +
> +static struct mesh_device *find_device_by_proxy(GList *source,
> + GDBusProxy *proxy)
> +{
> + GList *list;
> +
> + for (list = g_list_first(source); list; list = g_list_next(list)) {
> + struct mesh_device *dev = list->data;
> + GDBusProxy *proxy = dev->proxy;
> +
> + if (dev->proxy == proxy)
> + return dev;
> + }
> +
> + return NULL;
> +}
> +
> +static void device_removed(GDBusProxy *proxy)
> +{
> + struct adapter *adapter = find_parent(proxy);
> + struct mesh_device *dev;
> +
> + if (!adapter) {
> + /* TODO: Error */
> + return;
> + }
> +
> + dev = find_device_by_proxy(adapter->mesh_devices, proxy);
> + if (dev)
> + adapter->mesh_devices = g_list_remove(adapter->mesh_devices,
> + dev);
> +
> + print_device(proxy, COLORED_DEL);
> +
> + if (connection.device == proxy)
> + set_connected_device(NULL);
> +
> +}
> +
> +static void adapter_removed(GDBusProxy *proxy)
> +{
> + GList *ll;
> + for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll)) {
> + struct adapter *adapter = ll->data;
> +
> + if (adapter->proxy == proxy) {
> + print_adapter(proxy, COLORED_DEL);
> +
> + if (default_ctrl && default_ctrl->proxy == proxy) {
> + default_ctrl = NULL;
> + set_connected_device(NULL);
> + }
> +
> + ctrl_list = g_list_remove_link(ctrl_list, ll);
> +
> + g_list_free_full(adapter->mesh_devices, g_free);
> + g_free(adapter);
> + g_list_free(ll);
> + return;
> + }
> + }
> +}
> +
> +static void proxy_removed(GDBusProxy *proxy, void *user_data)
> +{
> + const char *interface;
> +
> + interface = g_dbus_proxy_get_interface(proxy);
> +
> + if (!strcmp(interface, "org.bluez.Device1")) {
> + device_removed(proxy);
> + } else if (!strcmp(interface, "org.bluez.Adapter1")) {
> + adapter_removed(proxy);
> + } else if (!strcmp(interface, "org.bluez.GattService1")) {
> + if (proxy == connection.service) {
> + if (service_is_mesh(proxy, MESH_PROXY_SVC_UUID)) {
> + data_out_notify(connection.data_out,
> + false, NULL);
> + net_session_close(connection.data_in);
> + }
> + connection.service = NULL;
> + connection.data_in = NULL;
> + connection.data_out = NULL;
> + }
> +
> + service_list = g_list_remove(service_list, proxy);
> +
> + } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
> + char_list = g_list_remove(char_list, proxy);
> + }
> +}
> +
> +static int get_characteristic_value(DBusMessageIter *value, uint8_t *buf)
> +{
> + DBusMessageIter array;
> + uint8_t *data;
> + int len;
> +
> + if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
> + return 0;
> +
> + dbus_message_iter_recurse(value, &array);
> +
> + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
> + return 0;
> +
> + dbus_message_iter_get_fixed_array(&array, &data, &len);
> + memcpy(buf, data, len);
> +
> + return len;
> +}
> +
> +static bool process_mesh_characteristic(GDBusProxy *proxy)
> +{
> + DBusMessageIter iter;
> + const char *uuid;
> + uint8_t *res;
> + uint8_t buf[256];
> + bool is_prov;
> +
> + if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
> + return false;
> +
> + dbus_message_iter_get_basic(&iter, &uuid);
> +
> + if (g_dbus_proxy_get_property(proxy, "Value", &iter) == FALSE)
> + return false;
> +
> + is_prov = !bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR);
> +
> + if (is_prov || !bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
> + {
> + struct mesh_node *node;
> + uint16_t len;
> +
> + len = get_characteristic_value(&iter, buf);
> +
> + if (!len || len > 69)
> + return false;
> +
> + res = buf;
> + len = mesh_gatt_sar(&res, len);
> +
> + if (!len)
> + return false;
> +
> + if (is_prov) {
> + node = node_find_by_uuid(connection.dev_uuid);
> +
> + if (!node) {
> + rl_printf("Node not found?\n");
> + return false;
> + }
> +
> + return prov_data_ready(node, res, len);
> + }
> +
> + return net_data_ready(res, len);
> + }
> +
> + return false;
> +}
> +
> +
> +static void property_changed(GDBusProxy *proxy, const char *name,
> + DBusMessageIter *iter, void *user_data)
> +{
> + const char *interface;
> +
> + interface = g_dbus_proxy_get_interface(proxy);
> +
> + if (!strcmp(interface, "org.bluez.Device1")) {
> +
> + if (default_ctrl && device_is_child(proxy,
> + default_ctrl->proxy) == TRUE) {
> +
> + if (strcmp(name, "Connected") == 0) {
> + dbus_bool_t connected;
> + dbus_message_iter_get_basic(iter, &connected);
> +
> + if (connected && connection.device == NULL)
> + set_connected_device(proxy);
> + else if (!connected &&
> + connection.device == proxy)
> + set_connected_device(NULL);
> + } else if ((strcmp(name, "Alias") == 0) &&
> + connection.device == proxy) {
> + /* Re-generate prompt */
> + set_connected_device(proxy);
> + } else if (!strcmp(name, "ServiceData")) {
> + update_device_info(proxy);
> + } else if (!strcmp(name, "ServicesResolved")) {
> + gboolean resolved;
> +
> + dbus_message_iter_get_basic(iter, &resolved);
> +
> + rl_printf("Services resolved %s\n", resolved ?
> + "yes" : "no");
> +
> + if (resolved)
> + mesh_session_setup(connection.device);
> + }
> +
> + }
> + } else if (!strcmp(interface, "org.bluez.Adapter1")) {
> + DBusMessageIter addr_iter;
> + char *str;
> +
> + rl_printf("Adapter property changed \n");
> + if (g_dbus_proxy_get_property(proxy, "Address",
> + &addr_iter) == TRUE) {
> + const char *address;
> +
> + dbus_message_iter_get_basic(&addr_iter, &address);
> + str = g_strdup_printf("[" COLORED_CHG
> + "] Controller %s ", address);
> + } else
> + str = g_strdup("");
> +
> + if (strcmp(name, "Discovering") == 0) {
> + int temp;
> +
> + dbus_message_iter_get_basic(iter, &temp);
> + discovering = !!temp;
> + }
> +
> + print_iter(str, name, iter);
> + g_free(str);
> + } else if (!strcmp(interface, "org.bluez.GattService1")) {
> + rl_printf("Service property changed %s\n",
> + g_dbus_proxy_get_path(proxy));
> + } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
> + rl_printf("Characteristic property changed %s\n",
> + g_dbus_proxy_get_path(proxy));
> +
> + if ((connection.type == CONN_TYPE_PROVISION) ||
> + connection.session_open)
> + process_mesh_characteristic(proxy);
> + }
> +}
> +
> +static void message_handler(DBusConnection *connection,
> + DBusMessage *message, void *user_data)
> +{
> + rl_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
> + dbus_message_get_member(message));
> +}
> +
> +static struct adapter *find_ctrl_by_address(GList *source, const char *address)
> +{
> + GList *list;
> +
> + for (list = g_list_first(source); list; list = g_list_next(list)) {
> + struct adapter *adapter = list->data;
> + DBusMessageIter iter;
> + const char *str;
> +
> + if (g_dbus_proxy_get_property(adapter->proxy,
> + "Address", &iter) == FALSE)
> + continue;
> +
> + dbus_message_iter_get_basic(&iter, &str);
> +
> + if (!strcmp(str, address))
> + return adapter;
> + }
> +
> + return NULL;
> +}
> +
> +static gboolean parse_argument_on_off(const char *arg, dbus_bool_t *value)
> +{
> + if (!arg || !strlen(arg)) {
> + rl_printf("Missing on/off argument\n");
> + return FALSE;
> + }
> +
> + if (!strcmp(arg, "on") || !strcmp(arg, "yes")) {
> + *value = TRUE;
> + return TRUE;
> + }
> +
> + if (!strcmp(arg, "off") || !strcmp(arg, "no")) {
> + *value = FALSE;
> + return TRUE;
> + }
> +
> + rl_printf("Invalid argument %s\n", arg);
> + return FALSE;
> +}
> +
> +static void cmd_list(const char *arg)
> +{
> + GList *list;
> +
> + for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
> + struct adapter *adapter = list->data;
> + print_adapter(adapter->proxy, NULL);
> + }
> +}
> +
> +static void cmd_show(const char *arg)
> +{
> + struct adapter *adapter;
> + GDBusProxy *proxy;
> + DBusMessageIter iter;
> + const char *address;
> +
> +
> + if (!arg || !strlen(arg)) {
> + if (check_default_ctrl() == FALSE)
> + return;
> +
> + proxy = default_ctrl->proxy;
> + } else {
> + adapter = find_ctrl_by_address(ctrl_list, arg);
> + if (!adapter) {
> + rl_printf("Controller %s not available\n", arg);
> + return;
> + }
> + proxy = adapter->proxy;
> + }
> +
> + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
> + return;
> +
> + dbus_message_iter_get_basic(&iter, &address);
> + rl_printf("Controller %s\n", address);
> +
> + print_property(proxy, "Name");
> + print_property(proxy, "Alias");
> + print_property(proxy, "Class");
> + print_property(proxy, "Powered");
> + print_property(proxy, "Discoverable");
> + print_uuids(proxy);
> + print_property(proxy, "Modalias");
> + print_property(proxy, "Discovering");
> +}
> +
> +static void cmd_select(const char *arg)
> +{
> + struct adapter *adapter;
> +
> + if (!arg || !strlen(arg)) {
> + rl_printf("Missing controller address argument\n");
> + return;
> + }
> +
> + adapter = find_ctrl_by_address(ctrl_list, arg);
> + if (!adapter) {
> + rl_printf("Controller %s not available\n", arg);
> + return;
> + }
> +
> + if (default_ctrl && default_ctrl->proxy == adapter->proxy)
> + return;
> +
> + forget_mesh_devices();
> +
> + default_ctrl = adapter;
> + print_adapter(adapter->proxy, NULL);
> +}
> +
> +static void generic_callback(const DBusError *error, void *user_data)
> +{
> + char *str = user_data;
> +
> + if (dbus_error_is_set(error))
> + rl_printf("Failed to set %s: %s\n", str, error->name);
> + else
> + rl_printf("Changing %s succeeded\n", str);
> +}
> +
> +static void cmd_power(const char *arg)
> +{
> + dbus_bool_t powered;
> + char *str;
> +
> + if (parse_argument_on_off(arg, &powered) == FALSE)
> + return;
> +
> + if (check_default_ctrl() == FALSE)
> + return;
> +
> + str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
> +
> + if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Powered",
> + DBUS_TYPE_BOOLEAN, &powered,
> + generic_callback, str, g_free) == TRUE)
> + return;
> +
> + g_free(str);
> +}
> +
> +static void cmd_scan(const char *arg)
> +{
> + dbus_bool_t enable;
> + const char *method;
> +
> + if (parse_argument_on_off(arg, &enable) == FALSE)
> + return;
> +
> + if (check_default_ctrl() == FALSE)
> + return;
> +
> + if (enable == TRUE) {
> + method = "StartDiscovery";
> + } else {
> + method = "StopDiscovery";
> + }
> +
> + if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
> + NULL, start_discovery_reply,
> + GUINT_TO_POINTER(enable), NULL) == FALSE) {
> + rl_printf("Failed to %s discovery\n",
> + enable == TRUE ? "start" : "stop");
> + return;
> + }
> +}
> +
> +static void append_variant(DBusMessageIter *iter, int type, void *val)
> +{
> + DBusMessageIter value;
> + char sig[2] = { type, '\0' };
> +
> + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
> +
> + dbus_message_iter_append_basic(&value, type, val);
> +
> + dbus_message_iter_close_container(iter, &value);
> +}
> +
> +static void append_array_variant(DBusMessageIter *iter, int type, void *val,
> + int n_elements)
> +{
> + DBusMessageIter variant, array;
> + char type_sig[2] = { type, '\0' };
> + char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
> +
> + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
> + array_sig, &variant);
> +
> + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
> + type_sig, &array);
> +
> + if (dbus_type_is_fixed(type) == TRUE) {
> + dbus_message_iter_append_fixed_array(&array, type, val,
> + n_elements);
> + } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
> + const char ***str_array = val;
> + int i;
> +
> + for (i = 0; i < n_elements; i++)
> + dbus_message_iter_append_basic(&array, type,
> + &((*str_array)[i]));
> + }
> +
> + dbus_message_iter_close_container(&variant, &array);
> +
> + dbus_message_iter_close_container(iter, &variant);
> +}
> +
> +static void dict_append_entry(DBusMessageIter *dict, const char *key,
> + int type, void *val)
> +{
> + DBusMessageIter entry;
> +
> + if (type == DBUS_TYPE_STRING) {
> + const char *str = *((const char **) val);
> +
> + if (str == NULL)
> + return;
> + }
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> +
> + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
> +
> + append_variant(&entry, type, val);
> +
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void dict_append_basic_array(DBusMessageIter *dict, int key_type,
> + const void *key, int type, void *val,
> + int n_elements)
> +{
> + DBusMessageIter entry;
> +
> + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
> + NULL, &entry);
> +
> + dbus_message_iter_append_basic(&entry, key_type, key);
> +
> + append_array_variant(&entry, type, val, n_elements);
> +
> + dbus_message_iter_close_container(dict, &entry);
> +}
> +
> +static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
> + void *val, int n_elements)
> +{
> + dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
> + n_elements);
> +}
> +
> +#define DISTANCE_VAL_INVALID 0x7FFF
> +
> +struct set_discovery_filter_args {
> + char *transport;
> + dbus_uint16_t rssi;
> + dbus_int16_t pathloss;
> + char **uuids;
> + size_t uuids_len;
> + dbus_bool_t reset;
> +};
> +
> +static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
> +{
> + struct set_discovery_filter_args *args = user_data;
> + DBusMessageIter dict;
> +
> + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
> + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
> + DBUS_TYPE_STRING_AS_STRING
> + DBUS_TYPE_VARIANT_AS_STRING
> + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
> +
> + dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &args->uuids,
> + args->uuids_len);
> +
> + if (args->pathloss != DISTANCE_VAL_INVALID)
> + dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
> + &args->pathloss);
> +
> + if (args->rssi != DISTANCE_VAL_INVALID)
> + dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi);
> +
> + if (args->transport != NULL)
> + dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
> + &args->transport);
> + if (args->reset)
> + dict_append_entry(&dict, "ResetData", DBUS_TYPE_BOOLEAN,
> + &args->reset);
> +
> + dbus_message_iter_close_container(iter, &dict);
> +}
> +
> +
> +static void set_discovery_filter_reply(DBusMessage *message, void *user_data)
> +{
> + DBusError error;
> +
> + dbus_error_init(&error);
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("SetDiscoveryFilter failed: %s\n", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + rl_printf("SetDiscoveryFilter success\n");
> +}
> +
> +static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
> +static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
> +static char **filtered_scan_uuids;
> +static size_t filtered_scan_uuids_len;
> +static char *filtered_scan_transport = "le";
> +
> +static void set_scan_filter_commit(void)
> +{
> + struct set_discovery_filter_args args;
> +
> + args.pathloss = filtered_scan_pathloss;
> + args.rssi = filtered_scan_rssi;
> + args.transport = filtered_scan_transport;
> + args.uuids = filtered_scan_uuids;
> + args.uuids_len = filtered_scan_uuids_len;
> + args.reset = TRUE;
> +
> + if (check_default_ctrl() == FALSE)
> + return;
> +
> + if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
> + set_discovery_filter_setup, set_discovery_filter_reply,
> + &args, NULL) == FALSE) {
> + rl_printf("Failed to set discovery filter\n");
> + return;
> + }
> +}
> +
> +static void set_scan_filter_uuids(const char *arg)
> +{
> + g_strfreev(filtered_scan_uuids);
> + filtered_scan_uuids = NULL;
> + filtered_scan_uuids_len = 0;
> +
> + if (!arg || !strlen(arg))
> + goto commit;
> +
> + rl_printf("set_scan_filter_uuids %s\n", arg);
> + filtered_scan_uuids = g_strsplit(arg, " ", -1);
> + if (!filtered_scan_uuids) {
> + rl_printf("Failed to parse input\n");
> + return;
> + }
> +
> + filtered_scan_uuids_len = g_strv_length(filtered_scan_uuids);
> +
> +commit:
> + set_scan_filter_commit();
> +}
> +
> +static void cmd_scan_unprovisioned_devices(const char *arg)
> +{
> + dbus_bool_t enable;
> +
> + if (parse_argument_on_off(arg, &enable) == FALSE)
> + return;
> +
> + if (enable == TRUE) {
> + discover_mesh = false;
> + set_scan_filter_uuids(MESH_PROV_SVC_UUID);
> + }
> + cmd_scan(arg);
> +}
> +
> +static void cmd_info(const char *arg)
> +{
> + GDBusProxy *proxy;
> + DBusMessageIter iter;
> + const char *address;
> +
> + proxy = connection.device;
> + if (!proxy)
> + return;
> +
> + if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
> + return;
> +
> + dbus_message_iter_get_basic(&iter, &address);
> + rl_printf("Device %s\n", address);
> +
> + print_property(proxy, "Name");
> + print_property(proxy, "Alias");
> + print_property(proxy, "Class");
> + print_property(proxy, "Appearance");
> + print_property(proxy, "Icon");
> + print_property(proxy, "Trusted");
> + print_property(proxy, "Blocked");
> + print_property(proxy, "Connected");
> + print_uuids(proxy);
> + print_property(proxy, "Modalias");
> + print_property(proxy, "ManufacturerData");
> + print_property(proxy, "ServiceData");
> + print_property(proxy, "RSSI");
> + print_property(proxy, "TxPower");
> +}
> +
> +static void cmd_connect(const char *arg)
> +{
> + if (check_default_ctrl() == FALSE)
> + return;
> +
> + memset(&connection, 0, sizeof(connection));
> +
> + if (!arg || !strlen(arg)) {
> + connection.net_idx = NET_IDX_PRIMARY;
> + } else {
> + char *end;
> + connection.net_idx = strtol(arg, &end, 16);
> + if (end == arg) {
> + connection.net_idx = NET_IDX_INVALID;
> + rl_printf("Invalid network index %s\n", arg);
> + return;
> + }
> + }
> +
> + if (discovering)
> + g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
> + NULL, NULL, NULL, NULL);
> +
> + set_scan_filter_uuids(MESH_PROXY_SVC_UUID);
> + discover_mesh = true;
> +
> + connection.type = CONN_TYPE_NETWORK;
> +
> +
> + rl_printf("Looking for mesh network with net index %4.4x\n",
> + connection.net_idx);
> +
> + if (g_dbus_proxy_method_call(default_ctrl->proxy,
> + "StartDiscovery", NULL, start_discovery_reply,
> + GUINT_TO_POINTER(TRUE), NULL) == FALSE)
> + rl_printf("Failed to start mesh proxy discovery\n");
> +
> + g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery",
> + NULL, NULL, NULL, NULL);
> +
> +}
> +
> +static void prov_disconn_reply(DBusMessage *message, void *user_data)
> +{
> + struct mesh_node *node = user_data;
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to disconnect: %s\n", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + set_connected_device(NULL);
> +
> + set_scan_filter_uuids(MESH_PROXY_SVC_UUID);
> + discover_mesh = true;
> +
> + connection.type = CONN_TYPE_IDENTITY;
> + connection.data_in = NULL;
> + connection.data_out = NULL;
> + connection.unicast = node_get_primary(node);
> +
> + if (g_dbus_proxy_method_call(default_ctrl->proxy,
> + "StartDiscovery", NULL, start_discovery_reply,
> + GUINT_TO_POINTER(TRUE), NULL) == FALSE)
> + rl_printf("Failed to start mesh proxy discovery\n");
> +
> +}
> +
> +static void disconn_reply(DBusMessage *message, void *user_data)
> +{
> + GDBusProxy *proxy = user_data;
> + DBusError error;
> +
> + dbus_error_init(&error);
> +
> + if (dbus_set_error_from_message(&error, message) == TRUE) {
> + rl_printf("Failed to disconnect: %s\n", error.name);
> + dbus_error_free(&error);
> + return;
> + }
> +
> + rl_printf("Successfully disconnected\n");
> +
> + if (proxy != connection.device)
> + return;
> +
> + set_connected_device(NULL);
> +}
> +
> +static void cmd_disconn(const char *arg)
> +{
> + if (connection.type == CONN_TYPE_PROVISION) {
> + struct mesh_node *node = node_find_by_uuid(connection.dev_uuid);
> + if (node)
> + node_free(node);
> + }
> +
> + disconnect_device(disconn_reply, connection.device);
> +}
> +
> +static void mesh_prov_done(void *user_data, int status)
> +{
> + struct mesh_node *node = user_data;
> +
> + if (status){
> + rl_printf("Provisioning failed\n");
> + node_free(node);
> + disconnect_device(NULL, NULL);
> + return;
> + }
> +
> + rl_printf("Provision success. Assigned Primary Unicast %4.4x\n",
> + node_get_primary(node));
> +
> + if (!prov_db_add_new_node(node))
> + rl_printf("Failed to add node to provisioning DB\n");
> +
> + disconnect_device(prov_disconn_reply, node);
> +}
> +
> +static void cmd_start_prov(const char *arg)
> +{
> + GDBusProxy *proxy;
> + struct mesh_device *dev;
> + struct mesh_node *node;
> + int len;
> +
> + if (!arg) {
> + rl_printf("Mesh Device UUID is required\n");
> + return;
> + }
> +
> + len = strlen(arg);
> + if ( len > 32 || len % 2) {
> + rl_printf("Incorrect UUID size %d\n", len);
> + }
> +
> + disconnect_device(NULL, NULL);
> +
> + memset(connection.dev_uuid, 0, 16);
> + str2hex(arg, len, connection.dev_uuid, len/2);
> +
> + node = node_find_by_uuid(connection.dev_uuid);
> + if (!node) {
> + rl_printf("Device with UUID %s not found.\n", arg);
> + rl_printf("Stale services? Remove device and re-discover\n");
> + return;
> + }
> +
> + /* TODO: add command to remove a node from mesh, i.e., "unprovision" */
> + if (node_is_provisioned(node)) {
> + rl_printf("Already provisioned with unicast %4.4x\n",
> + node_get_primary(node));
> + return;
> + }
> +
> + dev = find_device_by_uuid(default_ctrl->mesh_devices,
> + connection.dev_uuid);
> + if (!dev || !dev->proxy) {
> + rl_printf("Could not find device proxy\n");
> + memset(connection.dev_uuid, 0, 16);
> + return;
> + }
> +
> + proxy = dev->proxy;
> + if (discovering)
> + g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
> + NULL, NULL, NULL, NULL);
> + forget_mesh_devices();
> +
> + connection.type = CONN_TYPE_PROVISION;
> +
> + if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
> + proxy, NULL) == FALSE) {
> + rl_printf("Failed to connect ");
> + print_device(proxy, NULL);
> + return;
> + } else {
> + rl_printf("Trying to connect ");
> + print_device(proxy, NULL);
> + }
> +
> +}
> +
> +static void cmd_config(const char *arg)
> +{
> + rl_printf("Switching to Mesh Client configuration menu\n");
> +
> + if (!switch_cmd_menu("configure"))
> + return;
> +
> + set_menu_prompt("config", NULL);
> +
> + if (arg && strlen(arg))
> + config_set_node(arg);
> +}
> +
> +static void cmd_onoff_cli(const char *arg)
> +{
> + rl_printf("Switching to Mesh Generic ON OFF Client menu\n");
> +
> + if (!switch_cmd_menu("onoff"))
> + return;
> +
> + set_menu_prompt("on/off", NULL);
> +
> + if (arg && strlen(arg))
> + onoff_set_node(arg);
> +}
> +
> +static void cmd_print_mesh(const char *arg)
> +{
> + if (!prov_db_show(mesh_prov_db_filename))
> + rl_printf("Unavailable\n");
> +
> +}
> +
> + static void cmd_print_local(const char *arg)
> +{
> + if (!prov_db_show(mesh_local_config_filename))
> + rl_printf("Unavailable\n");
> +}
> +
> +static void disc_quit_cb(DBusMessage *message, void *user_data)
> +{
> + g_main_loop_quit(main_loop);
> +}
> +
> +static void cmd_quit(const char *arg)
> +{
> + if (connection.device) {
> + disconnect_device(disc_quit_cb, NULL);
> + return;
> + }
> +
> + g_main_loop_quit(main_loop);
> +}
> +
> +static const struct menu_entry meshctl_cmd_table[] = {
> + { "list", NULL, cmd_list, "List available controllers"},
> + { "show", "[ctrl]", cmd_show, "Controller information"},
> + { "select", "<ctrl>", cmd_select, "Select default controller"},
> + { "info", "[dev]", cmd_info, "Device information"},
> + { "connect", "[net_idx]",cmd_connect, "Connect to mesh network"},
> + { "discover-unprovisioned", "<on/off>", cmd_scan_unprovisioned_devices,
> + "Look for devices to provision" },
> + { "provision", "<uuid>", cmd_start_prov, "Initiate provisioning"},
> + { "power", "<on/off>", cmd_power, "Set controller power" },
> + { "disconnect", "[dev]", cmd_disconn, "Disconnect device"},
> + { "mesh-info", NULL, cmd_print_mesh,
> + "Mesh networkinfo (provisioner)" },
> + { "local-info", NULL, cmd_print_local, "Local mesh node info" },
> + { "configure", "[dst]", cmd_config, "Config client model menu"},
> + { "onoff", "[dst]", cmd_onoff_cli,
> + "Generic On/Off model menu"},
> + { "quit", NULL, cmd_quit, "Quit program" },
> + { "exit", NULL, cmd_quit },
> + { "help" },
> + { }
> +};
> +
> +static void rl_handler(char *input)
> +{
> + char *cmd, *arg;
> +
> + if (!input) {
> + rl_insert_text("quit");
> + rl_redisplay();
> + rl_crlf();
> + g_main_loop_quit(main_loop);
> + return;
> + }
> +
> + if (!strlen(input))
> + goto done;
> + else if (!strcmp(input, "q") || !strcmp(input, "quit")
> + || !strcmp(input, "exit")) {
> + cmd_quit(NULL);
> + goto done;
> + }
> +
> + if (agent_input(input) == TRUE)
> + goto done;
> +
> + add_history(input);
> +
> + cmd = strtok_r(input, " \t\r\n", &arg);
> + if (!cmd)
> + goto done;
> +
> + process_menu_cmd(cmd, arg);
> +
> +done:
> + free(input);
> +}
> +
> +static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
> + gpointer user_data)
> +{
> + static bool terminated = false;
> + struct signalfd_siginfo si;
> + ssize_t result;
> + int fd;
> +
> + if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
> + g_main_loop_quit(main_loop);
> + return FALSE;
> + }
> +
> + fd = g_io_channel_unix_get_fd(channel);
> +
> + result = read(fd, &si, sizeof(si));
> + if (result != sizeof(si))
> + return FALSE;
> +
> + switch (si.ssi_signo) {
> + case SIGINT:
> + if (input) {
> + rl_replace_line("", 0);
> + rl_crlf();
> + rl_on_new_line();
> + rl_redisplay();
> + break;
> + }
> +
> + /*
> + * If input was not yet setup up that means signal was received
> + * while daemon was not yet running. Since user is not able
> + * to terminate client by CTRL-D or typing exit treat this as
> + * exit and fall through.
> + */
> +
> + /* fall through */
> + case SIGTERM:
> + if (!terminated) {
> + rl_replace_line("", 0);
> + rl_crlf();
> + g_main_loop_quit(main_loop);
> + }
> +
> + terminated = true;
> + break;
> + }
> +
> + return TRUE;
> +}
> +
> +static guint setup_signalfd(void)
> +{
> + GIOChannel *channel;
> + guint source;
> + sigset_t mask;
> + int fd;
> +
> + sigemptyset(&mask);
> + sigaddset(&mask, SIGINT);
> + sigaddset(&mask, SIGTERM);
> +
> + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
> + perror("Failed to set signal mask");
> + return 0;
> + }
> +
> + fd = signalfd(-1, &mask, 0);
> + if (fd < 0) {
> + perror("Failed to create signal descriptor");
> + return 0;
> + }
> +
> + channel = g_io_channel_unix_new(fd);
> +
> + g_io_channel_set_close_on_unref(channel, TRUE);
> + g_io_channel_set_encoding(channel, NULL, NULL);
> + g_io_channel_set_buffered(channel, FALSE);
> +
> + source = g_io_add_watch(channel,
> + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
> + signal_handler, NULL);
> +
> + g_io_channel_unref(channel);
> +
> + return source;
> +}
> +
> +static gboolean option_version = FALSE;
> +static const char *mesh_config_dir;
> +
> +static GOptionEntry options[] = {
> + { "config", 'c', 0, G_OPTION_ARG_STRING, &mesh_config_dir,
> + "Read local mesh config JSON files from <directory>" },
> + { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
> + "Show version information and exit" },
> + { NULL },
> +};
> +
> +static void client_ready(GDBusClient *client, void *user_data)
> +{
> + if (!input)
> + input = setup_standard_input();
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + GOptionContext *context;
> + GError *error = NULL;
> + GDBusClient *client;
> + guint signal;
> + int len;
> + int extra;
> +
> + context = g_option_context_new(NULL);
> + g_option_context_add_main_entries(context, options, NULL);
> +
> + if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
> + if (error != NULL) {
> + g_printerr("%s\n", error->message);
> + g_error_free(error);
> + } else
> + g_printerr("An unknown error occurred\n");
> + exit(1);
> + }
> +
> + g_option_context_free(context);
> +
> + if (option_version == TRUE) {
> + rl_printf("%s\n", VERSION);
> + exit(0);
> + }
> +
> + if (!mesh_config_dir) {
> + rl_printf("Local config directory not provided.\n");
> + mesh_config_dir = "";
> + } else {
> + rl_printf("Reading prov_db.json and local_node.json from %s\n",
> + mesh_config_dir);
> + }
> +
> + len = strlen(mesh_config_dir);
> + if (len && mesh_config_dir[len - 1] != '/') {
> + extra = 1;
> + rl_printf("mesh_config_dir[%d] %s\n", len,
> + &mesh_config_dir[len - 1]);
> + } else {
> + extra = 0;
> + }
> + mesh_local_config_filename = g_malloc(len + strlen("local_node.json")
> + + 2);
> + if (!mesh_local_config_filename)
> + exit(1);
> +
> + mesh_prov_db_filename = g_malloc(len + strlen("prov_db.json") + 2);
> + if (!mesh_prov_db_filename) {
> + exit(1);
> + }
> +
> + sprintf(mesh_local_config_filename, "%s", mesh_config_dir);
> +
> + if (extra)
> + sprintf(mesh_local_config_filename + len , "%c", '/');
> +
> + sprintf(mesh_local_config_filename + len + extra, "%s",
> + "local_node.json");
> + len = len + extra + strlen("local_node.json");
> + sprintf(mesh_local_config_filename + len, "%c", '\0');
> +
> + if (!prov_db_read_local_node(mesh_local_config_filename, true)) {
> + g_printerr("Failed to parse local node configuration file %s\n",
> + mesh_local_config_filename);
> + exit(1);
> + }
> +
> + sprintf(mesh_prov_db_filename, "%s", mesh_config_dir);
> + len = strlen(mesh_config_dir);
> + if (extra)
> + sprintf(mesh_prov_db_filename + len , "%c", '/');
> +
> + sprintf(mesh_prov_db_filename + len + extra, "%s", "prov_db.json");
> + sprintf(mesh_prov_db_filename + len + extra + strlen("prov_db.json"),
> + "%c", '\0');
> +
> + if (!prov_db_read(mesh_prov_db_filename)) {
> + g_printerr("Failed to parse provisioning database file %s\n",
> + mesh_prov_db_filename);
> + exit(1);
> + }
> +
> + main_loop = g_main_loop_new(NULL, FALSE);
> + dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
> +
> + setlinebuf(stdout);
> +
> + rl_erase_empty_line = 1;
> + rl_callback_handler_install(NULL, rl_handler);
> +
> + rl_set_prompt(PROMPT_OFF);
> + rl_redisplay();
> +
> + signal = setup_signalfd();
> + client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
> +
> + g_dbus_client_set_connect_watch(client, connect_handler, NULL);
> + g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
> + g_dbus_client_set_signal_watch(client, message_handler, NULL);
> +
> + g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
> + property_changed, NULL);
> +
> + g_dbus_client_set_ready_watch(client, client_ready, NULL);
> +
> + cmd_menu_init(meshctl_cmd_table);
> +
> + if (!config_client_init())
> + g_printerr("Failed to initialize mesh configuration client\n");
> +
> + if (!config_server_init())
> + g_printerr("Failed to initialize mesh configuration server\n");
> +
> + if (!onoff_client_init(PRIMARY_ELEMENT_IDX))
> + g_printerr("Failed to initialize mesh generic On/Off client\n");
> +
> + g_main_loop_run(main_loop);
> +
> + g_dbus_client_unref(client);
> + g_source_remove(signal);
> + if (input > 0)
> + g_source_remove(input);
> +
> + rl_message("");
> + rl_callback_handler_remove();
> +
> + dbus_connection_unref(dbus_conn);
> + g_main_loop_unref(main_loop);
> +
> + node_cleanup();
> +
> + g_list_free(char_list);
> + g_list_free(service_list);
> + g_list_free_full(ctrl_list, proxy_leak);
> +
> + agent_release();
> +
> + return 0;
> +}
> diff --git a/mesh/net.c b/mesh/net.c
> new file mode 100644
> index 0000000..fb2d200
> --- /dev/null
> +++ b/mesh/net.c
> @@ -0,0 +1,2184 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <inttypes.h>
> +#include <ctype.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <glib.h>
> +
> +#include "src/shared/util.h"
> +#include "client/display.h"
> +
> +#include "crypto.h"
> +#include "gatt.h"
> +#include "mesh-net.h"
> +#include "util.h"
> +#include "keys.h"
> +#include "node.h"
> +#include "prov-db.h"
> +#include "net.h"
> +
> +struct address_range
> +{
> + uint16_t min;
> + uint16_t max;
> +};
> +
> +struct mesh_net {
> + uint32_t iv_index;
> + uint32_t seq_num;
> + uint32_t seq_num_reserved;
> + uint16_t primary_addr;
> + uint8_t iv_upd_state;
> + uint8_t num_elements;
> + uint8_t default_ttl;
> + bool iv_update;
> + bool provisioner;
> + bool blacklist;
> + guint iv_update_timeout;
> + GDBusProxy *proxy_in;
> + GList *address_pool;
> + GList *dest; /* List of valid local destinations for Whitelist */
> + GList *sar_in; /* Incoming segmented messages in progress */
> + GList *msg_out; /* Pre-Network encoded, might be multi-segment */
> + GList *pkt_out; /* Fully encoded packets awaiting Tx in order */
> + net_mesh_session_open_callback open_cb;
> +};
> +
> +struct generic_key {
> + uint16_t idx;
> +};
> +
> +struct net_key_parts {
> + uint8_t nid;
> + uint8_t enc_key[16];
> + uint8_t privacy_key[16];
> + uint8_t net_key[16];
> + uint8_t beacon_key[16];
> + uint8_t net_id[8];
> +};
> +
> +struct mesh_net_key {
> + struct generic_key generic;
> + uint8_t phase;
> + struct net_key_parts current;
> + struct net_key_parts new;
> +};
> +
> +struct app_key_parts {
> + uint8_t key[16];
> + uint8_t akf_aid;
> +};
> +
> +struct mesh_app_key {
> + struct generic_key generic;
> + uint16_t net_idx;
> + struct app_key_parts current;
> + struct app_key_parts new;
> +};
> +
> +struct mesh_virt_addr {
> + uint16_t va16;
> + uint32_t va32;
> + uint8_t va128[16];
> +};
> +
> +struct mesh_pkt {
> + uint8_t data[30];
> + uint8_t len;
> +};
> +
> +struct mesh_sar_msg {
> + guint ack_to;
> + guint msg_to;
> + uint32_t iv_index;
> + uint32_t seqAuth;
> + uint32_t ack;
> + uint32_t dst;
> + uint16_t src;
> + uint16_t net_idx;
> + uint16_t len;
> + uint8_t akf_aid;
> + uint8_t ttl;
> + uint8_t segN;
> + uint8_t activity_cnt;
> + bool ctl;
> + bool segmented;
> + bool szmic;
> + bool proxy;
> + uint8_t data[20]; /* Open ended, min 20 */
> +};
> +
> +struct mesh_destination {
> + uint16_t cnt;
> + uint16_t dst;
> +};
> +
> +/* Network Packet Layer based Offsets */
> +#define AKF_BIT 0x40
> +
> +#define PKT_IVI(p) !!((p)[0] & 0x80)
> +#define SET_PKT_IVI(p,v) do {(p)[0] &= 0x7f; \
> + (p)[0] |= ((v) ? 0x80 : 0);} while(0)
> +#define PKT_NID(p) ((p)[0] & 0x7f)
> +#define SET_PKT_NID(p,v) do {(p)[0] &= 0x80; (p)[0] |= (v);} while(0)
> +#define PKT_CTL(p) (!!((p)[1] & 0x80))
> +#define SET_PKT_CTL(p,v) do {(p)[1] &= 0x7f; \
> + (p)[1] |= ((v) ? 0x80 : 0);} while(0)
> +#define PKT_TTL(p) ((p)[1] & 0x7f)
> +#define SET_PKT_TTL(p,v) do {(p)[1] &= 0x80; (p)[1] |= (v);} while(0)
> +#define PKT_SEQ(p) (get_be32((p) + 1) & 0xffffff)
> +#define SET_PKT_SEQ(p,v) put_be32(((p)[1] << 24) + ((v) & 0xffffff), \
> + (p) + 1)
> +#define PKT_SRC(p) get_be16((p) + 5)
> +#define SET_PKT_SRC(p,v) put_be16(v, (p) + 5)
> +#define PKT_DST(p) get_be16((p) + 7)
> +#define SET_PKT_DST(p,v) put_be16(v, (p) + 7)
> +#define PKT_TRANS(p) ((p) + 9)
> +#define PKT_TRANS_LEN(l) ((l) - 9)
> +
> +#define PKT_SEGMENTED(p) (!!((p)[9] & 0x80))
> +#define SET_PKT_SEGMENTED(p,v) do {(p)[9] &= 0x7f; \
> + (p)[9] |= ((v) ? 0x80 : 0);} while(0)
> +#define PKT_AKF_AID(p) ((p)[9] & 0x7f)
> +#define SET_PKT_AKF_AID(p,v) do {(p)[9] &= 0x80; (p)[9] |= (v);} while(0)
> +#define PKT_OPCODE(p) ((p)[9] & 0x7f)
> +#define SET_PKT_OPCODE(p,v) do {(p)[9] &= 0x80; (p)[9] |= (v);} while(0)
> +#define PKT_OBO(p) (!!((p)[10] & 0x80))
> +#define PKT_SZMIC(p) (!!(PKT_SEGMENTED(p) ? ((p)[10] & 0x40) : 0))
> +#define SET_PKT_SZMIC(p,v) do {(p)[10] &= 0x7f; \
> + (p)[10] |= ((v) ? 0x80 : 0);} while(0)
> +#define PKT_SEQ0(p) ((get_be16((p) + 10) >> 2) & 0x1fff)
> +#define SET_PKT_SEQ0(p,v) do {put_be16((get_be16((p) + 10) & 0x8003) \
> + | (((v) & 0x1fff) << 2), \
> + (p) + 10);} while(0)
> +#define SET_PKT_SEGO(p,v) do {put_be16((get_be16( \
> + (p) + 11) & 0xfc1f) | ((v) << 5), \
> + (p) + 11);} while(0)
> +#define SET_PKT_SEGN(p,v) do {(p)[12] = ((p)[12] & 0xe0) | (v);} while(0)
> +#define PKT_ACK(p) (get_be32((p) + 12))
> +#define SET_PKT_ACK(p,v) (put_be32((v)(p) + 12))
> +
> +/* Transport Layer based offsets */
> +#define TRANS_SEGMENTED(t) (!!((t)[0] & 0x80))
> +#define SET_TRANS_SEGMENTD(t,v) do {(t)[0] &= 0x7f; \
> + (t)[0] |= ((v) ? 0x80 : 0);} while(0)
> +#define TRANS_OPCODE(t) ((t)[0] & 0x7f)
> +#define SET_TRANS_OPCODE(t,v) do {(t)[0] &= 0x80; (t)[0] |= (v);} while(0)
> +#define TRANS_AKF_AID(t) ((t)[0] & 0x7f)
> +#define SET_TRANS_AKF_AID(t,v) do {(t)[0] &= 0xc0; (t)[0] |= (v);} while(0)
> +#define TRANS_AKF(t) (!!((t)[0] & AKF_BIT))
> +#define TRANS_SZMIC(t) (!!(TRANS_SEGMENTED(t) ? ((t)[1] & 0x80) : 0))
> +#define TRANS_SEQ0(t) ((get_be16((t) + 1) >> 2) & 0x1fff)
> +#define SET_TRANS_SEQ0(t,v) do {put_be16((get_be16((t) + 1) & 0x8003) \
> + | (((v) & 0x1fff) << 2), \
> + (t) + 1);} while(0)
> +#define SET_TRANS_ACK(t,v) put_be32((v), (t) + 3)
> +#define TRANS_SEGO(t) ((get_be16((t) + 2) >> 5) & 0x1f)
> +#define TRANS_SEGN(t) ((t)[3] & 0x1f)
> +
> +#define TRANS_PAYLOAD(t) ((t) + (TRANS_SEGMENTED(t) ? 4 : 1))
> +#define TRANS_LEN(t,l) ((l) -(TRANS_SEGMENTED(t) ? 4 : 1))
> +
> +/* Proxy Config Opcodes */
> +#define FILTER_SETUP 0x00
> +#define FILTER_ADD 0x01
> +#define FILTER_DEL 0x02
> +#define FILTER_STATUS 0x03
> +
> +/* Proxy Filter Types */
> +#define WHITELIST_FILTER 0x00
> +#define BLACKLIST_FILTER 0x01
> +
> +/* IV Updating states for timing enforcement */
> +#define IV_UPD_INIT 0
> +#define IV_UPD_NORMAL 1
> +#define IV_UPD_UPDATING 2
> +#define IV_UPD_NORMAL_HOLD 3
> +
> +#define IV_IDX_DIFF_RANGE 42
> +
> +static struct mesh_net net;
> +static GList *virt_addrs = NULL;
> +static GList *net_keys = NULL;
> +static GList *app_keys = NULL;
> +
> +/* Forward static declarations */
> +static void resend_segs(struct mesh_sar_msg *sar);
> +
> +static int match_net_id(const void *a, const void *net_id)
> +{
> + const struct mesh_net_key *net_key = a;
> +
> + if (net_key->current.nid != 0xff &&
> + !memcmp(net_key->current.net_id, net_id, 8))
> + return 0;
> +
> + if (net_key->new.nid != 0xff &&
> + !memcmp(net_key->new.net_id, net_id, 8))
> + return 0;
> +
> + return -1;
> +}
> +
> +static struct mesh_net_key *find_net_key_by_id(const uint8_t *net_id)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(net_keys, net_id, match_net_id);
> +
> + if (!l)
> + return NULL;
> +
> + return l->data;
> +}
> +
> +uint16_t net_validate_proxy_beacon(const uint8_t *proxy_beacon)
> +{
> + struct mesh_net_key *net_key = find_net_key_by_id(proxy_beacon);
> +
> + if (net_key == NULL)
> + return NET_IDX_INVALID;
> +
> + return net_key->generic.idx;
> +}
> +
> +static int match_sar_dst(const void *a, const void *b)
> +{
> + const struct mesh_sar_msg *sar = a;
> + uint16_t dst = GPOINTER_TO_UINT(b);
> +
> + return (sar->dst == dst) ? 0 : -1;
> +}
> +
> +static struct mesh_sar_msg *find_sar_out_by_dst(uint16_t dst)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(net.msg_out, GUINT_TO_POINTER(dst),
> + match_sar_dst);
> +
> + if (!l)
> + return NULL;
> +
> + return l->data;
> +}
> +
> +static int match_sar_src(const void *a, const void *b)
> +{
> + const struct mesh_sar_msg *sar = a;
> + uint16_t src = GPOINTER_TO_UINT(b);
> +
> + return (sar->src == src) ? 0 : -1;
> +}
> +
> +static struct mesh_sar_msg *find_sar_in_by_src(uint16_t src)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(net.sar_in, GUINT_TO_POINTER(src),
> + match_sar_src);
> +
> + if (!l)
> + return NULL;
> +
> + return l->data;
> +}
> +
> +static int match_key_index(const void *a, const void *b)
> +{
> + const struct generic_key *generic = a;
> + uint16_t index = GPOINTER_TO_UINT(b);
> +
> + return (generic->idx == index) ? 0 : -1;
> +}
> +
> +static bool delete_key(GList **list, uint16_t index)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(*list, GUINT_TO_POINTER(index),
> + match_key_index);
> +
> + if (!l)
> + return false;
> +
> + *list = g_list_delete_link(*list, l);
> +
> + return true;
> +
> +}
> +
> +static uint8_t *get_key(GList *list, uint16_t index)
> +{
> + GList *l;
> + struct mesh_app_key *app_key;
> + struct mesh_net_key *net_key;
> +
> + l = g_list_find_custom(list, GUINT_TO_POINTER(index),
> + match_key_index);
> +
> + if (!l) return NULL;
> +
> + if (list == app_keys) {
> + app_key = l->data;
> +
> + /* All App Keys must belong to a valid Net Key */
> + l = g_list_find_custom(net_keys,
> + GUINT_TO_POINTER(app_key->net_idx),
> + match_key_index);
> +
> + if (!l) return NULL;
> +
> + net_key = l->data;
> +
> + if (net_key->phase == 2 && app_key->new.akf_aid != 0xff)
> + return app_key->new.key;
> +
> + if (app_key->current.akf_aid != 0xff)
> + return app_key->current.key;
> +
> + return NULL;
> + }
> +
> + net_key = l->data;
> +
> + if (net_key->phase == 2 && net_key->new.nid != 0xff)
> + return net_key->new.net_key;
> +
> + if (net_key->current.nid != 0xff)
> + return net_key->current.net_key;
> +
> + return NULL;
> +}
> +
> +bool keys_app_key_add(uint16_t net_idx, uint16_t app_idx, uint8_t *key,
> + bool update)
> +{
> + struct mesh_app_key *app_key = NULL;
> + uint8_t akf_aid;
> + GList *l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
> + match_key_index);
> +
> + if (!mesh_crypto_k4(key, &akf_aid))
> + return false;
> +
> + akf_aid |= AKF_BIT;
> +
> + if (l && update) {
> +
> + app_key = l->data;
> +
> + if (app_key->net_idx != net_idx)
> + return false;
> +
> + memcpy(app_key->new.key, key, 16);
> + app_key->new.akf_aid = akf_aid;
> +
> + } else if (l) {
> +
> + app_key = l->data;
> +
> + if (memcmp(app_key->current.key, key, 16) ||
> + app_key->net_idx != net_idx)
> + return false;
> +
> + } else {
> +
> + app_key = g_new(struct mesh_app_key, 1);
> + memcpy(app_key->current.key, key, 16);
> + app_key->net_idx = net_idx;
> + app_key->generic.idx = app_idx;
> + app_key->current.akf_aid = akf_aid;
> +
> + /* Invalidate "New" version */
> + app_key->new.akf_aid = 0xff;
> +
> + app_keys = g_list_append(app_keys, app_key);
> +
> + }
> +
> + return true;
> +}
> +
> +bool keys_net_key_add(uint16_t net_idx, uint8_t *key, bool update)
> +{
> + struct mesh_net_key *net_key = NULL;
> + uint8_t p = 0;
> + GList *l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
> + match_key_index);
> +
> + if (l && update) {
> + bool result;
> +
> + net_key = l->data;
> +
> + memcpy(net_key->new.net_key, key, 16);
> +
> + /* Calculate the many component parts */
> + result = mesh_crypto_nkbk(key, net_key->new.beacon_key);
> + if (!result)
> + return false;
> +
> + result = mesh_crypto_k3(key, net_key->new.net_id);
> + if (!result)
> + return false;
> +
> + result = mesh_crypto_k2(key, &p, 1,
> + &net_key->new.nid,
> + net_key->new.enc_key,
> + net_key->new.privacy_key);
> + if (!result)
> + net_key->new.nid = 0xff;
> +
> + return result;
> +
> + } else if (l) {
> + net_key = l->data;
> +
> + if (memcmp(net_key->current.net_key, key, 16))
> + return false;
> + } else {
> + bool result;
> +
> + net_key = g_new(struct mesh_net_key, 1);
> + memcpy(net_key->current.net_key, key, 16);
> + net_key->generic.idx = net_idx;
> +
> + /* Invalidate "New" version */
> + net_key->new.nid = 0xff;
> +
> + /* Calculate the many component parts */
> + result = mesh_crypto_nkbk(key, net_key->current.beacon_key);
> + if (!result) {
> + g_free(net_key);
> + return false;
> + }
> +
> + result = mesh_crypto_k3(key, net_key->current.net_id);
> + if (!result) {
> + g_free(net_key);
> + return false;
> + }
> +
> + result = mesh_crypto_k2(key, &p, 1,
> + &net_key->current.nid,
> + net_key->current.enc_key,
> + net_key->current.privacy_key);
> +
> + if (!result) {
> + g_free(net_key);
> + return false;
> + }
> +
> + net_keys = g_list_append(net_keys, net_key);
> + }
> +
> + return true;
> +}
> +
> +static struct mesh_app_key *find_app_key_by_idx(uint16_t app_idx)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
> + match_key_index);
> +
> + if (!l) return NULL;
> +
> + return l->data;
> +}
> +
> +static struct mesh_net_key *find_net_key_by_idx(uint16_t net_idx)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
> + match_key_index);
> +
> + if (!l) return NULL;
> +
> + return l->data;
> +}
> +
> +static int match_virt_dst(const void *a, const void *b)
> +{
> + const struct mesh_virt_addr *virt = a;
> + uint32_t dst = GPOINTER_TO_UINT(b);
> +
> + if (dst < 0x10000 && dst == virt->va16)
> + return 0;
> +
> + if (dst == virt->va32)
> + return 0;
> +
> + return -1;
> +}
> +
> +static struct mesh_virt_addr *find_virt_by_dst(uint32_t dst)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(virt_addrs, GUINT_TO_POINTER(dst),
> + match_virt_dst);
> +
> + if (!l) return NULL;
> +
> + return l->data;
> +}
> +
> +uint8_t *keys_net_key_get(uint16_t net_idx, bool current)
> +{
> + GList *l;
> +
> +
> + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
> + match_key_index);
> + if (!l) {
> + return NULL;
> + } else {
> + struct mesh_net_key *key = l->data;
> + if (current)
> + return key->current.net_key;
> + else
> + return key->new.net_key;
> + }
> +}
> +
> +bool keys_app_key_delete(uint16_t app_idx)
> +{
> + /* TODO: remove all associated bindings */
> + return delete_key(&app_keys, app_idx);
> +}
> +
> +bool keys_net_key_delete(uint16_t net_idx)
> +{
> + /* TODO: remove all associated app keys and bindings */
> + return delete_key(&net_keys, net_idx);
> +}
> +
> +uint8_t keys_get_kr_phase(uint16_t net_idx)
> +{
> + GList *l;
> + struct mesh_net_key *key;
> +
> + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
> + match_key_index);
> +
> + if (!l)
> + return KR_PHASE_INVALID;
> +
> + key = l->data;
> +
> + return key->phase;
> +}
> +
> +bool keys_set_kr_phase(uint16_t index, uint8_t phase)
> +{
> + GList *l;
> + struct mesh_net_key *net_key;
> +
> + l = g_list_find_custom(net_keys, GUINT_TO_POINTER(index),
> + match_key_index);
> +
> + if (!l)
> + return false;
> +
> + net_key = l->data;
> + net_key->phase = phase;
> +
> + return true;
> +}
> +
> +uint16_t keys_app_key_get_bound(uint16_t app_idx)
> +{
> + GList *l;
> +
> + l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
> + match_key_index);
> + if (!l)
> + return NET_IDX_INVALID;
> + else {
> + struct mesh_app_key *key = l->data;
> + return key->net_idx;
> + }
> +}
> +
> +uint8_t *keys_app_key_get(uint16_t app_idx, bool current)
> +{
> + GList *l;
> +
> +
> + l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
> + match_key_index);
> + if (!l) {
> + return NULL;
> + } else {
> + struct mesh_app_key *key = l->data;
> + if (current)
> + return key->current.key;
> + else
> + return key->new.key;
> + }
> +}
> +
> +void keys_cleanup_all(void)
> +{
> + g_list_free_full(app_keys, g_free);
> + g_list_free_full(net_keys, g_free);
> + app_keys = net_keys = NULL;
> +}
> +
> +bool net_get_key(uint16_t net_idx, uint8_t *key)
> +{
> + uint8_t *buf;
> +
> + buf = get_key(net_keys, net_idx);
> +
> + if (!buf)
> + return false;
> +
> + memcpy(key, buf, 16);
> + return true;
> +}
> +
> +bool net_get_flags(uint16_t net_idx, uint8_t *out_flags)
> +{
> + uint8_t phase;
> +
> + phase = keys_get_kr_phase(net_idx);
> +
> + if (phase == KR_PHASE_INVALID || !out_flags)
> + return false;
> +
> + if (phase != KR_PHASE_NONE)
> + *out_flags = 0x01;
> + else
> + *out_flags = 0x00;
> +
> + if (net.iv_update)
> + *out_flags |= 0x02;
> +
> + return true;
> +}
> +
> +uint32_t net_get_iv_index(bool *update)
> +{
> + if (update)
> + *update = net.iv_update;
> +
> + return net.iv_index;
> +}
> +
> +void net_set_iv_index(uint32_t iv_index, bool update)
> +{
> + net.iv_index = iv_index;
> + net.iv_update = update;
> +}
> +
> +void set_sequence_number(uint32_t seq_num)
> +{
> + net.seq_num = seq_num;
> +}
> +
> +uint32_t get_sequence_number(void)
> +{
> + return net.seq_num;
> +}
> +
> +bool net_add_address_pool(uint16_t min, uint16_t max)
> +{
> + uint32_t range;
> + if (max < min)
> + return false;
> + range = min + (max << 16);
> + net.address_pool = g_list_append(net.address_pool,
> + GUINT_TO_POINTER(range));
> + return true;
> +}
> +
> +static int match_address_range(const void *a, const void *b)
> +{
> + uint32_t range = GPOINTER_TO_UINT(a);
> + uint8_t num_elements = (uint8_t) (GPOINTER_TO_UINT(b));
> + uint16_t max = range >> 16;
> + uint16_t min = range & 0xffff;
> +
> + return ((max - min) >= (num_elements - 1)) ? 0 : -1;
> +
> +}
> +
> +uint16_t net_obtain_address(uint8_t num_eles)
> +{
> + uint16_t addr;
> + GList *l;
> +
> + l = g_list_find_custom(net.address_pool, GUINT_TO_POINTER(num_eles),
> + match_address_range);
> + if (l) {
> + uint32_t range = GPOINTER_TO_UINT(l->data);
> + uint16_t max = range >> 16;
> + uint16_t min = range & 0xffff;
> +
> + addr = min;
> + min += num_eles;
> +
> + if (min > max)
> + net.address_pool = g_list_delete_link(net.address_pool,
> + l);
> + else {
> + range = min + (max << 16);
> + l->data = GUINT_TO_POINTER(range);
> + }
> + return addr;
> + }
> +
> + return UNASSIGNED_ADDRESS;
> +}
> +
> +static int range_cmp(const void *a, const void *b)
> +{
> + uint32_t range1 = GPOINTER_TO_UINT(a);
> + uint32_t range2 = GPOINTER_TO_UINT(b);
> +
> + return range2 - range1;
> +}
> +
> +void net_release_address(uint16_t addr, uint8_t num_elements)
> +{
> + GList *l;
> + uint32_t range;
> +
> + for (l = net.address_pool; l != NULL; l = l->next)
> + {
> + uint16_t max;
> + uint16_t min;
> +
> + range = GPOINTER_TO_UINT(l->data);
> +
> + max = range >> 16;
> + min = range & 0xffff;
> +
> + if (min == (addr + num_elements + 1))
> + min = addr;
> + else if (addr && max == (addr - 1))
> + max = addr + num_elements + 1;
> + else
> + continue;
> +
> + range = min + (max << 16);
> + l->data = GUINT_TO_POINTER(range);
> + return;
> + }
> +
> + range = addr + ((addr + num_elements - 1) << 16);
> + net.address_pool = g_list_insert_sorted(net.address_pool,
> + GUINT_TO_POINTER(range),
> + range_cmp);
> +}
> +
> +bool net_reserve_address_range(uint16_t base, uint8_t num_elements)
> +{
> + GList *l;
> + uint32_t range;
> + uint16_t max;
> + uint16_t min;
> + bool shrink;
> +
> + for (l = net.address_pool; l != NULL; l = l->next) {
> +
> + range = GPOINTER_TO_UINT(l->data);
> +
> + max = range >> 16;
> + min = range & 0xffff;
> +
> + if (base >= min && (base + num_elements - 1) <= max)
> + break;
> + }
> +
> + if (!l)
> + return false;
> +
> + net.address_pool = g_list_delete_link(net.address_pool, l);
> +
> + shrink = false;
> +
> + if (base == min) {
> + shrink = true;
> + min = base + num_elements;
> + }
> +
> + if (max == base + num_elements - 1) {
> + shrink = true;
> + max -= num_elements;
> + }
> +
> + if (min > max)
> + return true;
> +
> + if (shrink)
> + range = min + (max << 16);
> + else
> + range = min + ((base - 1) << 16);
> +
> + net.address_pool = g_list_insert_sorted(net.address_pool,
> + GUINT_TO_POINTER(range),
> + range_cmp);
> +
> + if (shrink)
> + return true;
> +
> + range = (base + num_elements) + (max << 16);
> + net.address_pool = g_list_insert_sorted(net.address_pool,
> + GUINT_TO_POINTER(range),
> + range_cmp);
> +
> + return true;
> +}
> +
> +static int match_destination(const void *a, const void *b)
> +{
> + const struct mesh_destination *dest = a;
> + uint16_t dst = GPOINTER_TO_UINT(b);
> +
> + return (dest->dst == dst) ? 0 : -1;
> +}
> +
> +void net_dest_ref(uint16_t dst)
> +{
> + struct mesh_destination *dest;
> + GList *l;
> +
> + if (!dst) return;
> +
> + l = g_list_find_custom(net.dest, GUINT_TO_POINTER(dst),
> + match_destination);
> +
> + if (l) {
> + dest = l->data;
> + dest->cnt++;
> + return;
> + }
> +
> + dest = g_new0(struct mesh_destination, 1);
> + dest->dst = dst;
> + dest->cnt++;
> + net.dest = g_list_append(net.dest, dest);
> +}
> +
> +void net_dest_unref(uint16_t dst)
> +{
> + struct mesh_destination *dest;
> + GList *l;
> +
> + l = g_list_find_custom(net.dest, GUINT_TO_POINTER(dst),
> + match_destination);
> +
> + if (!l)
> + return;
> +
> + dest = l->data;
> + dest->cnt--;
> +
> + if (dest->cnt == 0) {
> + net.dest = g_list_remove(net.dest, dest);
> + g_free(dest);
> + }
> +}
> +
> +struct build_whitelist {
> + uint8_t len;
> + uint8_t data[12];
> +};
> +
> +static void whitefilter_add(gpointer data, gpointer user_data)
> +{
> + struct mesh_destination *dest = data;
> + struct build_whitelist *white = user_data;
> +
> + if (white->len == 0)
> + white->data[white->len++] = FILTER_ADD;
> +
> + put_be16(dest->dst, white->data + white->len);
> + white->len += 2;
> +
> + if (white->len > (sizeof(white->data) - sizeof(uint16_t))) {
> + net_ctl_msg_send(0, 0, 0, white->data, white->len);
> + white->len = 0;
> + }
> +}
> +
> +static void setup_whitelist()
> +{
> + struct build_whitelist white;
> +
> + white.len = 0;
> +
> + /* Enable (and Clear) Proxy Whitelist */
> + white.data[white.len++] = FILTER_SETUP;
> + white.data[white.len++] = WHITELIST_FILTER;
> +
> + net_ctl_msg_send(0, 0, 0, white.data, white.len);
> +
> + white.len = 0;
> + g_list_foreach(net.dest, whitefilter_add, &white);
> +
> + if (white.len)
> + net_ctl_msg_send(0, 0, 0, white.data, white.len);
> +}
> +
> +static void beacon_update(bool first, bool iv_update, uint32_t iv_index)
> +{
> +
> + /* Enforcement of 96 hour and 192 hour IVU time windows */
> + if (iv_update && !net.iv_update) {
> + rl_printf("iv_upd_state = IV_UPD_UPDATING\n");
> + net.iv_upd_state = IV_UPD_UPDATING;
> + /* TODO: Start timer to enforce IV Update parameters */
> + } else if (first) {
> + if (iv_update)
> + net.iv_upd_state = IV_UPD_UPDATING;
> + else
> + net.iv_upd_state = IV_UPD_NORMAL;
> +
> + rl_printf("iv_upd_state = IV_UPD_%s\n",
> + iv_update ? "UPDATING" : "NORMAL");
> +
> + } else if (iv_update && iv_index != net.iv_index) {
> + rl_printf("IV Update too soon -- Rejecting\n");
> + return;
> + }
> +
> + if (iv_index > net.iv_index ||
> + iv_update != net.iv_update) {
> +
> + /* Don't reset our seq_num unless
> + * we start using new iv_index */
> + if (!(iv_update && (net.iv_index + 1 == iv_index))) {
> + net.seq_num = 0;
> + net.seq_num_reserved = 100;
> + }
> + }
> +
> + if (!net.seq_num || net.iv_index != iv_index ||
> + net.iv_update != iv_update) {
> +
> + if (net.seq_num_reserved <= net.seq_num)
> + net.seq_num_reserved = net.seq_num + 100;
> +
> + prov_db_local_set_iv_index(iv_index, iv_update,
> + net.provisioner);
> + prov_db_local_set_seq_num(net.seq_num_reserved);
> + }
> +
> + net.iv_index = iv_index;
> + net.iv_update = iv_update;
> +
> + if (first) {
> + /* Must be done once per Proxy Connection after Beacon RXed */
> + setup_whitelist();
> + if (net.open_cb)
> + net.open_cb(0);
> + }
> +}
> +
> +static bool process_beacon(uint8_t *data, uint8_t size)
> +{
> + struct mesh_net_key *net_key;
> + struct net_key_parts *key_part;
> + bool rxed_iv_update, rxed_key_refresh, iv_update;
> + bool my_krf;
> + uint32_t rxed_iv_index, iv_index;
> + uint64_t cmac;
> +
> + if (size != 22)
> + return false;
> +
> + rxed_key_refresh = (data[1] & 0x01) == 0x01;
> + iv_update = rxed_iv_update = (data[1] & 0x02) == 0x02;
> + iv_index = rxed_iv_index = get_be32(data + 10);
> +
> + /* Inhibit recognizing iv_update true-->false
> + * if we have outbound SAR messages in flight */
> + if (net.msg_out != NULL) {
> + if (net.iv_update && !rxed_iv_update)
> + iv_update = true;
> + }
> +
> + /* Don't bother going further if nothing has changed */
> + if (iv_index == net.iv_index && iv_update == net.iv_update &&
> + net.iv_upd_state != IV_UPD_INIT)
> + return true;
> +
> + /* Find key we are using for SNBs */
> + net_key = find_net_key_by_id(data + 2);
> +
> + if (net_key == NULL)
> + return false;
> +
> + /* We are Provisioner, and control the key_refresh flag */
> + if (rxed_key_refresh != !!(net_key->phase == 2))
> + return false;
> +
> + if (net_key->phase != 2) {
> + my_krf = false;
> + key_part = &net_key->current;
> + } else {
> + my_krf = true;
> + key_part = &net_key->new;
> + }
> +
> + /* Ignore for incorrect KR state */
> + if (memcmp(key_part->net_id, data + 2, 8))
> + return false;
> +
> + if ((net.iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
> + (iv_index < net.iv_index)) {
> + rl_printf("iv index outside range\n");
> + return false;
> + }
> +
> + /* Any behavioral changes must pass CMAC test */
> + if (!mesh_crypto_beacon_cmac(key_part->beacon_key, key_part->net_id,
> + rxed_iv_index, my_krf,
> + rxed_iv_update, &cmac)) {
> + return false;
> + }
> +
> + if (cmac != get_be64(data + 14))
> + return false;
> +
> + if (iv_update && (net.iv_upd_state > IV_UPD_UPDATING)) {
> + if (iv_index != net.iv_index) {
> + rl_printf("Update too soon -- Rejecting\n");
> + }
> + /* Silently ignore old beacons */
> + return true;
> + }
> +
> + beacon_update(net.iv_upd_state == IV_UPD_INIT, iv_update, iv_index);
> +
> + return true;
> +}
> +
> +struct decode_params {
> + struct mesh_net_key *net_key;
> + uint8_t *packet;
> + uint32_t iv_index;
> + uint8_t size;
> + bool proxy;
> +};
> +
> +static void try_decode(gpointer data, gpointer user_data)
> +{
> + struct mesh_net_key *net_key = data;
> + struct decode_params *decode = user_data;
> + uint8_t nid = decode->packet[0] & 0x7f;
> + uint8_t tmp[29];
> + bool status = false;
> +
> + if (decode->net_key)
> + return;
> +
> + if (net_key->current.nid == nid)
> + status = mesh_crypto_packet_decode(decode->packet,
> + decode->size, decode->proxy, tmp,
> + decode->iv_index,
> + net_key->current.enc_key,
> + net_key->current.privacy_key);
> +
> + if (!status && net_key->new.nid == nid)
> + status = mesh_crypto_packet_decode(decode->packet,
> + decode->size, decode->proxy, tmp,
> + decode->iv_index,
> + net_key->new.enc_key,
> + net_key->new.privacy_key);
> +
> + if (status) {
> + decode->net_key = net_key;
> + memcpy(decode->packet, tmp, decode->size);
> + return;
> + }
> +}
> +
> +static struct mesh_net_key *net_packet_decode(bool proxy, uint32_t iv_index,
> + uint8_t *packet, uint8_t size)
> +{
> + struct decode_params decode = {
> + .proxy = proxy,
> + .iv_index = iv_index,
> + .packet = packet,
> + .size = size,
> + .net_key = NULL,
> + };
> +
> + g_list_foreach(net_keys, try_decode, &decode);
> +
> + return decode.net_key;
> +}
> +
> +static void flush_sar(GList **list, struct mesh_sar_msg *sar)
> +{
> + *list = g_list_remove(*list, sar);
> +
> + if (sar->msg_to)
> + g_source_remove(sar->msg_to);
> +
> + if (sar->ack_to)
> + g_source_remove(sar->ack_to);
> +
> + g_free(sar);
> +}
> +
> +static void flush_sar_list(GList **list)
> +{
> + struct mesh_sar_msg *sar;
> + GList *l = g_list_first(*list);
> +
> + while (l) {
> + sar = l->data;
> + flush_sar(list, sar);
> + l = g_list_first(*list);
> + }
> +}
> +
> +static void flush_pkt_list(GList **list)
> +{
> + struct mesh_pkt *pkt;
> + GList *l = g_list_first(*list);
> +
> + while (l) {
> + pkt = l->data;
> + *list = g_list_remove(*list, pkt);
> + g_free(pkt);
> + }
> +}
> +
> +static void resend_unacked_segs(gpointer data, gpointer user_data)
> +{
> + struct mesh_sar_msg *sar = data;
> +
> + if (sar->activity_cnt)
> + resend_segs(sar);
> +}
> +
> +static void send_pkt_cmplt(DBusMessage *message, void *user_data)
> +{
> + struct mesh_pkt *pkt = user_data;
> + GList *l = g_list_first(net.pkt_out);
> +
> + if (l && user_data == l->data) {
> + net.pkt_out = g_list_delete_link(net.pkt_out, l);
> + g_free(pkt);
> + } else {
> + /* This is a serious error, and probable memory leak */
> + rl_printf("ERR: send_pkt_cmplt %p not head of queue\n", pkt);
> + }
> +
> + l = g_list_first(net.pkt_out);
> +
> + if (l == NULL) {
> + /* If queue is newly empty, resend all SAR outbound packets */
> + g_list_foreach(net.msg_out, resend_unacked_segs, NULL);
> + return;
> + }
> +
> + pkt = l->data;
> +
> + mesh_gatt_write(net.proxy_in, pkt->data, pkt->len,
> + send_pkt_cmplt, pkt);
> +}
> +
> +static void send_mesh_pkt(struct mesh_pkt *pkt)
> +{
> + bool queued = !!(net.pkt_out);
> +
> + net.pkt_out = g_list_append(net.pkt_out, pkt);
> +
> + if (queued)
> + return;
> +
> + mesh_gatt_write(net.proxy_in, pkt->data, pkt->len,
> + send_pkt_cmplt, pkt);
> +}
> +
> +static uint32_t get_next_seq()
> +{
> + uint32_t this_seq = net.seq_num++;
> +
> + if (net.seq_num + 32 >= net.seq_num_reserved) {
> + net.seq_num_reserved = net.seq_num + 100;
> + prov_db_local_set_seq_num(net.seq_num_reserved);
> + }
> +
> + return this_seq;
> +}
> +
> +static void send_seg(struct mesh_sar_msg *sar, uint8_t seg)
> +{
> + struct mesh_net_key *net_key;
> + struct net_key_parts *part;
> + struct mesh_pkt *pkt;
> + uint8_t *data;
> +
> + net_key = find_net_key_by_idx(sar->net_idx);
> +
> + if (net_key == NULL)
> + return;
> +
> + /* Choose which components to use to secure pkt */
> + if (net_key->phase == 2 && net_key->new.nid != 0xff)
> + part = &net_key->new;
> + else
> + part = &net_key->current;
> +
> + pkt = g_new0(struct mesh_pkt, 1);
> +
> + if (pkt == NULL)
> + return;
> +
> + /* leave extra byte at start for GATT Proxy type */
> + data = pkt->data + 1;
> +
> + SET_PKT_NID(data, part->nid);
> + SET_PKT_IVI(data, sar->iv_index & 1);
> + SET_PKT_CTL(data, sar->ctl);
> + SET_PKT_TTL(data, sar->ttl);
> + SET_PKT_SEQ(data, get_next_seq());
> + SET_PKT_SRC(data, sar->src);
> + SET_PKT_DST(data, sar->dst);
> + SET_PKT_SEGMENTED(data, sar->segmented);
> +
> + if (sar->ctl)
> + SET_PKT_OPCODE(data, sar->data[0]);
> + else
> + SET_PKT_AKF_AID(data, sar->akf_aid);
> +
> + if (sar->segmented) {
> +
> + if (!sar->ctl)
> + SET_PKT_SZMIC(data, sar->szmic);
> +
> + SET_PKT_SEQ0(data, sar->seqAuth);
> + SET_PKT_SEGO(data, seg);
> + SET_PKT_SEGN(data, sar->segN);
> +
> + memcpy(PKT_TRANS(data) + 4,
> + sar->data + sar->ctl + (seg * 12), 12);
> +
> + pkt->len = 9 + 4;
> +
> + if (sar->segN == seg)
> + pkt->len += (sar->len - sar->ctl) % 12;
> +
> + if (pkt->len == (9 + 4))
> + pkt->len += 12;
> +
> + } else {
> + memcpy(PKT_TRANS(data) + 1,
> + sar->data + sar->ctl, 15);
> +
> + pkt->len = 9 + 1 + sar->len - sar->ctl;
> + }
> +
> + pkt->len += (sar->ctl ? 8 : 4);
> + mesh_crypto_packet_encode(data, pkt->len,
> + part->enc_key,
> + sar->iv_index,
> + part->privacy_key);
> +
> +
> + /* Prepend GATT_Proxy packet type */
> + if (sar->proxy)
> + pkt->data[0] = PROXY_CONFIG_PDU;
> + else
> + pkt->data[0] = PROXY_NETWORK_PDU;
> +
> + pkt->len++;
> +
> + send_mesh_pkt(pkt);
> +}
> +
> +static void resend_segs(struct mesh_sar_msg *sar)
> +{
> + uint32_t ack = 1;
> + uint8_t i;
> +
> + sar->activity_cnt = 0;
> +
> + for (i = 0; i <= sar->segN; i++, ack <<= 1) {
> + if (!(ack & sar->ack))
> + send_seg(sar, i);
> + }
> +}
> +
> +static bool ack_rxed(bool to, uint16_t src, uint16_t dst, bool obo,
> + uint16_t seq0, uint32_t ack_flags)
> +{
> + struct mesh_sar_msg *sar = find_sar_out_by_dst(src);
> + uint32_t full_ack;
> +
> + /* Silently ignore unknown (stale?) ACKs */
> + if (sar == NULL)
> + return true;
> +
> + full_ack = 0xffffffff >> (31 - sar->segN);
> +
> + sar->ack |= (ack_flags & full_ack);
> +
> + if (sar->ack == full_ack) {
> + /* Outbound message 100% received by remote node */
> + flush_sar(&net.msg_out, sar);
> + return true;
> + }
> +
> + /* Because we are GATT, and slow, only resend PKTs if it is
> + * time *and* our outbound PKT queue is empty. */
> + sar->activity_cnt++;
> +
> + if (net.pkt_out == NULL)
> + resend_segs(sar);
> +
> + return true;
> +}
> +
> +static bool proxy_ctl_rxed(uint16_t net_idx, uint32_t iv_index,
> + uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
> + uint8_t *trans, uint16_t len)
> +{
> + if (len < 1)
> + return false;
> +
> + switch(trans[0]) {
> + case FILTER_STATUS:
> + if (len != 4)
> + return false;
> +
> + net.blacklist = !!(trans[1] == BLACKLIST_FILTER);
> + rl_printf("Proxy %slist filter length: %d\n",
> + net.blacklist ? "Black" : "White",
> + get_be16(trans + 2));
> +
> + return true;
> +
> + default:
> + return false;
> + }
> +
> + return false;
> +}
> +
> +static bool ctl_rxed(uint16_t net_idx, uint32_t iv_index,
> + uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
> + uint8_t *trans, uint16_t len)
> +{
> + /* TODO: Handle control messages */
> + return false;
> +}
> +
> +struct decrypt_params {
> + uint8_t *nonce;
> + uint8_t *aad;
> + uint8_t *out_msg;
> + uint8_t *trans;
> + uint32_t iv_index;
> + uint32_t seq_num;
> + uint16_t src;
> + uint16_t dst;
> + uint16_t len;
> + uint16_t net_idx;
> + uint16_t app_idx;
> + uint8_t akf_aid;
> + bool szmic;
> +};
> +
> +
> +static void try_decrypt(gpointer data, gpointer user_data)
> +{
> + struct mesh_app_key *app_key = data;
> + struct decrypt_params *decrypt = user_data;
> + size_t mic_size = decrypt->szmic ? sizeof(uint64_t) : sizeof(uint32_t);
> + bool status = false;
> +
> + /* Already done... Nothing to do */
> + if (decrypt->app_idx != APP_IDX_INVALID)
> + return;
> +
> + /* Don't decrypt on Appkeys not owned by this NetKey */
> + if (app_key->net_idx != decrypt->net_idx)
> + return;
> +
> + /* Test and decrypt against current key copy */
> + if (app_key->current.akf_aid == decrypt->akf_aid)
> + status = mesh_crypto_aes_ccm_decrypt(decrypt->nonce,
> + app_key->current.key,
> + decrypt->aad, decrypt->aad ? 16 : 0,
> + decrypt->trans, decrypt->len,
> + decrypt->out_msg, NULL, mic_size);
> +
> + /* Test and decrypt against new key copy */
> + if (!status && app_key->new.akf_aid == decrypt->akf_aid)
> + status = mesh_crypto_aes_ccm_decrypt(decrypt->nonce,
> + app_key->new.key,
> + decrypt->aad, decrypt->aad ? 16 : 0,
> + decrypt->trans, decrypt->len,
> + decrypt->out_msg, NULL, mic_size);
> +
> + /* If successful, terminate with successful App IDX */
> + if (status)
> + decrypt->app_idx = app_key->generic.idx;
> +}
> +
> +static uint16_t access_pkt_decrypt(uint8_t *nonce, uint8_t *aad,
> + uint16_t net_idx, uint8_t akf_aid, bool szmic,
> + uint8_t *trans, uint16_t len)
> +{
> + uint8_t *out_msg;
> + struct decrypt_params decrypt = {
> + .nonce = nonce,
> + .aad = aad,
> + .net_idx = net_idx,
> + .akf_aid = akf_aid,
> + .szmic = szmic,
> + .trans = trans,
> + .len = len,
> + .app_idx = APP_IDX_INVALID,
> + };
> +
> + out_msg = g_malloc(len);
> +
> + if (out_msg == NULL)
> + return false;
> +
> + decrypt.out_msg = out_msg;
> +
> + g_list_foreach(app_keys, try_decrypt, &decrypt);
> +
> + if (decrypt.app_idx != APP_IDX_INVALID)
> + memcpy(trans, out_msg, len);
> +
> + g_free(out_msg);
> +
> + return decrypt.app_idx;
> +}
> +
> +static bool access_rxed(uint8_t *nonce, uint16_t net_idx,
> + uint32_t iv_index, uint32_t seq_num,
> + uint16_t src, uint16_t dst,
> + uint8_t akf_aid, bool szmic, uint8_t *trans, uint16_t len)
> +{
> + uint16_t app_idx = access_pkt_decrypt(nonce, NULL,
> + net_idx, akf_aid, szmic, trans, len);
> +
> + if (app_idx != APP_IDX_INVALID) {
> + len -= szmic ? sizeof(uint64_t) : sizeof(uint32_t);
> +
> + node_local_data_handler(src, dst, iv_index, seq_num,
> + app_idx, trans, len);
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static void try_virt_decrypt(gpointer data, gpointer user_data)
> +{
> + struct mesh_virt_addr *virt = data;
> + struct decrypt_params *decrypt = user_data;
> +
> + if (decrypt->app_idx != APP_IDX_INVALID || decrypt->dst != virt->va16)
> + return;
> +
> + decrypt->app_idx = access_pkt_decrypt(decrypt->nonce,
> + virt->va128,
> + decrypt->net_idx, decrypt->akf_aid,
> + decrypt->szmic, decrypt->trans, decrypt->len);
> +
> + if (decrypt->app_idx != APP_IDX_INVALID) {
> + uint16_t len = decrypt->len;
> +
> + len -= decrypt->szmic ? sizeof(uint64_t) : sizeof(uint32_t);
> +
> + node_local_data_handler(decrypt->src, virt->va32,
> + decrypt->iv_index, decrypt->seq_num,
> + decrypt->app_idx, decrypt->trans, len);
> + }
> +}
> +
> +static bool virtual_rxed(uint8_t *nonce, uint16_t net_idx,
> + uint32_t iv_index, uint32_t seq_num,
> + uint16_t src, uint16_t dst,
> + uint8_t akf_aid, bool szmic, uint8_t *trans, uint16_t len)
> +{
> + struct decrypt_params decrypt = {
> + .nonce = nonce,
> + .net_idx = net_idx,
> + .iv_index = iv_index,
> + .seq_num = seq_num,
> + .src = dst,
> + .dst = dst,
> + .akf_aid = akf_aid,
> + .szmic = szmic,
> + .trans = trans,
> + .len = len,
> + .app_idx = APP_IDX_INVALID,
> + };
> +
> + /* Cycle through known virtual addresses */
> + g_list_foreach(virt_addrs, try_virt_decrypt, &decrypt);
> +
> + if (decrypt.app_idx != APP_IDX_INVALID)
> + return true;
> +
> + return false;
> +}
> +
> +static bool msg_rxed(uint16_t net_idx, uint32_t iv_index, bool szmic,
> + uint8_t ttl, uint32_t seq_num, uint32_t seq_auth,
> + uint16_t src, uint16_t dst,
> + uint8_t *trans, uint16_t len)
> +{
> + uint8_t akf_aid = TRANS_AKF_AID(trans);
> + bool result;
> + size_t mic_size = szmic ? sizeof(uint64_t) : sizeof(uint32_t);
> + uint8_t nonce[13];
> + uint8_t *dev_key;
> + uint8_t *out = NULL;
> +
> + if (!TRANS_AKF(trans)) {
> + /* Compose Nonce */
> + result = mesh_crypto_device_nonce(seq_auth, src, dst,
> + iv_index, szmic, nonce);
> +
> + if (!result) return false;
> +
> + out = g_malloc0(TRANS_LEN(trans, len));
> + if (out == NULL) return false;
> +
> + /* If we are provisioner, we probably RXed on remote Dev Key */
> + if (net.provisioner) {
> + dev_key = node_get_device_key(node_find_by_addr(src));
> +
> + if (dev_key == NULL)
> + goto local_dev_key;
> + } else
> + goto local_dev_key;
> +
> + result = mesh_crypto_aes_ccm_decrypt(nonce, dev_key,
> + NULL, 0,
> + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len),
> + out, NULL, mic_size);
> +
> + if (result) {
> + node_local_data_handler(src, dst,
> + iv_index, seq_num, APP_IDX_DEV,
> + out, TRANS_LEN(trans, len) - mic_size);
> + goto done;
> + }
> +
> +local_dev_key:
> + /* Always fallback to the local Dev Key */
> + dev_key = node_get_device_key(node_get_local_node());
> +
> + if (dev_key == NULL)
> + goto done;
> +
> + result = mesh_crypto_aes_ccm_decrypt(nonce, dev_key,
> + NULL, 0,
> + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len),
> + out, NULL, mic_size);
> +
> + if (result) {
> + node_local_data_handler(src, dst,
> + iv_index, seq_num, APP_IDX_DEV,
> + out, TRANS_LEN(trans, len) - mic_size);
> + goto done;
> + }
> +
> + goto done;
> + }
> +
> + result = mesh_crypto_application_nonce(seq_auth, src, dst,
> + iv_index, szmic, nonce);
> +
> + if (!result) goto done;
> +
> + /* If Virtual destination wrap the Access decoder with Virtual */
> + if (IS_VIRTUAL(dst)) {
> + result = virtual_rxed(nonce, net_idx, iv_index, seq_num,
> + src, dst, akf_aid, szmic,
> + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len));
> + goto done;
> + }
> +
> + /* Try all matching App Keys until success or exhaustion */
> + result = access_rxed(nonce, net_idx, iv_index, seq_num,
> + src, dst, akf_aid, szmic,
> + TRANS_PAYLOAD(trans), TRANS_LEN(trans, len));
> +
> +done:
> + if (out != NULL)
> + g_free(out);
> +
> + return result;
> +}
> +
> +static void send_sar_ack(struct mesh_sar_msg *sar)
> +{
> + uint8_t ack[7];
> +
> + sar->activity_cnt = 0;
> +
> + memset(ack, 0, sizeof(ack));
> + SET_TRANS_OPCODE(ack, NET_OP_SEG_ACKNOWLEDGE);
> + SET_TRANS_SEQ0(ack, sar->seqAuth);
> + SET_TRANS_ACK(ack, sar->ack);
> +
> + net_ctl_msg_send(0xff, sar->dst, sar->src, ack, sizeof(ack));
> +}
> +
> +static gboolean sar_out_ack_timeout(void *user_data)
> +{
> + struct mesh_sar_msg *sar = user_data;
> +
> + sar->activity_cnt++;
> +
> + /* Because we are GATT, and slow, only resend PKTs if it is
> + * time *and* our outbound PKT queue is empty. */
> + if (net.pkt_out == NULL)
> + resend_segs(sar);
> +
> + /* Only add resent SAR pkts to empty queue */
> + return true;
> +}
> +
> +static gboolean sar_out_msg_timeout(void *user_data)
> +{
> + struct mesh_sar_msg *sar = user_data;
> +
> + /* msg_to will expire when we return false */
> + sar->msg_to = 0;
> +
> + flush_sar(&net.msg_out, sar);
> +
> + return false;
> +}
> +
> +static gboolean sar_in_ack_timeout(void *user_data)
> +{
> + struct mesh_sar_msg *sar = user_data;
> + uint32_t full_ack = 0xffffffff >> (31 - sar->segN);
> +
> + if (sar->activity_cnt || sar->ack != full_ack)
> + send_sar_ack(sar);
> +
> + return true;
> +}
> +
> +static gboolean sar_in_msg_timeout(void *user_data)
> +{
> + struct mesh_sar_msg *sar = user_data;
> +
> + /* msg_to will expire when we return false */
> + sar->msg_to = 0;
> +
> + flush_sar(&net.sar_in, sar);
> +
> + return false;
> +}
> +
> +static uint32_t calc_seqAuth(uint32_t seq_num, uint8_t *trans)
> +{
> + uint32_t seqAuth = seq_num & ~0x1fff;
> +
> + seqAuth |= TRANS_SEQ0(trans);
> +
> + return seqAuth;
> +}
> +
> +static bool seg_rxed(uint16_t net_idx, uint32_t iv_index, bool ctl,
> + uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
> + uint8_t *trans, uint16_t len)
> +{
> + struct mesh_sar_msg *sar;
> + uint32_t seqAuth = calc_seqAuth(seq_num, trans);
> + uint8_t segN, segO;
> + uint32_t old_ack, full_ack, last_ack_mask;
> + bool send_ack, result = false;
> +
> + segN = TRANS_SEGN(trans);
> + segO = TRANS_SEGO(trans);
> +
> + /* Only support single incoming SAR'd message per SRC */
> + sar = find_sar_in_by_src(src);
> +
> + /* Reuse existing SAR structure if appropriate */
> + if (sar) {
> + uint64_t iv_seqAuth = (uint64_t)iv_index << 32 | seqAuth;
> + uint64_t old_iv_seqAuth = (uint64_t)sar->iv_index << 32 |
> + sar->seqAuth;
> + if (old_iv_seqAuth < iv_seqAuth) {
> +
> + flush_sar(&net.sar_in, sar);
> + sar = NULL;
> +
> + } else if (old_iv_seqAuth > iv_seqAuth) {
> +
> + /* New segment is Stale. Silently ignore */
> + return false;
> +
> + } else if (segN != sar->segN) {
> +
> + /* Remote side sent conflicting data: abandon */
> + flush_sar(&net.sar_in, sar);
> + sar = NULL;
> +
> + }
> + }
> +
> + if (sar == NULL) {
> + sar = g_malloc0(sizeof(*sar) + (12 * segN));
> +
> + if (sar == NULL)
> + return false;
> +
> + sar->net_idx = net_idx;
> + sar->iv_index = iv_index;
> + sar->ctl = ctl;
> + sar->ttl = ttl;
> + sar->seqAuth = seqAuth;
> + sar->src = src;
> + sar->dst = dst;
> + sar->segmented = true;
> + sar->szmic = TRANS_SZMIC(trans);
> + sar->segN = segN;
> +
> + /* In all cases, the reassembled packet should begin with the
> + * same first octet of all segments, minus the SEGMENTED flag */
> + sar->data[0] = trans[0] & 0x7f;
> +
> + net.sar_in = g_list_append(net.sar_in, sar);
> +
> + /* Setup expiration timers */
> + if (IS_UNICAST(dst))
> + sar->ack_to = g_timeout_add(5000,
> + sar_in_ack_timeout, sar);
> +
> + sar->msg_to = g_timeout_add(60000, sar_in_msg_timeout, sar);
> + }
> +
> + /* If last segment, calculate full msg size */
> + if (segN == segO)
> + sar->len = (segN * 12) + len - 3;
> +
> + /* Copy to correct offset */
> + memcpy(sar->data + 1 + (12 * segO), trans + 4, 12);
> +
> + full_ack = 0xffffffff >> (31 - segN);
> + last_ack_mask = 0xffffffff << segO;
> + old_ack = sar->ack;
> + sar->ack |= 1 << segO;
> + send_ack = false;
> +
> + /* Determine if we should forward message */
> + if (sar->ack == full_ack && old_ack != full_ack) {
> +
> + /* First time we have seen this complete message */
> + send_ack = true;
> +
> + if (ctl)
> + result = ctl_rxed(sar->net_idx, sar->iv_index,
> + sar->ttl, sar->seqAuth, sar->src,
> + sar->dst, sar->data, sar->len);
> + else
> + result = msg_rxed(sar->net_idx, sar->iv_index,
> + sar->szmic, sar->ttl,
> + seq_num, sar->seqAuth, sar->src,
> + sar->dst, sar->data, sar->len);
> + }
> +
> + /* Never Ack Group addressed SAR messages */
> + if (!IS_UNICAST(dst))
> + return result;
> +
> + /* Tickle the ACK system so it knows we are still RXing segments */
> + sar->activity_cnt++;
> +
> + /* Determine if we should ACK */
> + if (old_ack == sar->ack)
> + /* Let the timer generate repeat ACKs as needed */
> + send_ack = false;
> + else if ((last_ack_mask & sar->ack) == (last_ack_mask & full_ack))
> + /* If this was largest segO outstanding segment, we ACK */
> + send_ack = true;
> +
> + if (send_ack)
> + send_sar_ack(sar);
> +
> + return result;
> +}
> +
> +bool net_data_ready(uint8_t *msg, uint8_t len)
> +{
> + uint8_t type = *msg++;
> + uint32_t iv_index = net.iv_index;
> + struct mesh_net_key *net_key;
> +
> + if (len-- < 10) return false;
> +
> + if (type == PROXY_MESH_BEACON)
> + return process_beacon(msg, len);
> + else if (type > PROXY_CONFIG_PDU)
> + return false;
> +
> + /* RXed iv_index must be equal or 1 less than local iv_index */
> + /* With the clue being high-order bit of first octet */
> + if (!!(iv_index & 0x01) != !!(msg[0] & 0x80)) {
> + if (iv_index)
> + iv_index--;
> + else
> + return false;
> + }
> +
> + net_key = net_packet_decode(type == PROXY_CONFIG_PDU,
> + iv_index, msg, len);
> +
> + if (net_key == NULL)
> + return false;
> +
> + /* CTL packets have 64 bit network MIC, otherwise 32 bit MIC */
> + len -= PKT_CTL(msg) ? sizeof(uint64_t) : sizeof(uint32_t);
> +
> + if (type == PROXY_CONFIG_PDU) {
> +
> + /* Proxy Configuration DST messages must be 0x0000 */
> + if (PKT_DST(msg))
> + return false;
> +
> + return proxy_ctl_rxed(net_key->generic.idx,
> + iv_index, PKT_TTL(msg), PKT_SEQ(msg),
> + PKT_SRC(msg), PKT_DST(msg),
> + PKT_TRANS(msg), PKT_TRANS_LEN(len));
> +
> + } if (PKT_CTL(msg) && PKT_OPCODE(msg) == NET_OP_SEG_ACKNOWLEDGE) {
> +
> + return ack_rxed(false, PKT_SRC(msg), PKT_DST(msg),
> + PKT_OBO(msg), PKT_SEQ0(msg), PKT_ACK(msg));
> +
> + } else if (PKT_SEGMENTED(msg)) {
> +
> + return seg_rxed(net_key->generic.idx, iv_index, PKT_CTL(msg),
> + PKT_TTL(msg), PKT_SEQ(msg),
> + PKT_SRC(msg), PKT_DST(msg),
> + PKT_TRANS(msg), PKT_TRANS_LEN(len));
> +
> + } else if (!PKT_CTL(msg)){
> +
> + return msg_rxed(net_key->generic.idx,
> + iv_index, false, PKT_TTL(msg), PKT_SEQ(msg),
> + PKT_SEQ(msg), PKT_SRC(msg), PKT_DST(msg),
> + PKT_TRANS(msg), PKT_TRANS_LEN(len));
> + } else {
> +
> + return ctl_rxed(net_key->generic.idx,
> + iv_index, PKT_TTL(msg), PKT_SEQ(msg),
> + PKT_SRC(msg), PKT_DST(msg),
> + PKT_TRANS(msg), PKT_TRANS_LEN(len));
> +
> + }
> +
> + return false;
> +}
> +
> +bool net_session_open(GDBusProxy *data_in, bool provisioner,
> + net_mesh_session_open_callback cb)
> +{
> + if (net.proxy_in)
> + return false;
> +
> + net.proxy_in = data_in;
> + net.iv_upd_state = IV_UPD_INIT;
> + net.blacklist = false;
> + net.provisioner = provisioner;
> + net.open_cb = cb;
> + flush_pkt_list(&net.pkt_out);
> + return true;
> +}
> +
> +void net_session_close(GDBusProxy *data_in)
> +{
> + if (net.proxy_in == data_in)
> + net.proxy_in = NULL;
> +
> + flush_sar_list(&net.sar_in);
> + flush_sar_list(&net.msg_out);
> + flush_pkt_list(&net.pkt_out);
> +}
> +
> +bool net_register_unicast(uint16_t unicast, uint8_t count)
> +{
> + /* TODO */
> + return true;
> +}
> +
> +bool net_register_group(uint16_t group_addr)
> +{
> + /* TODO */
> + return true;
> +}
> +
> +uint32_t net_register_virtual(uint8_t buf[16])
> +{
> + /* TODO */
> + return 0;
> +}
> +
> +static bool get_enc_keys(uint16_t app_idx, uint16_t dst,
> + uint8_t *akf_aid, uint8_t **app_enc_key,
> + uint16_t *net_idx)
> +{
> + if (app_idx == APP_IDX_DEV) {
> + struct mesh_node *node;
> + uint8_t *enc_key = NULL;
> +
> + if (net.provisioner) {
> + /* Default to Remote Device Key when Provisioner */
> + node = node_find_by_addr(dst);
> + enc_key = node_get_device_key(node);
> + }
> +
> + if (enc_key == NULL) {
> + /* Use Local node Device Key */
> + node = node_get_local_node();
> + enc_key = node_get_device_key(node);
> + }
> +
> + if (enc_key == NULL || node == NULL)
> + return false;
> +
> + if (akf_aid) *akf_aid = 0;
> + if (app_enc_key) *app_enc_key = enc_key;
> + if (net_idx) *net_idx = node_get_primary_net_idx(node);
> +
> + } else {
> + struct mesh_app_key *app_key = find_app_key_by_idx(app_idx);
> + struct mesh_net_key *net_key;
> + bool phase_two;
> +
> +
> + if (app_key == NULL)
> + return false;
> +
> + net_key = find_net_key_by_idx(app_key->net_idx);
> +
> + if (net_key == NULL)
> + return false;
> +
> + if (net_idx) *net_idx = app_key->net_idx;
> +
> + phase_two = !!(net_key->phase == 2);
> +
> + if (phase_two && app_key->new.akf_aid != 0xff) {
> + if (app_enc_key) *app_enc_key = app_key->new.key;
> + if (akf_aid) *akf_aid = app_key->new.akf_aid;
> + } else {
> + if (app_enc_key) *app_enc_key = app_key->current.key;
> + if (akf_aid) *akf_aid = app_key->current.akf_aid;
> + }
> + }
> +
> + return true;
> +}
> +
> +bool net_ctl_msg_send(uint8_t ttl, uint16_t src, uint16_t dst,
> + uint8_t *buf, uint16_t len)
> +{
> + struct mesh_node *node = node_get_local_node();
> + struct mesh_sar_msg sar_ctl;
> +
> + /* For simplicity, we will reject segmented OB CTL messages */
> + if (len > 12 || node == NULL || buf == NULL || buf[0] & 0x80)
> + return false;
> +
> + if (!src) {
> + src = node_get_primary(node);
> +
> + if (!src)
> + return false;
> + }
> +
> + if (ttl == 0xff)
> + ttl = net.default_ttl;
> +
> + memset(&sar_ctl, 0, sizeof(sar_ctl));
> +
> + if (!dst)
> + sar_ctl.proxy = true;
> +
> + /* Get the default net_idx for remote device (or local) */
> + get_enc_keys(APP_IDX_DEV, dst, NULL, NULL, &sar_ctl.net_idx);
> + sar_ctl.ctl = true;
> + sar_ctl.iv_index = net.iv_index - net.iv_update;
> + sar_ctl.ttl = ttl;
> + sar_ctl.src = src;
> + sar_ctl.dst = dst;
> + sar_ctl.len = len;
> + memcpy(sar_ctl.data, buf, len);
> + send_seg(&sar_ctl, 0);
> +
> + return true;
> +}
> +
> +bool net_access_layer_send(uint8_t ttl, uint16_t src, uint32_t dst,
> + uint16_t app_idx, uint8_t *buf, uint16_t len)
> +{
> + struct mesh_node *node = node_get_local_node();
> + struct mesh_sar_msg *sar;
> + uint8_t *app_enc_key = NULL;
> + uint8_t *aad = NULL;
> + uint32_t mic32;
> + uint8_t aad_len = 0;
> + uint8_t i, j, ackless_retries = 0;
> + uint8_t segN, akf_aid;
> + uint16_t net_idx;
> + bool result;
> +
> + if (len > 384 || node == NULL)
> + return false;
> +
> + if (!src)
> + src = node_get_primary(node);
> +
> + if (!src || !dst)
> + return false;
> +
> + if (ttl == 0xff)
> + ttl = net.default_ttl;
> +
> + if (IS_VIRTUAL(dst)) {
> + struct mesh_virt_addr *virt = find_virt_by_dst(dst);
> +
> + if (virt == NULL)
> + return false;
> +
> + dst = virt->va16;
> + aad = virt->va128;
> + aad_len = sizeof(virt->va128);
> + }
> +
> + result = get_enc_keys(app_idx, dst,
> + &akf_aid, &app_enc_key, &net_idx);
> +
> + if (!result)
> + return false;
> +
> + segN = SEG_MAX(len);
> +
> + /* Only one ACK required SAR message per destination at a time */
> + if (segN && IS_UNICAST(dst)) {
> + sar = find_sar_out_by_dst(dst);
> +
> + if (sar)
> + flush_sar(&net.msg_out, sar);
> + }
> +
> + sar = g_malloc0(sizeof(struct mesh_sar_msg) + (segN * 12));
> +
> + if (sar == NULL)
> + return false;
> +
> + if (segN)
> + sar->segmented = true;
> +
> + sar->ttl = ttl;
> + sar->segN = segN;
> + sar->seqAuth = net.seq_num;
> + sar->iv_index = net.iv_index - net.iv_update;
> + sar->net_idx = net_idx;
> + sar->src = src;
> + sar->dst = dst;
> + sar->akf_aid = akf_aid;
> + sar->len = len + sizeof(uint32_t);
> +
> + mesh_crypto_application_encrypt(akf_aid,
> + sar->seqAuth, src,
> + dst, sar->iv_index,
> + app_enc_key,
> + aad, aad_len,
> + buf, len,
> + sar->data, &mic32,
> + sizeof(uint32_t));
> +
> + /* If sending as a segmented message to a non-Unicast (thus non-ACKing)
> + * destination, send each segments multiple times. */
> + if (!IS_UNICAST(dst) && segN)
> + ackless_retries = 4;
> +
> + for (j = 0; j <= ackless_retries; j++) {
> + for (i = 0; i <= segN; i++)
> + send_seg(sar, i);
> + }
> +
> + if (IS_UNICAST(dst) && segN) {
> + net.msg_out = g_list_append(net.msg_out, sar);
> + sar->ack_to = g_timeout_add(2000, sar_out_ack_timeout, sar);
> + sar->msg_to = g_timeout_add(60000, sar_out_msg_timeout, sar);
> + } else
> + g_free(sar);
> +
> + return true;
> +}
> +
> +bool net_set_default_ttl(uint8_t ttl)
> +{
> + if (ttl > 0x7f)
> + return false;
> +
> + net.default_ttl = ttl;
> + return true;
> +}
> +
> +uint8_t net_get_default_ttl()
> +{
> + return net.default_ttl;
> +}
> +
> +bool net_set_seq_num(uint32_t seq_num)
> +{
> + if (seq_num > 0xffffff)
> + return false;
> +
> + net.seq_num = seq_num;
> + return true;
> +}
> +
> +uint32_t net_get_seq_num()
> +{
> + return net.seq_num;
> +}
> diff --git a/mesh/node.c b/mesh/node.c
> new file mode 100644
> index 0000000..ba8d4b6
> --- /dev/null
> +++ b/mesh/node.c
> @@ -0,0 +1,879 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <sys/uio.h>
> +#include <wordexp.h>
> +
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "client/display.h"
> +#include "src/shared/util.h"
> +#include "gdbus/gdbus.h"
> +#include "monitor/uuid.h"
> +#include "mesh-net.h"
> +#include "config-model.h"
> +#include "node.h"
> +#include "keys.h"
> +#include "gatt.h"
> +#include "net.h"
> +#include "prov-db.h"
> +#include "util.h"
> +
> +struct mesh_model {
> + struct mesh_model_ops cbs;
> + void *user_data;
> + GList *bindings;
> + GList *subscriptions;
> + uint32_t id;
> + struct mesh_publication *pub;
> +};
> +
> +struct mesh_element {
> + GList *models;
> + uint16_t loc;
> + uint8_t index;
> +};
> +
> +struct mesh_node {
> + const char *name;
> + GList *net_keys;
> + GList *app_keys;
> + void *prov;
> + GList *elements;
> + uint32_t iv_index;
> + uint32_t seq_number;
> + uint16_t primary_net_idx;
> + uint16_t primary;
> + uint16_t oob;
> + uint16_t features;
> + uint8_t gatt_pkt[MAX_GATT_SIZE];
> + uint8_t dev_uuid[16];
> + uint8_t dev_key[16];
> + uint8_t num_ele;
> + uint8_t ttl;
> + uint8_t gatt_size;
> + bool provisioner;
> + struct mesh_node_composition *comp;
> +};
> +
> +static GList *nodes;
> +
> +static struct mesh_node *local_node;
> +
> +static int match_node_unicast(const void *a, const void *b)
> +{
> + const struct mesh_node *node = a;
> + uint16_t dst = GPOINTER_TO_UINT(b);
> +
> + if (dst >= node->primary &&
> + dst <= (node->primary + node->num_ele - 1))
> + return 0;
> +
> + return -1;
> +}
> +
> +static int match_device_uuid(const void *a, const void *b)
> +{
> + const struct mesh_node *node = a;
> + const uint8_t *uuid = b;
> +
> + return memcmp(node->dev_uuid, uuid, 16);
> +}
> +
> +static int match_element_idx(const void *a, const void *b)
> +{
> + const struct mesh_element *element = a;
> + uint32_t index = GPOINTER_TO_UINT(b);
> +
> + return (element->index == index) ? 0 : -1;
> +}
> +
> +static int match_model_id(const void *a, const void *b)
> +{
> + const struct mesh_model *model = a;
> + uint32_t id = GPOINTER_TO_UINT(b);
> +
> + return (model->id == id) ? 0 : -1;
> +}
> +
> +struct mesh_node *node_find_by_addr(uint16_t addr)
> +{
> + GList *l;
> +
> + if (!IS_UNICAST(addr))
> + return NULL;
> +
> + l = g_list_find_custom(nodes, GUINT_TO_POINTER(addr),
> + match_node_unicast);
> +
> + if (l)
> + return l->data;
> + else
> + return NULL;
> +}
> +
> +struct mesh_node *node_find_by_uuid(uint8_t uuid[16])
> +{
> + GList *l;
> +
> + l = g_list_find_custom(nodes, uuid, match_device_uuid);
> +
> + if (l)
> + return l->data;
> + else
> + return NULL;
> +}
> +
> +struct mesh_node *node_create_new(struct prov_svc_data *prov)
> +{
> + struct mesh_node *node;
> +
> + if (node_find_by_uuid(prov->dev_uuid))
> + return NULL;
> +
> + node = g_malloc0(sizeof(struct mesh_node));
> + if (!node)
> + return NULL;
> +
> + memcpy(node->dev_uuid, prov->dev_uuid, 16);
> + node->oob = prov->oob;
> + nodes = g_list_append(nodes, node);
> +
> + return node;
> +}
> +
> +struct mesh_node *node_new(void)
> +{
> + struct mesh_node *node;
> +
> + node = g_malloc0(sizeof(struct mesh_node));
> + if (!node)
> + return NULL;
> +
> + nodes = g_list_append(nodes, node);
> +
> + return node;
> +}
> +
> +static void model_free(void *data)
> +{
> + struct mesh_model *model = data;
> +
> + g_list_free(model->bindings);
> + g_list_free(model->subscriptions);
> + g_free(model->pub);
> + g_free(model);
> +}
> +
> +static void element_free(void *data)
> +{
> + struct mesh_element *element = data;
> +
> + g_list_free_full(element->models, model_free);
> + g_free(element);
> +}
> +
> +static void free_node_resources(void *data)
> +{
> + struct mesh_node *node = data;
> + g_list_free(node->net_keys);
> + g_list_free(node->app_keys);
> +
> + g_list_free_full(node->elements, element_free);
> +
> + if(node->comp)
> + g_free(node->comp);
> +
> + g_free(node);
> +}
> +
> +void node_free(struct mesh_node *node)
> +{
> + if (!node)
> + return;
> + nodes = g_list_remove(nodes, node);
> + free_node_resources(node);
> +}
> +
> +void node_cleanup(void)
> +{
> + g_list_free_full(nodes, free_node_resources);
> + local_node = NULL;
> +}
> +
> +bool node_is_provisioned(struct mesh_node *node)
> +{
> + return (!IS_UNASSIGNED(node->primary));
> +}
> +
> +void *node_get_prov(struct mesh_node *node)
> +{
> + return node->prov;
> +}
> +
> +void node_set_prov(struct mesh_node *node, void *prov)
> +{
> + node->prov = prov;
> +}
> +
> +bool node_app_key_add(struct mesh_node *node, uint16_t idx)
> +{
> + uint32_t index;
> + uint16_t net_idx;
> +
> + if (!node)
> + return false;
> +
> + net_idx = keys_app_key_get_bound(idx);
> + if (net_idx == NET_IDX_INVALID)
> + return false;
> +
> + if (!g_list_find(node->net_keys, GUINT_TO_POINTER(net_idx)))
> + return false;
> +
> + index = (net_idx << 16) + idx;
> +
> + if (g_list_find(node->app_keys, GUINT_TO_POINTER(index)))
> + return false;
> +
> + node->app_keys = g_list_append(node->app_keys, GUINT_TO_POINTER(index));
> +
> + return true;
> +}
> +
> +bool node_net_key_add(struct mesh_node *node, uint16_t index)
> +{
> + if(!node)
> + return false;
> +
> + if (g_list_find(node->net_keys, GUINT_TO_POINTER(index)))
> + return false;
> +
> + node->net_keys = g_list_append(node->net_keys, GUINT_TO_POINTER(index));
> + return true;
> +}
> +
> +bool node_net_key_delete(struct mesh_node *node, uint16_t index)
> +{
> + GList *l;
> +
> + if(!node)
> + return false;
> +
> + l = g_list_find(node->net_keys, GUINT_TO_POINTER(index));
> + if (!l)
> + return false;
> +
> + node->net_keys = g_list_remove(node->net_keys,
> + GUINT_TO_POINTER(index));
> + /* TODO: remove all associated app keys and bindings */
> + return true;
> +}
> +
> +bool node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
> + uint16_t idx)
> +{
> + GList *l;
> + uint32_t index;
> +
> + if(!node)
> + return false;
> +
> + index = (net_idx << 16) + idx;
> +
> + l = g_list_find(node->app_keys, GUINT_TO_POINTER(index));
> + if (!l)
> + return false;
> +
> + node->app_keys = g_list_remove(node->app_keys,
> + GUINT_TO_POINTER(index));
> + /* TODO: remove all associated bindings */
> + return true;
> +}
> +
> +void node_set_primary(struct mesh_node *node, uint16_t unicast)
> +{
> + node->primary = unicast;
> +}
> +
> +uint16_t node_get_primary(struct mesh_node *node)
> +{
> + if (!node)
> + return UNASSIGNED_ADDRESS;
> + else
> + return node->primary;
> +}
> +
> +void node_set_device_key(struct mesh_node *node, uint8_t *key)
> +
> +{
> + if (!node || !key)
> + return;
> +
> + memcpy(node->dev_key, key, 16);
> +}
> +
> +uint8_t *node_get_device_key(struct mesh_node *node)
> +{
> + if (!node)
> + return NULL;
> + else
> + return node->dev_key;
> +}
> +
> +void node_set_num_elements(struct mesh_node *node, uint8_t num_ele)
> +{
> + node->num_ele = num_ele;
> +}
> +
> +uint8_t node_get_num_elements(struct mesh_node *node)
> +{
> + return node->num_ele;
> +}
> +
> +GList *node_get_net_keys(struct mesh_node *node)
> +{
> + if (!node)
> + return NULL;
> + else
> + return node->net_keys;
> +}
> +
> +GList *node_get_app_keys(struct mesh_node *node)
> +{
> + if (!node)
> + return NULL;
> + else
> + return node->app_keys;
> +}
> +
> +bool node_parse_composition(struct mesh_node *node, uint8_t *data, uint16_t len)
> +{
> + struct mesh_node_composition *comp;
> + uint16_t features;
> + int i;
> +
> + comp = g_malloc0(sizeof(struct mesh_node_composition));
> + if (!comp)
> + return false;
> +
> + /* skip page -- We only support Page Zero */
> + data++;
> + len--;
> +
> + comp->cid = get_le16(&data[0]);
> + comp->pid = get_le16(&data[2]);
> + comp->vid = get_le16(&data[4]);
> + comp->crpl = get_le16(&data[6]);
> + features = get_le16(&data[8]);
> + data += 10;
> + len -= 10;
> +
> + comp->relay = !!(features & MESH_FEATURE_RELAY);
> + comp->proxy = !!(features & MESH_FEATURE_PROXY);
> + comp->friend = !!(features & MESH_FEATURE_FRIEND);
> + comp->lpn = !!(features & MESH_FEATURE_LPN);
> +
> + for (i = 0; i< node->num_ele; i++) {
> + uint8_t m, v;
> + uint32_t mod_id;
> + uint16_t vendor_id;
> + struct mesh_element *ele;
> + ele = g_malloc0(sizeof(struct mesh_element));
> + if (!ele)
> + return false;
> +
> + ele->index = i;
> + ele->loc = get_le16(data);
> + data += 2;
> + node->elements = g_list_append(node->elements, ele);
> +
> + m = *data++;
> + v = *data++;
> + len -= 4;
> +
> + while (len >= 2 && m--) {
> + mod_id = get_le16(data);
> + /* initialize uppper 16 bits to 0xffff for SIG models */
> + mod_id |= 0xffff0000;
> + if (!node_set_model(node, ele->index, mod_id))
> + return false;
> + data += 2;
> + len -= 2;
> + }
> + while (len >= 4 && v--) {
> + mod_id = get_le16(data);
> + vendor_id = get_le16(data);
> + mod_id |= (vendor_id << 16);
> + if (!node_set_model(node, ele->index, mod_id))
> + return false;
> + data += 4;
> + len -= 4;
> + }
> +
> + }
> +
> + node->comp = comp;
> + return true;
> +}
> +
> +bool node_set_local_node(struct mesh_node *node)
> +{
> + if (local_node) {
> + rl_printf("Local node already registered\n");
> + return false;
> + }
> + net_register_unicast(node->primary, node->num_ele);
> +
> + local_node = node;
> + local_node->provisioner = true;
> +
> + return true;
> +}
> +
> +struct mesh_node *node_get_local_node()
> +{
> + return local_node;
> +}
> +
> +uint16_t node_get_primary_net_idx(struct mesh_node *node)
> +{
> + if (node == NULL)
> + return NET_IDX_INVALID;
> +
> + return node->primary_net_idx;
> +}
> +
> +static bool deliver_model_data(struct mesh_element* element, uint16_t src,
> + uint16_t app_idx, uint8_t *data, uint16_t len)
> +{
> + GList *l;
> +
> + for(l = element->models; l; l = l->next) {
> + struct mesh_model *model = l->data;
> +
> + if (!g_list_find(model->bindings, GUINT_TO_POINTER(app_idx)))
> + continue;
> +
> + if (model->cbs.recv &&
> + model->cbs.recv(src, data, len, model->user_data))
> + return true;
> + }
> +
> + return false;
> +}
> +
> +void node_local_data_handler(uint16_t src, uint32_t dst,
> + uint32_t iv_index, uint32_t seq_num,
> + uint16_t app_idx, uint8_t *data, uint16_t len)
> +{
> + GList *l;
> + bool res;
> + uint64_t iv_seq;
> + uint64_t iv_seq_remote;
> + uint8_t ele_idx;
> + struct mesh_element *element;
> + struct mesh_node *remote;
> + bool loopback;
> +
> + if (!local_node || seq_num > 0xffffff)
> + return;
> +
> + iv_seq = iv_index << 24;
> + iv_seq |= seq_num;
> +
> + remote = node_find_by_addr(src);
> +
> + if (!remote) {
> + if (local_node->provisioner) {
> + rl_printf("Remote node unknown (%4.4x)\n", src);
> + return;
> + }
> +
> + remote = g_new0(struct mesh_node, 1);
> + if (!remote)
> + return;
> +
> + /* Not Provisioner; Assume all SRC elements stand alone */
> + remote->primary = src;
> + remote->num_ele = 1;
> + nodes = g_list_append(nodes, remote);
> + }
> +
> + loopback = (src < (local_node->primary + local_node->num_ele) &&
> + src >= local_node->primary);
> +
> + if (!loopback) {
> + iv_seq_remote = remote->iv_index << 24;
> + iv_seq |= remote->seq_number;
> +
> + if (iv_seq_remote >= iv_seq) {
> + rl_printf("Replayed message detected "
> + "(%14lx >= %14lx)\n",
> + iv_seq_remote, iv_seq);
> + return;
> + }
> + }
> +
> + if (IS_GROUP(dst) || IS_VIRTUAL(dst)) {
> + /* TODO: if subscription address, deliver to subscribers */
> + return;
> + }
> +
> + if (IS_ALL_NODES(dst)) {
> + ele_idx = 0;
> + } else {
> + if (dst >= (local_node->primary + local_node->num_ele) ||
> + dst < local_node->primary)
> + return;
> +
> + ele_idx = dst - local_node->primary;
> + }
> +
> + l = g_list_find_custom(local_node->elements,
> + GUINT_TO_POINTER(ele_idx), match_element_idx);
> +
> + /* This should not happen */
> + if (!l)
> + return;
> +
> + element = l->data;
> + res = deliver_model_data(element, src, app_idx, data, len);
> +
> + if (res && !loopback) {
> + /* TODO: Save remote in Replay Protection db */
> + remote->iv_index = iv_index;
> + remote->seq_number = seq_num;
> + prov_db_node_set_iv_seq(remote, iv_index, seq_num);
> + }
> +}
> +
> +static gboolean restore_model_state(gpointer data)
> +{
> + struct mesh_model *model = data;
> + GList *l;
> + struct mesh_model_ops *ops;
> +
> + ops = &model->cbs;
> +
> + if (model->bindings && ops->bind) {
> + for (l = model->bindings; l; l = l->next) {
> + if (ops->bind(GPOINTER_TO_UINT(l->data), ACTION_ADD) !=
> + MESH_STATUS_SUCCESS)
> + break;
> + }
> + }
> +
> + if (model->pub && ops->pub)
> + ops->pub(model->pub);
> +
> + g_idle_remove_by_data(data);
> +
> + return true;
> +
> +}
> +
> +bool node_local_model_register(uint8_t ele_idx, uint16_t model_id,
> + struct mesh_model_ops *ops, void *user_data)
> +{
> + uint32_t id = 0xffff0000 | model_id;
> +
> + return node_local_vendor_model_register(ele_idx, id, ops, user_data);
> +}
> +
> +bool node_local_vendor_model_register(uint8_t ele_idx, uint32_t model_id,
> + struct mesh_model_ops *ops, void *user_data)
> +{
> + struct mesh_element *ele;
> + struct mesh_model *model;
> + GList *l;
> +
> + if (!local_node)
> + return false;
> +
> + l = g_list_find_custom(local_node->elements, GUINT_TO_POINTER(ele_idx),
> + match_element_idx);
> + if (!l)
> + return false;
> +
> + ele = l->data;
> +
> + l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
> + match_model_id);
> + if (!l)
> + return false;
> +
> + model = l->data;
> + model->cbs = *ops;
> + model->user_data = user_data;
> +
> + if (model_id >= 0xffff0000)
> + model_id = model_id & 0xffff;
> +
> + /* Silently assign device key binding to configuration models */
> + if (model_id == CONFIG_SERVER_MODEL_ID ||
> + model_id == CONFIG_CLIENT_MODEL_ID) {
> + model->bindings = g_list_append(model->bindings,
> + GUINT_TO_POINTER(APP_IDX_DEV));
> + } else {
> + g_idle_add(restore_model_state, model);
> + }
> +
> + return true;
> +}
> +
> +bool node_set_element(struct mesh_node *node, uint8_t ele_idx)
> +{
> + struct mesh_element *ele;
> + GList *l;
> +
> + if (!node)
> + return false;
> +
> + l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
> + match_element_idx);
> + if (l)
> + return false;
> +
> + ele = g_malloc0(sizeof(struct mesh_element));
> + if (!ele)
> + return false;
> +
> + ele->index = ele_idx;
> + node->elements = g_list_append(node->elements, ele);
> +
> + return true;
> +}
> +
> +bool node_set_model(struct mesh_node *node, uint8_t ele_idx, uint32_t id)
> +{
> + struct mesh_element *ele;
> + struct mesh_model *model;
> + GList *l;
> +
> + if (!node)
> + return false;
> +
> + l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
> + match_element_idx);
> + if (!l)
> + return false;
> +
> + ele = l->data;
> +
> + l = g_list_find_custom(ele->models, GUINT_TO_POINTER(id),
> + match_model_id);
> + if (l)
> + return false;
> +
> + model = g_malloc0(sizeof(struct mesh_model));
> + if (!model)
> + return false;
> +
> + model->id = id;
> + ele->models = g_list_append(ele->models, model);
> +
> + return true;
> +}
> +
> +bool node_set_composition(struct mesh_node *node,
> + struct mesh_node_composition *comp)
> +{
> + if (!node || !comp || node->comp)
> + return false;
> +
> + node->comp = g_malloc0(sizeof(struct mesh_node_composition));
> + if (!node->comp)
> + return false;
> +
> + *(node->comp) = *comp;
> + return true;
> +}
> +
> +struct mesh_node_composition *node_get_composition(struct mesh_node *node)
> +{
> + if (!node)
> + return NULL;
> +
> + return node->comp;
> +}
> +
> +static struct mesh_model *get_model(struct mesh_node *node, uint8_t ele_idx,
> + uint32_t model_id)
> +{
> + struct mesh_element *ele;
> + GList *l;
> +
> + if (!node)
> + return NULL;
> +
> + l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
> + match_element_idx);
> + if (!l)
> + return NULL;
> +
> + ele = l->data;
> +
> + l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
> + match_model_id);
> + if (!l)
> + return NULL;
> +
> + return l->data;
> +
> +}
> +
> +bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
> + uint32_t model_id, uint16_t app_idx)
> +{
> + struct mesh_model *model;
> + GList *l;
> +
> + model = get_model(node, ele_idx, model_id);
> + if(!model)
> + return false;
> +
> + l = g_list_find(model->bindings, GUINT_TO_POINTER(app_idx));
> + if (l)
> + return false;
> +
> + if ((node == local_node) && model->cbs.bind) {
> + if (!model->cbs.bind(app_idx, ACTION_ADD))
> + return false;
> + }
> +
> + model->bindings = g_list_append(model->bindings,
> + GUINT_TO_POINTER(app_idx));
> +
> + return true;
> +}
> +
> +uint8_t node_get_default_ttl(struct mesh_node *node)
> +{
> + if (!node)
> + return DEFAULT_TTL;
> + else if (node == local_node)
> + return net_get_default_ttl();
> + else
> + return node->ttl;
> +}
> +
> +bool node_set_default_ttl(struct mesh_node *node, uint8_t ttl)
> +{
> + if (!node)
> + return false;
> +
> + node->ttl = ttl;
> +
> + if (node == local_node || local_node == NULL)
> + return net_set_default_ttl(ttl);
> +
> + return true;
> +}
> +
> +bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
> +{
> + if (!node)
> + return false;
> +
> + node->seq_number = seq;
> +
> + if (node == local_node || local_node == NULL)
> + return net_set_seq_num(seq);
> +
> + return true;
> +}
> +
> +uint32_t node_get_sequence_number(struct mesh_node *node)
> +{
> + if (!node)
> + return 0xffffffff;
> + else if (node == local_node)
> + return net_get_seq_num();
> +
> + return node->seq_number;
> +}
> +
> +bool node_set_iv_index(struct mesh_node *node, uint32_t iv_index)
> +{
> + if (!node)
> + return false;
> +
> + node->iv_index = iv_index;
> + return true;
> +}
> +
> +uint32_t node_get_iv_index(struct mesh_node *node)
> +{
> + bool update;
> +
> + if (!node)
> + return 0xffffffff;
> + else if (node == local_node)
> + return net_get_iv_index(&update);
> + return node->iv_index;
> +}
> +
> +bool node_model_pub_set(struct mesh_node *node, uint8_t ele, uint32_t model_id,
> + struct mesh_publication *pub)
> +{
> + struct mesh_model *model;
> +
> + model = get_model(node, ele, model_id);
> + if(!model)
> + return false;
> +
> + if (!model->pub)
> + model->pub = g_malloc0(sizeof(struct mesh_publication));
> + if (!model)
> + return false;
> +
> + memcpy(model->pub, pub, (sizeof(struct mesh_publication)));
> +
> + if((node == local_node) && model->cbs.pub)
> + model->cbs.pub(pub);
> + return true;
> +}
> +
> +struct mesh_publication *node_model_pub_get(struct mesh_node *node, uint8_t ele,
> + uint32_t model_id)
> +{
> + struct mesh_model *model;
> +
> + model = get_model(node, ele, model_id);
> + if(!model)
> + return NULL;
> + else
> + return model->pub;
> +}
> diff --git a/mesh/onoff-model.c b/mesh/onoff-model.c
> new file mode 100644
> index 0000000..61c6ed6
> --- /dev/null
> +++ b/mesh/onoff-model.c
> @@ -0,0 +1,306 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <stdbool.h>
> +#include <sys/uio.h>
> +#include <wordexp.h>
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "client/display.h"
> +#include "src/shared/util.h"
> +#include "mesh-net.h"
> +#include "keys.h"
> +#include "net.h"
> +#include "node.h"
> +#include "prov-db.h"
> +#include "util.h"
> +#include "onoff-model.h"
> +
> +static uint8_t trans_id;
> +static uint16_t onoff_app_idx = APP_IDX_INVALID;
> +
> +static int client_bind(uint16_t app_idx, int action)
> +{
> + if (action == ACTION_ADD) {
> + if (onoff_app_idx != APP_IDX_INVALID) {
> + return MESH_STATUS_INSUFF_RESOURCES;
> + } else {
> + onoff_app_idx = app_idx;
> + rl_printf("On/Off client model: new binding %4.4x\n",
> + app_idx);
> + }
> + } else {
> + if (onoff_app_idx == app_idx)
> + onoff_app_idx = APP_IDX_INVALID;
> + }
> + return MESH_STATUS_SUCCESS;
> +}
> +
> +static void print_remaining_time(uint8_t remaining_time)
> +{
> + uint8_t step = (remaining_time & 0xc0) >> 6;
> + uint8_t count = remaining_time & 0x3f;
> + int secs = 0, msecs = 0, minutes = 0, hours = 0;
> +
> + switch (step) {
> + case 0:
> + msecs = 100 * count;
> + secs = msecs / 60;
> + msecs -= (secs * 60);
> + break;
> + case 1:
> + secs = 1 * count;
> + minutes = secs / 60;
> + secs -= (minutes * 60);
> + break;
> +
> + case 2:
> + secs = 10 * count;
> + minutes = secs / 60;
> + secs -= (minutes * 60);
> + break;
> + case 3:
> + minutes = 10 * count;
> + hours = minutes / 60;
> + minutes -= (hours * 60);
> + break;
> +
> + default:
> + break;
> + }
> +
> + rl_printf("\n\t\tRemaining time: %d hrs %d mins %d secs %d msecs\n",
> + hours, minutes, secs, msecs);
> +
> +}
> +
> +static bool client_msg_recvd(uint16_t src, uint8_t *data,
> + uint16_t len, void *user_data)
> +{
> + uint32_t opcode;
> + int n;
> +
> + if (mesh_opcode_get(data, len, &opcode, &n)) {
> + len -= n;
> + data += n;
> + } else
> + return false;
> +
> + rl_printf("On Off Model Message received (%d) opcode %x\n",
> + len, opcode);
> + print_byte_array("\t",data, len);
> +
> + switch (opcode & ~OP_UNRELIABLE) {
> + default:
> + return false;
> +
> + case OP_GENERIC_ONOFF_STATUS:
> + if (len != 1 && len != 3)
> + break;
> +
> + rl_printf("Node %4.4x: Off Status present = %s",
> + src, data[0] ? "ON" : "OFF");
> +
> + if (len == 3) {
> + rl_printf(", target = %s", data[1] ? "ON" : "OFF");
> + print_remaining_time(data[2]);
> + } else
> + rl_printf("\n");
> + break;
> + }
> +
> + return true;
> +}
> +
> +
> +static uint32_t target;
> +static uint32_t parms[8];
> +
> +static uint32_t read_input_parameters(const char *args)
> +{
> + uint32_t i;
> +
> + if (!args)
> + return 0;
> +
> + memset(parms, 0xff, sizeof(parms));
> +
> + for (i = 0; i < sizeof(parms)/sizeof(parms[0]); i++) {
> + int n;
> +
> + sscanf(args, "%x", &parms[i]);
> + if (parms[i] == 0xffffffff)
> + break;
> +
> + n = strcspn(args, " \t");
> + args = args + n + strspn(args + n, " \t");
> + }
> +
> + return i;
> +}
> +
> +static void cmd_set_node(const char *args)
> +{
> + uint32_t dst;
> + char *end;
> +
> + dst = strtol(args, &end, 16);
> + if (end != (args + 4)) {
> + rl_printf("Bad unicast address %s: "
> + "expected format 4 digit hex\n",
> + args);
> + target = UNASSIGNED_ADDRESS;
> + } else {
> + rl_printf("Controlling ON/OFF for node %4.4x\n", dst);
> + target = dst;
> + set_menu_prompt("on/off", args);
> + }
> +}
> +
> +static bool send_cmd(uint8_t *buf, uint16_t len)
> +{
> + struct mesh_node *node = node_get_local_node();
> + uint8_t ttl;
> +
> + if(!node)
> + return false;
> +
> + ttl = node_get_default_ttl(node);
> +
> + return net_access_layer_send(ttl, node_get_primary(node),
> + target, onoff_app_idx, buf, len);
> +}
> +
> +static void cmd_get_status(const char *args)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + struct mesh_node *node;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + node = node_find_by_addr(target);
> +
> + if (!node)
> + return;
> +
> + n = mesh_opcode_set(OP_GENERIC_ONOFF_GET, msg);
> +
> + if (!send_cmd(msg, n))
> + rl_printf("Failed to send \"GENERIC ON/OFF GET\"\n");
> +}
> +
> +static void cmd_set(const char *args)
> +{
> + uint16_t n;
> + uint8_t msg[32];
> + struct mesh_node *node;
> +
> + if (IS_UNASSIGNED(target)) {
> + rl_printf("Destination not set\n");
> + return;
> + }
> +
> + node = node_find_by_addr(target);
> +
> + if (!node)
> + return;
> +
> + if ((read_input_parameters(args) != 1) &&
> + parms[0] != 0 && parms[0] != 1) {
> + rl_printf("Bad arguments %s. Expecting \"0\" or \"1\"\n", args);
> + return;
> + }
> +
> + n = mesh_opcode_set(OP_GENERIC_ONOFF_SET, msg);
> + msg[n++] = parms[0];
> + msg[n++] = trans_id++;
> +
> + if (!send_cmd(msg, n))
> + rl_printf("Failed to send \"GENERIC ON/OFF SET\"\n");
> +
> +}
> +
> +static void cmd_back(const char *args)
> +{
> + cmd_menu_main(false);
> +}
> +
> +static void cmd_help(const char *args);
> +
> +static const struct menu_entry cfg_menu[] = {
> + {"target", "<unicast>", cmd_set_node,
> + "Set node to configure"},
> + {"get", NULL, cmd_get_status,
> + "Get ON/OFF status"},
> + {"onoff", "<0/1>", cmd_set,
> + "Send \"SET ON/OFF\" command"},
> + {"back", NULL, cmd_back,
> + "Back to main menu"},
> + {"help", NULL, cmd_help,
> + "Config Commands"},
> + {}
> +};
> +
> +static void cmd_help(const char *args)
> +{
> + rl_printf("Client Configuration Menu\n");
> + print_cmd_menu(cfg_menu);
> +}
> +
> +void onoff_set_node(const char *args) {
> + cmd_set_node(args);
> +}
> +
> +static struct mesh_model_ops client_cbs = {
> + client_msg_recvd,
> + client_bind,
> + NULL,
> + NULL
> +};
> +
> +bool onoff_client_init(uint8_t ele)
> +{
> + if (!node_local_model_register(ele, GENERIC_ONOFF_CLIENT_MODEL_ID,
> + &client_cbs, NULL))
> + return false;
> +
> + add_cmd_menu("onoff", cfg_menu);
> +
> + return true;
> +}
> diff --git a/mesh/prov-db.c b/mesh/prov-db.c
> new file mode 100644
> index 0000000..aad6145
> --- /dev/null
> +++ b/mesh/prov-db.c
> @@ -0,0 +1,1599 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <glib.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <json-c/json.h>
> +#include <sys/stat.h>
> +
> +#include <readline/readline.h>
> +#include <glib.h>
> +
> +#include "src/shared/util.h"
> +#include "client/display.h"
> +
> +#include "mesh-net.h"
> +#include "crypto.h"
> +#include "keys.h"
> +#include "net.h"
> +#include "node.h"
> +#include "util.h"
> +#include "prov-db.h"
> +
> +#define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
> +
> +static const char *prov_filename;
> +static const char *local_filename;
> +
> +static char* prov_file_read(const char *filename)
> +{
> + int fd;
> + char *str;
> + struct stat st;
> + ssize_t sz;
> +
> + if (!filename)
> + return NULL;
> +
> + fd = open(filename,O_RDONLY);
> + if (!fd)
> + return NULL;
> +
> + if (fstat(fd, &st) == -1) {
> + close(fd);
> + return NULL;
> + }
> +
> + str = (char *) g_malloc0(st.st_size + 1);
> + if (!str) {
> + close(fd);
> + return NULL;
> + }
> +
> + sz = read(fd, str, st.st_size);
> + if (sz != st.st_size)
> + rl_printf("Incomplete read: %d vs %d\n", (int)sz,
> + (int)(st.st_size));
> +
> + close(fd);
> +
> + return str;
> +}
> +
> +static void prov_file_write(json_object *jmain, bool local)
> +{
> + FILE *outfile;
> + const char *out_str;
> + const char *out_filename;
> +
> + if (local)
> + out_filename = local_filename;
> + else
> + out_filename = prov_filename;
> +
> + outfile = fopen(out_filename, "wr");
> + if (!outfile) {
> + rl_printf("Failed to open file %s for writing\n", out_filename);
> + return;
> + }
> +
> + out_str = json_object_to_json_string_ext(jmain,
> + JSON_C_TO_STRING_PRETTY);
> +
> + fwrite(out_str, sizeof(char), strlen(out_str), outfile);
> + fclose(outfile);
> +}
> +
> +static void put_uint16(json_object *jobject, const char *desc, uint16_t value)
> +{
> + json_object *jstring;
> + char buf[5];
> +
> + snprintf(buf, 5, "%4.4x", value);
> + jstring = json_object_new_string(buf);
> + json_object_object_add(jobject, desc, jstring);
> +}
> +
> +static void put_uint32(json_object *jobject, const char *desc, uint32_t value)
> +{
> + json_object *jstring;
> + char buf[9];
> +
> + snprintf(buf, 9, "%8.8x", value);
> + jstring = json_object_new_string(buf);
> + json_object_object_add(jobject, desc, jstring);
> +}
> +
> +static void put_uint16_array_entry(json_object *jarray, uint16_t value)
> +{
> + json_object *jstring;
> + char buf[5];
> +
> + snprintf(buf, 5, "%4.4x", value);
> + jstring = json_object_new_string(buf);
> + json_object_array_add(jarray, jstring);
> +}
> +
> +static void put_uint32_array_entry(json_object *jarray, uint32_t value)
> +{
> + json_object *jstring;
> + char buf[9];
> +
> + snprintf(buf, 9, "%8.8x", value);
> + jstring = json_object_new_string(buf);
> + json_object_array_add(jarray, jstring);
> +}
> +
> +static void put_uint16_list(json_object *jarray, GList *list)
> +{
> + GList *l;
> +
> + if (!list)
> + return;
> +
> + for (l = list; l; l = l->next) {
> + uint32_t ivalue = GPOINTER_TO_UINT(l->data);
> + put_uint16_array_entry(jarray, ivalue);
> + }
> +}
> +
> +static void add_node_idxs(json_object *jnode, const char *desc,
> + GList *idxs)
> +{
> + json_object *jarray;
> +
> + jarray = json_object_new_array();
> +
> + put_uint16_list(jarray, idxs);
> +
> + json_object_object_add(jnode, desc, jarray);
> +}
> +
> +static bool parse_unicast_range(json_object *jobject)
> +{
> + int cnt;
> + int i;
> +
> + cnt = json_object_array_length(jobject);
> +
> + for (i = 0; i < cnt; ++i) {
> + json_object *jrange;
> + json_object *jvalue;
> + uint16_t low, high;
> + char *str;
> +
> + jrange = json_object_array_get_idx(jobject, i);
> + json_object_object_get_ex(jrange, "lowAddress", &jvalue);
> + str = (char *)json_object_get_string(jvalue);
> + if (sscanf(str, "%04hx", &low) != 1)
> + return false;
> +
> + json_object_object_get_ex(jrange, "highAddress", &jvalue);
> + str = (char *)json_object_get_string(jvalue);
> + if (sscanf(str, "%04hx", &high) != 1)
> + return false;
> +
> + if(high < low)
> + return false;
> +
> + net_add_address_pool(low, high);
> + }
> + return true;
> +}
> +
> +static int parse_node_keys(struct mesh_node *node, json_object *jidxs,
> + bool is_app_key)
> +{
> + int idx_cnt;
> + int i;
> +
> + idx_cnt = json_object_array_length(jidxs);
> + for (i = 0; i < idx_cnt; ++i) {
> + int idx;
> + json_object *jvalue;
> +
> + jvalue = json_object_array_get_idx(jidxs, i);
> + if (!jvalue)
> + break;
> + idx = json_object_get_int(jvalue);
> + if (!CHECK_KEY_IDX_RANGE(idx))
> + break;
> +
> + if (is_app_key)
> + node_app_key_add(node, idx);
> + else
> + node_net_key_add(node, idx);
> + }
> +
> + return i;
> +}
> +
> +static bool parse_composition_models(struct mesh_node *node, int index,
> + json_object *jmodels)
> +{
> + int model_cnt;
> + int i;
> +
> + model_cnt = json_object_array_length(jmodels);
> +
> + for (i = 0; i < model_cnt; ++i) {
> + json_object *jmodel;
> + char *str;
> + uint32_t model_id;
> + int len;
> +
> + jmodel = json_object_array_get_idx(jmodels, i);
> + str = (char *)json_object_get_string(jmodel);
> + len = strlen(str);
> +
> + if (len != 4 && len != 8)
> + return false;
> +
> + if (sscanf(str, "%08x", &model_id) != 1)
> + return false;
> + if (len == 4)
> + model_id += 0xffff0000;
> +
> + node_set_model(node, index, model_id);
> + }
> +
> + return true;
> +}
> +
> +static bool parse_composition_elements(struct mesh_node *node,
> + json_object *jelements)
> +{
> + int el_cnt;
> + int i;
> +
> + el_cnt = json_object_array_length(jelements);
> + node_set_num_elements(node, el_cnt);
> +
> + for (i = 0; i < el_cnt; ++i) {
> + json_object *jelement;
> + json_object *jmodels;
> + json_object *jvalue;
> + int index;
> +
> + jelement = json_object_array_get_idx(jelements, i);
> + json_object_object_get_ex(jelement, "elementIndex", &jvalue);
> + if (jvalue) {
> + index = json_object_get_int(jvalue);
> + if (index >= el_cnt) {
> + return false;
> + }
> + } else
> + return false;
> +
> + if (!node_set_element(node, index))
> + return false;
> +
> + json_object_object_get_ex(jelement, "models", &jmodels);
> + if (!jmodels)
> + continue;
> +
> + if(!parse_composition_models(node, index, jmodels))
> + return false;
> + }
> + return true;
> +}
> +
> +static bool parse_model_pub(struct mesh_node *node, int ele_idx,
> + uint32_t model_id, json_object *jpub)
> +{
> + json_object *jvalue;
> + struct mesh_publication pub;
> + char *str;
> +
> + memset(&pub, 0, sizeof(struct mesh_publication));
> +
> + /* Read only required fields */
> + json_object_object_get_ex(jpub, "address", &jvalue);
> + if (!jvalue)
> + return false;
> +
> + str = (char *)json_object_get_string(jvalue);
> + if (sscanf(str, "%04hx", &pub.u.addr16) != 1)
> + return false;
> +
> + json_object_object_get_ex(jpub, "index", &jvalue);
> + if (!jvalue)
> + return false;
> +
> + str = (char *)json_object_get_string(jvalue);
> + if (sscanf(str, "%04hx", &pub.app_idx) != 1)
> + return false;
> +
> +
> + json_object_object_get_ex(jpub, "ttl", &jvalue);
> + pub.ttl = json_object_get_int(jvalue);
> +
> + if (!node_model_pub_set(node, ele_idx, model_id, &pub))
> + return false;
> +
> + return true;
> +}
> +
> +static bool parse_bindings(struct mesh_node *node, int ele_idx,
> + uint32_t model_id, json_object *jbindings)
> +{
> + int cnt;
> + int i;
> +
> + cnt = json_object_array_length(jbindings);
> +
> + for (i = 0; i < cnt; ++i) {
> + int key_idx;
> + json_object *jvalue;
> +
> + jvalue = json_object_array_get_idx(jbindings, i);
> + if (!jvalue)
> + return true;
> +
> + key_idx = json_object_get_int(jvalue);
> + if (!CHECK_KEY_IDX_RANGE(key_idx))
> + return false;
> +
> + if (!node_add_binding(node, ele_idx, model_id, key_idx))
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool parse_configuration_models(struct mesh_node *node, int ele_idx,
> + json_object *jmodels, uint32_t target_id, json_object **jtarget)
> +{
> + int model_cnt;
> + int i;
> +
> + if (jtarget)
> + *jtarget = NULL;
> +
> + model_cnt = json_object_array_length(jmodels);
> +
> + for (i = 0; i < model_cnt; ++i) {
> + json_object *jmodel;
> + json_object *jvalue;
> + json_object *jarray;
> + char *str;
> + int len;
> + uint32_t model_id;
> +
> + jmodel = json_object_array_get_idx(jmodels, i);
> +
> + json_object_object_get_ex(jmodel, "modelId", &jvalue);
> + str = (char *)json_object_get_string(jvalue);
> +
> + len = strlen(str);
> +
> + if (len != 4 && len != 8)
> + return false;
> +
> + if (sscanf(str, "%08x", &model_id) != 1)
> + return false;
> + if (len == 4)
> + model_id += 0xffff0000;
> +
> + if (jtarget && model_id == target_id) {
> + *jtarget = jmodel;
> + return true;
> + }
> +
> + json_object_object_get_ex(jmodel, "bind", &jarray);
> + if (jarray && !parse_bindings(node, ele_idx, model_id, jarray))
> + return false;
> +
> + json_object_object_get_ex(jmodel, "publish", &jvalue);
> +
> + if (jvalue && !parse_model_pub(node, ele_idx, model_id, jvalue))
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool parse_configuration_elements(struct mesh_node *node,
> + json_object *jelements, bool local)
> +{
> + int el_cnt;
> + int i;
> +
> + el_cnt = json_object_array_length(jelements);
> + node_set_num_elements(node, el_cnt);
> +
> + for (i = 0; i < el_cnt; ++i) {
> + json_object *jelement;
> + json_object *jmodels;
> + json_object *jvalue;
> + int index;
> + uint16_t addr;
> +
> + jelement = json_object_array_get_idx(jelements, i);
> + json_object_object_get_ex(jelement, "elementIndex", &jvalue);
> + if (jvalue) {
> + index = json_object_get_int(jvalue);
> + if (index >= el_cnt) {
> + return false;
> + }
> + } else
> + return false;
> +
> + if (index == 0) {
> + char *str;
> +
> + json_object_object_get_ex(jelement, "unicastAddress",
> + &jvalue);
> + str = (char *)json_object_get_string(jvalue);
> + if (sscanf(str, "%04hx", &addr) != 1)
> + return false;
> +
> + if (!local && !net_reserve_address_range(addr, el_cnt))
> + return false;
> +
> + node_set_primary(node, addr);
> + }
> +
> + json_object_object_get_ex(jelement, "models", &jmodels);
> + if (!jmodels)
> + continue;
> +
> + if(!parse_configuration_models(node, index, jmodels, 0, NULL))
> + return false;
> + }
> + return true;
> +}
> +
> +static void add_key(json_object *jobject, const char *desc, uint8_t* key)
> +{
> + json_object *jstring;
> + char hexstr[33];
> +
> + hex2str(key, 16, hexstr, 33);
> + jstring = json_object_new_string(hexstr);
> + json_object_object_add(jobject, desc, jstring);
> +}
> +
> +static json_object *find_node_by_primary(json_object *jmain, uint16_t primary)
> +{
> + json_object *jarray;
> + int i, len;
> +
> + json_object_object_get_ex(jmain, "nodes", &jarray);
> +
> + if (!jarray)
> + return NULL;
> + len = json_object_array_length(jarray);
> +
> + for (i = 0; i < len; ++i) {
> + json_object *jnode;
> + json_object *jconfig;
> + json_object *jelements;
> + json_object *jelement;
> + json_object *jvalue;
> + char *str;
> + uint16_t addr;
> +
> + jnode = json_object_array_get_idx(jarray, i);
> + if (!jnode)
> + return NULL;
> +
> + json_object_object_get_ex(jnode, "configuration", &jconfig);
> + if (!jconfig)
> + return NULL;
> +
> + json_object_object_get_ex(jconfig, "elements", &jelements);
> + if (!jelements)
> + return NULL;
> +
> + jelement = json_object_array_get_idx(jelements, 0);
> + if (!jelement)
> + return NULL;
> +
> + json_object_object_get_ex(jelement, "unicastAddress",
> + &jvalue);
> + str = (char *)json_object_get_string(jvalue);
> + if (sscanf(str, "%04hx", &addr) != 1)
> + return NULL;
> +
> + if (addr == primary)
> + return jnode;
> + }
> +
> + return NULL;
> +
> +}
> +
> +void prov_db_print_node_composition(struct mesh_node *node)
> +{
> + char *in_str;
> + const char *comp_str;
> + json_object *jmain;
> + json_object *jnode;
> + json_object *jcomp;
> + uint16_t primary = node_get_primary(node);
> + const char *filename;
> + bool res = false;
> +
> + if (!node || !node_get_composition(node))
> + return;
> +
> + if (node == node_get_local_node())
> + filename = local_filename;
> + else
> + filename = prov_filename;
> +
> + in_str = prov_file_read(filename);
> + if (!in_str)
> + return;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + jnode = find_node_by_primary(jmain, primary);
> + if (!jnode)
> + goto done;
> +
> + json_object_object_get_ex(jnode, "composition", &jcomp);
> + if (!jcomp)
> + goto done;
> +
> + comp_str = json_object_to_json_string_ext(jcomp,
> + JSON_C_TO_STRING_PRETTY);
> +
> + res = true;
> +
> +done:
> + if (res)
> + rl_printf("\tComposition data for node %4.4x %s\n",
> + primary, comp_str);
> + else
> + rl_printf("\tComposition data for node %4.4x not present\n",
> + primary);
> + g_free(in_str);
> +
> + if (jmain)
> + json_object_put(jmain);
> +}
> +
> +bool prov_db_add_node_composition(struct mesh_node *node, uint8_t *data,
> + uint16_t len)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jnode;
> + json_object *jcomp;
> + json_object *jbool;
> + json_object *jfeatures;
> + json_object *jelements;
> + struct mesh_node_composition *comp;
> + uint8_t num_ele;
> + int i;
> + uint16_t primary = node_get_primary(node);
> + bool res = NULL;
> +
> + comp = node_get_composition(node);
> + if (!comp)
> + return false;
> +
> + in_str = prov_file_read(prov_filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + jnode = find_node_by_primary(jmain, primary);
> + if (!jnode)
> + goto done;
> +
> + jcomp = json_object_new_object();
> +
> + put_uint16(jcomp, "cid", comp->cid);
> + put_uint16(jcomp, "pid", comp->pid);
> + put_uint16(jcomp, "vid", comp->pid);
> + put_uint16(jcomp, "crpl", comp->crpl);
> +
> + jfeatures = json_object_new_object();
> + jbool = json_object_new_boolean(comp->relay);
> + json_object_object_add(jfeatures, "relay", jbool);
> + jbool = json_object_new_boolean(comp->proxy);
> + json_object_object_add(jfeatures, "proxy", jbool);
> + jbool = json_object_new_boolean(comp->friend);
> + json_object_object_add(jfeatures, "friend", jbool);
> + jbool = json_object_new_boolean(comp->lpn);
> + json_object_object_add(jfeatures, "lpn", jbool);
> + json_object_object_add(jcomp, "features", jfeatures);
> +
> + data += 11;
> + len -= 11;
> +
> + num_ele = node_get_num_elements(node);
> +
> + jelements = json_object_new_array();
> +
> + for (i = 0; i < num_ele; ++i) {
> + json_object *jelement;
> + json_object *jmodels;
> + json_object *jint;
> + uint32_t mod_id;
> + uint16_t vendor_id;
> + uint8_t m, v;
> +
> + jelement = json_object_new_object();
> +
> + /* Element Index */
> + jint = json_object_new_int(i);
> + json_object_object_add(jelement, "elementIndex", jint);
> +
> + /* Location */
> + put_uint16(jelement, "location", get_le16(data));
> + data += 2;
> + m = *data++;
> + v = *data++;
> + len -= 4;
> +
> + /* Models */
> + jmodels = json_object_new_array();
> + while (len >= 2 && m--) {
> + mod_id = get_le16(data);
> + data += 2;
> + len -= 2;
> + put_uint16_array_entry(jmodels, (uint16_t) mod_id);
> + }
> +
> + while (len >= 4 && v--) {
> + mod_id = get_le16(data);
> + vendor_id = get_le16(data);
> + mod_id |= (vendor_id << 16);
> + data += 4;
> + len -= 4;
> + put_uint32_array_entry(jmodels, mod_id);
> + }
> +
> + json_object_object_add(jelement, "models", jmodels);
> + json_object_array_add(jelements, jelement);
> + }
> +
> + json_object_object_add(jcomp, "elements", jelements);
> +
> + json_object_object_add(jnode, "composition", jcomp);
> +
> + prov_file_write(jmain, false);
> +
> + res = true;;
> +done:
> +
> + g_free(in_str);
> +
> + if(jmain)
> + json_object_put(jmain);
> +
> + return res;
> +}
> +
> +bool prov_db_node_set_ttl(struct mesh_node *node, uint8_t ttl)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jnode;
> + json_object *jconfig;
> + json_object *jvalue;
> + uint16_t primary = node_get_primary(node);
> + const char *filename;
> + bool local = node == node_get_local_node();
> + bool res = false;
> +
> + if (local)
> + filename = local_filename;
> + else
> + filename = prov_filename;
> +
> + in_str = prov_file_read(filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + if (local)
> + json_object_object_get_ex(jmain, "node", &jnode);
> + else
> + jnode = find_node_by_primary(jmain, primary);
> +
> + if (!jnode)
> + goto done;
> +
> + json_object_object_get_ex(jnode, "configuration", &jconfig);
> + if (!jconfig)
> + goto done;
> +
> + json_object_object_del(jconfig, "defaultTTL");
> +
> + jvalue = json_object_new_int(ttl);
> + json_object_object_add(jconfig, "defaultTTL", jvalue);
> +
> + prov_file_write(jmain, local);
> +
> + res = true;
> +done:
> +
> + g_free(in_str);
> +
> + if(jmain)
> + json_object_put(jmain);
> +
> + return res;
> +
> +}
> +
> +static void set_local_iv_index(json_object *jobj, uint32_t idx, bool update)
> +{
> + json_object *jvalue;
> +
> + json_object_object_del(jobj, "IVindex");
> + jvalue = json_object_new_int(idx);
> + json_object_object_add(jobj, "IVindex", jvalue);
> +
> + json_object_object_del(jobj, "IVupdate");
> + jvalue = json_object_new_int((update) ? 1 : 0);
> + json_object_object_add(jobj, "IVupdate", jvalue);
> +
> +}
> +
> +bool prov_db_local_set_iv_index(uint32_t iv_index, bool update, bool prov)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jnode;
> + bool res = false;
> +
> + in_str = prov_file_read(local_filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + json_object_object_get_ex(jmain, "node", &jnode);
> + set_local_iv_index(jnode, iv_index, update);
> + prov_file_write(jmain, true);
> +
> + g_free(in_str);
> + json_object_put(jmain);
> +
> + /* If provisioner, save to global DB as well */
> + if (prov) {
> + in_str = prov_file_read(prov_filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + set_local_iv_index(jmain, iv_index, update);
> + prov_file_write(jmain, false);
> + }
> +
> + res = true;
> +done:
> +
> + g_free(in_str);
> +
> + if(jmain)
> + json_object_put(jmain);
> +
> + return res;
> +
> +}
> +
> +bool prov_db_local_set_seq_num(uint32_t seq_num)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jnode;
> + json_object *jvalue;
> + bool res = false;
> +
> + in_str = prov_file_read(local_filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + json_object_object_get_ex(jmain, "node", &jnode);
> +
> + json_object_object_del(jnode, "sequenceNumber");
> + jvalue = json_object_new_int(seq_num);
> + json_object_object_add(jnode, "sequenceNumber", jvalue);
> +
> + prov_file_write(jmain, true);
> +
> + res = true;
> +done:
> +
> + g_free(in_str);
> +
> + if(jmain)
> + json_object_put(jmain);
> +
> + return res;
> +}
> +
> +bool prov_db_node_set_iv_seq(struct mesh_node *node, uint32_t iv, uint32_t seq)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jnode;
> + json_object *jvalue;
> + uint16_t primary = node_get_primary(node);
> + bool res = false;
> +
> + in_str = prov_file_read(prov_filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + jnode = find_node_by_primary(jmain, primary);
> + if (!jnode)
> + goto done;
> +
> + json_object_object_del(jnode, "IVindex");
> +
> + jvalue = json_object_new_int(iv);
> + json_object_object_add(jnode, "IVindex", jvalue);
> +
> + json_object_object_del(jnode, "sequenceNumber");
> +
> + jvalue = json_object_new_int(seq);
> + json_object_object_add(jnode, "sequenceNumber", jvalue);
> +
> + prov_file_write(jmain, false);
> +
> + res = true;
> +done:
> +
> + g_free(in_str);
> +
> + if(jmain)
> + json_object_put(jmain);
> +
> + return res;
> +
> +}
> +
> +bool prov_db_node_keys(struct mesh_node *node, GList *idxs, const char *desc)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jnode;
> + json_object *jconfig;
> + json_object *jidxs;
> + uint16_t primary = node_get_primary(node);
> + const char *filename;
> + bool local = (node == node_get_local_node());
> + bool res = false;
> +
> + if (local)
> + filename = local_filename;
> + else
> + filename = prov_filename;
> +
> + in_str = prov_file_read(filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> +
> + jnode = find_node_by_primary(jmain, primary);
> + if (!jnode)
> + goto done;
> +
> + json_object_object_get_ex(jnode, "configuration", &jconfig);
> + if (!jconfig)
> + goto done;
> +
> + json_object_object_del(jconfig, desc);
> +
> + if (idxs) {
> + jidxs = json_object_new_array();
> + put_uint16_list(jidxs, idxs);
> + json_object_object_add(jconfig, desc, jidxs);
> + }
> +
> + prov_file_write(jmain, local);
> +
> + res = true;
> +done:
> +
> + g_free(in_str);
> +
> + if(jmain)
> + json_object_put(jmain);
> +
> + return res;
> +
> +}
> +
> +static json_object *get_jmodel_obj(struct mesh_node *node, uint8_t ele_idx,
> + uint32_t model_id, json_object **jmain)
> +{
> + char *in_str;
> + json_object *jnode;
> + json_object *jconfig;
> + json_object *jelements, *jelement;
> + json_object *jmodels, *jmodel = NULL;
> + uint16_t primary = node_get_primary(node);
> + const char *filename;
> + bool local = (node == node_get_local_node());
> +
> + if (local)
> + filename = local_filename;
> + else
> + filename = prov_filename;
> +
> + in_str = prov_file_read(filename);
> + if (!in_str)
> + return NULL;
> +
> + *jmain = json_tokener_parse(in_str);
> + if (!(*jmain))
> + goto done;
> +
> + if (local)
> + json_object_object_get_ex(*jmain, "node", &jnode);
> + else
> + jnode = find_node_by_primary(*jmain, primary);
> +
> + if (!jnode)
> + goto done;
> +
> + /* Configuration is mandatory for nodes in provisioning database */
> + json_object_object_get_ex(jnode, "configuration", &jconfig);
> + if (!jconfig)
> + goto done;
> +
> + json_object_object_get_ex(jconfig, "elements", &jelements);
> + if (!jelements) {
> + goto done;
> + }
> +
> + jelement = json_object_array_get_idx(jelements, ele_idx);
> + if (!jelement) {
> + goto done;
> + }
> +
> + json_object_object_get_ex(jelement, "models", &jmodels);
> +
> + if (!jmodels) {
> + jmodels = json_object_new_array();
> + json_object_object_add(jelement, "models", jmodels);
> + } else {
> + parse_configuration_models(node, ele_idx, jmodels,
> + model_id, &jmodel);
> + }
> +
> + if (!jmodel) {
> + jmodel = json_object_new_object();
> +
> + if ((model_id & 0xffff0000) == 0xffff0000)
> + put_uint16(jmodel, "modelId", model_id & 0xffff);
> + else
> + put_uint32(jmodel, "modelId", model_id);
> +
> + json_object_array_add(jmodels, jmodel);
> + }
> +
> +done:
> +
> + g_free(in_str);
> +
> + if(!jmodel && *jmain)
> + json_object_put(*jmain);
> +
> + return jmodel;
> +
> +}
> +
> +bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx,
> + uint32_t model_id, uint16_t app_idx)
> +{
> + json_object *jmain;
> + json_object *jmodel;
> + json_object *jvalue;
> + json_object *jbindings = NULL;
> + bool local = (node == node_get_local_node());
> +
> + jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
> +
> + if (!jmodel)
> + return false;
> +
> + json_object_object_get_ex(jmodel, "bind", &jbindings);
> +
> + if (!jbindings) {
> + jbindings = json_object_new_array();
> + json_object_object_add(jmodel, "bind", jbindings);
> + }
> +
> + jvalue = json_object_new_int(app_idx);
> + json_object_array_add(jbindings, jvalue);
> +
> + prov_file_write(jmain, local);
> +
> + json_object_put(jmain);
> +
> + return true;
> +}
> +
> +bool prov_db_node_set_model_pub(struct mesh_node *node, uint8_t ele_idx,
> + uint32_t model_id,
> + struct mesh_publication *pub)
> +{
> + json_object *jmain;
> + json_object *jmodel;
> + json_object *jpub;
> + json_object *jvalue;
> + bool local = (node == node_get_local_node());
> +
> + jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
> +
> + if (!jmodel)
> + return false;
> +
> + json_object_object_del(jmodel, "publish");
> + if (!pub)
> + goto done;
> +
> + jpub = json_object_new_object();
> +
> + /* Save only required fields */
> + put_uint16(jpub, "address", pub->u.addr16);
> + put_uint16(jpub, "index", pub->app_idx);
> + jvalue = json_object_new_int(pub->ttl);
> + json_object_object_add(jpub, "ttl", jvalue);
> +
> + json_object_object_add(jmodel, "publish", jpub);
> +
> +done:
> + prov_file_write(jmain, local);
> +
> + json_object_put(jmain);
> +
> + return true;
> +}
> +
> +bool prov_db_add_new_node(struct mesh_node *node)
> +{
> + char *in_str;
> + json_object *jmain;
> + json_object *jarray;
> + json_object *jnode;
> + json_object *jconfig;
> + json_object *jelements;
> + uint8_t num_ele;
> + uint16_t primary;
> + int i;
> + bool first_node;
> + bool res = false;
> +
> + in_str = prov_file_read(prov_filename);
> + if (!in_str)
> + return false;
> +
> + jmain = json_tokener_parse(in_str);
> + if (!jmain)
> + goto done;
> + json_object_object_get_ex(jmain, "nodes", &jarray);
> +
> + if (!jarray) {
> + jarray = json_object_new_array();
> + first_node = true;
> + } else
> + first_node = false;
> +
> + jnode = json_object_new_object();
> +
> + /* Device key */
> + add_key(jnode, "deviceKey", node_get_device_key(node));
> +
> + /* Net key */
> + jconfig = json_object_new_object();
> + add_node_idxs(jconfig, "netKeys", node_get_net_keys(node));
> +
> + num_ele = node_get_num_elements(node);
> + if (num_ele == 0)
> + goto done;
> +
> + jelements = json_object_new_array();
> +
> + primary = node_get_primary(node);
> + if (IS_UNASSIGNED(primary))
> + goto done;
> +
> + for (i = 0; i < num_ele; ++i) {
> + json_object *jelement;
> + json_object *jint;
> +
> + jelement = json_object_new_object();
> +
> + /* Element Index */
> + jint = json_object_new_int(i);
> + json_object_object_add(jelement, "elementIndex", jint);
> +
> + /* Unicast */
> + put_uint16(jelement, "unicastAddress", primary + i);
> +
> + json_object_array_add(jelements, jelement);
> + }
> +
> + json_object_object_add(jconfig, "elements", jelements);
> +
> + json_object_object_add(jnode, "configuration", jconfig);
> +
> + json_object_array_add(jarray, jnode);
> +
> + if (first_node)
> + json_object_object_add(jmain, "nodes", jarray);
> +
> + prov_file_write(jmain, false);
> +
> + res = true;
> +done:
> +
> + g_free(in_str);
> +
> + if (jmain)
> + json_object_put(jmain);
> +
> + return res;
> +}
> +
> +static bool parse_node_composition(struct mesh_node *node, json_object *jcomp)
> +{
> + json_object *jvalue;
> + json_object *jelements;
> + json_bool enable;
> + char *str;
> + struct mesh_node_composition comp;
> +
> + json_object_object_get_ex(jcomp, "cid", &jvalue);
> + if (!jvalue)
> + return false;
> +
> + str = (char *)json_object_get_string(jvalue);
> +
> + if (sscanf(str, "%04hx", &comp.cid) != 1)
> + return false;
> +
> + json_object_object_get_ex(jcomp, "pid", &jvalue);
> + if (!jvalue)
> + return false;
> +
> + str = (char *)json_object_get_string(jvalue);
> +
> + if (sscanf(str, "%04hx", &comp.vid) != 1)
> + return false;
> +
> + json_object_object_get_ex(jcomp, "vid", &jvalue);
> + if (!jvalue)
> + return false;
> +
> + str = (char *)json_object_get_string(jvalue);
> +
> + if (sscanf(str, "%04hx", &comp.vid) != 1)
> + return false;
> +
> + json_object_object_get_ex(jcomp, "crpl", &jvalue);
> + if (!jvalue)
> + return false;
> +
> + str = (char *)json_object_get_string(jvalue);
> +
> + if (sscanf(str, "%04hx", &comp.crpl) != 1)
> + return false;
> +
> + /* Extract features */
> + json_object_object_get_ex(jcomp, "relay", &jvalue);
> + enable = json_object_get_boolean(jvalue);
> + comp.relay = (enable) ? true : false;
> +
> + json_object_object_get_ex(jcomp, "proxy", &jvalue);
> + enable = json_object_get_boolean(jvalue);
> + comp.proxy = (enable) ? true : false;
> +
> + json_object_object_get_ex(jcomp, "friend", &jvalue);
> + enable = json_object_get_boolean(jvalue);
> + comp.friend = (enable) ? true : false;
> +
> + json_object_object_get_ex(jcomp, "lowPower", &jvalue);
> + enable = json_object_get_boolean(jvalue);
> + comp.lpn = (enable) ? true : false;
> +
> + if (!node_set_composition(node, &comp))
> + return false;
> +
> + json_object_object_get_ex(jcomp, "elements", &jelements);
> + if (!jelements)
> + return false;
> +
> + return parse_composition_elements(node, jelements);
> +}
> +
> +static bool parse_node(json_object *jnode, bool local)
> +{
> + json_object *jconfig;
> + json_object *jelements;
> + json_object *jidxs;
> + json_object *jvalue;
> + json_object *jint;
> + uint8_t key[16];
> + char *value_str;
> + uint32_t idx;
> + struct mesh_node *node;
> +
> + /* Device key */
> + if (!json_object_object_get_ex(jnode, "deviceKey", &jvalue) ||
> + !jvalue) {
> + if (!mesh_get_random_bytes(key, 16))
> + return false;
> +
> + add_key(jnode, "deviceKey", key);
> + } else {
> + value_str = (char *)json_object_get_string(jvalue);
> + if (!str2hex(value_str, strlen(value_str), key, 16))
> + return false;;
> + }
> +
> + node = node_new();
> +
> + if (!node)
> + return false;
> +
> + node_set_device_key(node, key);
> +
> + json_object_object_get_ex(jnode, "IVindex", &jint);
> + if (jint)
> + idx = json_object_get_int(jint);
> + else
> + idx = 0;
> +
> + node_set_iv_index(node, idx);
> + if (local) {
> + bool update = false;
> + json_object_object_get_ex(jnode, "IVupdate", &jint);
> + if (jint)
> + update = json_object_get_int(jint) ? true : false;
> + net_set_iv_index(idx, update);
> + }
> +
> + if (json_object_object_get_ex(jnode, "sequenceNumber", &jint) &&
> + jint) {
> + int seq = json_object_get_int(jint);
> + node_set_sequence_number(node, seq);
> + }
> +
> + /* Composition is mandatory for local node */
> + json_object_object_get_ex(jnode, "composition", &jconfig);
> + if ((jconfig && !parse_node_composition(node, jconfig)) ||
> + (!jconfig && local)) {
> + node_free(node);
> + return false;
> + }
> +
> + /* Configuration is mandatory for nodes in provisioning database */
> + json_object_object_get_ex(jnode, "configuration", &jconfig);
> + if (!jconfig) {
> + if (local) {
> + /* This is an unprovisioned local device */
> + goto done;
> + } else {
> + node_free(node);
> + return false;
> + }
> + }
> +
> + json_object_object_get_ex(jconfig, "elements", &jelements);
> + if (!jelements) {
> + node_free(node);
> + return false;
> + }
> +
> + if (!parse_configuration_elements(node, jelements, local)) {
> + node_free(node);
> + return false;;
> + }
> +
> + json_object_object_get_ex(jconfig, "netKeys", &jidxs);
> + if (!jidxs || (parse_node_keys(node, jidxs, false) == 0)) {
> + node_free(node);
> + return false;
> + }
> +
> + json_object_object_get_ex(jconfig, "appKeys", &jidxs);
> + if (jidxs)
> + parse_node_keys(node, jidxs, true);
> +
> + json_object_object_get_ex(jconfig, "defaultTTL", &jvalue);
> + if (jvalue) {
> + int ttl = json_object_get_int(jvalue);
> + node_set_default_ttl(node, ttl &TTL_MASK);
> + }
> +
> +done:
> + if (local && !node_set_local_node(node)) {
> + node_free(node);
> + return false;
> + }
> +
> + return true;
> +}
> +
> +bool prov_db_show(const char *filename)
> +{
> + char *str;
> +
> + str = prov_file_read(filename);
> + if (!str)
> + return false;
> +
> + rl_printf("%s\n", str);
> + g_free(str);
> + return true;
> +}
> +
> +static bool read_json_db(const char *filename, bool provisioner, bool local)
> +{
> + char *str;
> + json_object *jmain;
> + json_object *jarray;
> + json_object *jprov;
> + json_object *jvalue;
> + json_object *jtemp;
> + uint8_t key[16];
> + int value_int;
> + char *value_str;
> + int len;
> + int i;
> + uint32_t index;
> + bool refresh = false;
> + bool res = false;
> +
> + str = prov_file_read(filename);
> + if (!str) return false;
> +
> + jmain = json_tokener_parse(str);
> + if (!jmain)
> + goto done;
> +
> + if (local) {
> + json_object *jnode;
> + bool result;
> +
> + json_object_object_get_ex(jmain, "node", &jnode);
> + if (!jnode) {
> + rl_printf("Cannot find \"node\" object");
> + goto done;
> + } else
> + result = parse_node(jnode, true);
> +
> + /*
> + * If local node is provisioner, the rest of mesh settings
> + * are read from provisioning database.
> + */
> + if (provisioner) {
> + res = result;
> + goto done;
> + }
> + }
> +
> + /* IV index */
> + json_object_object_get_ex(jmain, "IVindex", &jvalue);
> + if (!jvalue)
> + goto done;
> +
> + index = json_object_get_int(jvalue);
> +
> + json_object_object_get_ex(jmain, "IVupdate", &jvalue);
> + if (!jvalue)
> + goto done;
> +
> + value_int = json_object_get_int(jvalue);
> +
> + net_set_iv_index(index, value_int);
> +
> + /* Network key(s) */
> + json_object_object_get_ex(jmain, "netKeys", &jarray);
> + if (!jarray)
> + goto done;
> +
> + len = json_object_array_length(jarray);
> + rl_printf("# netkeys = %d\n", len);
> +
> + for (i = 0; i < len; ++i) {
> + uint32_t idx;
> +
> + jtemp = json_object_array_get_idx(jarray, i);
> + json_object_object_get_ex(jtemp, "index", &jvalue);
> + if (!jvalue)
> + goto done;
> + idx = json_object_get_int(jvalue);
> +
> + json_object_object_get_ex(jtemp, "key", &jvalue);
> + if (!jvalue) {
> + if (!mesh_get_random_bytes(key, 16))
> + goto done;
> + add_key(jtemp, "key", key);
> + refresh = true;
> + } else {
> + value_str = (char *)json_object_get_string(jvalue);
> + if (!str2hex(value_str, strlen(value_str), key, 16)) {
> + goto done;
> + }
> + }
> +
> + if (!keys_net_key_add(idx, key, false))
> + goto done;
> +
> + json_object_object_get_ex(jtemp, "keyRefresh", &jvalue);
> + if (!jvalue)
> + goto done;
> +
> + keys_set_kr_phase(idx, (uint8_t) json_object_get_int(jvalue));
> + }
> +
> + /* App keys */
> + json_object_object_get_ex(jmain, "appKeys", &jarray);
> + if (jarray) {
> + len = json_object_array_length(jarray);
> + rl_printf("# appkeys = %d\n", len);
> +
> + for (i = 0; i < len; ++i) {
> + int app_idx;
> + int net_idx;
> +
> + jtemp = json_object_array_get_idx(jarray, i);
> + json_object_object_get_ex(jtemp, "index",
> + &jvalue);
> + if (!jvalue)
> + goto done;
> +
> + app_idx = json_object_get_int(jvalue);
> + if (!CHECK_KEY_IDX_RANGE(app_idx))
> + goto done;
> +
> + json_object_object_get_ex(jtemp, "key", &jvalue);
> + if (!jvalue) {
> + if (!mesh_get_random_bytes(key, 16))
> + goto done;
> + add_key(jtemp, "key", key);
> + refresh = true;
> + } else {
> + value_str =
> + (char *)json_object_get_string(jvalue);
> + str2hex(value_str, strlen(value_str), key, 16);
> + }
> +
> + json_object_object_get_ex(jtemp, "boundNetKey",
> + &jvalue);
> + if (!jvalue)
> + goto done;
> +
> + net_idx = json_object_get_int(jvalue);
> + if (!CHECK_KEY_IDX_RANGE(net_idx))
> + goto done;
> +
> + keys_app_key_add(net_idx, app_idx, key, false);
> + }
> + }
> +
> + /* Provisioner info */
> + json_object_object_get_ex(jmain, "provisioners", &jarray);
> + if (!jarray)
> + goto done;
> +
> + len = json_object_array_length(jarray);
> + rl_printf("# provisioners = %d\n", len);
> +
> + for (i = 0; i < len; ++i) {
> +
> + jprov = json_object_array_get_idx(jarray, i);
> +
> + /* Allocated unicast range */
> + json_object_object_get_ex(jprov, "allocatedUnicastRange",
> + &jtemp);
> + if (!jtemp) {
> + goto done;
> + }
> +
> + if (!parse_unicast_range(jtemp)) {
> + rl_printf("Doneed to parse unicast range\n");
> + goto done;
> + }
> + }
> +
> + json_object_object_get_ex(jmain, "nodes", &jarray);
> + if (!jarray) {
> + res = true;
> + goto done;
> + }
> +
> + len = json_object_array_length(jarray);
> +
> + rl_printf("# provisioned nodes = %d\n", len);
> + for (i = 0; i < len; ++i) {
> + json_object *jnode;
> + jnode = json_object_array_get_idx(jarray, i);
> +
> + if (!jnode || !parse_node(jnode, false))
> + goto done;
> + }
> +
> + res = true;
> +done:
> +
> + g_free(str);
> +
> + if (res && refresh)
> + prov_file_write(jmain, false);
> +
> + if (jmain)
> + json_object_put(jmain);
> +
> + return res;
> +}
> +
> +bool prov_db_read(const char *filename)
> +{
> + prov_filename = filename;
> + return read_json_db(filename, true, false);
> +}
> +
> +bool prov_db_read_local_node(const char *filename, bool provisioner)
> +{
> + local_filename = filename;
> + return read_json_db(filename, provisioner, true);
> +}
> diff --git a/mesh/prov.c b/mesh/prov.c
> new file mode 100644
> index 0000000..89fc884
> --- /dev/null
> +++ b/mesh/prov.c
> @@ -0,0 +1,664 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <sys/uio.h>
> +#include <wordexp.h>
> +
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +#include <glib.h>
> +
> +#include "src/shared/util.h"
> +#include "src/shared/ecc.h"
> +
> +#include "gdbus/gdbus.h"
> +#include "monitor/uuid.h"
> +#include "client/display.h"
> +#include "node.h"
> +#include "gatt.h"
> +#include "crypto.h"
> +#include "mesh-net.h"
> +#include "util.h"
> +#include "agent.h"
> +#include "prov.h"
> +#include "net.h"
> +
> +/* Provisioning Security Levels */
> +#define MESH_PROV_SEC_HIGH 2
> +#define MESH_PROV_SEC_MED 1
> +#define MESH_PROV_SEC_LOW 0
> +
> +/* For Deployment, Security levels below HIGH are *not* recomended */
> +#define mesh_gatt_prov_security() MESH_PROV_SEC_MED
> +
> +#define PROV_INVITE 0x00
> +#define PROV_CAPS 0x01
> +#define PROV_START 0x02
> +#define PROV_PUB_KEY 0x03
> +#define PROV_INP_CMPLT 0x04
> +#define PROV_CONFIRM 0x05
> +#define PROV_RANDOM 0x06
> +#define PROV_DATA 0x07
> +#define PROV_COMPLETE 0x08
> +#define PROV_FAILED 0x09
> +
> +#define PROV_NO_OOB 0
> +#define PROV_STATIC_OOB 1
> +#define PROV_OUTPUT_OOB 2
> +#define PROV_INPUT_OOB 3
> +
> +#define PROV_ERR_INVALID_PDU 0x01
> +#define PROV_ERR_INVALID_FORMAT 0x02
> +#define PROV_ERR_UNEXPECTED_PDU 0x03
> +#define PROV_ERR_CONFIRM_FAILED 0x04
> +#define PROV_ERR_INSUF_RESOURCE 0x05
> +#define PROV_ERR_DECRYPT_FAILED 0x06
> +#define PROV_ERR_UNEXPECTED_ERR 0x07
> +#define PROV_ERR_CANT_ASSIGN_ADDR 0x08
> +
> +/* Expected Provisioning PDU sizes */
> +static const uint16_t expected_pdu_size[] = {
> + 1 + 1, /* PROV_INVITE */
> + 1 + 1 + 2 + 1 + 1 + 1 + 2 + 1 + 2, /* PROV_CAPS */
> + 1 + 1 + 1 + 1 + 1 + 1, /* PROV_START */
> + 1 + 64, /* PROV_PUB_KEY */
> + 1, /* PROV_INP_CMPLT */
> + 1 + 16, /* PROV_CONFIRM */
> + 1 + 16, /* PROV_RANDOM */
> + 1 + 16 + 2 + 1 + 4 + 2 + 8, /* PROV_DATA */
> + 1, /* PROV_COMPLETE */
> + 1 + 1, /* PROV_FAILED */
> +};
> +
> +typedef struct __packed {
> + uint8_t attention;
> +} __attribute__ ((packed)) prov_invite;
> +
> +typedef struct {
> + uint8_t num_ele;
> + uint16_t algorithms;
> + uint8_t pub_type;
> + uint8_t static_type;
> + uint8_t output_size;
> + uint16_t output_action;
> + uint8_t input_size;
> + uint16_t input_action;
> +} __attribute__ ((packed)) prov_caps;
> +
> +typedef struct {
> + uint8_t algorithm;
> + uint8_t pub_key;
> + uint8_t auth_method;
> + uint8_t auth_action;
> + uint8_t auth_size;
> +} __attribute__ ((packed)) prov_start;
> +
> +typedef struct {
> + prov_invite invite;
> + prov_caps caps;
> + prov_start start;
> + uint8_t prv_pub_key[64];
> + uint8_t dev_pub_key[64];
> +} __attribute__ ((packed)) conf_input;
> +
> +struct prov_data {
> + GDBusProxy *prov_in;
> + provision_done_cb prov_done;
> + void *user_data;
> + uint16_t net_idx;
> + uint16_t new_addr;
> + uint8_t state;
> + uint8_t eph_priv_key[32];
> + uint8_t ecdh_secret[32];
> + conf_input conf_in;
> + uint8_t rand_auth[32];
> + uint8_t salt[16];
> + uint8_t conf_key[16];
> + uint8_t mesh_conf[16];
> + uint8_t dev_key[16];
> +};
> +
> +static uint8_t u16_highest_bit(uint16_t mask)
> +{
> + uint8_t cnt = 0;
> +
> + if (!mask) return 0xff;
> +
> + while (mask & 0xfffe) {
> + cnt++;
> + mask >>= 1;
> + }
> +
> + return cnt;
> +}
> +
> +bool prov_open(struct mesh_node *node, GDBusProxy *prov_in, uint16_t net_idx,
> + provision_done_cb cb, void *user_data)
> +{
> + uint8_t invite[] = { PROXY_PROVISIONING_PDU, PROV_INVITE, 0x10 };
> + struct prov_data *prov = node_get_prov(node);
> +
> + if (prov) return false;
> +
> + prov = g_new0(struct prov_data, 1);
> + prov->prov_in = prov_in;
> + prov->net_idx = net_idx;
> + prov->prov_done = cb;
> + prov->user_data = user_data;
> + node_set_prov(node, prov);
> + prov->conf_in.invite.attention = invite[2];
> + prov->state = PROV_INVITE;
> +
> + rl_printf("Open-Node: %p\n", node);
> + rl_printf("Open-Prov: %p\n", prov);
> + rl_printf("Open-Prov: proxy %p\n", prov_in);
> +
> + return mesh_gatt_write(prov_in, invite, sizeof(invite), NULL, node);
> +}
> +
> +static bool prov_send_prov_data(void *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> + uint8_t out[35] = { PROXY_PROVISIONING_PDU, PROV_DATA };
> + uint8_t key[16];
> + uint8_t nonce[13];
> + uint64_t mic;
> +
> + if (prov == NULL) return false;
> +
> + mesh_crypto_session_key(prov->ecdh_secret, prov->salt, key);
> + mesh_crypto_nonce(prov->ecdh_secret, prov->salt, nonce);
> + mesh_crypto_device_key(prov->ecdh_secret, prov->salt, prov->dev_key);
> +
> + print_byte_array("S-Key\t", key, sizeof(key));
> + print_byte_array("S-Nonce\t", nonce, sizeof(nonce));
> + print_byte_array("DevKey\t", prov->dev_key, sizeof(prov->dev_key));
> +
> + if (!net_get_key(prov->net_idx, out + 2))
> + return false;
> +
> + put_be16(prov->net_idx, out + 2 + 16);
> + net_get_flags(prov->net_idx, out + 2 + 16 + 2);
> + put_be32(net_get_iv_index(NULL), out + 2 + 16 + 2 + 1);
> + put_be16(prov->new_addr, out + 2 + 16 + 2 + 1 + 4);
> +
> + print_byte_array("Data\t", out + 2, 16 + 2 + 1 + 4 + 2);
> +
> + mesh_crypto_aes_ccm_encrypt(nonce, key,
> + NULL, 0,
> + out + 2,
> + sizeof(out) - 2 - sizeof(mic),
> + out + 2,
> + &mic, sizeof(mic));
> +
> + print_byte_array("DataEncrypted + mic\t", out + 2, sizeof(out) - 2);
> +
> + prov->state = PROV_DATA;
> + return mesh_gatt_write(prov->prov_in, out, sizeof(out), NULL, node);
> +}
> +
> +static bool prov_send_confirm(void *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> + uint8_t out[18] = { PROXY_PROVISIONING_PDU, PROV_CONFIRM };
> +
> + if (prov == NULL) return false;
> +
> + mesh_get_random_bytes(prov->rand_auth, 16);
> +
> + mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
> + sizeof(prov->rand_auth), out + 2);
> +
> + prov->state = PROV_CONFIRM;
> + return mesh_gatt_write(prov->prov_in, out, sizeof(out), NULL, node);
> +}
> +
> +static void prov_out_oob_done(oob_type_t type, void *buf, uint16_t len,
> + void *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> +
> + if (prov == NULL) return;
> +
> + switch (type) {
> + default:
> + case NONE:
> + case OUTPUT:
> + prov_complete(node, PROV_ERR_INVALID_PDU);
> + return;
> +
> + case ASCII:
> + case HEXADECIMAL:
> + if (len > 16)
> + prov_complete(node, PROV_ERR_INVALID_PDU);
> +
> + memcpy(prov->rand_auth + 16, buf, len);
> + break;
> +
> + case DECIMAL:
> + if (len != 4)
> + prov_complete(node, PROV_ERR_INVALID_PDU);
> +
> + memcpy(prov->rand_auth +
> + sizeof(prov->rand_auth) -
> + sizeof(uint32_t),
> + buf, len);
> + break;
> + }
> +
> + prov_send_confirm(node);
> +}
> +
> +static uint32_t power_ten(uint8_t power)
> +{
> + uint32_t ret = 1;
> +
> + while (power--)
> + ret *= 10;
> +
> + return ret;
> +}
> +
> +char *in_action[3] = {
> + "Push",
> + "Twist",
> + "Enter"
> +};
> +
> +static void prov_calc_ecdh(DBusMessage *message, void *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> + uint8_t action = prov->conf_in.start.auth_action;
> + uint8_t size = prov->conf_in.start.auth_size;
> + char in_oob_display[100];
> + uint8_t *tmp = (void *) in_oob_display;
> + uint32_t in_oob;
> +
> + if (prov == NULL) return;
> +
> + /* Convert to Mesh byte order */
> + memcpy(tmp, prov->conf_in.dev_pub_key, 64);
> + swap_u256_bytes(tmp);
> + swap_u256_bytes(tmp + 32);
> +
> + ecdh_shared_secret(tmp, prov->eph_priv_key, prov->ecdh_secret);
> +
> + /* Convert to Mesh byte order */
> + swap_u256_bytes(prov->ecdh_secret);
> +
> + mesh_crypto_s1(&prov->conf_in,
> + sizeof(prov->conf_in), prov->salt);
> +
> + mesh_crypto_prov_conf_key(prov->ecdh_secret,
> + prov->salt, prov->conf_key);
> +
> + switch (prov->conf_in.start.auth_method) {
> + default:
> + prov_complete(node, PROV_ERR_INVALID_PDU);
> + break;
> +
> + case 0: /* No OOB */
> + prov_send_confirm(node);
> + break;
> +
> + case 1: /* Static OOB */
> + agent_input_request(HEXADECIMAL,
> + 16,
> + prov_out_oob_done, node);
> + break;
> +
> + case 2: /* Output OOB */
> + if (action <= 3)
> + agent_input_request(DECIMAL,
> + size,
> + prov_out_oob_done, node);
> + else
> + agent_input_request(ASCII,
> + size,
> + prov_out_oob_done, node);
> + break;
> +
> + case 3: /* Input OOB */
> +
> + if (action <= 2) {
> + mesh_get_random_bytes(&in_oob, sizeof(in_oob));
> + in_oob %= power_ten(size);
> + sprintf(in_oob_display, "%s %d on device\n",
> + in_action[action], in_oob);
> + put_be32(in_oob,
> + prov->rand_auth +
> + sizeof(prov->rand_auth) -
> + sizeof(uint32_t));
> + } else {
> + uint8_t in_ascii[9];
> + int i = size;
> +
> + mesh_get_random_bytes(in_ascii, i);
> +
> + while (i--) {
> + in_ascii[i] =
> + in_ascii[i] % ((26 * 2) + 10);
> + if (in_ascii[i] >= 10 + 26)
> + in_ascii[i] += 'a' - (10 + 26);
> + else if (in_ascii[i] >= 10)
> + in_ascii[i] += 'A' - 10;
> + else
> + in_ascii[i] += '0';
> + }
> + in_ascii[size] = '\0';
> + memcpy(prov->rand_auth + 16, in_ascii, size);
> + sprintf(in_oob_display,
> + "Enter %s on device\n",
> + in_ascii);
> + }
> + rl_printf("Agent String: %s\n", in_oob_display);
> + agent_output_request(in_oob_display);
> + break;
> + }
> +}
> +
> +static void prov_send_pub_key(struct mesh_node *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> + uint8_t out[66] = { PROXY_PROVISIONING_PDU, PROV_PUB_KEY };
> + GDBusReturnFunction cb = NULL;
> +
> + if (prov == NULL) return;
> +
> + if (prov->conf_in.start.pub_key)
> + cb = prov_calc_ecdh;
> +
> + memcpy(out + 2, prov->conf_in.prv_pub_key, 64);
> + prov->state = PROV_PUB_KEY;
> + mesh_gatt_write(prov->prov_in, out, 66, cb, node);
> +}
> +
> +static void prov_oob_pub_key(oob_type_t type, void *buf, uint16_t len,
> + void *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> +
> + if (prov == NULL) return;
> +
> + memcpy(prov->conf_in.dev_pub_key, buf, 64);
> + prov_send_pub_key(node);
> +}
> +
> +static void prov_start_cmplt(DBusMessage *message, void *node)
> +{
> + struct prov_data *prov = node_get_prov(node);
> +
> + if (prov == NULL) return;
> +
> + if (prov->conf_in.start.pub_key)
> + agent_input_request(HEXADECIMAL, 64, prov_oob_pub_key, node);
> + else
> + prov_send_pub_key(node);
> +}
> +
> +bool prov_data_ready(struct mesh_node *node, uint8_t *buf, uint8_t len)
> +{
> + struct prov_data *prov = node_get_prov(node);
> + uint8_t sec_level = MESH_PROV_SEC_HIGH;
> + uint8_t out[35] = { PROXY_PROVISIONING_PDU };
> +
> + if (prov == NULL || len < 2) return false;
> +
> + buf++;
> + len--;
> +
> + rl_printf("Got provisioning data (%d bytes)\n", len);
> +
> + if (buf[0] > PROV_FAILED || expected_pdu_size[buf[0]] != len)
> + return prov_complete(node, PROV_ERR_INVALID_PDU);
> +
> + print_byte_array("\t", buf, len);
> +
> + if (buf[0] == PROV_FAILED)
> + return prov_complete(node, buf[1]);
> +
> + /* Check provisioning state */
> + switch (prov->state) {
> + default:
> + return prov_complete(node, PROV_ERR_INVALID_PDU);
> +
> + case PROV_INVITE:
> +
> + if (buf[0] != PROV_CAPS)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + /* Normalize to beginning of packed Param struct */
> + buf++;
> + len--;
> +
> + /* Save Capability values */
> + memcpy(&prov->conf_in.caps, buf, len);
> +
> + sec_level = mesh_gatt_prov_security();
> +
> + if (sec_level == MESH_PROV_SEC_HIGH) {
> +
> + /* Enforce High Security */
> + if (prov->conf_in.caps.pub_type != 1 &&
> + prov->conf_in.caps.static_type != 1)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + } else if (sec_level == MESH_PROV_SEC_MED) {
> +
> + /* Enforce Medium Security */
> + if (prov->conf_in.caps.pub_type != 1 &&
> + prov->conf_in.caps.static_type != 1 &&
> + prov->conf_in.caps.input_size == 0 &&
> + prov->conf_in.caps.output_size == 0)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + }
> +
> + /* Num Elements cannot be Zero */
> + if (prov->conf_in.caps.num_ele == 0)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + /* All nodes must support Algorithm 0x0001 */
> + if (!(get_be16(buf + 1) & 0x0001))
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + /* Pub Key and Static type may not be > 1 */
> + if (prov->conf_in.caps.pub_type > 0x01 ||
> + prov->conf_in.caps.static_type > 0x01)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + prov->new_addr =
> + net_obtain_address(prov->conf_in.caps.num_ele);
> +
> + if (!prov->new_addr)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + out[1] = PROV_START;
> + prov->conf_in.start.algorithm = 0;
> + prov->conf_in.start.pub_key =
> + prov->conf_in.caps.pub_type;
> +
> + /* Compose START based on most secure values */
> + if (prov->conf_in.caps.static_type) {
> +
> + prov->conf_in.start.auth_method =
> + PROV_STATIC_OOB;
> +
> + } else if (prov->conf_in.caps.output_size >
> + prov->conf_in.caps.input_size) {
> +
> + prov->conf_in.start.auth_method =
> + PROV_OUTPUT_OOB;
> + prov->conf_in.start.auth_action =
> + u16_highest_bit(get_be16(buf + 6));
> + prov->conf_in.start.auth_size =
> + prov->conf_in.caps.output_size;
> +
> + } else if (prov->conf_in.caps.input_size > 0) {
> +
> + prov->conf_in.start.auth_method =
> + PROV_INPUT_OOB;
> + prov->conf_in.start.auth_action =
> + u16_highest_bit(get_be16(buf + 9));
> + prov->conf_in.start.auth_size =
> + prov->conf_in.caps.input_size;
> + }
> +
> + /* Range Check START values */
> + if (prov->conf_in.start.auth_size > 8)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + prov->state = PROV_START;
> +
> + memcpy(out + 2, &prov->conf_in.start, 5);
> +
> + ecc_make_key(prov->conf_in.prv_pub_key,
> + prov->eph_priv_key);
> +
> + /* Swap public key to share into Mesh byte ordering */
> + swap_u256_bytes(prov->conf_in.prv_pub_key);
> + swap_u256_bytes(prov->conf_in.prv_pub_key + 32);
> +
> + return mesh_gatt_write(prov->prov_in, out, 7,
> + prov_start_cmplt, node);
> +
> +
> + case PROV_PUB_KEY:
> + if (buf[0] == PROV_PUB_KEY &&
> + !prov->conf_in.start.pub_key) {
> +
> + memcpy(prov->conf_in.dev_pub_key, buf + 1, 64);
> + prov_calc_ecdh(NULL, node);
> + return true;
> +
> + } else if (buf[0] == PROV_INP_CMPLT) {
> + agent_output_request_cancel();
> + return prov_send_confirm(node);
> + } else
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + case PROV_CONFIRM:
> + if (buf[0] != PROV_CONFIRM)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + memcpy(prov->mesh_conf, buf + 1, 16);
> +
> + out[1] = PROV_RANDOM;
> + memcpy(out + 2, prov->rand_auth, 16);
> +
> + prov->state = PROV_RANDOM;
> + return mesh_gatt_write(prov->prov_in, out, 18,
> + NULL, node);
> +
> + case PROV_RANDOM:
> + if (buf[0] != PROV_RANDOM)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + /* Calculate New Salt while we still have
> + * both random values */
> + mesh_crypto_prov_prov_salt(prov->salt,
> + prov->rand_auth,
> + buf + 1,
> + prov->salt);
> +
> + /* Calculate meshs Conf Value */
> + memcpy(prov->rand_auth, buf + 1, 16);
> + mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
> + sizeof(prov->rand_auth), out + 1);
> +
> + /* Validate Mesh confirmation */
> + if (memcmp(out + 1, prov->mesh_conf, 16) != 0)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + rl_printf("Confirmation Validated\n");
> +
> + prov_send_prov_data(node);
> +
> + return true;
> +
> + case PROV_DATA:
> + if (buf[0] != PROV_COMPLETE)
> + return prov_complete(node,
> + PROV_ERR_INVALID_PDU);
> +
> + return prov_complete(node, 0);
> + }
> +
> +
> +
> + /* Compose appropriate reply for the prov state message */
> + /* Send reply via mesh_gatt_write() */
> + /* If done, call prov_done calllback and free prov housekeeping data */
> + rl_printf("Got provisioning data (%d bytes)\n", len);
> + print_byte_array("\t", buf, len);
> +
> + return true;
> +}
> +
> +bool prov_complete(struct mesh_node *node, uint8_t status)
> +{
> + struct prov_data *prov = node_get_prov(node);
> + void *user_data;
> + provision_done_cb cb;
> +
> + if (prov == NULL) return false;
> +
> + if (status && prov->new_addr && prov->conf_in.caps.num_ele) {
> + net_release_address(prov->new_addr, prov->conf_in.caps.num_ele);
> + }
> +
> + if (!status) {
> + node_set_num_elements(node, prov->conf_in.caps.num_ele);
> + node_set_primary(node, prov->new_addr);
> + node_set_device_key(node, prov->dev_key);
> + node_net_key_add(node, prov->net_idx);
> + }
> +
> + user_data = prov->user_data;
> + cb = prov->prov_done;
> + g_free(prov);
> + node_set_prov(node, NULL);
> + if (cb) cb(user_data, status);
> +
> + return true;
> +}
> diff --git a/mesh/util.c b/mesh/util.c
> new file mode 100644
> index 0000000..cb241b3
> --- /dev/null
> +++ b/mesh/util.c
> @@ -0,0 +1,369 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2017 Intel Corporation. All rights reserved.
> + *
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <readline/readline.h>
> +#include <glib.h>
> +
> +#include "client/display.h"
> +#include "src/shared/util.h"
> +#include "mesh-net.h"
> +#include "util.h"
> +
> +struct cmd_menu {
> + const char *name;
> + const struct menu_entry *table;
> +};
> +
> +static struct menu_entry *main_cmd_table;
> +static struct menu_entry *current_cmd_table;
> +static GList *menu_list;
> +
> +static char *main_menu_prompt;
> +static int main_menu_point;
> +
> +static int match_menu_name(const void *a, const void *b)
> +{
> + const struct cmd_menu *menu = a;
> + const char *name = b;
> +
> + return strcasecmp(menu->name, name);
> +}
> +
> +bool cmd_menu_init(const struct menu_entry *cmd_table)
> +{
> + struct cmd_menu *menu;
> +
> + if (main_cmd_table) {
> + rl_printf("Main menu already registered\n");
> + return false;
> + }
> +
> + menu = g_malloc(sizeof(struct cmd_menu));
> + if (!menu)
> + return false;
> +
> + menu->name = "meshctl";
> + menu->table = cmd_table;
> + menu_list = g_list_append(menu_list, menu);
> + main_cmd_table = (struct menu_entry *) cmd_table;
> + current_cmd_table = (struct menu_entry *) main_cmd_table;
> +
> + return true;
> +}
> +
> +void cmd_menu_main(bool forced)
> +{
> + current_cmd_table = main_cmd_table;
> +
> + if (!forced) {
> + rl_set_prompt(main_menu_prompt);
> + rl_replace_line("", 0);
> + rl_point = main_menu_point;
> + rl_redisplay();
> + }
> +
> + g_free(main_menu_prompt);
> + main_menu_prompt = NULL;
> +}
> +
> +bool add_cmd_menu(const char *name, const struct menu_entry *cmd_table)
> +{
> + struct cmd_menu *menu;
> + GList *l;
> +
> + l = g_list_find_custom(menu_list, name, match_menu_name);
> + if (l) {
> + menu = l->data;
> + rl_printf("menu \"%s\" already registered\n", menu->name);
> + return false;
> + }
> +
> + menu = g_malloc(sizeof(struct cmd_menu));
> + if (!menu)
> + return false;
> +
> + menu->name = name;
> + menu->table = cmd_table;
> + menu_list = g_list_append(menu_list, menu);
> +
> + return true;
> +}
> +
> +void set_menu_prompt(const char *name, const char *id)
> +{
> + char *prompt;
> +
> + prompt = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", name,
> + id ? ": Target = " : "", id ? id : "");
> + rl_set_prompt(prompt);
> + g_free(prompt);
> + rl_on_new_line();
> +}
> +
> +bool switch_cmd_menu(const char *name)
> +{
> + GList *l;
> + struct cmd_menu *menu;
> +
> + l = g_list_find_custom(menu_list, name, match_menu_name);
> + if(!l)
> + return false;
> +
> + menu = l->data;
> + current_cmd_table = (struct menu_entry *) menu->table;
> +
> + main_menu_point = rl_point;
> + main_menu_prompt = g_strdup(rl_prompt);
> +
> + return true;
> +}
> +
> +void process_menu_cmd(const char *cmd, const char *arg)
> +{
> + int i;
> + int len;
> + struct menu_entry *cmd_table = current_cmd_table;
> +
> + if (!current_cmd_table)
> + return;
> +
> + len = strlen(cmd);
> +
> + for (i = 0; cmd_table[i].cmd; i++) {
> + if (strncmp(cmd, cmd_table[i].cmd, len))
> + continue;
> +
> + if (cmd_table[i].func) {
> + cmd_table[i].func(arg);
> + return;
> + }
> + }
> +
> + if (strncmp(cmd, "help", len)) {
> + rl_printf("Invalid command\n");
> + return;
> + }
> +
> + print_cmd_menu(cmd_table);
> +}
> +
> +void print_cmd_menu(const struct menu_entry *cmd_table)
> +{
> + int i;
> +
> + rl_printf("Available commands:\n");
> +
> + for (i = 0; cmd_table[i].cmd; i++) {
> + if (cmd_table[i].desc)
> + rl_printf(" %s %-*s %s\n", cmd_table[i].cmd,
> + (int)(40 - strlen(cmd_table[i].cmd)),
> + cmd_table[i].arg ? : "",
> + cmd_table[i].desc ? : "");
> + }
> +
> +}
> +
> +void cmd_menu_cleanup(void)
> +{
> + main_cmd_table = NULL;
> + current_cmd_table = NULL;
> +
> + g_list_free_full(menu_list, g_free);
> +}
> +
> +void print_byte_array(const char *prefix, const void *ptr, int len)
> +{
> + const uint8_t *data = ptr;
> + char *line, *bytes;
> + int i;
> +
> + line = g_malloc(strlen(prefix) + (16 * 3) + 2);
> + sprintf(line, "%s ", prefix);
> + bytes = line + strlen(prefix) + 1;
> +
> + for (i = 0; i < len; ++i) {
> + sprintf(bytes, "%2.2x ", data[i]);
> + if ((i + 1) % 16) {
> + bytes += 3;
> + } else {
> + rl_printf("\r%s\n", line);
> + bytes = line + strlen(prefix) + 1;
> + }
> + }
> +
> + if (i % 16)
> + rl_printf("\r%s\n", line);
> +
> + g_free(line);
> +}
> +
> +bool str2hex(const char *str, uint16_t in_len, uint8_t *out,
> + uint16_t out_len)
> +{
> + uint16_t i;
> +
> + if (in_len < out_len * 2)
> + return false;
> +
> + for (i = 0; i < out_len; i++) {
> + if (sscanf(&str[i * 2], "%02hhx", &out[i]) != 1)
> + return false;
> + }
> +
> + return true;
> +}
> +
> +size_t hex2str(uint8_t *in, size_t in_len, char *out,
> + size_t out_len)
> +{
> + static const char hexdigits[] = "0123456789abcdef";
> + size_t i;
> +
> + if(in_len * 2 > out_len - 1)
> + return 0;
> +
> + for (i = 0; i < in_len; i++) {
> + out[i * 2] = hexdigits[in[i] >> 4];
> + out[i * 2 + 1] = hexdigits[in[i] & 0xf];
> + }
> +
> + out[in_len * 2] = '\0';
> + return i;
> +}
> +
> +uint16_t mesh_opcode_set(uint32_t opcode, uint8_t *buf)
> +{
> + if (opcode <= 0x7e) {
> + buf[0] = opcode;
> + return 1;
> + } else if (opcode >= 0x8000 && opcode <= 0xbfff) {
> + put_be16(opcode, buf);
> + return 2;
> + } else if (opcode >= 0xc00000 && opcode <= 0xffffff) {
> + buf[0] = (opcode >> 16) & 0xff;
> + put_be16(opcode, buf + 1);
> + return 3;
> + } else {
> + rl_printf("Illegal Opcode %x", opcode);
> + return 0;
> + }
> +}
> +
> +bool mesh_opcode_get(const uint8_t *buf, uint16_t sz, uint32_t *opcode, int *n)
> +{
> + if (!n || !opcode || sz < 1) return false;
> +
> + switch (buf[0] & 0xc0) {
> + case 0x00:
> + case 0x40:
> + /* RFU */
> + if (buf[0] == 0x7f)
> + return false;
> +
> + *n = 1;
> + *opcode = buf[0];
> + break;
> +
> + case 0x80:
> + if (sz < 2)
> + return false;
> +
> + *n = 2;
> + *opcode = get_be16(buf);
> + break;
> +
> + case 0xc0:
> + if (sz < 3)
> + return false;
> +
> + *n = 3;
> + *opcode = get_be16(buf + 1);
> + *opcode |= buf[0] << 16;
> + break;
> +
> + default:
> + rl_printf("Bad Packet:\n");
> + print_byte_array("\t", (void *) buf, sz);
> + return false;
> + }
> +
> + return true;
> +}
> +
> +const char *mesh_status_str(uint8_t status)
> +{
> + switch (status) {
> + case MESH_STATUS_SUCCESS: return "Success";
> + case MESH_STATUS_INVALID_ADDRESS: return "Invalid Address";
> + case MESH_STATUS_INVALID_MODEL: return "Invalid Model";
> + case MESH_STATUS_INVALID_APPKEY: return "Invalid AppKey";
> + case MESH_STATUS_INVALID_NETKEY: return "Invalid NetKey";
> + case MESH_STATUS_INSUFF_RESOURCES: return "Insufficient Resources";
> + case MESH_STATUS_IDX_ALREADY_STORED: return "Key Idx Already Stored";
> + case MESH_STATUS_INVALID_PUB_PARAM: return "Invalid Publish Parameters";
> + case MESH_STATUS_NOT_SUB_MOD: return "Not a Subscribe Model";
> + case MESH_STATUS_STORAGE_FAIL: return "Storage Failure";
> + case MESH_STATUS_FEAT_NOT_SUP: return "Feature Not Supported";
> + case MESH_STATUS_CANNOT_UPDATE: return "Cannot Update";
> + case MESH_STATUS_CANNOT_REMOVE: return "Cannot Remove";
> + case MESH_STATUS_CANNOT_BIND: return "Cannot bind";
> + case MESH_STATUS_UNABLE_CHANGE_STATE: return "Unable to change state";
> + case MESH_STATUS_CANNOT_SET: return "Cannot set";
> + case MESH_STATUS_UNSPECIFIED_ERROR: return "Unspecified error";
> + case MESH_STATUS_INVALID_BINDING: return "Invalid Binding";
> +
> + default: return "Unknown";
> + }
> +}
> +
> +void print_model_pub(uint16_t ele_addr, uint32_t mod_id,
> + struct mesh_publication *pub)
> +{
> + rl_printf("\tElement: %4.4x\n", ele_addr);
> + rl_printf("\tPub Addr: %4.4x", pub->u.addr16);
> + if (mod_id > 0xffff0000)
> + rl_printf("\tModel: %8.8x \n", mod_id);
> + else
> + rl_printf("\tModel: %4.4x \n", (uint16_t) (mod_id & 0xffff));
> + rl_printf("\tApp Key Idx: %4.4x", pub->app_idx);
> + rl_printf("\tTTL: %2.2x", pub->ttl);
> +}
> +
> +void swap_u256_bytes(uint8_t *u256)
> +{
> + int i;
> +
> + /* End-to-End byte reflection of 32 octet buffer */
> + for (i = 0; i < 16; i++) {
> + u256[i] ^= u256[31 - i];
> + u256[31 - i] ^= u256[i];
> + u256[i] ^= u256[31 - i];
> + }
> +}
> --
> 2.9.5
>



--
Luiz Augusto von Dentz

2017-08-14 19:01:18

by Gix, Brian

[permalink] [raw]
Subject: [PATCH 4/5] mesh: Baseline Mesh implementation

---
mesh/agent.c | 276 ++++++
mesh/config-client.c | 667 +++++++++++++++
mesh/config-server.c | 165 ++++
mesh/crypto.c | 1168 ++++++++++++++++++++++++++
mesh/gatt.c | 609 ++++++++++++++
mesh/main.c | 2269 ++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/net.c | 2184 ++++++++++++++++++++++++++++++++++++++++++++++++
mesh/node.c | 879 +++++++++++++++++++
mesh/onoff-model.c | 306 +++++++
mesh/prov-db.c | 1599 +++++++++++++++++++++++++++++++++++
mesh/prov.c | 664 +++++++++++++++
mesh/util.c | 369 ++++++++
12 files changed, 11155 insertions(+)
create mode 100644 mesh/agent.c
create mode 100644 mesh/config-client.c
create mode 100644 mesh/config-server.c
create mode 100644 mesh/crypto.c
create mode 100644 mesh/gatt.c
create mode 100644 mesh/main.c
create mode 100644 mesh/net.c
create mode 100644 mesh/node.c
create mode 100644 mesh/onoff-model.c
create mode 100644 mesh/prov-db.c
create mode 100644 mesh/prov.c
create mode 100644 mesh/util.c

diff --git a/mesh/agent.c b/mesh/agent.c
new file mode 100644
index 0000000..0944862
--- /dev/null
+++ b/mesh/agent.c
@@ -0,0 +1,276 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <readline/readline.h>
+
+#include <glib.h>
+
+#include <lib/bluetooth.h>
+#include "client/display.h"
+#include "util.h"
+#include "agent.h"
+
+#define AGENT_PROMPT COLOR_RED "[agent]" COLOR_OFF " "
+
+static char *agent_saved_prompt = NULL;
+static int agent_saved_point = 0;
+
+struct input_request {
+ oob_type_t type;
+ uint16_t len;
+ agent_input_cb cb;
+ void *user_data;
+};
+
+static struct input_request pending_request = {NONE, 0, NULL, NULL};
+
+static void agent_prompt(const char *msg)
+{
+ char *prompt;
+
+ /* Normal use should not prompt for user input to the agent a second
+ * time before it releases the prompt, but we take a safe action. */
+ if (agent_saved_prompt)
+ return;
+
+ agent_saved_point = rl_point;
+ agent_saved_prompt = g_strdup(rl_prompt);
+
+ rl_set_prompt("");
+ rl_redisplay();
+
+ prompt = g_strdup_printf(AGENT_PROMPT "%s", msg);
+ rl_set_prompt(prompt);
+ g_free(prompt);
+
+ rl_replace_line("", 0);
+ rl_redisplay();
+}
+
+static void agent_release_prompt(void)
+{
+ if (!agent_saved_prompt)
+ return;
+
+ /* This will cause rl_expand_prompt to re-run over the last prompt, but
+ * our prompt doesn't expand anyway. */
+ rl_set_prompt(agent_saved_prompt);
+ rl_replace_line("", 0);
+ rl_point = agent_saved_point;
+ rl_redisplay();
+
+ g_free(agent_saved_prompt);
+ agent_saved_prompt = NULL;
+}
+
+bool agent_completion(void)
+{
+ if (pending_request.type == NONE)
+ return false;
+
+ return true;
+}
+
+static bool response_hexadecimal(const char *input)
+{
+ uint8_t buf[MAX_HEXADECIMAL_OOB_LEN];
+
+ if (!str2hex(input, strlen(input), buf, pending_request.len) ) {
+ rl_printf("Incorrect input: expecting %d hex octets\n",
+ pending_request.len);
+ return false;
+ }
+
+ if (pending_request.cb)
+ pending_request.cb(HEXADECIMAL, buf, pending_request.len,
+ pending_request.user_data);
+ return true;
+}
+
+static bool response_decimal(const char *input)
+{
+ uint8_t buf[DECIMAL_OOB_LEN];
+
+ if (strlen(input) > pending_request.len)
+ return false;
+
+ bt_put_be32(atoi(input), buf);
+
+ if (pending_request.cb)
+ pending_request.cb(DECIMAL, buf, DECIMAL_OOB_LEN,
+ pending_request.user_data);
+
+ return true;
+}
+
+static void response_ascii(const char *input)
+{
+ if (pending_request.cb)
+ pending_request.cb(ASCII, (uint8_t *) input, strlen(input),
+ pending_request.user_data);
+}
+
+bool agent_input(const char *input)
+{
+ bool repeat = false;
+
+ if (pending_request.type == NONE)
+ return false;
+
+ switch (pending_request.type) {
+ case HEXADECIMAL:
+ if (!response_hexadecimal(input))
+ repeat = true;
+ break;
+ case DECIMAL:
+ if (!response_decimal(input))
+ repeat = true;
+ break;
+ case ASCII:
+ response_ascii(input);
+ break;
+ case OUTPUT:
+ repeat = true;
+ case NONE:
+ default:
+ break;
+ };
+
+ if (!repeat) {
+ pending_request.type = NONE;
+ pending_request.len = 0;
+ pending_request.cb = NULL;
+ pending_request.user_data = NULL;
+
+ agent_release_prompt();
+ }
+
+ return true;
+}
+
+void agent_release(void)
+{
+ agent_release_prompt();
+}
+
+static bool request_hexadecimal(uint16_t len)
+{
+ if (len > MAX_HEXADECIMAL_OOB_LEN)
+ return false;
+
+ rl_printf("Request hexadecimal key (hex %d octets)\n", len);
+ agent_prompt("Enter key (hex number): ");
+
+ return true;
+}
+
+static uint32_t power_ten(uint8_t power)
+{
+ uint32_t ret = 1;
+
+ while (power--)
+ ret *= 10;
+
+ return ret;
+}
+
+static bool request_decimal(uint16_t len)
+{
+ rl_printf("Request decimal key (0 - %d)\n", power_ten(len) - 1);
+ agent_prompt("Enter Numeric key: ");
+
+ return true;
+}
+
+static bool request_ascii(uint16_t len)
+{
+ if (len != MAX_ASCII_OOB_LEN)
+ return false;
+
+ rl_printf("Request ASCII key (max characters %d)\n", len);
+ agent_prompt("Enter key (ascii string): ");
+
+ return true;
+}
+
+bool agent_input_request(oob_type_t type, uint16_t max_len, agent_input_cb cb,
+ void *user_data)
+{
+ bool result;
+
+ if (pending_request.type != NONE)
+ return FALSE;
+
+ switch (type) {
+ case HEXADECIMAL:
+ result = request_hexadecimal(max_len);
+ break;
+ case DECIMAL:
+ result = request_decimal(max_len);
+ break;
+ case ASCII:
+ result = request_ascii(max_len);
+ break;
+ case NONE:
+ case OUTPUT:
+ default:
+ return false;
+ };
+
+ if (result) {
+ pending_request.type = type;
+ pending_request.len = max_len;
+ pending_request.cb = cb;
+ pending_request.user_data = user_data;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool agent_output_request(const char* str)
+{
+ if (pending_request.type != NONE)
+ return false;
+
+ pending_request.type = OUTPUT;
+ agent_prompt(str);
+ return true;
+}
+
+void agent_output_request_cancel(void)
+{
+ if (pending_request.type != OUTPUT)
+ return;
+ pending_request.type = NONE;
+ agent_release_prompt();
+}
diff --git a/mesh/config-client.c b/mesh/config-client.c
new file mode 100644
index 0000000..a0f6eee
--- /dev/null
+++ b/mesh/config-client.c
@@ -0,0 +1,667 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <wordexp.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "client/display.h"
+#include "mesh-net.h"
+#include "keys.h"
+#include "net.h"
+#include "node.h"
+#include "prov-db.h"
+#include "util.h"
+#include "config-model.h"
+
+#define MIN_COMPOSITION_LEN 16
+
+static bool client_msg_recvd(uint16_t src, uint8_t *data,
+ uint16_t len, void *user_data)
+{
+ uint32_t opcode;
+ struct mesh_node *node;
+ uint16_t app_idx, net_idx, addr;
+ uint32_t mod_id;
+ uint16_t primary;
+ uint16_t ele_addr;
+ uint8_t ele_idx;
+ struct mesh_publication pub;
+ int n;
+
+ if (mesh_opcode_get(data, len, &opcode, &n)) {
+ len -= n;
+ data += n;
+ } else
+ return false;
+
+ if (IS_UNICAST(src)) {
+ node = node_find_by_addr(src);
+ } else
+ node = NULL;
+
+ if (!node)
+ return false;
+
+ primary = node_get_primary(node);
+ if (primary != src)
+ return false;
+
+ switch (opcode & ~OP_UNRELIABLE) {
+ default:
+ return false;
+
+ case OP_DEV_COMP_STATUS:
+ if (len < MIN_COMPOSITION_LEN || !node)
+ break;
+ if (node_parse_composition(node, data, len)) {
+ if (!prov_db_add_node_composition(node, data, len))
+ break;
+ }
+
+ if (node_get_composition(node))
+ prov_db_print_node_composition(node);
+ break;
+
+ case OP_APPKEY_STATUS:
+ if (len != 4)
+ break;
+
+ rl_printf("Node %4.4x AppKey Status %s\n", src,
+ mesh_status_str(data[0]));
+ net_idx = get_le16(data + 1) & 0xfff;
+ app_idx = get_le16(data + 2) >> 4;
+
+ rl_printf("\tNetKey %3.3x, AppKey %3.3x\n", net_idx, app_idx);
+
+ if (data[0] != MESH_STATUS_SUCCESS &&
+ data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
+ node_app_key_delete(node, net_idx, app_idx))
+ prov_db_node_keys(node, node_get_app_keys(node),
+ "appKeys");
+ break;
+
+ case OP_NETKEY_STATUS:
+ if (len != 3)
+ break;
+
+ rl_printf("Node %4.4x NetKey Status %s\n", src,
+ mesh_status_str(data[0]));
+ net_idx = get_le16(data + 1) & 0xfff;
+
+ rl_printf("\tNetKey %3.3x\n", net_idx);
+
+ if (data[0] != MESH_STATUS_SUCCESS &&
+ data[0] != MESH_STATUS_IDX_ALREADY_STORED &&
+ node_net_key_delete(node, net_idx))
+ prov_db_node_keys(node, node_get_net_keys(node),
+ "netKeys");
+ break;
+
+ case OP_MODEL_APP_STATUS:
+ if (len != 7 && len != 9)
+ break;
+
+ rl_printf("Node %4.4x Model App Status %s\n", src,
+ mesh_status_str(data[0]));
+ addr = get_le16(data + 1);
+ app_idx = get_le16(data + 3);
+
+ rl_printf("\tElement %4.4x AppIdx %3.3x\n ", addr, app_idx);
+
+ if (len == 7) {
+ mod_id = get_le16(data + 5);
+ rl_printf("ModelId %4.4x\n", mod_id);
+ mod_id = 0xffff0000 | mod_id;
+ } else {
+ mod_id = get_le16(data + 7);
+ rl_printf("ModelId %4.4x %4.4x\n", get_le16(data + 5),
+ mod_id);
+ mod_id = get_le16(data + 5) << 16 | mod_id;
+ }
+
+ if (data[0] == MESH_STATUS_SUCCESS &&
+ node_add_binding(node, addr - src, mod_id, app_idx))
+ prov_db_add_binding(node, addr - src, mod_id, app_idx);
+ break;
+
+ case OP_CONFIG_DEFAULT_TTL_STATUS:
+ if (len != 1)
+ return true;
+ rl_printf("Node %4.4x Default TTL %d\n", src, data[0]);
+ if (node_set_default_ttl (node, data[0]))
+ prov_db_node_set_ttl(node, data[0]);
+ break;
+
+ case OP_CONFIG_MODEL_PUB_STATUS:
+ if (len != 12 && len != 14)
+ return true;
+
+ rl_printf("\nSet publication for node %4.4x status: %s\n", src,
+ data[0] == MESH_STATUS_SUCCESS ? "Success" :
+ mesh_status_str(data[0]));
+
+ if (data[0] != MESH_STATUS_SUCCESS)
+ return true;
+
+ ele_addr = get_le16(data + 1);
+ mod_id = get_le16(data + 10);
+ if (len == 14)
+ mod_id = (mod_id << 16) | get_le16(data + 12);
+ else
+ mod_id |= 0xffff0000;
+
+ pub.u.addr16 = get_le16(data + 3);
+ pub.app_idx = get_le16(data + 5);
+ pub.ttl = data[7];
+ pub.period = data[8];
+ n = (data[8] & 0x3f);
+ switch (data[8] >> 6) {
+ case 0:
+ rl_printf("Period: %d ms\n", n * 100);
+ break;
+ case 2:
+ n *= 10;
+ /* fall through */
+ case 1:
+ rl_printf("Period: %d sec\n", n);
+ break;
+ case 3:
+ rl_printf("Period: %d min\n", n * 10);
+ break;
+ }
+
+ pub.retransmit = data[9];
+ rl_printf("Retransmit count: %d\n", data[9] >> 5);
+ rl_printf("Retransmit Interval Steps: %d\n", data[9] & 0x1f);
+
+ ele_idx = ele_addr - node_get_primary(node);
+
+ /* Local configuration is saved by server */
+ if (node == node_get_local_node())
+ break;
+
+ if (node_model_pub_set(node, ele_idx, mod_id, &pub))
+ prov_db_node_set_model_pub(node, ele_idx, mod_id,
+ node_model_pub_get(node, ele_idx, mod_id));
+ break;
+ }
+ return true;
+}
+
+static uint32_t target;
+static uint32_t parms[8];
+
+static uint32_t read_input_parameters(const char *args)
+{
+ uint32_t i;
+
+ if (!args)
+ return 0;
+
+ memset(parms, 0xff, sizeof(parms));
+
+ for (i = 0; i < sizeof(parms)/sizeof(parms[0]); i++) {
+ int n;
+
+ sscanf(args, "%x", &parms[i]);
+ if (parms[i] == 0xffffffff)
+ break;
+
+ n = strcspn(args, " \t");
+ args = args + n + strspn(args + n, " \t");
+ }
+
+ return i;
+}
+
+static void cmd_set_node(const char *args)
+{
+ uint32_t dst;
+ char *end;
+
+ dst = strtol(args, &end, 16);
+ if (end != (args + 4)) {
+ rl_printf("Bad unicast address %s: "
+ "expected format 4 digit hex\n", args);
+ target = UNASSIGNED_ADDRESS;
+ } else {
+ rl_printf("Configuring node %4.4x\n", dst);
+ target = dst;
+ set_menu_prompt("config", args);
+ }
+
+}
+
+static bool config_send(uint8_t *buf, uint16_t len)
+{
+ struct mesh_node *node = node_get_local_node();
+ uint16_t primary;
+
+ if(!node)
+ return false;
+
+ primary = node_get_primary(node);
+ if (target != primary)
+ return net_access_layer_send(DEFAULT_TTL, primary,
+ target, APP_IDX_DEV, buf, len);
+
+ node_local_data_handler(primary, target, node_get_iv_index(node),
+ node_get_sequence_number(node), APP_IDX_DEV,
+ buf, len);
+ return true;
+
+}
+
+static void cmd_get_composition(const char *args)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ struct mesh_node *node;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ node = node_find_by_addr(target);
+
+ if (!node)
+ return;
+
+ n = mesh_opcode_set(OP_DEV_COMP_GET, msg);
+
+ /* By default, use page 0 */
+ msg[n++] = (read_input_parameters(args) == 1) ? parms[0] : 0;
+
+ if (!config_send(msg, n))
+ rl_printf("Failed to send \"GET NODE COMPOSITION\"\n");
+}
+
+static void cmd_net_key(const char *args, uint32_t opcode)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ uint16_t net_idx;
+ uint8_t *key;
+ struct mesh_node *node;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ n = mesh_opcode_set(opcode, msg);
+
+ if (read_input_parameters(args) != 1) {
+ rl_printf("Bad arguments %s\n", args);
+ return;
+ }
+
+ node = node_find_by_addr(target);
+ if (!node) {
+ rl_printf("Node %4.4x\n not found", target);
+ return;
+ }
+
+ net_idx = parms[0];
+
+ if (opcode != OP_NETKEY_DELETE) {
+
+ key = keys_net_key_get(net_idx, true);
+ if (!key) {
+ rl_printf("Network key with index %4.4x not found\n",
+ net_idx);
+ return;
+ }
+
+ put_le16(net_idx, &msg[n]);
+ n += 2;
+
+ memcpy(msg + n, key, 16);
+ n += 16;
+ }
+
+ if (!config_send(msg, n)) {
+ rl_printf("Failed to send \"%s NET KEY\"\n",
+ opcode == OP_NETKEY_ADD ? "ADD" : "DEL");
+ return;
+ }
+
+ if (opcode != OP_NETKEY_DELETE) {
+ if (node_net_key_add(node, net_idx))
+ prov_db_node_keys(node, node_get_net_keys(node),
+ "netKeys");
+ } else {
+ if (node_net_key_delete(node, net_idx))
+ prov_db_node_keys(node, node_get_net_keys(node),
+ "netKeys");
+ }
+
+}
+
+static void cmd_add_net_key(const char *args)
+{
+ cmd_net_key(args, OP_NETKEY_ADD);
+}
+
+static void cmd_del_net_key(const char *args)
+{
+ cmd_net_key(args, OP_NETKEY_DELETE);
+}
+
+static void cmd_app_key(const char *args, uint32_t opcode)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ uint16_t net_idx;
+ uint16_t app_idx;
+ uint8_t *key;
+ struct mesh_node *node;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ if (read_input_parameters(args) != 1) {
+ rl_printf("Bad arguments %s\n", args);
+ return;
+ }
+
+ node = node_find_by_addr(target);
+ if (!node) {
+ rl_printf("Node %4.4x\n not found", target);
+ return;
+ }
+
+ n = mesh_opcode_set(opcode, msg);
+
+ app_idx = parms[0];
+ net_idx = keys_app_key_get_bound(app_idx);
+ if (net_idx == NET_IDX_INVALID) {
+ rl_printf("App key with index %4.4x not found\n", app_idx);
+ return;
+ }
+
+ msg[n++] = net_idx & 0xf;
+ msg[n++] = ((net_idx >> 8) & 0xf) |
+ ((app_idx << 4) & 0xf0);
+ msg[n++] = app_idx >> 4;
+
+ if (opcode != OP_APPKEY_DELETE) {
+ key = keys_app_key_get(app_idx, true);
+ if (!key) {
+ rl_printf("App key %4.4x not found\n", net_idx);
+ return;
+ }
+
+ memcpy(msg + n, key, 16);
+ n += 16;
+ }
+
+ if (!config_send(msg, n)) {
+ rl_printf("Failed to send \"ADD %s KEY\"\n",
+ opcode == OP_APPKEY_ADD ? "ADD" : "DEL");
+ return;
+ }
+
+ if (opcode != OP_APPKEY_DELETE) {
+ if (node_app_key_add(node, app_idx))
+ prov_db_node_keys(node, node_get_app_keys(node),
+ "appKeys");
+ } else {
+ if (node_app_key_delete(node, net_idx, app_idx))
+ prov_db_node_keys(node, node_get_app_keys(node),
+ "appKeys");
+ }
+}
+
+static void cmd_add_app_key(const char *args)
+{
+ cmd_app_key(args, OP_APPKEY_ADD);
+}
+
+static void cmd_del_app_key(const char *args)
+{
+ cmd_app_key(args, OP_APPKEY_DELETE);
+}
+
+static void cmd_bind(const char *args)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ int parm_cnt;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ parm_cnt = read_input_parameters(args);
+ if (parm_cnt != 3 && parm_cnt != 4) {
+ rl_printf("Bad arguments %s\n", args);
+ return;
+ }
+
+ n = mesh_opcode_set(OP_MODEL_APP_BIND, msg);
+
+ put_le16(target + parms[0], msg + n);
+ n += 2;
+ put_le16(parms[1], msg + n);
+ n += 2;
+ if (parm_cnt == 4) {
+ put_le16(parms[3], msg + n);
+ put_le16(parms[2], msg + n + 2);
+ n += 4;
+ } else {
+ put_le16(parms[2], msg + n);
+ n += 2;
+ }
+
+ if (!config_send(msg, n))
+ rl_printf("Failed to send \"MODEL APP BIND\"\n");
+}
+
+static void cmd_set_ttl(const char *args)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ int parm_cnt;
+ uint8_t ttl;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_SET, msg);
+
+ parm_cnt = read_input_parameters(args);
+ if (parm_cnt) {
+ ttl = parms[0] & TTL_MASK;
+ } else
+ ttl = node_get_default_ttl(node_get_local_node());
+
+ msg[n++] = ttl;
+
+ if (!config_send(msg, n))
+ rl_printf("Failed to send \"SET_DEFAULT TTL\"\n");
+}
+
+static void cmd_set_pub(const char *args)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ int parm_cnt;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ n = mesh_opcode_set(OP_CONFIG_MODEL_PUB_SET, msg);
+
+ parm_cnt = read_input_parameters(args);
+ if (parm_cnt != 5) {
+ rl_printf("Bad arguments: %s\n", args);
+ return;
+ }
+
+ put_le16(parms[0], msg + n);
+ n += 2;
+ /* Publish address */
+ put_le16(parms[1], msg + n);
+ n += 2;
+ /* App key index + credential (set to 0) */
+ put_le16(parms[2], msg + n);
+ n += 2;
+ /* TTL */
+ msg[n++] = DEFAULT_TTL;
+ /* Publish period step count and step resolution */
+ msg[n++] = parms[3];
+ /* Publish retransmit count & interval steps */
+ msg[n++] = (1 << 5) + 2;
+ /* Model Id */
+ if (parms[4] > 0xffff) {
+ put_le16(parms[4] >> 16, msg + n);
+ put_le16(parms[4], msg + n + 2);
+ n += 4;
+ } else {
+ put_le16(parms[4], msg + n);
+ n += 2;
+ }
+
+ if (!config_send(msg, n))
+ rl_printf("Failed to send \"SET MODEL PUBLICATION\"\n");
+}
+
+static void cmd_default(uint32_t opcode)
+{
+ uint16_t n;
+ uint8_t msg[32];
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ n = mesh_opcode_set(opcode, msg);
+
+ if (!config_send(msg, n))
+ rl_printf("Failed to send command (opcode 0x%x)\n", opcode);
+}
+
+static void cmd_get_ttl(const char *args)
+{
+ cmd_default(OP_CONFIG_DEFAULT_TTL_GET);
+}
+
+static void cmd_back(const char *args)
+{
+ cmd_menu_main(false);
+}
+
+static void cmd_help(const char *args);
+
+static const struct menu_entry cfg_menu[] = {
+ {"target", "<unicast>", cmd_set_node,
+ "Set target node to configure"},
+ {"get-composition", "[<page_num>]", cmd_get_composition,
+ "Get Composition Data"},
+ {"add-netkey", "<net_idx>", cmd_add_net_key,
+ "Add network key"},
+ {"del-netkey", "<net_idx>", cmd_del_net_key,
+ "Delete network key"},
+ {"add-appkey", "<app_idx>", cmd_add_app_key,
+ "Add application key"},
+ {"del-appkey", "<app_idx>", cmd_del_app_key,
+ "Delete application key"},
+ {"bind", "<ele_idx> <app_idx> <mod_id> [cid]",
+ cmd_bind, "Bind app key to a model"},
+ {"set-ttl", "<ttl>", cmd_set_ttl,
+ "Set default TTL"},
+ {"get-ttl", NULL, cmd_get_ttl,
+ "Get default TTL"},
+ {"set-pub", "<ele_addr> <pub_addr> <app_idx> "
+ "<period (step|res)> <model>",
+ cmd_set_pub, "Set publication"},
+ {"back", NULL, cmd_back,
+ "Back to main menu"},
+ {"help", NULL, cmd_help,
+ "Config Commands"},
+ {}
+};
+
+static void cmd_help(const char *args)
+{
+ rl_printf("Client Configuration Menu\n");
+ print_cmd_menu(cfg_menu);
+}
+
+void config_set_node(const char *args)
+{
+ cmd_set_node(args);
+}
+
+void config_client_get_composition(uint32_t dst)
+{
+ uint32_t tmp = target;
+
+ target = dst;
+ cmd_get_composition("");
+ target = tmp;
+}
+
+static struct mesh_model_ops client_cbs = {
+ client_msg_recvd,
+ NULL,
+ NULL,
+ NULL
+};
+
+bool config_client_init(void)
+{
+ if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
+ CONFIG_CLIENT_MODEL_ID,
+ &client_cbs, NULL))
+ return false;
+
+ add_cmd_menu("configure", cfg_menu);
+
+ return true;
+}
diff --git a/mesh/config-server.c b/mesh/config-server.c
new file mode 100644
index 0000000..14e5d7b
--- /dev/null
+++ b/mesh/config-server.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <wordexp.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "client/display.h"
+#include "mesh-net.h"
+#include "keys.h"
+#include "net.h"
+#include "node.h"
+#include "prov-db.h"
+#include "util.h"
+#include "config-model.h"
+
+static bool server_msg_recvd(uint16_t src, uint8_t *data,
+ uint16_t len, void *user_data)
+{
+ uint32_t opcode;
+ uint8_t msg[32];
+ struct mesh_node *node;
+ uint16_t primary;
+ uint32_t mod_id;
+ uint16_t ele_addr;
+ uint8_t ele_idx;
+ struct mesh_publication pub;
+
+ int n;
+
+ if (mesh_opcode_get(data, len, &opcode, &n)) {
+ len -= n;
+ data += n;
+ } else
+ return false;
+
+ node = node_get_local_node();
+
+ if (!node)
+ return true;
+
+ switch (opcode & ~OP_UNRELIABLE) {
+ default:
+ return false;
+
+ case OP_CONFIG_DEFAULT_TTL_SET:
+ if (len != 1 || data[0] > TTL_MASK || data[0] == 1)
+ return true;
+
+ if (data[0] <= TTL_MASK) {
+ node_set_default_ttl(node, data[0]);
+ prov_db_node_set_ttl(node, data[0]);
+ }
+
+ /* Fall Through */
+
+ case OP_CONFIG_DEFAULT_TTL_GET:
+ n = mesh_opcode_set(OP_CONFIG_DEFAULT_TTL_STATUS, msg);
+ msg[n++] = node_get_default_ttl(node);
+ break;
+
+ case OP_CONFIG_MODEL_PUB_SET:
+ if (len != 11 && len != 13)
+ return true;
+
+ rl_printf("Set publication\n");
+
+ ele_addr = get_le16(data);
+ mod_id = get_le16(data + 9);
+ if (len == 14)
+ mod_id = (mod_id << 16) | get_le16(data + 11);
+ else
+ mod_id |= 0xffff0000;
+
+ pub.u.addr16 = get_le16(data + 2);
+ pub.app_idx = get_le16(data + 4);
+ pub.ttl = data[6];
+ pub.period = data[7];
+ n = (data[7] & 0x3f);
+ switch (data[7] >> 6) {
+ case 0:
+ rl_printf("Period: %d ms\n", n * 100);
+ break;
+ case 2:
+ n *= 10;
+ /* fall through */
+ case 1:
+ rl_printf("Period: %d sec\n", n);
+ break;
+ case 3:
+ rl_printf("Period: %d min\n", n * 10);
+ break;
+ }
+
+ pub.retransmit = data[8];
+ rl_printf("Retransmit count: %d\n", data[8] >> 5);
+ rl_printf("Retransmit Interval Steps: %d\n", data[8] & 0x1f);
+
+ ele_idx = ele_addr - node_get_primary(node);
+
+ if (node_model_pub_set(node, ele_idx, mod_id, &pub)) {
+ prov_db_node_set_model_pub(node, ele_idx, mod_id,
+ node_model_pub_get(node, ele_idx, mod_id));
+ }
+ break;
+ }
+
+ primary = node_get_primary(node);
+ if (src != primary)
+ net_access_layer_send(node_get_default_ttl(node), primary,
+ src, APP_IDX_DEV, msg, len);
+ return true;
+}
+
+
+static struct mesh_model_ops server_cbs = {
+ server_msg_recvd,
+ NULL,
+ NULL,
+ NULL
+};
+
+bool config_server_init(void)
+{
+ if (!node_local_model_register(PRIMARY_ELEMENT_IDX,
+ CONFIG_SERVER_MODEL_ID,
+ &server_cbs, NULL))
+ return false;
+
+ return true;
+}
diff --git a/mesh/crypto.c b/mesh/crypto.c
new file mode 100644
index 0000000..189624e
--- /dev/null
+++ b/mesh/crypto.c
@@ -0,0 +1,1168 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <linux/if_alg.h>
+
+#include <glib.h>
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+#ifndef ALG_SET_AEAD_AUTHSIZE
+#define ALG_SET_AEAD_AUTHSIZE 5
+#endif
+
+#include "src/shared/util.h"
+#include "mesh-net.h"
+#include "crypto.h"
+
+static int alg_new(int fd, const void *keyval, socklen_t keylen,
+ size_t mic_size)
+{
+ if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, keyval, keylen) < 0) {
+ g_printerr("key");
+ return -1;
+ }
+
+ if (mic_size &&
+ setsockopt(fd, SOL_ALG,
+ ALG_SET_AEAD_AUTHSIZE, NULL, mic_size) < 0) {
+ g_printerr("taglen");
+ return -1;
+ }
+
+ /* FIXME: This should use accept4() with SOCK_CLOEXEC */
+ return accept(fd, NULL, 0);
+}
+
+static bool alg_encrypt(int fd, const void *inbuf, size_t inlen,
+ void *outbuf, size_t outlen)
+{
+ __u32 alg_op = ALG_OP_ENCRYPT;
+ char cbuf[CMSG_SPACE(sizeof(alg_op))];
+ struct cmsghdr *cmsg;
+ struct msghdr msg;
+ struct iovec iov;
+ ssize_t len;
+
+ memset(cbuf, 0, sizeof(cbuf));
+ memset(&msg, 0, sizeof(msg));
+
+ msg.msg_control = cbuf;
+ msg.msg_controllen = sizeof(cbuf);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_ALG;
+ cmsg->cmsg_type = ALG_SET_OP;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(alg_op));
+ memcpy(CMSG_DATA(cmsg), &alg_op, sizeof(alg_op));
+
+ iov.iov_base = (void *) inbuf;
+ iov.iov_len = inlen;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ len = sendmsg(fd, &msg, 0);
+ if (len < 0)
+ return false;
+
+ len = read(fd, outbuf, outlen);
+ if (len < 0)
+ return false;
+
+ return true;
+}
+
+static int aes_ecb_setup(const uint8_t key[16])
+{
+ struct sockaddr_alg salg;
+ int fd, nfd;
+
+ fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return -1;
+
+ memset(&salg, 0, sizeof(salg));
+ salg.salg_family = AF_ALG;
+ strcpy((char *) salg.salg_type, "skcipher");
+ strcpy((char *) salg.salg_name, "ecb(aes)");
+
+ if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ nfd = alg_new(fd, key, 16, 0);
+
+ close(fd);
+
+ return nfd;
+}
+
+static bool aes_ecb(int fd, const uint8_t plaintext[16], uint8_t encrypted[16])
+{
+ return alg_encrypt(fd, plaintext, 16, encrypted, 16);
+}
+
+static void aes_ecb_destroy(int fd)
+{
+ close(fd);
+}
+
+static bool aes_ecb_one(const uint8_t key[16],
+ const uint8_t plaintext[16], uint8_t encrypted[16])
+{
+ bool result;
+ int fd;
+
+ fd = aes_ecb_setup(key);
+ if (fd < 0)
+ return false;
+
+ result = aes_ecb(fd, plaintext, encrypted);
+
+ aes_ecb_destroy(fd);
+
+ return result;
+}
+
+/* Maximum message length that can be passed to aes_cmac */
+#define CMAC_MSG_MAX (64 + 64 + 17)
+
+static int aes_cmac_setup(const uint8_t key[16])
+{
+ struct sockaddr_alg salg;
+ int fd, nfd;
+
+ fd = socket(PF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return -1;
+
+ memset(&salg, 0, sizeof(salg));
+ salg.salg_family = AF_ALG;
+ strcpy((char *) salg.salg_type, "hash");
+ strcpy((char *) salg.salg_name, "cmac(aes)");
+
+ if (bind(fd, (struct sockaddr *) &salg, sizeof(salg)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ nfd = alg_new(fd, key, 16, 0);
+
+ close(fd);
+
+ return nfd;
+}
+
+static bool aes_cmac(int fd, const uint8_t *msg,
+ size_t msg_len, uint8_t res[16])
+{
+ ssize_t len;
+
+ if (msg_len > CMAC_MSG_MAX)
+ return false;
+
+ len = send(fd, msg, msg_len, 0);
+ if (len < 0)
+ return false;
+
+ len = read(fd, res, 16);
+ if (len < 0)
+ return false;
+
+ return true;
+}
+
+static void aes_cmac_destroy(int fd)
+{
+ close(fd);
+}
+
+static int aes_cmac_N_start(const uint8_t N[16])
+{
+ int fd;
+
+ fd = aes_cmac_setup(N);
+ return fd;
+}
+
+static bool aes_cmac_one(const uint8_t key[16], const void *msg,
+ size_t msg_len, uint8_t res[16])
+{
+ bool result;
+ int fd;
+
+ fd = aes_cmac_setup(key);
+ if (fd < 0)
+ return false;
+
+ result = aes_cmac(fd, msg, msg_len, res);
+
+ aes_cmac_destroy(fd);
+
+ return result;
+}
+
+bool mesh_crypto_aes_cmac(const uint8_t key[16], const uint8_t *msg,
+ size_t msg_len, uint8_t res[16])
+{
+ return aes_cmac_one(key, msg, msg_len, res);
+}
+
+bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
+ const uint8_t *aad, uint16_t aad_len,
+ const uint8_t *msg, uint16_t msg_len,
+ uint8_t *out_msg, void *out_mic,
+ size_t mic_size)
+{
+ uint8_t pmsg[16], cmic[16], cmsg[16];
+ uint8_t mic[16], Xn[16];
+ uint16_t blk_cnt, last_blk;
+ bool result;
+ size_t i, j;
+ int fd;
+
+ if (aad_len >= 0xff00) {
+ g_printerr("Unsupported AAD size");
+ return false;
+ }
+
+ fd = aes_ecb_setup(key);
+ if (fd < 0)
+ return false;
+
+ /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
+ pmsg[0] = 0x01;
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(0x0000, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, cmic);
+ if (!result)
+ goto done;
+
+ /* X_0 = e(AppKey, 0x09 || nonce || length) */
+ if (mic_size == sizeof(uint64_t))
+ pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
+ else
+ pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
+
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(msg_len, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+
+ /* If AAD is being used to authenticate, include it here */
+ if (aad_len) {
+ put_be16(aad_len, pmsg);
+
+ for (i = 0; i < sizeof(uint16_t); i++)
+ pmsg[i] = Xn[i] ^ pmsg[i];
+
+ j = 0;
+ aad_len += sizeof(uint16_t);
+ while (aad_len > 16) {
+ do {
+ pmsg[i] = Xn[i] ^ aad[j];
+ i++, j++;
+ } while (i < 16);
+
+ aad_len -= 16;
+ i = 0;
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+ }
+
+ for (i = 0; i < aad_len; i++, j++)
+ pmsg[i] = Xn[i] ^ aad[j];
+
+ for (i = aad_len; i < 16; i++)
+ pmsg[i] = Xn[i];
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+ }
+
+ last_blk = msg_len % 16;
+ blk_cnt = (msg_len + 15) / 16;
+ if (!last_blk)
+ last_blk = 16;
+
+ for (j = 0; j < blk_cnt; j++) {
+ if (j + 1 == blk_cnt) {
+ /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
+ for (i = 0; i < last_blk; i++)
+ pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
+ for (i = last_blk; i < 16; i++)
+ pmsg[i] = Xn[i] ^ 0x00;
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+
+ /* MIC = C_mic ^ X_1 */
+ for (i = 0; i < sizeof(mic); i++)
+ mic[i] = cmic[i] ^ Xn[i];
+
+ /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
+ pmsg[0] = 0x01;
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(j + 1, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, cmsg);
+ if (!result)
+ goto done;
+
+ if (out_msg) {
+ /* Encrypted = Payload[0-15] ^ C_1 */
+ for (i = 0; i < last_blk; i++)
+ out_msg[(j * 16) + i] =
+ msg[(j * 16) + i] ^ cmsg[i];
+
+ }
+ } else {
+ /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
+ for (i = 0; i < 16; i++)
+ pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+
+ /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
+ pmsg[0] = 0x01;
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(j + 1, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, cmsg);
+ if (!result)
+ goto done;
+
+ if (out_msg) {
+ /* Encrypted = Payload[0-15] ^ C_N */
+ for (i = 0; i < 16; i++)
+ out_msg[(j * 16) + i] =
+ msg[(j * 16) + i] ^ cmsg[i];
+ }
+
+ }
+ }
+
+ if (out_msg)
+ memcpy(out_msg + msg_len, mic, mic_size);
+
+ if (out_mic) {
+ switch (mic_size) {
+ case sizeof(uint32_t):
+ *(uint32_t *)out_mic = get_be32(mic);
+ break;
+ case sizeof(uint64_t):
+ *(uint64_t *)out_mic = get_be64(mic);
+ break;
+ default:
+ g_printerr("Unsupported MIC size");
+ }
+ }
+
+done:
+ aes_ecb_destroy(fd);
+
+ return result;
+}
+
+bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
+ const uint8_t *aad, uint16_t aad_len,
+ const uint8_t *enc_msg, uint16_t enc_msg_len,
+ uint8_t *out_msg, void *out_mic,
+ size_t mic_size)
+{
+ uint8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16];
+ uint8_t mic[16];
+ uint16_t msg_len = enc_msg_len - mic_size;
+ uint16_t last_blk, blk_cnt;
+ bool result;
+ size_t i, j;
+ int fd;
+
+ if (enc_msg_len < 5 || aad_len >= 0xff00)
+ return false;
+
+ fd = aes_ecb_setup(key);
+ if (fd < 0)
+ return false;
+
+ /* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
+ pmsg[0] = 0x01;
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(0x0000, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, cmic);
+ if (!result)
+ goto done;
+
+ /* X_0 = e(AppKey, 0x09 || nonce || length) */
+ if (mic_size == sizeof(uint64_t))
+ pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
+ else
+ pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
+
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(msg_len, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+
+ /* If AAD is being used to authenticate, include it here */
+ if (aad_len) {
+ put_be16(aad_len, pmsg);
+
+ for (i = 0; i < sizeof(uint16_t); i++)
+ pmsg[i] = Xn[i] ^ pmsg[i];
+
+ j = 0;
+ aad_len += sizeof(uint16_t);
+ while (aad_len > 16) {
+ do {
+ pmsg[i] = Xn[i] ^ aad[j];
+ i++, j++;
+ } while (i < 16);
+
+ aad_len -= 16;
+ i = 0;
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+ }
+
+ for (i = 0; i < aad_len; i++, j++)
+ pmsg[i] = Xn[i] ^ aad[j];
+
+ for (i = aad_len; i < 16; i++)
+ pmsg[i] = Xn[i];
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+ }
+
+ last_blk = msg_len % 16;
+ blk_cnt = (msg_len + 15) / 16;
+ if (!last_blk)
+ last_blk = 16;
+
+ for (j = 0; j < blk_cnt; j++) {
+ if (j + 1 == blk_cnt) {
+ /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
+ pmsg[0] = 0x01;
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(j + 1, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, cmsg);
+ if (!result)
+ goto done;
+
+ /* Encrypted = Payload[0-15] ^ C_1 */
+ for (i = 0; i < last_blk; i++)
+ msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
+
+ if (out_msg)
+ memcpy(out_msg + (j * 16), msg, last_blk);
+
+ /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
+ for (i = 0; i < last_blk; i++)
+ pmsg[i] = Xn[i] ^ msg[i];
+ for (i = last_blk; i < 16; i++)
+ pmsg[i] = Xn[i] ^ 0x00;
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+
+ /* MIC = C_mic ^ X_1 */
+ for (i = 0; i < sizeof(mic); i++)
+ mic[i] = cmic[i] ^ Xn[i];
+ } else {
+ /* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
+ pmsg[0] = 0x01;
+ memcpy(pmsg + 1, nonce, 13);
+ put_be16(j + 1, pmsg + 14);
+
+ result = aes_ecb(fd, pmsg, cmsg);
+ if (!result)
+ goto done;
+
+ /* Encrypted = Payload[0-15] ^ C_1 */
+ for (i = 0; i < 16; i++)
+ msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
+
+ if (out_msg)
+ memcpy(out_msg + (j * 16), msg, 16);
+
+ /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
+ for (i = 0; i < 16; i++)
+ pmsg[i] = Xn[i] ^ msg[i];
+
+ result = aes_ecb(fd, pmsg, Xn);
+ if (!result)
+ goto done;
+ }
+ }
+
+ switch (mic_size) {
+ case sizeof(uint32_t):
+ if (out_mic)
+ *(uint32_t *)out_mic = get_be32(mic);
+ else if (get_be32(enc_msg + enc_msg_len - mic_size) !=
+ get_be32(mic))
+ result = false;
+ break;
+
+ case sizeof(uint64_t):
+ if (out_mic)
+ *(uint64_t *)out_mic = get_be64(mic);
+ else if (get_be64(enc_msg + enc_msg_len - mic_size) !=
+ get_be64(mic))
+ result = false;
+ break;
+
+ default:
+ g_printerr("Unsupported MIC size");
+ result = false;
+ }
+
+done:
+ aes_ecb_destroy(fd);
+
+ return result;
+}
+
+bool mesh_crypto_k1(const uint8_t ikm[16], const uint8_t salt[16],
+ const void *info, size_t info_len, uint8_t okm[16])
+{
+ uint8_t res[16];
+
+ if (!aes_cmac_one(salt, ikm, 16, res))
+ return false;
+
+ return aes_cmac_one(res, info, info_len, okm);
+}
+
+bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
+ uint8_t net_id[1],
+ uint8_t enc_key[16],
+ uint8_t priv_key[16])
+{
+ int fd;
+ uint8_t output[16];
+ uint8_t t[16];
+ uint8_t *stage;
+ bool success = false;
+
+ stage = g_malloc(sizeof(output) + p_len + 1);
+ if (stage == NULL)
+ return false;
+
+ if (!mesh_crypto_s1("smk2", 4, stage))
+ goto fail;
+
+ if (!aes_cmac_one(stage, n, 16, t))
+ goto fail;
+
+ fd = aes_cmac_N_start(t);
+ if (fd < 0)
+ goto fail;
+
+ memcpy(stage, p, p_len);
+ stage[p_len] = 1;
+
+ if(!aes_cmac(fd, stage, p_len + 1, output))
+ goto done;
+
+ net_id[0] = output[15] & 0x7f;
+
+ memcpy(stage, output, 16);
+ memcpy(stage + 16, p, p_len);
+ stage[p_len + 16] = 2;
+
+ if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
+ goto done;
+
+ memcpy(enc_key, output, 16);
+
+ memcpy(stage, output, 16);
+ memcpy(stage + 16, p, p_len);
+ stage[p_len + 16] = 3;
+
+ if(!aes_cmac(fd, stage, p_len + 16 + 1, output))
+ goto done;
+
+ memcpy(priv_key, output, 16);
+ success = true;
+
+done:
+ aes_cmac_destroy(fd);
+fail:
+ g_free(stage);
+
+ return success;
+}
+
+static bool crypto_128(const uint8_t n[16], const char *s, uint8_t out128[16])
+{
+ uint8_t id128[] = { 'i', 'd', '1', '2', '8', 0x01 };
+ uint8_t salt[16];
+
+ if (!mesh_crypto_s1(s, 4, salt))
+ return false;
+
+ return mesh_crypto_k1(n, salt, id128, sizeof(id128), out128);
+}
+
+bool mesh_crypto_nkik(const uint8_t n[16], uint8_t identity_key[16])
+{
+ return crypto_128(n, "nkik", identity_key);
+}
+
+static bool identity_calc(const uint8_t net_key[16], uint16_t addr,
+ bool check, uint8_t id[16])
+{
+ uint8_t id_key[16];
+ uint8_t tmp[16];
+
+ if (!mesh_crypto_nkik(net_key, id_key))
+ return false;
+
+ memset(tmp, 0, sizeof(tmp));
+ put_be16(addr, tmp + 14);
+
+ if (check) {
+ memcpy(tmp + 6, id + 8, 8);
+ } else {
+ mesh_get_random_bytes(tmp + 6, 8);
+ memcpy(id + 8, tmp + 6, 8);
+ }
+
+ if (!aes_ecb_one(id_key, tmp, tmp))
+ return false;
+
+ if (check)
+ return (memcmp(id, tmp + 8, 8) == 0);
+
+ memcpy(id, tmp + 8, 8);
+ return true;
+}
+
+bool mesh_crypto_identity(const uint8_t net_key[16], uint16_t addr,
+ uint8_t id[16])
+{
+ return identity_calc(net_key, addr, false, id);
+}
+
+bool mesh_crypto_identity_check(const uint8_t net_key[16], uint16_t addr,
+ uint8_t id[16])
+{
+ return identity_calc(net_key, addr, true, id);
+}
+
+bool mesh_crypto_nkbk(const uint8_t n[16], uint8_t beacon_key[16])
+{
+ return crypto_128(n, "nkbk", beacon_key);
+}
+
+bool mesh_crypto_k3(const uint8_t n[16], uint8_t out64[8])
+{
+ uint8_t tmp[16];
+ uint8_t t[16];
+ uint8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
+
+ if (!mesh_crypto_s1("smk3", 4, tmp))
+ return false;
+
+ if (!aes_cmac_one(tmp, n, 16, t))
+ return false;
+
+ if (!aes_cmac_one(t, id64, sizeof(id64), tmp))
+ return false;
+
+ memcpy(out64, tmp + 8, 8);
+
+ return true;
+}
+
+bool mesh_crypto_k4(const uint8_t a[16], uint8_t out6[1])
+{
+ uint8_t tmp[16];
+ uint8_t t[16];
+ uint8_t id6[] = { 'i', 'd', '6', 0x01 };
+
+ if (!mesh_crypto_s1("smk4", 4, tmp))
+ return false;
+
+ if (!aes_cmac_one(tmp, a, 16, t))
+ return false;
+
+ if (!aes_cmac_one(t, id6, sizeof(id6), tmp))
+ return false;
+
+ out6[0] = tmp[15] & 0x3f;
+ return true;
+}
+
+bool mesh_crypto_beacon_cmac(const uint8_t encryption_key[16],
+ const uint8_t network_id[8],
+ uint32_t iv_index, bool kr, bool iu,
+ uint64_t *cmac)
+{
+ uint8_t msg[13], tmp[16];
+
+ if (!cmac)
+ return false;
+
+ msg[0] = kr ? 0x01 : 0x00;
+ msg[0] |= iu ? 0x02 : 0x00;
+ memcpy(msg + 1, network_id, 8);
+ put_be32(iv_index, msg + 9);
+
+ if (!aes_cmac_one(encryption_key, msg, 13, tmp))
+ return false;
+
+ *cmac = get_be64(tmp);
+
+ return true;
+}
+
+bool mesh_crypto_network_nonce(bool ctl, uint8_t ttl, uint32_t seq,
+ uint16_t src, uint32_t iv_index,
+ uint8_t nonce[13])
+{
+ nonce[0] = 0;
+ nonce[1] = (ttl & TTL_MASK) | (ctl ? CTL : 0x00);
+ nonce[2] = (seq >> 16) & 0xff;
+ nonce[3] = (seq >> 8) & 0xff;
+ nonce[4] = seq & 0xff;
+
+ /* SRC */
+ put_be16(src, nonce + 5);
+
+ put_be16(0, nonce + 7);
+
+ /* IV Index */
+ put_be32(iv_index, nonce + 9);
+
+ return true;
+}
+
+bool mesh_crypto_network_encrypt(bool ctl, uint8_t ttl,
+ uint32_t seq, uint16_t src,
+ uint32_t iv_index,
+ const uint8_t net_key[16],
+ const uint8_t *enc_msg, uint8_t enc_msg_len,
+ uint8_t *out, void *net_mic)
+{
+ uint8_t nonce[13];
+
+ if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
+ return false;
+
+ return mesh_crypto_aes_ccm_encrypt(nonce, net_key,
+ NULL, 0, enc_msg,
+ enc_msg_len, out,
+ net_mic,
+ ctl ? sizeof(uint64_t) : sizeof(uint32_t));
+}
+
+bool mesh_crypto_network_decrypt(bool ctl, uint8_t ttl,
+ uint32_t seq, uint16_t src,
+ uint32_t iv_index,
+ const uint8_t net_key[16],
+ const uint8_t *enc_msg, uint8_t enc_msg_len,
+ uint8_t *out, void *net_mic, size_t mic_size)
+{
+ uint8_t nonce[13];
+
+ if (!mesh_crypto_network_nonce(ctl, ttl, seq, src, iv_index, nonce))
+ return false;
+
+ return mesh_crypto_aes_ccm_decrypt(nonce, net_key, NULL, 0,
+ enc_msg, enc_msg_len, out,
+ net_mic, mic_size);
+}
+
+bool mesh_crypto_application_nonce(uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ bool aszmic, uint8_t nonce[13])
+{
+ nonce[0] = 0x01;
+ nonce[1] = aszmic ? 0x80 : 0x00;
+ nonce[2] = (seq & 0x00ff0000) >> 16;
+ nonce[3] = (seq & 0x0000ff00) >> 8;
+ nonce[4] = (seq & 0x000000ff);
+ nonce[5] = (src & 0xff00) >> 8;
+ nonce[6] = (src & 0x00ff);
+ nonce[7] = (dst & 0xff00) >> 8;
+ nonce[8] = (dst & 0x00ff);
+ put_be32(iv_index, nonce + 9);
+
+ return true;
+}
+
+bool mesh_crypto_device_nonce(uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ bool aszmic, uint8_t nonce[13])
+{
+ nonce[0] = 0x02;
+ nonce[1] = aszmic ? 0x80 : 0x00;
+ nonce[2] = (seq & 0x00ff0000) >> 16;
+ nonce[3] = (seq & 0x0000ff00) >> 8;
+ nonce[4] = (seq & 0x000000ff);
+ nonce[5] = (src & 0xff00) >> 8;
+ nonce[6] = (src & 0x00ff);
+ nonce[7] = (dst & 0xff00) >> 8;
+ nonce[8] = (dst & 0x00ff);
+ put_be32(iv_index, nonce + 9);
+
+ return true;
+}
+
+bool mesh_crypto_application_encrypt(uint8_t key_id, uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ const uint8_t app_key[16],
+ const uint8_t *aad, uint8_t aad_len,
+ const uint8_t *msg, uint8_t msg_len,
+ uint8_t *out, void *app_mic,
+ size_t mic_size)
+{
+ uint8_t nonce[13];
+ bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
+
+ if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
+ iv_index, aszmic, nonce))
+ return false;
+
+ if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
+ iv_index, aszmic, nonce))
+ return false;
+
+ return mesh_crypto_aes_ccm_encrypt(nonce, app_key, aad, aad_len,
+ msg, msg_len,
+ out, app_mic, mic_size);
+}
+
+bool mesh_crypto_application_decrypt(uint8_t key_id, uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ const uint8_t app_key[16],
+ const uint8_t *aad, uint8_t aad_len,
+ const uint8_t *enc_msg, uint8_t enc_msg_len,
+ uint8_t *out, void *app_mic, size_t mic_size)
+{
+ uint8_t nonce[13];
+ bool aszmic = (mic_size == sizeof(uint64_t)) ? true : false;
+
+ if (!key_id && !mesh_crypto_device_nonce(seq, src, dst,
+ iv_index, aszmic, nonce))
+ return false;
+
+ if (key_id && !mesh_crypto_application_nonce(seq, src, dst,
+ iv_index, aszmic, nonce))
+ return false;
+
+ return mesh_crypto_aes_ccm_decrypt(nonce, app_key,
+ aad, aad_len, enc_msg,
+ enc_msg_len, out,
+ app_mic, mic_size);
+}
+
+bool mesh_crypto_session_key(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t session_key[16])
+{
+ const uint8_t prsk[4] = "prsk";
+
+ if (!aes_cmac_one(salt, secret, 32, session_key))
+ return false;
+
+ return aes_cmac_one(session_key, prsk, 4, session_key);
+}
+
+bool mesh_crypto_nonce(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t nonce[13])
+{
+ const uint8_t prsn[4] = "prsn";
+ uint8_t tmp[16];
+ bool result;
+
+ if (!aes_cmac_one(salt, secret, 32, tmp))
+ return false;
+
+ result = aes_cmac_one(tmp, prsn, 4, tmp);
+
+ if (result)
+ memcpy(nonce, tmp + 3, 13);
+
+ return result;
+}
+
+bool mesh_crypto_s1(const void *info, size_t len, uint8_t salt[16])
+{
+ const uint8_t zero[16] = {0};
+
+ return aes_cmac_one(zero, info, len, salt);
+}
+
+bool mesh_crypto_prov_prov_salt(const uint8_t conf_salt[16],
+ const uint8_t prov_rand[16],
+ const uint8_t dev_rand[16],
+ uint8_t prov_salt[16])
+{
+ const uint8_t zero[16] = {0};
+ uint8_t tmp[16 * 3];
+
+ memcpy(tmp, conf_salt, 16);
+ memcpy(tmp + 16, prov_rand, 16);
+ memcpy(tmp + 32, dev_rand, 16);
+
+ return aes_cmac_one(zero, tmp, sizeof(tmp), prov_salt);
+}
+
+bool mesh_crypto_prov_conf_key(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t conf_key[16])
+{
+ const uint8_t prck[4] = "prck";
+
+ if (!aes_cmac_one(salt, secret, 32, conf_key))
+ return false;
+
+ return aes_cmac_one(conf_key, prck, 4, conf_key);
+}
+
+bool mesh_crypto_device_key(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t device_key[16])
+{
+ const uint8_t prdk[4] = "prdk";
+
+ if (!aes_cmac_one(salt, secret, 32, device_key))
+ return false;
+
+ return aes_cmac_one(device_key, prdk, 4, device_key);
+}
+
+bool mesh_crypto_virtual_addr(const uint8_t virtual_label[16],
+ uint16_t *addr)
+{
+ uint8_t tmp[16];
+
+ if (!mesh_crypto_s1("vtad", 4, tmp))
+ return false;
+
+ if (!addr || !aes_cmac_one(tmp, virtual_label, 16, tmp))
+ return false;
+
+ *addr = (get_be16(tmp + 14) & 0x3fff) | 0x8000;
+
+ return true;
+}
+
+bool mesh_crypto_packet_encode(uint8_t *packet, uint8_t packet_len,
+ const uint8_t network_key[16],
+ uint32_t iv_index,
+ const uint8_t privacy_key[16])
+{
+ uint8_t network_nonce[13] = { 0x00, 0x00 };
+ uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
+ uint8_t tmp[16];
+ int i;
+
+ /* Detect Proxy packet by CTL == true && DST == 0x0000 */
+ if ((packet[1] & CTL) && get_be16(packet + 7) == 0)
+ network_nonce[0] = 0x03;
+ else
+ /* CTL + TTL */
+ network_nonce[1] = packet[1];
+
+ /* Seq Num */
+ network_nonce[2] = packet[2];
+ network_nonce[3] = packet[3];
+ network_nonce[4] = packet[4];
+
+ /* SRC */
+ network_nonce[5] = packet[5];
+ network_nonce[6] = packet[6];
+
+ /* DST not available */
+ network_nonce[7] = 0;
+ network_nonce[8] = 0;
+
+ /* IV Index */
+ put_be32(iv_index, network_nonce + 9);
+
+ /* Check for Long net-MIC */
+ if (packet[1] & CTL) {
+ if (!mesh_crypto_aes_ccm_encrypt(network_nonce, network_key,
+ NULL, 0,
+ packet + 7, packet_len - 7 - 8,
+ packet + 7, NULL, sizeof(uint64_t)))
+ return false;
+ } else {
+ if (!mesh_crypto_aes_ccm_encrypt(network_nonce, network_key,
+ NULL, 0,
+ packet + 7, packet_len - 7 - 4,
+ packet + 7, NULL, sizeof(uint32_t)))
+ return false;
+ }
+
+ put_be32(iv_index, privacy_counter + 5);
+ memcpy(privacy_counter + 9, packet + 7, 7);
+
+ if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
+ return false;
+
+ for (i = 0; i < 6; i++)
+ packet[1 + i] ^= tmp[i];
+
+ return true;
+}
+
+bool mesh_crypto_packet_decode(const uint8_t *packet, uint8_t packet_len,
+ bool proxy, uint8_t *out, uint32_t iv_index,
+ const uint8_t network_key[16],
+ const uint8_t privacy_key[16])
+{
+ uint8_t privacy_counter[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
+ uint8_t network_nonce[13] = { 0x00, 0x00, };
+ uint8_t tmp[16];
+ uint16_t src;
+ int i;
+
+ if (packet_len < 14)
+ return false;
+
+ put_be32(iv_index, privacy_counter + 5);
+ memcpy(privacy_counter + 9, packet + 7, 7);
+
+ if (!aes_ecb_one(privacy_key, privacy_counter, tmp))
+ return false;
+
+ memcpy(out, packet, packet_len);
+ for (i = 0; i < 6; i++)
+ out[1 + i] ^= tmp[i];
+
+ src = get_be16(out + 5);
+
+ /* Pre-check SRC address for illegal values */
+ if (!src || src >= 0x8000)
+ return false;
+
+ /* Detect Proxy packet by CTL == true && proxy == true */
+ if ((out[1] & CTL) && proxy)
+ network_nonce[0] = 0x03;
+ else
+ /* CTL + TTL */
+ network_nonce[1] = out[1];
+
+ /* Seq Num */
+ network_nonce[2] = out[2];
+ network_nonce[3] = out[3];
+ network_nonce[4] = out[4];
+
+ /* SRC */
+ network_nonce[5] = out[5];
+ network_nonce[6] = out[6];
+
+ /* DST not available */
+ network_nonce[7] = 0;
+ network_nonce[8] = 0;
+
+ /* IV Index */
+ put_be32(iv_index, network_nonce + 9);
+
+ /* Check for Long MIC */
+ if (out[1] & CTL) {
+ uint64_t mic;
+
+ if (!mesh_crypto_aes_ccm_decrypt(network_nonce, network_key,
+ NULL, 0, packet + 7, packet_len - 7,
+ out + 7, &mic, sizeof(mic)))
+ return false;
+
+ mic ^= get_be64(out + packet_len - 8);
+ put_be64(mic, out + packet_len - 8);
+
+ if (mic)
+ return false;
+ } else {
+ uint32_t mic;
+
+ if (!mesh_crypto_aes_ccm_decrypt(network_nonce, network_key,
+ NULL, 0, packet + 7, packet_len - 7,
+ out + 7, &mic, sizeof(mic)))
+ return false;
+
+ mic ^= get_be32(out + packet_len - 4);
+ put_be32(mic, out + packet_len - 4);
+
+ if (mic)
+ return false;
+ }
+
+ return true;
+}
+
+bool mesh_get_random_bytes(void *buf, size_t num_bytes)
+{
+ ssize_t len;
+ int fd;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ return false;
+
+ len = read(fd, buf, num_bytes);
+
+ close(fd);
+
+ if (len < 0)
+ return false;
+
+ return true;
+}
diff --git a/mesh/gatt.c b/mesh/gatt.c
new file mode 100644
index 0000000..b981054
--- /dev/null
+++ b/mesh/gatt.c
@@ -0,0 +1,609 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <wordexp.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "src/shared/io.h"
+#include "gdbus/gdbus.h"
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+#include "client/display.h"
+#include "node.h"
+#include "util.h"
+#include "gatt.h"
+#include "prov.h"
+#include "net.h"
+
+#define MESH_PROV_DATA_OUT_UUID_STR "00002adc-0000-1000-8000-00805f9b34fb"
+#define MESH_PROXY_DATA_OUT_UUID_STR "00002ade-0000-1000-8000-00805f9b34fb"
+
+static struct io *write_io;
+static uint16_t write_mtu;
+
+static struct io *notify_io;
+static uint16_t notify_mtu;
+
+struct write_data {
+ GDBusProxy *proxy;
+ void *user_data;
+ struct iovec iov;
+ GDBusReturnFunction cb;
+ uint8_t *gatt_data;
+ uint8_t gatt_len;
+};
+
+struct notify_data {
+ GDBusProxy *proxy;
+ bool enable;
+ GDBusReturnFunction cb;
+ void *user_data;
+};
+
+bool mesh_gatt_is_child(GDBusProxy *proxy, GDBusProxy *parent,
+ const char *name)
+{
+ DBusMessageIter iter;
+ const char *parent_path;
+
+ if (!parent)
+ return FALSE;
+
+ if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &parent_path);
+
+ if (!strcmp(parent_path, g_dbus_proxy_get_path(parent)))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Refactor this once actual MTU is available */
+#define GATT_MTU 23
+
+static void write_data_free(void *user_data)
+{
+ struct write_data *data = user_data;
+
+ g_free(data->gatt_data);
+ free(data);
+}
+
+static void write_setup(DBusMessageIter *iter, void *user_data)
+{
+ struct write_data *data = user_data;
+ struct iovec *iov = &data->iov;
+ DBusMessageIter array, dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+ &iov->iov_base, iov->iov_len);
+ dbus_message_iter_close_container(iter, &array);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &dict);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+uint16_t mesh_gatt_sar(uint8_t **pkt, uint16_t size)
+{
+ const uint8_t *data = *pkt;
+ uint8_t gatt_hdr = *data++;
+ uint8_t type = gatt_hdr & GATT_TYPE_MASK;
+ static uint8_t gatt_size;
+ static uint8_t gatt_pkt[67];
+
+ print_byte_array("GATT-RX:\t", *pkt, size);
+ if (size < 1) {
+ gatt_pkt[0] = GATT_TYPE_INVALID;
+ /* TODO: Disconnect GATT per last paragraph sec 6.6 */
+ return 0;
+ }
+
+ size--;
+
+ switch (gatt_hdr & GATT_SAR_MASK) {
+ case GATT_SAR_FIRST:
+ gatt_size = 1;
+ gatt_pkt[0] = type;
+ /* TODO: Start Proxy Timeout */
+ /* fall through */
+
+ case GATT_SAR_CONTINUE:
+ if (gatt_pkt[0] != type ||
+ gatt_size + size > MAX_GATT_SIZE) {
+
+ /* Invalidate packet and return failure */
+ gatt_pkt[0] = GATT_TYPE_INVALID;
+ /* TODO: Disconnect GATT per last paragraph sec 6.6 */
+ return 0;
+ }
+
+ memcpy(gatt_pkt + gatt_size, data, size);
+ gatt_size += size;
+
+ /* We are good to this point, but incomplete */
+ return 0;
+
+ default:
+ case GATT_SAR_COMPLETE:
+ gatt_size = 1;
+ gatt_pkt[0] = type;
+
+ /* fall through */
+
+ case GATT_SAR_LAST:
+ if (gatt_pkt[0] != type ||
+ gatt_size + size > MAX_GATT_SIZE) {
+
+ /* Invalidate packet and return failure */
+ gatt_pkt[0] = GATT_TYPE_INVALID;
+ /* Disconnect GATT per last paragraph sec 6.6 */
+ return 0;
+ }
+
+ memcpy(gatt_pkt + gatt_size, data, size);
+ gatt_size += size;
+ *pkt = gatt_pkt;
+ return gatt_size;
+ }
+}
+
+static bool pipe_write(struct io *io, void *user_data)
+{
+ struct write_data *data = user_data;
+ struct iovec iov[2];
+ uint8_t sar;
+ uint8_t max_len = write_mtu - 4;
+
+ if (data == NULL)
+ return true;
+
+ print_byte_array("GATT-TX:\t", data->gatt_data, data->gatt_len);
+
+ sar = data->gatt_data[0];
+
+ data->iov.iov_base = data->gatt_data + 1;
+ data->iov.iov_len--;
+
+ iov[0].iov_base = &sar;
+ iov[0].iov_len = sizeof(sar);
+
+ while (1) {
+ int err;
+
+ iov[1] = data->iov;
+
+ err = io_send(io, iov, 2);
+ if (err < 0) {
+ rl_printf("Failed to write: %s\n", strerror(-err));
+ write_data_free(data);
+ return false;
+ }
+
+ switch (sar & GATT_SAR_MASK) {
+ case GATT_SAR_FIRST:
+ case GATT_SAR_CONTINUE:
+ data->gatt_len -= max_len;
+ data->iov.iov_base = data->iov.iov_base + max_len;
+
+ sar &= GATT_TYPE_MASK;
+ if (max_len < data->gatt_len) {
+ data->iov.iov_len = max_len;
+ sar |= GATT_SAR_CONTINUE;
+ } else {
+ data->iov.iov_len = data->gatt_len;
+ sar |= GATT_SAR_LAST;
+ }
+
+ break;
+
+ default:
+ if(data->cb)
+ data->cb(NULL, data->user_data);
+ write_data_free(data);
+ return true;
+ }
+ }
+}
+
+static void write_reply(DBusMessage *message, void *user_data)
+{
+ struct write_data *data = user_data;
+ struct write_data *tmp;
+ uint8_t *dptr = data->gatt_data;
+ uint8_t max_len = GATT_MTU - 3;
+ uint8_t max_seg = GATT_MTU - 4;
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to write: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ if (data == NULL)
+ return;
+
+ switch (data->gatt_data[0] & GATT_SAR_MASK) {
+ case GATT_SAR_FIRST:
+ case GATT_SAR_CONTINUE:
+ tmp = g_new0(struct write_data, 1);
+ if (!data)
+ return;
+
+ *tmp = *data;
+ tmp->gatt_data = g_malloc(data->gatt_len);
+
+ if (!tmp->gatt_data) {
+ g_free(tmp);
+ return;
+ }
+
+ tmp->gatt_data[0] = dptr[0];
+ data = tmp;
+ memcpy(data->gatt_data + 1, dptr + max_len,
+ data->gatt_len - max_seg);
+ data->gatt_len -= max_seg;
+ data->gatt_data[0] &= GATT_TYPE_MASK;
+ data->iov.iov_base = data->gatt_data;
+ if (max_len < data->gatt_len) {
+ data->iov.iov_len = max_len;
+ data->gatt_data[0] |= GATT_SAR_CONTINUE;
+ } else {
+ data->iov.iov_len = data->gatt_len;
+ data->gatt_data[0] |= GATT_SAR_LAST;
+ }
+
+ break;
+
+ default:
+ if(data->cb)
+ data->cb(message, data->user_data);
+ return;
+ }
+
+ if (g_dbus_proxy_method_call(data->proxy, "WriteValue", write_setup,
+ write_reply, data, write_data_free) == FALSE) {
+ rl_printf("Failed to write\n");
+ write_data_free(data);
+ return;
+ }
+
+}
+
+static void write_io_destroy(void)
+{
+ io_destroy(write_io);
+ write_io = NULL;
+ write_mtu = 0;
+}
+
+static void notify_io_destroy(void)
+{
+ io_destroy(notify_io);
+ notify_io = NULL;
+ notify_mtu = 0;
+}
+
+static bool pipe_hup(struct io *io, void *user_data)
+{
+ rl_printf("%s closed\n", io == notify_io ? "Notify" : "Write");
+
+ if (io == notify_io)
+ notify_io_destroy();
+ else
+ write_io_destroy();
+
+ return false;
+}
+
+static struct io *pipe_io_new(int fd)
+{
+ struct io *io;
+
+ io = io_new(fd);
+
+ io_set_close_on_destroy(io, true);
+
+ io_set_disconnect_handler(io, pipe_hup, NULL, NULL);
+
+ return io;
+}
+
+static void acquire_write_reply(DBusMessage *message, void *user_data)
+{
+ struct write_data *data = user_data;
+ DBusError error;
+ int fd;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ dbus_error_free(&error);
+ if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
+ write_setup, write_reply, data,
+ write_data_free) == FALSE) {
+ rl_printf("Failed to write\n");
+ write_data_free(data);
+ }
+ return;
+ }
+
+ if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
+ DBUS_TYPE_UINT16, &write_mtu,
+ DBUS_TYPE_INVALID) == false)) {
+ rl_printf("Invalid AcquireWrite response\n");
+ return;
+ }
+
+ rl_printf("AcquireWrite success: fd %d MTU %u\n", fd, write_mtu);
+
+ write_io = pipe_io_new(fd);
+
+ pipe_write(write_io, data);
+}
+
+bool mesh_gatt_write(GDBusProxy *proxy, uint8_t *buf, uint16_t len,
+ GDBusReturnFunction cb, void *user_data)
+{
+ struct write_data *data;
+ DBusMessageIter iter;
+ uint8_t max_len;
+
+ if (!buf || !len)
+ return false;
+
+ if (len > 69)
+ return false;
+
+ data = g_new0(struct write_data, 1);
+ if (!data)
+ return false;
+
+ max_len = write_mtu ? write_mtu - 3 : GATT_MTU - 3;
+
+ /* TODO: should keep in queue in case we need to cancel write? */
+
+ data->gatt_len = len;
+ data->gatt_data = g_memdup(buf, len);
+ data->gatt_data[0] &= GATT_TYPE_MASK;
+ if (max_len < len) {
+ len = max_len;
+ data->gatt_data[0] |= GATT_SAR_FIRST;
+ }
+ data->iov.iov_base = data->gatt_data;
+ data->iov.iov_len = len;
+ data->proxy = proxy;
+ data->user_data = user_data;
+ data->cb = cb;
+
+ if (write_io)
+ return pipe_write(write_io, data);
+
+ if (g_dbus_proxy_get_property(proxy, "WriteAcquired", &iter)) {
+ if (g_dbus_proxy_method_call(proxy, "AcquireWrite", NULL,
+ acquire_write_reply, data, NULL) == FALSE) {
+ rl_printf("Failed to AcquireWrite\n");
+ write_data_free(data);
+ return false;
+ }
+ } else {
+ if (g_dbus_proxy_method_call(data->proxy, "WriteValue",
+ write_setup, write_reply, data,
+ write_data_free) == FALSE) {
+ rl_printf("Failed to write\n");
+ write_data_free(data);
+ return false;
+ }
+ print_byte_array("GATT-TX: ", buf, len);
+ rl_printf("Attempting to write %s\n",
+ g_dbus_proxy_get_path(proxy));
+ }
+
+ return true;
+}
+
+static void notify_reply(DBusMessage *message, void *user_data)
+{
+ struct notify_data *data = user_data;
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to %s notify: %s\n",
+ data->enable ? "start" : "stop", error.name);
+ dbus_error_free(&error);
+ goto done;
+ }
+
+ rl_printf("Notify %s\n", data->enable ? "started" : "stopped");
+
+done:
+ if (data->cb)
+ data->cb(message, data->user_data);
+
+ g_free(data);
+}
+
+static bool pipe_read(struct io *io, bool prov, void *user_data)
+{
+ struct mesh_node *node = user_data;
+ uint8_t buf[512];
+ uint8_t *res;
+ int fd = io_get_fd(io);
+ ssize_t len;
+
+ if (io != notify_io)
+ return true;
+
+ while ((len = read(fd, buf, sizeof(buf)))) {
+ if (len <= 0)
+ break;
+
+ res = buf;
+ mesh_gatt_sar(&res, len);
+
+ if (prov)
+ prov_data_ready(node, res, len);
+ else
+ net_data_ready(res, len);
+ }
+
+ return true;
+}
+
+static bool pipe_read_prov(struct io *io, void *user_data)
+{
+ return pipe_read(io, true, user_data);
+}
+
+static bool pipe_read_proxy(struct io *io, void *user_data)
+{
+ return pipe_read(io, false, user_data);
+}
+
+static void acquire_notify_reply(DBusMessage *message, void *user_data)
+{
+ struct notify_data *data = user_data;
+ DBusMessageIter iter;
+ DBusError error;
+ int fd;
+ const char *uuid;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ dbus_error_free(&error);
+ if (g_dbus_proxy_method_call(data->proxy, "StartNotify", NULL,
+ notify_reply, data, NULL) == FALSE) {
+ rl_printf("Failed to StartNotify\n");
+ g_free(data);
+ }
+ return;
+ }
+
+ if (notify_io) {
+ io_destroy(notify_io);
+ notify_io = NULL;
+ }
+
+ notify_mtu = 0;
+
+ if ((dbus_message_get_args(message, NULL, DBUS_TYPE_UNIX_FD, &fd,
+ DBUS_TYPE_UINT16, &notify_mtu,
+ DBUS_TYPE_INVALID) == false)) {
+ if (g_dbus_proxy_method_call(data->proxy, "StartNotify", NULL,
+ notify_reply, data, NULL) == FALSE) {
+ rl_printf("Failed to StartNotify\n");
+ g_free(data);
+ }
+ return;
+ }
+
+ rl_printf("AcquireNotify success: fd %d MTU %u\n", fd, notify_mtu);
+
+ if (g_dbus_proxy_get_property(data->proxy, "UUID", &iter) == FALSE)
+ goto done;
+
+ notify_io = pipe_io_new(fd);
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
+ io_set_read_handler(notify_io, pipe_read_prov, data->user_data,
+ NULL);
+ else if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
+ io_set_read_handler(notify_io, pipe_read_proxy, data->user_data,
+ NULL);
+
+done:
+ if (data->cb)
+ data->cb(message, data->user_data);
+
+ g_free(data);
+}
+
+bool mesh_gatt_notify(GDBusProxy *proxy, bool enable, GDBusReturnFunction cb,
+ void *user_data)
+{
+ struct notify_data *data;
+ DBusMessageIter iter;
+ const char *method;
+
+ data = g_new0(struct notify_data, 1);
+ data->proxy = proxy;
+ data->enable = enable;
+ data->cb = cb;
+ data->user_data = user_data;
+
+ if (enable == TRUE) {
+ if (g_dbus_proxy_get_property(proxy, "NotifyAcquired", &iter)) {
+ method = "AcquireNotify";
+ cb = acquire_notify_reply;
+ } else {
+ method = "StartNotify";
+ cb = notify_reply;
+ }
+ } else {
+ if (notify_io) {
+ notify_io_destroy();
+ if (cb)
+ cb(NULL, user_data);
+ return true;
+ } else {
+ method = "StopNotify";
+ cb = notify_reply;
+ }
+ }
+
+ if (g_dbus_proxy_method_call(proxy, method, NULL, cb,
+ data, NULL) == FALSE) {
+ rl_printf("Failed to %s\n", method);
+ return false;
+ }
+ return true;
+}
diff --git a/mesh/main.c b/mesh/main.c
new file mode 100644
index 0000000..a347484
--- /dev/null
+++ b/mesh/main.c
@@ -0,0 +1,2269 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+#include <wordexp.h>
+
+#include <inttypes.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include "bluetooth/bluetooth.h"
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+#include "src/shared/util.h"
+#include "gdbus/gdbus.h"
+#include "monitor/uuid.h"
+#include "client/display.h"
+#include "mesh-net.h"
+#include "gatt.h"
+#include "crypto.h"
+#include "node.h"
+#include "net.h"
+#include "keys.h"
+#include "prov.h"
+#include "util.h"
+#include "agent.h"
+#include "prov-db.h"
+#include "config-model.h"
+#include "onoff-model.h"
+
+/* String display constants */
+#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
+#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
+#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
+
+#define PROMPT_ON COLOR_BLUE "[meshctl]" COLOR_OFF "# "
+#define PROMPT_OFF "Waiting to connect to bluetoothd..."
+
+#define MESH_PROV_DATA_IN_UUID_STR "00002adb-0000-1000-8000-00805f9b34fb"
+#define MESH_PROV_DATA_OUT_UUID_STR "00002adc-0000-1000-8000-00805f9b34fb"
+#define MESH_PROXY_DATA_IN_UUID_STR "00002add-0000-1000-8000-00805f9b34fb"
+#define MESH_PROXY_DATA_OUT_UUID_STR "00002ade-0000-1000-8000-00805f9b34fb"
+
+static GMainLoop *main_loop;
+static DBusConnection *dbus_conn;
+
+struct adapter {
+GDBusProxy *proxy;
+ GList *mesh_devices;
+};
+
+struct mesh_device {
+ GDBusProxy *proxy;
+ uint8_t dev_uuid[16];
+ gboolean hide;
+};
+
+GList *service_list;
+GList *char_list;
+
+static GList *ctrl_list;
+static struct adapter *default_ctrl;
+
+static char *mesh_prov_db_filename;
+static char *mesh_local_config_filename;
+
+static bool discovering = false;
+static bool discover_mesh;
+static uint16_t prov_net_key_index = NET_IDX_PRIMARY;
+
+static guint input = 0;
+
+#define CONN_TYPE_NETWORK 0x00
+#define CONN_TYPE_IDENTITY 0x01
+#define CONN_TYPE_PROVISION 0x02
+#define CONN_TYPE_INVALID 0xff
+
+#define NET_IDX_INVALID 0xffff
+
+struct {
+ GDBusProxy *device;
+ GDBusProxy *service;
+ GDBusProxy *data_in;
+ GDBusProxy *data_out;
+ bool session_open;
+ uint16_t unicast;
+ uint16_t net_idx;
+ uint8_t dev_uuid[16];
+ uint8_t type;
+} connection;
+
+static bool service_is_mesh(GDBusProxy *proxy, const char *target_uuid)
+{
+ DBusMessageIter iter;
+ const char *uuid;
+
+ if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+ return false;
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (target_uuid)
+ return (!bt_uuid_strcmp(uuid, target_uuid));
+ else if (bt_uuid_strcmp(uuid, MESH_PROV_SVC_UUID) ||
+ bt_uuid_strcmp(uuid, MESH_PROXY_SVC_UUID))
+ return true;
+ else
+ return false;
+}
+
+static bool char_is_mesh(GDBusProxy *proxy, const char *target_uuid)
+{
+ DBusMessageIter iter;
+ const char *uuid;
+
+ if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+ return false;
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (target_uuid)
+ return (!bt_uuid_strcmp(uuid, target_uuid));
+
+ if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_IN_UUID_STR))
+ return true;
+
+ if (!bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR))
+ return true;
+
+ if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_IN_UUID_STR))
+ return true;
+
+ if (!bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
+ return true;
+
+ return false;
+}
+
+static gboolean check_default_ctrl(void)
+{
+ if (!default_ctrl) {
+ rl_printf("No default controller available\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void proxy_leak(gpointer data)
+{
+ rl_printf("Leaking proxy %p\n", data);
+}
+
+static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ if (condition & G_IO_IN) {
+ rl_callback_read_char();
+ return TRUE;
+ }
+
+ if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ g_main_loop_quit(main_loop);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static guint setup_standard_input(void)
+{
+ GIOChannel *channel;
+ guint source;
+
+ channel = g_io_channel_unix_new(fileno(stdin));
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ input_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+ rl_set_prompt(PROMPT_ON);
+ rl_printf("\r");
+ rl_on_new_line();
+ rl_redisplay();
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+ if (input > 0) {
+ g_source_remove(input);
+ input = 0;
+ }
+
+ rl_set_prompt(PROMPT_OFF);
+ rl_printf("\r");
+ rl_on_new_line();
+ rl_redisplay();
+
+ g_list_free_full(ctrl_list, proxy_leak);
+ ctrl_list = NULL;
+
+ default_ctrl = NULL;
+}
+
+static void print_adapter(GDBusProxy *proxy, const char *description)
+{
+ DBusMessageIter iter;
+ const char *address, *name;
+
+ if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+ return;
+
+ dbus_message_iter_get_basic(&iter, &address);
+
+ if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
+ dbus_message_iter_get_basic(&iter, &name);
+ else
+ name = "<unknown>";
+
+ rl_printf("%s%s%sController %s %s %s\n",
+ description ? "[" : "",
+ description ? : "",
+ description ? "] " : "",
+ address, name,
+ default_ctrl &&
+ default_ctrl->proxy == proxy ?
+ "[default]" : "");
+
+}
+
+static void print_device(GDBusProxy *proxy, const char *description)
+{
+ DBusMessageIter iter;
+ const char *address, *name;
+
+ if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+ return;
+
+ dbus_message_iter_get_basic(&iter, &address);
+
+ if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
+ dbus_message_iter_get_basic(&iter, &name);
+ else
+ name = "<unknown>";
+
+ rl_printf("%s%s%sDevice %s %s\n",
+ description ? "[" : "",
+ description ? : "",
+ description ? "] " : "",
+ address, name);
+}
+
+static void print_iter(const char *label, const char *name,
+ DBusMessageIter *iter)
+{
+ dbus_bool_t valbool;
+ dbus_uint32_t valu32;
+ dbus_uint16_t valu16;
+ dbus_int16_t vals16;
+ unsigned char byte;
+ const char *valstr;
+ DBusMessageIter subiter;
+ char *entry;
+
+ if (iter == NULL) {
+ rl_printf("%s%s is nil\n", label, name);
+ return;
+ }
+
+ switch (dbus_message_iter_get_arg_type(iter)) {
+ case DBUS_TYPE_INVALID:
+ rl_printf("%s%s is invalid\n", label, name);
+ break;
+ case DBUS_TYPE_STRING:
+ case DBUS_TYPE_OBJECT_PATH:
+ dbus_message_iter_get_basic(iter, &valstr);
+ rl_printf("%s%s: %s\n", label, name, valstr);
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ dbus_message_iter_get_basic(iter, &valbool);
+ rl_printf("%s%s: %s\n", label, name,
+ valbool == TRUE ? "yes" : "no");
+ break;
+ case DBUS_TYPE_UINT32:
+ dbus_message_iter_get_basic(iter, &valu32);
+ rl_printf("%s%s: 0x%06x\n", label, name, valu32);
+ break;
+ case DBUS_TYPE_UINT16:
+ dbus_message_iter_get_basic(iter, &valu16);
+ rl_printf("%s%s: 0x%04x\n", label, name, valu16);
+ break;
+ case DBUS_TYPE_INT16:
+ dbus_message_iter_get_basic(iter, &vals16);
+ rl_printf("%s%s: %d\n", label, name, vals16);
+ break;
+ case DBUS_TYPE_BYTE:
+ dbus_message_iter_get_basic(iter, &byte);
+ rl_printf("%s%s: 0x%02x\n", label, name, byte);
+ break;
+ case DBUS_TYPE_VARIANT:
+ dbus_message_iter_recurse(iter, &subiter);
+ print_iter(label, name, &subiter);
+ break;
+ case DBUS_TYPE_ARRAY:
+ dbus_message_iter_recurse(iter, &subiter);
+ while (dbus_message_iter_get_arg_type(&subiter) !=
+ DBUS_TYPE_INVALID) {
+ print_iter(label, name, &subiter);
+ dbus_message_iter_next(&subiter);
+ }
+ break;
+ case DBUS_TYPE_DICT_ENTRY:
+ dbus_message_iter_recurse(iter, &subiter);
+ entry = g_strconcat(name, "Key", NULL);
+ print_iter(label, entry, &subiter);
+ g_free(entry);
+
+ entry = g_strconcat(name, " Value", NULL);
+ dbus_message_iter_next(&subiter);
+ print_iter(label, entry, &subiter);
+ g_free(entry);
+ break;
+ default:
+ rl_printf("%s%s has unsupported type\n", label, name);
+ break;
+ }
+}
+
+static void print_property(GDBusProxy *proxy, const char *name)
+{
+ DBusMessageIter iter;
+
+ if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
+ return;
+
+ print_iter("\t", name, &iter);
+}
+
+static void forget_mesh_devices()
+{
+ g_list_free_full(default_ctrl->mesh_devices, g_free);
+ default_ctrl->mesh_devices = NULL;
+}
+
+static struct mesh_device *find_device_by_uuid(GList *source, uint8_t uuid[16])
+{
+ GList *list;
+
+ for (list = g_list_first(source); list; list = g_list_next(list)) {
+ struct mesh_device *dev = list->data;
+
+ if (!memcmp(dev->dev_uuid, uuid, 16))
+ return dev;
+ }
+
+ return NULL;
+}
+
+static void print_prov_service(struct prov_svc_data *prov_data)
+{
+ const char *prefix = "\t\t";
+ char txt_uuid[16 * 2 + 1];
+ int i;
+
+ rl_printf("%sMesh Provisioning Service (%s)\n", prefix,
+ MESH_PROV_SVC_UUID);
+ for (i = 0; i < 16; ++i) {
+ sprintf(txt_uuid + (i * 2), "%2.2x", prov_data->dev_uuid[i]);
+ }
+
+ rl_printf("%s\tDevice UUID: %s\n", prefix, txt_uuid);
+ rl_printf("%s\tOOB: %4.4x\n", prefix, prov_data->oob);
+
+}
+
+static bool parse_prov_service_data(const char *uuid, uint8_t *data, int len,
+ void *data_out)
+{
+ struct prov_svc_data *prov_data = data_out;
+ int i;
+
+ if (len < 18)
+ return false;
+
+ for (i = 0; i < 16; ++i) {
+ prov_data->dev_uuid[i] = data[i];
+ }
+
+ prov_data->oob = get_be16(&data[16]);
+
+ return true;
+}
+
+static bool parse_mesh_service_data(const char *uuid, uint8_t *data, int len,
+ void *data_out)
+{
+ const char *prefix = "\t\t";
+
+ if (!(len == 9 && data[0] == 0x00) && !(len == 17 && data[0] == 0x01)) {
+ rl_printf("Unexpected mesh proxy service data length %d\n",
+ len);
+ return false;
+ }
+
+ if (data[0] != connection.type)
+ return false;
+
+ if (data[0] == CONN_TYPE_IDENTITY) {
+ uint8_t *key;
+
+ if (IS_UNASSIGNED(connection.unicast)) {
+ /* This would be a bug */
+ rl_printf("Error: Searching identity with "
+ "unicast 0000\n");
+ return false;
+ }
+
+ key = keys_net_key_get(prov_net_key_index, true);
+ if (!key)
+ return false;
+
+ if (!mesh_crypto_identity_check(key, connection.unicast,
+ &data[1]))
+ return false;
+
+ if (discovering) {
+ rl_printf("\n%sMesh Proxy Service (%s)\n", prefix,
+ uuid);
+ rl_printf("%sIdentity for node %4.4x\n", prefix,
+ connection.unicast);
+ }
+
+ } else if (data[0] == CONN_TYPE_NETWORK) {
+ uint16_t net_idx = net_validate_proxy_beacon(data + 1);
+
+ if (net_idx == NET_IDX_INVALID || net_idx != connection.net_idx)
+ return false;
+
+ if (discovering) {
+ rl_printf("\n%sMesh Proxy Service (%s)\n", prefix,
+ uuid);
+ rl_printf("%sNetwork Beacon for net index %4.4x\n",
+ prefix, net_idx);
+ }
+ }
+
+ return true;
+}
+
+static bool parse_service_data(GDBusProxy *proxy, const char *target_uuid,
+ void *data_out)
+{
+ DBusMessageIter iter, entries;
+ bool mesh_prov = false;
+ bool mesh_proxy = false;
+
+ if (target_uuid) {
+ mesh_prov = !strcmp(target_uuid, MESH_PROV_SVC_UUID);
+ mesh_proxy = !strcmp(target_uuid, MESH_PROXY_SVC_UUID);
+ }
+
+ if (!g_dbus_proxy_get_property(proxy, "ServiceData", &iter))
+ return true;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+ return false;
+
+ dbus_message_iter_recurse(&iter, &entries);
+
+ while (dbus_message_iter_get_arg_type(&entries)
+ == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter value, entry, array;
+ const char *uuid_str;
+ bt_uuid_t uuid;
+ uint8_t *service_data;
+ int len;
+
+ dbus_message_iter_recurse(&entries, &entry);
+ dbus_message_iter_get_basic(&entry, &uuid_str);
+
+ if (bt_string_to_uuid(&uuid, uuid_str) < 0)
+ goto fail;
+
+ dbus_message_iter_next(&entry);
+
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+ goto fail;
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY)
+ goto fail;
+
+ dbus_message_iter_recurse(&value, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
+ goto fail;
+
+ dbus_message_iter_get_fixed_array(&array, &service_data, &len);
+
+ if (mesh_prov && !strcmp(uuid_str, MESH_PROV_SVC_UUID)) {
+ return parse_prov_service_data(uuid_str, service_data,
+ len, data_out);
+ } else if (mesh_proxy &&
+ !strcmp(uuid_str, MESH_PROXY_SVC_UUID)) {
+ return parse_mesh_service_data(uuid_str, service_data,
+ len, data_out);
+ }
+
+ dbus_message_iter_next(&entries);
+ }
+
+ if (!target_uuid)
+ return true;
+fail:
+ return false;
+}
+
+static void print_uuids(GDBusProxy *proxy)
+{
+ DBusMessageIter iter, value;
+
+ if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
+ return;
+
+ dbus_message_iter_recurse(&iter, &value);
+
+ while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
+ const char *uuid, *text;
+
+ dbus_message_iter_get_basic(&value, &uuid);
+
+ text = uuidstr_to_str(uuid);
+ if (text) {
+ char str[26];
+ unsigned int n;
+
+ str[sizeof(str) - 1] = '\0';
+
+ n = snprintf(str, sizeof(str), "%s", text);
+ if (n > sizeof(str) - 1) {
+ str[sizeof(str) - 2] = '.';
+ str[sizeof(str) - 3] = '.';
+ if (str[sizeof(str) - 4] == ' ')
+ str[sizeof(str) - 4] = '.';
+
+ n = sizeof(str) - 1;
+ }
+
+ rl_printf("\tUUID: %s%*c(%s)\n",
+ str, 26 - n, ' ', uuid);
+ } else
+ rl_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
+
+ dbus_message_iter_next(&value);
+ }
+}
+
+static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
+{
+ DBusMessageIter iter;
+ const char *adapter, *path;
+
+ if (!master)
+ return FALSE;
+
+ if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &adapter);
+ path = g_dbus_proxy_get_path(master);
+
+ if (!strcmp(path, adapter))
+ return TRUE;
+
+ return FALSE;
+}
+
+static struct adapter *find_parent(GDBusProxy *device)
+{
+ GList *list;
+
+ for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
+ struct adapter *adapter = list->data;
+
+ if (device_is_child(device, adapter->proxy) == TRUE)
+ return adapter;
+ }
+ return NULL;
+}
+
+static void set_connected_device(GDBusProxy *proxy)
+{
+ char *desc = NULL;
+ DBusMessageIter iter;
+ char buf[10];
+ bool mesh;
+
+ connection.device = proxy;
+
+ if (proxy == NULL) {
+ memset(&connection, 0, sizeof(connection));
+ connection.type = CONN_TYPE_INVALID;
+ goto done;
+ }
+
+ if (connection.type == CONN_TYPE_IDENTITY) {
+ mesh = true;
+ snprintf(buf, 10, "Node-%4.4x", connection.unicast);
+ } else if (connection.type == CONN_TYPE_NETWORK) {
+ mesh = true;
+ snprintf(buf, 9, "Net-%4.4x", connection.net_idx);
+ } else {
+ mesh = false;
+ }
+
+ if (!g_dbus_proxy_get_property(proxy, "Alias", &iter) && !mesh)
+ goto done;
+
+ dbus_message_iter_get_basic(&iter, &desc);
+ desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
+ (desc && mesh) ? "-" : "",
+ mesh ? buf : "");
+
+done:
+ rl_set_prompt(desc ? desc : PROMPT_ON);
+ rl_printf("\r");
+ rl_on_new_line();
+ g_free(desc);
+
+ /* If disconnected, return to main menu */
+ if (proxy == NULL)
+ cmd_menu_main(true);
+}
+
+static void connect_reply(DBusMessage *message, void *user_data)
+{
+ GDBusProxy *proxy = user_data;
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to connect: %s\n", error.name);
+ dbus_error_free(&error);
+ set_connected_device(NULL);
+ return;
+ }
+
+ rl_printf("Connection successful\n");
+
+ set_connected_device(proxy);
+}
+
+static void update_device_info(GDBusProxy *proxy)
+{
+ struct adapter *adapter = find_parent(proxy);
+ DBusMessageIter iter;
+ struct prov_svc_data prov_data;
+
+ if (!adapter) {
+ /* TODO: Error */
+ return;
+ }
+
+ if (adapter != default_ctrl)
+ return;
+
+ if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
+ return;
+
+ if (parse_service_data(proxy, MESH_PROV_SVC_UUID, &prov_data)) {
+ struct mesh_device *dev;
+
+ dev = find_device_by_uuid(adapter->mesh_devices,
+ prov_data.dev_uuid);
+
+ /* Display provisioning service once per sicovery session */
+ if (discovering && (!dev || !dev->hide))
+ print_prov_service(&prov_data);
+
+ if (dev) {
+ dev->proxy = proxy;
+ dev->hide = discovering;
+ return;
+ }
+
+ dev = g_malloc0(sizeof(struct mesh_device));
+ if (!dev)
+ return;
+
+ dev->proxy = proxy;
+ dev->hide = discovering;
+
+ memcpy(dev->dev_uuid, prov_data.dev_uuid, 16);
+
+ adapter->mesh_devices = g_list_append(adapter->mesh_devices,
+ dev);
+ print_device(proxy, COLORED_NEW);
+
+ node_create_new(&prov_data);
+
+ } else if (parse_service_data(proxy, MESH_PROXY_SVC_UUID, NULL) &&
+ discover_mesh) {
+ bool res;
+
+ g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
+ NULL, NULL, NULL, NULL);
+ discover_mesh = false;
+
+ forget_mesh_devices();
+
+ res = g_dbus_proxy_method_call(proxy, "Connect", NULL,
+ connect_reply, proxy, NULL);
+
+ if (!res)
+ rl_printf("Failed to connect to mesh\n");
+
+ else
+ rl_printf("Trying to connect to mesh\n");
+
+ }
+}
+
+static void adapter_added(GDBusProxy *proxy)
+{
+ struct adapter *adapter = g_malloc0(sizeof(struct adapter));
+
+ adapter->proxy = proxy;
+ ctrl_list = g_list_append(ctrl_list, adapter);
+
+ if (!default_ctrl)
+ default_ctrl = adapter;
+
+ print_adapter(proxy, COLORED_NEW);
+}
+
+static void data_out_notify(GDBusProxy *proxy, bool enable,
+ GDBusReturnFunction cb)
+{
+ struct mesh_node *node;
+
+ node = node_find_by_uuid(connection.dev_uuid);
+
+ if (!mesh_gatt_notify(proxy, enable, cb, node))
+ rl_printf("Failed to %s notification on %s\n", enable ?
+ "start" : "stop", g_dbus_proxy_get_path(proxy));
+ else
+ rl_printf("%s notification on %s\n", enable ?
+ "Start" : "Stop", g_dbus_proxy_get_path(proxy));
+}
+
+struct disconnect_data {
+ GDBusReturnFunction cb;
+ void *data;
+};
+
+static void disconnect(GDBusReturnFunction cb, void *user_data)
+{
+ GDBusProxy *proxy;
+ DBusMessageIter iter;
+ const char *addr;
+
+ proxy = connection.device;
+ if (!proxy)
+ return;
+
+ if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, cb, user_data,
+ NULL) == FALSE) {
+ rl_printf("Failed to disconnect\n");
+ return;
+ }
+
+ if (g_dbus_proxy_get_property(proxy, "Address", &iter) == TRUE)
+ dbus_message_iter_get_basic(&iter, &addr);
+
+ rl_printf("Attempting to disconnect from %s\n", addr);
+}
+
+static void disc_notify_cb(DBusMessage *message, void *user_data)
+{
+ struct disconnect_data *disc_data = user_data;
+
+ disconnect(disc_data->cb, disc_data->data);
+
+ g_free(user_data);
+}
+
+static void disconnect_device(GDBusReturnFunction cb, void *user_data)
+{
+ DBusMessageIter iter;
+
+ net_session_close(connection.data_in);
+
+ /* Stop notificiation on prov_out or proxy out characteristics */
+ if (connection.data_out) {
+ if (g_dbus_proxy_get_property(connection.data_out, "Notifying",
+ &iter) == TRUE) {
+ struct disconnect_data *disc_data;
+ disc_data = g_malloc(sizeof(struct disconnect_data));
+ disc_data->cb = cb;
+ disc_data->data = user_data;
+
+ if (mesh_gatt_notify(connection.data_out, false,
+ disc_notify_cb, disc_data))
+ return;
+ }
+ }
+
+ disconnect(cb, user_data);
+}
+
+static void mesh_prov_done(void *user_data, int status);
+
+static void notify_prov_out_cb(DBusMessage *message, void *user_data)
+{
+ struct mesh_node *node = user_data;
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to start notify: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ rl_printf("Notify for Mesh Provisioning Out Data started\n");
+
+ if (connection.type != CONN_TYPE_PROVISION) {
+ rl_printf("Error: wrong connection type %d (expected %d)\n",
+ connection.type, CONN_TYPE_PROVISION);
+ return;
+ }
+
+ if (!connection.data_in) {
+ rl_printf("Error: don't have mesh provisioning data in\n");
+ return;
+ }
+
+ if (!node) {
+ rl_printf("Error: provisioning node not present\n");
+ return;
+ }
+
+ if(!prov_open(node, connection.data_in, prov_net_key_index,
+ mesh_prov_done, node))
+ {
+ rl_printf("Failed to start provisioning\n");
+ node_free(node);
+ disconnect_device(NULL, NULL);
+ } else
+ rl_printf("Initiated provisioning\n");
+
+}
+
+static void session_open_cb (int status)
+{
+ if (status) {
+ rl_printf("Failed to open Mesh session\n");
+ disconnect_device(NULL, NULL);
+ return;
+ }
+
+ rl_printf("Mesh session is open\n");
+
+ /* Get composition data for a newly provisioned node */
+ if (connection.type == CONN_TYPE_IDENTITY)
+ config_client_get_composition(connection.unicast);
+}
+
+static void notify_proxy_out_cb(DBusMessage *message, void *user_data)
+{
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to start notify: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ rl_printf("Notify for Mesh Proxy Out Data started\n");
+
+ if (connection.type != CONN_TYPE_IDENTITY &&
+ connection.type != CONN_TYPE_NETWORK) {
+ rl_printf("Error: wrong connection type %d "
+ "(expected %d or %d)\n", connection.type,
+ CONN_TYPE_IDENTITY, CONN_TYPE_NETWORK);
+ return;
+ }
+
+ if (!connection.data_in) {
+ rl_printf("Error: don't have mesh proxy data in\n");
+ return;
+ }
+
+ rl_printf("Trying to open mesh session\n");
+ net_session_open(connection.data_in, true, session_open_cb);
+ connection.session_open = true;
+}
+
+static GDBusProxy *get_characteristic(GDBusProxy *device, const char *char_uuid)
+{
+ GList *l;
+ GDBusProxy *service;
+ const char *svc_uuid;
+
+ if (connection.type == CONN_TYPE_PROVISION) {
+ svc_uuid = MESH_PROV_SVC_UUID;
+ } else {
+ svc_uuid = MESH_PROXY_SVC_UUID;
+ }
+ for (l = service_list; l; l = l->next) {
+ if (mesh_gatt_is_child(l->data, device, "Device") &&
+ service_is_mesh(l->data, svc_uuid))
+ break;
+ }
+
+ if (l)
+ service = l->data;
+ else {
+ rl_printf("Mesh service not found\n");
+ return NULL;
+ }
+
+ for (l = char_list; l; l = l->next) {
+ if (mesh_gatt_is_child(l->data, service, "Service") &&
+ char_is_mesh(l->data, char_uuid)) {
+ rl_printf("Found matching char: path %s, uuid %s\n",
+ g_dbus_proxy_get_path(l->data), char_uuid);
+ return l->data;
+ }
+ }
+ return NULL;
+}
+
+static void mesh_session_setup(GDBusProxy *proxy)
+{
+ if (connection.type == CONN_TYPE_PROVISION) {
+ connection.data_in = get_characteristic(proxy,
+ MESH_PROV_DATA_IN_UUID_STR);
+ if (!connection.data_in)
+ goto fail;
+
+ connection.data_out = get_characteristic(proxy,
+ MESH_PROV_DATA_OUT_UUID_STR);
+ if (!connection.data_out)
+ goto fail;
+
+ data_out_notify(connection.data_out, true, notify_prov_out_cb);
+
+ } else if (connection.type != CONN_TYPE_INVALID){
+
+ connection.data_in = get_characteristic(proxy,
+ MESH_PROXY_DATA_IN_UUID_STR);
+ if (!connection.data_in)
+ goto fail;
+
+ connection.data_out = get_characteristic(proxy,
+ MESH_PROXY_DATA_OUT_UUID_STR);
+ if (!connection.data_out)
+ goto fail;
+
+ data_out_notify(connection.data_out, true, notify_proxy_out_cb);
+ }
+
+ return;
+
+fail:
+
+ rl_printf("Services resolved, mesh characteristics not found\n");
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (!strcmp(interface, "org.bluez.Device1")) {
+ update_device_info(proxy);
+
+ } else if (!strcmp(interface, "org.bluez.Adapter1")) {
+
+ adapter_added(proxy);
+
+ } else if (!strcmp(interface, "org.bluez.GattService1") &&
+ service_is_mesh(proxy, NULL)) {
+
+ rl_printf("Service added %s\n", g_dbus_proxy_get_path(proxy));
+ service_list = g_list_append(service_list, proxy);
+
+ } else if (!strcmp(interface, "org.bluez.GattCharacteristic1") &&
+ char_is_mesh(proxy, NULL)) {
+
+ rl_printf("Char added %s:\n", g_dbus_proxy_get_path(proxy));
+
+ char_list = g_list_append(char_list, proxy);
+ }
+}
+
+static void start_discovery_reply(DBusMessage *message, void *user_data)
+{
+ dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to %s discovery: %s\n",
+ enable == TRUE ? "start" : "stop", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ rl_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
+}
+
+static struct mesh_device *find_device_by_proxy(GList *source,
+ GDBusProxy *proxy)
+{
+ GList *list;
+
+ for (list = g_list_first(source); list; list = g_list_next(list)) {
+ struct mesh_device *dev = list->data;
+ GDBusProxy *proxy = dev->proxy;
+
+ if (dev->proxy == proxy)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static void device_removed(GDBusProxy *proxy)
+{
+ struct adapter *adapter = find_parent(proxy);
+ struct mesh_device *dev;
+
+ if (!adapter) {
+ /* TODO: Error */
+ return;
+ }
+
+ dev = find_device_by_proxy(adapter->mesh_devices, proxy);
+ if (dev)
+ adapter->mesh_devices = g_list_remove(adapter->mesh_devices,
+ dev);
+
+ print_device(proxy, COLORED_DEL);
+
+ if (connection.device == proxy)
+ set_connected_device(NULL);
+
+}
+
+static void adapter_removed(GDBusProxy *proxy)
+{
+ GList *ll;
+ for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll)) {
+ struct adapter *adapter = ll->data;
+
+ if (adapter->proxy == proxy) {
+ print_adapter(proxy, COLORED_DEL);
+
+ if (default_ctrl && default_ctrl->proxy == proxy) {
+ default_ctrl = NULL;
+ set_connected_device(NULL);
+ }
+
+ ctrl_list = g_list_remove_link(ctrl_list, ll);
+
+ g_list_free_full(adapter->mesh_devices, g_free);
+ g_free(adapter);
+ g_list_free(ll);
+ return;
+ }
+ }
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (!strcmp(interface, "org.bluez.Device1")) {
+ device_removed(proxy);
+ } else if (!strcmp(interface, "org.bluez.Adapter1")) {
+ adapter_removed(proxy);
+ } else if (!strcmp(interface, "org.bluez.GattService1")) {
+ if (proxy == connection.service) {
+ if (service_is_mesh(proxy, MESH_PROXY_SVC_UUID)) {
+ data_out_notify(connection.data_out,
+ false, NULL);
+ net_session_close(connection.data_in);
+ }
+ connection.service = NULL;
+ connection.data_in = NULL;
+ connection.data_out = NULL;
+ }
+
+ service_list = g_list_remove(service_list, proxy);
+
+ } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
+ char_list = g_list_remove(char_list, proxy);
+ }
+}
+
+static int get_characteristic_value(DBusMessageIter *value, uint8_t *buf)
+{
+ DBusMessageIter array;
+ uint8_t *data;
+ int len;
+
+ if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_ARRAY)
+ return 0;
+
+ dbus_message_iter_recurse(value, &array);
+
+ if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE)
+ return 0;
+
+ dbus_message_iter_get_fixed_array(&array, &data, &len);
+ memcpy(buf, data, len);
+
+ return len;
+}
+
+static bool process_mesh_characteristic(GDBusProxy *proxy)
+{
+ DBusMessageIter iter;
+ const char *uuid;
+ uint8_t *res;
+ uint8_t buf[256];
+ bool is_prov;
+
+ if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
+ return false;
+
+ dbus_message_iter_get_basic(&iter, &uuid);
+
+ if (g_dbus_proxy_get_property(proxy, "Value", &iter) == FALSE)
+ return false;
+
+ is_prov = !bt_uuid_strcmp(uuid, MESH_PROV_DATA_OUT_UUID_STR);
+
+ if (is_prov || !bt_uuid_strcmp(uuid, MESH_PROXY_DATA_OUT_UUID_STR))
+ {
+ struct mesh_node *node;
+ uint16_t len;
+
+ len = get_characteristic_value(&iter, buf);
+
+ if (!len || len > 69)
+ return false;
+
+ res = buf;
+ len = mesh_gatt_sar(&res, len);
+
+ if (!len)
+ return false;
+
+ if (is_prov) {
+ node = node_find_by_uuid(connection.dev_uuid);
+
+ if (!node) {
+ rl_printf("Node not found?\n");
+ return false;
+ }
+
+ return prov_data_ready(node, res, len);
+ }
+
+ return net_data_ready(res, len);
+ }
+
+ return false;
+}
+
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (!strcmp(interface, "org.bluez.Device1")) {
+
+ if (default_ctrl && device_is_child(proxy,
+ default_ctrl->proxy) == TRUE) {
+
+ if (strcmp(name, "Connected") == 0) {
+ dbus_bool_t connected;
+ dbus_message_iter_get_basic(iter, &connected);
+
+ if (connected && connection.device == NULL)
+ set_connected_device(proxy);
+ else if (!connected &&
+ connection.device == proxy)
+ set_connected_device(NULL);
+ } else if ((strcmp(name, "Alias") == 0) &&
+ connection.device == proxy) {
+ /* Re-generate prompt */
+ set_connected_device(proxy);
+ } else if (!strcmp(name, "ServiceData")) {
+ update_device_info(proxy);
+ } else if (!strcmp(name, "ServicesResolved")) {
+ gboolean resolved;
+
+ dbus_message_iter_get_basic(iter, &resolved);
+
+ rl_printf("Services resolved %s\n", resolved ?
+ "yes" : "no");
+
+ if (resolved)
+ mesh_session_setup(connection.device);
+ }
+
+ }
+ } else if (!strcmp(interface, "org.bluez.Adapter1")) {
+ DBusMessageIter addr_iter;
+ char *str;
+
+ rl_printf("Adapter property changed \n");
+ if (g_dbus_proxy_get_property(proxy, "Address",
+ &addr_iter) == TRUE) {
+ const char *address;
+
+ dbus_message_iter_get_basic(&addr_iter, &address);
+ str = g_strdup_printf("[" COLORED_CHG
+ "] Controller %s ", address);
+ } else
+ str = g_strdup("");
+
+ if (strcmp(name, "Discovering") == 0) {
+ int temp;
+
+ dbus_message_iter_get_basic(iter, &temp);
+ discovering = !!temp;
+ }
+
+ print_iter(str, name, iter);
+ g_free(str);
+ } else if (!strcmp(interface, "org.bluez.GattService1")) {
+ rl_printf("Service property changed %s\n",
+ g_dbus_proxy_get_path(proxy));
+ } else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
+ rl_printf("Characteristic property changed %s\n",
+ g_dbus_proxy_get_path(proxy));
+
+ if ((connection.type == CONN_TYPE_PROVISION) ||
+ connection.session_open)
+ process_mesh_characteristic(proxy);
+ }
+}
+
+static void message_handler(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ rl_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
+ dbus_message_get_member(message));
+}
+
+static struct adapter *find_ctrl_by_address(GList *source, const char *address)
+{
+ GList *list;
+
+ for (list = g_list_first(source); list; list = g_list_next(list)) {
+ struct adapter *adapter = list->data;
+ DBusMessageIter iter;
+ const char *str;
+
+ if (g_dbus_proxy_get_property(adapter->proxy,
+ "Address", &iter) == FALSE)
+ continue;
+
+ dbus_message_iter_get_basic(&iter, &str);
+
+ if (!strcmp(str, address))
+ return adapter;
+ }
+
+ return NULL;
+}
+
+static gboolean parse_argument_on_off(const char *arg, dbus_bool_t *value)
+{
+ if (!arg || !strlen(arg)) {
+ rl_printf("Missing on/off argument\n");
+ return FALSE;
+ }
+
+ if (!strcmp(arg, "on") || !strcmp(arg, "yes")) {
+ *value = TRUE;
+ return TRUE;
+ }
+
+ if (!strcmp(arg, "off") || !strcmp(arg, "no")) {
+ *value = FALSE;
+ return TRUE;
+ }
+
+ rl_printf("Invalid argument %s\n", arg);
+ return FALSE;
+}
+
+static void cmd_list(const char *arg)
+{
+ GList *list;
+
+ for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
+ struct adapter *adapter = list->data;
+ print_adapter(adapter->proxy, NULL);
+ }
+}
+
+static void cmd_show(const char *arg)
+{
+ struct adapter *adapter;
+ GDBusProxy *proxy;
+ DBusMessageIter iter;
+ const char *address;
+
+
+ if (!arg || !strlen(arg)) {
+ if (check_default_ctrl() == FALSE)
+ return;
+
+ proxy = default_ctrl->proxy;
+ } else {
+ adapter = find_ctrl_by_address(ctrl_list, arg);
+ if (!adapter) {
+ rl_printf("Controller %s not available\n", arg);
+ return;
+ }
+ proxy = adapter->proxy;
+ }
+
+ if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+ return;
+
+ dbus_message_iter_get_basic(&iter, &address);
+ rl_printf("Controller %s\n", address);
+
+ print_property(proxy, "Name");
+ print_property(proxy, "Alias");
+ print_property(proxy, "Class");
+ print_property(proxy, "Powered");
+ print_property(proxy, "Discoverable");
+ print_uuids(proxy);
+ print_property(proxy, "Modalias");
+ print_property(proxy, "Discovering");
+}
+
+static void cmd_select(const char *arg)
+{
+ struct adapter *adapter;
+
+ if (!arg || !strlen(arg)) {
+ rl_printf("Missing controller address argument\n");
+ return;
+ }
+
+ adapter = find_ctrl_by_address(ctrl_list, arg);
+ if (!adapter) {
+ rl_printf("Controller %s not available\n", arg);
+ return;
+ }
+
+ if (default_ctrl && default_ctrl->proxy == adapter->proxy)
+ return;
+
+ forget_mesh_devices();
+
+ default_ctrl = adapter;
+ print_adapter(adapter->proxy, NULL);
+}
+
+static void generic_callback(const DBusError *error, void *user_data)
+{
+ char *str = user_data;
+
+ if (dbus_error_is_set(error))
+ rl_printf("Failed to set %s: %s\n", str, error->name);
+ else
+ rl_printf("Changing %s succeeded\n", str);
+}
+
+static void cmd_power(const char *arg)
+{
+ dbus_bool_t powered;
+ char *str;
+
+ if (parse_argument_on_off(arg, &powered) == FALSE)
+ return;
+
+ if (check_default_ctrl() == FALSE)
+ return;
+
+ str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
+
+ if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Powered",
+ DBUS_TYPE_BOOLEAN, &powered,
+ generic_callback, str, g_free) == TRUE)
+ return;
+
+ g_free(str);
+}
+
+static void cmd_scan(const char *arg)
+{
+ dbus_bool_t enable;
+ const char *method;
+
+ if (parse_argument_on_off(arg, &enable) == FALSE)
+ return;
+
+ if (check_default_ctrl() == FALSE)
+ return;
+
+ if (enable == TRUE) {
+ method = "StartDiscovery";
+ } else {
+ method = "StopDiscovery";
+ }
+
+ if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
+ NULL, start_discovery_reply,
+ GUINT_TO_POINTER(enable), NULL) == FALSE) {
+ rl_printf("Failed to %s discovery\n",
+ enable == TRUE ? "start" : "stop");
+ return;
+ }
+}
+
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+ DBusMessageIter value;
+ char sig[2] = { type, '\0' };
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+ dbus_message_iter_append_basic(&value, type, val);
+
+ dbus_message_iter_close_container(iter, &value);
+}
+
+static void append_array_variant(DBusMessageIter *iter, int type, void *val,
+ int n_elements)
+{
+ DBusMessageIter variant, array;
+ char type_sig[2] = { type, '\0' };
+ char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ array_sig, &variant);
+
+ dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+ type_sig, &array);
+
+ if (dbus_type_is_fixed(type) == TRUE) {
+ dbus_message_iter_append_fixed_array(&array, type, val,
+ n_elements);
+ } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+ const char ***str_array = val;
+ int i;
+
+ for (i = 0; i < n_elements; i++)
+ dbus_message_iter_append_basic(&array, type,
+ &((*str_array)[i]));
+ }
+
+ dbus_message_iter_close_container(&variant, &array);
+
+ dbus_message_iter_close_container(iter, &variant);
+}
+
+static void dict_append_entry(DBusMessageIter *dict, const char *key,
+ int type, void *val)
+{
+ DBusMessageIter entry;
+
+ if (type == DBUS_TYPE_STRING) {
+ const char *str = *((const char **) val);
+
+ if (str == NULL)
+ return;
+ }
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ append_variant(&entry, type, val);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_basic_array(DBusMessageIter *dict, int key_type,
+ const void *key, int type, void *val,
+ int n_elements)
+{
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, key_type, key);
+
+ append_array_variant(&entry, type, val, n_elements);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
+ void *val, int n_elements)
+{
+ dict_append_basic_array(dict, DBUS_TYPE_STRING, &key, type, val,
+ n_elements);
+}
+
+#define DISTANCE_VAL_INVALID 0x7FFF
+
+struct set_discovery_filter_args {
+ char *transport;
+ dbus_uint16_t rssi;
+ dbus_int16_t pathloss;
+ char **uuids;
+ size_t uuids_len;
+ dbus_bool_t reset;
+};
+
+static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
+{
+ struct set_discovery_filter_args *args = user_data;
+ DBusMessageIter dict;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &args->uuids,
+ args->uuids_len);
+
+ if (args->pathloss != DISTANCE_VAL_INVALID)
+ dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
+ &args->pathloss);
+
+ if (args->rssi != DISTANCE_VAL_INVALID)
+ dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16, &args->rssi);
+
+ if (args->transport != NULL)
+ dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
+ &args->transport);
+ if (args->reset)
+ dict_append_entry(&dict, "ResetData", DBUS_TYPE_BOOLEAN,
+ &args->reset);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+
+static void set_discovery_filter_reply(DBusMessage *message, void *user_data)
+{
+ DBusError error;
+
+ dbus_error_init(&error);
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("SetDiscoveryFilter failed: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ rl_printf("SetDiscoveryFilter success\n");
+}
+
+static gint filtered_scan_rssi = DISTANCE_VAL_INVALID;
+static gint filtered_scan_pathloss = DISTANCE_VAL_INVALID;
+static char **filtered_scan_uuids;
+static size_t filtered_scan_uuids_len;
+static char *filtered_scan_transport = "le";
+
+static void set_scan_filter_commit(void)
+{
+ struct set_discovery_filter_args args;
+
+ args.pathloss = filtered_scan_pathloss;
+ args.rssi = filtered_scan_rssi;
+ args.transport = filtered_scan_transport;
+ args.uuids = filtered_scan_uuids;
+ args.uuids_len = filtered_scan_uuids_len;
+ args.reset = TRUE;
+
+ if (check_default_ctrl() == FALSE)
+ return;
+
+ if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
+ set_discovery_filter_setup, set_discovery_filter_reply,
+ &args, NULL) == FALSE) {
+ rl_printf("Failed to set discovery filter\n");
+ return;
+ }
+}
+
+static void set_scan_filter_uuids(const char *arg)
+{
+ g_strfreev(filtered_scan_uuids);
+ filtered_scan_uuids = NULL;
+ filtered_scan_uuids_len = 0;
+
+ if (!arg || !strlen(arg))
+ goto commit;
+
+ rl_printf("set_scan_filter_uuids %s\n", arg);
+ filtered_scan_uuids = g_strsplit(arg, " ", -1);
+ if (!filtered_scan_uuids) {
+ rl_printf("Failed to parse input\n");
+ return;
+ }
+
+ filtered_scan_uuids_len = g_strv_length(filtered_scan_uuids);
+
+commit:
+ set_scan_filter_commit();
+}
+
+static void cmd_scan_unprovisioned_devices(const char *arg)
+{
+ dbus_bool_t enable;
+
+ if (parse_argument_on_off(arg, &enable) == FALSE)
+ return;
+
+ if (enable == TRUE) {
+ discover_mesh = false;
+ set_scan_filter_uuids(MESH_PROV_SVC_UUID);
+ }
+ cmd_scan(arg);
+}
+
+static void cmd_info(const char *arg)
+{
+ GDBusProxy *proxy;
+ DBusMessageIter iter;
+ const char *address;
+
+ proxy = connection.device;
+ if (!proxy)
+ return;
+
+ if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+ return;
+
+ dbus_message_iter_get_basic(&iter, &address);
+ rl_printf("Device %s\n", address);
+
+ print_property(proxy, "Name");
+ print_property(proxy, "Alias");
+ print_property(proxy, "Class");
+ print_property(proxy, "Appearance");
+ print_property(proxy, "Icon");
+ print_property(proxy, "Trusted");
+ print_property(proxy, "Blocked");
+ print_property(proxy, "Connected");
+ print_uuids(proxy);
+ print_property(proxy, "Modalias");
+ print_property(proxy, "ManufacturerData");
+ print_property(proxy, "ServiceData");
+ print_property(proxy, "RSSI");
+ print_property(proxy, "TxPower");
+}
+
+static void cmd_connect(const char *arg)
+{
+ if (check_default_ctrl() == FALSE)
+ return;
+
+ memset(&connection, 0, sizeof(connection));
+
+ if (!arg || !strlen(arg)) {
+ connection.net_idx = NET_IDX_PRIMARY;
+ } else {
+ char *end;
+ connection.net_idx = strtol(arg, &end, 16);
+ if (end == arg) {
+ connection.net_idx = NET_IDX_INVALID;
+ rl_printf("Invalid network index %s\n", arg);
+ return;
+ }
+ }
+
+ if (discovering)
+ g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
+ NULL, NULL, NULL, NULL);
+
+ set_scan_filter_uuids(MESH_PROXY_SVC_UUID);
+ discover_mesh = true;
+
+ connection.type = CONN_TYPE_NETWORK;
+
+
+ rl_printf("Looking for mesh network with net index %4.4x\n",
+ connection.net_idx);
+
+ if (g_dbus_proxy_method_call(default_ctrl->proxy,
+ "StartDiscovery", NULL, start_discovery_reply,
+ GUINT_TO_POINTER(TRUE), NULL) == FALSE)
+ rl_printf("Failed to start mesh proxy discovery\n");
+
+ g_dbus_proxy_method_call(default_ctrl->proxy, "StartDiscovery",
+ NULL, NULL, NULL, NULL);
+
+}
+
+static void prov_disconn_reply(DBusMessage *message, void *user_data)
+{
+ struct mesh_node *node = user_data;
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to disconnect: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ set_connected_device(NULL);
+
+ set_scan_filter_uuids(MESH_PROXY_SVC_UUID);
+ discover_mesh = true;
+
+ connection.type = CONN_TYPE_IDENTITY;
+ connection.data_in = NULL;
+ connection.data_out = NULL;
+ connection.unicast = node_get_primary(node);
+
+ if (g_dbus_proxy_method_call(default_ctrl->proxy,
+ "StartDiscovery", NULL, start_discovery_reply,
+ GUINT_TO_POINTER(TRUE), NULL) == FALSE)
+ rl_printf("Failed to start mesh proxy discovery\n");
+
+}
+
+static void disconn_reply(DBusMessage *message, void *user_data)
+{
+ GDBusProxy *proxy = user_data;
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ rl_printf("Failed to disconnect: %s\n", error.name);
+ dbus_error_free(&error);
+ return;
+ }
+
+ rl_printf("Successfully disconnected\n");
+
+ if (proxy != connection.device)
+ return;
+
+ set_connected_device(NULL);
+}
+
+static void cmd_disconn(const char *arg)
+{
+ if (connection.type == CONN_TYPE_PROVISION) {
+ struct mesh_node *node = node_find_by_uuid(connection.dev_uuid);
+ if (node)
+ node_free(node);
+ }
+
+ disconnect_device(disconn_reply, connection.device);
+}
+
+static void mesh_prov_done(void *user_data, int status)
+{
+ struct mesh_node *node = user_data;
+
+ if (status){
+ rl_printf("Provisioning failed\n");
+ node_free(node);
+ disconnect_device(NULL, NULL);
+ return;
+ }
+
+ rl_printf("Provision success. Assigned Primary Unicast %4.4x\n",
+ node_get_primary(node));
+
+ if (!prov_db_add_new_node(node))
+ rl_printf("Failed to add node to provisioning DB\n");
+
+ disconnect_device(prov_disconn_reply, node);
+}
+
+static void cmd_start_prov(const char *arg)
+{
+ GDBusProxy *proxy;
+ struct mesh_device *dev;
+ struct mesh_node *node;
+ int len;
+
+ if (!arg) {
+ rl_printf("Mesh Device UUID is required\n");
+ return;
+ }
+
+ len = strlen(arg);
+ if ( len > 32 || len % 2) {
+ rl_printf("Incorrect UUID size %d\n", len);
+ }
+
+ disconnect_device(NULL, NULL);
+
+ memset(connection.dev_uuid, 0, 16);
+ str2hex(arg, len, connection.dev_uuid, len/2);
+
+ node = node_find_by_uuid(connection.dev_uuid);
+ if (!node) {
+ rl_printf("Device with UUID %s not found.\n", arg);
+ rl_printf("Stale services? Remove device and re-discover\n");
+ return;
+ }
+
+ /* TODO: add command to remove a node from mesh, i.e., "unprovision" */
+ if (node_is_provisioned(node)) {
+ rl_printf("Already provisioned with unicast %4.4x\n",
+ node_get_primary(node));
+ return;
+ }
+
+ dev = find_device_by_uuid(default_ctrl->mesh_devices,
+ connection.dev_uuid);
+ if (!dev || !dev->proxy) {
+ rl_printf("Could not find device proxy\n");
+ memset(connection.dev_uuid, 0, 16);
+ return;
+ }
+
+ proxy = dev->proxy;
+ if (discovering)
+ g_dbus_proxy_method_call(default_ctrl->proxy, "StopDiscovery",
+ NULL, NULL, NULL, NULL);
+ forget_mesh_devices();
+
+ connection.type = CONN_TYPE_PROVISION;
+
+ if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
+ proxy, NULL) == FALSE) {
+ rl_printf("Failed to connect ");
+ print_device(proxy, NULL);
+ return;
+ } else {
+ rl_printf("Trying to connect ");
+ print_device(proxy, NULL);
+ }
+
+}
+
+static void cmd_config(const char *arg)
+{
+ rl_printf("Switching to Mesh Client configuration menu\n");
+
+ if (!switch_cmd_menu("configure"))
+ return;
+
+ set_menu_prompt("config", NULL);
+
+ if (arg && strlen(arg))
+ config_set_node(arg);
+}
+
+static void cmd_onoff_cli(const char *arg)
+{
+ rl_printf("Switching to Mesh Generic ON OFF Client menu\n");
+
+ if (!switch_cmd_menu("onoff"))
+ return;
+
+ set_menu_prompt("on/off", NULL);
+
+ if (arg && strlen(arg))
+ onoff_set_node(arg);
+}
+
+static void cmd_print_mesh(const char *arg)
+{
+ if (!prov_db_show(mesh_prov_db_filename))
+ rl_printf("Unavailable\n");
+
+}
+
+ static void cmd_print_local(const char *arg)
+{
+ if (!prov_db_show(mesh_local_config_filename))
+ rl_printf("Unavailable\n");
+}
+
+static void disc_quit_cb(DBusMessage *message, void *user_data)
+{
+ g_main_loop_quit(main_loop);
+}
+
+static void cmd_quit(const char *arg)
+{
+ if (connection.device) {
+ disconnect_device(disc_quit_cb, NULL);
+ return;
+ }
+
+ g_main_loop_quit(main_loop);
+}
+
+static const struct menu_entry meshctl_cmd_table[] = {
+ { "list", NULL, cmd_list, "List available controllers"},
+ { "show", "[ctrl]", cmd_show, "Controller information"},
+ { "select", "<ctrl>", cmd_select, "Select default controller"},
+ { "info", "[dev]", cmd_info, "Device information"},
+ { "connect", "[net_idx]",cmd_connect, "Connect to mesh network"},
+ { "discover-unprovisioned", "<on/off>", cmd_scan_unprovisioned_devices,
+ "Look for devices to provision" },
+ { "provision", "<uuid>", cmd_start_prov, "Initiate provisioning"},
+ { "power", "<on/off>", cmd_power, "Set controller power" },
+ { "disconnect", "[dev]", cmd_disconn, "Disconnect device"},
+ { "mesh-info", NULL, cmd_print_mesh,
+ "Mesh networkinfo (provisioner)" },
+ { "local-info", NULL, cmd_print_local, "Local mesh node info" },
+ { "configure", "[dst]", cmd_config, "Config client model menu"},
+ { "onoff", "[dst]", cmd_onoff_cli,
+ "Generic On/Off model menu"},
+ { "quit", NULL, cmd_quit, "Quit program" },
+ { "exit", NULL, cmd_quit },
+ { "help" },
+ { }
+};
+
+static void rl_handler(char *input)
+{
+ char *cmd, *arg;
+
+ if (!input) {
+ rl_insert_text("quit");
+ rl_redisplay();
+ rl_crlf();
+ g_main_loop_quit(main_loop);
+ return;
+ }
+
+ if (!strlen(input))
+ goto done;
+ else if (!strcmp(input, "q") || !strcmp(input, "quit")
+ || !strcmp(input, "exit")) {
+ cmd_quit(NULL);
+ goto done;
+ }
+
+ if (agent_input(input) == TRUE)
+ goto done;
+
+ add_history(input);
+
+ cmd = strtok_r(input, " \t\r\n", &arg);
+ if (!cmd)
+ goto done;
+
+ process_menu_cmd(cmd, arg);
+
+done:
+ free(input);
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+ gpointer user_data)
+{
+ static bool terminated = false;
+ struct signalfd_siginfo si;
+ ssize_t result;
+ int fd;
+
+ if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ g_main_loop_quit(main_loop);
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ result = read(fd, &si, sizeof(si));
+ if (result != sizeof(si))
+ return FALSE;
+
+ switch (si.ssi_signo) {
+ case SIGINT:
+ if (input) {
+ rl_replace_line("", 0);
+ rl_crlf();
+ rl_on_new_line();
+ rl_redisplay();
+ break;
+ }
+
+ /*
+ * If input was not yet setup up that means signal was received
+ * while daemon was not yet running. Since user is not able
+ * to terminate client by CTRL-D or typing exit treat this as
+ * exit and fall through.
+ */
+
+ /* fall through */
+ case SIGTERM:
+ if (!terminated) {
+ rl_replace_line("", 0);
+ rl_crlf();
+ g_main_loop_quit(main_loop);
+ }
+
+ terminated = true;
+ break;
+ }
+
+ return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+ GIOChannel *channel;
+ guint source;
+ sigset_t mask;
+ int fd;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+ perror("Failed to set signal mask");
+ return 0;
+ }
+
+ fd = signalfd(-1, &mask, 0);
+ if (fd < 0) {
+ perror("Failed to create signal descriptor");
+ return 0;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ signal_handler, NULL);
+
+ g_io_channel_unref(channel);
+
+ return source;
+}
+
+static gboolean option_version = FALSE;
+static const char *mesh_config_dir;
+
+static GOptionEntry options[] = {
+ { "config", 'c', 0, G_OPTION_ARG_STRING, &mesh_config_dir,
+ "Read local mesh config JSON files from <directory>" },
+ { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+ "Show version information and exit" },
+ { NULL },
+};
+
+static void client_ready(GDBusClient *client, void *user_data)
+{
+ if (!input)
+ input = setup_standard_input();
+}
+
+int main(int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ GDBusClient *client;
+ guint signal;
+ int len;
+ int extra;
+
+ context = g_option_context_new(NULL);
+ g_option_context_add_main_entries(context, options, NULL);
+
+ if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+ if (error != NULL) {
+ g_printerr("%s\n", error->message);
+ g_error_free(error);
+ } else
+ g_printerr("An unknown error occurred\n");
+ exit(1);
+ }
+
+ g_option_context_free(context);
+
+ if (option_version == TRUE) {
+ rl_printf("%s\n", VERSION);
+ exit(0);
+ }
+
+ if (!mesh_config_dir) {
+ rl_printf("Local config directory not provided.\n");
+ mesh_config_dir = "";
+ } else {
+ rl_printf("Reading prov_db.json and local_node.json from %s\n",
+ mesh_config_dir);
+ }
+
+ len = strlen(mesh_config_dir);
+ if (len && mesh_config_dir[len - 1] != '/') {
+ extra = 1;
+ rl_printf("mesh_config_dir[%d] %s\n", len,
+ &mesh_config_dir[len - 1]);
+ } else {
+ extra = 0;
+ }
+ mesh_local_config_filename = g_malloc(len + strlen("local_node.json")
+ + 2);
+ if (!mesh_local_config_filename)
+ exit(1);
+
+ mesh_prov_db_filename = g_malloc(len + strlen("prov_db.json") + 2);
+ if (!mesh_prov_db_filename) {
+ exit(1);
+ }
+
+ sprintf(mesh_local_config_filename, "%s", mesh_config_dir);
+
+ if (extra)
+ sprintf(mesh_local_config_filename + len , "%c", '/');
+
+ sprintf(mesh_local_config_filename + len + extra, "%s",
+ "local_node.json");
+ len = len + extra + strlen("local_node.json");
+ sprintf(mesh_local_config_filename + len, "%c", '\0');
+
+ if (!prov_db_read_local_node(mesh_local_config_filename, true)) {
+ g_printerr("Failed to parse local node configuration file %s\n",
+ mesh_local_config_filename);
+ exit(1);
+ }
+
+ sprintf(mesh_prov_db_filename, "%s", mesh_config_dir);
+ len = strlen(mesh_config_dir);
+ if (extra)
+ sprintf(mesh_prov_db_filename + len , "%c", '/');
+
+ sprintf(mesh_prov_db_filename + len + extra, "%s", "prov_db.json");
+ sprintf(mesh_prov_db_filename + len + extra + strlen("prov_db.json"),
+ "%c", '\0');
+
+ if (!prov_db_read(mesh_prov_db_filename)) {
+ g_printerr("Failed to parse provisioning database file %s\n",
+ mesh_prov_db_filename);
+ exit(1);
+ }
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+ dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+ setlinebuf(stdout);
+
+ rl_erase_empty_line = 1;
+ rl_callback_handler_install(NULL, rl_handler);
+
+ rl_set_prompt(PROMPT_OFF);
+ rl_redisplay();
+
+ signal = setup_signalfd();
+ client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+ g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+ g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
+ g_dbus_client_set_signal_watch(client, message_handler, NULL);
+
+ g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+ property_changed, NULL);
+
+ g_dbus_client_set_ready_watch(client, client_ready, NULL);
+
+ cmd_menu_init(meshctl_cmd_table);
+
+ if (!config_client_init())
+ g_printerr("Failed to initialize mesh configuration client\n");
+
+ if (!config_server_init())
+ g_printerr("Failed to initialize mesh configuration server\n");
+
+ if (!onoff_client_init(PRIMARY_ELEMENT_IDX))
+ g_printerr("Failed to initialize mesh generic On/Off client\n");
+
+ g_main_loop_run(main_loop);
+
+ g_dbus_client_unref(client);
+ g_source_remove(signal);
+ if (input > 0)
+ g_source_remove(input);
+
+ rl_message("");
+ rl_callback_handler_remove();
+
+ dbus_connection_unref(dbus_conn);
+ g_main_loop_unref(main_loop);
+
+ node_cleanup();
+
+ g_list_free(char_list);
+ g_list_free(service_list);
+ g_list_free_full(ctrl_list, proxy_leak);
+
+ agent_release();
+
+ return 0;
+}
diff --git a/mesh/net.c b/mesh/net.c
new file mode 100644
index 0000000..fb2d200
--- /dev/null
+++ b/mesh/net.c
@@ -0,0 +1,2184 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <inttypes.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "client/display.h"
+
+#include "crypto.h"
+#include "gatt.h"
+#include "mesh-net.h"
+#include "util.h"
+#include "keys.h"
+#include "node.h"
+#include "prov-db.h"
+#include "net.h"
+
+struct address_range
+{
+ uint16_t min;
+ uint16_t max;
+};
+
+struct mesh_net {
+ uint32_t iv_index;
+ uint32_t seq_num;
+ uint32_t seq_num_reserved;
+ uint16_t primary_addr;
+ uint8_t iv_upd_state;
+ uint8_t num_elements;
+ uint8_t default_ttl;
+ bool iv_update;
+ bool provisioner;
+ bool blacklist;
+ guint iv_update_timeout;
+ GDBusProxy *proxy_in;
+ GList *address_pool;
+ GList *dest; /* List of valid local destinations for Whitelist */
+ GList *sar_in; /* Incoming segmented messages in progress */
+ GList *msg_out; /* Pre-Network encoded, might be multi-segment */
+ GList *pkt_out; /* Fully encoded packets awaiting Tx in order */
+ net_mesh_session_open_callback open_cb;
+};
+
+struct generic_key {
+ uint16_t idx;
+};
+
+struct net_key_parts {
+ uint8_t nid;
+ uint8_t enc_key[16];
+ uint8_t privacy_key[16];
+ uint8_t net_key[16];
+ uint8_t beacon_key[16];
+ uint8_t net_id[8];
+};
+
+struct mesh_net_key {
+ struct generic_key generic;
+ uint8_t phase;
+ struct net_key_parts current;
+ struct net_key_parts new;
+};
+
+struct app_key_parts {
+ uint8_t key[16];
+ uint8_t akf_aid;
+};
+
+struct mesh_app_key {
+ struct generic_key generic;
+ uint16_t net_idx;
+ struct app_key_parts current;
+ struct app_key_parts new;
+};
+
+struct mesh_virt_addr {
+ uint16_t va16;
+ uint32_t va32;
+ uint8_t va128[16];
+};
+
+struct mesh_pkt {
+ uint8_t data[30];
+ uint8_t len;
+};
+
+struct mesh_sar_msg {
+ guint ack_to;
+ guint msg_to;
+ uint32_t iv_index;
+ uint32_t seqAuth;
+ uint32_t ack;
+ uint32_t dst;
+ uint16_t src;
+ uint16_t net_idx;
+ uint16_t len;
+ uint8_t akf_aid;
+ uint8_t ttl;
+ uint8_t segN;
+ uint8_t activity_cnt;
+ bool ctl;
+ bool segmented;
+ bool szmic;
+ bool proxy;
+ uint8_t data[20]; /* Open ended, min 20 */
+};
+
+struct mesh_destination {
+ uint16_t cnt;
+ uint16_t dst;
+};
+
+/* Network Packet Layer based Offsets */
+#define AKF_BIT 0x40
+
+#define PKT_IVI(p) !!((p)[0] & 0x80)
+#define SET_PKT_IVI(p,v) do {(p)[0] &= 0x7f; \
+ (p)[0] |= ((v) ? 0x80 : 0);} while(0)
+#define PKT_NID(p) ((p)[0] & 0x7f)
+#define SET_PKT_NID(p,v) do {(p)[0] &= 0x80; (p)[0] |= (v);} while(0)
+#define PKT_CTL(p) (!!((p)[1] & 0x80))
+#define SET_PKT_CTL(p,v) do {(p)[1] &= 0x7f; \
+ (p)[1] |= ((v) ? 0x80 : 0);} while(0)
+#define PKT_TTL(p) ((p)[1] & 0x7f)
+#define SET_PKT_TTL(p,v) do {(p)[1] &= 0x80; (p)[1] |= (v);} while(0)
+#define PKT_SEQ(p) (get_be32((p) + 1) & 0xffffff)
+#define SET_PKT_SEQ(p,v) put_be32(((p)[1] << 24) + ((v) & 0xffffff), \
+ (p) + 1)
+#define PKT_SRC(p) get_be16((p) + 5)
+#define SET_PKT_SRC(p,v) put_be16(v, (p) + 5)
+#define PKT_DST(p) get_be16((p) + 7)
+#define SET_PKT_DST(p,v) put_be16(v, (p) + 7)
+#define PKT_TRANS(p) ((p) + 9)
+#define PKT_TRANS_LEN(l) ((l) - 9)
+
+#define PKT_SEGMENTED(p) (!!((p)[9] & 0x80))
+#define SET_PKT_SEGMENTED(p,v) do {(p)[9] &= 0x7f; \
+ (p)[9] |= ((v) ? 0x80 : 0);} while(0)
+#define PKT_AKF_AID(p) ((p)[9] & 0x7f)
+#define SET_PKT_AKF_AID(p,v) do {(p)[9] &= 0x80; (p)[9] |= (v);} while(0)
+#define PKT_OPCODE(p) ((p)[9] & 0x7f)
+#define SET_PKT_OPCODE(p,v) do {(p)[9] &= 0x80; (p)[9] |= (v);} while(0)
+#define PKT_OBO(p) (!!((p)[10] & 0x80))
+#define PKT_SZMIC(p) (!!(PKT_SEGMENTED(p) ? ((p)[10] & 0x40) : 0))
+#define SET_PKT_SZMIC(p,v) do {(p)[10] &= 0x7f; \
+ (p)[10] |= ((v) ? 0x80 : 0);} while(0)
+#define PKT_SEQ0(p) ((get_be16((p) + 10) >> 2) & 0x1fff)
+#define SET_PKT_SEQ0(p,v) do {put_be16((get_be16((p) + 10) & 0x8003) \
+ | (((v) & 0x1fff) << 2), \
+ (p) + 10);} while(0)
+#define SET_PKT_SEGO(p,v) do {put_be16((get_be16( \
+ (p) + 11) & 0xfc1f) | ((v) << 5), \
+ (p) + 11);} while(0)
+#define SET_PKT_SEGN(p,v) do {(p)[12] = ((p)[12] & 0xe0) | (v);} while(0)
+#define PKT_ACK(p) (get_be32((p) + 12))
+#define SET_PKT_ACK(p,v) (put_be32((v)(p) + 12))
+
+/* Transport Layer based offsets */
+#define TRANS_SEGMENTED(t) (!!((t)[0] & 0x80))
+#define SET_TRANS_SEGMENTD(t,v) do {(t)[0] &= 0x7f; \
+ (t)[0] |= ((v) ? 0x80 : 0);} while(0)
+#define TRANS_OPCODE(t) ((t)[0] & 0x7f)
+#define SET_TRANS_OPCODE(t,v) do {(t)[0] &= 0x80; (t)[0] |= (v);} while(0)
+#define TRANS_AKF_AID(t) ((t)[0] & 0x7f)
+#define SET_TRANS_AKF_AID(t,v) do {(t)[0] &= 0xc0; (t)[0] |= (v);} while(0)
+#define TRANS_AKF(t) (!!((t)[0] & AKF_BIT))
+#define TRANS_SZMIC(t) (!!(TRANS_SEGMENTED(t) ? ((t)[1] & 0x80) : 0))
+#define TRANS_SEQ0(t) ((get_be16((t) + 1) >> 2) & 0x1fff)
+#define SET_TRANS_SEQ0(t,v) do {put_be16((get_be16((t) + 1) & 0x8003) \
+ | (((v) & 0x1fff) << 2), \
+ (t) + 1);} while(0)
+#define SET_TRANS_ACK(t,v) put_be32((v), (t) + 3)
+#define TRANS_SEGO(t) ((get_be16((t) + 2) >> 5) & 0x1f)
+#define TRANS_SEGN(t) ((t)[3] & 0x1f)
+
+#define TRANS_PAYLOAD(t) ((t) + (TRANS_SEGMENTED(t) ? 4 : 1))
+#define TRANS_LEN(t,l) ((l) -(TRANS_SEGMENTED(t) ? 4 : 1))
+
+/* Proxy Config Opcodes */
+#define FILTER_SETUP 0x00
+#define FILTER_ADD 0x01
+#define FILTER_DEL 0x02
+#define FILTER_STATUS 0x03
+
+/* Proxy Filter Types */
+#define WHITELIST_FILTER 0x00
+#define BLACKLIST_FILTER 0x01
+
+/* IV Updating states for timing enforcement */
+#define IV_UPD_INIT 0
+#define IV_UPD_NORMAL 1
+#define IV_UPD_UPDATING 2
+#define IV_UPD_NORMAL_HOLD 3
+
+#define IV_IDX_DIFF_RANGE 42
+
+static struct mesh_net net;
+static GList *virt_addrs = NULL;
+static GList *net_keys = NULL;
+static GList *app_keys = NULL;
+
+/* Forward static declarations */
+static void resend_segs(struct mesh_sar_msg *sar);
+
+static int match_net_id(const void *a, const void *net_id)
+{
+ const struct mesh_net_key *net_key = a;
+
+ if (net_key->current.nid != 0xff &&
+ !memcmp(net_key->current.net_id, net_id, 8))
+ return 0;
+
+ if (net_key->new.nid != 0xff &&
+ !memcmp(net_key->new.net_id, net_id, 8))
+ return 0;
+
+ return -1;
+}
+
+static struct mesh_net_key *find_net_key_by_id(const uint8_t *net_id)
+{
+ GList *l;
+
+ l = g_list_find_custom(net_keys, net_id, match_net_id);
+
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+uint16_t net_validate_proxy_beacon(const uint8_t *proxy_beacon)
+{
+ struct mesh_net_key *net_key = find_net_key_by_id(proxy_beacon);
+
+ if (net_key == NULL)
+ return NET_IDX_INVALID;
+
+ return net_key->generic.idx;
+}
+
+static int match_sar_dst(const void *a, const void *b)
+{
+ const struct mesh_sar_msg *sar = a;
+ uint16_t dst = GPOINTER_TO_UINT(b);
+
+ return (sar->dst == dst) ? 0 : -1;
+}
+
+static struct mesh_sar_msg *find_sar_out_by_dst(uint16_t dst)
+{
+ GList *l;
+
+ l = g_list_find_custom(net.msg_out, GUINT_TO_POINTER(dst),
+ match_sar_dst);
+
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+static int match_sar_src(const void *a, const void *b)
+{
+ const struct mesh_sar_msg *sar = a;
+ uint16_t src = GPOINTER_TO_UINT(b);
+
+ return (sar->src == src) ? 0 : -1;
+}
+
+static struct mesh_sar_msg *find_sar_in_by_src(uint16_t src)
+{
+ GList *l;
+
+ l = g_list_find_custom(net.sar_in, GUINT_TO_POINTER(src),
+ match_sar_src);
+
+ if (!l)
+ return NULL;
+
+ return l->data;
+}
+
+static int match_key_index(const void *a, const void *b)
+{
+ const struct generic_key *generic = a;
+ uint16_t index = GPOINTER_TO_UINT(b);
+
+ return (generic->idx == index) ? 0 : -1;
+}
+
+static bool delete_key(GList **list, uint16_t index)
+{
+ GList *l;
+
+ l = g_list_find_custom(*list, GUINT_TO_POINTER(index),
+ match_key_index);
+
+ if (!l)
+ return false;
+
+ *list = g_list_delete_link(*list, l);
+
+ return true;
+
+}
+
+static uint8_t *get_key(GList *list, uint16_t index)
+{
+ GList *l;
+ struct mesh_app_key *app_key;
+ struct mesh_net_key *net_key;
+
+ l = g_list_find_custom(list, GUINT_TO_POINTER(index),
+ match_key_index);
+
+ if (!l) return NULL;
+
+ if (list == app_keys) {
+ app_key = l->data;
+
+ /* All App Keys must belong to a valid Net Key */
+ l = g_list_find_custom(net_keys,
+ GUINT_TO_POINTER(app_key->net_idx),
+ match_key_index);
+
+ if (!l) return NULL;
+
+ net_key = l->data;
+
+ if (net_key->phase == 2 && app_key->new.akf_aid != 0xff)
+ return app_key->new.key;
+
+ if (app_key->current.akf_aid != 0xff)
+ return app_key->current.key;
+
+ return NULL;
+ }
+
+ net_key = l->data;
+
+ if (net_key->phase == 2 && net_key->new.nid != 0xff)
+ return net_key->new.net_key;
+
+ if (net_key->current.nid != 0xff)
+ return net_key->current.net_key;
+
+ return NULL;
+}
+
+bool keys_app_key_add(uint16_t net_idx, uint16_t app_idx, uint8_t *key,
+ bool update)
+{
+ struct mesh_app_key *app_key = NULL;
+ uint8_t akf_aid;
+ GList *l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
+ match_key_index);
+
+ if (!mesh_crypto_k4(key, &akf_aid))
+ return false;
+
+ akf_aid |= AKF_BIT;
+
+ if (l && update) {
+
+ app_key = l->data;
+
+ if (app_key->net_idx != net_idx)
+ return false;
+
+ memcpy(app_key->new.key, key, 16);
+ app_key->new.akf_aid = akf_aid;
+
+ } else if (l) {
+
+ app_key = l->data;
+
+ if (memcmp(app_key->current.key, key, 16) ||
+ app_key->net_idx != net_idx)
+ return false;
+
+ } else {
+
+ app_key = g_new(struct mesh_app_key, 1);
+ memcpy(app_key->current.key, key, 16);
+ app_key->net_idx = net_idx;
+ app_key->generic.idx = app_idx;
+ app_key->current.akf_aid = akf_aid;
+
+ /* Invalidate "New" version */
+ app_key->new.akf_aid = 0xff;
+
+ app_keys = g_list_append(app_keys, app_key);
+
+ }
+
+ return true;
+}
+
+bool keys_net_key_add(uint16_t net_idx, uint8_t *key, bool update)
+{
+ struct mesh_net_key *net_key = NULL;
+ uint8_t p = 0;
+ GList *l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
+ match_key_index);
+
+ if (l && update) {
+ bool result;
+
+ net_key = l->data;
+
+ memcpy(net_key->new.net_key, key, 16);
+
+ /* Calculate the many component parts */
+ result = mesh_crypto_nkbk(key, net_key->new.beacon_key);
+ if (!result)
+ return false;
+
+ result = mesh_crypto_k3(key, net_key->new.net_id);
+ if (!result)
+ return false;
+
+ result = mesh_crypto_k2(key, &p, 1,
+ &net_key->new.nid,
+ net_key->new.enc_key,
+ net_key->new.privacy_key);
+ if (!result)
+ net_key->new.nid = 0xff;
+
+ return result;
+
+ } else if (l) {
+ net_key = l->data;
+
+ if (memcmp(net_key->current.net_key, key, 16))
+ return false;
+ } else {
+ bool result;
+
+ net_key = g_new(struct mesh_net_key, 1);
+ memcpy(net_key->current.net_key, key, 16);
+ net_key->generic.idx = net_idx;
+
+ /* Invalidate "New" version */
+ net_key->new.nid = 0xff;
+
+ /* Calculate the many component parts */
+ result = mesh_crypto_nkbk(key, net_key->current.beacon_key);
+ if (!result) {
+ g_free(net_key);
+ return false;
+ }
+
+ result = mesh_crypto_k3(key, net_key->current.net_id);
+ if (!result) {
+ g_free(net_key);
+ return false;
+ }
+
+ result = mesh_crypto_k2(key, &p, 1,
+ &net_key->current.nid,
+ net_key->current.enc_key,
+ net_key->current.privacy_key);
+
+ if (!result) {
+ g_free(net_key);
+ return false;
+ }
+
+ net_keys = g_list_append(net_keys, net_key);
+ }
+
+ return true;
+}
+
+static struct mesh_app_key *find_app_key_by_idx(uint16_t app_idx)
+{
+ GList *l;
+
+ l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
+ match_key_index);
+
+ if (!l) return NULL;
+
+ return l->data;
+}
+
+static struct mesh_net_key *find_net_key_by_idx(uint16_t net_idx)
+{
+ GList *l;
+
+ l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
+ match_key_index);
+
+ if (!l) return NULL;
+
+ return l->data;
+}
+
+static int match_virt_dst(const void *a, const void *b)
+{
+ const struct mesh_virt_addr *virt = a;
+ uint32_t dst = GPOINTER_TO_UINT(b);
+
+ if (dst < 0x10000 && dst == virt->va16)
+ return 0;
+
+ if (dst == virt->va32)
+ return 0;
+
+ return -1;
+}
+
+static struct mesh_virt_addr *find_virt_by_dst(uint32_t dst)
+{
+ GList *l;
+
+ l = g_list_find_custom(virt_addrs, GUINT_TO_POINTER(dst),
+ match_virt_dst);
+
+ if (!l) return NULL;
+
+ return l->data;
+}
+
+uint8_t *keys_net_key_get(uint16_t net_idx, bool current)
+{
+ GList *l;
+
+
+ l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
+ match_key_index);
+ if (!l) {
+ return NULL;
+ } else {
+ struct mesh_net_key *key = l->data;
+ if (current)
+ return key->current.net_key;
+ else
+ return key->new.net_key;
+ }
+}
+
+bool keys_app_key_delete(uint16_t app_idx)
+{
+ /* TODO: remove all associated bindings */
+ return delete_key(&app_keys, app_idx);
+}
+
+bool keys_net_key_delete(uint16_t net_idx)
+{
+ /* TODO: remove all associated app keys and bindings */
+ return delete_key(&net_keys, net_idx);
+}
+
+uint8_t keys_get_kr_phase(uint16_t net_idx)
+{
+ GList *l;
+ struct mesh_net_key *key;
+
+ l = g_list_find_custom(net_keys, GUINT_TO_POINTER(net_idx),
+ match_key_index);
+
+ if (!l)
+ return KR_PHASE_INVALID;
+
+ key = l->data;
+
+ return key->phase;
+}
+
+bool keys_set_kr_phase(uint16_t index, uint8_t phase)
+{
+ GList *l;
+ struct mesh_net_key *net_key;
+
+ l = g_list_find_custom(net_keys, GUINT_TO_POINTER(index),
+ match_key_index);
+
+ if (!l)
+ return false;
+
+ net_key = l->data;
+ net_key->phase = phase;
+
+ return true;
+}
+
+uint16_t keys_app_key_get_bound(uint16_t app_idx)
+{
+ GList *l;
+
+ l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
+ match_key_index);
+ if (!l)
+ return NET_IDX_INVALID;
+ else {
+ struct mesh_app_key *key = l->data;
+ return key->net_idx;
+ }
+}
+
+uint8_t *keys_app_key_get(uint16_t app_idx, bool current)
+{
+ GList *l;
+
+
+ l = g_list_find_custom(app_keys, GUINT_TO_POINTER(app_idx),
+ match_key_index);
+ if (!l) {
+ return NULL;
+ } else {
+ struct mesh_app_key *key = l->data;
+ if (current)
+ return key->current.key;
+ else
+ return key->new.key;
+ }
+}
+
+void keys_cleanup_all(void)
+{
+ g_list_free_full(app_keys, g_free);
+ g_list_free_full(net_keys, g_free);
+ app_keys = net_keys = NULL;
+}
+
+bool net_get_key(uint16_t net_idx, uint8_t *key)
+{
+ uint8_t *buf;
+
+ buf = get_key(net_keys, net_idx);
+
+ if (!buf)
+ return false;
+
+ memcpy(key, buf, 16);
+ return true;
+}
+
+bool net_get_flags(uint16_t net_idx, uint8_t *out_flags)
+{
+ uint8_t phase;
+
+ phase = keys_get_kr_phase(net_idx);
+
+ if (phase == KR_PHASE_INVALID || !out_flags)
+ return false;
+
+ if (phase != KR_PHASE_NONE)
+ *out_flags = 0x01;
+ else
+ *out_flags = 0x00;
+
+ if (net.iv_update)
+ *out_flags |= 0x02;
+
+ return true;
+}
+
+uint32_t net_get_iv_index(bool *update)
+{
+ if (update)
+ *update = net.iv_update;
+
+ return net.iv_index;
+}
+
+void net_set_iv_index(uint32_t iv_index, bool update)
+{
+ net.iv_index = iv_index;
+ net.iv_update = update;
+}
+
+void set_sequence_number(uint32_t seq_num)
+{
+ net.seq_num = seq_num;
+}
+
+uint32_t get_sequence_number(void)
+{
+ return net.seq_num;
+}
+
+bool net_add_address_pool(uint16_t min, uint16_t max)
+{
+ uint32_t range;
+ if (max < min)
+ return false;
+ range = min + (max << 16);
+ net.address_pool = g_list_append(net.address_pool,
+ GUINT_TO_POINTER(range));
+ return true;
+}
+
+static int match_address_range(const void *a, const void *b)
+{
+ uint32_t range = GPOINTER_TO_UINT(a);
+ uint8_t num_elements = (uint8_t) (GPOINTER_TO_UINT(b));
+ uint16_t max = range >> 16;
+ uint16_t min = range & 0xffff;
+
+ return ((max - min) >= (num_elements - 1)) ? 0 : -1;
+
+}
+
+uint16_t net_obtain_address(uint8_t num_eles)
+{
+ uint16_t addr;
+ GList *l;
+
+ l = g_list_find_custom(net.address_pool, GUINT_TO_POINTER(num_eles),
+ match_address_range);
+ if (l) {
+ uint32_t range = GPOINTER_TO_UINT(l->data);
+ uint16_t max = range >> 16;
+ uint16_t min = range & 0xffff;
+
+ addr = min;
+ min += num_eles;
+
+ if (min > max)
+ net.address_pool = g_list_delete_link(net.address_pool,
+ l);
+ else {
+ range = min + (max << 16);
+ l->data = GUINT_TO_POINTER(range);
+ }
+ return addr;
+ }
+
+ return UNASSIGNED_ADDRESS;
+}
+
+static int range_cmp(const void *a, const void *b)
+{
+ uint32_t range1 = GPOINTER_TO_UINT(a);
+ uint32_t range2 = GPOINTER_TO_UINT(b);
+
+ return range2 - range1;
+}
+
+void net_release_address(uint16_t addr, uint8_t num_elements)
+{
+ GList *l;
+ uint32_t range;
+
+ for (l = net.address_pool; l != NULL; l = l->next)
+ {
+ uint16_t max;
+ uint16_t min;
+
+ range = GPOINTER_TO_UINT(l->data);
+
+ max = range >> 16;
+ min = range & 0xffff;
+
+ if (min == (addr + num_elements + 1))
+ min = addr;
+ else if (addr && max == (addr - 1))
+ max = addr + num_elements + 1;
+ else
+ continue;
+
+ range = min + (max << 16);
+ l->data = GUINT_TO_POINTER(range);
+ return;
+ }
+
+ range = addr + ((addr + num_elements - 1) << 16);
+ net.address_pool = g_list_insert_sorted(net.address_pool,
+ GUINT_TO_POINTER(range),
+ range_cmp);
+}
+
+bool net_reserve_address_range(uint16_t base, uint8_t num_elements)
+{
+ GList *l;
+ uint32_t range;
+ uint16_t max;
+ uint16_t min;
+ bool shrink;
+
+ for (l = net.address_pool; l != NULL; l = l->next) {
+
+ range = GPOINTER_TO_UINT(l->data);
+
+ max = range >> 16;
+ min = range & 0xffff;
+
+ if (base >= min && (base + num_elements - 1) <= max)
+ break;
+ }
+
+ if (!l)
+ return false;
+
+ net.address_pool = g_list_delete_link(net.address_pool, l);
+
+ shrink = false;
+
+ if (base == min) {
+ shrink = true;
+ min = base + num_elements;
+ }
+
+ if (max == base + num_elements - 1) {
+ shrink = true;
+ max -= num_elements;
+ }
+
+ if (min > max)
+ return true;
+
+ if (shrink)
+ range = min + (max << 16);
+ else
+ range = min + ((base - 1) << 16);
+
+ net.address_pool = g_list_insert_sorted(net.address_pool,
+ GUINT_TO_POINTER(range),
+ range_cmp);
+
+ if (shrink)
+ return true;
+
+ range = (base + num_elements) + (max << 16);
+ net.address_pool = g_list_insert_sorted(net.address_pool,
+ GUINT_TO_POINTER(range),
+ range_cmp);
+
+ return true;
+}
+
+static int match_destination(const void *a, const void *b)
+{
+ const struct mesh_destination *dest = a;
+ uint16_t dst = GPOINTER_TO_UINT(b);
+
+ return (dest->dst == dst) ? 0 : -1;
+}
+
+void net_dest_ref(uint16_t dst)
+{
+ struct mesh_destination *dest;
+ GList *l;
+
+ if (!dst) return;
+
+ l = g_list_find_custom(net.dest, GUINT_TO_POINTER(dst),
+ match_destination);
+
+ if (l) {
+ dest = l->data;
+ dest->cnt++;
+ return;
+ }
+
+ dest = g_new0(struct mesh_destination, 1);
+ dest->dst = dst;
+ dest->cnt++;
+ net.dest = g_list_append(net.dest, dest);
+}
+
+void net_dest_unref(uint16_t dst)
+{
+ struct mesh_destination *dest;
+ GList *l;
+
+ l = g_list_find_custom(net.dest, GUINT_TO_POINTER(dst),
+ match_destination);
+
+ if (!l)
+ return;
+
+ dest = l->data;
+ dest->cnt--;
+
+ if (dest->cnt == 0) {
+ net.dest = g_list_remove(net.dest, dest);
+ g_free(dest);
+ }
+}
+
+struct build_whitelist {
+ uint8_t len;
+ uint8_t data[12];
+};
+
+static void whitefilter_add(gpointer data, gpointer user_data)
+{
+ struct mesh_destination *dest = data;
+ struct build_whitelist *white = user_data;
+
+ if (white->len == 0)
+ white->data[white->len++] = FILTER_ADD;
+
+ put_be16(dest->dst, white->data + white->len);
+ white->len += 2;
+
+ if (white->len > (sizeof(white->data) - sizeof(uint16_t))) {
+ net_ctl_msg_send(0, 0, 0, white->data, white->len);
+ white->len = 0;
+ }
+}
+
+static void setup_whitelist()
+{
+ struct build_whitelist white;
+
+ white.len = 0;
+
+ /* Enable (and Clear) Proxy Whitelist */
+ white.data[white.len++] = FILTER_SETUP;
+ white.data[white.len++] = WHITELIST_FILTER;
+
+ net_ctl_msg_send(0, 0, 0, white.data, white.len);
+
+ white.len = 0;
+ g_list_foreach(net.dest, whitefilter_add, &white);
+
+ if (white.len)
+ net_ctl_msg_send(0, 0, 0, white.data, white.len);
+}
+
+static void beacon_update(bool first, bool iv_update, uint32_t iv_index)
+{
+
+ /* Enforcement of 96 hour and 192 hour IVU time windows */
+ if (iv_update && !net.iv_update) {
+ rl_printf("iv_upd_state = IV_UPD_UPDATING\n");
+ net.iv_upd_state = IV_UPD_UPDATING;
+ /* TODO: Start timer to enforce IV Update parameters */
+ } else if (first) {
+ if (iv_update)
+ net.iv_upd_state = IV_UPD_UPDATING;
+ else
+ net.iv_upd_state = IV_UPD_NORMAL;
+
+ rl_printf("iv_upd_state = IV_UPD_%s\n",
+ iv_update ? "UPDATING" : "NORMAL");
+
+ } else if (iv_update && iv_index != net.iv_index) {
+ rl_printf("IV Update too soon -- Rejecting\n");
+ return;
+ }
+
+ if (iv_index > net.iv_index ||
+ iv_update != net.iv_update) {
+
+ /* Don't reset our seq_num unless
+ * we start using new iv_index */
+ if (!(iv_update && (net.iv_index + 1 == iv_index))) {
+ net.seq_num = 0;
+ net.seq_num_reserved = 100;
+ }
+ }
+
+ if (!net.seq_num || net.iv_index != iv_index ||
+ net.iv_update != iv_update) {
+
+ if (net.seq_num_reserved <= net.seq_num)
+ net.seq_num_reserved = net.seq_num + 100;
+
+ prov_db_local_set_iv_index(iv_index, iv_update,
+ net.provisioner);
+ prov_db_local_set_seq_num(net.seq_num_reserved);
+ }
+
+ net.iv_index = iv_index;
+ net.iv_update = iv_update;
+
+ if (first) {
+ /* Must be done once per Proxy Connection after Beacon RXed */
+ setup_whitelist();
+ if (net.open_cb)
+ net.open_cb(0);
+ }
+}
+
+static bool process_beacon(uint8_t *data, uint8_t size)
+{
+ struct mesh_net_key *net_key;
+ struct net_key_parts *key_part;
+ bool rxed_iv_update, rxed_key_refresh, iv_update;
+ bool my_krf;
+ uint32_t rxed_iv_index, iv_index;
+ uint64_t cmac;
+
+ if (size != 22)
+ return false;
+
+ rxed_key_refresh = (data[1] & 0x01) == 0x01;
+ iv_update = rxed_iv_update = (data[1] & 0x02) == 0x02;
+ iv_index = rxed_iv_index = get_be32(data + 10);
+
+ /* Inhibit recognizing iv_update true-->false
+ * if we have outbound SAR messages in flight */
+ if (net.msg_out != NULL) {
+ if (net.iv_update && !rxed_iv_update)
+ iv_update = true;
+ }
+
+ /* Don't bother going further if nothing has changed */
+ if (iv_index == net.iv_index && iv_update == net.iv_update &&
+ net.iv_upd_state != IV_UPD_INIT)
+ return true;
+
+ /* Find key we are using for SNBs */
+ net_key = find_net_key_by_id(data + 2);
+
+ if (net_key == NULL)
+ return false;
+
+ /* We are Provisioner, and control the key_refresh flag */
+ if (rxed_key_refresh != !!(net_key->phase == 2))
+ return false;
+
+ if (net_key->phase != 2) {
+ my_krf = false;
+ key_part = &net_key->current;
+ } else {
+ my_krf = true;
+ key_part = &net_key->new;
+ }
+
+ /* Ignore for incorrect KR state */
+ if (memcmp(key_part->net_id, data + 2, 8))
+ return false;
+
+ if ((net.iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
+ (iv_index < net.iv_index)) {
+ rl_printf("iv index outside range\n");
+ return false;
+ }
+
+ /* Any behavioral changes must pass CMAC test */
+ if (!mesh_crypto_beacon_cmac(key_part->beacon_key, key_part->net_id,
+ rxed_iv_index, my_krf,
+ rxed_iv_update, &cmac)) {
+ return false;
+ }
+
+ if (cmac != get_be64(data + 14))
+ return false;
+
+ if (iv_update && (net.iv_upd_state > IV_UPD_UPDATING)) {
+ if (iv_index != net.iv_index) {
+ rl_printf("Update too soon -- Rejecting\n");
+ }
+ /* Silently ignore old beacons */
+ return true;
+ }
+
+ beacon_update(net.iv_upd_state == IV_UPD_INIT, iv_update, iv_index);
+
+ return true;
+}
+
+struct decode_params {
+ struct mesh_net_key *net_key;
+ uint8_t *packet;
+ uint32_t iv_index;
+ uint8_t size;
+ bool proxy;
+};
+
+static void try_decode(gpointer data, gpointer user_data)
+{
+ struct mesh_net_key *net_key = data;
+ struct decode_params *decode = user_data;
+ uint8_t nid = decode->packet[0] & 0x7f;
+ uint8_t tmp[29];
+ bool status = false;
+
+ if (decode->net_key)
+ return;
+
+ if (net_key->current.nid == nid)
+ status = mesh_crypto_packet_decode(decode->packet,
+ decode->size, decode->proxy, tmp,
+ decode->iv_index,
+ net_key->current.enc_key,
+ net_key->current.privacy_key);
+
+ if (!status && net_key->new.nid == nid)
+ status = mesh_crypto_packet_decode(decode->packet,
+ decode->size, decode->proxy, tmp,
+ decode->iv_index,
+ net_key->new.enc_key,
+ net_key->new.privacy_key);
+
+ if (status) {
+ decode->net_key = net_key;
+ memcpy(decode->packet, tmp, decode->size);
+ return;
+ }
+}
+
+static struct mesh_net_key *net_packet_decode(bool proxy, uint32_t iv_index,
+ uint8_t *packet, uint8_t size)
+{
+ struct decode_params decode = {
+ .proxy = proxy,
+ .iv_index = iv_index,
+ .packet = packet,
+ .size = size,
+ .net_key = NULL,
+ };
+
+ g_list_foreach(net_keys, try_decode, &decode);
+
+ return decode.net_key;
+}
+
+static void flush_sar(GList **list, struct mesh_sar_msg *sar)
+{
+ *list = g_list_remove(*list, sar);
+
+ if (sar->msg_to)
+ g_source_remove(sar->msg_to);
+
+ if (sar->ack_to)
+ g_source_remove(sar->ack_to);
+
+ g_free(sar);
+}
+
+static void flush_sar_list(GList **list)
+{
+ struct mesh_sar_msg *sar;
+ GList *l = g_list_first(*list);
+
+ while (l) {
+ sar = l->data;
+ flush_sar(list, sar);
+ l = g_list_first(*list);
+ }
+}
+
+static void flush_pkt_list(GList **list)
+{
+ struct mesh_pkt *pkt;
+ GList *l = g_list_first(*list);
+
+ while (l) {
+ pkt = l->data;
+ *list = g_list_remove(*list, pkt);
+ g_free(pkt);
+ }
+}
+
+static void resend_unacked_segs(gpointer data, gpointer user_data)
+{
+ struct mesh_sar_msg *sar = data;
+
+ if (sar->activity_cnt)
+ resend_segs(sar);
+}
+
+static void send_pkt_cmplt(DBusMessage *message, void *user_data)
+{
+ struct mesh_pkt *pkt = user_data;
+ GList *l = g_list_first(net.pkt_out);
+
+ if (l && user_data == l->data) {
+ net.pkt_out = g_list_delete_link(net.pkt_out, l);
+ g_free(pkt);
+ } else {
+ /* This is a serious error, and probable memory leak */
+ rl_printf("ERR: send_pkt_cmplt %p not head of queue\n", pkt);
+ }
+
+ l = g_list_first(net.pkt_out);
+
+ if (l == NULL) {
+ /* If queue is newly empty, resend all SAR outbound packets */
+ g_list_foreach(net.msg_out, resend_unacked_segs, NULL);
+ return;
+ }
+
+ pkt = l->data;
+
+ mesh_gatt_write(net.proxy_in, pkt->data, pkt->len,
+ send_pkt_cmplt, pkt);
+}
+
+static void send_mesh_pkt(struct mesh_pkt *pkt)
+{
+ bool queued = !!(net.pkt_out);
+
+ net.pkt_out = g_list_append(net.pkt_out, pkt);
+
+ if (queued)
+ return;
+
+ mesh_gatt_write(net.proxy_in, pkt->data, pkt->len,
+ send_pkt_cmplt, pkt);
+}
+
+static uint32_t get_next_seq()
+{
+ uint32_t this_seq = net.seq_num++;
+
+ if (net.seq_num + 32 >= net.seq_num_reserved) {
+ net.seq_num_reserved = net.seq_num + 100;
+ prov_db_local_set_seq_num(net.seq_num_reserved);
+ }
+
+ return this_seq;
+}
+
+static void send_seg(struct mesh_sar_msg *sar, uint8_t seg)
+{
+ struct mesh_net_key *net_key;
+ struct net_key_parts *part;
+ struct mesh_pkt *pkt;
+ uint8_t *data;
+
+ net_key = find_net_key_by_idx(sar->net_idx);
+
+ if (net_key == NULL)
+ return;
+
+ /* Choose which components to use to secure pkt */
+ if (net_key->phase == 2 && net_key->new.nid != 0xff)
+ part = &net_key->new;
+ else
+ part = &net_key->current;
+
+ pkt = g_new0(struct mesh_pkt, 1);
+
+ if (pkt == NULL)
+ return;
+
+ /* leave extra byte at start for GATT Proxy type */
+ data = pkt->data + 1;
+
+ SET_PKT_NID(data, part->nid);
+ SET_PKT_IVI(data, sar->iv_index & 1);
+ SET_PKT_CTL(data, sar->ctl);
+ SET_PKT_TTL(data, sar->ttl);
+ SET_PKT_SEQ(data, get_next_seq());
+ SET_PKT_SRC(data, sar->src);
+ SET_PKT_DST(data, sar->dst);
+ SET_PKT_SEGMENTED(data, sar->segmented);
+
+ if (sar->ctl)
+ SET_PKT_OPCODE(data, sar->data[0]);
+ else
+ SET_PKT_AKF_AID(data, sar->akf_aid);
+
+ if (sar->segmented) {
+
+ if (!sar->ctl)
+ SET_PKT_SZMIC(data, sar->szmic);
+
+ SET_PKT_SEQ0(data, sar->seqAuth);
+ SET_PKT_SEGO(data, seg);
+ SET_PKT_SEGN(data, sar->segN);
+
+ memcpy(PKT_TRANS(data) + 4,
+ sar->data + sar->ctl + (seg * 12), 12);
+
+ pkt->len = 9 + 4;
+
+ if (sar->segN == seg)
+ pkt->len += (sar->len - sar->ctl) % 12;
+
+ if (pkt->len == (9 + 4))
+ pkt->len += 12;
+
+ } else {
+ memcpy(PKT_TRANS(data) + 1,
+ sar->data + sar->ctl, 15);
+
+ pkt->len = 9 + 1 + sar->len - sar->ctl;
+ }
+
+ pkt->len += (sar->ctl ? 8 : 4);
+ mesh_crypto_packet_encode(data, pkt->len,
+ part->enc_key,
+ sar->iv_index,
+ part->privacy_key);
+
+
+ /* Prepend GATT_Proxy packet type */
+ if (sar->proxy)
+ pkt->data[0] = PROXY_CONFIG_PDU;
+ else
+ pkt->data[0] = PROXY_NETWORK_PDU;
+
+ pkt->len++;
+
+ send_mesh_pkt(pkt);
+}
+
+static void resend_segs(struct mesh_sar_msg *sar)
+{
+ uint32_t ack = 1;
+ uint8_t i;
+
+ sar->activity_cnt = 0;
+
+ for (i = 0; i <= sar->segN; i++, ack <<= 1) {
+ if (!(ack & sar->ack))
+ send_seg(sar, i);
+ }
+}
+
+static bool ack_rxed(bool to, uint16_t src, uint16_t dst, bool obo,
+ uint16_t seq0, uint32_t ack_flags)
+{
+ struct mesh_sar_msg *sar = find_sar_out_by_dst(src);
+ uint32_t full_ack;
+
+ /* Silently ignore unknown (stale?) ACKs */
+ if (sar == NULL)
+ return true;
+
+ full_ack = 0xffffffff >> (31 - sar->segN);
+
+ sar->ack |= (ack_flags & full_ack);
+
+ if (sar->ack == full_ack) {
+ /* Outbound message 100% received by remote node */
+ flush_sar(&net.msg_out, sar);
+ return true;
+ }
+
+ /* Because we are GATT, and slow, only resend PKTs if it is
+ * time *and* our outbound PKT queue is empty. */
+ sar->activity_cnt++;
+
+ if (net.pkt_out == NULL)
+ resend_segs(sar);
+
+ return true;
+}
+
+static bool proxy_ctl_rxed(uint16_t net_idx, uint32_t iv_index,
+ uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
+ uint8_t *trans, uint16_t len)
+{
+ if (len < 1)
+ return false;
+
+ switch(trans[0]) {
+ case FILTER_STATUS:
+ if (len != 4)
+ return false;
+
+ net.blacklist = !!(trans[1] == BLACKLIST_FILTER);
+ rl_printf("Proxy %slist filter length: %d\n",
+ net.blacklist ? "Black" : "White",
+ get_be16(trans + 2));
+
+ return true;
+
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+static bool ctl_rxed(uint16_t net_idx, uint32_t iv_index,
+ uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
+ uint8_t *trans, uint16_t len)
+{
+ /* TODO: Handle control messages */
+ return false;
+}
+
+struct decrypt_params {
+ uint8_t *nonce;
+ uint8_t *aad;
+ uint8_t *out_msg;
+ uint8_t *trans;
+ uint32_t iv_index;
+ uint32_t seq_num;
+ uint16_t src;
+ uint16_t dst;
+ uint16_t len;
+ uint16_t net_idx;
+ uint16_t app_idx;
+ uint8_t akf_aid;
+ bool szmic;
+};
+
+
+static void try_decrypt(gpointer data, gpointer user_data)
+{
+ struct mesh_app_key *app_key = data;
+ struct decrypt_params *decrypt = user_data;
+ size_t mic_size = decrypt->szmic ? sizeof(uint64_t) : sizeof(uint32_t);
+ bool status = false;
+
+ /* Already done... Nothing to do */
+ if (decrypt->app_idx != APP_IDX_INVALID)
+ return;
+
+ /* Don't decrypt on Appkeys not owned by this NetKey */
+ if (app_key->net_idx != decrypt->net_idx)
+ return;
+
+ /* Test and decrypt against current key copy */
+ if (app_key->current.akf_aid == decrypt->akf_aid)
+ status = mesh_crypto_aes_ccm_decrypt(decrypt->nonce,
+ app_key->current.key,
+ decrypt->aad, decrypt->aad ? 16 : 0,
+ decrypt->trans, decrypt->len,
+ decrypt->out_msg, NULL, mic_size);
+
+ /* Test and decrypt against new key copy */
+ if (!status && app_key->new.akf_aid == decrypt->akf_aid)
+ status = mesh_crypto_aes_ccm_decrypt(decrypt->nonce,
+ app_key->new.key,
+ decrypt->aad, decrypt->aad ? 16 : 0,
+ decrypt->trans, decrypt->len,
+ decrypt->out_msg, NULL, mic_size);
+
+ /* If successful, terminate with successful App IDX */
+ if (status)
+ decrypt->app_idx = app_key->generic.idx;
+}
+
+static uint16_t access_pkt_decrypt(uint8_t *nonce, uint8_t *aad,
+ uint16_t net_idx, uint8_t akf_aid, bool szmic,
+ uint8_t *trans, uint16_t len)
+{
+ uint8_t *out_msg;
+ struct decrypt_params decrypt = {
+ .nonce = nonce,
+ .aad = aad,
+ .net_idx = net_idx,
+ .akf_aid = akf_aid,
+ .szmic = szmic,
+ .trans = trans,
+ .len = len,
+ .app_idx = APP_IDX_INVALID,
+ };
+
+ out_msg = g_malloc(len);
+
+ if (out_msg == NULL)
+ return false;
+
+ decrypt.out_msg = out_msg;
+
+ g_list_foreach(app_keys, try_decrypt, &decrypt);
+
+ if (decrypt.app_idx != APP_IDX_INVALID)
+ memcpy(trans, out_msg, len);
+
+ g_free(out_msg);
+
+ return decrypt.app_idx;
+}
+
+static bool access_rxed(uint8_t *nonce, uint16_t net_idx,
+ uint32_t iv_index, uint32_t seq_num,
+ uint16_t src, uint16_t dst,
+ uint8_t akf_aid, bool szmic, uint8_t *trans, uint16_t len)
+{
+ uint16_t app_idx = access_pkt_decrypt(nonce, NULL,
+ net_idx, akf_aid, szmic, trans, len);
+
+ if (app_idx != APP_IDX_INVALID) {
+ len -= szmic ? sizeof(uint64_t) : sizeof(uint32_t);
+
+ node_local_data_handler(src, dst, iv_index, seq_num,
+ app_idx, trans, len);
+ return true;
+ }
+
+ return false;
+}
+
+static void try_virt_decrypt(gpointer data, gpointer user_data)
+{
+ struct mesh_virt_addr *virt = data;
+ struct decrypt_params *decrypt = user_data;
+
+ if (decrypt->app_idx != APP_IDX_INVALID || decrypt->dst != virt->va16)
+ return;
+
+ decrypt->app_idx = access_pkt_decrypt(decrypt->nonce,
+ virt->va128,
+ decrypt->net_idx, decrypt->akf_aid,
+ decrypt->szmic, decrypt->trans, decrypt->len);
+
+ if (decrypt->app_idx != APP_IDX_INVALID) {
+ uint16_t len = decrypt->len;
+
+ len -= decrypt->szmic ? sizeof(uint64_t) : sizeof(uint32_t);
+
+ node_local_data_handler(decrypt->src, virt->va32,
+ decrypt->iv_index, decrypt->seq_num,
+ decrypt->app_idx, decrypt->trans, len);
+ }
+}
+
+static bool virtual_rxed(uint8_t *nonce, uint16_t net_idx,
+ uint32_t iv_index, uint32_t seq_num,
+ uint16_t src, uint16_t dst,
+ uint8_t akf_aid, bool szmic, uint8_t *trans, uint16_t len)
+{
+ struct decrypt_params decrypt = {
+ .nonce = nonce,
+ .net_idx = net_idx,
+ .iv_index = iv_index,
+ .seq_num = seq_num,
+ .src = dst,
+ .dst = dst,
+ .akf_aid = akf_aid,
+ .szmic = szmic,
+ .trans = trans,
+ .len = len,
+ .app_idx = APP_IDX_INVALID,
+ };
+
+ /* Cycle through known virtual addresses */
+ g_list_foreach(virt_addrs, try_virt_decrypt, &decrypt);
+
+ if (decrypt.app_idx != APP_IDX_INVALID)
+ return true;
+
+ return false;
+}
+
+static bool msg_rxed(uint16_t net_idx, uint32_t iv_index, bool szmic,
+ uint8_t ttl, uint32_t seq_num, uint32_t seq_auth,
+ uint16_t src, uint16_t dst,
+ uint8_t *trans, uint16_t len)
+{
+ uint8_t akf_aid = TRANS_AKF_AID(trans);
+ bool result;
+ size_t mic_size = szmic ? sizeof(uint64_t) : sizeof(uint32_t);
+ uint8_t nonce[13];
+ uint8_t *dev_key;
+ uint8_t *out = NULL;
+
+ if (!TRANS_AKF(trans)) {
+ /* Compose Nonce */
+ result = mesh_crypto_device_nonce(seq_auth, src, dst,
+ iv_index, szmic, nonce);
+
+ if (!result) return false;
+
+ out = g_malloc0(TRANS_LEN(trans, len));
+ if (out == NULL) return false;
+
+ /* If we are provisioner, we probably RXed on remote Dev Key */
+ if (net.provisioner) {
+ dev_key = node_get_device_key(node_find_by_addr(src));
+
+ if (dev_key == NULL)
+ goto local_dev_key;
+ } else
+ goto local_dev_key;
+
+ result = mesh_crypto_aes_ccm_decrypt(nonce, dev_key,
+ NULL, 0,
+ TRANS_PAYLOAD(trans), TRANS_LEN(trans, len),
+ out, NULL, mic_size);
+
+ if (result) {
+ node_local_data_handler(src, dst,
+ iv_index, seq_num, APP_IDX_DEV,
+ out, TRANS_LEN(trans, len) - mic_size);
+ goto done;
+ }
+
+local_dev_key:
+ /* Always fallback to the local Dev Key */
+ dev_key = node_get_device_key(node_get_local_node());
+
+ if (dev_key == NULL)
+ goto done;
+
+ result = mesh_crypto_aes_ccm_decrypt(nonce, dev_key,
+ NULL, 0,
+ TRANS_PAYLOAD(trans), TRANS_LEN(trans, len),
+ out, NULL, mic_size);
+
+ if (result) {
+ node_local_data_handler(src, dst,
+ iv_index, seq_num, APP_IDX_DEV,
+ out, TRANS_LEN(trans, len) - mic_size);
+ goto done;
+ }
+
+ goto done;
+ }
+
+ result = mesh_crypto_application_nonce(seq_auth, src, dst,
+ iv_index, szmic, nonce);
+
+ if (!result) goto done;
+
+ /* If Virtual destination wrap the Access decoder with Virtual */
+ if (IS_VIRTUAL(dst)) {
+ result = virtual_rxed(nonce, net_idx, iv_index, seq_num,
+ src, dst, akf_aid, szmic,
+ TRANS_PAYLOAD(trans), TRANS_LEN(trans, len));
+ goto done;
+ }
+
+ /* Try all matching App Keys until success or exhaustion */
+ result = access_rxed(nonce, net_idx, iv_index, seq_num,
+ src, dst, akf_aid, szmic,
+ TRANS_PAYLOAD(trans), TRANS_LEN(trans, len));
+
+done:
+ if (out != NULL)
+ g_free(out);
+
+ return result;
+}
+
+static void send_sar_ack(struct mesh_sar_msg *sar)
+{
+ uint8_t ack[7];
+
+ sar->activity_cnt = 0;
+
+ memset(ack, 0, sizeof(ack));
+ SET_TRANS_OPCODE(ack, NET_OP_SEG_ACKNOWLEDGE);
+ SET_TRANS_SEQ0(ack, sar->seqAuth);
+ SET_TRANS_ACK(ack, sar->ack);
+
+ net_ctl_msg_send(0xff, sar->dst, sar->src, ack, sizeof(ack));
+}
+
+static gboolean sar_out_ack_timeout(void *user_data)
+{
+ struct mesh_sar_msg *sar = user_data;
+
+ sar->activity_cnt++;
+
+ /* Because we are GATT, and slow, only resend PKTs if it is
+ * time *and* our outbound PKT queue is empty. */
+ if (net.pkt_out == NULL)
+ resend_segs(sar);
+
+ /* Only add resent SAR pkts to empty queue */
+ return true;
+}
+
+static gboolean sar_out_msg_timeout(void *user_data)
+{
+ struct mesh_sar_msg *sar = user_data;
+
+ /* msg_to will expire when we return false */
+ sar->msg_to = 0;
+
+ flush_sar(&net.msg_out, sar);
+
+ return false;
+}
+
+static gboolean sar_in_ack_timeout(void *user_data)
+{
+ struct mesh_sar_msg *sar = user_data;
+ uint32_t full_ack = 0xffffffff >> (31 - sar->segN);
+
+ if (sar->activity_cnt || sar->ack != full_ack)
+ send_sar_ack(sar);
+
+ return true;
+}
+
+static gboolean sar_in_msg_timeout(void *user_data)
+{
+ struct mesh_sar_msg *sar = user_data;
+
+ /* msg_to will expire when we return false */
+ sar->msg_to = 0;
+
+ flush_sar(&net.sar_in, sar);
+
+ return false;
+}
+
+static uint32_t calc_seqAuth(uint32_t seq_num, uint8_t *trans)
+{
+ uint32_t seqAuth = seq_num & ~0x1fff;
+
+ seqAuth |= TRANS_SEQ0(trans);
+
+ return seqAuth;
+}
+
+static bool seg_rxed(uint16_t net_idx, uint32_t iv_index, bool ctl,
+ uint8_t ttl, uint32_t seq_num, uint16_t src, uint16_t dst,
+ uint8_t *trans, uint16_t len)
+{
+ struct mesh_sar_msg *sar;
+ uint32_t seqAuth = calc_seqAuth(seq_num, trans);
+ uint8_t segN, segO;
+ uint32_t old_ack, full_ack, last_ack_mask;
+ bool send_ack, result = false;
+
+ segN = TRANS_SEGN(trans);
+ segO = TRANS_SEGO(trans);
+
+ /* Only support single incoming SAR'd message per SRC */
+ sar = find_sar_in_by_src(src);
+
+ /* Reuse existing SAR structure if appropriate */
+ if (sar) {
+ uint64_t iv_seqAuth = (uint64_t)iv_index << 32 | seqAuth;
+ uint64_t old_iv_seqAuth = (uint64_t)sar->iv_index << 32 |
+ sar->seqAuth;
+ if (old_iv_seqAuth < iv_seqAuth) {
+
+ flush_sar(&net.sar_in, sar);
+ sar = NULL;
+
+ } else if (old_iv_seqAuth > iv_seqAuth) {
+
+ /* New segment is Stale. Silently ignore */
+ return false;
+
+ } else if (segN != sar->segN) {
+
+ /* Remote side sent conflicting data: abandon */
+ flush_sar(&net.sar_in, sar);
+ sar = NULL;
+
+ }
+ }
+
+ if (sar == NULL) {
+ sar = g_malloc0(sizeof(*sar) + (12 * segN));
+
+ if (sar == NULL)
+ return false;
+
+ sar->net_idx = net_idx;
+ sar->iv_index = iv_index;
+ sar->ctl = ctl;
+ sar->ttl = ttl;
+ sar->seqAuth = seqAuth;
+ sar->src = src;
+ sar->dst = dst;
+ sar->segmented = true;
+ sar->szmic = TRANS_SZMIC(trans);
+ sar->segN = segN;
+
+ /* In all cases, the reassembled packet should begin with the
+ * same first octet of all segments, minus the SEGMENTED flag */
+ sar->data[0] = trans[0] & 0x7f;
+
+ net.sar_in = g_list_append(net.sar_in, sar);
+
+ /* Setup expiration timers */
+ if (IS_UNICAST(dst))
+ sar->ack_to = g_timeout_add(5000,
+ sar_in_ack_timeout, sar);
+
+ sar->msg_to = g_timeout_add(60000, sar_in_msg_timeout, sar);
+ }
+
+ /* If last segment, calculate full msg size */
+ if (segN == segO)
+ sar->len = (segN * 12) + len - 3;
+
+ /* Copy to correct offset */
+ memcpy(sar->data + 1 + (12 * segO), trans + 4, 12);
+
+ full_ack = 0xffffffff >> (31 - segN);
+ last_ack_mask = 0xffffffff << segO;
+ old_ack = sar->ack;
+ sar->ack |= 1 << segO;
+ send_ack = false;
+
+ /* Determine if we should forward message */
+ if (sar->ack == full_ack && old_ack != full_ack) {
+
+ /* First time we have seen this complete message */
+ send_ack = true;
+
+ if (ctl)
+ result = ctl_rxed(sar->net_idx, sar->iv_index,
+ sar->ttl, sar->seqAuth, sar->src,
+ sar->dst, sar->data, sar->len);
+ else
+ result = msg_rxed(sar->net_idx, sar->iv_index,
+ sar->szmic, sar->ttl,
+ seq_num, sar->seqAuth, sar->src,
+ sar->dst, sar->data, sar->len);
+ }
+
+ /* Never Ack Group addressed SAR messages */
+ if (!IS_UNICAST(dst))
+ return result;
+
+ /* Tickle the ACK system so it knows we are still RXing segments */
+ sar->activity_cnt++;
+
+ /* Determine if we should ACK */
+ if (old_ack == sar->ack)
+ /* Let the timer generate repeat ACKs as needed */
+ send_ack = false;
+ else if ((last_ack_mask & sar->ack) == (last_ack_mask & full_ack))
+ /* If this was largest segO outstanding segment, we ACK */
+ send_ack = true;
+
+ if (send_ack)
+ send_sar_ack(sar);
+
+ return result;
+}
+
+bool net_data_ready(uint8_t *msg, uint8_t len)
+{
+ uint8_t type = *msg++;
+ uint32_t iv_index = net.iv_index;
+ struct mesh_net_key *net_key;
+
+ if (len-- < 10) return false;
+
+ if (type == PROXY_MESH_BEACON)
+ return process_beacon(msg, len);
+ else if (type > PROXY_CONFIG_PDU)
+ return false;
+
+ /* RXed iv_index must be equal or 1 less than local iv_index */
+ /* With the clue being high-order bit of first octet */
+ if (!!(iv_index & 0x01) != !!(msg[0] & 0x80)) {
+ if (iv_index)
+ iv_index--;
+ else
+ return false;
+ }
+
+ net_key = net_packet_decode(type == PROXY_CONFIG_PDU,
+ iv_index, msg, len);
+
+ if (net_key == NULL)
+ return false;
+
+ /* CTL packets have 64 bit network MIC, otherwise 32 bit MIC */
+ len -= PKT_CTL(msg) ? sizeof(uint64_t) : sizeof(uint32_t);
+
+ if (type == PROXY_CONFIG_PDU) {
+
+ /* Proxy Configuration DST messages must be 0x0000 */
+ if (PKT_DST(msg))
+ return false;
+
+ return proxy_ctl_rxed(net_key->generic.idx,
+ iv_index, PKT_TTL(msg), PKT_SEQ(msg),
+ PKT_SRC(msg), PKT_DST(msg),
+ PKT_TRANS(msg), PKT_TRANS_LEN(len));
+
+ } if (PKT_CTL(msg) && PKT_OPCODE(msg) == NET_OP_SEG_ACKNOWLEDGE) {
+
+ return ack_rxed(false, PKT_SRC(msg), PKT_DST(msg),
+ PKT_OBO(msg), PKT_SEQ0(msg), PKT_ACK(msg));
+
+ } else if (PKT_SEGMENTED(msg)) {
+
+ return seg_rxed(net_key->generic.idx, iv_index, PKT_CTL(msg),
+ PKT_TTL(msg), PKT_SEQ(msg),
+ PKT_SRC(msg), PKT_DST(msg),
+ PKT_TRANS(msg), PKT_TRANS_LEN(len));
+
+ } else if (!PKT_CTL(msg)){
+
+ return msg_rxed(net_key->generic.idx,
+ iv_index, false, PKT_TTL(msg), PKT_SEQ(msg),
+ PKT_SEQ(msg), PKT_SRC(msg), PKT_DST(msg),
+ PKT_TRANS(msg), PKT_TRANS_LEN(len));
+ } else {
+
+ return ctl_rxed(net_key->generic.idx,
+ iv_index, PKT_TTL(msg), PKT_SEQ(msg),
+ PKT_SRC(msg), PKT_DST(msg),
+ PKT_TRANS(msg), PKT_TRANS_LEN(len));
+
+ }
+
+ return false;
+}
+
+bool net_session_open(GDBusProxy *data_in, bool provisioner,
+ net_mesh_session_open_callback cb)
+{
+ if (net.proxy_in)
+ return false;
+
+ net.proxy_in = data_in;
+ net.iv_upd_state = IV_UPD_INIT;
+ net.blacklist = false;
+ net.provisioner = provisioner;
+ net.open_cb = cb;
+ flush_pkt_list(&net.pkt_out);
+ return true;
+}
+
+void net_session_close(GDBusProxy *data_in)
+{
+ if (net.proxy_in == data_in)
+ net.proxy_in = NULL;
+
+ flush_sar_list(&net.sar_in);
+ flush_sar_list(&net.msg_out);
+ flush_pkt_list(&net.pkt_out);
+}
+
+bool net_register_unicast(uint16_t unicast, uint8_t count)
+{
+ /* TODO */
+ return true;
+}
+
+bool net_register_group(uint16_t group_addr)
+{
+ /* TODO */
+ return true;
+}
+
+uint32_t net_register_virtual(uint8_t buf[16])
+{
+ /* TODO */
+ return 0;
+}
+
+static bool get_enc_keys(uint16_t app_idx, uint16_t dst,
+ uint8_t *akf_aid, uint8_t **app_enc_key,
+ uint16_t *net_idx)
+{
+ if (app_idx == APP_IDX_DEV) {
+ struct mesh_node *node;
+ uint8_t *enc_key = NULL;
+
+ if (net.provisioner) {
+ /* Default to Remote Device Key when Provisioner */
+ node = node_find_by_addr(dst);
+ enc_key = node_get_device_key(node);
+ }
+
+ if (enc_key == NULL) {
+ /* Use Local node Device Key */
+ node = node_get_local_node();
+ enc_key = node_get_device_key(node);
+ }
+
+ if (enc_key == NULL || node == NULL)
+ return false;
+
+ if (akf_aid) *akf_aid = 0;
+ if (app_enc_key) *app_enc_key = enc_key;
+ if (net_idx) *net_idx = node_get_primary_net_idx(node);
+
+ } else {
+ struct mesh_app_key *app_key = find_app_key_by_idx(app_idx);
+ struct mesh_net_key *net_key;
+ bool phase_two;
+
+
+ if (app_key == NULL)
+ return false;
+
+ net_key = find_net_key_by_idx(app_key->net_idx);
+
+ if (net_key == NULL)
+ return false;
+
+ if (net_idx) *net_idx = app_key->net_idx;
+
+ phase_two = !!(net_key->phase == 2);
+
+ if (phase_two && app_key->new.akf_aid != 0xff) {
+ if (app_enc_key) *app_enc_key = app_key->new.key;
+ if (akf_aid) *akf_aid = app_key->new.akf_aid;
+ } else {
+ if (app_enc_key) *app_enc_key = app_key->current.key;
+ if (akf_aid) *akf_aid = app_key->current.akf_aid;
+ }
+ }
+
+ return true;
+}
+
+bool net_ctl_msg_send(uint8_t ttl, uint16_t src, uint16_t dst,
+ uint8_t *buf, uint16_t len)
+{
+ struct mesh_node *node = node_get_local_node();
+ struct mesh_sar_msg sar_ctl;
+
+ /* For simplicity, we will reject segmented OB CTL messages */
+ if (len > 12 || node == NULL || buf == NULL || buf[0] & 0x80)
+ return false;
+
+ if (!src) {
+ src = node_get_primary(node);
+
+ if (!src)
+ return false;
+ }
+
+ if (ttl == 0xff)
+ ttl = net.default_ttl;
+
+ memset(&sar_ctl, 0, sizeof(sar_ctl));
+
+ if (!dst)
+ sar_ctl.proxy = true;
+
+ /* Get the default net_idx for remote device (or local) */
+ get_enc_keys(APP_IDX_DEV, dst, NULL, NULL, &sar_ctl.net_idx);
+ sar_ctl.ctl = true;
+ sar_ctl.iv_index = net.iv_index - net.iv_update;
+ sar_ctl.ttl = ttl;
+ sar_ctl.src = src;
+ sar_ctl.dst = dst;
+ sar_ctl.len = len;
+ memcpy(sar_ctl.data, buf, len);
+ send_seg(&sar_ctl, 0);
+
+ return true;
+}
+
+bool net_access_layer_send(uint8_t ttl, uint16_t src, uint32_t dst,
+ uint16_t app_idx, uint8_t *buf, uint16_t len)
+{
+ struct mesh_node *node = node_get_local_node();
+ struct mesh_sar_msg *sar;
+ uint8_t *app_enc_key = NULL;
+ uint8_t *aad = NULL;
+ uint32_t mic32;
+ uint8_t aad_len = 0;
+ uint8_t i, j, ackless_retries = 0;
+ uint8_t segN, akf_aid;
+ uint16_t net_idx;
+ bool result;
+
+ if (len > 384 || node == NULL)
+ return false;
+
+ if (!src)
+ src = node_get_primary(node);
+
+ if (!src || !dst)
+ return false;
+
+ if (ttl == 0xff)
+ ttl = net.default_ttl;
+
+ if (IS_VIRTUAL(dst)) {
+ struct mesh_virt_addr *virt = find_virt_by_dst(dst);
+
+ if (virt == NULL)
+ return false;
+
+ dst = virt->va16;
+ aad = virt->va128;
+ aad_len = sizeof(virt->va128);
+ }
+
+ result = get_enc_keys(app_idx, dst,
+ &akf_aid, &app_enc_key, &net_idx);
+
+ if (!result)
+ return false;
+
+ segN = SEG_MAX(len);
+
+ /* Only one ACK required SAR message per destination at a time */
+ if (segN && IS_UNICAST(dst)) {
+ sar = find_sar_out_by_dst(dst);
+
+ if (sar)
+ flush_sar(&net.msg_out, sar);
+ }
+
+ sar = g_malloc0(sizeof(struct mesh_sar_msg) + (segN * 12));
+
+ if (sar == NULL)
+ return false;
+
+ if (segN)
+ sar->segmented = true;
+
+ sar->ttl = ttl;
+ sar->segN = segN;
+ sar->seqAuth = net.seq_num;
+ sar->iv_index = net.iv_index - net.iv_update;
+ sar->net_idx = net_idx;
+ sar->src = src;
+ sar->dst = dst;
+ sar->akf_aid = akf_aid;
+ sar->len = len + sizeof(uint32_t);
+
+ mesh_crypto_application_encrypt(akf_aid,
+ sar->seqAuth, src,
+ dst, sar->iv_index,
+ app_enc_key,
+ aad, aad_len,
+ buf, len,
+ sar->data, &mic32,
+ sizeof(uint32_t));
+
+ /* If sending as a segmented message to a non-Unicast (thus non-ACKing)
+ * destination, send each segments multiple times. */
+ if (!IS_UNICAST(dst) && segN)
+ ackless_retries = 4;
+
+ for (j = 0; j <= ackless_retries; j++) {
+ for (i = 0; i <= segN; i++)
+ send_seg(sar, i);
+ }
+
+ if (IS_UNICAST(dst) && segN) {
+ net.msg_out = g_list_append(net.msg_out, sar);
+ sar->ack_to = g_timeout_add(2000, sar_out_ack_timeout, sar);
+ sar->msg_to = g_timeout_add(60000, sar_out_msg_timeout, sar);
+ } else
+ g_free(sar);
+
+ return true;
+}
+
+bool net_set_default_ttl(uint8_t ttl)
+{
+ if (ttl > 0x7f)
+ return false;
+
+ net.default_ttl = ttl;
+ return true;
+}
+
+uint8_t net_get_default_ttl()
+{
+ return net.default_ttl;
+}
+
+bool net_set_seq_num(uint32_t seq_num)
+{
+ if (seq_num > 0xffffff)
+ return false;
+
+ net.seq_num = seq_num;
+ return true;
+}
+
+uint32_t net_get_seq_num()
+{
+ return net.seq_num;
+}
diff --git a/mesh/node.c b/mesh/node.c
new file mode 100644
index 0000000..ba8d4b6
--- /dev/null
+++ b/mesh/node.c
@@ -0,0 +1,879 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <wordexp.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "client/display.h"
+#include "src/shared/util.h"
+#include "gdbus/gdbus.h"
+#include "monitor/uuid.h"
+#include "mesh-net.h"
+#include "config-model.h"
+#include "node.h"
+#include "keys.h"
+#include "gatt.h"
+#include "net.h"
+#include "prov-db.h"
+#include "util.h"
+
+struct mesh_model {
+ struct mesh_model_ops cbs;
+ void *user_data;
+ GList *bindings;
+ GList *subscriptions;
+ uint32_t id;
+ struct mesh_publication *pub;
+};
+
+struct mesh_element {
+ GList *models;
+ uint16_t loc;
+ uint8_t index;
+};
+
+struct mesh_node {
+ const char *name;
+ GList *net_keys;
+ GList *app_keys;
+ void *prov;
+ GList *elements;
+ uint32_t iv_index;
+ uint32_t seq_number;
+ uint16_t primary_net_idx;
+ uint16_t primary;
+ uint16_t oob;
+ uint16_t features;
+ uint8_t gatt_pkt[MAX_GATT_SIZE];
+ uint8_t dev_uuid[16];
+ uint8_t dev_key[16];
+ uint8_t num_ele;
+ uint8_t ttl;
+ uint8_t gatt_size;
+ bool provisioner;
+ struct mesh_node_composition *comp;
+};
+
+static GList *nodes;
+
+static struct mesh_node *local_node;
+
+static int match_node_unicast(const void *a, const void *b)
+{
+ const struct mesh_node *node = a;
+ uint16_t dst = GPOINTER_TO_UINT(b);
+
+ if (dst >= node->primary &&
+ dst <= (node->primary + node->num_ele - 1))
+ return 0;
+
+ return -1;
+}
+
+static int match_device_uuid(const void *a, const void *b)
+{
+ const struct mesh_node *node = a;
+ const uint8_t *uuid = b;
+
+ return memcmp(node->dev_uuid, uuid, 16);
+}
+
+static int match_element_idx(const void *a, const void *b)
+{
+ const struct mesh_element *element = a;
+ uint32_t index = GPOINTER_TO_UINT(b);
+
+ return (element->index == index) ? 0 : -1;
+}
+
+static int match_model_id(const void *a, const void *b)
+{
+ const struct mesh_model *model = a;
+ uint32_t id = GPOINTER_TO_UINT(b);
+
+ return (model->id == id) ? 0 : -1;
+}
+
+struct mesh_node *node_find_by_addr(uint16_t addr)
+{
+ GList *l;
+
+ if (!IS_UNICAST(addr))
+ return NULL;
+
+ l = g_list_find_custom(nodes, GUINT_TO_POINTER(addr),
+ match_node_unicast);
+
+ if (l)
+ return l->data;
+ else
+ return NULL;
+}
+
+struct mesh_node *node_find_by_uuid(uint8_t uuid[16])
+{
+ GList *l;
+
+ l = g_list_find_custom(nodes, uuid, match_device_uuid);
+
+ if (l)
+ return l->data;
+ else
+ return NULL;
+}
+
+struct mesh_node *node_create_new(struct prov_svc_data *prov)
+{
+ struct mesh_node *node;
+
+ if (node_find_by_uuid(prov->dev_uuid))
+ return NULL;
+
+ node = g_malloc0(sizeof(struct mesh_node));
+ if (!node)
+ return NULL;
+
+ memcpy(node->dev_uuid, prov->dev_uuid, 16);
+ node->oob = prov->oob;
+ nodes = g_list_append(nodes, node);
+
+ return node;
+}
+
+struct mesh_node *node_new(void)
+{
+ struct mesh_node *node;
+
+ node = g_malloc0(sizeof(struct mesh_node));
+ if (!node)
+ return NULL;
+
+ nodes = g_list_append(nodes, node);
+
+ return node;
+}
+
+static void model_free(void *data)
+{
+ struct mesh_model *model = data;
+
+ g_list_free(model->bindings);
+ g_list_free(model->subscriptions);
+ g_free(model->pub);
+ g_free(model);
+}
+
+static void element_free(void *data)
+{
+ struct mesh_element *element = data;
+
+ g_list_free_full(element->models, model_free);
+ g_free(element);
+}
+
+static void free_node_resources(void *data)
+{
+ struct mesh_node *node = data;
+ g_list_free(node->net_keys);
+ g_list_free(node->app_keys);
+
+ g_list_free_full(node->elements, element_free);
+
+ if(node->comp)
+ g_free(node->comp);
+
+ g_free(node);
+}
+
+void node_free(struct mesh_node *node)
+{
+ if (!node)
+ return;
+ nodes = g_list_remove(nodes, node);
+ free_node_resources(node);
+}
+
+void node_cleanup(void)
+{
+ g_list_free_full(nodes, free_node_resources);
+ local_node = NULL;
+}
+
+bool node_is_provisioned(struct mesh_node *node)
+{
+ return (!IS_UNASSIGNED(node->primary));
+}
+
+void *node_get_prov(struct mesh_node *node)
+{
+ return node->prov;
+}
+
+void node_set_prov(struct mesh_node *node, void *prov)
+{
+ node->prov = prov;
+}
+
+bool node_app_key_add(struct mesh_node *node, uint16_t idx)
+{
+ uint32_t index;
+ uint16_t net_idx;
+
+ if (!node)
+ return false;
+
+ net_idx = keys_app_key_get_bound(idx);
+ if (net_idx == NET_IDX_INVALID)
+ return false;
+
+ if (!g_list_find(node->net_keys, GUINT_TO_POINTER(net_idx)))
+ return false;
+
+ index = (net_idx << 16) + idx;
+
+ if (g_list_find(node->app_keys, GUINT_TO_POINTER(index)))
+ return false;
+
+ node->app_keys = g_list_append(node->app_keys, GUINT_TO_POINTER(index));
+
+ return true;
+}
+
+bool node_net_key_add(struct mesh_node *node, uint16_t index)
+{
+ if(!node)
+ return false;
+
+ if (g_list_find(node->net_keys, GUINT_TO_POINTER(index)))
+ return false;
+
+ node->net_keys = g_list_append(node->net_keys, GUINT_TO_POINTER(index));
+ return true;
+}
+
+bool node_net_key_delete(struct mesh_node *node, uint16_t index)
+{
+ GList *l;
+
+ if(!node)
+ return false;
+
+ l = g_list_find(node->net_keys, GUINT_TO_POINTER(index));
+ if (!l)
+ return false;
+
+ node->net_keys = g_list_remove(node->net_keys,
+ GUINT_TO_POINTER(index));
+ /* TODO: remove all associated app keys and bindings */
+ return true;
+}
+
+bool node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
+ uint16_t idx)
+{
+ GList *l;
+ uint32_t index;
+
+ if(!node)
+ return false;
+
+ index = (net_idx << 16) + idx;
+
+ l = g_list_find(node->app_keys, GUINT_TO_POINTER(index));
+ if (!l)
+ return false;
+
+ node->app_keys = g_list_remove(node->app_keys,
+ GUINT_TO_POINTER(index));
+ /* TODO: remove all associated bindings */
+ return true;
+}
+
+void node_set_primary(struct mesh_node *node, uint16_t unicast)
+{
+ node->primary = unicast;
+}
+
+uint16_t node_get_primary(struct mesh_node *node)
+{
+ if (!node)
+ return UNASSIGNED_ADDRESS;
+ else
+ return node->primary;
+}
+
+void node_set_device_key(struct mesh_node *node, uint8_t *key)
+
+{
+ if (!node || !key)
+ return;
+
+ memcpy(node->dev_key, key, 16);
+}
+
+uint8_t *node_get_device_key(struct mesh_node *node)
+{
+ if (!node)
+ return NULL;
+ else
+ return node->dev_key;
+}
+
+void node_set_num_elements(struct mesh_node *node, uint8_t num_ele)
+{
+ node->num_ele = num_ele;
+}
+
+uint8_t node_get_num_elements(struct mesh_node *node)
+{
+ return node->num_ele;
+}
+
+GList *node_get_net_keys(struct mesh_node *node)
+{
+ if (!node)
+ return NULL;
+ else
+ return node->net_keys;
+}
+
+GList *node_get_app_keys(struct mesh_node *node)
+{
+ if (!node)
+ return NULL;
+ else
+ return node->app_keys;
+}
+
+bool node_parse_composition(struct mesh_node *node, uint8_t *data, uint16_t len)
+{
+ struct mesh_node_composition *comp;
+ uint16_t features;
+ int i;
+
+ comp = g_malloc0(sizeof(struct mesh_node_composition));
+ if (!comp)
+ return false;
+
+ /* skip page -- We only support Page Zero */
+ data++;
+ len--;
+
+ comp->cid = get_le16(&data[0]);
+ comp->pid = get_le16(&data[2]);
+ comp->vid = get_le16(&data[4]);
+ comp->crpl = get_le16(&data[6]);
+ features = get_le16(&data[8]);
+ data += 10;
+ len -= 10;
+
+ comp->relay = !!(features & MESH_FEATURE_RELAY);
+ comp->proxy = !!(features & MESH_FEATURE_PROXY);
+ comp->friend = !!(features & MESH_FEATURE_FRIEND);
+ comp->lpn = !!(features & MESH_FEATURE_LPN);
+
+ for (i = 0; i< node->num_ele; i++) {
+ uint8_t m, v;
+ uint32_t mod_id;
+ uint16_t vendor_id;
+ struct mesh_element *ele;
+ ele = g_malloc0(sizeof(struct mesh_element));
+ if (!ele)
+ return false;
+
+ ele->index = i;
+ ele->loc = get_le16(data);
+ data += 2;
+ node->elements = g_list_append(node->elements, ele);
+
+ m = *data++;
+ v = *data++;
+ len -= 4;
+
+ while (len >= 2 && m--) {
+ mod_id = get_le16(data);
+ /* initialize uppper 16 bits to 0xffff for SIG models */
+ mod_id |= 0xffff0000;
+ if (!node_set_model(node, ele->index, mod_id))
+ return false;
+ data += 2;
+ len -= 2;
+ }
+ while (len >= 4 && v--) {
+ mod_id = get_le16(data);
+ vendor_id = get_le16(data);
+ mod_id |= (vendor_id << 16);
+ if (!node_set_model(node, ele->index, mod_id))
+ return false;
+ data += 4;
+ len -= 4;
+ }
+
+ }
+
+ node->comp = comp;
+ return true;
+}
+
+bool node_set_local_node(struct mesh_node *node)
+{
+ if (local_node) {
+ rl_printf("Local node already registered\n");
+ return false;
+ }
+ net_register_unicast(node->primary, node->num_ele);
+
+ local_node = node;
+ local_node->provisioner = true;
+
+ return true;
+}
+
+struct mesh_node *node_get_local_node()
+{
+ return local_node;
+}
+
+uint16_t node_get_primary_net_idx(struct mesh_node *node)
+{
+ if (node == NULL)
+ return NET_IDX_INVALID;
+
+ return node->primary_net_idx;
+}
+
+static bool deliver_model_data(struct mesh_element* element, uint16_t src,
+ uint16_t app_idx, uint8_t *data, uint16_t len)
+{
+ GList *l;
+
+ for(l = element->models; l; l = l->next) {
+ struct mesh_model *model = l->data;
+
+ if (!g_list_find(model->bindings, GUINT_TO_POINTER(app_idx)))
+ continue;
+
+ if (model->cbs.recv &&
+ model->cbs.recv(src, data, len, model->user_data))
+ return true;
+ }
+
+ return false;
+}
+
+void node_local_data_handler(uint16_t src, uint32_t dst,
+ uint32_t iv_index, uint32_t seq_num,
+ uint16_t app_idx, uint8_t *data, uint16_t len)
+{
+ GList *l;
+ bool res;
+ uint64_t iv_seq;
+ uint64_t iv_seq_remote;
+ uint8_t ele_idx;
+ struct mesh_element *element;
+ struct mesh_node *remote;
+ bool loopback;
+
+ if (!local_node || seq_num > 0xffffff)
+ return;
+
+ iv_seq = iv_index << 24;
+ iv_seq |= seq_num;
+
+ remote = node_find_by_addr(src);
+
+ if (!remote) {
+ if (local_node->provisioner) {
+ rl_printf("Remote node unknown (%4.4x)\n", src);
+ return;
+ }
+
+ remote = g_new0(struct mesh_node, 1);
+ if (!remote)
+ return;
+
+ /* Not Provisioner; Assume all SRC elements stand alone */
+ remote->primary = src;
+ remote->num_ele = 1;
+ nodes = g_list_append(nodes, remote);
+ }
+
+ loopback = (src < (local_node->primary + local_node->num_ele) &&
+ src >= local_node->primary);
+
+ if (!loopback) {
+ iv_seq_remote = remote->iv_index << 24;
+ iv_seq |= remote->seq_number;
+
+ if (iv_seq_remote >= iv_seq) {
+ rl_printf("Replayed message detected "
+ "(%14lx >= %14lx)\n",
+ iv_seq_remote, iv_seq);
+ return;
+ }
+ }
+
+ if (IS_GROUP(dst) || IS_VIRTUAL(dst)) {
+ /* TODO: if subscription address, deliver to subscribers */
+ return;
+ }
+
+ if (IS_ALL_NODES(dst)) {
+ ele_idx = 0;
+ } else {
+ if (dst >= (local_node->primary + local_node->num_ele) ||
+ dst < local_node->primary)
+ return;
+
+ ele_idx = dst - local_node->primary;
+ }
+
+ l = g_list_find_custom(local_node->elements,
+ GUINT_TO_POINTER(ele_idx), match_element_idx);
+
+ /* This should not happen */
+ if (!l)
+ return;
+
+ element = l->data;
+ res = deliver_model_data(element, src, app_idx, data, len);
+
+ if (res && !loopback) {
+ /* TODO: Save remote in Replay Protection db */
+ remote->iv_index = iv_index;
+ remote->seq_number = seq_num;
+ prov_db_node_set_iv_seq(remote, iv_index, seq_num);
+ }
+}
+
+static gboolean restore_model_state(gpointer data)
+{
+ struct mesh_model *model = data;
+ GList *l;
+ struct mesh_model_ops *ops;
+
+ ops = &model->cbs;
+
+ if (model->bindings && ops->bind) {
+ for (l = model->bindings; l; l = l->next) {
+ if (ops->bind(GPOINTER_TO_UINT(l->data), ACTION_ADD) !=
+ MESH_STATUS_SUCCESS)
+ break;
+ }
+ }
+
+ if (model->pub && ops->pub)
+ ops->pub(model->pub);
+
+ g_idle_remove_by_data(data);
+
+ return true;
+
+}
+
+bool node_local_model_register(uint8_t ele_idx, uint16_t model_id,
+ struct mesh_model_ops *ops, void *user_data)
+{
+ uint32_t id = 0xffff0000 | model_id;
+
+ return node_local_vendor_model_register(ele_idx, id, ops, user_data);
+}
+
+bool node_local_vendor_model_register(uint8_t ele_idx, uint32_t model_id,
+ struct mesh_model_ops *ops, void *user_data)
+{
+ struct mesh_element *ele;
+ struct mesh_model *model;
+ GList *l;
+
+ if (!local_node)
+ return false;
+
+ l = g_list_find_custom(local_node->elements, GUINT_TO_POINTER(ele_idx),
+ match_element_idx);
+ if (!l)
+ return false;
+
+ ele = l->data;
+
+ l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
+ match_model_id);
+ if (!l)
+ return false;
+
+ model = l->data;
+ model->cbs = *ops;
+ model->user_data = user_data;
+
+ if (model_id >= 0xffff0000)
+ model_id = model_id & 0xffff;
+
+ /* Silently assign device key binding to configuration models */
+ if (model_id == CONFIG_SERVER_MODEL_ID ||
+ model_id == CONFIG_CLIENT_MODEL_ID) {
+ model->bindings = g_list_append(model->bindings,
+ GUINT_TO_POINTER(APP_IDX_DEV));
+ } else {
+ g_idle_add(restore_model_state, model);
+ }
+
+ return true;
+}
+
+bool node_set_element(struct mesh_node *node, uint8_t ele_idx)
+{
+ struct mesh_element *ele;
+ GList *l;
+
+ if (!node)
+ return false;
+
+ l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
+ match_element_idx);
+ if (l)
+ return false;
+
+ ele = g_malloc0(sizeof(struct mesh_element));
+ if (!ele)
+ return false;
+
+ ele->index = ele_idx;
+ node->elements = g_list_append(node->elements, ele);
+
+ return true;
+}
+
+bool node_set_model(struct mesh_node *node, uint8_t ele_idx, uint32_t id)
+{
+ struct mesh_element *ele;
+ struct mesh_model *model;
+ GList *l;
+
+ if (!node)
+ return false;
+
+ l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
+ match_element_idx);
+ if (!l)
+ return false;
+
+ ele = l->data;
+
+ l = g_list_find_custom(ele->models, GUINT_TO_POINTER(id),
+ match_model_id);
+ if (l)
+ return false;
+
+ model = g_malloc0(sizeof(struct mesh_model));
+ if (!model)
+ return false;
+
+ model->id = id;
+ ele->models = g_list_append(ele->models, model);
+
+ return true;
+}
+
+bool node_set_composition(struct mesh_node *node,
+ struct mesh_node_composition *comp)
+{
+ if (!node || !comp || node->comp)
+ return false;
+
+ node->comp = g_malloc0(sizeof(struct mesh_node_composition));
+ if (!node->comp)
+ return false;
+
+ *(node->comp) = *comp;
+ return true;
+}
+
+struct mesh_node_composition *node_get_composition(struct mesh_node *node)
+{
+ if (!node)
+ return NULL;
+
+ return node->comp;
+}
+
+static struct mesh_model *get_model(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id)
+{
+ struct mesh_element *ele;
+ GList *l;
+
+ if (!node)
+ return NULL;
+
+ l = g_list_find_custom(node->elements, GUINT_TO_POINTER(ele_idx),
+ match_element_idx);
+ if (!l)
+ return NULL;
+
+ ele = l->data;
+
+ l = g_list_find_custom(ele->models, GUINT_TO_POINTER(model_id),
+ match_model_id);
+ if (!l)
+ return NULL;
+
+ return l->data;
+
+}
+
+bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id, uint16_t app_idx)
+{
+ struct mesh_model *model;
+ GList *l;
+
+ model = get_model(node, ele_idx, model_id);
+ if(!model)
+ return false;
+
+ l = g_list_find(model->bindings, GUINT_TO_POINTER(app_idx));
+ if (l)
+ return false;
+
+ if ((node == local_node) && model->cbs.bind) {
+ if (!model->cbs.bind(app_idx, ACTION_ADD))
+ return false;
+ }
+
+ model->bindings = g_list_append(model->bindings,
+ GUINT_TO_POINTER(app_idx));
+
+ return true;
+}
+
+uint8_t node_get_default_ttl(struct mesh_node *node)
+{
+ if (!node)
+ return DEFAULT_TTL;
+ else if (node == local_node)
+ return net_get_default_ttl();
+ else
+ return node->ttl;
+}
+
+bool node_set_default_ttl(struct mesh_node *node, uint8_t ttl)
+{
+ if (!node)
+ return false;
+
+ node->ttl = ttl;
+
+ if (node == local_node || local_node == NULL)
+ return net_set_default_ttl(ttl);
+
+ return true;
+}
+
+bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
+{
+ if (!node)
+ return false;
+
+ node->seq_number = seq;
+
+ if (node == local_node || local_node == NULL)
+ return net_set_seq_num(seq);
+
+ return true;
+}
+
+uint32_t node_get_sequence_number(struct mesh_node *node)
+{
+ if (!node)
+ return 0xffffffff;
+ else if (node == local_node)
+ return net_get_seq_num();
+
+ return node->seq_number;
+}
+
+bool node_set_iv_index(struct mesh_node *node, uint32_t iv_index)
+{
+ if (!node)
+ return false;
+
+ node->iv_index = iv_index;
+ return true;
+}
+
+uint32_t node_get_iv_index(struct mesh_node *node)
+{
+ bool update;
+
+ if (!node)
+ return 0xffffffff;
+ else if (node == local_node)
+ return net_get_iv_index(&update);
+ return node->iv_index;
+}
+
+bool node_model_pub_set(struct mesh_node *node, uint8_t ele, uint32_t model_id,
+ struct mesh_publication *pub)
+{
+ struct mesh_model *model;
+
+ model = get_model(node, ele, model_id);
+ if(!model)
+ return false;
+
+ if (!model->pub)
+ model->pub = g_malloc0(sizeof(struct mesh_publication));
+ if (!model)
+ return false;
+
+ memcpy(model->pub, pub, (sizeof(struct mesh_publication)));
+
+ if((node == local_node) && model->cbs.pub)
+ model->cbs.pub(pub);
+ return true;
+}
+
+struct mesh_publication *node_model_pub_get(struct mesh_node *node, uint8_t ele,
+ uint32_t model_id)
+{
+ struct mesh_model *model;
+
+ model = get_model(node, ele, model_id);
+ if(!model)
+ return NULL;
+ else
+ return model->pub;
+}
diff --git a/mesh/onoff-model.c b/mesh/onoff-model.c
new file mode 100644
index 0000000..61c6ed6
--- /dev/null
+++ b/mesh/onoff-model.c
@@ -0,0 +1,306 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <wordexp.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "client/display.h"
+#include "src/shared/util.h"
+#include "mesh-net.h"
+#include "keys.h"
+#include "net.h"
+#include "node.h"
+#include "prov-db.h"
+#include "util.h"
+#include "onoff-model.h"
+
+static uint8_t trans_id;
+static uint16_t onoff_app_idx = APP_IDX_INVALID;
+
+static int client_bind(uint16_t app_idx, int action)
+{
+ if (action == ACTION_ADD) {
+ if (onoff_app_idx != APP_IDX_INVALID) {
+ return MESH_STATUS_INSUFF_RESOURCES;
+ } else {
+ onoff_app_idx = app_idx;
+ rl_printf("On/Off client model: new binding %4.4x\n",
+ app_idx);
+ }
+ } else {
+ if (onoff_app_idx == app_idx)
+ onoff_app_idx = APP_IDX_INVALID;
+ }
+ return MESH_STATUS_SUCCESS;
+}
+
+static void print_remaining_time(uint8_t remaining_time)
+{
+ uint8_t step = (remaining_time & 0xc0) >> 6;
+ uint8_t count = remaining_time & 0x3f;
+ int secs = 0, msecs = 0, minutes = 0, hours = 0;
+
+ switch (step) {
+ case 0:
+ msecs = 100 * count;
+ secs = msecs / 60;
+ msecs -= (secs * 60);
+ break;
+ case 1:
+ secs = 1 * count;
+ minutes = secs / 60;
+ secs -= (minutes * 60);
+ break;
+
+ case 2:
+ secs = 10 * count;
+ minutes = secs / 60;
+ secs -= (minutes * 60);
+ break;
+ case 3:
+ minutes = 10 * count;
+ hours = minutes / 60;
+ minutes -= (hours * 60);
+ break;
+
+ default:
+ break;
+ }
+
+ rl_printf("\n\t\tRemaining time: %d hrs %d mins %d secs %d msecs\n",
+ hours, minutes, secs, msecs);
+
+}
+
+static bool client_msg_recvd(uint16_t src, uint8_t *data,
+ uint16_t len, void *user_data)
+{
+ uint32_t opcode;
+ int n;
+
+ if (mesh_opcode_get(data, len, &opcode, &n)) {
+ len -= n;
+ data += n;
+ } else
+ return false;
+
+ rl_printf("On Off Model Message received (%d) opcode %x\n",
+ len, opcode);
+ print_byte_array("\t",data, len);
+
+ switch (opcode & ~OP_UNRELIABLE) {
+ default:
+ return false;
+
+ case OP_GENERIC_ONOFF_STATUS:
+ if (len != 1 && len != 3)
+ break;
+
+ rl_printf("Node %4.4x: Off Status present = %s",
+ src, data[0] ? "ON" : "OFF");
+
+ if (len == 3) {
+ rl_printf(", target = %s", data[1] ? "ON" : "OFF");
+ print_remaining_time(data[2]);
+ } else
+ rl_printf("\n");
+ break;
+ }
+
+ return true;
+}
+
+
+static uint32_t target;
+static uint32_t parms[8];
+
+static uint32_t read_input_parameters(const char *args)
+{
+ uint32_t i;
+
+ if (!args)
+ return 0;
+
+ memset(parms, 0xff, sizeof(parms));
+
+ for (i = 0; i < sizeof(parms)/sizeof(parms[0]); i++) {
+ int n;
+
+ sscanf(args, "%x", &parms[i]);
+ if (parms[i] == 0xffffffff)
+ break;
+
+ n = strcspn(args, " \t");
+ args = args + n + strspn(args + n, " \t");
+ }
+
+ return i;
+}
+
+static void cmd_set_node(const char *args)
+{
+ uint32_t dst;
+ char *end;
+
+ dst = strtol(args, &end, 16);
+ if (end != (args + 4)) {
+ rl_printf("Bad unicast address %s: "
+ "expected format 4 digit hex\n",
+ args);
+ target = UNASSIGNED_ADDRESS;
+ } else {
+ rl_printf("Controlling ON/OFF for node %4.4x\n", dst);
+ target = dst;
+ set_menu_prompt("on/off", args);
+ }
+}
+
+static bool send_cmd(uint8_t *buf, uint16_t len)
+{
+ struct mesh_node *node = node_get_local_node();
+ uint8_t ttl;
+
+ if(!node)
+ return false;
+
+ ttl = node_get_default_ttl(node);
+
+ return net_access_layer_send(ttl, node_get_primary(node),
+ target, onoff_app_idx, buf, len);
+}
+
+static void cmd_get_status(const char *args)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ struct mesh_node *node;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ node = node_find_by_addr(target);
+
+ if (!node)
+ return;
+
+ n = mesh_opcode_set(OP_GENERIC_ONOFF_GET, msg);
+
+ if (!send_cmd(msg, n))
+ rl_printf("Failed to send \"GENERIC ON/OFF GET\"\n");
+}
+
+static void cmd_set(const char *args)
+{
+ uint16_t n;
+ uint8_t msg[32];
+ struct mesh_node *node;
+
+ if (IS_UNASSIGNED(target)) {
+ rl_printf("Destination not set\n");
+ return;
+ }
+
+ node = node_find_by_addr(target);
+
+ if (!node)
+ return;
+
+ if ((read_input_parameters(args) != 1) &&
+ parms[0] != 0 && parms[0] != 1) {
+ rl_printf("Bad arguments %s. Expecting \"0\" or \"1\"\n", args);
+ return;
+ }
+
+ n = mesh_opcode_set(OP_GENERIC_ONOFF_SET, msg);
+ msg[n++] = parms[0];
+ msg[n++] = trans_id++;
+
+ if (!send_cmd(msg, n))
+ rl_printf("Failed to send \"GENERIC ON/OFF SET\"\n");
+
+}
+
+static void cmd_back(const char *args)
+{
+ cmd_menu_main(false);
+}
+
+static void cmd_help(const char *args);
+
+static const struct menu_entry cfg_menu[] = {
+ {"target", "<unicast>", cmd_set_node,
+ "Set node to configure"},
+ {"get", NULL, cmd_get_status,
+ "Get ON/OFF status"},
+ {"onoff", "<0/1>", cmd_set,
+ "Send \"SET ON/OFF\" command"},
+ {"back", NULL, cmd_back,
+ "Back to main menu"},
+ {"help", NULL, cmd_help,
+ "Config Commands"},
+ {}
+};
+
+static void cmd_help(const char *args)
+{
+ rl_printf("Client Configuration Menu\n");
+ print_cmd_menu(cfg_menu);
+}
+
+void onoff_set_node(const char *args) {
+ cmd_set_node(args);
+}
+
+static struct mesh_model_ops client_cbs = {
+ client_msg_recvd,
+ client_bind,
+ NULL,
+ NULL
+};
+
+bool onoff_client_init(uint8_t ele)
+{
+ if (!node_local_model_register(ele, GENERIC_ONOFF_CLIENT_MODEL_ID,
+ &client_cbs, NULL))
+ return false;
+
+ add_cmd_menu("onoff", cfg_menu);
+
+ return true;
+}
diff --git a/mesh/prov-db.c b/mesh/prov-db.c
new file mode 100644
index 0000000..aad6145
--- /dev/null
+++ b/mesh/prov-db.c
@@ -0,0 +1,1599 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <json-c/json.h>
+#include <sys/stat.h>
+
+#include <readline/readline.h>
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "client/display.h"
+
+#include "mesh-net.h"
+#include "crypto.h"
+#include "keys.h"
+#include "net.h"
+#include "node.h"
+#include "util.h"
+#include "prov-db.h"
+
+#define CHECK_KEY_IDX_RANGE(x) (((x) >= 0) && ((x) <= 4095))
+
+static const char *prov_filename;
+static const char *local_filename;
+
+static char* prov_file_read(const char *filename)
+{
+ int fd;
+ char *str;
+ struct stat st;
+ ssize_t sz;
+
+ if (!filename)
+ return NULL;
+
+ fd = open(filename,O_RDONLY);
+ if (!fd)
+ return NULL;
+
+ if (fstat(fd, &st) == -1) {
+ close(fd);
+ return NULL;
+ }
+
+ str = (char *) g_malloc0(st.st_size + 1);
+ if (!str) {
+ close(fd);
+ return NULL;
+ }
+
+ sz = read(fd, str, st.st_size);
+ if (sz != st.st_size)
+ rl_printf("Incomplete read: %d vs %d\n", (int)sz,
+ (int)(st.st_size));
+
+ close(fd);
+
+ return str;
+}
+
+static void prov_file_write(json_object *jmain, bool local)
+{
+ FILE *outfile;
+ const char *out_str;
+ const char *out_filename;
+
+ if (local)
+ out_filename = local_filename;
+ else
+ out_filename = prov_filename;
+
+ outfile = fopen(out_filename, "wr");
+ if (!outfile) {
+ rl_printf("Failed to open file %s for writing\n", out_filename);
+ return;
+ }
+
+ out_str = json_object_to_json_string_ext(jmain,
+ JSON_C_TO_STRING_PRETTY);
+
+ fwrite(out_str, sizeof(char), strlen(out_str), outfile);
+ fclose(outfile);
+}
+
+static void put_uint16(json_object *jobject, const char *desc, uint16_t value)
+{
+ json_object *jstring;
+ char buf[5];
+
+ snprintf(buf, 5, "%4.4x", value);
+ jstring = json_object_new_string(buf);
+ json_object_object_add(jobject, desc, jstring);
+}
+
+static void put_uint32(json_object *jobject, const char *desc, uint32_t value)
+{
+ json_object *jstring;
+ char buf[9];
+
+ snprintf(buf, 9, "%8.8x", value);
+ jstring = json_object_new_string(buf);
+ json_object_object_add(jobject, desc, jstring);
+}
+
+static void put_uint16_array_entry(json_object *jarray, uint16_t value)
+{
+ json_object *jstring;
+ char buf[5];
+
+ snprintf(buf, 5, "%4.4x", value);
+ jstring = json_object_new_string(buf);
+ json_object_array_add(jarray, jstring);
+}
+
+static void put_uint32_array_entry(json_object *jarray, uint32_t value)
+{
+ json_object *jstring;
+ char buf[9];
+
+ snprintf(buf, 9, "%8.8x", value);
+ jstring = json_object_new_string(buf);
+ json_object_array_add(jarray, jstring);
+}
+
+static void put_uint16_list(json_object *jarray, GList *list)
+{
+ GList *l;
+
+ if (!list)
+ return;
+
+ for (l = list; l; l = l->next) {
+ uint32_t ivalue = GPOINTER_TO_UINT(l->data);
+ put_uint16_array_entry(jarray, ivalue);
+ }
+}
+
+static void add_node_idxs(json_object *jnode, const char *desc,
+ GList *idxs)
+{
+ json_object *jarray;
+
+ jarray = json_object_new_array();
+
+ put_uint16_list(jarray, idxs);
+
+ json_object_object_add(jnode, desc, jarray);
+}
+
+static bool parse_unicast_range(json_object *jobject)
+{
+ int cnt;
+ int i;
+
+ cnt = json_object_array_length(jobject);
+
+ for (i = 0; i < cnt; ++i) {
+ json_object *jrange;
+ json_object *jvalue;
+ uint16_t low, high;
+ char *str;
+
+ jrange = json_object_array_get_idx(jobject, i);
+ json_object_object_get_ex(jrange, "lowAddress", &jvalue);
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &low) != 1)
+ return false;
+
+ json_object_object_get_ex(jrange, "highAddress", &jvalue);
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &high) != 1)
+ return false;
+
+ if(high < low)
+ return false;
+
+ net_add_address_pool(low, high);
+ }
+ return true;
+}
+
+static int parse_node_keys(struct mesh_node *node, json_object *jidxs,
+ bool is_app_key)
+{
+ int idx_cnt;
+ int i;
+
+ idx_cnt = json_object_array_length(jidxs);
+ for (i = 0; i < idx_cnt; ++i) {
+ int idx;
+ json_object *jvalue;
+
+ jvalue = json_object_array_get_idx(jidxs, i);
+ if (!jvalue)
+ break;
+ idx = json_object_get_int(jvalue);
+ if (!CHECK_KEY_IDX_RANGE(idx))
+ break;
+
+ if (is_app_key)
+ node_app_key_add(node, idx);
+ else
+ node_net_key_add(node, idx);
+ }
+
+ return i;
+}
+
+static bool parse_composition_models(struct mesh_node *node, int index,
+ json_object *jmodels)
+{
+ int model_cnt;
+ int i;
+
+ model_cnt = json_object_array_length(jmodels);
+
+ for (i = 0; i < model_cnt; ++i) {
+ json_object *jmodel;
+ char *str;
+ uint32_t model_id;
+ int len;
+
+ jmodel = json_object_array_get_idx(jmodels, i);
+ str = (char *)json_object_get_string(jmodel);
+ len = strlen(str);
+
+ if (len != 4 && len != 8)
+ return false;
+
+ if (sscanf(str, "%08x", &model_id) != 1)
+ return false;
+ if (len == 4)
+ model_id += 0xffff0000;
+
+ node_set_model(node, index, model_id);
+ }
+
+ return true;
+}
+
+static bool parse_composition_elements(struct mesh_node *node,
+ json_object *jelements)
+{
+ int el_cnt;
+ int i;
+
+ el_cnt = json_object_array_length(jelements);
+ node_set_num_elements(node, el_cnt);
+
+ for (i = 0; i < el_cnt; ++i) {
+ json_object *jelement;
+ json_object *jmodels;
+ json_object *jvalue;
+ int index;
+
+ jelement = json_object_array_get_idx(jelements, i);
+ json_object_object_get_ex(jelement, "elementIndex", &jvalue);
+ if (jvalue) {
+ index = json_object_get_int(jvalue);
+ if (index >= el_cnt) {
+ return false;
+ }
+ } else
+ return false;
+
+ if (!node_set_element(node, index))
+ return false;
+
+ json_object_object_get_ex(jelement, "models", &jmodels);
+ if (!jmodels)
+ continue;
+
+ if(!parse_composition_models(node, index, jmodels))
+ return false;
+ }
+ return true;
+}
+
+static bool parse_model_pub(struct mesh_node *node, int ele_idx,
+ uint32_t model_id, json_object *jpub)
+{
+ json_object *jvalue;
+ struct mesh_publication pub;
+ char *str;
+
+ memset(&pub, 0, sizeof(struct mesh_publication));
+
+ /* Read only required fields */
+ json_object_object_get_ex(jpub, "address", &jvalue);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &pub.u.addr16) != 1)
+ return false;
+
+ json_object_object_get_ex(jpub, "index", &jvalue);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &pub.app_idx) != 1)
+ return false;
+
+
+ json_object_object_get_ex(jpub, "ttl", &jvalue);
+ pub.ttl = json_object_get_int(jvalue);
+
+ if (!node_model_pub_set(node, ele_idx, model_id, &pub))
+ return false;
+
+ return true;
+}
+
+static bool parse_bindings(struct mesh_node *node, int ele_idx,
+ uint32_t model_id, json_object *jbindings)
+{
+ int cnt;
+ int i;
+
+ cnt = json_object_array_length(jbindings);
+
+ for (i = 0; i < cnt; ++i) {
+ int key_idx;
+ json_object *jvalue;
+
+ jvalue = json_object_array_get_idx(jbindings, i);
+ if (!jvalue)
+ return true;
+
+ key_idx = json_object_get_int(jvalue);
+ if (!CHECK_KEY_IDX_RANGE(key_idx))
+ return false;
+
+ if (!node_add_binding(node, ele_idx, model_id, key_idx))
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_configuration_models(struct mesh_node *node, int ele_idx,
+ json_object *jmodels, uint32_t target_id, json_object **jtarget)
+{
+ int model_cnt;
+ int i;
+
+ if (jtarget)
+ *jtarget = NULL;
+
+ model_cnt = json_object_array_length(jmodels);
+
+ for (i = 0; i < model_cnt; ++i) {
+ json_object *jmodel;
+ json_object *jvalue;
+ json_object *jarray;
+ char *str;
+ int len;
+ uint32_t model_id;
+
+ jmodel = json_object_array_get_idx(jmodels, i);
+
+ json_object_object_get_ex(jmodel, "modelId", &jvalue);
+ str = (char *)json_object_get_string(jvalue);
+
+ len = strlen(str);
+
+ if (len != 4 && len != 8)
+ return false;
+
+ if (sscanf(str, "%08x", &model_id) != 1)
+ return false;
+ if (len == 4)
+ model_id += 0xffff0000;
+
+ if (jtarget && model_id == target_id) {
+ *jtarget = jmodel;
+ return true;
+ }
+
+ json_object_object_get_ex(jmodel, "bind", &jarray);
+ if (jarray && !parse_bindings(node, ele_idx, model_id, jarray))
+ return false;
+
+ json_object_object_get_ex(jmodel, "publish", &jvalue);
+
+ if (jvalue && !parse_model_pub(node, ele_idx, model_id, jvalue))
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_configuration_elements(struct mesh_node *node,
+ json_object *jelements, bool local)
+{
+ int el_cnt;
+ int i;
+
+ el_cnt = json_object_array_length(jelements);
+ node_set_num_elements(node, el_cnt);
+
+ for (i = 0; i < el_cnt; ++i) {
+ json_object *jelement;
+ json_object *jmodels;
+ json_object *jvalue;
+ int index;
+ uint16_t addr;
+
+ jelement = json_object_array_get_idx(jelements, i);
+ json_object_object_get_ex(jelement, "elementIndex", &jvalue);
+ if (jvalue) {
+ index = json_object_get_int(jvalue);
+ if (index >= el_cnt) {
+ return false;
+ }
+ } else
+ return false;
+
+ if (index == 0) {
+ char *str;
+
+ json_object_object_get_ex(jelement, "unicastAddress",
+ &jvalue);
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &addr) != 1)
+ return false;
+
+ if (!local && !net_reserve_address_range(addr, el_cnt))
+ return false;
+
+ node_set_primary(node, addr);
+ }
+
+ json_object_object_get_ex(jelement, "models", &jmodels);
+ if (!jmodels)
+ continue;
+
+ if(!parse_configuration_models(node, index, jmodels, 0, NULL))
+ return false;
+ }
+ return true;
+}
+
+static void add_key(json_object *jobject, const char *desc, uint8_t* key)
+{
+ json_object *jstring;
+ char hexstr[33];
+
+ hex2str(key, 16, hexstr, 33);
+ jstring = json_object_new_string(hexstr);
+ json_object_object_add(jobject, desc, jstring);
+}
+
+static json_object *find_node_by_primary(json_object *jmain, uint16_t primary)
+{
+ json_object *jarray;
+ int i, len;
+
+ json_object_object_get_ex(jmain, "nodes", &jarray);
+
+ if (!jarray)
+ return NULL;
+ len = json_object_array_length(jarray);
+
+ for (i = 0; i < len; ++i) {
+ json_object *jnode;
+ json_object *jconfig;
+ json_object *jelements;
+ json_object *jelement;
+ json_object *jvalue;
+ char *str;
+ uint16_t addr;
+
+ jnode = json_object_array_get_idx(jarray, i);
+ if (!jnode)
+ return NULL;
+
+ json_object_object_get_ex(jnode, "configuration", &jconfig);
+ if (!jconfig)
+ return NULL;
+
+ json_object_object_get_ex(jconfig, "elements", &jelements);
+ if (!jelements)
+ return NULL;
+
+ jelement = json_object_array_get_idx(jelements, 0);
+ if (!jelement)
+ return NULL;
+
+ json_object_object_get_ex(jelement, "unicastAddress",
+ &jvalue);
+ str = (char *)json_object_get_string(jvalue);
+ if (sscanf(str, "%04hx", &addr) != 1)
+ return NULL;
+
+ if (addr == primary)
+ return jnode;
+ }
+
+ return NULL;
+
+}
+
+void prov_db_print_node_composition(struct mesh_node *node)
+{
+ char *in_str;
+ const char *comp_str;
+ json_object *jmain;
+ json_object *jnode;
+ json_object *jcomp;
+ uint16_t primary = node_get_primary(node);
+ const char *filename;
+ bool res = false;
+
+ if (!node || !node_get_composition(node))
+ return;
+
+ if (node == node_get_local_node())
+ filename = local_filename;
+ else
+ filename = prov_filename;
+
+ in_str = prov_file_read(filename);
+ if (!in_str)
+ return;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ jnode = find_node_by_primary(jmain, primary);
+ if (!jnode)
+ goto done;
+
+ json_object_object_get_ex(jnode, "composition", &jcomp);
+ if (!jcomp)
+ goto done;
+
+ comp_str = json_object_to_json_string_ext(jcomp,
+ JSON_C_TO_STRING_PRETTY);
+
+ res = true;
+
+done:
+ if (res)
+ rl_printf("\tComposition data for node %4.4x %s\n",
+ primary, comp_str);
+ else
+ rl_printf("\tComposition data for node %4.4x not present\n",
+ primary);
+ g_free(in_str);
+
+ if (jmain)
+ json_object_put(jmain);
+}
+
+bool prov_db_add_node_composition(struct mesh_node *node, uint8_t *data,
+ uint16_t len)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jnode;
+ json_object *jcomp;
+ json_object *jbool;
+ json_object *jfeatures;
+ json_object *jelements;
+ struct mesh_node_composition *comp;
+ uint8_t num_ele;
+ int i;
+ uint16_t primary = node_get_primary(node);
+ bool res = NULL;
+
+ comp = node_get_composition(node);
+ if (!comp)
+ return false;
+
+ in_str = prov_file_read(prov_filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ jnode = find_node_by_primary(jmain, primary);
+ if (!jnode)
+ goto done;
+
+ jcomp = json_object_new_object();
+
+ put_uint16(jcomp, "cid", comp->cid);
+ put_uint16(jcomp, "pid", comp->pid);
+ put_uint16(jcomp, "vid", comp->pid);
+ put_uint16(jcomp, "crpl", comp->crpl);
+
+ jfeatures = json_object_new_object();
+ jbool = json_object_new_boolean(comp->relay);
+ json_object_object_add(jfeatures, "relay", jbool);
+ jbool = json_object_new_boolean(comp->proxy);
+ json_object_object_add(jfeatures, "proxy", jbool);
+ jbool = json_object_new_boolean(comp->friend);
+ json_object_object_add(jfeatures, "friend", jbool);
+ jbool = json_object_new_boolean(comp->lpn);
+ json_object_object_add(jfeatures, "lpn", jbool);
+ json_object_object_add(jcomp, "features", jfeatures);
+
+ data += 11;
+ len -= 11;
+
+ num_ele = node_get_num_elements(node);
+
+ jelements = json_object_new_array();
+
+ for (i = 0; i < num_ele; ++i) {
+ json_object *jelement;
+ json_object *jmodels;
+ json_object *jint;
+ uint32_t mod_id;
+ uint16_t vendor_id;
+ uint8_t m, v;
+
+ jelement = json_object_new_object();
+
+ /* Element Index */
+ jint = json_object_new_int(i);
+ json_object_object_add(jelement, "elementIndex", jint);
+
+ /* Location */
+ put_uint16(jelement, "location", get_le16(data));
+ data += 2;
+ m = *data++;
+ v = *data++;
+ len -= 4;
+
+ /* Models */
+ jmodels = json_object_new_array();
+ while (len >= 2 && m--) {
+ mod_id = get_le16(data);
+ data += 2;
+ len -= 2;
+ put_uint16_array_entry(jmodels, (uint16_t) mod_id);
+ }
+
+ while (len >= 4 && v--) {
+ mod_id = get_le16(data);
+ vendor_id = get_le16(data);
+ mod_id |= (vendor_id << 16);
+ data += 4;
+ len -= 4;
+ put_uint32_array_entry(jmodels, mod_id);
+ }
+
+ json_object_object_add(jelement, "models", jmodels);
+ json_object_array_add(jelements, jelement);
+ }
+
+ json_object_object_add(jcomp, "elements", jelements);
+
+ json_object_object_add(jnode, "composition", jcomp);
+
+ prov_file_write(jmain, false);
+
+ res = true;;
+done:
+
+ g_free(in_str);
+
+ if(jmain)
+ json_object_put(jmain);
+
+ return res;
+}
+
+bool prov_db_node_set_ttl(struct mesh_node *node, uint8_t ttl)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jnode;
+ json_object *jconfig;
+ json_object *jvalue;
+ uint16_t primary = node_get_primary(node);
+ const char *filename;
+ bool local = node == node_get_local_node();
+ bool res = false;
+
+ if (local)
+ filename = local_filename;
+ else
+ filename = prov_filename;
+
+ in_str = prov_file_read(filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ if (local)
+ json_object_object_get_ex(jmain, "node", &jnode);
+ else
+ jnode = find_node_by_primary(jmain, primary);
+
+ if (!jnode)
+ goto done;
+
+ json_object_object_get_ex(jnode, "configuration", &jconfig);
+ if (!jconfig)
+ goto done;
+
+ json_object_object_del(jconfig, "defaultTTL");
+
+ jvalue = json_object_new_int(ttl);
+ json_object_object_add(jconfig, "defaultTTL", jvalue);
+
+ prov_file_write(jmain, local);
+
+ res = true;
+done:
+
+ g_free(in_str);
+
+ if(jmain)
+ json_object_put(jmain);
+
+ return res;
+
+}
+
+static void set_local_iv_index(json_object *jobj, uint32_t idx, bool update)
+{
+ json_object *jvalue;
+
+ json_object_object_del(jobj, "IVindex");
+ jvalue = json_object_new_int(idx);
+ json_object_object_add(jobj, "IVindex", jvalue);
+
+ json_object_object_del(jobj, "IVupdate");
+ jvalue = json_object_new_int((update) ? 1 : 0);
+ json_object_object_add(jobj, "IVupdate", jvalue);
+
+}
+
+bool prov_db_local_set_iv_index(uint32_t iv_index, bool update, bool prov)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jnode;
+ bool res = false;
+
+ in_str = prov_file_read(local_filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ json_object_object_get_ex(jmain, "node", &jnode);
+ set_local_iv_index(jnode, iv_index, update);
+ prov_file_write(jmain, true);
+
+ g_free(in_str);
+ json_object_put(jmain);
+
+ /* If provisioner, save to global DB as well */
+ if (prov) {
+ in_str = prov_file_read(prov_filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ set_local_iv_index(jmain, iv_index, update);
+ prov_file_write(jmain, false);
+ }
+
+ res = true;
+done:
+
+ g_free(in_str);
+
+ if(jmain)
+ json_object_put(jmain);
+
+ return res;
+
+}
+
+bool prov_db_local_set_seq_num(uint32_t seq_num)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jnode;
+ json_object *jvalue;
+ bool res = false;
+
+ in_str = prov_file_read(local_filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ json_object_object_get_ex(jmain, "node", &jnode);
+
+ json_object_object_del(jnode, "sequenceNumber");
+ jvalue = json_object_new_int(seq_num);
+ json_object_object_add(jnode, "sequenceNumber", jvalue);
+
+ prov_file_write(jmain, true);
+
+ res = true;
+done:
+
+ g_free(in_str);
+
+ if(jmain)
+ json_object_put(jmain);
+
+ return res;
+}
+
+bool prov_db_node_set_iv_seq(struct mesh_node *node, uint32_t iv, uint32_t seq)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jnode;
+ json_object *jvalue;
+ uint16_t primary = node_get_primary(node);
+ bool res = false;
+
+ in_str = prov_file_read(prov_filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ jnode = find_node_by_primary(jmain, primary);
+ if (!jnode)
+ goto done;
+
+ json_object_object_del(jnode, "IVindex");
+
+ jvalue = json_object_new_int(iv);
+ json_object_object_add(jnode, "IVindex", jvalue);
+
+ json_object_object_del(jnode, "sequenceNumber");
+
+ jvalue = json_object_new_int(seq);
+ json_object_object_add(jnode, "sequenceNumber", jvalue);
+
+ prov_file_write(jmain, false);
+
+ res = true;
+done:
+
+ g_free(in_str);
+
+ if(jmain)
+ json_object_put(jmain);
+
+ return res;
+
+}
+
+bool prov_db_node_keys(struct mesh_node *node, GList *idxs, const char *desc)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jnode;
+ json_object *jconfig;
+ json_object *jidxs;
+ uint16_t primary = node_get_primary(node);
+ const char *filename;
+ bool local = (node == node_get_local_node());
+ bool res = false;
+
+ if (local)
+ filename = local_filename;
+ else
+ filename = prov_filename;
+
+ in_str = prov_file_read(filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+
+ jnode = find_node_by_primary(jmain, primary);
+ if (!jnode)
+ goto done;
+
+ json_object_object_get_ex(jnode, "configuration", &jconfig);
+ if (!jconfig)
+ goto done;
+
+ json_object_object_del(jconfig, desc);
+
+ if (idxs) {
+ jidxs = json_object_new_array();
+ put_uint16_list(jidxs, idxs);
+ json_object_object_add(jconfig, desc, jidxs);
+ }
+
+ prov_file_write(jmain, local);
+
+ res = true;
+done:
+
+ g_free(in_str);
+
+ if(jmain)
+ json_object_put(jmain);
+
+ return res;
+
+}
+
+static json_object *get_jmodel_obj(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id, json_object **jmain)
+{
+ char *in_str;
+ json_object *jnode;
+ json_object *jconfig;
+ json_object *jelements, *jelement;
+ json_object *jmodels, *jmodel = NULL;
+ uint16_t primary = node_get_primary(node);
+ const char *filename;
+ bool local = (node == node_get_local_node());
+
+ if (local)
+ filename = local_filename;
+ else
+ filename = prov_filename;
+
+ in_str = prov_file_read(filename);
+ if (!in_str)
+ return NULL;
+
+ *jmain = json_tokener_parse(in_str);
+ if (!(*jmain))
+ goto done;
+
+ if (local)
+ json_object_object_get_ex(*jmain, "node", &jnode);
+ else
+ jnode = find_node_by_primary(*jmain, primary);
+
+ if (!jnode)
+ goto done;
+
+ /* Configuration is mandatory for nodes in provisioning database */
+ json_object_object_get_ex(jnode, "configuration", &jconfig);
+ if (!jconfig)
+ goto done;
+
+ json_object_object_get_ex(jconfig, "elements", &jelements);
+ if (!jelements) {
+ goto done;
+ }
+
+ jelement = json_object_array_get_idx(jelements, ele_idx);
+ if (!jelement) {
+ goto done;
+ }
+
+ json_object_object_get_ex(jelement, "models", &jmodels);
+
+ if (!jmodels) {
+ jmodels = json_object_new_array();
+ json_object_object_add(jelement, "models", jmodels);
+ } else {
+ parse_configuration_models(node, ele_idx, jmodels,
+ model_id, &jmodel);
+ }
+
+ if (!jmodel) {
+ jmodel = json_object_new_object();
+
+ if ((model_id & 0xffff0000) == 0xffff0000)
+ put_uint16(jmodel, "modelId", model_id & 0xffff);
+ else
+ put_uint32(jmodel, "modelId", model_id);
+
+ json_object_array_add(jmodels, jmodel);
+ }
+
+done:
+
+ g_free(in_str);
+
+ if(!jmodel && *jmain)
+ json_object_put(*jmain);
+
+ return jmodel;
+
+}
+
+bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id, uint16_t app_idx)
+{
+ json_object *jmain;
+ json_object *jmodel;
+ json_object *jvalue;
+ json_object *jbindings = NULL;
+ bool local = (node == node_get_local_node());
+
+ jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
+
+ if (!jmodel)
+ return false;
+
+ json_object_object_get_ex(jmodel, "bind", &jbindings);
+
+ if (!jbindings) {
+ jbindings = json_object_new_array();
+ json_object_object_add(jmodel, "bind", jbindings);
+ }
+
+ jvalue = json_object_new_int(app_idx);
+ json_object_array_add(jbindings, jvalue);
+
+ prov_file_write(jmain, local);
+
+ json_object_put(jmain);
+
+ return true;
+}
+
+bool prov_db_node_set_model_pub(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id,
+ struct mesh_publication *pub)
+{
+ json_object *jmain;
+ json_object *jmodel;
+ json_object *jpub;
+ json_object *jvalue;
+ bool local = (node == node_get_local_node());
+
+ jmodel = get_jmodel_obj(node, ele_idx, model_id, &jmain);
+
+ if (!jmodel)
+ return false;
+
+ json_object_object_del(jmodel, "publish");
+ if (!pub)
+ goto done;
+
+ jpub = json_object_new_object();
+
+ /* Save only required fields */
+ put_uint16(jpub, "address", pub->u.addr16);
+ put_uint16(jpub, "index", pub->app_idx);
+ jvalue = json_object_new_int(pub->ttl);
+ json_object_object_add(jpub, "ttl", jvalue);
+
+ json_object_object_add(jmodel, "publish", jpub);
+
+done:
+ prov_file_write(jmain, local);
+
+ json_object_put(jmain);
+
+ return true;
+}
+
+bool prov_db_add_new_node(struct mesh_node *node)
+{
+ char *in_str;
+ json_object *jmain;
+ json_object *jarray;
+ json_object *jnode;
+ json_object *jconfig;
+ json_object *jelements;
+ uint8_t num_ele;
+ uint16_t primary;
+ int i;
+ bool first_node;
+ bool res = false;
+
+ in_str = prov_file_read(prov_filename);
+ if (!in_str)
+ return false;
+
+ jmain = json_tokener_parse(in_str);
+ if (!jmain)
+ goto done;
+ json_object_object_get_ex(jmain, "nodes", &jarray);
+
+ if (!jarray) {
+ jarray = json_object_new_array();
+ first_node = true;
+ } else
+ first_node = false;
+
+ jnode = json_object_new_object();
+
+ /* Device key */
+ add_key(jnode, "deviceKey", node_get_device_key(node));
+
+ /* Net key */
+ jconfig = json_object_new_object();
+ add_node_idxs(jconfig, "netKeys", node_get_net_keys(node));
+
+ num_ele = node_get_num_elements(node);
+ if (num_ele == 0)
+ goto done;
+
+ jelements = json_object_new_array();
+
+ primary = node_get_primary(node);
+ if (IS_UNASSIGNED(primary))
+ goto done;
+
+ for (i = 0; i < num_ele; ++i) {
+ json_object *jelement;
+ json_object *jint;
+
+ jelement = json_object_new_object();
+
+ /* Element Index */
+ jint = json_object_new_int(i);
+ json_object_object_add(jelement, "elementIndex", jint);
+
+ /* Unicast */
+ put_uint16(jelement, "unicastAddress", primary + i);
+
+ json_object_array_add(jelements, jelement);
+ }
+
+ json_object_object_add(jconfig, "elements", jelements);
+
+ json_object_object_add(jnode, "configuration", jconfig);
+
+ json_object_array_add(jarray, jnode);
+
+ if (first_node)
+ json_object_object_add(jmain, "nodes", jarray);
+
+ prov_file_write(jmain, false);
+
+ res = true;
+done:
+
+ g_free(in_str);
+
+ if (jmain)
+ json_object_put(jmain);
+
+ return res;
+}
+
+static bool parse_node_composition(struct mesh_node *node, json_object *jcomp)
+{
+ json_object *jvalue;
+ json_object *jelements;
+ json_bool enable;
+ char *str;
+ struct mesh_node_composition comp;
+
+ json_object_object_get_ex(jcomp, "cid", &jvalue);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+
+ if (sscanf(str, "%04hx", &comp.cid) != 1)
+ return false;
+
+ json_object_object_get_ex(jcomp, "pid", &jvalue);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+
+ if (sscanf(str, "%04hx", &comp.vid) != 1)
+ return false;
+
+ json_object_object_get_ex(jcomp, "vid", &jvalue);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+
+ if (sscanf(str, "%04hx", &comp.vid) != 1)
+ return false;
+
+ json_object_object_get_ex(jcomp, "crpl", &jvalue);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+
+ if (sscanf(str, "%04hx", &comp.crpl) != 1)
+ return false;
+
+ /* Extract features */
+ json_object_object_get_ex(jcomp, "relay", &jvalue);
+ enable = json_object_get_boolean(jvalue);
+ comp.relay = (enable) ? true : false;
+
+ json_object_object_get_ex(jcomp, "proxy", &jvalue);
+ enable = json_object_get_boolean(jvalue);
+ comp.proxy = (enable) ? true : false;
+
+ json_object_object_get_ex(jcomp, "friend", &jvalue);
+ enable = json_object_get_boolean(jvalue);
+ comp.friend = (enable) ? true : false;
+
+ json_object_object_get_ex(jcomp, "lowPower", &jvalue);
+ enable = json_object_get_boolean(jvalue);
+ comp.lpn = (enable) ? true : false;
+
+ if (!node_set_composition(node, &comp))
+ return false;
+
+ json_object_object_get_ex(jcomp, "elements", &jelements);
+ if (!jelements)
+ return false;
+
+ return parse_composition_elements(node, jelements);
+}
+
+static bool parse_node(json_object *jnode, bool local)
+{
+ json_object *jconfig;
+ json_object *jelements;
+ json_object *jidxs;
+ json_object *jvalue;
+ json_object *jint;
+ uint8_t key[16];
+ char *value_str;
+ uint32_t idx;
+ struct mesh_node *node;
+
+ /* Device key */
+ if (!json_object_object_get_ex(jnode, "deviceKey", &jvalue) ||
+ !jvalue) {
+ if (!mesh_get_random_bytes(key, 16))
+ return false;
+
+ add_key(jnode, "deviceKey", key);
+ } else {
+ value_str = (char *)json_object_get_string(jvalue);
+ if (!str2hex(value_str, strlen(value_str), key, 16))
+ return false;;
+ }
+
+ node = node_new();
+
+ if (!node)
+ return false;
+
+ node_set_device_key(node, key);
+
+ json_object_object_get_ex(jnode, "IVindex", &jint);
+ if (jint)
+ idx = json_object_get_int(jint);
+ else
+ idx = 0;
+
+ node_set_iv_index(node, idx);
+ if (local) {
+ bool update = false;
+ json_object_object_get_ex(jnode, "IVupdate", &jint);
+ if (jint)
+ update = json_object_get_int(jint) ? true : false;
+ net_set_iv_index(idx, update);
+ }
+
+ if (json_object_object_get_ex(jnode, "sequenceNumber", &jint) &&
+ jint) {
+ int seq = json_object_get_int(jint);
+ node_set_sequence_number(node, seq);
+ }
+
+ /* Composition is mandatory for local node */
+ json_object_object_get_ex(jnode, "composition", &jconfig);
+ if ((jconfig && !parse_node_composition(node, jconfig)) ||
+ (!jconfig && local)) {
+ node_free(node);
+ return false;
+ }
+
+ /* Configuration is mandatory for nodes in provisioning database */
+ json_object_object_get_ex(jnode, "configuration", &jconfig);
+ if (!jconfig) {
+ if (local) {
+ /* This is an unprovisioned local device */
+ goto done;
+ } else {
+ node_free(node);
+ return false;
+ }
+ }
+
+ json_object_object_get_ex(jconfig, "elements", &jelements);
+ if (!jelements) {
+ node_free(node);
+ return false;
+ }
+
+ if (!parse_configuration_elements(node, jelements, local)) {
+ node_free(node);
+ return false;;
+ }
+
+ json_object_object_get_ex(jconfig, "netKeys", &jidxs);
+ if (!jidxs || (parse_node_keys(node, jidxs, false) == 0)) {
+ node_free(node);
+ return false;
+ }
+
+ json_object_object_get_ex(jconfig, "appKeys", &jidxs);
+ if (jidxs)
+ parse_node_keys(node, jidxs, true);
+
+ json_object_object_get_ex(jconfig, "defaultTTL", &jvalue);
+ if (jvalue) {
+ int ttl = json_object_get_int(jvalue);
+ node_set_default_ttl(node, ttl &TTL_MASK);
+ }
+
+done:
+ if (local && !node_set_local_node(node)) {
+ node_free(node);
+ return false;
+ }
+
+ return true;
+}
+
+bool prov_db_show(const char *filename)
+{
+ char *str;
+
+ str = prov_file_read(filename);
+ if (!str)
+ return false;
+
+ rl_printf("%s\n", str);
+ g_free(str);
+ return true;
+}
+
+static bool read_json_db(const char *filename, bool provisioner, bool local)
+{
+ char *str;
+ json_object *jmain;
+ json_object *jarray;
+ json_object *jprov;
+ json_object *jvalue;
+ json_object *jtemp;
+ uint8_t key[16];
+ int value_int;
+ char *value_str;
+ int len;
+ int i;
+ uint32_t index;
+ bool refresh = false;
+ bool res = false;
+
+ str = prov_file_read(filename);
+ if (!str) return false;
+
+ jmain = json_tokener_parse(str);
+ if (!jmain)
+ goto done;
+
+ if (local) {
+ json_object *jnode;
+ bool result;
+
+ json_object_object_get_ex(jmain, "node", &jnode);
+ if (!jnode) {
+ rl_printf("Cannot find \"node\" object");
+ goto done;
+ } else
+ result = parse_node(jnode, true);
+
+ /*
+ * If local node is provisioner, the rest of mesh settings
+ * are read from provisioning database.
+ */
+ if (provisioner) {
+ res = result;
+ goto done;
+ }
+ }
+
+ /* IV index */
+ json_object_object_get_ex(jmain, "IVindex", &jvalue);
+ if (!jvalue)
+ goto done;
+
+ index = json_object_get_int(jvalue);
+
+ json_object_object_get_ex(jmain, "IVupdate", &jvalue);
+ if (!jvalue)
+ goto done;
+
+ value_int = json_object_get_int(jvalue);
+
+ net_set_iv_index(index, value_int);
+
+ /* Network key(s) */
+ json_object_object_get_ex(jmain, "netKeys", &jarray);
+ if (!jarray)
+ goto done;
+
+ len = json_object_array_length(jarray);
+ rl_printf("# netkeys = %d\n", len);
+
+ for (i = 0; i < len; ++i) {
+ uint32_t idx;
+
+ jtemp = json_object_array_get_idx(jarray, i);
+ json_object_object_get_ex(jtemp, "index", &jvalue);
+ if (!jvalue)
+ goto done;
+ idx = json_object_get_int(jvalue);
+
+ json_object_object_get_ex(jtemp, "key", &jvalue);
+ if (!jvalue) {
+ if (!mesh_get_random_bytes(key, 16))
+ goto done;
+ add_key(jtemp, "key", key);
+ refresh = true;
+ } else {
+ value_str = (char *)json_object_get_string(jvalue);
+ if (!str2hex(value_str, strlen(value_str), key, 16)) {
+ goto done;
+ }
+ }
+
+ if (!keys_net_key_add(idx, key, false))
+ goto done;
+
+ json_object_object_get_ex(jtemp, "keyRefresh", &jvalue);
+ if (!jvalue)
+ goto done;
+
+ keys_set_kr_phase(idx, (uint8_t) json_object_get_int(jvalue));
+ }
+
+ /* App keys */
+ json_object_object_get_ex(jmain, "appKeys", &jarray);
+ if (jarray) {
+ len = json_object_array_length(jarray);
+ rl_printf("# appkeys = %d\n", len);
+
+ for (i = 0; i < len; ++i) {
+ int app_idx;
+ int net_idx;
+
+ jtemp = json_object_array_get_idx(jarray, i);
+ json_object_object_get_ex(jtemp, "index",
+ &jvalue);
+ if (!jvalue)
+ goto done;
+
+ app_idx = json_object_get_int(jvalue);
+ if (!CHECK_KEY_IDX_RANGE(app_idx))
+ goto done;
+
+ json_object_object_get_ex(jtemp, "key", &jvalue);
+ if (!jvalue) {
+ if (!mesh_get_random_bytes(key, 16))
+ goto done;
+ add_key(jtemp, "key", key);
+ refresh = true;
+ } else {
+ value_str =
+ (char *)json_object_get_string(jvalue);
+ str2hex(value_str, strlen(value_str), key, 16);
+ }
+
+ json_object_object_get_ex(jtemp, "boundNetKey",
+ &jvalue);
+ if (!jvalue)
+ goto done;
+
+ net_idx = json_object_get_int(jvalue);
+ if (!CHECK_KEY_IDX_RANGE(net_idx))
+ goto done;
+
+ keys_app_key_add(net_idx, app_idx, key, false);
+ }
+ }
+
+ /* Provisioner info */
+ json_object_object_get_ex(jmain, "provisioners", &jarray);
+ if (!jarray)
+ goto done;
+
+ len = json_object_array_length(jarray);
+ rl_printf("# provisioners = %d\n", len);
+
+ for (i = 0; i < len; ++i) {
+
+ jprov = json_object_array_get_idx(jarray, i);
+
+ /* Allocated unicast range */
+ json_object_object_get_ex(jprov, "allocatedUnicastRange",
+ &jtemp);
+ if (!jtemp) {
+ goto done;
+ }
+
+ if (!parse_unicast_range(jtemp)) {
+ rl_printf("Doneed to parse unicast range\n");
+ goto done;
+ }
+ }
+
+ json_object_object_get_ex(jmain, "nodes", &jarray);
+ if (!jarray) {
+ res = true;
+ goto done;
+ }
+
+ len = json_object_array_length(jarray);
+
+ rl_printf("# provisioned nodes = %d\n", len);
+ for (i = 0; i < len; ++i) {
+ json_object *jnode;
+ jnode = json_object_array_get_idx(jarray, i);
+
+ if (!jnode || !parse_node(jnode, false))
+ goto done;
+ }
+
+ res = true;
+done:
+
+ g_free(str);
+
+ if (res && refresh)
+ prov_file_write(jmain, false);
+
+ if (jmain)
+ json_object_put(jmain);
+
+ return res;
+}
+
+bool prov_db_read(const char *filename)
+{
+ prov_filename = filename;
+ return read_json_db(filename, true, false);
+}
+
+bool prov_db_read_local_node(const char *filename, bool provisioner)
+{
+ local_filename = filename;
+ return read_json_db(filename, provisioner, true);
+}
diff --git a/mesh/prov.c b/mesh/prov.c
new file mode 100644
index 0000000..89fc884
--- /dev/null
+++ b/mesh/prov.c
@@ -0,0 +1,664 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <wordexp.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/shared/ecc.h"
+
+#include "gdbus/gdbus.h"
+#include "monitor/uuid.h"
+#include "client/display.h"
+#include "node.h"
+#include "gatt.h"
+#include "crypto.h"
+#include "mesh-net.h"
+#include "util.h"
+#include "agent.h"
+#include "prov.h"
+#include "net.h"
+
+/* Provisioning Security Levels */
+#define MESH_PROV_SEC_HIGH 2
+#define MESH_PROV_SEC_MED 1
+#define MESH_PROV_SEC_LOW 0
+
+/* For Deployment, Security levels below HIGH are *not* recomended */
+#define mesh_gatt_prov_security() MESH_PROV_SEC_MED
+
+#define PROV_INVITE 0x00
+#define PROV_CAPS 0x01
+#define PROV_START 0x02
+#define PROV_PUB_KEY 0x03
+#define PROV_INP_CMPLT 0x04
+#define PROV_CONFIRM 0x05
+#define PROV_RANDOM 0x06
+#define PROV_DATA 0x07
+#define PROV_COMPLETE 0x08
+#define PROV_FAILED 0x09
+
+#define PROV_NO_OOB 0
+#define PROV_STATIC_OOB 1
+#define PROV_OUTPUT_OOB 2
+#define PROV_INPUT_OOB 3
+
+#define PROV_ERR_INVALID_PDU 0x01
+#define PROV_ERR_INVALID_FORMAT 0x02
+#define PROV_ERR_UNEXPECTED_PDU 0x03
+#define PROV_ERR_CONFIRM_FAILED 0x04
+#define PROV_ERR_INSUF_RESOURCE 0x05
+#define PROV_ERR_DECRYPT_FAILED 0x06
+#define PROV_ERR_UNEXPECTED_ERR 0x07
+#define PROV_ERR_CANT_ASSIGN_ADDR 0x08
+
+/* Expected Provisioning PDU sizes */
+static const uint16_t expected_pdu_size[] = {
+ 1 + 1, /* PROV_INVITE */
+ 1 + 1 + 2 + 1 + 1 + 1 + 2 + 1 + 2, /* PROV_CAPS */
+ 1 + 1 + 1 + 1 + 1 + 1, /* PROV_START */
+ 1 + 64, /* PROV_PUB_KEY */
+ 1, /* PROV_INP_CMPLT */
+ 1 + 16, /* PROV_CONFIRM */
+ 1 + 16, /* PROV_RANDOM */
+ 1 + 16 + 2 + 1 + 4 + 2 + 8, /* PROV_DATA */
+ 1, /* PROV_COMPLETE */
+ 1 + 1, /* PROV_FAILED */
+};
+
+typedef struct __packed {
+ uint8_t attention;
+} __attribute__ ((packed)) prov_invite;
+
+typedef struct {
+ uint8_t num_ele;
+ uint16_t algorithms;
+ uint8_t pub_type;
+ uint8_t static_type;
+ uint8_t output_size;
+ uint16_t output_action;
+ uint8_t input_size;
+ uint16_t input_action;
+} __attribute__ ((packed)) prov_caps;
+
+typedef struct {
+ uint8_t algorithm;
+ uint8_t pub_key;
+ uint8_t auth_method;
+ uint8_t auth_action;
+ uint8_t auth_size;
+} __attribute__ ((packed)) prov_start;
+
+typedef struct {
+ prov_invite invite;
+ prov_caps caps;
+ prov_start start;
+ uint8_t prv_pub_key[64];
+ uint8_t dev_pub_key[64];
+} __attribute__ ((packed)) conf_input;
+
+struct prov_data {
+ GDBusProxy *prov_in;
+ provision_done_cb prov_done;
+ void *user_data;
+ uint16_t net_idx;
+ uint16_t new_addr;
+ uint8_t state;
+ uint8_t eph_priv_key[32];
+ uint8_t ecdh_secret[32];
+ conf_input conf_in;
+ uint8_t rand_auth[32];
+ uint8_t salt[16];
+ uint8_t conf_key[16];
+ uint8_t mesh_conf[16];
+ uint8_t dev_key[16];
+};
+
+static uint8_t u16_highest_bit(uint16_t mask)
+{
+ uint8_t cnt = 0;
+
+ if (!mask) return 0xff;
+
+ while (mask & 0xfffe) {
+ cnt++;
+ mask >>= 1;
+ }
+
+ return cnt;
+}
+
+bool prov_open(struct mesh_node *node, GDBusProxy *prov_in, uint16_t net_idx,
+ provision_done_cb cb, void *user_data)
+{
+ uint8_t invite[] = { PROXY_PROVISIONING_PDU, PROV_INVITE, 0x10 };
+ struct prov_data *prov = node_get_prov(node);
+
+ if (prov) return false;
+
+ prov = g_new0(struct prov_data, 1);
+ prov->prov_in = prov_in;
+ prov->net_idx = net_idx;
+ prov->prov_done = cb;
+ prov->user_data = user_data;
+ node_set_prov(node, prov);
+ prov->conf_in.invite.attention = invite[2];
+ prov->state = PROV_INVITE;
+
+ rl_printf("Open-Node: %p\n", node);
+ rl_printf("Open-Prov: %p\n", prov);
+ rl_printf("Open-Prov: proxy %p\n", prov_in);
+
+ return mesh_gatt_write(prov_in, invite, sizeof(invite), NULL, node);
+}
+
+static bool prov_send_prov_data(void *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+ uint8_t out[35] = { PROXY_PROVISIONING_PDU, PROV_DATA };
+ uint8_t key[16];
+ uint8_t nonce[13];
+ uint64_t mic;
+
+ if (prov == NULL) return false;
+
+ mesh_crypto_session_key(prov->ecdh_secret, prov->salt, key);
+ mesh_crypto_nonce(prov->ecdh_secret, prov->salt, nonce);
+ mesh_crypto_device_key(prov->ecdh_secret, prov->salt, prov->dev_key);
+
+ print_byte_array("S-Key\t", key, sizeof(key));
+ print_byte_array("S-Nonce\t", nonce, sizeof(nonce));
+ print_byte_array("DevKey\t", prov->dev_key, sizeof(prov->dev_key));
+
+ if (!net_get_key(prov->net_idx, out + 2))
+ return false;
+
+ put_be16(prov->net_idx, out + 2 + 16);
+ net_get_flags(prov->net_idx, out + 2 + 16 + 2);
+ put_be32(net_get_iv_index(NULL), out + 2 + 16 + 2 + 1);
+ put_be16(prov->new_addr, out + 2 + 16 + 2 + 1 + 4);
+
+ print_byte_array("Data\t", out + 2, 16 + 2 + 1 + 4 + 2);
+
+ mesh_crypto_aes_ccm_encrypt(nonce, key,
+ NULL, 0,
+ out + 2,
+ sizeof(out) - 2 - sizeof(mic),
+ out + 2,
+ &mic, sizeof(mic));
+
+ print_byte_array("DataEncrypted + mic\t", out + 2, sizeof(out) - 2);
+
+ prov->state = PROV_DATA;
+ return mesh_gatt_write(prov->prov_in, out, sizeof(out), NULL, node);
+}
+
+static bool prov_send_confirm(void *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+ uint8_t out[18] = { PROXY_PROVISIONING_PDU, PROV_CONFIRM };
+
+ if (prov == NULL) return false;
+
+ mesh_get_random_bytes(prov->rand_auth, 16);
+
+ mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
+ sizeof(prov->rand_auth), out + 2);
+
+ prov->state = PROV_CONFIRM;
+ return mesh_gatt_write(prov->prov_in, out, sizeof(out), NULL, node);
+}
+
+static void prov_out_oob_done(oob_type_t type, void *buf, uint16_t len,
+ void *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+
+ if (prov == NULL) return;
+
+ switch (type) {
+ default:
+ case NONE:
+ case OUTPUT:
+ prov_complete(node, PROV_ERR_INVALID_PDU);
+ return;
+
+ case ASCII:
+ case HEXADECIMAL:
+ if (len > 16)
+ prov_complete(node, PROV_ERR_INVALID_PDU);
+
+ memcpy(prov->rand_auth + 16, buf, len);
+ break;
+
+ case DECIMAL:
+ if (len != 4)
+ prov_complete(node, PROV_ERR_INVALID_PDU);
+
+ memcpy(prov->rand_auth +
+ sizeof(prov->rand_auth) -
+ sizeof(uint32_t),
+ buf, len);
+ break;
+ }
+
+ prov_send_confirm(node);
+}
+
+static uint32_t power_ten(uint8_t power)
+{
+ uint32_t ret = 1;
+
+ while (power--)
+ ret *= 10;
+
+ return ret;
+}
+
+char *in_action[3] = {
+ "Push",
+ "Twist",
+ "Enter"
+};
+
+static void prov_calc_ecdh(DBusMessage *message, void *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+ uint8_t action = prov->conf_in.start.auth_action;
+ uint8_t size = prov->conf_in.start.auth_size;
+ char in_oob_display[100];
+ uint8_t *tmp = (void *) in_oob_display;
+ uint32_t in_oob;
+
+ if (prov == NULL) return;
+
+ /* Convert to Mesh byte order */
+ memcpy(tmp, prov->conf_in.dev_pub_key, 64);
+ swap_u256_bytes(tmp);
+ swap_u256_bytes(tmp + 32);
+
+ ecdh_shared_secret(tmp, prov->eph_priv_key, prov->ecdh_secret);
+
+ /* Convert to Mesh byte order */
+ swap_u256_bytes(prov->ecdh_secret);
+
+ mesh_crypto_s1(&prov->conf_in,
+ sizeof(prov->conf_in), prov->salt);
+
+ mesh_crypto_prov_conf_key(prov->ecdh_secret,
+ prov->salt, prov->conf_key);
+
+ switch (prov->conf_in.start.auth_method) {
+ default:
+ prov_complete(node, PROV_ERR_INVALID_PDU);
+ break;
+
+ case 0: /* No OOB */
+ prov_send_confirm(node);
+ break;
+
+ case 1: /* Static OOB */
+ agent_input_request(HEXADECIMAL,
+ 16,
+ prov_out_oob_done, node);
+ break;
+
+ case 2: /* Output OOB */
+ if (action <= 3)
+ agent_input_request(DECIMAL,
+ size,
+ prov_out_oob_done, node);
+ else
+ agent_input_request(ASCII,
+ size,
+ prov_out_oob_done, node);
+ break;
+
+ case 3: /* Input OOB */
+
+ if (action <= 2) {
+ mesh_get_random_bytes(&in_oob, sizeof(in_oob));
+ in_oob %= power_ten(size);
+ sprintf(in_oob_display, "%s %d on device\n",
+ in_action[action], in_oob);
+ put_be32(in_oob,
+ prov->rand_auth +
+ sizeof(prov->rand_auth) -
+ sizeof(uint32_t));
+ } else {
+ uint8_t in_ascii[9];
+ int i = size;
+
+ mesh_get_random_bytes(in_ascii, i);
+
+ while (i--) {
+ in_ascii[i] =
+ in_ascii[i] % ((26 * 2) + 10);
+ if (in_ascii[i] >= 10 + 26)
+ in_ascii[i] += 'a' - (10 + 26);
+ else if (in_ascii[i] >= 10)
+ in_ascii[i] += 'A' - 10;
+ else
+ in_ascii[i] += '0';
+ }
+ in_ascii[size] = '\0';
+ memcpy(prov->rand_auth + 16, in_ascii, size);
+ sprintf(in_oob_display,
+ "Enter %s on device\n",
+ in_ascii);
+ }
+ rl_printf("Agent String: %s\n", in_oob_display);
+ agent_output_request(in_oob_display);
+ break;
+ }
+}
+
+static void prov_send_pub_key(struct mesh_node *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+ uint8_t out[66] = { PROXY_PROVISIONING_PDU, PROV_PUB_KEY };
+ GDBusReturnFunction cb = NULL;
+
+ if (prov == NULL) return;
+
+ if (prov->conf_in.start.pub_key)
+ cb = prov_calc_ecdh;
+
+ memcpy(out + 2, prov->conf_in.prv_pub_key, 64);
+ prov->state = PROV_PUB_KEY;
+ mesh_gatt_write(prov->prov_in, out, 66, cb, node);
+}
+
+static void prov_oob_pub_key(oob_type_t type, void *buf, uint16_t len,
+ void *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+
+ if (prov == NULL) return;
+
+ memcpy(prov->conf_in.dev_pub_key, buf, 64);
+ prov_send_pub_key(node);
+}
+
+static void prov_start_cmplt(DBusMessage *message, void *node)
+{
+ struct prov_data *prov = node_get_prov(node);
+
+ if (prov == NULL) return;
+
+ if (prov->conf_in.start.pub_key)
+ agent_input_request(HEXADECIMAL, 64, prov_oob_pub_key, node);
+ else
+ prov_send_pub_key(node);
+}
+
+bool prov_data_ready(struct mesh_node *node, uint8_t *buf, uint8_t len)
+{
+ struct prov_data *prov = node_get_prov(node);
+ uint8_t sec_level = MESH_PROV_SEC_HIGH;
+ uint8_t out[35] = { PROXY_PROVISIONING_PDU };
+
+ if (prov == NULL || len < 2) return false;
+
+ buf++;
+ len--;
+
+ rl_printf("Got provisioning data (%d bytes)\n", len);
+
+ if (buf[0] > PROV_FAILED || expected_pdu_size[buf[0]] != len)
+ return prov_complete(node, PROV_ERR_INVALID_PDU);
+
+ print_byte_array("\t", buf, len);
+
+ if (buf[0] == PROV_FAILED)
+ return prov_complete(node, buf[1]);
+
+ /* Check provisioning state */
+ switch (prov->state) {
+ default:
+ return prov_complete(node, PROV_ERR_INVALID_PDU);
+
+ case PROV_INVITE:
+
+ if (buf[0] != PROV_CAPS)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ /* Normalize to beginning of packed Param struct */
+ buf++;
+ len--;
+
+ /* Save Capability values */
+ memcpy(&prov->conf_in.caps, buf, len);
+
+ sec_level = mesh_gatt_prov_security();
+
+ if (sec_level == MESH_PROV_SEC_HIGH) {
+
+ /* Enforce High Security */
+ if (prov->conf_in.caps.pub_type != 1 &&
+ prov->conf_in.caps.static_type != 1)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ } else if (sec_level == MESH_PROV_SEC_MED) {
+
+ /* Enforce Medium Security */
+ if (prov->conf_in.caps.pub_type != 1 &&
+ prov->conf_in.caps.static_type != 1 &&
+ prov->conf_in.caps.input_size == 0 &&
+ prov->conf_in.caps.output_size == 0)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ }
+
+ /* Num Elements cannot be Zero */
+ if (prov->conf_in.caps.num_ele == 0)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ /* All nodes must support Algorithm 0x0001 */
+ if (!(get_be16(buf + 1) & 0x0001))
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ /* Pub Key and Static type may not be > 1 */
+ if (prov->conf_in.caps.pub_type > 0x01 ||
+ prov->conf_in.caps.static_type > 0x01)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ prov->new_addr =
+ net_obtain_address(prov->conf_in.caps.num_ele);
+
+ if (!prov->new_addr)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ out[1] = PROV_START;
+ prov->conf_in.start.algorithm = 0;
+ prov->conf_in.start.pub_key =
+ prov->conf_in.caps.pub_type;
+
+ /* Compose START based on most secure values */
+ if (prov->conf_in.caps.static_type) {
+
+ prov->conf_in.start.auth_method =
+ PROV_STATIC_OOB;
+
+ } else if (prov->conf_in.caps.output_size >
+ prov->conf_in.caps.input_size) {
+
+ prov->conf_in.start.auth_method =
+ PROV_OUTPUT_OOB;
+ prov->conf_in.start.auth_action =
+ u16_highest_bit(get_be16(buf + 6));
+ prov->conf_in.start.auth_size =
+ prov->conf_in.caps.output_size;
+
+ } else if (prov->conf_in.caps.input_size > 0) {
+
+ prov->conf_in.start.auth_method =
+ PROV_INPUT_OOB;
+ prov->conf_in.start.auth_action =
+ u16_highest_bit(get_be16(buf + 9));
+ prov->conf_in.start.auth_size =
+ prov->conf_in.caps.input_size;
+ }
+
+ /* Range Check START values */
+ if (prov->conf_in.start.auth_size > 8)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ prov->state = PROV_START;
+
+ memcpy(out + 2, &prov->conf_in.start, 5);
+
+ ecc_make_key(prov->conf_in.prv_pub_key,
+ prov->eph_priv_key);
+
+ /* Swap public key to share into Mesh byte ordering */
+ swap_u256_bytes(prov->conf_in.prv_pub_key);
+ swap_u256_bytes(prov->conf_in.prv_pub_key + 32);
+
+ return mesh_gatt_write(prov->prov_in, out, 7,
+ prov_start_cmplt, node);
+
+
+ case PROV_PUB_KEY:
+ if (buf[0] == PROV_PUB_KEY &&
+ !prov->conf_in.start.pub_key) {
+
+ memcpy(prov->conf_in.dev_pub_key, buf + 1, 64);
+ prov_calc_ecdh(NULL, node);
+ return true;
+
+ } else if (buf[0] == PROV_INP_CMPLT) {
+ agent_output_request_cancel();
+ return prov_send_confirm(node);
+ } else
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ case PROV_CONFIRM:
+ if (buf[0] != PROV_CONFIRM)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ memcpy(prov->mesh_conf, buf + 1, 16);
+
+ out[1] = PROV_RANDOM;
+ memcpy(out + 2, prov->rand_auth, 16);
+
+ prov->state = PROV_RANDOM;
+ return mesh_gatt_write(prov->prov_in, out, 18,
+ NULL, node);
+
+ case PROV_RANDOM:
+ if (buf[0] != PROV_RANDOM)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ /* Calculate New Salt while we still have
+ * both random values */
+ mesh_crypto_prov_prov_salt(prov->salt,
+ prov->rand_auth,
+ buf + 1,
+ prov->salt);
+
+ /* Calculate meshs Conf Value */
+ memcpy(prov->rand_auth, buf + 1, 16);
+ mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
+ sizeof(prov->rand_auth), out + 1);
+
+ /* Validate Mesh confirmation */
+ if (memcmp(out + 1, prov->mesh_conf, 16) != 0)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ rl_printf("Confirmation Validated\n");
+
+ prov_send_prov_data(node);
+
+ return true;
+
+ case PROV_DATA:
+ if (buf[0] != PROV_COMPLETE)
+ return prov_complete(node,
+ PROV_ERR_INVALID_PDU);
+
+ return prov_complete(node, 0);
+ }
+
+
+
+ /* Compose appropriate reply for the prov state message */
+ /* Send reply via mesh_gatt_write() */
+ /* If done, call prov_done calllback and free prov housekeeping data */
+ rl_printf("Got provisioning data (%d bytes)\n", len);
+ print_byte_array("\t", buf, len);
+
+ return true;
+}
+
+bool prov_complete(struct mesh_node *node, uint8_t status)
+{
+ struct prov_data *prov = node_get_prov(node);
+ void *user_data;
+ provision_done_cb cb;
+
+ if (prov == NULL) return false;
+
+ if (status && prov->new_addr && prov->conf_in.caps.num_ele) {
+ net_release_address(prov->new_addr, prov->conf_in.caps.num_ele);
+ }
+
+ if (!status) {
+ node_set_num_elements(node, prov->conf_in.caps.num_ele);
+ node_set_primary(node, prov->new_addr);
+ node_set_device_key(node, prov->dev_key);
+ node_net_key_add(node, prov->net_idx);
+ }
+
+ user_data = prov->user_data;
+ cb = prov->prov_done;
+ g_free(prov);
+ node_set_prov(node, NULL);
+ if (cb) cb(user_data, status);
+
+ return true;
+}
diff --git a/mesh/util.c b/mesh/util.c
new file mode 100644
index 0000000..cb241b3
--- /dev/null
+++ b/mesh/util.c
@@ -0,0 +1,369 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <readline/readline.h>
+#include <glib.h>
+
+#include "client/display.h"
+#include "src/shared/util.h"
+#include "mesh-net.h"
+#include "util.h"
+
+struct cmd_menu {
+ const char *name;
+ const struct menu_entry *table;
+};
+
+static struct menu_entry *main_cmd_table;
+static struct menu_entry *current_cmd_table;
+static GList *menu_list;
+
+static char *main_menu_prompt;
+static int main_menu_point;
+
+static int match_menu_name(const void *a, const void *b)
+{
+ const struct cmd_menu *menu = a;
+ const char *name = b;
+
+ return strcasecmp(menu->name, name);
+}
+
+bool cmd_menu_init(const struct menu_entry *cmd_table)
+{
+ struct cmd_menu *menu;
+
+ if (main_cmd_table) {
+ rl_printf("Main menu already registered\n");
+ return false;
+ }
+
+ menu = g_malloc(sizeof(struct cmd_menu));
+ if (!menu)
+ return false;
+
+ menu->name = "meshctl";
+ menu->table = cmd_table;
+ menu_list = g_list_append(menu_list, menu);
+ main_cmd_table = (struct menu_entry *) cmd_table;
+ current_cmd_table = (struct menu_entry *) main_cmd_table;
+
+ return true;
+}
+
+void cmd_menu_main(bool forced)
+{
+ current_cmd_table = main_cmd_table;
+
+ if (!forced) {
+ rl_set_prompt(main_menu_prompt);
+ rl_replace_line("", 0);
+ rl_point = main_menu_point;
+ rl_redisplay();
+ }
+
+ g_free(main_menu_prompt);
+ main_menu_prompt = NULL;
+}
+
+bool add_cmd_menu(const char *name, const struct menu_entry *cmd_table)
+{
+ struct cmd_menu *menu;
+ GList *l;
+
+ l = g_list_find_custom(menu_list, name, match_menu_name);
+ if (l) {
+ menu = l->data;
+ rl_printf("menu \"%s\" already registered\n", menu->name);
+ return false;
+ }
+
+ menu = g_malloc(sizeof(struct cmd_menu));
+ if (!menu)
+ return false;
+
+ menu->name = name;
+ menu->table = cmd_table;
+ menu_list = g_list_append(menu_list, menu);
+
+ return true;
+}
+
+void set_menu_prompt(const char *name, const char *id)
+{
+ char *prompt;
+
+ prompt = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", name,
+ id ? ": Target = " : "", id ? id : "");
+ rl_set_prompt(prompt);
+ g_free(prompt);
+ rl_on_new_line();
+}
+
+bool switch_cmd_menu(const char *name)
+{
+ GList *l;
+ struct cmd_menu *menu;
+
+ l = g_list_find_custom(menu_list, name, match_menu_name);
+ if(!l)
+ return false;
+
+ menu = l->data;
+ current_cmd_table = (struct menu_entry *) menu->table;
+
+ main_menu_point = rl_point;
+ main_menu_prompt = g_strdup(rl_prompt);
+
+ return true;
+}
+
+void process_menu_cmd(const char *cmd, const char *arg)
+{
+ int i;
+ int len;
+ struct menu_entry *cmd_table = current_cmd_table;
+
+ if (!current_cmd_table)
+ return;
+
+ len = strlen(cmd);
+
+ for (i = 0; cmd_table[i].cmd; i++) {
+ if (strncmp(cmd, cmd_table[i].cmd, len))
+ continue;
+
+ if (cmd_table[i].func) {
+ cmd_table[i].func(arg);
+ return;
+ }
+ }
+
+ if (strncmp(cmd, "help", len)) {
+ rl_printf("Invalid command\n");
+ return;
+ }
+
+ print_cmd_menu(cmd_table);
+}
+
+void print_cmd_menu(const struct menu_entry *cmd_table)
+{
+ int i;
+
+ rl_printf("Available commands:\n");
+
+ for (i = 0; cmd_table[i].cmd; i++) {
+ if (cmd_table[i].desc)
+ rl_printf(" %s %-*s %s\n", cmd_table[i].cmd,
+ (int)(40 - strlen(cmd_table[i].cmd)),
+ cmd_table[i].arg ? : "",
+ cmd_table[i].desc ? : "");
+ }
+
+}
+
+void cmd_menu_cleanup(void)
+{
+ main_cmd_table = NULL;
+ current_cmd_table = NULL;
+
+ g_list_free_full(menu_list, g_free);
+}
+
+void print_byte_array(const char *prefix, const void *ptr, int len)
+{
+ const uint8_t *data = ptr;
+ char *line, *bytes;
+ int i;
+
+ line = g_malloc(strlen(prefix) + (16 * 3) + 2);
+ sprintf(line, "%s ", prefix);
+ bytes = line + strlen(prefix) + 1;
+
+ for (i = 0; i < len; ++i) {
+ sprintf(bytes, "%2.2x ", data[i]);
+ if ((i + 1) % 16) {
+ bytes += 3;
+ } else {
+ rl_printf("\r%s\n", line);
+ bytes = line + strlen(prefix) + 1;
+ }
+ }
+
+ if (i % 16)
+ rl_printf("\r%s\n", line);
+
+ g_free(line);
+}
+
+bool str2hex(const char *str, uint16_t in_len, uint8_t *out,
+ uint16_t out_len)
+{
+ uint16_t i;
+
+ if (in_len < out_len * 2)
+ return false;
+
+ for (i = 0; i < out_len; i++) {
+ if (sscanf(&str[i * 2], "%02hhx", &out[i]) != 1)
+ return false;
+ }
+
+ return true;
+}
+
+size_t hex2str(uint8_t *in, size_t in_len, char *out,
+ size_t out_len)
+{
+ static const char hexdigits[] = "0123456789abcdef";
+ size_t i;
+
+ if(in_len * 2 > out_len - 1)
+ return 0;
+
+ for (i = 0; i < in_len; i++) {
+ out[i * 2] = hexdigits[in[i] >> 4];
+ out[i * 2 + 1] = hexdigits[in[i] & 0xf];
+ }
+
+ out[in_len * 2] = '\0';
+ return i;
+}
+
+uint16_t mesh_opcode_set(uint32_t opcode, uint8_t *buf)
+{
+ if (opcode <= 0x7e) {
+ buf[0] = opcode;
+ return 1;
+ } else if (opcode >= 0x8000 && opcode <= 0xbfff) {
+ put_be16(opcode, buf);
+ return 2;
+ } else if (opcode >= 0xc00000 && opcode <= 0xffffff) {
+ buf[0] = (opcode >> 16) & 0xff;
+ put_be16(opcode, buf + 1);
+ return 3;
+ } else {
+ rl_printf("Illegal Opcode %x", opcode);
+ return 0;
+ }
+}
+
+bool mesh_opcode_get(const uint8_t *buf, uint16_t sz, uint32_t *opcode, int *n)
+{
+ if (!n || !opcode || sz < 1) return false;
+
+ switch (buf[0] & 0xc0) {
+ case 0x00:
+ case 0x40:
+ /* RFU */
+ if (buf[0] == 0x7f)
+ return false;
+
+ *n = 1;
+ *opcode = buf[0];
+ break;
+
+ case 0x80:
+ if (sz < 2)
+ return false;
+
+ *n = 2;
+ *opcode = get_be16(buf);
+ break;
+
+ case 0xc0:
+ if (sz < 3)
+ return false;
+
+ *n = 3;
+ *opcode = get_be16(buf + 1);
+ *opcode |= buf[0] << 16;
+ break;
+
+ default:
+ rl_printf("Bad Packet:\n");
+ print_byte_array("\t", (void *) buf, sz);
+ return false;
+ }
+
+ return true;
+}
+
+const char *mesh_status_str(uint8_t status)
+{
+ switch (status) {
+ case MESH_STATUS_SUCCESS: return "Success";
+ case MESH_STATUS_INVALID_ADDRESS: return "Invalid Address";
+ case MESH_STATUS_INVALID_MODEL: return "Invalid Model";
+ case MESH_STATUS_INVALID_APPKEY: return "Invalid AppKey";
+ case MESH_STATUS_INVALID_NETKEY: return "Invalid NetKey";
+ case MESH_STATUS_INSUFF_RESOURCES: return "Insufficient Resources";
+ case MESH_STATUS_IDX_ALREADY_STORED: return "Key Idx Already Stored";
+ case MESH_STATUS_INVALID_PUB_PARAM: return "Invalid Publish Parameters";
+ case MESH_STATUS_NOT_SUB_MOD: return "Not a Subscribe Model";
+ case MESH_STATUS_STORAGE_FAIL: return "Storage Failure";
+ case MESH_STATUS_FEAT_NOT_SUP: return "Feature Not Supported";
+ case MESH_STATUS_CANNOT_UPDATE: return "Cannot Update";
+ case MESH_STATUS_CANNOT_REMOVE: return "Cannot Remove";
+ case MESH_STATUS_CANNOT_BIND: return "Cannot bind";
+ case MESH_STATUS_UNABLE_CHANGE_STATE: return "Unable to change state";
+ case MESH_STATUS_CANNOT_SET: return "Cannot set";
+ case MESH_STATUS_UNSPECIFIED_ERROR: return "Unspecified error";
+ case MESH_STATUS_INVALID_BINDING: return "Invalid Binding";
+
+ default: return "Unknown";
+ }
+}
+
+void print_model_pub(uint16_t ele_addr, uint32_t mod_id,
+ struct mesh_publication *pub)
+{
+ rl_printf("\tElement: %4.4x\n", ele_addr);
+ rl_printf("\tPub Addr: %4.4x", pub->u.addr16);
+ if (mod_id > 0xffff0000)
+ rl_printf("\tModel: %8.8x \n", mod_id);
+ else
+ rl_printf("\tModel: %4.4x \n", (uint16_t) (mod_id & 0xffff));
+ rl_printf("\tApp Key Idx: %4.4x", pub->app_idx);
+ rl_printf("\tTTL: %2.2x", pub->ttl);
+}
+
+void swap_u256_bytes(uint8_t *u256)
+{
+ int i;
+
+ /* End-to-End byte reflection of 32 octet buffer */
+ for (i = 0; i < 16; i++) {
+ u256[i] ^= u256[31 - i];
+ u256[31 - i] ^= u256[i];
+ u256[i] ^= u256[31 - i];
+ }
+}
--
2.9.5

2017-08-14 19:01:19

by Gix, Brian

[permalink] [raw]
Subject: [PATCH 5/5] mesh: Add mesh to main bluez build

---
Makefile.tools | 24 ++++++++++++++++++++++++
bootstrap-configure | 1 +
configure.ac | 18 ++++++++++++++++++
3 files changed, 43 insertions(+)

diff --git a/Makefile.tools b/Makefile.tools
index 0fd6dec..f646bb7 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -13,6 +13,30 @@ client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
@GLIB_LIBS@ @DBUS_LIBS@ -lreadline
endif

+if BTMESH
+bin_PROGRAMS += mesh/meshctl
+
+mesh_meshctl_SOURCES = mesh/main.c \
+ mesh/node.h mesh/node.c \
+ mesh/gatt.h mesh/gatt.c \
+ mesh/crypto.h mesh/crypto.c \
+ mesh/keys.h \
+ mesh/net.h mesh/net.c \
+ mesh/prov.h mesh/prov.c \
+ mesh/util.h mesh/util.c \
+ mesh/agent.h mesh/agent.c \
+ mesh/prov-db.h mesh/prov-db.c \
+ mesh/config-model.h mesh/config-client.c \
+ mesh/config-server.c \
+ mesh/onoff-model.h mesh/onoff-model.c \
+ client/display.h client/display.c \
+ monitor/uuid.h monitor/uuid.c
+mesh_meshctl_LDADD = lib/libbluetooth-internal.la gdbus/libgdbus-internal.la \
+ src/libshared-glib.la \
+ @GLIB_LIBS@ @DBUS_LIBS@ -ljson-c -lreadline
+endif
+
+
if MONITOR
bin_PROGRAMS += monitor/btmon

diff --git a/bootstrap-configure b/bootstrap-configure
index 47926fc..658eef2 100755
--- a/bootstrap-configure
+++ b/bootstrap-configure
@@ -23,4 +23,5 @@ fi
--enable-android \
--enable-sixaxis \
--enable-midi \
+ --enable-mesh \
--disable-datafiles $*
diff --git a/configure.ac b/configure.ac
index 89b164b..bbbc760 100644
--- a/configure.ac
+++ b/configure.ac
@@ -331,6 +331,24 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
[Directory for the configuration files])
AC_SUBST(CONFIGDIR, "${configdir}")

+AC_ARG_ENABLE(mesh, AC_HELP_STRING([--enable-mesh],
+ [enable BlueZ for Bluetooth Mesh]),
+ [enable_mesh=${enableval}])
+AM_CONDITIONAL(BTMESH, test "${enable_mesh}" = "yes")
+
+if (test "${enable_mesh}" == "yes"); then
+ PKG_CHECK_MODULES(JSONC, json-c, dummy=yes,
+ AC_MSG_ERROR(json-c is required))
+ AC_SUBST(JSON_CFLAGS)
+ AC_SUBST(JSON_LIBS)
+fi
+
+if (test "${enable_mesh}" == "yes"); then
+ AC_CHECK_HEADERS(readline/readline.h, enable_readline=yes,
+ AC_MSG_ERROR(readline header files are required))
+fi
+AM_CONDITIONAL(READLINE, test "${enable_readline}" = "yes")
+
AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
[enable BlueZ for Android]),
[enable_android=${enableval}])
--
2.9.5

2017-08-14 19:01:17

by Gix, Brian

[permalink] [raw]
Subject: [PATCH 3/5] mesh: Baseline Mesh runtime configuration files

---
mesh/local_node.json | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/prov_db.json | 37 +++++++++++++++++++++++++++++++
2 files changed, 98 insertions(+)
create mode 100644 mesh/local_node.json
create mode 100644 mesh/prov_db.json

diff --git a/mesh/local_node.json b/mesh/local_node.json
new file mode 100644
index 0000000..6591289
--- /dev/null
+++ b/mesh/local_node.json
@@ -0,0 +1,61 @@
+{
+ "$schema":"file:\/\/\/Bluetooth SIG\/Mesh\/schema\/mesh.jsonschema",
+ "meshName":"Intel BT Mesh",
+ "netKeys":[
+ {
+ "index": 0,
+ "keyRefresh": 0
+ }
+ ],
+ "appKeys":[
+ {
+ "index": 0,
+ "boundNetKey": 0
+ },
+ {
+ "index": 1,
+ "boundNetKey": 0
+ }
+ ],
+"node": {
+ "IVindex":"00000005",
+ "IVupdate":"0",
+ "sequenceNumber": 0,
+ "composition": {
+ "cid": "0002",
+ "pid": "0010",
+ "vid": "0001",
+ "crpl": "000a",
+ "features": {
+ "relay": false,
+ "proxy": true,
+ "friend": false,
+ "lowPower": false
+ },
+ "elements": [
+ {
+ "elementIndex": 0,
+ "location": "0001",
+ "models": ["0000", "0001", "1001"]
+ }
+ ]
+ },
+ "configuration":{
+ "netKeys": [0],
+ "appKeys": [ 0, 1],
+ "defaultTTL": 10,
+ "elements": [
+ {
+ "elementIndex": 0,
+ "unicastAddress":"0077",
+ "models": [
+ {
+ "modelId": "1001",
+ "bind": [1]
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
diff --git a/mesh/prov_db.json b/mesh/prov_db.json
new file mode 100644
index 0000000..d810a7d
--- /dev/null
+++ b/mesh/prov_db.json
@@ -0,0 +1,37 @@
+{
+ "$schema":"file:\/\/\/Bluetooth SIG\/Mesh\/schema\/mesh.jsonschema",
+ "meshName":"Intel BT Mesh",
+ "IVindex":5,
+ "IVupdate":0,
+ "netKeys":[
+ {
+ "index":0,
+ "keyRefresh":0,
+ "key":"18eed9c2a56add85049ffc3c59ad0e12"
+ }
+ ],
+ "appKeys":[
+ {
+ "index":0,
+ "boundNetKey":0,
+ "key":"4f68ad85d9f48ac8589df665b6b49b8a"
+ },
+ {
+ "index":1,
+ "boundNetKey":0,
+ "key":"2aa2a6ded5a0798ceab5787ca3ae39fc"
+ }
+ ],
+ "provisioners":[
+ {
+ "provisionerName":"BT Mesh Provisioner",
+ "unicastAddress":"0077",
+ "allocatedUnicastRange":[
+ {
+ "lowAddress":"0100",
+ "highAddress":"7fff"
+ }
+ ]
+ }
+ ],
+}
--
2.9.5

2017-08-14 19:01:16

by Gix, Brian

[permalink] [raw]
Subject: [PATCH 2/5] mesh: define APIs for Bluetooth Mesh

---
mesh/README | 26 ++++++++
mesh/agent.h | 58 ++++++++++++++++++
mesh/config-model.h | 119 +++++++++++++++++++++++++++++++++++
mesh/crypto.h | 133 +++++++++++++++++++++++++++++++++++++++
mesh/gatt.h | 47 ++++++++++++++
mesh/keys.h | 43 +++++++++++++
mesh/mesh-net.h | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/net.h | 72 ++++++++++++++++++++++
mesh/node.h | 146 +++++++++++++++++++++++++++++++++++++++++++
mesh/onoff-model.h | 50 +++++++++++++++
mesh/prov-db.h | 52 ++++++++++++++++
mesh/prov.h | 43 +++++++++++++
mesh/util.h | 71 +++++++++++++++++++++
13 files changed, 1034 insertions(+)
create mode 100644 mesh/README
create mode 100644 mesh/agent.h
create mode 100644 mesh/config-model.h
create mode 100644 mesh/crypto.h
create mode 100644 mesh/gatt.h
create mode 100644 mesh/keys.h
create mode 100644 mesh/mesh-net.h
create mode 100644 mesh/net.h
create mode 100644 mesh/node.h
create mode 100644 mesh/onoff-model.h
create mode 100644 mesh/prov-db.h
create mode 100644 mesh/prov.h
create mode 100644 mesh/util.h

diff --git a/mesh/README b/mesh/README
new file mode 100644
index 0000000..ea561ef
--- /dev/null
+++ b/mesh/README
@@ -0,0 +1,26 @@
+MeshCtl - BlueZ GATT based Bluetooth Mesh Provisioner
+******************************************
+
+Copyright (C) 2017 Intel Corporation. All rights reserved.
+
+Compilation and installation
+============================
+
+In addition to main BlueZ requirements, MeshCtl needs the following:
+ - JSON library
+
+Configuration and options
+=========================
+
+ --enable-mesh
+
+ Build meshctl and other Bluetooth Mesh based tools and utils
+
+Information
+===========
+
+Mailing lists:
+ [email protected]
+
+For additional information about the project visit BlueZ web site:
+ http://www.bluez.org
diff --git a/mesh/agent.h b/mesh/agent.h
new file mode 100644
index 0000000..fe19353
--- /dev/null
+++ b/mesh/agent.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_AGENT_H
+#define __MESH_AGENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_HEXADECIMAL_OOB_LEN 128
+#define DECIMAL_OOB_LEN 4
+#define MAX_ASCII_OOB_LEN 16
+
+typedef enum {
+ NONE,
+ HEXADECIMAL,
+ DECIMAL,
+ ASCII,
+ OUTPUT,
+} oob_type_t;
+
+typedef void (*agent_input_cb)(oob_type_t type, void *input, uint16_t len,
+ void *user_data);
+bool agent_input_request(oob_type_t type, uint16_t max_len, agent_input_cb cb,
+ void *user_data);
+
+bool agent_output_request(const char* str);
+void agent_output_request_cancel(void);
+bool agent_completion(void);
+bool agent_input(const char *input);
+void agent_release(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_AGENT_H */
diff --git a/mesh/config-model.h b/mesh/config-model.h
new file mode 100644
index 0000000..115491f
--- /dev/null
+++ b/mesh/config-model.h
@@ -0,0 +1,119 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_CONFIG_MODEL_H
+#define __MESH_CONFIG_MODEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define CONFIG_SERVER_MODEL_ID 0x0000
+#define CONFIG_CLIENT_MODEL_ID 0x0001
+
+#define OP_APPKEY_ADD 0x00
+#define OP_APPKEY_DELETE 0x8000
+#define OP_APPKEY_GET 0x8001
+#define OP_APPKEY_LIST 0x8002
+#define OP_APPKEY_STATUS 0x8003
+#define OP_APPKEY_UPDATE 0x01
+#define OP_DEV_COMP_GET 0x8008
+#define OP_DEV_COMP_STATUS 0x02
+#define OP_CONFIG_BEACON_GET 0x8009
+#define OP_CONFIG_BEACON_SET 0x800A
+#define OP_CONFIG_BEACON_STATUS 0x800B
+#define OP_CONFIG_DEFAULT_TTL_GET 0x800C
+#define OP_CONFIG_DEFAULT_TTL_SET 0x800D
+#define OP_CONFIG_DEFAULT_TTL_STATUS 0x800E
+#define OP_CONFIG_FRIEND_GET 0x800F
+#define OP_CONFIG_FRIEND_SET 0x8010
+#define OP_CONFIG_FRIEND_STATUS 0x8011
+#define OP_CONFIG_PROXY_GET 0x8012
+#define OP_CONFIG_PROXY_SET 0x8013
+#define OP_CONFIG_PROXY_STATUS 0x8014
+#define OP_CONFIG_KEY_REFRESH_PHASE_GET 0x8015
+#define OP_CONFIG_KEY_REFRESH_PHASE_SET 0x8016
+#define OP_CONFIG_KEY_REFRESH_PHASE_STATUS 0x8017
+#define OP_CONFIG_MODEL_PUB_GET 0x8018
+#define OP_CONFIG_MODEL_PUB_SET 0x03
+#define OP_CONFIG_MODEL_PUB_STATUS 0x8019
+#define OP_CONFIG_MODEL_PUB_VIRT_SET 0x801A
+#define OP_CONFIG_MODEL_SUB_ADD 0x801B
+#define OP_CONFIG_MODEL_SUB_DELETE 0x801C
+#define OP_CONFIG_MODEL_SUB_DELETE_ALL 0x801D
+#define OP_CONFIG_MODEL_SUB_OVERWRITE 0x801E
+#define OP_CONFIG_MODEL_SUB_STATUS 0x801F
+#define OP_CONFIG_MODEL_SUB_VIRT_ADD 0x8020
+#define OP_CONFIG_MODEL_SUB_VIRT_DELETE 0x8021
+#define OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE 0x8022
+#define OP_CONFIG_NETWORK_TRANSMIT_GET 0x8023
+#define OP_CONFIG_NETWORK_TRANSMIT_SET 0x8024
+#define OP_CONFIG_NETWORK_TRANSMIT_STATUS 0x8025
+#define OP_CONFIG_RELAY_GET 0x8026
+#define OP_CONFIG_RELAY_SET 0x8027
+#define OP_CONFIG_RELAY_STATUS 0x8028
+#define OP_CONFIG_MODEL_SUB_GET 0x8029
+#define OP_CONFIG_MODEL_SUB_LIST 0x802A
+#define OP_CONFIG_VEND_MODEL_SUB_GET 0x802B
+#define OP_CONFIG_VEND_MODEL_SUB_LIST 0x802C
+#define OP_CONFIG_POLL_TIMEOUT_LIST 0x802D
+#define OP_CONFIG_POLL_TIMEOUT_STATUS 0x802E
+#define OP_CONFIG_HEARTBEAT_PUB_GET 0x8038
+#define OP_CONFIG_HEARTBEAT_PUB_SET 0x8039
+#define OP_CONFIG_HEARTBEAT_PUB_STATUS 0x06
+#define OP_CONFIG_HEARTBEAT_SUB_GET 0x803A
+#define OP_CONFIG_HEARTBEAT_SUB_SET 0x803B
+#define OP_CONFIG_HEARTBEAT_SUB_STATUS 0x803C
+#define OP_MODEL_APP_BIND 0x803D
+#define OP_MODEL_APP_STATUS 0x803E
+#define OP_MODEL_APP_UNBIND 0x803F
+#define OP_NETKEY_ADD 0x8040
+#define OP_NETKEY_DELETE 0x8041
+#define OP_NETKEY_GET 0x8042
+#define OP_NETKEY_LIST 0x8043
+#define OP_NETKEY_STATUS 0x8044
+#define OP_NETKEY_UPDATE 0x8045
+#define OP_NODE_IDENTITY_GET 0x8046
+#define OP_NODE_IDENTITY_SET 0x8047
+#define OP_NODE_IDENTITY_STATUS 0x8048
+#define OP_NODE_RESET 0x8049
+#define OP_NODE_RESET_STATUS 0x804A
+#define OP_MODEL_APP_GET 0x804B
+#define OP_MODEL_APP_LIST 0x804C
+#define OP_VEND_MODEL_APP_GET 0x804C
+#define OP_VEND_MODEL_APP_LIST 0x804E
+
+bool config_server_init(void);
+bool config_client_init(void);
+void config_client_get_composition(uint32_t dst);
+void config_set_node(const char *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_CONFIG_MODEL_H */
diff --git a/mesh/crypto.h b/mesh/crypto.h
new file mode 100644
index 0000000..98bc065
--- /dev/null
+++ b/mesh/crypto.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_CRYPTO_H
+#define __MESH_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+
+bool mesh_crypto_aes_ccm_encrypt(const uint8_t nonce[13], const uint8_t key[16],
+ const uint8_t *aad, uint16_t aad_len,
+ const uint8_t *msg, uint16_t msg_len,
+ uint8_t *out_msg, void *out_mic,
+ size_t mic_size);
+bool mesh_crypto_aes_ccm_decrypt(const uint8_t nonce[13], const uint8_t key[16],
+ const uint8_t *aad, uint16_t aad_len,
+ const uint8_t *enc_msg, uint16_t enc_msg_len,
+ uint8_t *out_msg, void *out_mic,
+ size_t mic_size);
+bool mesh_crypto_nkik(const uint8_t network_key[16], uint8_t identity_key[16]);
+bool mesh_crypto_nkbk(const uint8_t network_key[16], uint8_t beacon_key[16]);
+bool mesh_crypto_identity(const uint8_t net_key[16], uint16_t addr,
+ uint8_t id[16]);
+bool mesh_crypto_identity_check(const uint8_t net_key[16], uint16_t addr,
+ uint8_t id[16]);
+bool mesh_crypto_beacon_cmac(const uint8_t encryption_key[16],
+ const uint8_t network_id[16],
+ uint32_t iv_index, bool kr, bool iu,
+ uint64_t *cmac);
+bool mesh_crypto_network_nonce(bool frnd, uint8_t ttl, uint32_t seq,
+ uint16_t src, uint32_t iv_index,
+ uint8_t nonce[13]);
+bool mesh_crypto_network_encrypt(bool ctl, uint8_t ttl,
+ uint32_t seq, uint16_t src,
+ uint32_t iv_index,
+ const uint8_t net_key[16],
+ const uint8_t *enc_msg, uint8_t enc_msg_len,
+ uint8_t *out, void *net_mic);
+bool mesh_crypto_network_decrypt(bool frnd, uint8_t ttl,
+ uint32_t seq, uint16_t src,
+ uint32_t iv_index,
+ const uint8_t net_key[16],
+ const uint8_t *enc_msg, uint8_t enc_msg_len,
+ uint8_t *out, void *net_mic, size_t mic_size);
+bool mesh_crypto_application_nonce(uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ bool aszmic, uint8_t nonce[13]);
+bool mesh_crypto_device_nonce(uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ bool aszmic, uint8_t nonce[13]);
+bool mesh_crypto_application_encrypt(uint8_t akf, uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ const uint8_t app_key[16],
+ const uint8_t *aad, uint8_t aad_len,
+ const uint8_t *msg, uint8_t msg_len,
+ uint8_t *out, void *app_mic,
+ size_t mic_size);
+bool mesh_crypto_application_decrypt(uint8_t akf, uint32_t seq, uint16_t src,
+ uint16_t dst, uint32_t iv_index,
+ const uint8_t app_key[16],
+ const uint8_t *aad, uint8_t aad_len,
+ const uint8_t *enc_msg, uint8_t enc_msg_len,
+ uint8_t *out, void *app_mic, size_t mic_size);
+bool mesh_crypto_device_key(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t device_key[16]);
+bool mesh_crypto_virtual_addr(const uint8_t virtual_label[16],
+ uint16_t *v_addr);
+bool mesh_crypto_nonce(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t nonce[13]);
+bool mesh_crypto_k1(const uint8_t ikm[16], const uint8_t salt[16],
+ const void *info, size_t info_len, uint8_t okm[16]);
+bool mesh_crypto_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
+ uint8_t net_id[1],
+ uint8_t enc_key[16],
+ uint8_t priv_key[16]);
+bool mesh_crypto_k3(const uint8_t n[16], uint8_t out64[8]);
+bool mesh_crypto_k4(const uint8_t a[16], uint8_t out5[1]);
+bool mesh_crypto_s1(const void *info, size_t len, uint8_t salt[16]);
+bool mesh_crypto_prov_prov_salt(const uint8_t conf_salt[16],
+ const uint8_t prov_rand[16],
+ const uint8_t dev_rand[16],
+ uint8_t prov_salt[16]);
+bool mesh_crypto_prov_conf_key(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t conf_key[16]);
+bool mesh_crypto_session_key(const uint8_t secret[32],
+ const uint8_t salt[16],
+ uint8_t session_key[16]);
+bool mesh_crypto_packet_encode(uint8_t *packet, uint8_t packet_len,
+ const uint8_t network_key[16],
+ uint32_t iv_index,
+ const uint8_t privacy_key[16]);
+bool mesh_crypto_packet_decode(const uint8_t *packet, uint8_t packet_len,
+ bool proxy, uint8_t *out, uint32_t iv_index,
+ const uint8_t network_key[16],
+ const uint8_t privacy_key[16]);
+
+bool mesh_crypto_aes_cmac(const uint8_t key[16], const uint8_t *msg,
+ size_t msg_len, uint8_t res[16]);
+
+bool mesh_get_random_bytes(void *buf, size_t num_bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mesh/gatt.h b/mesh/gatt.h
new file mode 100644
index 0000000..d6e5ec3
--- /dev/null
+++ b/mesh/gatt.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_GATT_H
+#define __MESH_GATT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gdbus/gdbus.h"
+#include "node.h"
+
+uint16_t mesh_gatt_sar(uint8_t **pkt, uint16_t size);
+bool mesh_gatt_is_child(GDBusProxy *proxy, GDBusProxy *parent,
+ const char *name);
+bool mesh_gatt_write(GDBusProxy *proxy, uint8_t *buf, uint16_t len,
+ GDBusReturnFunction cb, void *user_data);
+bool mesh_gatt_notify(GDBusProxy *proxy, bool enable, GDBusReturnFunction cb,
+ void *user_data);
+void mesh_gatt_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_GATT_H */
diff --git a/mesh/keys.h b/mesh/keys.h
new file mode 100644
index 0000000..5b955b2
--- /dev/null
+++ b/mesh/keys.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define KR_PHASE_NONE 0x00
+#define KR_PHASE_ONE 0x01
+#define KR_PHASE_TWO 0x02
+#define KR_PHASE_INVALID 0xff
+
+bool keys_app_key_add(uint16_t net_idx, uint16_t app_idx, uint8_t *key,
+ bool update);
+bool keys_net_key_add(uint16_t index, uint8_t *key, bool update);
+uint16_t keys_app_key_get_bound(uint16_t app_idx);
+uint8_t *keys_app_key_get(uint16_t app_idx, bool current);
+uint8_t *keys_net_key_get(uint16_t net_idx, bool current);
+bool keys_app_key_delete(uint16_t app_idx);
+bool keys_net_key_delete(uint16_t net_idx);
+uint8_t keys_get_kr_phase(uint16_t net_idx);
+bool keys_set_kr_phase(uint16_t index, uint8_t phase);
+void keys_cleanup_all(void);
diff --git a/mesh/mesh-net.h b/mesh/mesh-net.h
new file mode 100644
index 0000000..cb6c6e4
--- /dev/null
+++ b/mesh/mesh-net.h
@@ -0,0 +1,174 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_NETORK_H
+#define __MESH_NETORK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Proxy PDU Types */
+#define PROXY_NETWORK_PDU 0x00
+#define PROXY_MESH_BEACON 0x01
+#define PROXY_CONFIG_PDU 0x02
+#define PROXY_PROVISIONING_PDU 0x03
+
+#define CTL 0x80
+#define TTL_MASK 0x7f
+#define SEQ_MASK 0xffffff
+
+#define CREDFLAG_MASK 0x1000
+#define APP_IDX_MASK 0x0fff
+#define APP_IDX_DEV 0x7fff
+#define APP_IDX_ANY 0x8000
+#define APP_IDX_NET 0xffff
+#define APP_IDX_INVALID 0xffff
+
+#define NET_IDX_INVALID 0xffff
+#define NET_IDX_PRIMARY 0x0000
+
+#define KEY_CACHE_SIZE 64
+#define FRND_CACHE_MAX 32
+
+#define UNASSIGNED_ADDRESS 0x0000
+#define PROXIES_ADDRESS 0xfffc
+#define FRIENDS_ADDRESS 0xfffd
+#define RELAYS_ADDRESS 0xfffe
+#define ALL_NODES_ADDRESS 0xffff
+#define VIRTUAL_ADDRESS_LOW 0x8000
+#define VIRTUAL_ADDRESS_HIGH 0xbfff
+#define GROUP_ADDRESS_LOW 0xc000
+#define GROUP_ADDRESS_HIGH 0xff00
+
+#define DEFAULT_TTL 0xff
+
+#define PRIMARY_ELEMENT_IDX 0x00
+
+#define MAX_UNSEG_LEN 15 /* msg_len == 11 + sizeof(MIC) */
+#define MAX_SEG_LEN 12 /* UnSeg length - 3 octets overhead */
+#define SEG_MAX(len) (((len) <= MAX_UNSEG_LEN) ? 0 : \
+ (((len) - 1) / MAX_SEG_LEN))
+#define SEG_OFF(seg) ((seg) * MAX_SEG_LEN)
+#define MAX_SEG_TO_LEN(seg) ((seg) ? SEG_OFF((seg) + 1) : MAX_UNSEG_LEN)
+
+
+#define IS_UNASSIGNED(x) ((x) == UNASSIGNED_ADDRESS)
+#define IS_UNICAST(x) (((x) > UNASSIGNED_ADDRESS) && \
+ ((x) < VIRTUAL_ADDRESS_LOW))
+#define IS_VIRTUAL(x) (((x) >= VIRTUAL_ADDRESS_LOW) && \
+ ((x) <= VIRTUAL_ADDRESS_HIGH))
+#define IS_GROUP(x) (((x) >= GROUP_ADDRESS_LOW) && \
+ ((x) <= GROUP_ADDRESS_HIGH))
+#define IS_ALL_NODES(x) ((x) == ALL_NODES_ADDRESS)
+
+#define SEGMENTED 0x80
+#define UNSEGMENTED 0x00
+#define SEG_HDR_SHIFT 31
+#define IS_SEGMENTED(hdr) (!!((hdr) & (true << SEG_HDR_SHIFT)))
+
+#define KEY_ID_MASK 0x7f
+#define KEY_AID_MASK 0x3f
+#define KEY_ID_AKF 0x40
+#define KEY_AID_SHIFT 0
+#define AKF_HDR_SHIFT 30
+#define KEY_HDR_SHIFT 24
+#define HAS_APP_KEY(hdr) (!!((hdr) & (true << AKF_HDR_SHIFT)))
+
+#define OPCODE_MASK 0x7f
+#define OPCODE_HDR_SHIFT 24
+#define RELAY 0x80
+#define RELAY_HDR_SHIFT 23
+#define SZMIC 0x80
+#define SZMIC_HDR_SHIFT 23
+#define SEQ_ZERO_MASK 0x1fff
+#define SEQ_ZERO_HDR_SHIFT 10
+#define IS_RELAYED(hdr) (!!((hdr) & (true << RELAY_HDR_SHIFT)))
+#define HAS_MIC64(hdr) (!!((hdr) & (true << SZMIC_HDR_SHIFT)))
+
+#define SEG_MASK 0x1f
+#define SEGO_HDR_SHIFT 5
+#define SEGN_HDR_SHIFT 0
+#define SEG_TOTAL(hdr) (((hdr) >> SEGN_HDR_SHIFT) & SEG_MASK)
+/* Proxy Configuration Opcodes */
+#define PROXY_OP_SET_FILTER_TYPE 0x00
+#define PROXY_OP_FILTER_ADD 0x01
+#define PROXY_OP_FILTER_DEL 0x02
+#define PROXY_OP_FILTER_STATUS 0x03
+
+/* Proxy Filter Defines */
+#define PROXY_FILTER_WHITELIST 0x00
+#define PROXY_FILTER_BLACKLIST 0x01
+
+/* Network Tranport Opcodes */
+#define NET_OP_SEG_ACKNOWLEDGE 0x00
+#define NET_OP_FRND_POLL 0x01
+#define NET_OP_FRND_UPDATE 0x02
+#define NET_OP_FRND_REQUEST 0x03
+#define NET_OP_FRND_OFFER 0x04
+#define NET_OP_FRND_CLEAR 0x05
+#define NET_OP_FRND_CLEAR_CONFIRM 0x06
+
+#define NET_OP_PROXY_SUB_ADD 0x07
+#define NET_OP_PROXY_SUB_REMOVE 0x08
+#define NET_OP_PROXY_SUB_CONFIRM 0x09
+#define NET_OP_HEARTBEAT 0x0a
+
+/* Key refresh state on the mesh */
+#define NET_KEY_REFRESH_PHASE_NONE 0x00
+#define NET_KEY_REFRESH_PHASE_ONE 0x01
+#define NET_KEY_REFRESH_PHASE_TWO 0x02
+#define NET_KEY_REFRESH_PHASE_THREE 0x03
+
+#define MESH_FEATURE_RELAY 1
+#define MESH_FEATURE_PROXY 2
+#define MESH_FEATURE_FRIEND 4
+#define MESH_FEATURE_LPN 8
+
+#define MESH_MAX_ACCESS_PAYLOAD 380
+
+#define MESH_STATUS_SUCCESS 0x00
+#define MESH_STATUS_INVALID_ADDRESS 0x01
+#define MESH_STATUS_INVALID_MODEL 0x02
+#define MESH_STATUS_INVALID_APPKEY 0x03
+#define MESH_STATUS_INVALID_NETKEY 0x04
+#define MESH_STATUS_INSUFF_RESOURCES 0x05
+#define MESH_STATUS_IDX_ALREADY_STORED 0x06
+#define MESH_STATUS_INVALID_PUB_PARAM 0x07
+#define MESH_STATUS_NOT_SUB_MOD 0x08
+#define MESH_STATUS_STORAGE_FAIL 0x09
+#define MESH_STATUS_FEAT_NOT_SUP 0x0a
+#define MESH_STATUS_CANNOT_UPDATE 0x0b
+#define MESH_STATUS_CANNOT_REMOVE 0x0c
+#define MESH_STATUS_CANNOT_BIND 0x0d
+#define MESH_STATUS_UNABLE_CHANGE_STATE 0x0e
+#define MESH_STATUS_CANNOT_SET 0x0f
+#define MESH_STATUS_UNSPECIFIED_ERROR 0x10
+#define MESH_STATUS_INVALID_BINDING 0x11
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_NETORK_H */
diff --git a/mesh/net.h b/mesh/net.h
new file mode 100644
index 0000000..00866cb
--- /dev/null
+++ b/mesh/net.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_NET_H
+#define __MESH_NET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gdbus/gdbus.h"
+#include "node.h"
+
+typedef void (*net_mesh_session_open_callback)(int status);
+
+uint32_t net_get_iv_index(bool *iv_update);
+bool net_get_key(uint16_t net_idx, uint8_t *key);
+bool net_get_flags(uint16_t net_idx, uint8_t *out_flags);
+void net_set_iv_index(uint32_t index, bool update);
+uint32_t get_sequence_number(void);
+void set_sequence_number(uint32_t seq_number);
+uint16_t net_validate_proxy_beacon(const uint8_t *proxy_beacon);
+bool net_add_address_pool(uint16_t min, uint16_t max);
+uint16_t net_obtain_address(uint8_t num_elements);
+bool net_reserve_address_range(uint16_t base, uint8_t num_elements);
+void net_release_address(uint16_t addr, uint8_t num_elements);
+bool net_session_open(GDBusProxy *data_in, bool provisioner,
+ net_mesh_session_open_callback cb);
+void net_session_close(GDBusProxy *data_in);
+
+bool net_data_ready(uint8_t *ptr, uint8_t len);
+bool net_access_layer_send(uint8_t ttl, uint16_t src, uint32_t dst,
+ uint16_t app_idx, uint8_t *buf, uint16_t len);
+bool net_ctl_msg_send(uint8_t ttl, uint16_t src, uint16_t dst,
+ uint8_t *buf, uint16_t len);
+bool net_set_default_ttl(uint8_t ttl);
+uint8_t net_get_default_ttl(void);
+bool net_set_seq_num(uint32_t seq_num);
+uint32_t net_get_seq_num(void);
+void net_dest_ref(uint16_t dst);
+void net_dest_unref(uint16_t dst);
+bool net_register_unicast(uint16_t unicast, uint8_t count);
+bool net_register_group(uint16_t group_addr);
+uint32_t net_register_virtual(uint8_t buf[16]);
+bool mesh_model_recv(uint16_t app_idx, uint16_t src, uint32_t dst,
+ uint8_t *payload, uint16_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_NET_H */
diff --git a/mesh/node.h b/mesh/node.h
new file mode 100644
index 0000000..40b964c
--- /dev/null
+++ b/mesh/node.h
@@ -0,0 +1,146 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_NODE_H
+#define __MESH_NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Largest Possible GATT Packet: Provisioning Public Key + type + sar */
+#define MAX_GATT_SIZE (64 + 1 + 1)
+
+#define GATT_SAR_MASK 0xc0
+#define GATT_SAR_COMPLETE 0x00
+#define GATT_SAR_FIRST 0x40
+#define GATT_SAR_CONTINUE 0x80
+#define GATT_SAR_LAST 0xc0
+#define GATT_TYPE_INVALID 0xff
+#define GATT_TYPE_MASK 0x3f
+
+struct mesh_node;
+
+#define ACTION_ADD 1
+#define ACTION_UPDATE 2
+#define ACTION_DELETE 3
+
+struct prov_svc_data {
+ uint16_t oob;
+ uint8_t dev_uuid[16];
+};
+
+struct mesh_node_composition {
+ bool relay;
+ bool proxy;
+ bool lpn;
+ bool friend;
+ uint16_t cid;
+ uint16_t pid;
+ uint16_t vid;
+ uint16_t crpl;
+};
+
+struct mesh_publication {
+ uint16_t app_idx;
+ union {
+ uint16_t addr16;
+ uint8_t va_128[16];
+ } u;
+ uint8_t ttl;
+ uint8_t credential;
+ uint8_t period;
+ uint8_t retransmit;
+};
+
+typedef bool (*node_model_recv_callback)(uint16_t src, uint8_t *data,
+ uint16_t len, void *user_data);
+typedef int (*node_model_bind_callback)(uint16_t app_idx, int action);
+typedef void (*node_model_pub_callback)(struct mesh_publication *pub);
+typedef void (*node_model_sub_callback)(uint16_t sub_addr, int action);
+
+struct mesh_model_ops {
+ node_model_recv_callback recv;
+ node_model_bind_callback bind;
+ node_model_pub_callback pub;
+ node_model_sub_callback sub;
+};
+
+struct mesh_node *node_find_by_addr(uint16_t addr);
+struct mesh_node *node_find_by_uuid(uint8_t uuid[16]);
+struct mesh_node *node_create_new(struct prov_svc_data *prov);
+struct mesh_node *node_new(void);
+void node_free(struct mesh_node *node);
+bool node_is_provisioned(struct mesh_node *node);
+void *node_get_prov(struct mesh_node *node);
+void node_set_prov(struct mesh_node *node, void *prov);
+bool node_app_key_add(struct mesh_node *node, uint16_t idx);
+bool node_net_key_add(struct mesh_node *node, uint16_t index);
+bool node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
+ uint16_t idx);
+bool node_net_key_delete(struct mesh_node *node, uint16_t index);
+void node_set_primary(struct mesh_node *node, uint16_t unicast);
+uint16_t node_get_primary(struct mesh_node *node);
+uint16_t node_get_primary_net_idx(struct mesh_node *node);
+void node_set_device_key(struct mesh_node *node, uint8_t *key);
+uint8_t *node_get_device_key(struct mesh_node *node);
+void node_set_num_elements(struct mesh_node *node, uint8_t num_ele);
+uint8_t node_get_num_elements(struct mesh_node *node);
+bool node_parse_composition(struct mesh_node *node, uint8_t *buf, uint16_t len);
+GList *node_get_net_keys(struct mesh_node *node);
+GList *node_get_app_keys(struct mesh_node *node);
+void node_cleanup(void);
+
+bool node_set_local_node(struct mesh_node *node);
+struct mesh_node *node_get_local_node(void);
+void node_local_data_handler(uint16_t src, uint32_t dst,
+ uint32_t iv_index, uint32_t seq_num,
+ uint16_t app_idx, uint8_t *data, uint16_t len);
+
+bool node_local_model_register(uint8_t element_idx, uint16_t model_id,
+ struct mesh_model_ops *ops, void *user_data);
+bool node_local_vendor_model_register(uint8_t element_idx, uint32_t model_id,
+ struct mesh_model_ops *ops, void *user_data);
+
+bool node_set_element(struct mesh_node *node, uint8_t ele_idx);
+bool node_set_model(struct mesh_node *node, uint8_t ele_idx, uint32_t id);
+struct mesh_node_composition *node_get_composition(struct mesh_node *node);
+bool node_set_composition(struct mesh_node *node,
+ struct mesh_node_composition *comp);
+bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id, uint16_t app_idx);
+uint8_t node_get_default_ttl(struct mesh_node *node);
+bool node_set_default_ttl(struct mesh_node *node, uint8_t ttl);
+bool node_set_sequence_number(struct mesh_node *node, uint32_t seq);
+uint32_t node_get_sequence_number(struct mesh_node *node);
+bool node_set_iv_index(struct mesh_node *node, uint32_t iv_index);
+uint32_t node_get_iv_index(struct mesh_node *node);
+bool node_model_pub_set(struct mesh_node *node, uint8_t ele, uint32_t model_id,
+ struct mesh_publication *pub);
+struct mesh_publication *node_model_pub_get(struct mesh_node *node, uint8_t ele,
+ uint32_t model_id);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_NODE_H */
diff --git a/mesh/onoff-model.h b/mesh/onoff-model.h
new file mode 100644
index 0000000..57f3ecc
--- /dev/null
+++ b/mesh/onoff-model.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_GENERIC_ONOFF_MODEL_H
+#define __MESH_GENERIC_ONOFF_MODEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define GENERIC_ONOFF_SERVER_MODEL_ID 0x1000
+#define GENERIC_ONOFF_CLIENT_MODEL_ID 0x1001
+
+#define OP_GENERIC_ONOFF_GET 0x8201
+#define OP_GENERIC_ONOFF_SET 0x8202
+#define OP_GENERIC_ONOFF_SET_UNACK 0x8203
+#define OP_GENERIC_ONOFF_STATUS 0x8204
+
+void onoff_set_node(const char *args);
+bool onoff_client_init(uint8_t ele);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_GENERIC_ONOFF_MODEL_H */
diff --git a/mesh/prov-db.h b/mesh/prov-db.h
new file mode 100644
index 0000000..6b95937
--- /dev/null
+++ b/mesh/prov-db.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_PROV_DB_H
+#define __MESH_PROV_DB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool prov_db_show(const char *filename);
+bool prov_db_read(const char *filename);
+bool prov_db_read_local_node(const char *filename, bool provisioner);
+bool prov_db_add_new_node(struct mesh_node *node);
+bool prov_db_add_node_composition(struct mesh_node *node, uint8_t *data,
+ uint16_t len);
+bool prov_db_node_keys(struct mesh_node *node, GList *idxs, const char *desc);
+bool prov_db_add_binding(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id, uint16_t app_idx);
+bool prov_db_node_set_ttl(struct mesh_node *node, uint8_t ttl);
+bool prov_db_node_set_iv_seq(struct mesh_node *node, uint32_t iv, uint32_t seq);
+bool prov_db_local_set_iv_index(uint32_t iv_index, bool update, bool prov);
+bool prov_db_local_set_seq_num(uint32_t seq_num);
+bool prov_db_node_set_model_pub(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t model_id,
+ struct mesh_publication *pub);
+void prov_db_print_node_composition(struct mesh_node *node);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_PROV_DB_H */
diff --git a/mesh/prov.h b/mesh/prov.h
new file mode 100644
index 0000000..c4e068a
--- /dev/null
+++ b/mesh/prov.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_PROV_H
+#define __MESH_PROV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct prov;
+
+typedef void (*provision_done_cb)(void *user_data, int status);
+
+bool prov_open(struct mesh_node *node, GDBusProxy *prov_in, uint16_t net_idx,
+ provision_done_cb cb, void *user_data);
+bool prov_data_ready(struct mesh_node *node, uint8_t *buf, uint8_t len);
+bool prov_complete(struct mesh_node *node, uint8_t status);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_PROV_H */
diff --git a/mesh/util.h b/mesh/util.h
new file mode 100644
index 0000000..8212b53
--- /dev/null
+++ b/mesh/util.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __MESH_UTIL_H
+#define __MESH_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+
+#include "node.h"
+
+#define OP_UNRELIABLE 0x0100
+
+struct menu_entry {
+ const char *cmd;
+ const char *arg;
+ void (*func) (const char *arg);
+ const char *desc;
+};
+
+bool cmd_menu_init(const struct menu_entry *cmd_table);
+void cmd_menu_main(bool forced);
+bool add_cmd_menu(const char *name, const struct menu_entry *cmd_table);
+bool switch_cmd_menu(const char *name);
+void set_menu_prompt(const char *prefix, const char * node);
+void process_menu_cmd(const char *cmd, const char *arg);
+void print_cmd_menu(const struct menu_entry *cmd_table);
+void cmd_menu_cleanup(void);
+void print_byte_array(const char *prefix, const void *ptr, int len);
+bool str2hex(const char *str, uint16_t in_len, uint8_t *out_buf,
+ uint16_t out_len);
+size_t hex2str(uint8_t *in, size_t in_len, char *out,
+ size_t out_len);
+uint16_t mesh_opcode_set(uint32_t opcode, uint8_t *buf);
+bool mesh_opcode_get(const uint8_t *buf, uint16_t sz, uint32_t *opcode, int *n);
+const char *mesh_status_str(uint8_t status);
+void print_model_pub(uint16_t ele_addr, uint32_t mod_id,
+ struct mesh_publication *pub);
+void swap_u256_bytes(uint8_t *u256);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MESH_UTIL_H */
--
2.9.5

2017-08-14 19:01:15

by Gix, Brian

[permalink] [raw]
Subject: [PATCH 1/5] mesh: Add BT SIG reserved numbers for Mesh

---
lib/uuid.h | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index 2dcfe9e..2c57a33 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -139,6 +139,16 @@ extern "C" {
#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
#define GATT_REPORT_REFERENCE 0x2908

+/* GATT Mesh Services */
+#define MESH_PROV_SVC_UUID "00001827-0000-1000-8000-00805f9b34fb"
+#define MESH_PROXY_SVC_UUID "00001828-0000-1000-8000-00805f9b34fb"
+
+/* GATT Mesh Characteristic Types */
+#define MESH_PROVISIONING_DATA_IN 0x2ADB
+#define MESH_PROVISIONING_DATA_OUT 0x2ADC
+#define MESH_PROXY_DATA_IN 0x2ADD
+#define MESH_PROXY_DATA_OUT 0x2ADE
+
typedef struct {
enum {
BT_UUID_UNSPEC = 0,
--
2.9.5