/****************************************************************************** * * Copyright (C) 2021-2021 amlogic 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. * ******************************************************************************/ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "aml_comm.h" #include "aml_multibt.h" #include "aml_conf.h" /***************************************************************************** ** COMMON FUNCTIONS DEFINE *****************************************************************************/ static int mkdir_p(const char *path, mode_t mode) { char tmp[256]; char *p = NULL; size_t len; if (!path || !*path) { ALOGE("path err"); return -1; } snprintf(tmp, sizeof(tmp), "%s", path); len = strlen(tmp); if (tmp[len - 1] == '/') tmp[len - 1] = '\0'; for (p = tmp + 1; *p; p++) { if (*p == '/') { *p = '\0'; if (mkdir(tmp, mode) && errno != EEXIST) { ALOGE("mkdir %s err", tmp); return -1; } *p = '/'; } } if (mkdir(tmp, mode) && errno != EEXIST) { ALOGE("mkdir %s err", tmp); return -1; } return 0; } int amlbt_write_file(const char* fpath, const char *str, int len) { int ret = -1; int fd; char path_copy[BUF_MAX_LEN]; char *dir; if (!fpath || !str || len <= 0) { ALOGE("invalid input: path=%p str=%p size=%d", fpath, str, len); return -1; } snprintf(path_copy, sizeof(path_copy), "%s", fpath); dir = dirname(path_copy); if (mkdir_p(dir, 0755) < 0) { ALOGE("mkdir_p fail for %s", dir); return -1; } fd = open(fpath, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) { ALOGE("open:%s fail", fpath); return -1; } ret = write(fd, str, len); if (ret != len) { ALOGE("write fail: expect:%d, get:%d", len, ret); ret = -1; } close(fd); return ret; } int amlbt_get_random_addr(unsigned char *bdaddr, enum addr_mode mode) { int fd; ssize_t cnt, need; unsigned char buffer[BT_MAC_LEN] = {0}; fd = open(AMLBT_RANDOM_DEV, O_RDONLY); if (fd < 0) { ALOGE("open:%s fail", AMLBT_RANDOM_DEV); return -1; } need = sizeof(buffer); cnt = 0; while (cnt < need) { ssize_t n = read(fd, buffer + cnt, need - cnt); if (n <= 0) { ALOGE("read :%s fail, cnt:%zd", AMLBT_RANDOM_DEV, cnt); close(fd); return -1; } cnt += n; } close(fd); if (mode == ADDR_FIXED_PREFIX) { // Prefix 0x22:22, last 4 bytes are random bdaddr[0] = 0x22; bdaddr[1] = 0x22; memcpy(bdaddr + 2, buffer + 2, 4); } else { // Fully random 6 bytes memcpy(bdaddr, buffer, BT_MAC_LEN); // Ensure locally administered + unicast bdaddr[0] &= 0xFE; // clear bit0 → unicast bdaddr[0] |= 0x02; // set bit1 → locally administered } return 0; } static char *amlbt_read_file(const char *path) { int fd = open(path, O_RDONLY); if (fd < 0) { ALOGE("open %s failed: %s", path, strerror(errno)); return NULL; } struct stat st; if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode) || st.st_size == 0) { ALOGE("stat err"); close(fd); return NULL; } char *buf = calloc(1, st.st_size + 1); if (!buf) { ALOGE("calloc %zu bytes fail: %s", (size_t)st.st_size + 1, strerror(errno)); close(fd); return NULL; } ssize_t total = 0; while (total < st.st_size) { ssize_t r = read(fd, buf + total, st.st_size - total); if (r <= 0) { ALOGE("read fail: %zd", r); free(buf); close(fd); return NULL; } total += r; } close(fd); return buf; // Caller is responsible for free() } static char *amlbt_get_value(const char *file_buf, const char *key) { static char val[BUF_MAX_LEN]; char *pos = strstr(file_buf, key); if (!pos) return NULL; pos = strchr(pos, ':'); if (!pos) return NULL; pos++; while (*pos == ' ') pos++; char *end = strchr(pos, '\n'); if (!end) end = (char *)(file_buf + strlen(file_buf)); size_t len = end - pos; if (len >= sizeof(val)) len = sizeof(val) - 1; strncpy(val, pos, len); val[len] = '\0'; return val; } int amlbt_info_update(const char *key, const char *new_val) { char *buf = amlbt_read_file(AMLBT_INFO_PATH); char new_content[BUF_MAX_LEN*4] = {0}; char old_val[BUF_MAX_LEN] = {0}; char name_val[BUF_MAX_LEN] = {0}; char addr_val[BUF_MAX_LEN] = {0}; char fw_val[BUF_MAX_LEN] = {0}; if (buf) { char *temp = amlbt_get_value(buf, key); if (temp && strcmp(temp, new_val) == 0) { ALOGD("%s not changed, skip write", key); free(buf); return 0; } strncpy(old_val, temp ? temp : "", sizeof(old_val)-1); old_val[BUF_MAX_LEN-1] = '\0'; char *tmp; tmp = amlbt_get_value(buf, AMLBT_NAME); strncpy(name_val, tmp ? tmp : "", sizeof(name_val)-1); tmp = amlbt_get_value(buf, AMLBT_ADDR); strncpy(addr_val, tmp ? tmp : "", sizeof(addr_val)-1); tmp = amlbt_get_value(buf, AMLBT_FW_VER); strncpy(fw_val, tmp ? tmp : "", sizeof(fw_val)-1); free(buf); } else { old_val[0] = '\0'; } if (strcmp(key, AMLBT_NAME) == 0) strncpy(name_val, new_val, sizeof(name_val)-1); if (strcmp(key, AMLBT_ADDR) == 0) strncpy(addr_val, new_val, sizeof(addr_val)-1); if (strcmp(key, AMLBT_FW_VER) == 0) strncpy(fw_val, new_val, sizeof(fw_val)-1); snprintf(new_content, sizeof(new_content), "amlbt_name: %s\n" "addr: %s\n" "fw_version: %s\n", name_val, addr_val, fw_val); int fd = open(AMLBT_INFO_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { ALOGE("open %s fail: %s", AMLBT_INFO_PATH, strerror(errno)); return -1; } size_t len = strlen(new_content); size_t written = 0; while (written < len) { ssize_t r = write(fd, new_content + written, len - written); if (r < 0) { ALOGE("write %s fail: %s", AMLBT_INFO_PATH, strerror(errno)); close(fd); return -1; } written += r; } fsync(fd); close(fd); ALOGD("update %s: %s -> %s", key, old_val, new_val); return 0; } int amlbt_get_fw_ver(const unsigned char *str) { if (!str) { ALOGE("parameters err"); return -1; } char *fw_version = NULL; const unsigned char *fw_ptr = str + 7; // skip 7 bytes int ret = asprintf(&fw_version, "date:%02x.%02x, number:0x%02x%02x", *(fw_ptr + 1), *fw_ptr, *(fw_ptr + 3), *(fw_ptr + 2)); if (ret == -1 || !fw_version) { ALOGE("get fw version fail"); return -1; } ret = amlbt_info_update(AMLBT_FW_VER, fw_version); if (ret < 0) { ALOGE("update %s fail", AMLBT_FW_VER); free(fw_version); return ret; } free(fw_version); return 0; } int amlbt_read_addr(unsigned char *addr) { if (!addr) { ALOGE("parameters err"); return -1; } char *buf = amlbt_read_file(AMLBT_INFO_PATH); if (!buf) { ALOGE("read %s fail", AMLBT_INFO_PATH); return -1; } char *addr_str = amlbt_get_value(buf, AMLBT_ADDR); if (!addr_str || strlen(addr_str) != BT_MAC_BUF_LEN) { ALOGE("%s key not found or invalid: %s", AMLBT_ADDR, addr_str ? addr_str : "(null)"); free(buf); return -1; } unsigned int val[BT_MAC_LEN]; int n = sscanf(addr_str, "%2x:%2x:%2x:%2x:%2x:%2x", &val[0], &val[1], &val[2], &val[3], &val[4], &val[5]); if (n != BT_MAC_LEN) { ALOGE("invalid addr format: %s", addr_str); free(buf); return -1; } for (int i = 0; i < BT_MAC_LEN; i++) addr[i] = (unsigned char)val[i]; free(buf); return 0; }