#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tss.h"
#include "certificate.h"
#include "tss_cloud.h"
#include "tss_loop.h"
#include "tss_ubus.h"
#define TSSC_SCAN_DETECTION_INTERVAL 10000
#define TSSC_JOINING_DETECTION_INTERVAL 10000
#define TSSC_JOINING_TIMEOUT 180
#define TSSC_SCANING_TIMEOUT 30
#define TSSC_FULL_SCAN_INTERVAL_MIN 10 /* 10s */
#define TSSC_FULL_SCAN_INTERVAL_MAX 120 /* 120s */
#define TSSC_FULL_SCAN_REMAIN_TIME 3 /* 有ER回复,仍执行几次全信道扫描 */
#define TSSC_SCAN_TIMEOUT (30 * 60) /* 30min */
static struct tssc_context *tssc_ctx = NULL;
static struct tss_loop_fd *inotify_fd = NULL;
static struct tss_loop_timer *scan_timer = NULL;
static struct tss_loop_timer *tssc_joining_timer = NULL;
static void tssc_set_state(enum provisionee_connect_state state)
{
time_t now = tss_get_timestamp();
if (!tssc_ctx) {
return;
}
tssc_ctx->state = state;
if (state == SCANNING)
tssc_ctx->scaning_time = now;
else if (state == CONNECTING) {
tssc_ctx->joining_time = now;
tss_add_loop_timer(tssc_joining_timer, TSSC_JOINING_DETECTION_INTERVAL);
}
return;
}
static uint8_t *tssc_build_tss_req_payload(struct provisionee *ee, uint8_t *target_bssid, uint16_t *payload_len)
{
struct tss_context *tss_ctx = tss_ctx_get();
struct tss_request req = {{0}};
uint8_t *req_data = NULL;
if (!tss_ctx)
return NULL;
memcpy(req.addr, ee->addr, ETH_ADDR_LEN);
if (target_bssid)
memcpy(req.target_bssid, target_bssid, ETH_ADDR_LEN);
req.sysmode = ee->sysmode;
memcpy(&req.cap, &ee->cap, sizeof(struct tss_capability));
req.inter_ca = tss_ctx->inter_ca;
req.inter_ca_len = tss_ctx->inter_ca_len;
req.end_ca = tss_ctx->end_ca;
req.end_ca_len = tss_ctx->end_ca_len;
tss_get_group_id(req.gid);
if (SYSTEM_MODE_SUPPORT_AP(ee->sysmode))
req.dev_crypto = tss_get_device_crypto(&req.dev_crypto_len, tss_ctx->ecc_private_key, tss_ctx->ecc_private_key_len);
tss_get_model_name(req.dev_model);
tss_get_device_type(req.dev_type);
tss_get_hardware_ver(req.dev_hw_ver);
tss_get_country(req.dev_country);
req_data = build_tss_req_data(&req, payload_len);
if (req.dev_crypto)
free(req.dev_crypto);
return req_data;
}
static TSS_STATUS tssc_send_tss_resp_ack(int sd, uint8_t *da, uint8_t *sa, uint16_t freq)
{
TSS_STATUS ret = TSS_NOK;
uint8_t freq_option[6] = {TLCP_FREQ, 0x2, 0x0, 0x0, TLCP_END_CODE, 0x0};
uint8_t headroom = TSS_FRAME_HEADROOM + 6;
struct tssp_info tssp_info = {0};
struct tss_frame_buff *tfb = NULL;
tss_print("Reply tss response ack on chan %d", frequency_to_channel(freq));
tfb = tss_frame_alloc(headroom, headroom);
if (!tfb){
tss_print("Alloc tss frame buff failed!");
return ret;
}
tssp_info.type = TSSP_RESP_ACK;
memcpy(&freq_option[2], &freq, 2);
ret = tss_send(sd, tfb, TLCP_PROTO_TSSP, &tssp_info, da, sa, freq_option, 6, 0xff);
tss_frame_free(tfb);
return ret;
}
static TSS_STATUS tssc_send_tss_req(int sd, uint8_t *payload, uint16_t payload_len, uint8_t *da, uint8_t *sa, uint16_t freq)
{
TSS_STATUS ret = TSS_NOK;
uint8_t freq_option[6] = {TLCP_FREQ, 0x2, 0x0, 0x0, TLCP_END_CODE, 0x0};
uint8_t headroom = TSS_FRAME_HEADROOM + 6;
struct tssp_info tssp_info = {0};
struct tss_frame_buff *tfb = NULL;
if (!payload || freq == 0)
return ret;
tss_print("Send tss req on chan %d", frequency_to_channel(freq));
tssp_info.type = TSSP_REQ;
tssp_info.is_bcast = 1;
tfb = tss_frame_alloc(payload_len + headroom, headroom);
if (!tfb){
tss_print("Alloc tss frame buff failed!");
return ret;
}
memcpy(tfb->data, payload, payload_len);
memcpy(&freq_option[2], &freq, 2);
ret = tss_send(sd, tfb, TLCP_PROTO_TSSP, &tssp_info, da, sa, freq_option, 6, 0);
tss_frame_free(tfb);
return ret;
}
static void tssc_fill_scan_list(uint16_t freq)
{
int i;
uint16_t *list = NULL;
enum tss_wifi_band band;
if (!tssc_ctx) {
return;
}
band = frequency_to_band(freq);
if (band >= BAND_MAX)
return;
list = tssc_ctx->partial_scan_list[band];
for (i = 0; i < MAX_CHANNEL_NUM; i++) {
if (list[i] == 0 || list[i] == freq)
break;
}
if (i < MAX_CHANNEL_NUM)
list[i] = freq;
return;
}
static void tssc_scan_handler(struct tss_loop_timer *timer)
{
struct tss_context *tss_ctx = tss_ctx_get();
TSS_BOOL full_scan = TSS_TRUE;
#ifdef TSS_SUPPORT_REACCESS
TSS_BOOL reaccess = TSS_FALSE;
#endif
uint8_t *tss_req_payload = NULL;
uint16_t tss_req_payload_len;
time_t now = tss_get_timestamp();
int i, j;
if (!tssc_ctx) {
return;
}
if (tssc_ctx->scan_time + TSSC_SCAN_TIMEOUT < now)
return;
/* Only certificate are present and not being updated can execute scan process */
if (!tss_ctx || !tss_ctx->inter_ca || !tss_ctx->end_ca)
goto out;
#ifdef TP_BLE
if (tss_ctx->stop_tss_scan == 1) {
tss_print("stop tss scan");
goto out;
}
#endif
/* Only IDLE and SCANNING timeout can execute scan process */
if (!(tssc_ctx->state == IDLE || (tssc_ctx->state == SCANNING && tssc_ctx->scaning_time + TSSC_SCANING_TIMEOUT < now)))
goto out;
for (i = BAND_2G; i < BAND_MAX; i++) {
/* Check scan type, full or partial */
if (tssc_ctx->partial_scan_list[i][0])
full_scan = TSS_FALSE;
#ifdef TSS_SUPPORT_REACCESS
/* Check if reaccess */
if (memcmp(tss_ctx->connected_bssid[i], zero_addr, ETH_ADDR_LEN))
reaccess = TSS_TRUE;
#endif
}
if (full_scan) {
/* The time for the next full scan was not reached */
if (tssc_ctx->full_scan_time + tssc_ctx->full_scan_interval > now)
goto out;
} else {
tssc_ctx->full_scan_interval = TSSC_FULL_SCAN_INTERVAL_MIN;
if (tssc_ctx->full_scan_remain_time < TSSC_FULL_SCAN_REMAIN_TIME)
tssc_ctx->full_scan_remain_time++;
/* A full scan is performed after successive partial scans occur */
if (tssc_ctx->full_scan_time + TSSC_FULL_SCAN_INTERVAL_MAX < now)
full_scan = TSS_TRUE;
}
tss_print("Process tss scan");
tssc_set_state(SCANNING);
if (full_scan) {
tssc_ctx->full_scan_time = now;
tssc_ctx->full_scan_interval *= 2;
if (tssc_ctx->full_scan_interval > TSSC_FULL_SCAN_INTERVAL_MAX)
tssc_ctx->full_scan_interval = TSSC_FULL_SCAN_INTERVAL_MAX;
}
for (i = BAND_2G; i < BAND_MAX; i++) {
#ifdef TSS_SUPPORT_REACCESS
if (reaccess) {
if (memcmp(tss_ctx->connected_bssid[i], zero_addr, ETH_ADDR_LEN))
tss_req_payload = tssc_build_tss_req_payload(tssc_ctx->ee, tss_ctx->connected_bssid[i], &tss_req_payload_len);
} else
tss_req_payload = tssc_build_tss_req_payload(tssc_ctx->ee, NULL, &tss_req_payload_len);
#else
tss_req_payload = tssc_build_tss_req_payload(tssc_ctx->ee, NULL, &tss_req_payload_len);
#endif
if (tss_req_payload) {
for (j = 0; j < MAX_CHANNEL_NUM; j ++) {
/* EE可能只在邻频收到了req ack,再重复几次全信道扫描确保能在主信道收到req ack */
if (full_scan || tssc_ctx->full_scan_remain_time < TSSC_FULL_SCAN_REMAIN_TIME) {
if (tssc_ctx->full_scan_list[i][j] == 0)
break;
tssc_send_tss_req(tss_ctx->socket_fd, tss_req_payload, tss_req_payload_len,
bcast_addr, tssc_ctx->ee->trans_addr[i], tssc_ctx->full_scan_list[i][j]);
} else {
if (tssc_ctx->partial_scan_list[i][j] == 0)
break;
tssc_send_tss_req(tss_ctx->socket_fd, tss_req_payload, tss_req_payload_len,
bcast_addr, tssc_ctx->ee->trans_addr[i], tssc_ctx->partial_scan_list[i][j]);
}
}
free(tss_req_payload);
tss_req_payload = NULL;
}
}
/* Clear partial scan list */
if (full_scan) {
tssc_ctx->full_scan_remain_time = 0;
memset(tssc_ctx->partial_scan_list, 0, BAND_MAX * MAX_CHANNEL_NUM * sizeof(uint16_t));
}
out:
tss_add_loop_timer(timer, TSSC_SCAN_DETECTION_INTERVAL);
return;
}
static void tssc_joining_handler(struct tss_loop_timer *timer)
{
time_t now = tss_get_timestamp();
if (!tssc_ctx) {
return;
}
if (tssc_ctx->state != CONNECTING)
return;
if (tssc_ctx->joining_time + TSSC_JOINING_TIMEOUT < now) {
tssc_set_state(IDLE);
tss_print("tssc connecting for a long time, change to IDLE");
return;
}
tss_add_loop_timer(timer, TSSC_JOINING_DETECTION_INTERVAL);
return;
}
static void tssc_handle_cmd(struct tss_command *command, uint8_t command_cnt)
{
enum tss_system_mode sysmode = 0;
uint8_t sysmode_ctype = 0;
struct tss_command *cmd = NULL;
int i = 0;
for (i = 0; i < command_cnt; i++) {
cmd = command + i;
if (!cmd)
break;
if (cmd->dtype == TSS_FORMAT_STRUCT) {
switch (cmd->format) {
case TSS_CLOUD:
tss_print("Handle cloud command");
tss_set_cloud_config(&cmd->cloud, cmd->ctype);
break;
case TSS_NETWORK:
tss_print("Handle network command");
tss_set_network_config(&cmd->net_conf, cmd->ctype);
break;
case TSS_WIRELESS_CONFIG:
tss_print("Handle wireless command");
tss_set_wireless_config(cmd->wl_conf, cmd->wl_conf_cnt, cmd->ctype);
break;
default:
tss_print("Unexpected command");
break;
}
} else if (cmd->dtype == TSS_SYSTEM_MODE) {
tss_print("Handle sysmode command");
sysmode = cmd->sysmode;
sysmode_ctype = cmd->ctype;
} else if (cmd->dtype == TSS_MESH_TYPE) {
tss_print("Handle mesh command");
tss_set_mesh_type(cmd->mesh_type, cmd->ctype);
} else if (cmd->dtype == TSS_LOCATION) {
tss_print("Handle location command");
tss_set_location(cmd->location, cmd->ctype);
} else if (cmd->dtype == TSS_TIME_ZONE) {
tss_print("Handle timezone command");
tss_set_time_zone(cmd->time_zone, cmd->ctype);
}
}
if (sysmode > 0 && sysmode_ctype > 0)
tss_set_sysmode(sysmode, sysmode_ctype);
return;
}
static TSS_STATUS tssc_tss_req_ack_handler(struct tss_frame_buff *tfb)
{
uint8_t *freq = tlcp_get_specific_option(tfb, TLCP_FREQ);
if (!freq) {
tss_print("Without frequence infomation");
return TSS_NOK;
}
tssc_fill_scan_list(*((uint16_t *)freq));
return TSS_OK;
}
static TSS_STATUS tssc_tss_resp_handler(struct tss_frame_buff *tfb)
{
struct tss_context *tss_ctx = tss_ctx_get();
struct ether_hdr *eth_h = tss_eth_get_header(tfb);
struct tss_response resp = {0};
struct tss_ecc_key_pair pair = {0};
uint8_t *freq;
TSS_STATUS ret = TSS_NOK;
#ifdef AMAZON_FFS_SUPPORT
AMAZON_FFS_ONBOARDING_MSG ffs_msg = {0};
#endif
if (!tss_ctx || !tssc_ctx)
goto out;
freq = tlcp_get_specific_option(tfb, TLCP_FREQ);
if (!freq) {
tss_print("Without frequence infomation");
goto out;
}
tssc_send_tss_resp_ack(tss_ctx->socket_fd, eth_h->src_addr, eth_h->dst_addr, *((uint16_t *)freq));
if (tssc_ctx->state >= CONNECTING)
goto out;
pair.ecc_prikey = tss_ctx->ecc_private_key;
pair.ecc_prikey_len = tss_ctx->ecc_private_key_len;
if (parse_tss_resp_data(tfb->data, tfb->data_len, &resp, &pair) == TSS_NOK || resp.cmd_cnt == 0)
goto out;
#ifdef AMAZON_FFS_SUPPORT
/* tssc执行connecting时,关闭ffs,避免冲突 */
ffs_msg.type = AMAZON_FFS_STOP;
msg_send(AMAZON_FFS_ONBOARDING_STATUS_MID, (U8 *)&ffs_msg, sizeof(ffs_msg));
#endif
tssc_set_state(CONNECTING);
tssc_handle_cmd(resp.command, resp.cmd_cnt);
ret = TSS_OK;
out:
return ret;
}
static void tssc_bss_connect_handler()
{
tssc_set_state(CONNECTED);
tss_change_role(TSS_ROLE_TSSD);
return;
}
static int tssc_bss_connect_callback(TBUS_JSON req_obj, TBUS_JSON *resp_obj)
{
tssc_bss_connect_handler();
return 0;
}
void tssc_handle_tssp(struct tss_frame_buff *tfb)
{
struct tlcp_hdr *tlcp_h = tlcp_get_header(tfb);
struct tssp_hdr *tssp_h = tssp_get_header(tfb);
uint8_t *msg;
if (!tssc_ctx)
return;
/* TLCP MSG */
if ((tlcp_h->flags & TLCP_OPTION) && (tlcp_h->total_length == 0)) {
msg = tlcp_get_specific_option(tfb, TLCP_MSG);
if (msg) {
switch (*msg) {
case TLCP_MSG_SCAN_FINISH:
tss_print("TSS Scan finish");
if (tssc_ctx->state == SCANNING)
tssc_set_state(IDLE);
break;
case TLCP_MSG_BSS_CONNECT:
tss_print("TSS bss connectd");
tssc_bss_connect_handler();
break;
default:
break;
}
}
return;
}
tssp_h = tssp_get_header(tfb);
switch (tssp_h->frame_type) {
case TSSP_REQ_ACK:
tssc_tss_req_ack_handler(tfb);
break;
case TSSP_RESP:
tssc_tss_resp_handler(tfb);
break;
default:
//tss_print("Unsupported frame type %d", tssp_h->frame_type);
break;
}
return;
}
void tssc_bind_file_changed_handler(int fd)
{
char buf[128] = {0};
/* Just clear modify event */
read(fd, buf, sizeof(buf)-1);
if (!tss_dev_is_restore_state()) {
tss_change_role(TSS_ROLE_TSSD);
}
return;
}
/*------------------------------------------------------INIT------------------------------------------*/
static void tssc_provisionee_fini(struct provisionee *ee)
{
if (!ee)
return;
free(ee);
return;
}
static struct provisionee *tssc_provisionee_init()
{
struct provisionee *ee = calloc(1, sizeof(struct provisionee));
int i = 0;
if (!ee)
return NULL;
tss_get_dev_addr(ee->addr);
for (i = BAND_2G; i < BAND_MAX; i++)
tss_get_transition_addr(i, ee->trans_addr[i]);
ee->sysmode = tss_get_sysmode_capability();
ee->cap.modem_type = tss_get_modem_type_capability();
ee->cap.mesh_type = tss_get_mesh_type_capability();
ee->cap.wl_freq = tss_get_wireless_freq_capability();
ee->cap.band = tss_get_wifi_band_capability();
ee->cap.key_type = tss_get_wifi_key_type_capability();
return ee;
}
static void tssc_ctx_fini(struct tssc_context **ctx)
{
if (ctx == NULL || *ctx == NULL)
return;
if ((*ctx)->ee)
tssc_provisionee_fini((*ctx)->ee);
if ((*ctx)->inotify_fd > 0)
tss_destroy_notify_fd((*ctx)->inotify_fd);
free(*ctx);
*ctx = NULL;
return;
}
static struct tssc_context *tssc_ctx_init()
{
struct tssc_context *ctx;
char *restore_state_file = NULL;
uint8_t trans_addr[ETH_ADDR_LEN];
int i;
ctx = calloc(1, sizeof(struct tssc_context));
if (!ctx)
return NULL;
ctx->ee = tssc_provisionee_init();
if (!ctx->ee)
goto failed;
restore_state_file = tss_get_restore_state_file();
if (restore_state_file) {
ctx->inotify_fd = tss_create_notify_fd(restore_state_file);
if (ctx->inotify_fd < 0)
goto failed;
}
for (i = BAND_2G; i < BAND_MAX; i++) {
/* Only scan bands with trans_addr configured */
if (!memcmp(ctx->ee->trans_addr[i], zero_addr, ETH_ADDR_LEN))
continue;
tss_get_channel_list(i, ctx->full_scan_list[i]);
}
ctx->state = IDLE;
ctx->scan_time = tss_get_timestamp();
ctx->full_scan_time = 0;
ctx->full_scan_interval = TSSC_FULL_SCAN_INTERVAL_MIN;
ctx->scaning_time = 0;
ctx->joining_time = 0;
return ctx;
failed:
tssc_ctx_fini(&ctx);
return NULL;
}
static void tssc_loop_fini(void)
{
tss_del_loop_timer(scan_timer);
tss_del_loop_timer(tssc_joining_timer);
if (tssc_ctx && tssc_ctx->inotify_fd > 0)
tss_del_loop_fd(inotify_fd);
return;
}
static void tssc_loop_init(struct tssc_context *ctx)
{
if (!ctx) {
return;
}
if (ctx->inotify_fd > 0)
inotify_fd = tss_loop_fd_init(ctx->inotify_fd, tssc_bind_file_changed_handler);
scan_timer = tss_loop_timer_init(ctx, tssc_scan_handler);
tssc_joining_timer = tss_loop_timer_init(ctx, tssc_joining_handler);
if (ctx->inotify_fd > 0)
tss_add_loop_fd(inotify_fd);
tss_add_loop_timer(scan_timer, TSSC_SCAN_DETECTION_INTERVAL);
return;
}
void tssc_fini()
{
tss_ubus_action_unregister(TSS_UBUS_BSS_CONNECT);
tssc_loop_fini();
tssc_ctx_fini(&tssc_ctx);
tss_print("tssc finish");
return;
}
TSS_STATUS tssc_init()
{
tssc_ctx = tssc_ctx_init();
if (!tssc_ctx) {
tss_print("Tssc context init failed");
return TSS_NOK;
}
#ifdef TSS_SUPPORT_REACCESS
/* Clear connected bssid when the device is restore state */
if (tss_dev_is_restore_state())
tss_update_connected_bssid(TSS_TRUE);
#endif
tssc_loop_init(tssc_ctx);
tss_ubus_action_register(TSS_UBUS_BSS_CONNECT, tssc_bss_connect_callback);
tss_print("tssc init");
return TSS_OK;
}
最新发布