1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "dev_bind_internal.h"
5 
6 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
7 extern "C" {
8 #endif
9 
10 #define AWSS_REPORT_LEN_MAX      (256)
11 #define AWSS_TOKEN_TIMEOUT_MS    (120 * 1000)
12 #define MATCH_MONITOR_TIMEOUT_MS (10 * 1000)
13 #define MATCH_REPORT_CNT_MAX     (2)
14 
15 volatile char awss_report_token_suc = 0; // avoid be optimized by the compiler
16 volatile char awss_report_token_cnt = 0; // avoid be optimized by the compiler
17 static char awss_report_id = 0;
18 #ifdef WIFI_PROVISION_ENABLED
19 static uint8_t switchap_bssid[ETH_ALEN] = { 0 };
20 static char switchap_ssid[OS_MAX_SSID_LEN] = { 0 };
21 static char switchap_passwd[OS_MAX_PASSWD_LEN] = { 0 };
22 static void *switchap_timer = NULL;
23 #endif
24 
25 static uint32_t awss_report_token_time = 0;
26 static void *report_token_timer = NULL;
27 
28 static int awss_report_token_to_cloud();
29 #ifdef WIFI_PROVISION_ENABLED
30 static int awss_switch_ap_online();
31 static int awss_reboot_system();
32 #endif
33 
awss_token_remain_time()34 int awss_token_remain_time()
35 {
36     int remain = 0;
37     uint32_t cur = os_get_time_ms();
38     uint32_t diff = (uint32_t)(cur - awss_report_token_time);
39 
40     if (awss_report_token_suc == 0) {
41         return remain;
42     }
43 
44     if (diff < AWSS_TOKEN_TIMEOUT_MS) {
45         remain = AWSS_TOKEN_TIMEOUT_MS - diff;
46     }
47 
48     return remain;
49 }
50 
awss_update_token()51 int awss_update_token()
52 {
53     awss_report_token_time = 0;
54     awss_report_token_cnt = 0;
55     awss_report_token_suc = 0;
56 
57     produce_random(aes_random, sizeof(aes_random));
58     if (report_token_timer == NULL) {
59         report_token_timer = HAL_Timer_Create(
60             "rp_token", (void (*)(void *))awss_report_token_to_cloud, NULL);
61     }
62     HAL_Timer_Stop(report_token_timer);
63     HAL_Timer_Start(report_token_timer, 10);
64     awss_info("update token");
65 
66     return 0;
67 }
68 
awss_token_timeout()69 int awss_token_timeout()
70 {
71     uint32_t cur;
72     if (awss_report_token_time == 0) {
73         return 1;
74     }
75 
76     cur = os_get_time_ms();
77     if ((uint32_t)(cur - awss_report_token_time) > AWSS_TOKEN_TIMEOUT_MS) {
78         return 1;
79     }
80     return 0;
81 }
82 
awss_report_token_reply(void * pcontext,void * pclient,void * msg)83 void awss_report_token_reply(void *pcontext, void *pclient, void *msg)
84 {
85     int ret, len;
86     char *payload;
87     char *id = NULL;
88     char reply_id = 0;
89     uint32_t payload_len;
90 
91     ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len);
92 
93     if (ret != 0 || payload == NULL || payload_len == 0) {
94         return;
95     }
96 
97     id = json_get_value_by_name(payload, payload_len, AWSS_JSON_ID, &len, NULL);
98     if (id == NULL) {
99         return;
100     }
101 
102     reply_id = atoi(id);
103     if (reply_id + 1 < awss_report_id) {
104         return;
105     }
106     awss_info("%s\r\n", __func__);
107     awss_report_token_suc = 1;
108     awss_stop_timer(report_token_timer);
109     report_token_timer = NULL;
110     AWSS_DB_UPDATE_STATIS(AWSS_DB_STATIS_SUC);
111     AWSS_DB_DISP_STATIS();
112     return;
113 }
114 
115 #ifdef WIFI_PROVISION_ENABLED
awss_online_switchap(void * pcontext,void * pclient,void * msg)116 void awss_online_switchap(void *pcontext, void *pclient, void *msg)
117 {
118 #define SWITCHAP_RSP_LEN   (64)
119 #define AWSS_BSSID_STR_LEN (17)
120 #define AWSS_SSID          "ssid"
121 #define AWSS_PASSWD        "passwd"
122 #define AWSS_BSSID         "bssid"
123 #define AWSS_SWITCH_MODE   "switchMode"
124 #define AWSS_TIMEOUT       "timeout"
125 
126     int len = 0, timeout = 0;
127     char *packet = NULL, *awss_info = NULL, *elem = NULL;
128     int packet_len = SWITCHAP_RSP_LEN, awss_info_len = 0;
129 
130     uint32_t payload_len;
131     char *payload;
132     int ret;
133 
134     ret = awss_cmp_mqtt_get_payload(msg, &payload, &payload_len);
135 
136     if (ret != 0) {
137         goto ONLINE_SWITCHAP_FAIL;
138     }
139 
140     if (payload == NULL || payload_len == 0) {
141         goto ONLINE_SWITCHAP_FAIL;
142     }
143 
144     awss_debug("online switchap len:%u, payload:%s\r\n", payload_len, payload);
145     packet = awss_zalloc(packet_len + 1);
146     if (packet == NULL) {
147         goto ONLINE_SWITCHAP_FAIL;
148     }
149 
150     awss_info = json_get_value_by_name(payload, payload_len, AWSS_JSON_PARAM,
151                                        &awss_info_len, NULL);
152     if (awss_info == NULL || awss_info_len == 0) {
153         goto ONLINE_SWITCHAP_FAIL;
154     }
155 
156     /*
157      * get SSID , PASSWD, BSSID of router
158      */
159     elem =
160         json_get_value_by_name(awss_info, awss_info_len, AWSS_SSID, &len, NULL);
161     if (elem == NULL || len <= 0 || len >= OS_MAX_SSID_LEN) {
162         goto ONLINE_SWITCHAP_FAIL;
163     }
164 
165     memset(switchap_ssid, 0, sizeof(switchap_ssid));
166     memcpy(switchap_ssid, elem, len);
167 
168     len = 0;
169     elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_PASSWD, &len,
170                                   NULL);
171     if (elem == NULL || len <= 0 || len >= OS_MAX_PASSWD_LEN) {
172         goto ONLINE_SWITCHAP_FAIL;
173     }
174 
175     memset(switchap_passwd, 0, sizeof(switchap_passwd));
176     memcpy(switchap_passwd, elem, len);
177 
178     len = 0;
179     memset(switchap_bssid, 0, sizeof(switchap_bssid));
180     elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_BSSID, &len,
181                                   NULL);
182 
183     if (elem != NULL && len == AWSS_BSSID_STR_LEN) {
184         uint8_t i = 0;
185         char *bssid_str = elem;
186         /* convert bssid string to bssid value */
187         while (i < OS_ETH_ALEN) {
188             switchap_bssid[i++] = (uint8_t)strtol(bssid_str, &bssid_str, 16);
189             ++bssid_str;
190             /*
191              * fix the format of bssid string is not legal.
192              */
193             if ((uint32_t)((unsigned long)bssid_str - (unsigned long)elem) >
194                 AWSS_BSSID_STR_LEN) {
195                 memset(switchap_bssid, 0, sizeof(switchap_bssid));
196                 break;
197             }
198         }
199     }
200 
201     len = 0;
202     elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_SWITCH_MODE,
203                                   &len, NULL);
204     if (elem != NULL && (elem[0] == '0' || elem[0] == 0)) {
205         elem = json_get_value_by_name(awss_info, awss_info_len, AWSS_TIMEOUT,
206                                       &len, NULL);
207         if (elem) {
208             timeout = (int)strtol(elem, &elem, 16);
209         }
210     }
211 
212     do {
213         /* reduce stack used */
214         char *id = NULL;
215         char id_str[MSG_REQ_ID_LEN] = { 0 };
216         id = json_get_value_by_name(payload, payload_len, AWSS_JSON_ID, &len,
217                                     NULL);
218         memcpy(id_str, id, len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : len);
219         awss_build_packet(AWSS_CMP_PKT_TYPE_RSP, id_str, ILOP_VER,
220                           METHOD_EVENT_ZC_SWITCHAP, "{}", 200, packet,
221                           &packet_len);
222     } while (0);
223 
224     do {
225         char reply[TOPIC_LEN_MAX] = { 0 };
226         awss_build_topic(TOPIC_SWITCHAP_REPLY, reply, TOPIC_LEN_MAX);
227         awss_cmp_mqtt_send(reply, packet, packet_len, 1);
228         HAL_Free(packet);
229     } while (0);
230 
231     /*
232      * make sure the response would been received
233      */
234     if (timeout < 1000) {
235         timeout = 1000;
236     }
237 
238     do {
239         uint8_t bssid[ETH_ALEN] = { 0 };
240         char ssid[OS_MAX_SSID_LEN + 1] = { 0 },
241                                     passwd[OS_MAX_PASSWD_LEN + 1] = { 0 };
242         HAL_Wifi_Get_Ap_Info(ssid, passwd, bssid);
243         /*
244          * switch ap when destination ap is differenct from current ap
245          */
246         if (strncmp(ssid, switchap_ssid, sizeof(ssid)) ||
247             memcmp(bssid, switchap_bssid, sizeof(bssid)) ||
248             strncmp(passwd, switchap_passwd, sizeof(passwd))) {
249             if (switchap_timer == NULL) {
250                 switchap_timer = HAL_Timer_Create(
251                     "swichap_online", (void (*)(void *))awss_switch_ap_online,
252                     NULL);
253             }
254 
255             HAL_Timer_Stop(switchap_timer);
256             HAL_Timer_Start(switchap_timer, timeout);
257         }
258     } while (0);
259 
260     return;
261 
262 ONLINE_SWITCHAP_FAIL:
263     awss_warn("ilop online switchap failed");
264     memset(switchap_ssid, 0, sizeof(switchap_ssid));
265     memset(switchap_bssid, 0, sizeof(switchap_bssid));
266     memset(switchap_passwd, 0, sizeof(switchap_passwd));
267     if (packet) {
268         HAL_Free(packet);
269     }
270     return;
271 }
272 
273 static void *reboot_timer = NULL;
awss_switch_ap_online()274 static int awss_switch_ap_online()
275 {
276     HAL_Awss_Connect_Ap(WLAN_CONNECTION_TIMEOUT_MS, switchap_ssid,
277                         switchap_passwd, AWSS_AUTH_TYPE_INVALID,
278                         AWSS_ENC_TYPE_INVALID, switchap_bssid, 0);
279 
280     awss_stop_timer(switchap_timer);
281     switchap_timer = NULL;
282 
283     memset(switchap_ssid, 0, sizeof(switchap_ssid));
284     memset(switchap_bssid, 0, sizeof(switchap_bssid));
285     memset(switchap_passwd, 0, sizeof(switchap_passwd));
286 
287     reboot_timer = HAL_Timer_Create("rb_timer",
288                                     (void (*)(void *))awss_reboot_system, NULL);
289     HAL_Timer_Start(reboot_timer, 1000);
290     ;
291 
292     return 0;
293 }
294 
awss_reboot_system()295 static int awss_reboot_system()
296 {
297     awss_stop_timer(reboot_timer);
298     reboot_timer = NULL;
299     HAL_Reboot();
300     return 0;
301 }
302 #endif
303 
awss_report_token_to_cloud()304 static int awss_report_token_to_cloud()
305 {
306     int packet_len, ret;
307     char *packet;
308     char topic[TOPIC_LEN_MAX] = { 0 };
309 #define REPORT_TOKEN_PARAM_LEN (64)
310     if (awss_report_token_suc) { /* success ,no need to report */
311         return 0;
312     }
313 
314     AWSS_DB_UPDATE_STATIS(AWSS_DB_STATIS_START);
315 
316     /*
317      * it is still failed after try to report token MATCH_REPORT_CNT_MAX times
318      */
319     if (awss_report_token_cnt++ > MATCH_REPORT_CNT_MAX) {
320         awss_stop_timer(report_token_timer);
321         report_token_timer = NULL;
322         awss_info("try %d times fail", awss_report_token_cnt);
323         return -2;
324     }
325 
326     if (report_token_timer == NULL) {
327         report_token_timer = HAL_Timer_Create(
328             "rp_token", (void (*)(void *))awss_report_token_to_cloud, NULL);
329     }
330     HAL_Timer_Stop(report_token_timer);
331     HAL_Timer_Start(report_token_timer, 3 * 1000);
332 
333     packet_len = AWSS_REPORT_LEN_MAX;
334 
335     packet = awss_zalloc(packet_len + 1);
336     if (packet == NULL) {
337         awss_err("alloc mem(%d) failed", packet_len);
338         return -1;
339     }
340 
341     do {
342         /* reduce stack used */
343         uint8_t i;
344         char id_str[MSG_REQ_ID_LEN] = { 0 };
345         char param[REPORT_TOKEN_PARAM_LEN] = { 0 };
346         char token_str[(RANDOM_MAX_LEN << 1) + 1] = { 0 };
347 
348         for (i = 0; i < sizeof(aes_random);
349              i++) /* check aes_random is initialed or not */
350             if (aes_random[i] != 0x00) {
351                 break;
352             }
353 
354         if (i >= sizeof(aes_random)) { /* aes_random needs to be initialed */
355             produce_random(aes_random, sizeof(aes_random));
356         }
357 
358         awss_report_token_time = os_get_time_ms();
359 
360         HAL_Snprintf(id_str, MSG_REQ_ID_LEN - 1, "\"%u\"", awss_report_id++);
361         utils_hex_to_str(aes_random, RANDOM_MAX_LEN, token_str,
362                          sizeof(token_str) - 1);
363         HAL_Snprintf(param, REPORT_TOKEN_PARAM_LEN - 1, "{\"token\":\"%s\"}",
364                      token_str);
365         awss_build_packet(AWSS_CMP_PKT_TYPE_REQ, id_str, ILOP_VER,
366                           METHOD_MATCH_REPORT, param, 0, packet, &packet_len);
367     } while (0);
368 
369     awss_debug("report token:%s\r\n", packet);
370     awss_build_topic(TOPIC_MATCH_REPORT, topic, TOPIC_LEN_MAX);
371 
372     ret = awss_cmp_mqtt_send(topic, packet, packet_len, 1);
373     awss_info("report token res:%d\r\n", ret);
374     HAL_Free(packet);
375 
376     return ret;
377 }
378 
awss_report_token()379 int awss_report_token()
380 {
381     awss_report_token_cnt = 0;
382     awss_report_token_suc = 0;
383 
384     return awss_report_token_to_cloud();
385 }
386 
awss_stop_report_token()387 int awss_stop_report_token()
388 {
389     if (report_token_timer) {
390         awss_stop_timer(report_token_timer);
391         report_token_timer = NULL;
392     }
393 
394     memset(aes_random, 0x00, sizeof(aes_random));
395 
396     return 0;
397 }
398 
399 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
400 }
401 #endif
402