Mesh: Add Utility & helper functions for service
authorAnupam Roy <anupam.r@samsung.com>
Fri, 17 Jul 2020 10:07:23 +0000 (15:37 +0530)
committerAnupam Roy <anupam.r@samsung.com>
Fri, 17 Jul 2020 10:07:23 +0000 (15:37 +0530)
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 <anupam.r@samsung.com>
bt-service/CMakeLists.txt
bt-service/services/include/bt-service-mesh-util.h [new file with mode: 0644]
bt-service/services/mesh/bt-service-mesh-util.c [new file with mode: 0644]

index 41f9e80..0bac7a4 100644 (file)
@@ -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 (file)
index 0000000..4f6418d
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Anupam Roy <anupam.r@samsung.com>
+ *
+ * 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 <glib.h>
+#include <sys/types.h>
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include <json-c/json.h>
+
+#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 (file)
index 0000000..08fe99a
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Anupam Roy <anupam.r@samsung.com>
+ *
+ * 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 <dirent.h>
+#include <ftw.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <dlog.h>
+#include <limits.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "bt-service-common.h"
+#include "bt-service-util.h"
+
+#include "bt-service-mesh-util.h"
+#include <ell/ell.h>
+
+/* 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;
+}