* [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner
@ 2017-08-14 19:01 Brian Gix
2017-08-14 19:01 ` [PATCH 1/5] mesh: Add BT SIG reserved numbers for Mesh Brian Gix
` (6 more replies)
0 siblings, 7 replies; 12+ messages in thread
From: Brian Gix @ 2017-08-14 19:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Brian Gix, marcel, luiz.dentz
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
^ permalink raw reply [flat|nested] 12+ messages in thread* [PATCH 1/5] mesh: Add BT SIG reserved numbers for Mesh 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix @ 2017-08-14 19:01 ` Brian Gix 2017-08-14 19:01 ` [PATCH 2/5] mesh: define APIs for Bluetooth Mesh Brian Gix ` (5 subsequent siblings) 6 siblings, 0 replies; 12+ messages in thread From: Brian Gix @ 2017-08-14 19:01 UTC (permalink / raw) To: linux-bluetooth; +Cc: Brian Gix, marcel, luiz.dentz --- 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 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/5] mesh: define APIs for Bluetooth Mesh 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix 2017-08-14 19:01 ` [PATCH 1/5] mesh: Add BT SIG reserved numbers for Mesh Brian Gix @ 2017-08-14 19:01 ` Brian Gix 2017-08-14 19:01 ` [PATCH 3/5] mesh: Baseline Mesh runtime configuration files Brian Gix ` (4 subsequent siblings) 6 siblings, 0 replies; 12+ messages in thread From: Brian Gix @ 2017-08-14 19:01 UTC (permalink / raw) To: linux-bluetooth; +Cc: Brian Gix, marcel, luiz.dentz --- 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: + linux-bluetooth@vger.kernel.org + +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 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/5] mesh: Baseline Mesh runtime configuration files 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix 2017-08-14 19:01 ` [PATCH 1/5] mesh: Add BT SIG reserved numbers for Mesh Brian Gix 2017-08-14 19:01 ` [PATCH 2/5] mesh: define APIs for Bluetooth Mesh Brian Gix @ 2017-08-14 19:01 ` Brian Gix 2017-08-14 19:01 ` [PATCH 4/5] mesh: Baseline Mesh implementation Brian Gix ` (3 subsequent siblings) 6 siblings, 0 replies; 12+ messages in thread From: Brian Gix @ 2017-08-14 19:01 UTC (permalink / raw) To: linux-bluetooth; +Cc: Brian Gix, marcel, luiz.dentz --- 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 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/5] mesh: Baseline Mesh implementation 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix ` (2 preceding siblings ...) 2017-08-14 19:01 ` [PATCH 3/5] mesh: Baseline Mesh runtime configuration files Brian Gix @ 2017-08-14 19:01 ` Brian Gix 2017-08-15 9:07 ` Luiz Augusto von Dentz 2017-08-14 19:01 ` [PATCH 5/5] mesh: Add mesh to main bluez build Brian Gix ` (2 subsequent siblings) 6 siblings, 1 reply; 12+ messages in thread From: Brian Gix @ 2017-08-14 19:01 UTC (permalink / raw) To: linux-bluetooth; +Cc: Brian Gix, marcel, luiz.dentz --- 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, ¬ify_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 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 4/5] mesh: Baseline Mesh implementation 2017-08-14 19:01 ` [PATCH 4/5] mesh: Baseline Mesh implementation Brian Gix @ 2017-08-15 9:07 ` Luiz Augusto von Dentz 2017-08-15 15:36 ` Gix, Brian 0 siblings, 1 reply; 12+ messages in thread From: Luiz Augusto von Dentz @ 2017-08-15 9:07 UTC (permalink / raw) To: Brian Gix; +Cc: linux-bluetooth@vger.kernel.org, Marcel Holtmann Hi Brian, On Mon, Aug 14, 2017 at 10:01 PM, Brian Gix <brian.gix@intel.com> 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, ¬ify_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 ^ permalink raw reply [flat|nested] 12+ messages in thread
* RE: [PATCH 4/5] mesh: Baseline Mesh implementation 2017-08-15 9:07 ` Luiz Augusto von Dentz @ 2017-08-15 15:36 ` Gix, Brian 2017-08-16 12:29 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 12+ messages in thread From: Gix, Brian @ 2017-08-15 15:36 UTC (permalink / raw) To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org, Marcel Holtmann 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== ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 4/5] mesh: Baseline Mesh implementation 2017-08-15 15:36 ` Gix, Brian @ 2017-08-16 12:29 ` Luiz Augusto von Dentz 0 siblings, 0 replies; 12+ messages in thread From: Luiz Augusto von Dentz @ 2017-08-16 12:29 UTC (permalink / raw) To: Gix, Brian; +Cc: linux-bluetooth@vger.kernel.org, Marcel Holtmann Hi Brian, On Tue, Aug 15, 2017 at 6:36 PM, Gix, Brian <brian.gix@intel.com> 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:luiz.dentz@gmail.com] >> Sent: Tuesday, August 15, 2017 2:07 AM >> To: Gix, Brian <brian.gix@intel.com> >> Cc: linux-bluetooth@vger.kernel.org; Marcel Holtmann >> <marcel@holtmann.org> >> Subject: Re: [PATCH 4/5] mesh: Baseline Mesh implementation >> >> Hi Brian, >> >> On Mon, Aug 14, 2017 at 10:01 PM, Brian Gix <brian.gix@intel.com> 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, ¬ify_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 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 5/5] mesh: Add mesh to main bluez build 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix ` (3 preceding siblings ...) 2017-08-14 19:01 ` [PATCH 4/5] mesh: Baseline Mesh implementation Brian Gix @ 2017-08-14 19:01 ` Brian Gix 2017-08-16 12:28 ` [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Szymon Janc 2017-08-21 10:42 ` Marcel Holtmann 6 siblings, 0 replies; 12+ messages in thread From: Brian Gix @ 2017-08-14 19:01 UTC (permalink / raw) To: linux-bluetooth; +Cc: Brian Gix, marcel, luiz.dentz --- 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 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix ` (4 preceding siblings ...) 2017-08-14 19:01 ` [PATCH 5/5] mesh: Add mesh to main bluez build Brian Gix @ 2017-08-16 12:28 ` Szymon Janc 2017-08-16 12:30 ` Luiz Augusto von Dentz 2017-08-21 10:42 ` Marcel Holtmann 6 siblings, 1 reply; 12+ messages in thread From: Szymon Janc @ 2017-08-16 12:28 UTC (permalink / raw) To: Brian Gix; +Cc: linux-bluetooth, marcel, luiz.dentz 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 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner 2017-08-16 12:28 ` [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Szymon Janc @ 2017-08-16 12:30 ` Luiz Augusto von Dentz 0 siblings, 0 replies; 12+ messages in thread From: Luiz Augusto von Dentz @ 2017-08-16 12:30 UTC (permalink / raw) To: Szymon Janc; +Cc: Brian Gix, linux-bluetooth@vger.kernel.org, Marcel Holtmann Hi Szymon, On Wed, Aug 16, 2017 at 3:28 PM, Szymon Janc <szymon.janc@codecoup.pl> 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 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix ` (5 preceding siblings ...) 2017-08-16 12:28 ` [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Szymon Janc @ 2017-08-21 10:42 ` Marcel Holtmann 6 siblings, 0 replies; 12+ messages in thread From: Marcel Holtmann @ 2017-08-21 10:42 UTC (permalink / raw) To: Brian Gix; +Cc: linux-bluetooth, Luiz Augusto von Dentz 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 ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2017-08-21 10:42 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-08-14 19:01 [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Brian Gix 2017-08-14 19:01 ` [PATCH 1/5] mesh: Add BT SIG reserved numbers for Mesh Brian Gix 2017-08-14 19:01 ` [PATCH 2/5] mesh: define APIs for Bluetooth Mesh Brian Gix 2017-08-14 19:01 ` [PATCH 3/5] mesh: Baseline Mesh runtime configuration files Brian Gix 2017-08-14 19:01 ` [PATCH 4/5] mesh: Baseline Mesh implementation Brian Gix 2017-08-15 9:07 ` Luiz Augusto von Dentz 2017-08-15 15:36 ` Gix, Brian 2017-08-16 12:29 ` Luiz Augusto von Dentz 2017-08-14 19:01 ` [PATCH 5/5] mesh: Add mesh to main bluez build Brian Gix 2017-08-16 12:28 ` [PATCH 0/5] MeshCtl - Mesh GATT Client Provisioner Szymon Janc 2017-08-16 12:30 ` Luiz Augusto von Dentz 2017-08-21 10:42 ` Marcel Holtmann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox