357 lines
8.8 KiB
C
357 lines
8.8 KiB
C
/******************************************************************************
|
|
*
|
|
* 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 <errno.h>
|
|
#include <fcntl.h>
|
|
#include <libgen.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#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;
|
|
}
|
|
|