From 81b64418df35e68c3f91795e56f8d91243437762 Mon Sep 17 00:00:00 2001 From: pengyinjie Date: Wed, 25 Sep 2024 11:36:02 +0800 Subject: [PATCH] [set_model]:export api for sim [Desc]: export operation : 1. write info 2. get info 3. reset info 4. set default info add CMake secripts for set_model Signed-off-by: pengyinjie --- CMakeLists.txt | 17 ++ include/set_model_api.h | 145 ++++++++++++++++ tools/CMakeLists.txt | 23 +++ tools/set_model/CMakeLists.txt | 49 ++++++ tools/set_model/Kconfig | 46 ++++- tools/set_model/Make.defs | 2 +- tools/set_model/Makefile | 7 +- tools/set_model/set_model.c | 222 +++--------------------- tools/set_model/set_model_api.c | 290 ++++++++++++++++++++++++++++++++ 9 files changed, 597 insertions(+), 204 deletions(-) create mode 100644 include/set_model_api.h create mode 100644 tools/CMakeLists.txt create mode 100644 tools/set_model/CMakeLists.txt create mode 100644 tools/set_model/set_model_api.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c522d5..d3e39fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,3 +21,20 @@ nuttx_add_subdirectory() nuttx_generate_kconfig(MENUDESC "Security") + +# ############################################################################## +# Include Directory +# ############################################################################## + +set(EXPORT_INCDIR ${CMAKE_CURRENT_LIST_DIR}/include) + +# ############################################################################## +# Global FLAG +# ############################################################################## + +if(TARGET nuttx) + set_property( + TARGET nuttx + APPEND + PROPERTY NUTTX_INCLUDE_DIRECTORIES ${EXPORT_INCDIR}) +endif(TARGET nuttx) diff --git a/include/set_model_api.h b/include/set_model_api.h new file mode 100644 index 0000000..b1ea342 --- /dev/null +++ b/include/set_model_api.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022-2024 Xiaomi Corporation + * + * 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 SET_MODEL_API_H_ +#define SET_MODEL_API_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Writes product model information and CRC to a PSM (Product Specific Model) file. + * + * This function prepares a file path to store the product model information and its CRC. + * It first checks if the directory specified by PSM_PATH exists, and creates it if not. + * Then, it opens (or creates) a file named 'ot_config.psm_model' within this directory + * for writing. The product model (PRODUCT_MODEL macro) is written to this file, followed + * by its CRC (computed using kvs_crc8). Additionally, it sets several system properties + * related to the product, including market name, model, Bluetooth name and PID, MiIO model, + * and system app ID. + * + * @return 0 on success, -1 if an error occurs during directory creation, file opening, + * writing to file, or setting system properties. + * + * @note PRODUCT_MODEL, PSM_PATH, and other PRODUCT_* macros must be defined prior to + * calling this function. + */ +int psm_info_write(void); + +/** + * @brief Clears the content of the device information file. + * + * This function first checks the status of the directory where the device information file + * resides (typically /data/etc). If the directory status check fails, an error message is + * logged and the function returns with an error code. + * + * If the directory status check is successful, the function proceeds to open the device + * information file (specified by DEVICE_INFO_PATH) in write-only mode. If the file cannot + * be opened for writing, an error message is logged and the function returns with an error + * code. + * + * Once the file is successfully opened, the content of the file is cleared by truncating + * it to zero length. If truncation fails, an error message is logged, the file is closed, + * and the function returns with an error code. + * + * Upon successful truncation, the file is closed, and a success message is logged. + * + * @return 0 on success, -1 on failure. + * + * @note This function assumes that DEVICE_INFO_PATH is defined and points to a valid + * path to the device information file. + */ +int device_info_clear(void); + +/** + * @brief Retrieves the value associated with a given key from the device information file. + * + * This function first checks the status of the directory where the device information + * file resides. If the check fails, an error is logged and the function returns with + * an error code. + * + * It then calls the is_key_exist() function to search for the given key in the device + * information file. If the key is not found, an error message is logged and the + * function returns with an error code. + * + * If the key is found, the function returns successfully without any further action + * since the value (if needed) is retrieved and copied by the is_key_exist() function. + * + * @param key The key for which to retrieve the value. + * @param value A pointer to a character array where the retrieved value will be stored. + * This parameter is ignored by this function but is used by is_key_exist(). + * @return 0 on success, -1 on failure. + * + * @note This function assumes that DEVICE_INFO_PATH is defined and points to a valid + * path to the device information file. + */ +int device_info_get(const char* key, char* value); + +/** + * @brief Sets the value for a given key in the device information file. + * + * This function first checks the status of the directory where the device information file + * is located (usually /data/etc). If the directory status check fails, an error is logged + * and the function returns with an error code. + * + * If the key already exists in the device information file, as determined by calling + * is_key_exist(), an informational message is logged indicating that the key already + * exists and the function returns successfully without making any changes. + * + * If the key does not exist, the function proceeds to open the device information file + * (specified by DEVICE_INFO_PATH) in append mode with read/write capabilities ("a+"). + * If the file cannot be opened, an error is logged and the function returns with an error + * code. + * + * Using fprintf(), the function attempts to write the key and its corresponding value + * to the file in the format "key=\"value\"\n". If the write operation fails, an error + * is logged, the file is closed, and the function returns with an error code. + * + * Upon successful write, the file is closed and the function returns successfully. + * + * @param key The key for which to set the value. + * @param value The value to set for the given key. + * @return 0 on success, -1 on failure. + * + * @note This function assumes that DEVICE_INFO_PATH is defined and points to a valid + * path to the device information file. It also relies on the implementation of + * check_dir_status() and is_key_exist() functions to perform their respective + * tasks correctly. + */ +int device_info_set(const char* key, const char* value); + +/** + * @brief Sets the default device information. + * + * This function iterates through a predefined list of device information key-value pairs + * and sets each pair using the device_info_set function. The device information includes + * serial number (sn), WiFi MAC address (mac_wifi), Bluetooth MAC address (mac_bt), + * MiIO device ID (miio_did), MiIO device key (miio_key), color ID (color_id), and color + * description (color_desc). + * + * @return 0 on success, -1 if any of the device information settings fail. + * + * @note The default values for each key are defined as macros (e.g., DEFAULT_SN_VALUE) + * and should be defined prior to calling this function. + */ +int default_device_info_set(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..2641f64 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,23 @@ +# ############################################################################## +# frameworks/security/tools/CMakeList.txt +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you 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. +# +# ############################################################################## + +nuttx_add_subdirectory() + +nuttx_generate_kconfig(MENUDESC "Security tools") diff --git a/tools/set_model/CMakeLists.txt b/tools/set_model/CMakeLists.txt new file mode 100644 index 0000000..5c23c19 --- /dev/null +++ b/tools/set_model/CMakeLists.txt @@ -0,0 +1,49 @@ +# ############################################################################## +# frameworks/security/tools/set_model/CMakeLists.txt +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you 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. +# +# ############################################################################## + +# ############################################################################## +# Source files +# ############################################################################## + +set(CSRCS) + +if(CONFIG_SC_SET_MODEL_TOOL) + list(APPEND CSRCS ${CMAKE_CURRENT_LIST_DIR}/set_model.c) +endif(CONFIG_SC_SET_MODEL_TOOL) + +if(CONFIG_SC_SET_MODEL_API) + list(APPEND CSRCS ${CMAKE_CURRENT_LIST_DIR}/set_model_api.c) +endif(CONFIG_SC_SET_MODEL_API) + +# ############################################################################## +# Application add +# ############################################################################## + +if(CONFIG_SC_SET_MODEL_TOOL) + nuttx_add_application( + NAME + ${CONFIG_SC_SET_MODEL_PROGNAME} + SRCS + ${CSRCS} + STACKSIZE + ${CONFIG_SC_SET_MODEL_STACKSIZE} + PRIORITY + ${CONFIG_SET_MODEL_PRIORITY}) +endif(CONFIG_SC_SET_MODEL_TOOL) diff --git a/tools/set_model/Kconfig b/tools/set_model/Kconfig index 71350aa..863c752 100644 --- a/tools/set_model/Kconfig +++ b/tools/set_model/Kconfig @@ -16,15 +16,21 @@ # ############################################################################ -config SC_SET_MODEL - bool "enable set_model security tool" +config SC_SET_MODEL_API + bool "enable set_model security api" default n ---help--- - This config enable the set_model security tool, which is + This config enable the set_model security api, which is used to get the device infomation (SN, Mac etc..) from the storage device/file system and set to kvdb. -if SC_SET_MODEL +if SC_SET_MODEL_API + +config SC_SET_MODEL_TOOL + bool "use security set model tool" + default n + ---help--- + "use security set model tool" config SC_SET_MODEL_MIIO_PSM_PATH string "the data path" @@ -54,6 +60,38 @@ config SC_SET_MODEL_PRODUCT_HARDWARE string "hardware name" default "X4P" +config SC_SET_MODEL_DEFAULT_SN_VALUE + string "sn value, its length shall be 15" + default "55118/F3Z800841" + +config SC_SET_MODEL_DEFAULT_MAC_WIFI_VALUE + string "mac_wifi value, its length shall be 17" + default "42:43:44:45:46:47" + +config SC_SET_MODEL_DEFAULT_MAC_BT_VALUE + string "mac_bt value, its length shall be 17" + default "42:43:44:45:46:47" + +config SC_SET_MODEL_DEFAULT_MIIO_DID_VALUE + string "miio_did value, its length shall be 9" + default"000000001" + +config SC_SET_MODEL_DEFAULT_MIIO_KEY_VALUE + string "miio_key value, its length shall be 16" + default "0000000000000001" + +config SC_SET_MODEL_DEFAULT_COLOR_ID_VALUE + string "color_id value, its length shall be 1" + default "0" + +config SC_SET_MODEL_DEFAULT_COLOR_DESC_VALUE + string "color_desc value, its length shall be 15" + default "000000000000000" + +config SC_SET_MODEL_DEVICE_INFO_PATH + string "device info path" + default "/data/etc/device_info.txt" + config SC_SET_MODEL_PROGNAME string "Program name" default "set_model" diff --git a/tools/set_model/Make.defs b/tools/set_model/Make.defs index 937734e..b41c493 100644 --- a/tools/set_model/Make.defs +++ b/tools/set_model/Make.defs @@ -16,6 +16,6 @@ # ############################################################################ -ifneq ($(CONFIG_SC_SET_MODEL),) +ifneq ($(CONFIG_SC_SET_MODEL_API),) CONFIGURED_APPS += $(APPDIR)/frameworks/security/tools/set_model endif diff --git a/tools/set_model/Makefile b/tools/set_model/Makefile index 007c70f..5852761 100644 --- a/tools/set_model/Makefile +++ b/tools/set_model/Makefile @@ -18,10 +18,15 @@ include $(APPDIR)/Make.defs +ifneq ($(CONFIG_SC_SET_MODEL_API),) +CSRCS += set_model_api.c +ifneq ($(CONFIG_SC_SET_MODEL_TOOL),) PROGNAME = ${CONFIG_SC_SET_MODEL_PROGNAME} PRIORITY = ${CONFIG_SC_SET_MODEL_PRIORITY} STACKSIZE = ${CONFIG_SC_SET_MODEL_STACKSIZE} -MODULE = ${CONFIG_SC_SET_MODEL} +MODULE = ${CONFIG_SC_SET_MODEL_TOOL} MAINSRC = set_model.c +endif +endif include $(APPDIR)/Application.mk diff --git a/tools/set_model/set_model.c b/tools/set_model/set_model.c index e579b6a..c92fbad 100644 --- a/tools/set_model/set_model.c +++ b/tools/set_model/set_model.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -34,15 +35,6 @@ * Pre-processor Definitions ****************************************************************************/ -#define PRODUCT_MARKET_NAME CONFIG_SC_SET_MODEL_PRODUCT_MARKET_NAME -#define PSM_PATH CONFIG_SC_SET_MODEL_MIIO_PSM_PATH -#define PRODUCT_NAME CONFIG_SC_SET_MODEL_PRODUCT_NAME -#define PRODUCT_ID CONFIG_SC_SET_MODEL_PRODUCT_ID -#define PRODUCT_MODEL CONFIG_SC_SET_MODEL_PRODUCT_MODEL -#define PRODUCT_APP_ID CONFIG_SC_SET_MODEL_PRODUCT_APP_ID -#define PRODUCT_HARDWARE CONFIG_SC_SET_MODEL_PRODUCT_HARDWARE -#define DEVICE_INFO_PATH "/data/etc/device.info" - /* These length is inherited from previous projects.*/ #define PRODUCT_SN_LEN 15 #define PRODUCT_MAC_WIFI_LEN 17 @@ -59,7 +51,7 @@ static void usage(void) { syslog(LOG_INFO, "set_model usage:\n" "\tTo set model properties, use the following syntax:\n" - "\tset_model set \n" + "\t\tset_model set \n" "\tAvailable properties and their values:\n" "\t\tsn: (length: 15 characters max)\n" "\t\tmac_wifi: (length: 17 characters)\n" @@ -68,7 +60,7 @@ static void usage(void) "\t\tmiio_key: (length: 16 characters)\n" "\t\tcolor_id: (length: 1 characters)\n" "\t\tcolor_desc: (length: 15 characters)\n" - "\t\tExample:\n" + "\tExample:\n" "\t\tset_model set sn 55119/F3YN00102\n" "\t\tset_model set mac_wifi CC:D8:43:20:C4:22\n" "\t\tset_model set mac_bt CC:D8:43:20:C4:22\n" @@ -77,183 +69,16 @@ static void usage(void) "\t\tset_model set color_id 0\n" "\t\tset_model set color_desc 000000000000000\n" "\tTo set the PSM model and properties, use:\n" - "\tset_model setpsm\n" + "\t\tset_model setpsm\n" "\tTo reset the set model properties, use:\n" - "\tset_model reset\n" + "\t\tset_model reset\n" "\tTo get the all model properties and values, use:\n" - "\tset_model get\n"); -} - -static uint8_t kvs_crc8(const char* buf, uint16_t len) -{ - uint8_t crc = 0x00; - uint8_t i = 0; - - while (len--) { - crc ^= *buf++; - for (i = 8; i > 0; i--) { - if (crc & 0x80) - crc = (crc << 1) ^ 0x31; - else - crc <<= 1; - } - } - - return crc; -} - -static int check_dir_status(void) -{ - if (access("/data/etc", F_OK)) { - int ret = mkdir("/data/etc", 0644); - if (ret != 0) { - syslog(LOG_ERR, "can not create dir /data/etc\n"); - return -1; - } - syslog(LOG_INFO, "create /data/etc successfully!"); - } - syslog(LOG_INFO, "/data/etc is exist\n"); - - return 0; -} - -static int device_info_get(void) -{ - FILE* p = fopen(DEVICE_INFO_PATH, "r"); - if (!p) { - syslog(LOG_ERR, "Could not open %s for reading\n", DEVICE_INFO_PATH); - return -1; - } - - char buf[128]; - syslog(LOG_INFO, "Here getting content from %s:\n", DEVICE_INFO_PATH); - while (fgets(buf, sizeof(buf), p) != NULL) { - syslog(LOG_INFO, "%s", buf); - } - - fclose(p); - return 0; -} - -static bool is_key_exist(const char* path, const char* key) -{ - FILE* file = fopen(path, "r"); - if (!file) { - syslog(LOG_ERR, "Could not open %s\n", path); - return false; - } - - char line[32]; - while (fgets(line, sizeof(line), file)) { - char* token = strtok(line, "="); - if (token && strcmp(token, key) == 0) { - fclose(file); - return true; - } - } - - fclose(file); - return false; -} - -static int device_info_set(char* argv[]) -{ - if (is_key_exist(DEVICE_INFO_PATH, argv[2])) { - syslog(LOG_INFO, "Key %s already exists in %s\n", argv[2], DEVICE_INFO_PATH); - return 0; - } - - FILE* p = fopen(DEVICE_INFO_PATH, "a+"); - if (!p) { - syslog(LOG_ERR, "Could not open %s\n", DEVICE_INFO_PATH); - return -1; - } - - if (fprintf(p, "%s=%s\n", argv[2], argv[3]) < 0) { - syslog(LOG_ERR, "Failed to write %s=%s to %s\n", argv[2], argv[3], DEVICE_INFO_PATH); - fclose(p); - return -1; - } - - fclose(p); - return 0; -} - -static int device_info_clear(void) -{ - int fd = open(DEVICE_INFO_PATH, O_WRONLY); - if (fd == -1) { - syslog(LOG_ERR, "Could not open %s for writing\n", DEVICE_INFO_PATH); - return -1; - } - - if (ftruncate(fd, 0) == -1) { - syslog(LOG_ERR, "failed to truncate %s\n", DEVICE_INFO_PATH); - close(fd); - return -1; - } - - close(fd); - syslog(LOG_INFO, "%s is clear\n", DEVICE_INFO_PATH); - return 0; -} - -static int psm_info_write(void) -{ - int fd = -1; - const char m_model[32] = PRODUCT_MODEL; - char psm_path[64] = { 0 }; - uint8_t crc = 0; - int ret = 0; - - memset(psm_path, 0, sizeof(psm_path)); - if (access(PSM_PATH, F_OK)) { - if (mkdir(PSM_PATH, 0666) != 0) { - syslog(LOG_ERR, "Failed to create directory %s\n", PSM_PATH); - return -1; - } - } - snprintf(psm_path, sizeof(psm_path), "%s/ot_config.psm_model", PSM_PATH); - - fd = open(psm_path, O_CREAT | O_RDWR | O_TRUNC, 0666); - if (fd < 0) { - syslog(LOG_ERR, "Failed to create %s file\n", psm_path); - return -1; - } - - ret = write(fd, m_model, strlen(m_model)); - if (ret != strlen(m_model)) { - syslog(LOG_ERR, "Write %s into %s failed\n", m_model, psm_path); - close(fd); - return -1; - } - - crc = kvs_crc8(m_model, strlen(m_model)); - ret = write(fd, &crc, sizeof(uint8_t)); - if (ret != sizeof(uint8_t)) { - syslog(LOG_ERR, "Write crc failed\n"); - close(fd); - return -1; - } - syslog(LOG_INFO, "write %s into %s success\n", m_model, psm_path); - - property_set("market_name", PRODUCT_MARKET_NAME); - property_set("model", PRODUCT_HARDWARE); - property_set("persist.bt.name", PRODUCT_NAME); - property_set("persist.bt.pid", PRODUCT_ID); - property_set("persist.miio.model", PRODUCT_MODEL); - property_set("persist.sys.appid", PRODUCT_APP_ID); - syslog(LOG_INFO, "Set property as follows success :\n" - "\tmarket_name:%s\n" - "\tmodel: %s\n" - "\tpersist.miio.model: %s\n" - "\tpersist.bt.name: %s\n" - "\tpersist.bt.pid: %s\n" - "\tpersist.sys.appid: %s\n", - PRODUCT_MARKET_NAME, PRODUCT_HARDWARE, m_model, PRODUCT_NAME, - PRODUCT_ID, PRODUCT_APP_ID); - - return 0; + "\t\tset_model get sn\n" + "\t\tset_model get mac_bt\n" + "\t\tset_model get miio_did\n" + "\t\tset_model get miio_key\n" + "\t\tset_model get color_id\n" + "\t\tset_model get color_desc\n"); } /**************************************************************************** @@ -262,18 +87,12 @@ static int psm_info_write(void) int main(int argc, FAR char* argv[]) { - if (argc != 1 && argc != 2 && argc != 4) { + if (argc != 1 && argc != 2 && argc != 3 && argc != 4) { syslog(LOG_ERR, "Invalid argument number\n"); usage(); return -1; } - if (check_dir_status() != 0) { - syslog(LOG_ERR, "Check /data/etc status fail\n"); - return -1; - } - syslog(LOG_INFO, "check directory success\n"); - if (argc == 4 && strcmp(argv[1], "set") == 0) { if (strcmp(argv[2], "sn") == 0 && strlen(argv[3]) == PRODUCT_SN_LEN) { } else if (strcmp(argv[2], "mac_wifi") == 0 && strlen(argv[3]) == PRODUCT_MAC_WIFI_LEN) { @@ -287,8 +106,8 @@ int main(int argc, FAR char* argv[]) usage(); return -1; } - if (device_info_set(argv) != 0) { - syslog(LOG_ERR, "Set %s fail\n", argv[2]); + if (device_info_set(argv[2], argv[3]) != 0) { + syslog(LOG_ERR, "Set %s=%s fail\n", argv[2], argv[3]); return -1; } syslog(LOG_INFO, "Set %s=%s success\n", argv[2], argv[3]); @@ -298,18 +117,25 @@ int main(int argc, FAR char* argv[]) return -1; } syslog(LOG_INFO, "Reset /data/etc/device.info success\n"); - } else if (argc == 2 && strcmp(argv[1], "get") == 0) { - if (device_info_get() != 0) { + } else if (argc == 3 && strcmp(argv[1], "get") == 0) { + char value[24]; + memset(value, 0, sizeof(value)); + if (device_info_get(argv[2], value) != 0) { syslog(LOG_ERR, "Getting /data/etc/device.info fail\n"); return -1; } - syslog(LOG_INFO, "get /data/etc/device.info success\n"); + syslog(LOG_INFO, "get %s = %s from /data/etc/device.info success\n", argv[2], value); } else if (argc == 2 && strcmp(argv[1], "setpsm") == 0) { if (psm_info_write() != 0) { syslog(LOG_ERR, "Writing psm path or set property fail\n"); return -1; } syslog(LOG_INFO, "Writing psm path and set property success\n"); + } else if (argc == 2 && strcmp(argv[1], "setdefault") == 0) { + if (default_device_info_set() != 0) { + syslog(LOG_ERR, "Set default device info fail\n"); + return -1; + } } else { syslog(LOG_ERR, "Unrecognized option: %s\n", argv[1]); usage(); diff --git a/tools/set_model/set_model_api.c b/tools/set_model/set_model_api.c new file mode 100644 index 0000000..d783a2b --- /dev/null +++ b/tools/set_model/set_model_api.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2022-2024 Xiaomi Corporation + * + * 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. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PRODUCT_MARKET_NAME CONFIG_SC_SET_MODEL_PRODUCT_MARKET_NAME +#define PSM_PATH CONFIG_SC_SET_MODEL_MIIO_PSM_PATH +#define PRODUCT_NAME CONFIG_SC_SET_MODEL_PRODUCT_NAME +#define PRODUCT_ID CONFIG_SC_SET_MODEL_PRODUCT_ID +#define PRODUCT_MODEL CONFIG_SC_SET_MODEL_PRODUCT_MODEL +#define PRODUCT_APP_ID CONFIG_SC_SET_MODEL_PRODUCT_APP_ID +#define PRODUCT_HARDWARE CONFIG_SC_SET_MODEL_PRODUCT_HARDWARE +#define DEVICE_INFO_PATH CONFIG_SC_SET_MODEL_DEVICE_INFO_PATH + +#define DEFAULT_SN_VALUE CONFIG_SC_SET_MODEL_DEFAULT_SN_VALUE +#define DEFAULT_MAC_WIFI_VALUE CONFIG_SC_SET_MODEL_DEFAULT_MAC_WIFI_VALUE +#define DEFAULT_MAC_BT_VALUE CONFIG_SC_SET_MODEL_DEFAULT_MAC_BT_VALUE +#define DEFAULT_MIIO_DID_VALUE CONFIG_SC_SET_MODEL_DEFAULT_MIIO_DID_VALUE +#define DEFAULT_MIIO_KEY_VALUE CONFIG_SC_SET_MODEL_DEFAULT_MIIO_KEY_VALUE +#define DEFAULT_COLOR_ID_VALUE CONFIG_SC_SET_MODEL_DEFAULT_COLOR_ID_VALUE +#define DEFAULT_COLOR_DESC_VALUE CONFIG_SC_SET_MODEL_DEFAULT_COLOR_DESC_VALUE + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint8_t kvs_crc8(const char* line, uint16_t len) +{ + uint8_t crc = 0x00; + uint8_t i = 0; + + while (len--) { + crc ^= *line++; + for (i = 8; i > 0; i--) { + if (crc & 0x80) + crc = (crc << 1) ^ 0x31; + else + crc <<= 1; + } + } + + return crc; +} + +static int check_dir_status(void) +{ + if (access("/data/etc", F_OK)) { + int ret = mkdir("/data/etc", 0755); + if (ret != 0) { + syslog(LOG_ERR, "can not create dir /data/etc\n"); + return -1; + } + syslog(LOG_INFO, "create /data/etc successfully!"); + } + + return 0; +} + +static int is_key_exist(const char* path, const char* key, char* value, bool need_get_value, bool* found) +{ + FILE* file = fopen(path, "r"); + if (!file) { + syslog(LOG_ERR, "Could not open %s\n", path); + return -1; + } + char line[64]; + while (fgets(line, sizeof(line), file)) { + line[strcspn(line, "\n")] = 0; + char* read_key = strtok(line, "="); + if (!read_key) + continue; + if (read_key && strcmp(read_key, key) == 0) { + if (value) { + char* read_value = strtok(NULL, "\n"); + if (!read_value) + continue; + int read_length = strlen(read_value); + if (read_length > 0 && read_value[0] == '"' && read_value[read_length - 1] == '"') { + read_value[read_length - 1] = '\0'; + read_value++; + } + read_length = strlen(read_value); + if (need_get_value) { + strncpy(value, read_value, read_length); + } + } + *found = true; + break; + } + } + + if (found == false && need_get_value == true) { + value = NULL; + } + + fclose(file); + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int device_info_get(const char* key, char* value) +{ + if (check_dir_status() != 0) { + syslog(LOG_ERR, "Check /data/etc status fail\n"); + return -1; + } + + bool found = false; + bool need_get_value = true; + if (is_key_exist(DEVICE_INFO_PATH, key, value, need_get_value, &found) == 0 && found == false) { + syslog(LOG_ERR, "Key %s not found in %s\n", key, DEVICE_INFO_PATH); + return -1; + } + + return 0; +} + +int device_info_set(const char* key, const char* value) +{ + if (check_dir_status() != 0) { + syslog(LOG_ERR, "Check /data/etc status fail\n"); + return -1; + } + + bool found = false; + bool need_get_value = false; + if (is_key_exist(DEVICE_INFO_PATH, key, (char*)value, need_get_value, &found) == 0 && found == true) { + if (found == true) { + syslog(LOG_INFO, "%s already exists in %s\n", key, DEVICE_INFO_PATH); + return 0; + } + } else { + FILE* p = fopen(DEVICE_INFO_PATH, "a+"); + if (!p) { + syslog(LOG_ERR, "Could not open %s\n", DEVICE_INFO_PATH); + return -1; + } + + if (fprintf(p, "%s=\"%s\"\n", key, value) < 0) { + syslog(LOG_ERR, "Failed to write %s=%s to %s\n", key, value, DEVICE_INFO_PATH); + fclose(p); + return -1; + } + fclose(p); + } + + return 0; +} + +int device_info_clear(void) +{ + if (check_dir_status() != 0) { + syslog(LOG_ERR, "Check /data/etc status fail\n"); + return -1; + } + syslog(LOG_INFO, "Check /data/etc success\n"); + + int fd = open(DEVICE_INFO_PATH, O_WRONLY); + if (fd == -1) { + syslog(LOG_ERR, "Could not open %s for writing\n", DEVICE_INFO_PATH); + return -1; + } + + if (ftruncate(fd, 0) == -1) { + syslog(LOG_ERR, "failed to truncate %s\n", DEVICE_INFO_PATH); + close(fd); + return -1; + } + + close(fd); + syslog(LOG_INFO, "%s is clear\n", DEVICE_INFO_PATH); + return 0; +} + +int psm_info_write(void) +{ + int fd = -1; + const char m_model[32] = PRODUCT_MODEL; + char psm_path[64] = { 0 }; + uint8_t crc = 0; + int ret = 0; + + memset(psm_path, 0, sizeof(psm_path)); + if (access(PSM_PATH, F_OK)) { + if (mkdir(PSM_PATH, 0666) != 0) { + syslog(LOG_ERR, "Failed to create directory %s\n", PSM_PATH); + return -1; + } + } + snprintf(psm_path, sizeof(psm_path), "%s/ot_config.psm_model", PSM_PATH); + + fd = open(psm_path, O_CREAT | O_RDWR | O_TRUNC, 0666); + if (fd < 0) { + syslog(LOG_ERR, "Failed to create %s file\n", psm_path); + return -1; + } + + ret = write(fd, m_model, strlen(m_model)); + if (ret != strlen(m_model)) { + syslog(LOG_ERR, "Write %s into %s failed\n", m_model, psm_path); + close(fd); + return -1; + } + + crc = kvs_crc8(m_model, strlen(m_model)); + ret = write(fd, &crc, sizeof(uint8_t)); + if (ret != sizeof(uint8_t)) { + syslog(LOG_ERR, "Write crc failed\n"); + close(fd); + return -1; + } + syslog(LOG_INFO, "write %s into %s success\n", m_model, psm_path); + + property_set("market_name", PRODUCT_MARKET_NAME); + property_set("model", PRODUCT_HARDWARE); + property_set("persist.bt.name", PRODUCT_NAME); + property_set("persist.bt.pid", PRODUCT_ID); + property_set("persist.miio.model", PRODUCT_MODEL); + property_set("persist.sys.appid", PRODUCT_APP_ID); + syslog(LOG_INFO, "Set property as follows success :\n" + "\tmarket_name:%s\n" + "\tmodel: %s\n" + "\tpersist.miio.model: %s\n" + "\tpersist.bt.name: %s\n" + "\tpersist.bt.pid: %s\n" + "\tpersist.sys.appid: %s\n", + PRODUCT_MARKET_NAME, PRODUCT_HARDWARE, m_model, PRODUCT_NAME, + PRODUCT_ID, PRODUCT_APP_ID); + + return 0; +} + +int default_device_info_set(void) +{ + struct { + const char* key; + const char* value; + } default_device_info[] = { + { "sn", DEFAULT_SN_VALUE }, + { "mac_wifi", DEFAULT_MAC_WIFI_VALUE }, + { "mac_bt", DEFAULT_MAC_BT_VALUE }, + { "miio_did", DEFAULT_MIIO_DID_VALUE }, + { "miio_key", DEFAULT_MIIO_KEY_VALUE }, + { "color_id", DEFAULT_COLOR_ID_VALUE }, + { "color_desc", DEFAULT_COLOR_DESC_VALUE }, + }; + + for (int i = 0; i < sizeof(default_device_info) / sizeof(default_device_info[0]); i++) { + if (device_info_set(default_device_info[i].key, default_device_info[i].value) != 0) { + syslog(LOG_ERR, "Set %s=%s fail\n", default_device_info[i].key, default_device_info[i].value); + return -1; + } + } + + return 0; +}