doubao_chat/lib/net/telecom/ap_qlink.c

758 lines
22 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "system/includes.h"
#include "json_c/json_object.h"
#include "common/base64.h"
#include "common/aes.h"
#include "sock_api/sock_api.h"
#include "lwip.h"
#include "wifi/wifi_connect.h"
#include "mbedtls/aes.h"
#include "mbedtls/dhm.h"
#include "mbedtls/rsa.h"
#include "mbedtls/sha1.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "time.h"
#include <stdlib.h>
#if 1
#define log_info(x, ...) printf("\n\n>>>>>>[aplink_test]" x " ", ## __VA_ARGS__)
#else
#define log_info(...)
#endif
#define DH_INFO "{\"type\":\"dh\",\"sequence\":2,\"data\":{\"dh_key\":\"%s\",\"dh_p\":\"%s\",\"dh_g\":\"%s\"}}"
#define KEYNGREQ 0x01
#define DH 0x02
#define QPLINK 0x03
#define ACK 0x04
#define ELINK_SRV_PORT 32769 //服务器端口
#define IOT_SSID "ChinaIOT-%s-%02X%02X" //ssid格式
#define IOT_PWD "" //AP模式下登录密码,这里不设置密码
#define VENDOR "Vendor" //设备厂商
extern struct json_object *json_tokener_parse(const char *str);
const static int iot_device_send_keyngack(char *buf, int buf_len);
const static int iot_device_send_dh(char *buf, int buf_len);
const static int iot_device_send_aplinkget(char *buf, int buf_len);
static int dh_base64_decode(const unsigned char *input, unsigned char *output);
static int ap_elink_start(void);
void Hex2Str(const unsigned char *hex, char *str, int len);
static int dh_base64_encode(const unsigned char *input, const int len, unsigned char *output);
static int calculate_common_key(mbedtls_dhm_context *context, unsigned char *srv_pub, char *out_put);
static void iot_interact_to_app(void *client_sock);
static int aes_cbc_encode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *encode_buf);
static int aes_cbc_decode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *decode_buf);
static int iot_device_rec_handle(const char *object);
static int aplink_sock_write(void *sockhdl, const char *buf, size_t n);
extern int elink_aplink_set_ssid_pwd(const char *ssid, const char *pwd);
extern void get_wifi_mac_addr(u8 *mac_addr);
static void iot_device_enter_ap_mode(void);
static int flag;
typedef enum {
aplink_idel_state = 1,
aplink_wait_keyngreq,
aplink_wait_dh_info,
aplink_wait_aplink_info,
aplink_wait_ack,
aplink_qlink_finish,
} aplink_state;
typedef enum {
aplink_receive_keyngreq = 1,
aplink_receive_dh_info,
aplink_receive_aplink_info,
aplink_receive_ack,
} aplink_event;
typedef struct {
aplink_state curState;
aplink_event event;
const int (*aplink_action)(char *, int);
aplink_state nextState;
} aplink_state_change;
typedef struct {
aplink_state curState;
int stuNum;
aplink_state_change *form;
} elink_aplink;
typedef struct _iot_device_info {
unsigned char common_key[16];
char ssid[32];
char pwd[32];
unsigned char dh_key[36];
unsigned char dh_p[36];
unsigned char dh_g[12];
mbedtls_dhm_context dhm_cli;
elink_aplink e_aplink;
aplink_event e_event;
int protected;
} iot_device_info;
typedef struct _iot_rec_type {
char *rec_string;
uint8_t type;
} iot_rec_type;
static iot_device_info iot_device_local;
static mbedtls_ctr_drbg_context ctr_drbg;
static const char aplink_ver[] = "V1.0";
static void *ap_elink_sock = NULL;
static void *cli_sock = NULL;
static int aplink_get_ssid_pwd_success = 0;
static int local_pid = 0;
static iot_rec_type type_table[] = {
{"keyngreq", KEYNGREQ},
{"dh", DH},
{"aplink", QPLINK},
{"ack", ACK},
{NULL, 0}
};
//State Table : 当前状态 激发事件 回调函数 下一个状态
static aplink_state_change aplink_table[] = {
{aplink_idel_state, aplink_receive_keyngreq, iot_device_send_keyngack, aplink_wait_dh_info},
{aplink_wait_dh_info, aplink_receive_dh_info, iot_device_send_dh, aplink_wait_aplink_info},
{aplink_wait_aplink_info, aplink_receive_aplink_info, iot_device_send_aplinkget, aplink_wait_ack},
{aplink_wait_ack, aplink_receive_ack, NULL, aplink_qlink_finish},
};
const char *aplink_version(void)
{
return aplink_ver;
}
void Hex2Str(const unsigned char *hex, char *str, int len)
{
int i;
char temp[3];
for (i = 0; i < len; i++) {
sprintf(temp, "%02X", (unsigned char)hex[i]);
memcpy(&str[i * 2], temp, 2);
}
str[2 * len] = '\0';
}
static void aplink_state_transFer(elink_aplink *aplink, aplink_state state)
{
aplink->curState = state;
}
static int aplink_sock_write(void *sockhdl, const char *buf, size_t n)
{
size_t nLeft = n;
size_t nWrite = 0;
int ret;
while (nLeft > 0) {
ret = sock_send(sockhdl, buf + nWrite, nLeft, 0);
if (ret != nLeft) {
log_info("aplink_sock_write error occurred:%d\n", sock_get_error(sockhdl));
break;
} else {
nLeft -= ret;
nWrite += ret;
}
}
return nWrite == n ? n : -1;
}
static int aplink_eventHandle(elink_aplink *aqlink, const aplink_event event, void *parm)
{
aplink_state_change *changeTable = aqlink->form;
const int (*aplink_action)(char *, int) = NULL;
aplink_state nextState;
aplink_state curState = aqlink->curState;
unsigned something_happen = 0;
unsigned int i;
unsigned int ret;
char send_buf[512];
unsigned int len;
void *cli_sock = parm;
for (i = 0; i < aqlink->stuNum; i++) {
if (event == changeTable[i].event && curState == changeTable[i].curState) {
aplink_action = changeTable[i].aplink_action;
nextState = changeTable[i].nextState;
something_happen = 1;
break;
}
}
if (something_happen) {
if (aplink_action != NULL) {
len = aplink_action(send_buf, sizeof(send_buf));
if (len == -1) {
return -1;
}
os_time_dly(50);
ret = aplink_sock_write(cli_sock, send_buf, len);
if (ret == -1) {
log_info("sock_sendto err!!!");
return -1;
}
}
aplink_state_transFer(aqlink, nextState);
something_happen = 0;
}
return 0;
}
static void aplink_init(elink_aplink *aqlink, aplink_state curState, const int num, aplink_state_change *form)
{
aqlink->form = form;
aqlink->stuNum = num;
aqlink->curState = curState;
return;
}
static int dh_calculate_public_key(mbedtls_dhm_context *context, const char *p, const char *g, unsigned char *public)
{
int ret = 0;
const char *pers = "aplink";
unsigned char cli_pub[16];
mbedtls_entropy_context entropy;
mbedtls_dhm_init(context);
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen(pers))) != 0) {
mbedtls_printf("error!!! mbedtls_ctr_drbg_seed returned %d\n", ret);
goto EXIT;
}
mbedtls_mpi_read_string(&(context->P), 16, p);
mbedtls_mpi_read_string(&(context->G), 10, g);
context->len = mbedtls_mpi_size(&(context->P));
ret = mbedtls_dhm_make_public(context, 16, cli_pub, sizeof(cli_pub), mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0) {
mbedtls_printf(" error!!! mbedtls_dhm_make_public %d\n", ret);
goto EXIT;
}
memcpy(public, cli_pub, sizeof(cli_pub));
mbedtls_entropy_free(&entropy);
/* mbedtls_ctr_drbg_free(&ctr_drbg); */
return 0;
EXIT:
mbedtls_dhm_free(context);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);
return -1;
}
void aplink_cfg_start(void)
{
iot_device_enter_ap_mode();
}
static void wifi_set_lan_setting_info(void)
{
struct lan_setting lan_setting_info = {
.WIRELESS_IP_ADDR0 = 192,
.WIRELESS_IP_ADDR1 = 168,
.WIRELESS_IP_ADDR2 = 1,
.WIRELESS_IP_ADDR3 = 1,
.WIRELESS_NETMASK0 = 255,
.WIRELESS_NETMASK1 = 255,
.WIRELESS_NETMASK2 = 255,
.WIRELESS_NETMASK3 = 0,
.WIRELESS_GATEWAY0 = 192,
.WIRELESS_GATEWAY1 = 168,
.WIRELESS_GATEWAY2 = 1,
.WIRELESS_GATEWAY3 = 1,
.SERVER_IPADDR1 = 192,
.SERVER_IPADDR2 = 168,
.SERVER_IPADDR3 = 1,
.SERVER_IPADDR4 = 1,
.CLIENT_IPADDR1 = 192,
.CLIENT_IPADDR2 = 168,
.CLIENT_IPADDR3 = 1,
.CLIENT_IPADDR4 = 2,
.SUB_NET_MASK1 = 255,
.SUB_NET_MASK2 = 255,
.SUB_NET_MASK3 = 255,
.SUB_NET_MASK4 = 0,
};
net_set_lan_info(&lan_setting_info);
}
static void iot_device_enter_ap_mode(void)
{
u8 mac[6];
char device_mac[32];
wifi_get_mac(mac);
sprintf(device_mac, IOT_SSID, VENDOR, mac[0], mac[1]);
log_info("aplink ssid: %s", device_mac);
wifi_set_lan_setting_info(); //STA转AP模式,需要重新配置一下IP信息和DHCP池起始分配地址
wifi_enter_ap_mode(device_mac, IOT_PWD);
ap_elink_start();
}
/* void iot_device_enter_sta_mode(const char *ssid, const char *pwd) */
void iot_device_enter_sta_mode(char *ssid, char *pwd)
{
wifi_set_sta_connect_timeout(0);
wifi_enter_sta_mode(ssid, pwd);
wifi_store_mode_info(STA_MODE, ssid, pwd);
}
static void ap_elink_tcp_init(void *priv)
{
struct sockaddr_in client_addr;
socklen_t socketLength = sizeof(struct sockaddr_in);
ap_elink_sock = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
if (ap_elink_sock == NULL) {
log_info("ap_elink_tcp_init socket error");
goto EXIT;
}
if (sock_set_reuseaddr(ap_elink_sock)) {
log_info("sock_set_reuseaddr error");
goto EXIT;
}
struct sockaddr _ss;
struct sockaddr_in *dest_addr = (struct sockaddr_in *)&_ss;
dest_addr->sin_family = AF_INET;
dest_addr->sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr->sin_port = htons(ELINK_SRV_PORT);
if (sock_bind(ap_elink_sock, (struct sockaddr *)&_ss, sizeof(_ss))) {
log_info("ap_elink_tcp_init bind error");
goto EXIT;
}
if (sock_listen(ap_elink_sock, 5)) {
log_info("ap_elink_tcp_init sock_listen error");
goto EXIT;
}
log_info("sock_accept starting......................");
cli_sock = sock_accept(ap_elink_sock, (struct sockaddr *)&client_addr, &socketLength, NULL, NULL);
flag = 0;
if (cli_sock == NULL) {
log_info("ap_elink_tcp_init sock_accept error");
goto EXIT;
}
log_info("Successfully connected. Network configuration is starting!!!.....................");
memset(&iot_device_local, 0, sizeof(iot_device_info));
aplink_init(&(iot_device_local.e_aplink), aplink_idel_state, sizeof(aplink_table) / sizeof(aplink_state_change), aplink_table);
extern int wifi_is_on(void);
while (wifi_is_on() == 0) {
os_time_dly(1);
}
iot_interact_to_app(cli_sock);
if (ap_elink_sock) {
sock_unreg(ap_elink_sock);
ap_elink_sock = NULL;
}
EXIT:
if (ap_elink_sock) {
sock_unreg(ap_elink_sock);
ap_elink_sock = NULL;
}
}
static int ap_elink_start(void)
{
if (thread_fork("ap_elink_tcp_init", 17, 2024, 0, &local_pid, ap_elink_tcp_init, NULL) != OS_NO_ERR) {
return -1;
}
return 0;
}
static void iot_interact_to_app(void *client_sock)
{
int recv_len = 0;
unsigned char recv_buf[1024] = {0};
unsigned char decode_buf[512] = {0};
int decode_len = 0;
int err = 0;
for (;;) {
recv_len = sock_recvfrom(client_sock, recv_buf, sizeof(recv_buf), 0, NULL, NULL);
if ((recv_len != -1) && (recv_len != 0)) {
if (iot_device_local.protected) {
/* put_buf(recv_buf, recv_len); */
decode_len = aes_cbc_decode(recv_buf + 8, recv_len - 8, iot_device_local.common_key, decode_buf);
decode_buf[decode_len] = '\0';
/* put_buf(iot_device_local.common_key, 16); */
log_info("recv string : %s", decode_buf);
err = iot_device_rec_handle((char *)decode_buf);
if (err == -1) {
log_info("iot_device_rec_handle err!!!\n");
goto EXIT;
}
} else {
recv_buf[recv_len] = '\0';
log_info("recv string : %s", recv_buf + 8);
err = iot_device_rec_handle((char *)(recv_buf + 8));
if (err == -1) {
log_info("iot_device_rec_handle err!!!\n");
goto EXIT;
}
}
memset(recv_buf, 0, sizeof(recv_buf));
os_time_dly(30);
} else {
log_info("sock_recvfrom err!!!");
goto EXIT;
}
err = aplink_eventHandle(&(iot_device_local.e_aplink), iot_device_local.e_event, client_sock);
if (err == -1) {
log_info("aplink_eventHandle err!!!\n");
goto EXIT;
}
/* if(iot_device_local.e_aplink.curState == aplink_qlink_finish) */
if (iot_device_local.e_aplink.curState == aplink_wait_ack) {
break;
}
}
aplink_get_ssid_pwd_success = 1;
log_info("Successfully obtained distribution network information.Connecting to network..........");
log_info("get ssid: %s, pwd: %s", iot_device_local.ssid, iot_device_local.pwd);
elink_aplink_set_ssid_pwd(iot_device_local.ssid, iot_device_local.pwd);
EXIT:
/* sock_unreg(client_sock); */
if (!aplink_get_ssid_pwd_success) {
log_info("Failed to connect to the Internet, please help me connect to the Internet again");
}
aplink_get_ssid_pwd_success = 0;
}
const static uint8_t check_rec_type(const char *string)
{
iot_rec_type *type_t = type_table;
while (type_t->rec_string) {
if (0 == strcmp(string, type_t->rec_string)) {
return type_t->type;
}
type_t++;
}
return 0;
}
static int iot_device_rec_handle(const char *object)
{
json_object *json = NULL;
json_object *result = NULL;
char *type = NULL;
int len = 0;
char dh_key[32];
unsigned char dh_cli_key[32];
unsigned char dh_ap_key[32];
char dh_p[64];
char dh_g[12];
unsigned char rec_buf[64];
if (NULL == object) {
log_info("Input is empty");
return -1;
}
json = json_tokener_parse(object);
if (NULL == json) {
log_info("Parsing error");
return -1;
}
type = (char *)json_object_get_string(json_object_object_get(json, "type"));
switch (check_rec_type(type)) {
case KEYNGREQ :
log_info("%s\n", object);
result = json_object_array_get_idx(json_object_object_get(json, "keymodelist"), 0);
log_info("the keymode is :%s\n", json_object_get_string(json_object_object_get(result, "keymode")));
iot_device_local.protected = 0;
iot_device_local.e_event = aplink_receive_keyngreq;
break;
case DH :
log_info("DH");
log_info("%s\n", object);
json_object_object_get_ex(json, "data", &result);
log_info("dh_key : %s\n", json_object_get_string(json_object_object_get(result, "dh_key")));
strcpy((char *)iot_device_local.dh_p, json_object_get_string(json_object_object_get(result, "dh_p")));
strcpy((char *)iot_device_local.dh_g, json_object_get_string(json_object_object_get(result, "dh_g")));
log_info("dh_p : %s\n", iot_device_local.dh_p);
log_info("dh_g : %s\n", iot_device_local.dh_g);
len = dh_base64_decode(iot_device_local.dh_p, rec_buf);
Hex2Str(rec_buf, dh_p, len);
log_info("dh_p : %s", dh_p);
len = dh_base64_decode((unsigned char *)iot_device_local.dh_g, rec_buf);
Hex2Str(rec_buf, dh_g, len);
log_info("dh_g : %s", dh_g);
dh_calculate_public_key(&(iot_device_local.dhm_cli), dh_p, dh_g, dh_ap_key);
dh_base64_encode(dh_ap_key, 16, iot_device_local.dh_key);
log_info("public_key encode : %s", iot_device_local.dh_key);
len = dh_base64_decode((unsigned char *)json_object_get_string(json_object_object_get(result, "dh_key")), dh_cli_key);
calculate_common_key(&(iot_device_local.dhm_cli), dh_cli_key, (char *)iot_device_local.common_key);
/* put_buf(iot_device_local.common_key, 16); */
iot_device_local.protected = 1;
iot_device_local.e_event = aplink_receive_dh_info;
os_time_dly(30);
break;
case QPLINK :
log_info("QPLINK");
log_info("%s\n", object);
if (0 != strcmp(json_object_get_string(json_object_object_get(json, "result")), "allow")) {
log_info("Failed to obtain information");
break;
}
json_object_object_get_ex(json, "wifi", &result);
strcpy(iot_device_local.ssid, json_object_get_string(json_object_object_get(result, "ssid")));
strcpy(iot_device_local.pwd, json_object_get_string(json_object_object_get(result, "password")));
log_info("ssid : %s\n", iot_device_local.ssid);
log_info("password : %s\n", iot_device_local.pwd);
iot_device_local.protected = 0;
iot_device_local.e_event = aplink_receive_aplink_info;
break;
case ACK :
log_info("ACK");
log_info("%s\n", object);
iot_device_local.e_event = aplink_receive_ack;
break;
default:
log_info("Data is not defined");
break;
}
json_object_put(json);
return 0;
}
static int dh_p_base64_encode(const unsigned char *p, const int p_len, unsigned char *output)
{
int out_len;
memcpy(output, base64_encode(p, p_len, &out_len), out_len);
*(output + out_len) = '\0';
return out_len;
}
static int dh_base64_encode(const unsigned char *input, const int len, unsigned char *output)
{
int out_len;
memcpy(output, base64_encode(input, len, &out_len), out_len);
*(output + out_len) = '\0';
return out_len;
}
static int dh_g_base64_encode(const unsigned char *g, const int g_len, unsigned char *output)
{
int out_len;
memcpy(output, base64_encode(g, g_len, &out_len), out_len);
*(output + out_len) = '\0';
return out_len;
}
static int calculate_common_key(mbedtls_dhm_context *context, unsigned char *srv_pub, char *out_put)
{
unsigned char secret[16];
int ret;
size_t n = 0;
/* mbedtls_ctr_drbg_context ctr_drbg; */
mbedtls_ctr_drbg_init(&ctr_drbg);
ret = mbedtls_dhm_read_public(context, srv_pub, 16);
ret = mbedtls_dhm_calc_secret(context, secret, sizeof(secret), &n, mbedtls_ctr_drbg_random, &ctr_drbg);
if (ret != 0) {
mbedtls_printf(" failed\n! mbedtls_dhm_calc_secret %d\n", ret);
return -1;
}
memcpy(out_put, secret, 16);
mbedtls_dhm_free(context);
mbedtls_ctr_drbg_free(&ctr_drbg);
return 0;
}
static int dh_base64_decode(const unsigned char *input, unsigned char *output)
{
int out_len;
memcpy(output, base64_decode(input, strlen((char *)input), &out_len), out_len);
/* put_buf(output, out_len); */
return out_len;
}
static int aes_cbc_encode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *encode_buf)
{
unsigned char iv[16] = {0};
unsigned int encode_len;
CT_AES_CBC_Encrypt(input_buf, input_len, key, 16, iv, 16, encode_buf, &encode_len);
return encode_len;
}
static int aes_cbc_decode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *decode_buf)
{
unsigned char iv[16] = {0};
unsigned int decode_len;
CT_AES_CBC_Decrypt(input_buf, input_len, key, 16, iv, 16, decode_buf, &decode_len);
return decode_len;
}
static int aqlink_package_assembly(char *data, int data_len, char *package, int package_buf_len)
{
if (data == NULL || data_len <= 0 || package == NULL || (data_len + 8) > package_buf_len) {
return -1;
}
package[0] = 0x3f;
package[1] = 0x72;
package[2] = 0x1f;
package[3] = 0xb5;
package[4] = (u8)(((u32)data_len >> 24) & 0x00ff);
package[5] = (u8)(((u32)data_len >> 16) & 0x00ff);
package[6] = (u8)(((u32)data_len >> 8) & 0x00ff);
package[7] = (u8)(((u32)data_len >> 0) & 0x00ff);
memcpy(package + 8, data, data_len);
return (data_len + 8);
}
const static int iot_device_send_keyngack(char *buf, int buf_len)
{
char temp_buf[512];
unsigned int len;
char *keyngack = "{\"type\":\"keyngack\",\"sequence\":1,\"keymode\":\"dh\"}";
len = aqlink_package_assembly(keyngack, strlen(keyngack), buf, buf_len);
return len;
}
const static int iot_device_send_dh(char *buf, int buf_len)
{
char temp_buf[256];
char key[64];
char dh_p[64];
char dh_g[64];
unsigned int len;
snprintf(temp_buf, sizeof(temp_buf), DH_INFO,
iot_device_local.dh_key,
iot_device_local.dh_p,
iot_device_local.dh_g);
log_info("iot_device_send_dh : %s", temp_buf);
len = aqlink_package_assembly(temp_buf, strlen(temp_buf), buf, buf_len);
return len;
}
const static int iot_device_send_aplinkget(char *buf, int buf_len)
{
unsigned int len;
unsigned char encode_buf[512];
int encode_len;
char *aplinkget = "{\"type\":\"aplinkget\",\"sequence\":3,\"result\":\"get\"}";
encode_len = aes_cbc_encode((unsigned char *)aplinkget, strlen((char *)aplinkget), iot_device_local.common_key, encode_buf);
len = aqlink_package_assembly((char *)encode_buf, encode_len, buf, buf_len);
/* char decode_buf[256]; */
/* int decode_len; */
/* decode_len = aes_cbc_decode(encode_buf, encode_len, iot_device_local.common_key, decode_buf); */
/* decode_buf[decode_len] = '\0'; */
/* log_info("aplinkget decode: %s", decode_buf); */
return len;
}
void qlink_cfg_stop(void)
{
if (ap_elink_sock) {
flag = 1;
sock_set_quit(ap_elink_sock);
while (flag) {
os_time_dly(20);
}
sock_unreg(ap_elink_sock);
ap_elink_sock = NULL;
}
}