/************************************************************
* Copyright(c) 2019-2021 TP-Link Systems Inc.
*
* file general_camera_manage.c
*
* Note
*
* author Li Xiangcun
* date 28Aug23
* history V1.0 Create file
************************************************************/
#include <sys/stat.h>
#include <sys/types.h>
#include <lib-tpcom/lib_tpcom.h>
#include "udsd.h"
#include "general_camera_manage.h"
#include "udsd_auth.h"
#include "udsd_session.h"
/**************************************************************************************************/
/* DEFINES */
/**************************************************************************************************/
#define SESSION_CLIENT_PATH "/tmp/luci-client-sessions"
#define LOGIN_RETRY_INTERVAL (3 * 1000)
#define UDSD_LOGIN_POST_CAMERA_HEAD_REQ \
"POST %s HTTP/1.1\r\n"\
"Connection: keep-alive\r\n"\
"User-Agent: Hub\r\n"\
"Content-Type: application/json\r\n"\
"Content-Length: %d\r\n"\
"\r\n"
#define UDSD_REQUEST_POST_CAMERA_HEAD_REQ \
"POST %s HTTP/1.1\r\n"\
"Connection: keep-alive\r\n"\
"User-Agent: Hub\r\n"\
"Content-Type: application/json\r\n"\
"Content-Length: %d\r\n"\
"tapo_tag: %s\r\n"\
"seq: %d\r\n"\
"\r\n"
#define UDSD_CAMERA_REQUEST_CONTENT \
"{\"method\":\"multipleRequest\", \"params\":{\"requests\":[{\"method\":\"%s\",\"params\":{\"%s\":{\"%s\":%s}}}]}}\r\n"
#ifndef MAX_24H_RECORD_NUMBER
#define MAX_24H_RECORD_NUMBER 4
#endif
/**************************************************************************************************/
/* TYPES */
/**************************************************************************************************/
typedef enum {
LOGIN_INIT = 0,
LOGIN_FIRST_POST,
LOGIN_FINISH,
} LOGIN_STATE;
struct udsd_camera_session {
struct ubus_app *app;
struct ubus_call *call;
struct tpsocket_fd *sock;
char *dev_ip;
char *method; /* method name in interface */
char *domain; /* domain name in interface */
char *req;
char *json_data; /* specific content of the request */
/* login_cnt:
* record the number of POST times when sync to camera, limited to two.
* not retry immediately if login failed to avoid entering a loop.
*/
int login_cnt;
LOGIN_STATE login_state;
bool send_req; /* if sent request already */
int response; /* response code from camera, -1:no response, 0:success, other:failed */
struct uloop_timeout retry_timer; /* if sync failed, retry later */
int retry_times; /* times of sycn retry */
struct long_conn_session *client_session;
};
/**************************************************************************************************/
/* VARIABLES */
/**************************************************************************************************/
struct list_head client_auth_info_list;
extern struct list_head g_auth_info_list;
/**************************************************************************************************/
/* FUNCTIONS */
/**************************************************************************************************/
static bool tpsocket_event_config_to_camera_secure(struct tpsocket_handler *handler, struct list_head *buf, int event);
static struct tpsocket_fd* udsd_create_session_sock(struct udsd_camera_session *session);
#ifdef PROTOCOL_SECURE
bool udsd_send_request_to_camera(struct udsd_camera_session *session, char *path);
#endif
static int mac_format_change(const char *in, char *out, int out_len, int upcase) {
/* target: AABBCCDDEEFF or aabbccddeeff */
int i = 0, j = 0, len = 0;
int need_split = 0;
len = strlen(in);
if (len == 17) {
need_split = 1;
} else if (len == 12) {
need_split = 0;
} else {
return -1;
}
for (i = 0; i < len; i++) {
if (need_split && (i + 1) % 3 == 0) {
if (in[i] == ':' || in[i] == '-') {
continue;
} else {
return -1;
}
} else if (j < out_len) {
if (in[i] >= '0' && in[i] <= '9') {
out[j++] = in[i];
} else if (in[i] >= 'A' && in[i] <= 'F') {
if (!upcase) {
out[j++] = in[i] + 'a' - 'A';
} else {
out[j++] = in[i];
}
} else if (in[i] >= 'a' && in[i] <= 'f') {
if (upcase) {
out[j++] = in[i] + 'A' - 'a';
} else {
out[j++] = in[i];
}
} else {
return -1;
}
} else {
return -1;
}
}
out[out_len - 1] = 0;
return 0;
}
static void ubus_get_general_sysinfo_cb(struct ubus_app* app, struct blob_attr *msg, int ret, void *priv)
{
struct blob_buf *bBuf = (struct blob_buf *)priv;
struct blob_attr *cur = NULL;
int rem = 0;
void *array = NULL;
if (NULL == priv) {
return;
}
if (msg) {
struct blobmsg (
blobmsg_array system,
blobmsg_int32 max_bound,
blobmsg_int32 current_bound,
blobmsg_int32 max_24h_record_dev,
blobmsg_int32 cur_24h_record_dev,
) (arg, msg, false);
if (arg.max_bound) {
blobmsg_add_u32(bBuf, "max_bound", blobmsg_get_u32(arg.max_bound));
}
if (arg.current_bound) {
blobmsg_add_u32(bBuf, "current_bound", blobmsg_get_u32(arg.current_bound));
}
if (arg.max_24h_record_dev) {
blobmsg_add_u32(bBuf, "max_24h_record_dev", blobmsg_get_u32(arg.max_24h_record_dev));
}
if (arg.cur_24h_record_dev) {
blobmsg_add_u32(bBuf, "cur_24h_record_dev", blobmsg_get_u32(arg.cur_24h_record_dev));
}
if (arg.system) {
array = blobmsg_open_array(bBuf, "paired_general_device_list");
if (array) {
blobmsg_for_each_attr(cur, arg.system, rem) {
blobmsg_add_blob(bBuf, cur);
}
blobmsg_close_array(bBuf, array);
}
}
}
return;
}
#ifdef AIENHANCE_SUPPORT
static void ubus_get_ai_result_cb(struct ubus_app * app, struct blob_attr * msg, int ret, void * priv) {
if (msg && priv) {
int *ai_hub_support = (int*)priv;
struct blobmsg (
blobmsg_table AIEnhance,
) (resp, msg, false);
if (resp.AIEnhance) {
struct blobmsg (
blobmsg_int32 AI_support,
) (info, resp.AIEnhance, false);
if (info.AI_support) {
*ai_hub_support = blobmsg_get_u32(info.AI_support);
}
}
}
}
#endif
static void ubus_get_scan_device_cb(struct ubus_app* app, struct blob_attr *msg, int ret, void *priv)
{
struct blob_buf *bBuf = (struct blob_buf *)priv;
if (NULL == priv) {
return;
}
if (msg) {
struct blobmsg (
blobmsg_bool active,
blobmsg_array general_device_list,
blobmsg_array unsupported_device_list,
) (arg, msg, false);
if (arg.active) {
blobmsg_add_string(bBuf, "scan_status", blobmsg_get_bool(arg.active) ? "scanning" : "idle");
}
if (arg.general_device_list) {
blobmsg_add_blob(bBuf, arg.general_device_list);
}
if (arg.unsupported_device_list) {
blobmsg_add_blob(bBuf, arg.unsupported_device_list);
}
}
return;
}
static void ubus_sync_AIEnhance_cb(struct ubus_app* app, struct blob_attr *msg, int ret, void *priv)
{
struct blob_buf *bBuf = (struct blob_buf *)priv;
struct blob_attr *cur = NULL;
int rem = 0;
if (NULL == priv) {
return;
}
if (msg) {
blobmsg_for_each_attr(cur, msg, rem) {
blobmsg_add_blob(bBuf, cur);
}
}
return;
}
static void udsd_camera_session_free(struct udsd_camera_session *session, bool close_sock) {
struct blob_buf b = {0};
if (!session) {
return;
}
if (close_sock && session->sock) {
session->sock->handler.priv = NULL;
tpsocket_close(session->sock);
}
if (session->method) {
free(session->method);
session->method = NULL;
}
if (session->domain) {
free(session->domain);
session->domain = NULL;
}
if (session->json_data) {
free(session->json_data);
session->json_data = NULL;
}
if (session->dev_ip) {
free(session->dev_ip);
session->dev_ip = NULL;
}
if (session->req) {
free(session->req);
session->req = NULL;
}
session->app = NULL;
if (session->call) {
blobmsg_buf_init(&b);
blobmsg_add_u32(&b, "error_code", session->response);
ubus_app_reply(session->call, b.head);
blob_buf_free(&b);
}
uloop_timeout_cancel(&session->retry_timer);
free(session);
session = NULL;
return;
}
static void udsd_retry_timeout(struct uloop_timeout *tmo) {
struct udsd_camera_session *session = container_of(tmo, struct udsd_camera_session, retry_timer);
if (session) {
session->retry_times++;
session->response = -1;
session->login_state = LOGIN_FINISH;
udsd_create_session_sock(session);
}
return;
}
static struct udsd_camera_session* udsd_camera_session_new(char *dev_ip, const char *method, const char *domain,
char *req, struct blob_attr *msg, struct ubus_app *svr_ubus_app, struct ubus_call *call)
{
struct udsd_camera_session *session = malloc(sizeof(struct udsd_camera_session));
if (!session) {
return NULL;
}
memset(session, 0, sizeof(struct udsd_camera_session));
session->app = svr_ubus_app;
session->call = call;
session->dev_ip = strdup(dev_ip);
session->method = strdup(method);
session->domain = strdup(domain);
session->req = strdup(req);
session->json_data = blobmsg_format_json(msg, true);
session->response = -1; /* no response */
session->login_state = LOGIN_FINISH; /* read token from file by default */
session->retry_timer.cb = udsd_retry_timeout;
session->client_session = NULL;
return session;
}
static void update_camera_token_file(const char *ip, const char *user_name, const char *group, const char *token) {
if (!ip || !user_name || !group || !token) {
DBG_ERR("param error\n");
return;
}
if (!is_directory(SESSION_CLIENT_PATH)) {
mkdir(SESSION_CLIENT_PATH, 0700);
}
char sess_data[SESSION_DATA_MAX_LEN + 1] = {0};
char path[PATH_MAX + 1] = {0};
snprintf(sess_data, sizeof(sess_data), "%ld %s %s %s",
get_uptime(), user_name, group, token);
snprintf(path, sizeof(path), "%s/%s", SESSION_CLIENT_PATH, ip);
DBG_DBG("path:%s\n", path);
write_file_data(path, sess_data);
return;
}
static struct tpsocket_fd* udsd_create_session_sock(struct udsd_camera_session *session) {
if (!session || !session->dev_ip || !session->dev_ip[0]) {
goto err;
}
struct tpsocket_fd *sock = NULL;
char url[128] = {0};
char file_path[PATH_MAX + 1] = {0};
int rlen = 0;
char sess_data[SESSION_DATA_MAX_LEN + 1] = {0};
char *user_name = NULL, *group = NULL, *token = NULL;
struct tpsocket_fd *client_sock = NULL;
if (session->client_session) {
client_sock = session->client_session->client_sock;
}
if (session->login_state == LOGIN_FINISH) {
/* get token from file */
snprintf(file_path, sizeof(file_path), "%s/%s", client_sock ? SESSION_PATH : SESSION_CLIENT_PATH, session->dev_ip);
rlen = read_file_data(file_path, sess_data, sizeof(sess_data));
if (rlen <= 0) {
DBG_NOTICE("do login first: %s!", session->dev_ip);
} else {
user_name = strchr(sess_data, ' ');
if (user_name) {
user_name++;
group = strchr(user_name, ' ');
}
if (group) {
group++;
token = strchr(group, ' ');
if (token) {
token++;
}
}
}
}
if (client_sock) {
DBG_NOTICE("use long conn to send request to %s\n", session->dev_ip);
if (token) {
#ifdef PROTOCOL_SECURE
snprintf(url, sizeof(url), "/stok=%s/ds", token);
session->sock = client_sock;
if (true == udsd_send_request_to_camera(session, url)) {
DBG_NOTICE("success to send request through long conn\n");
udsd_camera_session_free(session, false);
return client_sock;
}
#endif
} else {
DBG_ERR("get no token of long conn\n");
}
DBG_ERR("fail to send request through long conn and close socket\n");
long_session_free(session->client_session);
session->client_session = NULL;
if (session->login_state == LOGIN_FINISH) {
session->login_state = LOGIN_INIT;
}
snprintf(url, sizeof(url), "https://%s:443", session->dev_ip);
} else {
DBG_NOTICE("use short conn to send request to %s\n", session->dev_ip);
if (token) {
snprintf(url, sizeof(url), "https://%s:443/stok=%s/ds", session->dev_ip, token);
} else {
if (session->login_state == LOGIN_FINISH) {
session->login_state = LOGIN_INIT;
}
snprintf(url, sizeof(url), "https://%s:443", session->dev_ip);
}
}
struct tpsocket_handler config_to_camera = {
.cb = tpsocket_event_config_to_camera_secure,
.timeout = 3000,
};
DBG_DBG("short conn url:%s\n", url);
if (!(sock = tpsocket_from_url(url, &config_to_camera))) {
goto err;
}
sock->handler.priv = session;
session->response = -1;
session->sock = sock;
return sock;
err:
udsd_camera_session_free(session, true);
return NULL;
}
int udsd_connect_camera(char *dev_ip, const char *method, const char *domain, char *req, struct blob_attr *msg, struct long_conn_session *client_session,
struct ubus_app *svr_ubus_app, struct ubus_call *call) {
if (!dev_ip || !dev_ip[0] || !method || !domain || !req) {
DBG_ERR("dev ip null\n");
return -1;
}
struct udsd_camera_session *session = NULL;
session = udsd_camera_session_new(dev_ip, method, domain, req, msg, svr_ubus_app, call);
if (!session) {
DBG_ERR("create session error\n");
return -1;
}
session->client_session = client_session;
if (NULL == udsd_create_session_sock(session)) {
DBG_ERR("create session socket error\n");
return -1;
}
return 0;
}
#ifdef PROTOCOL_SECURE
int init_secure_client_auth_info()
{
INIT_LIST_HEAD(&client_auth_info_list);
return 0;
}
static struct auth_info_list_t *get_client_auth_info(char *ip, int long_conn) {
struct auth_info_list_t *auth_info = NULL, *n_auth_info = NULL, *rtn_auth_info = NULL;
struct list_head *auth_info_list = long_conn ? (&g_auth_info_list) : (&client_auth_info_list);
long cur_time = get_uptime();
if (!ip || !ip[0]) {
return NULL;
}
list_for_each_entry_safe(auth_info, n_auth_info, auth_info_list, list) {
if (!strncmp(ip, auth_info->ip, sizeof(auth_info->ip)) &&
((auth_info->login_success == 0 && cur_time - auth_info->time <= SESSION_TOKEN_UPDATE)
|| (auth_info->login_success == 1 && cur_time - auth_info->time <= (long_conn ? SESSION_TOKEN_LONG_TIMEOUT : SESSION_TOKEN_TIMEOUT)))) {
if (auth_info->login_success == 0) {
auth_info->time = cur_time;
}
DBG_NOTICE("find authinfo, login_success:%d, time:%ld, now time:%ld\n", auth_info->login_success, auth_info->time, cur_time);
rtn_auth_info = auth_info;
}
if ((auth_info->login_success == 0 && cur_time - auth_info->time > SESSION_TOKEN_UPDATE)
|| (auth_info->login_success == 1 && cur_time - auth_info->time > (long_conn ? SESSION_TOKEN_LONG_TIMEOUT : SESSION_TOKEN_TIMEOUT))) {
if (rtn_auth_info == auth_info) {
rtn_auth_info = NULL;
}
DBG_DBG("delete auth info of host:%s\n", auth_info->ip);
uloop_timeout_cancel(&auth_info->seq_timeout);
list_del(&auth_info->list);
free(auth_info);
}
}
return rtn_auth_info;
}
static bool update_client_auth_info(char *ip, char *nonce, char *cnonce, unsigned char *lsk, unsigned char *ivb, int seq, bool login_success) {
struct auth_info_list_t *auth_info = NULL, *n_auth_info = NULL;
long cur_time = get_uptime();
int matched = 0;
if (!ip || !ip[0]) {
return false;
}
list_for_each_entry_safe(auth_info, n_auth_info, &client_auth_info_list, list) {
if (!strncmp(ip, auth_info->ip, sizeof(auth_info->ip))) {
matched = 1;
auth_info->time = cur_time;
if (login_success) {
auth_info->login_success = 1;
} else {
auth_info->login_success = 0;
}
if (nonce && nonce[0]) {
memcpy(auth_info->nonce, nonce, sizeof(auth_info->nonce) - 1);
}
if (cnonce && cnonce[0]) {
memcpy(auth_info->cnonce, cnonce, sizeof(auth_info->cnonce) - 1);
}
if (lsk) {
memcpy(auth_info->aes_lsk, lsk, sizeof(auth_info->aes_lsk));
}
if (ivb) {
memcpy(auth_info->aes_ivb, ivb, sizeof(auth_info->aes_ivb));
}
if (seq >= 0) {
auth_info->last_seq = seq;
}
}
if ((auth_info->login_success == 0 && cur_time - auth_info->time > SESSION_TOKEN_UPDATE)
|| (auth_info->login_success == 1 && cur_time - auth_info->time > SESSION_TOKEN_TIMEOUT)) {
DBG_DBG("delete auth info of host:%s\n", auth_info->ip);
uloop_timeout_cancel(&auth_info->seq_timeout);
list_del(&auth_info->list);
free(auth_info);
}
}
if (!matched && cnonce) {
auth_info = (struct auth_info_list_t *)malloc(sizeof(struct auth_info_list_t));
if (!auth_info) {
return false;
}
memset(auth_info, 0, sizeof(struct auth_info_list_t));
memcpy(auth_info->ip, ip, sizeof(auth_info->ip) - 1);
memcpy(auth_info->cnonce, cnonce, sizeof(auth_info->cnonce) - 1);
auth_info->time = cur_time;
auth_info->login_success = 0;
INIT_LIST_HEAD(&auth_info->list);
list_add_tail(&auth_info->list, &client_auth_info_list);
DBG_DBG("auth info not match, add host:%s\n", auth_info->ip);
}
return true;
}
/* protocol secure first login */
static bool udsd_secure_login_first_post(struct tpsocket_fd *sock) {
struct tpsocket_buf *pbuf = NULL, *nbuf = NULL;
char *post_json = NULL;
int content_len = 0;
struct list_head head;
INIT_LIST_HEAD(&head);
struct blob_buf b = {NULL}, b1 = {NULL};
void *table = NULL;
char cnonce[ENCRYPT_NONCE_LEN_16 + 1] = {0};
char *user = NULL;
/* build json */
blobmsg_buf_init(&b);
blobmsg_add_string(&b, "method", "login");
table = blobmsg_open_table(&b, "params");
if (table) {
blobmsg_buf_init(&b1);
user = blobuci_get(account, account, user, blobmsg_get_string, &b1);
if (user) {
blobmsg_add_string(&b, "username", user);
}
blob_buf_free(&b1);
blobmsg_add_string(&b, "encrypt_type", "3");
/* generate cnonce */
get_random_nonce(ENCRYPT_NONCE_LEN_16, cnonce);
cnonce[ENCRYPT_NONCE_LEN_16] = '\0';
blobmsg_add_string(&b, "cnonce", cnonce);
blobmsg_close_table(&b, table);
}
post_json = blobmsg_format_json(b.head, true);
nbuf = tpbuf_snprintf(1024, "%s\r\n", post_json);
content_len = tpbuf_data_len(nbuf);
if (post_json) {
free(post_json);
}
blob_buf_free(&b);
/* build head */
pbuf = tpbuf_snprintf(512, UDSD_LOGIN_POST_CAMERA_HEAD_REQ, "/", content_len);
list_add_tail(&pbuf->list, &head);
list_add_tail(&nbuf->list, &head);
if (false == tpsocket_write_list_force(sock, &head, false)) {
tpsocket_free_buf(&head, NULL, 0);
return false;
}
/* update auth info list */
update_client_auth_info(sock->addr, NULL, cnonce, NULL, NULL, -1, false);
return true;
}
/* protocol secure second login */
static bool udsd_secure_login_second_post(struct tpsocket_fd *sock) {
struct tpsocket_buf *pbuf = NULL, *nbuf = NULL;
char *post_json = NULL;
int content_len = 0;
struct list_head head;
INIT_LIST_HEAD(&head);
struct blob_buf b = {NULL}, b1 = {NULL};
void *table = NULL;
struct auth_info_list_t *auth_info = NULL;
char *user = NULL;
char *config_passwd = NULL;
char app_confirm[CONFIRM_LEN + 1] = {0};
unsigned char aes_lsk[AES_KEY_LEN] = {0};
unsigned char aes_ivb[AES_KEY_LEN] = {0};
/* build json */
blobmsg_buf_init(&b);
blobmsg_add_string(&b, "method", "login");
table = blobmsg_open_table(&b, "params");
if (table) {
blobmsg_buf_init(&b1);
user = blobuci_get(account, account, user, blobmsg_get_string, &b1);
if (user) {
blobmsg_add_string(&b, "username", user);
}
blob_buf_free(&b1);
blobmsg_add_string(&b, "encrypt_type", "3");
auth_info = get_client_auth_info(sock->addr, 0);
if (auth_info) {
/* generate digest_password */
blobmsg_buf_init(&b1);
config_passwd = blobuci_get(account, account, general_password, blobmsg_get_string, &b1);
cal_app_confirm((char *)auth_info->cnonce, (char *)auth_info->nonce, config_passwd, app_confirm, sizeof(app_confirm));
blob_buf_free(&b1);
blobmsg_add_string(&b, "cnonce", (char *)auth_info->cnonce);
blobmsg_add_string(&b, "digest_passwd", app_confirm);
}
blobmsg_close_table(&b, table);
}
post_json = blobmsg_format_json(b.head, true);
nbuf = tpbuf_snprintf(1024, "%s\r\n", post_json);
content_len = tpbuf_data_len(nbuf);
if (post_json) {
free(post_json);
}
blob_buf_free(&b);
/* build head */
pbuf = tpbuf_snprintf(512, UDSD_LOGIN_POST_CAMERA_HEAD_REQ, "/", content_len);
list_add_tail(&pbuf->list, &head);
list_add_tail(&nbuf->list, &head);
if (false == tpsocket_write_list_force(sock, &head, false)) {
tpsocket_free_buf(&head, NULL, 0);
return false;
}
/* update lsk ivb of auth info list */
if (auth_info) {
cal_aes_lsk_ivb(config_passwd, (char *)auth_info->nonce, (char *)auth_info->cnonce, aes_lsk, aes_ivb);
update_client_auth_info(sock->addr, NULL, NULL, aes_lsk, aes_ivb, -1, false);
}
return true;
}
bool udsd_send_request_to_camera(struct udsd_camera_session *session, char *path) {
struct auth_info_list_t *auth_info = NULL;
unsigned char *content = NULL;
int content_len = 0;
int enc_len = 0, buf_size = 0;
unsigned char *base64_req = NULL;
int nbuf_len = 0;
char tapo_tag[256] = {0};
char *config_passwd = NULL;
struct list_head head;
INIT_LIST_HEAD(&head);
struct tpsocket_buf *nbuf = NULL, *pbuf = NULL;
struct blob_buf b_tmp = {NULL};
char aes_lsk[AES_KEY_LEN] = {0};
char aes_ivb[AES_KEY_LEN] = {0};
int long_conn = 0;
if (!session || !session->sock) {
DBG_ERR("session or sock NULL\n");
return false;
}
if (session->client_session && session->client_session->client_sock) {
DBG_NOTICE("use long conn to send\n");
long_conn = 1;
}
session->send_req = true;
auth_info = get_client_auth_info(session->sock->addr, long_conn);
if (!auth_info) {
DBG_NOTICE("no auth_info, need login to %s\n", session->sock->addr);
session->response = SLP_EUNAUTH;
return false;
}
content_len = strlen(session->json_data) + 1024;
content = malloc(content_len);
if (!content) {
DBG_ERR("malloc content %d failed\n", content_len);
return false;
}
memset(content, 0, content_len);
snprintf((char *)content, content_len, UDSD_CAMERA_REQUEST_CONTENT, session->method, session->domain, session->req, session->json_data);
DBG_DBG("send %s length %d, content length %d\n", session->method, strlen((char *)content), content_len);
/* aes encrypt */
memcpy(aes_lsk, auth_info->aes_lsk, AES_KEY_LEN);
memcpy(aes_ivb, auth_info->aes_ivb, AES_KEY_LEN);
enc_len = aes_cbc_128_encrypt(content, strlen((char *)content), content, strlen((char *)content) + 16, (unsigned char *)aes_lsk, (unsigned char *)aes_ivb);
/* base64 encode */
buf_size = (enc_len + 2) / 3 * 4 + 1;
base64_req = (unsigned char *)malloc(buf_size);
if (base64_req) {
memset(base64_req, 0, buf_size);
enc_len = tpsocket_base64_encode(content, enc_len, base64_req);
buf_size = enc_len + 128;
nbuf = tpbuf_snprintf(buf_size, "{\"method\":\"securePassthrough\",\"params\":{\"request\":\"%s\"}}", base64_req);
nbuf_len = tpbuf_data_len(nbuf);
auth_info->last_seq++;
free(base64_req);
}
/* build head */
if (nbuf) {
blobmsg_buf_init(&b_tmp);
config_passwd = blobuci_get(account, account, general_password, blobmsg_get_string, &b_tmp);
cal_tapo_tag(config_passwd, auth_info->cnonce, tpbuf_data(nbuf), auth_info->last_seq, tapo_tag, sizeof(tapo_tag));
pbuf = tpbuf_snprintf(512, UDSD_REQUEST_POST_CAMERA_HEAD_REQ, path ? path : "/", nbuf_len, tapo_tag, auth_info->last_seq);
blob_buf_free(&b_tmp);
list_add_tail(&pbuf->list, &head);
list_add_tail(&nbuf->list, &head);
}
if (content) {
free(content);
}
if (false == tpsocket_write_list_force(session->sock, &head, false)) {
tpsocket_free_buf(&head, NULL, 0);
return false;
}
return true;
}
#endif
static bool tpsocket_event_config_to_camera_secure(struct tpsocket_handler *handler, struct list_head *buf, int event) {
struct tpsocket_fd *sock = container_of(handler, struct tpsocket_fd, handler);
struct udsd_camera_session *session = NULL;
if (sock) {
session = (struct udsd_camera_session *)sock->handler.priv;
}
int err_code = -1;
struct tpsocket_buf *nbuf = NULL;
struct blob_buf b = {NULL}, b_tmp = {NULL};
char *pstr = NULL;
DBG_DBG("socket event = %s\n", tpsocket_event_name(event));
#ifdef PROTOCOL_SECURE
switch (event) {
case TPSOCKET_EVENT_CONNECTED:
if (session) {
if (LOGIN_INIT == session->login_state) {
if (false == udsd_secure_login_first_post(sock)) {
tpsocket_free_buf(buf, tpsocket_event_name(event), 0);
return false;
}
session->login_cnt++;
} else if (LOGIN_FIRST_POST == session->login_state) {
if (false == udsd_secure_login_second_post(sock)) {
tpsocket_free_buf(buf, tpsocket_event_name(event), 0);
return false;
}
session->login_cnt++;
} else {
/* finish login and send request to camera */
if (false == udsd_send_request_to_camera(session, sock->path)) {
tpsocket_free_buf(buf, tpsocket_event_name(event), 0);
return false;
}
}
}
tpsocket_set_timeout(sock, 3000);
break;
case TPSOCKET_EVENT_RSP_HEAD:
return true;
case TPSOCKET_EVENT_STREAM:
return true;
case TPSOCKET_EVENT_MESSAGE:
nbuf = tpsocket_merge_buf(buf);
blobmsg_buf_init(&b);
blobmsg_buf_init(&b_tmp);
if (!nbuf || !session) {
goto end;
}
pstr = strstr(tpbuf_data(nbuf), "{");
if (!pstr) {
goto end;
}
if (blobmsg_add_json_from_string(&b, pstr)) {
struct blobmsg (
blobmsg_int32 error_code,
blobmsg_table result,
) (resp, &b);
if (!resp.error_code) {
goto end;
}
err_code = blobmsg_get_u32(resp.error_code);
session->response = err_code;
if (!resp.result) {
DBG_DBG("response no result and not parse\n");
goto end;
}
if (session->login_state == LOGIN_INIT) {
char device_confirm[CONFIRM_LEN + 1] = {0};
char *nonce = NULL;
struct auth_info_list_t *auth_info = NULL;
char *config_passwd = NULL;
struct blobmsg (
blobmsg_table data,
) (res, resp.result, false);
if (res.data) {
struct blobmsg (
blobmsg_string nonce,
blobmsg_string device_confirm,
) (data, res.data, false);
if (!data.nonce || !data.device_confirm) {
DBG_ERR("param error\n");
goto end;
}
nonce = blobmsg_get_string(data.nonce);
update_client_auth_info(sock->addr, nonce, NULL, NULL, NULL, -1, false);
auth_info = get_client_auth_info(sock->addr, 0);
config_passwd = blobuci_get(account, account, general_password, blobmsg_get_string, &b_tmp);
if (!config_passwd) {
DBG_ERR("no general password\n");
goto end;
}
if (auth_info) {
cal_device_confirm((char *)auth_info->cnonce, (char *)auth_info->nonce, config_passwd, device_confirm, sizeof(device_confirm));
/* check device confirm */
if (!strncmp(device_confirm, blobmsg_get_string(data.device_confirm), sizeof(device_confirm) - 1)) {
session->login_state = LOGIN_FIRST_POST;
} else {
DBG_ERR("device confirm failed,cnonce:%s, nonce:%s\nget:%s\ncal:%s\n",
auth_info->cnonce, auth_info->nonce, blobmsg_get_string(data.device_confirm), device_confirm);
}
}
}
} else if (session->login_state == LOGIN_FIRST_POST) {
struct blobmsg (
blobmsg_string stok,
blobmsg_string user_group,
blobmsg_int32 start_seq,
) (res, resp.result, false);
if (res.stok && res.user_group && res.start_seq) {
update_client_auth_info(sock->addr, NULL, NULL, NULL, NULL, blobmsg_get_u32(res.start_seq), true);
session->login_state = LOGIN_FINISH;
update_camera_token_file(sock->addr, "admin", blobmsg_get_string(res.user_group), blobmsg_get_string(res.stok));
}
}
}
end:
blob_buf_free(&b_tmp);
blob_buf_free(&b);
tpsocket_close(sock);
break;
case TPSOCKET_EVENT_TIMEOUT:
break;
case TPSOCKET_EVENT_ERROR:
break;
case TPSOCKET_EVENT_CLOSED:
if (session) {
session->sock = NULL;
sock->handler.priv = NULL;
DBG_DBG("resp code:%d, login state:%d, login_cnt:%d\n", session->response, session->login_state, session->login_cnt);
if (session->response == -1) {
DBG_ERR("connect to camera failed or get no response, current retry times:%d\n", session->retry_times);
if (0 == session->retry_times) {
/* retry later */
uloop_timeout_set(&session->retry_timer, LOGIN_RETRY_INTERVAL);
} else {
udsd_camera_session_free(session, true);
}
break;
}
if (LOGIN_INIT == session->login_state) {
DBG_ERR("login %s failed\n", sock->addr);
if (0 == session->retry_times) {
/* retry later */
uloop_timeout_set(&session->retry_timer, LOGIN_RETRY_INTERVAL);
} else {
udsd_camera_session_free(session, true);
}
} else if (LOGIN_FIRST_POST == session->login_state) {
if (session->login_cnt < 2) {
DBG_DBG("next login second step");
udsd_create_session_sock(session);
} else {
DBG_ERR("login %s failed\n", sock->addr);
if (0 == session->retry_times) {
/* retry later */
uloop_timeout_set(&session->retry_timer, LOGIN_RETRY_INTERVAL);
} else {
udsd_camera_session_free(session, true);
}
}
} else {
if (session->send_req) {
/* get wrong response and restart login */
if (session->response != 0 && session->login_cnt <= 2) {
DBG_DBG("restart login\n");
session->login_state = LOGIN_INIT;
session->send_req = false;
udsd_create_session_sock(session);
} else {
udsd_camera_session_free(session, true);
}
} else {
udsd_create_session_sock(session);
}
}
}
break;
default:
break;
}
#endif
tpsocket_free_buf(buf, tpsocket_event_name(event), 0);
return true;
}
static void ubus_get_storage_media_status_cb(struct ubus_app *app, struct blob_attr *msg, int ret, void *priv) {
if (!msg || !priv) {
DBG_ERR("param error, ret %d\n", ret);
return;
}
int *storage_media_status = (int *)priv;
struct blobmsg (
blobmsg_int32 storage_media_status,
) (resp, msg, false);
if (resp.storage_media_status) {
*storage_media_status = blobmsg_get_u32(resp.storage_media_status);
}
}
static void udsd_get_general_device_list(struct ubus_app *svr_ubus_app, struct blob_buf* bBuf, struct blob_attr *msg, int *error_code)
{
struct blob_buf b_res = {0}, b = {0};
struct blob_attr *cur = NULL;
int rem = 0;
void *array = NULL;
void *table = NULL;
void *domain = NULL;
int ai_hub_support = 0;
int wifi_backup_enabled = 0;
int hub_storage_enabled = 0;
if (!bBuf || !error_code || !msg) {
DBG_ERR("arg err\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
domain = blobmsg_open_table(bBuf, "general_camera_manage");
if (domain) {
blobmsg_buf_init(&b_res);
ubus_app_invoke(svr_ubus_app, "devmgr", "get_general_sysinfo", NULL, 10000, ubus_get_general_sysinfo_cb, &b_res);
struct blobmsg (
blobmsg_int32 max_bound,
blobmsg_int32 current_bound,
blobmsg_int32 max_24h_record_dev,
blobmsg_int32 cur_24h_record_dev,
blobmsg_array paired_general_device_list,
) (list, &b_res);
if (list.max_bound) {
blobmsg_add_blob(bBuf, list.max_bound);
}
if (list.current_bound) {
blobmsg_add_blob(bBuf, list.current_bound);
}
if (list.max_24h_record_dev) {
blobmsg_add_blob(bBuf, list.max_24h_record_dev);
}
if (list.cur_24h_record_dev) {
blobmsg_add_blob(bBuf, list.cur_24h_record_dev);
}
array = blobmsg_open_array(bBuf, "paired_general_device_list");
if (array) {
if (list.paired_general_device_list) {
blobmsg_for_each_attr(cur, list.paired_general_device_list, rem) {
struct blobmsg (
blobmsg_string model, //change key
blobmsg_string type, //change key
blobmsg_string ipaddr, //not return to app
blobmsg_string alias,
blobmsg_string mac,
blobmsg_string device_id,
blobmsg_string network_mode,
blobmsg_bool wifi_backup_enabled,
blobmsg_string backup_wifi,
blobmsg_bool hub_storage_enabled,
blobmsg_int32 ai_camera_support,
blobmsg_int32 ai_enhance,
blobmsg_bool AI_enhance_enabled,
blobmsg_bool plan_24h_record,
) (info, cur, false);
if (info.wifi_backup_enabled) {
wifi_backup_enabled = blobmsg_get_bool(info.wifi_backup_enabled);
} else {
wifi_backup_enabled = 0;
}
if (info.hub_storage_enabled) {
hub_storage_enabled = blobmsg_get_bool(info.hub_storage_enabled);
} else {
hub_storage_enabled = 0;
}
if (!wifi_backup_enabled && !hub_storage_enabled) {
continue;
}
table = blobmsg_open_table(bBuf, "");
if (table) {
if (info.alias) {
blobmsg_add_blob(bBuf, info.alias);
}
if (info.mac) {
blobmsg_add_blob(bBuf, info.mac);
}
if (info.device_id) {
blobmsg_add_blob(bBuf, info.device_id);
}
if (info.network_mode) {
blobmsg_add_blob(bBuf, info.network_mode);
}
blobmsg_add_u8(bBuf, "wifi_backup_enabled", wifi_backup_enabled);
if (info.backup_wifi) {
blobmsg_add_blob(bBuf, info.backup_wifi);
}
blobmsg_add_u8(bBuf, "hub_storage_enabled", hub_storage_enabled);
if (info.plan_24h_record) {
blobmsg_add_blob(bBuf, info.plan_24h_record);
}
if (info.ai_camera_support) {
blobmsg_add_blob(bBuf, info.ai_camera_support);
}
if (info.ai_enhance) {
blobmsg_add_blob(bBuf, info.ai_enhance);
}
if (info.AI_enhance_enabled) {
blobmsg_add_blob(bBuf, info.AI_enhance_enabled);
}
blobmsg_buf_init(&b);
if (blobuci_load_state(&b, "system", "/var/state/")) {
struct blobmsg (
blobmsg_section firm,
) (sys, &b);
if (sys.firm) {
struct blobmsg (
blobmsg_option DEV_ID,
) (firm, sys.firm, false);
if (firm.DEV_ID) {
blobmsg_add_string(bBuf, "parent_device_id", blobmsg_get_string(firm.DEV_ID));
}
}
}
blob_buf_free(&b);
if (info.model) {
blobmsg_add_string(bBuf, "device_model", blobmsg_get_string(info.model));
}
if (info.type) {
/* "SMART.IPBATTERYCAMERA" is only for hub to send tddp packet to 20004(battery camera) or 20002.
* it need be converted to "SMART.IPCAMERA" for APP.
*/
if (!strncmp(blobmsg_get_string(info.type), "SMART.IPBATTERYCAMERA", strlen("SMART.IPBATTERYCAMERA"))) {
blobmsg_add_string(bBuf, "device_type", "SMART.IPCAMERA");
} else {
blobmsg_add_string(bBuf, "device_type", blobmsg_get_string(info.type));
}
}
blobmsg_add_string(bBuf, "category", "camera");
#ifdef AIENHANCE_SUPPORT
ubus_app_invoke(svr_ubus_app, "devmgr", "get_AIEnhance_info", NULL, 3000, ubus_get_ai_result_cb, &ai_hub_support);
#endif
blobmsg_add_u32(bBuf, "ai_hub_support", ai_hub_support);
blobmsg_close_table(bBuf, table);
}
}
}
blobmsg_close_array(bBuf, array);
}
blob_buf_free(&b_res);
blobmsg_close_table(bBuf, domain);
}
*error_code = SLP_ENONE;
return;
}
static int udsd_add_general_device(struct ubus_app *svr_ubus_app, struct blob_attr *attr, struct blob_buf *out) {
struct blob_buf b = {0};
void *table = NULL, *table1 = NULL, *table2 = NULL;
struct blob_attr *cur = NULL;
int rem = 0;
int err = 0;
char mac_str[MAC_STR_LEN + 1] = {0};
int ai_hub_support = 0;
int storage_media_status = 0;
ubus_app_invoke(svr_ubus_app, "mediacenter", "storage_get_storage_media_status", NULL, 3000, ubus_get_storage_media_status_cb, &storage_media_status);
struct blobmsg (
blobmsg_string network_mode,
blobmsg_string auth_type,
blobmsg_string ai_camera_support,
blobmsg_string resolution,
blobmsg_int32 storage_schedule_status,
blobmsg_string hub_storage_enabled,
blobmsg_string wifi_backup_enabled,
blobmsg_string backup,
) (info, attr, false);
blobmsg_buf_init(&b);
table = blobmsg_open_table(&b, "device_info");
if (table) {
blobmsg_for_each_attr(cur, attr, rem) {
blobmsg_add_blob(&b, cur);
}
blobmsg_add_u32(&b, "storage_media_status", storage_media_status);
blobmsg_close_table(&b, table);
}
table = blobmsg_open_table(&b, "config");
if (table) {
if ((table1 = blobmsg_open_table(&b, "device_info"))) {
if ((table2 = blobmsg_open_table(&b, "basic_info"))) {
if (info.network_mode) {
blobmsg_add_string(&b, "network_mode", blobmsg_get_string(info.network_mode));
} else {
blobmsg_add_string(&b, "network_mode", "NONE");
}
if (info.auth_type) {
blobmsg_add_string(&b, "auth_type", blobmsg_get_string(info.auth_type));
} else {
blobmsg_add_string(&b, "auth_type", "NONE");
}
blobmsg_close_table(&b, table2);
}
if ((table2 = blobmsg_open_table(&b, "wifi_backup"))) {
if (info.wifi_backup_enabled) {
if (!strncmp(blobmsg_get_string(info.wifi_backup_enabled), "on", strlen("on"))) {
blobmsg_add_u32(&b, "enable", 1);
} else {
blobmsg_add_u32(&b, "enable", 0);
}
}
if (info.backup) {
blobmsg_add_string(&b, "backup_wifi", blobmsg_get_string(info.backup));
}
blobmsg_close_table(&b, table2);
}
blobmsg_close_table(&b, table1);
}
if ((table1 = blobmsg_open_table(&b, "hub_storage"))) {
if ((table2 = blobmsg_open_table(&b, "storage_info"))) {
if (info.resolution) {
blobmsg_add_blob(&b, info.resolution);
}
if (info.storage_schedule_status) {
blobmsg_add_blob(&b, info.storage_schedule_status);
}
if (info.hub_storage_enabled) {
if (!strncmp(blobmsg_get_string(info.hub_storage_enabled), "on", strlen("on"))) {
blobmsg_add_u32(&b, "enable", 1);
} else {
blobmsg_add_u32(&b, "enable", 0);
}
}
blobmsg_add_u32(&b, "storage_media_status", storage_media_status);
blobmsg_close_table(&b, table2);
}
blobmsg_close_table(&b, table1);
}
/* not generate AIEnhance config until call setAIEnhanceConfig */
blobmsg_close_table(&b, table);
}
/* send cam info to devmgr */
ubus_app_invoke(svr_ubus_app, "devmgr", "dev_add_general", b.head, 0, NULL, NULL);
/* return info */
blobmsg_buf_init(&b);
if (blobuci_load_state(&b, "system", "/var/state/")) {
struct blobmsg (
blobmsg_section firm,
) (sys, &b);
if (sys.firm) {
struct blobmsg (
blobmsg_option REGION, //US
blobmsg_option MAC, //28-87-BA-9A-3D-4F
blobmsg_option DEV_ID,
blobmsg_option MODEL, //H200
blobmsg_option ALIAS,
blobmsg_option CATEGORY,//SMART.TAPOHUB
) (firm, sys.firm, false);
if (firm.MAC) {
if (!mac_format_change(blobmsg_get_string(firm.MAC), mac_str, sizeof(mac_str), true)) {
blobmsg_add_string(out, "mac", mac_str);
}
}
if (firm.DEV_ID) {
blobmsg_add_string(out, "device_id", blobmsg_get_string(firm.DEV_ID));
}
if (firm.MODEL) {
blobmsg_add_string(out, "model", blobmsg_get_string(firm.MODEL));
}
if (firm.ALIAS) {
blobmsg_add_string(out, "alias", blobmsg_get_string(firm.ALIAS));
}
if (firm.CATEGORY) {
blobmsg_add_string(out, "type", blobmsg_get_string(firm.CATEGORY));
}
}
}
blobmsg_buf_init(&b);
if (blobuci_load(&b, "network")) {
struct blobmsg (
blobmsg_section wan,
) (data, &b);
if (data.wan) {
struct blobmsg (
blobmsg_option ipaddr,
) (wan, data.wan, false);
if (wan.ipaddr) {
blobmsg_add_string(out, "ipaddr", blobmsg_get_string(wan.ipaddr));
}
}
}
/* return general password */
blobmsg_buf_init(&b);
if (blobuci_load(&b, "account")) {
struct blobmsg (
blobmsg_section account,
) (account, &b);
if (account.account) {
struct blobmsg (
blobmsg_option general_password,
blobmsg_option tddp_hub_id,
) (auth, account.account, false);
if (auth.general_password) {
blobmsg_add_string(out, "general_password", blobmsg_get_string(auth.general_password));
}
if (auth.tddp_hub_id) {
blobmsg_add_string(out, "hub_id", blobmsg_get_string(auth.tddp_hub_id));
}
}
}
blob_buf_free(&b);
/* auth type: todo */
blobmsg_add_string(out, "auth_type", "3");
/* ai enhance */
#ifdef AIENHANCE_SUPPORT
ubus_app_invoke(svr_ubus_app, "devmgr", "get_AIEnhance_info", NULL, 3000, ubus_get_ai_result_cb, &ai_hub_support);
#endif
blobmsg_add_u32(out, "ai_hub_support", ai_hub_support);
/* storage status */
blobmsg_add_u32(out, "storage_media_status", storage_media_status);
return err;
}
static void udsd_wifi_backup_info_request(struct ubus_app *svr_ubus_app, struct blob_buf *bBuf, struct blob_attr *msg, int *error_code) {
struct blob_buf b = {0};
void *table = NULL, *table1 = NULL, *domain = NULL;
char bssid[MAC_STR_LEN + 1] = {0};
#ifndef HARDDISK_STORAGE
char mac_data[18] = {0};
char mac_ra0[18] = {0};
int data_len = 0;
#endif
struct blob_attr *cur = NULL;
int rem = 0;
char *enabled = NULL;
*error_code = SLP_ENONE;
if (!bBuf || !error_code || !msg) {
DBG_ERR("arg err\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
struct blobmsg (
blobmsg_table backup_wifi_info,
) (arg, msg, false);
if (!arg.backup_wifi_info) {
DBG_ERR("arg err\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
struct blobmsg (
blobmsg_string mac,
blobmsg_string enabled,
blobmsg_string backup,
blobmsg_string dport,
blobmsg_table basic_info,
) (info, arg.backup_wifi_info, false);
if (!info.mac || !info.enabled) {
DBG_ERR("arg err\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
domain = blobmsg_open_table(bBuf, "general_camera_manage");
if (!domain) {
DBG_ERR("open table error\n");
*error_code = SLP_ESYSTEM;
return;
}
table = blobmsg_open_table(bBuf, "backup_wifi_info");
if (!table) {
DBG_ERR("open table error\n");
*error_code = SLP_ESYSTEM;
return;
}
blobmsg_buf_init(&b);
if (blobuci_load(&b, "wireless")) {
#ifdef HARDDISK_STORAGE
struct blobmsg (
blobmsg_section wifi_backup,
) (data, &b);
if (data.wifi_backup) {
struct blobmsg (
blobmsg_option ssid,
blobmsg_option psk,
blobmsg_option bssid,
) (wifi_backup, data.wifi_backup, false);
if (!wifi_backup.ssid || !wifi_backup.psk || !wifi_backup.bssid) {
DBG_ERR("params NULL\n");
*error_code = IPC_INTF_PARA_ERR;;
blobmsg_close_table(bBuf, table);
blob_buf_free(&b);
return;
}
blobmsg_add_string(bBuf, "ssid", blobmsg_get_string(wifi_backup.ssid));
blobmsg_add_string(bBuf, "password", blobmsg_get_string(wifi_backup.psk));
mac_format_change(blobmsg_get_string(wifi_backup.bssid), bssid, sizeof(bssid), true);
blobmsg_add_string(bBuf, "bssid", bssid);
}
#else
struct blobmsg (
blobmsg_section ra1,
) (data, &b);
if (data.ra1) {
struct blobmsg (
blobmsg_option ssid,
blobmsg_option psk_key,
) (ra1, data.ra1, false);
if (!ra1.ssid || !ra1.psk_key) {
DBG_ERR("param error\n");
*error_code =IPC_INTF_PARA_ERR;
blobmsg_close_table(bBuf, table);
blob_buf_free(&b);
return;
}
blobmsg_add_string(bBuf, "ssid", blobmsg_get_string(ra1.ssid));
blobmsg_add_string(bBuf, "password", blobmsg_get_string(ra1.psk_key));
}
/* get bssid */
read_file_data("/sys/class/net/ra0/address", mac_ra0, sizeof(mac_ra0) - 1);
data_len = read_file_data("/sys/class/net/ra1/address", mac_data, sizeof(mac_data) - 1);
if (!strncmp(mac_ra0, mac_data, strlen(mac_ra0))) {
data_len = read_file_data("/sys/class/net/ra2/address", mac_data, sizeof(mac_data) - 1);
DBG_ERR("ra1 is same as ra0:%s, then use ra2:%s\n", mac_ra0, mac_data);
}
if (data_len > 0) {
mac_format_change(mac_data, bssid, sizeof(bssid), true);
blobmsg_add_string(bBuf, "bssid", bssid);
}
#endif
}
blobmsg_buf_init(&b);
if (info.dport) {
blobmsg_add_blob(&b, info.dport);
ubus_app_invoke(svr_ubus_app, "unetwork", "ebtable_reload", b.head, 0, NULL, NULL);
}
blobmsg_buf_init(&b);
enabled = blobmsg_get_string(info.enabled);
if (info.basic_info && !strncmp(enabled, "on", strlen("on"))) {
if ((table1 = blobmsg_open_table(bBuf, "basic_info"))) {
blobmsg_for_each_attr(cur, info.basic_info, rem) {
blobmsg_add_blob(&b, cur);
}
blobmsg_add_blob(&b, info.mac);
if (info.backup) {
blobmsg_add_blob(&b, info.backup);
}
blobmsg_add_string(&b, "wifi_backup_enabled", blobmsg_get_string(info.enabled));
udsd_add_general_device(svr_ubus_app, b.head, bBuf);
blobmsg_close_table(bBuf, table1);
}
} else {
blobmsg_add_blob(&b, info.mac);
blobmsg_add_blob(&b, info.enabled);
if (info.backup) {
blobmsg_add_blob(&b, info.backup);
}
ubus_app_event(svr_ubus_app, "general_wifi_backup", b.head);
}
blob_buf_free(&b);
blobmsg_close_table(bBuf, table);
blobmsg_close_table(bBuf, domain);
return;
}
static void udsd_storage_hub_request(struct ubus_app *svr_ubus_app, struct blob_buf *bBuf, struct blob_attr *msg, int *error_code) {
/* including bind hub request */
struct blob_buf b = {0};
void *table = NULL, *table1 = NULL, *domain = NULL;
struct blob_attr *cur = NULL;
int rem = 0;
int storage_media_status = 0;
char *enabled = NULL;
*error_code = SLP_ENONE;
if (!bBuf || !error_code || !msg) {
DBG_ERR("arg err\n");
*error_code =IPC_INTF_PARA_ERR;
return;
}
struct blobmsg (
blobmsg_table storage_info,
) (arg, msg, false);
if (!arg.storage_info) {
DBG_ERR("no storage info\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
struct blobmsg (
blobmsg_string enabled, /* on, off */
blobmsg_string mac,
blobmsg_table basic_info,
) (info, arg.storage_info, false);
if (!info.enabled || !info.mac) {
DBG_ERR("param error\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
blobmsg_buf_init(&b);
enabled = blobmsg_get_string(info.enabled);
#ifdef HARDDISK_STORAGE
struct blob_buf dev_buf = {0};
char *mac_str = blobmsg_get_string(info.mac);
blobmsg_buf_init(&dev_buf);
blobmsg_add_string(&dev_buf, "device_mac", mac_str);
ubus_app_invoke(svr_ubus_app, "mediacenter", "storage_get_storage_media_status", dev_buf.head, 3000, ubus_get_storage_media_status_cb, &storage_media_status);
blob_buf_free(&dev_buf);
#else
ubus_app_invoke(svr_ubus_app, "mediacenter", "storage_get_storage_media_status", NULL, 3000, ubus_get_storage_media_status_cb, &storage_media_status);
#endif
domain = blobmsg_open_table(bBuf, "general_camera_manage");
if (domain) {
table = blobmsg_open_table(bBuf, "storage_info");
if (table) {
if (info.basic_info && !strncmp(enabled, "on", strlen("on"))) {
/* return hub info */
table1 = blobmsg_open_table(bBuf, "basic_info");
if (table1) {
blobmsg_for_each_attr(cur, info.basic_info, rem) {
blobmsg_add_blob(&b, cur);
}
blobmsg_for_each_attr(cur, arg.storage_info, rem) {
if (strncmp(blobmsg_name(cur), "basic_info", strlen("basic_info"))) {
blobmsg_add_blob(&b, cur);
}
}
if (info.enabled) {
blobmsg_add_string(&b, "hub_storage_enabled", blobmsg_get_string(info.enabled));
}
udsd_add_general_device(svr_ubus_app, b.head, bBuf);
blobmsg_close_table(bBuf, table1);
}
} else {
/* update :mac, enabled */
blobmsg_for_each_attr(cur, arg.storage_info, rem) {
if (strncmp(blobmsg_name(cur), "basic_info", strlen("basic_info"))) {
blobmsg_add_blob(&b, cur);
}
}
if(!strncmp(enabled, "off", strlen("off"))){
blobmsg_add_u32(&b, "enable", 0);
}else{
blobmsg_add_u32(&b, "enable", 1);
}
blobmsg_add_u32(&b, "storage_media_status", storage_media_status);
ubus_app_invoke(svr_ubus_app, "devmgr", "general_hub_storage_update", b.head, 0, NULL, NULL);
}
blobmsg_add_u32(bBuf, "storage_media_status", storage_media_status);
blobmsg_add_u32(bBuf, "long_conn_support", 1);
blobmsg_close_table(bBuf, table);
}
blobmsg_close_table(bBuf, domain);
}
blob_buf_free(&b);
return;
}
static void udsd_sync_hub_request(struct ubus_app *svr_ubus_app, struct blob_buf *bBuf, struct blob_attr *msg, int *error_code) {
struct blob_buf b = {0};
struct blob_attr *cur = NULL;
int rem = 0;
void *table = NULL, *domain = NULL;
blobmsg_buf_init(&b);
if (!bBuf || !error_code || !msg) {
DBG_ERR("arg err\n");
if (error_code) {
*error_code = IPC_INTF_PARA_ERR;
}
goto RTN;
}
struct blobmsg (
blobmsg_table config_sync,
) (arg, msg, false);
if (!arg.config_sync) {
DBG_ERR("no config_sync\n");
goto RTN;
}
domain = blobmsg_open_table(bBuf, "general_camera_manage");
if (domain) {
if ((table = blobmsg_open_table(bBuf, "config_sync"))) {
blobmsg_for_each_attr(cur, arg.config_sync, rem) {
blobmsg_add_blob(&b, cur);
}
ubus_app_invoke(svr_ubus_app, "devmgr", "sync_config_from_camera", b.head, 3000, ubus_sync_AIEnhance_cb, bBuf);
blobmsg_add_u32(bBuf, "long_conn_support", 1);
blobmsg_close_table(bBuf, table);
}
blobmsg_close_table(bBuf, domain);
}
if (error_code) {
*error_code = SLP_ENONE;
}
RTN:
blob_buf_free(&b);
return;
}
static void udsd_get_general_device_scan_list(struct ubus_app *svr_ubus_app, struct blob_buf* bBuf, struct blob_attr *msg, int *error_code) {
void *domain = NULL;
if (!bBuf || !error_code || !msg) {
DBG_ERR("arg err\n");
if (error_code) {
*error_code = IPC_INTF_PARA_ERR;
}
return;
}
struct blobmsg(
blobmsg_table general_device_list
) (arg, msg, false);
if (!arg.general_device_list) {
DBG_ERR("no general_device_list item in request arg\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
domain = blobmsg_open_table(bBuf, "general_camera_manage");
if (!domain) {
DBG_ERR("open domain failed\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
ubus_app_invoke(svr_ubus_app, "tddp-mmt", "get_scan_cam_list", NULL, 10000, ubus_get_scan_device_cb, bBuf);
blobmsg_close_table(bBuf, domain);
*error_code = SLP_ENONE;
return;
}
static void udsd_start_scan_general_device(struct ubus_app *svr_ubus_app, struct blob_buf* bBuf, struct blob_attr *msg, int *error_code)
{
if (!error_code) {
DBG_ERR("arg err\n");
return;
}
if (!msg) {
*error_code = SLP_EINVARG;
return;
}
struct blobmsg(
blobmsg_table start_scan
) (arg, msg, false);
if (!arg.start_scan) {
DBG_ERR("no start_scan item in request arg\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
ubus_app_invoke(svr_ubus_app, "tddp-mmt", "start_scan_cam", NULL, 0, NULL, NULL);
*error_code = SLP_ENONE;
return;
}
static void udsd_stop_scan_general_device(struct ubus_app *svr_ubus_app, struct blob_buf* bBuf, struct blob_attr *msg, int *error_code)
{
if (!error_code) {
DBG_ERR("arg err\n");
return;
}
if (!msg) {
*error_code = SLP_EINVARG;
return;
}
struct blobmsg(
blobmsg_table stop_scan
) (arg, msg, false);
if (!arg.stop_scan) {
DBG_ERR("no stop_scan item in request arg\n");
*error_code = IPC_INTF_PARA_ERR;
return;
}
ubus_app_invoke(svr_ubus_app, "tddp-mmt", "stop_scan_cam", NULL, 0, NULL, NULL);
*error_code = SLP_ENONE;
return;
}
static const UDSD_MOD_CMD g_udsd_cmds_general_camera_manage[] = {
/* for general camera */
{UDSD_CMD_R, "backupWifiRequest", udsd_wifi_backup_info_request},
{UDSD_CMD_W, "storageHubRequest", udsd_storage_hub_request},
{UDSD_CMD_W, "syncHubRequest", udsd_sync_hub_request},
/* for app */
{UDSD_CMD_R, "getGeneralDeviceList", udsd_get_general_device_list},
{UDSD_CMD_R, "getScanGeneralDeviceList", udsd_get_general_device_scan_list},
{UDSD_CMD_W, "startScanGeneralDevice", udsd_start_scan_general_device},
{UDSD_CMD_W, "stopScanGeneralDevice", udsd_stop_scan_general_device},
{UDSD_CMD_N, NULL, NULL}
};
UDSD_CMD_ADD(general_camera_manage, "general_camera_manage", g_udsd_cmds_general_camera_manage);