From d1ed3947a4da0439ad2de8b8952d30c6adb05372 Mon Sep 17 00:00:00 2001 From: Anupam Roy Date: Fri, 17 Jul 2020 15:37:23 +0530 Subject: [PATCH] Mesh: Add Utility & helper functions for service This patch adds basic set of Mesh utility & helper methods. It will be expanded to support more methods in future Change-Id: Ib36f7da93719acd67456262d100d9a1f7de75fca Signed-off-by: Anupam Roy --- bt-service/CMakeLists.txt | 1 + .../services/include/bt-service-mesh-util.h | 221 ++++++++++++++ .../services/mesh/bt-service-mesh-util.c | 279 ++++++++++++++++++ 3 files changed, 501 insertions(+) create mode 100644 bt-service/services/include/bt-service-mesh-util.h create mode 100644 bt-service/services/mesh/bt-service-mesh-util.c diff --git a/bt-service/CMakeLists.txt b/bt-service/CMakeLists.txt index 41f9e802..0bac7a47 100644 --- a/bt-service/CMakeLists.txt +++ b/bt-service/CMakeLists.txt @@ -31,6 +31,7 @@ SET(SRCS ./services/audio/avrcp/bt-service-avrcp-ctrl.c ./services/gatt/bt-service-gatt.c ./services/audio/hf/bt-service-hf-client.c +./services/mesh/bt-service-mesh-util.c ) IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_FEATURE_BT_OBEX") diff --git a/bt-service/services/include/bt-service-mesh-util.h b/bt-service/services/include/bt-service-mesh-util.h new file mode 100644 index 00000000..4f6418da --- /dev/null +++ b/bt-service/services/include/bt-service-mesh-util.h @@ -0,0 +1,221 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * @author: Anupam Roy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef BT_SERVICE_MESH_UTIL_H_ +#define BT_SERVICE_MESH_UTIL_H_ + +#include +#include +#include "bluetooth-api.h" +#include "bluetooth-mesh-api.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MESH_FEATURE_RELAY 1 +#define MESH_FEATURE_PROXY 2 +#define MESH_FEATURE_FRIEND 4 +#define MESH_FEATURE_LPN 8 + +#define MESH_DEFAULT_LOCATION 0x0000 + +#define MESH_CDB_DEFAULT_DIR_PATH "/opt/usr/mesh" + +/* Status codes */ +#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_FEATURE_NO_SUPPORT 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 + +#define MESH_UNASSIGNED_ADDRESS 0x0000 +#define MESH_PROXIES_ADDRESS 0xfffc +#define MESH_FRIENDS_ADDRESS 0xfffd +#define MESH_RELAYS_ADDRESS 0xfffe +#define MESH_ALL_NODES_ADDRESS 0xffff +#define MESH_VIRTUAL_ADDRESS_LOW 0x8000 +#define MESH_VIRTUAL_ADDRESS_HIGH 0xbfff +#define MESH_GROUP_ADDRESS_LOW 0xc000 +#define MESH_GROUP_ADDRESS_HIGH 0xfeff +#define MESH_FIXED_GROUP_LOW 0xff00 +#define MESH_FIXED_GROUP_HIGH 0xffff + +#define MESH_DEFAULT_START_ADDRESS 0x00aa +#define MESH_DEFAULT_MAX_ADDRESS (MESH_VIRTUAL_ADDRESS_LOW - 1) +#define MESH_IS_VIRTUAL(x) (((x) >= MESH_VIRTUAL_ADDRESS_LOW) && \ + ((x) <= MESH_VIRTUAL_ADDRESS_HIGH)) +#define MESH_IS_GROUP(x) ((((x) >= MESH_GROUP_ADDRESS_LOW) && \ + ((x) < MESH_FIXED_GROUP_HIGH)) || \ + ((x) == MESH_ALL_NODES_ADDRESS)) + +#define MESH_IS_FIXED_GROUP_ADDRESS(x) ((x) >= MESH_PROXIES_ADDRESS) +#define MESH_IS_ALL_NODES(x) ((x) == MESH_ALL_NODES_ADDRESS) + +#define MESH_DEFAULT_NET_INDEX 0x0000 +#define MESH_MAX_CRPL_SIZE 0x7fff + +#define MESH_PRIMARY_ELE_IDX 0x00 + +#define MESH_PRIMARY_NET_IDX 0x0000 +#define MESH_MAX_KEY_IDX 0x0fff +#define MESH_MAX_MODEL_COUNT 0xff +#define MESH_MAX_ELE_COUNT 0xff + +#define MESH_KEY_REFRESH_PHASE_NONE 0x00 +#define MESH_KEY_REFRESH_PHASE_ONE 0x01 +#define MESH_KEY_REFRESH_PHASE_TWO 0x03 +#define MESH_KEY_REFRESH_PHASE_THREE 0x02 + +#define MESH_NET_IDX_INVALID 0xffff +#define MESH_NET_NID_INVALID 0xff + +#define MESH_KEY_IDX_INVALID MESH_NET_IDX_INVALID +#define MESH_VENDOR_ID_MASK 0xffff0000 + +#define MESH_DEFAULT_RESPONSE_TIMEOUT 3 +#define MESH_RESPONSE_NONE 0xFFFFFFFF + +#define MESH_OPCODE_UNRELIABLE 0x0100 +#define MESH_MINIMUM_COMPOSITION_LEN 16 + +/* New List */ +#define MESH_OPCODE_APPKEY_ADD 0x00 +#define MESH_OPCODE_APPKEY_DELETE 0x8000 +#define MESH_OPCODE_APPKEY_GET 0x8001 +#define MESH_OPCODE_APPKEY_LIST 0x8002 +#define MESH_OPCODE_APPKEY_STATUS 0x8003 +#define MESH_OPCODE_APPKEY_UPDATE 0x01 +#define MESH_OPCODE_DEV_COMP_GET 0x8008 +#define MESH_OPCODE_DEV_COMP_STATUS 0x02 +#define MESH_OPCODE_CONFIG_BEACON_GET 0x8009 +#define MESH_OPCODE_CONFIG_BEACON_SET 0x800A +#define MESH_OPCODE_CONFIG_BEACON_STATUS 0x800B +#define MESH_OPCODE_CONFIG_DEFAULT_TTL_GET 0x800C +#define MESH_OPCODE_CONFIG_DEFAULT_TTL_SET 0x800D +#define MESH_OPCODE_CONFIG_DEFAULT_TTL_STATUS 0x800E +#define MESH_OPCODE_CONFIG_FRIEND_GET 0x800F +#define MESH_OPCODE_CONFIG_FRIEND_SET 0x8010 +#define MESH_OPCODE_CONFIG_FRIEND_STATUS 0x8011 +#define MESH_OPCODE_CONFIG_PROXY_GET 0x8012 +#define MESH_OPCODE_CONFIG_PROXY_SET 0x8013 +#define MESH_OPCODE_CONFIG_PROXY_STATUS 0x8014 +#define MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_GET 0x8015 +#define MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_SET 0x8016 +#define MESH_OPCODE_CONFIG_KEY_REFRESH_PHASE_STATUS 0x8017 +#define MESH_OPCODE_CONFIG_MODEL_PUB_GET 0x8018 +#define MESH_OPCODE_CONFIG_MODEL_PUB_SET 0x03 +#define MESH_OPCODE_CONFIG_MODEL_PUB_STATUS 0x8019 +#define MESH_OPCODE_CONFIG_MODEL_PUB_VIRT_SET 0x801A +#define MESH_OPCODE_CONFIG_MODEL_SUB_ADD 0x801B +#define MESH_OPCODE_CONFIG_MODEL_SUB_DELETE 0x801C +#define MESH_OPCODE_CONFIG_MODEL_SUB_DELETE_ALL 0x801D +#define MESH_OPCODE_CONFIG_MODEL_SUB_OVERWRITE 0x801E +#define MESH_OPCODE_CONFIG_MODEL_SUB_STATUS 0x801F +#define MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_ADD 0x8020 +#define MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_DELETE 0x8021 +#define MESH_OPCODE_CONFIG_MODEL_SUB_VIRT_OVERWRITE 0x8022 +#define MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_GET 0x8023 +#define MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_SET 0x8024 +#define MESH_OPCODE_CONFIG_NETWORK_TRANSMIT_STATUS 0x8025 +#define MESH_OPCODE_CONFIG_RELAY_GET 0x8026 +#define MESH_OPCODE_CONFIG_RELAY_SET 0x8027 +#define MESH_OPCODE_CONFIG_RELAY_STATUS 0x8028 +#define MESH_OPCODE_CONFIG_MODEL_SUB_GET 0x8029 +#define MESH_OPCODE_CONFIG_MODEL_SUB_LIST 0x802A +#define MESH_OPCODE_CONFIG_VEND_MODEL_SUB_GET 0x802B +#define MESH_OPCODE_CONFIG_VEND_MODEL_SUB_LIST 0x802C +#define MESH_OPCODE_CONFIG_POLL_TIMEOUT_LIST 0x802D +#define MESH_OPCODE_CONFIG_POLL_TIMEOUT_STATUS 0x802E +/* Health opcodes in health-mod.h */ +#define MESH_OPCODE_CONFIG_HEARTBEAT_PUB_GET 0x8038 +#define MESH_OPCODE_CONFIG_HEARTBEAT_PUB_SET 0x8039 +#define MESH_OPCODE_CONFIG_HEARTBEAT_PUB_STATUS 0x06 +#define MESH_OPCODE_CONFIG_HEARTBEAT_SUB_GET 0x803A +#define MESH_OPCODE_CONFIG_HEARTBEAT_SUB_SET 0x803B +#define MESH_OPCODE_CONFIG_HEARTBEAT_SUB_STATUS 0x803C +#define MESH_OPCODE_MODEL_APP_BIND 0x803D +#define MESH_OPCODE_MODEL_APP_STATUS 0x803E +#define MESH_OPCODE_MODEL_APP_UNBIND 0x803F +#define MESH_OPCODE_NETKEY_ADD 0x8040 +#define MESH_OPCODE_NETKEY_DELETE 0x8041 +#define MESH_OPCODE_NETKEY_GET 0x8042 +#define MESH_OPCODE_NETKEY_LIST 0x8043 +#define MESH_OPCODE_NETKEY_STATUS 0x8044 +#define MESH_OPCODE_NETKEY_UPDATE 0x8045 +#define MESH_OPCODE_NODE_IDENTITY_GET 0x8046 +#define MESH_OPCODE_NODE_IDENTITY_SET 0x8047 +#define MESH_OPCODE_NODE_IDENTITY_STATUS 0x8048 +#define MESH_OPCODE_NODE_RESET 0x8049 +#define MESH_OPCODE_NODE_RESET_STATUS 0x804A +#define MESH_OPCODE_MODEL_APP_GET 0x804B +#define MESH_OPCODE_MODEL_APP_LIST 0x804C +#define MESH_OPCODE_VENDOR_MODEL_APP_GET 0x804D +#define MESH_OPCODE_VENDOR_MODEL_APP_LIST 0x804E + + +uint32_t _bt_mesh_util_get_timestamp_secs(void); + +bool _bt_mesh_util_convert_string_to_hex(const char *str, + uint16_t in_len, uint8_t *out, + uint16_t out_len); + +size_t _bt_mesh_util_convert_hex_to_string(uint8_t *in, + size_t in_len, char *out, size_t out_len); + +void _bt_mesh_util_print_packet(const char *label, + const void *data, uint16_t size); + +bool _bt_mesh_util_create_directory(const char *dir_name); + +bool _bt_mesh_util_is_directory_exists(const char *dir_path); + +uint16_t _bt_mesh_util_opcode_set(uint32_t opcode, + uint8_t *buf); + +bool _bt_mesh_util_opcode_get(const uint8_t *buf, + uint16_t sz, uint32_t *opcode, int *n); + +bool _bt_mesh_util_crypto_s1(const void *info, size_t len, + uint8_t salt[16]); + +bool _bt_mesh_util_crypto_create_virtual_address( + const uint8_t virtual_label[16], + uint16_t *addr); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* BT_SERVICE_MESH_UTIL_H_ */ diff --git a/bt-service/services/mesh/bt-service-mesh-util.c b/bt-service/services/mesh/bt-service-mesh-util.c new file mode 100644 index 00000000..08fe99a7 --- /dev/null +++ b/bt-service/services/mesh/bt-service-mesh-util.c @@ -0,0 +1,279 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * @author: Anupam Roy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing prov_err_strs and + * limitations under the License. + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bt-service-common.h" +#include "bt-service-util.h" + +#include "bt-service-mesh-util.h" +#include + +/* Multiply used Zero array */ +static const uint8_t zero[16] = { 0, }; + +static bool __mesh_util_crypto_aes_cmac_one( + const uint8_t key[16], const void *msg, + size_t msg_len, uint8_t res[16]) +{ + void *checksum; + bool result; + + checksum = l_checksum_new_cmac_aes(key, 16); + if (!checksum) + return false; + + result = l_checksum_update(checksum, msg, msg_len); + + if (result) { + ssize_t len = l_checksum_get_digest(checksum, res, 16); + result = !!(len == 16); + } + + l_checksum_free(checksum); + + return result; +} + +bool _bt_mesh_util_crypto_s1(const void *info, + size_t len, uint8_t salt[16]) +{ + return __mesh_util_crypto_aes_cmac_one(zero, + info, len, salt); +} + +bool _bt_mesh_util_crypto_create_virtual_address( + const uint8_t virtual_label[16], uint16_t *addr) +{ + uint8_t tmp[16]; + + if (!_bt_mesh_util_crypto_s1("vtad", 4, tmp)) + return false; + + if (!addr || !__mesh_util_crypto_aes_cmac_one(tmp, + virtual_label, 16, tmp)) + return false; + + *addr = (l_get_be16(tmp + 14) & 0x3fff) | 0x8000; + return true; +} + +void _bt_mesh_util_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 { + BT_INFO("\r%s\n", line); + bytes = line + strlen(prefix) + 1; + } + } + + if (i % 16) + BT_INFO("\r%s\n", line); + + g_free(line); +} + +uint16_t _bt_mesh_util_opcode_set(uint32_t opcode, + uint8_t *buf) +{ + if (opcode <= 0x7e) { + buf[0] = opcode; + return 1; + } else if (opcode >= 0x8000 && opcode <= 0xbfff) { + l_put_be16(opcode, buf); + return 2; + } else if (opcode >= 0xc00000 && opcode <= 0xffffff) { + buf[0] = (opcode >> 16) & 0xff; + l_put_be16(opcode, buf + 1); + return 3; + } else + return 0; +} + +bool _bt_mesh_util_opcode_get(const uint8_t *buf, + uint16_t sz, uint32_t *opcode, int *n) +{ + BT_INFO("Mesh: Opcode Get DatLen [%d] Buf0 [0x%x]", + sz, buf[0]); + 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 = l_get_be16(buf); + break; + + case 0xc0: + if (sz < 3) + return false; + + *n = 3; + *opcode = l_get_be16(buf + 1); + *opcode |= buf[0] << 16; + break; + + default: + BT_ERR("Mesh: Bad Packet:\n"); + _bt_mesh_util_print_byte_array("\t", (void *) buf, sz); + return false; + } + + return true; +} + + +uint32_t _bt_mesh_util_get_timestamp_secs(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec; +} + +bool _bt_mesh_util_convert_string_to_hex(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 _bt_mesh_util_convert_hex_to_string(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; +} + +void _bt_mesh_util_print_packet(const char *label, + const void *data, uint16_t size) +{ + struct timeval pkt_time; + + gettimeofday(&pkt_time, NULL); + + if (size > 0) { + char *str; + + str = l_util_hexstring(data, size); + BT_DBG("%05d.%03d %s: %s", + (uint32_t) pkt_time.tv_sec % 100000, + (uint32_t) pkt_time.tv_usec/1000, label, str); + l_free(str); + } else + BT_DBG("%05d.%03d %s: empty", + (uint32_t) pkt_time.tv_sec % 100000, + (uint32_t) pkt_time.tv_usec/1000, label); +} + +bool _bt_mesh_util_create_directory(const char *mesh_dir) +{ + struct stat st; + BT_ERR("Mesh: Create [%s]", mesh_dir); + + if (stat(mesh_dir, &st) == 0) { + if (!S_ISDIR(st.st_mode)) { + BT_ERR("Mesh: [%s] not a directory", mesh_dir); + return false; + } + } else if (errno == ENOENT) { + BT_ERR("Mesh: Dir not available: [%s]", mesh_dir); + if (mkdir(mesh_dir, 0755) != 0) { + BT_ERR("Mesh: Dir creation failed: [%s] error [%d]", + mesh_dir, errno); + return false; + } + } else { + BT_ERR("Mesh: Cannot open config directory"); + return false; + } + + return true; +} + +bool _bt_mesh_util_is_directory_exists(const char *dir_path) +{ + struct stat st; + + if (stat(dir_path, &st) == 0) { + if (!S_ISDIR(st.st_mode)) { + BT_ERR("Mesh: [%s] not a directory", dir_path); + return false; + } + } else if (errno == ENOENT) { + return false; + } + + return true; +} -- 2.34.1