1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <string.h>
6 #include <cJSON.h>
7 #include <stdlib.h>
8 #include "ota_log.h"
9 #include "ota_hal.h"
10 #include "ota_import.h"
11 #include "ota_hal_os.h"
12 #include "ota_hal_trans.h"
13 #include "ota_agent.h"
14 #include "aiot_mqtt_api.h"
15 /**
16  * ota_sevice_parse_msg  OTA parse download info from cloud
17  *
18  * @param[in]  ota_service_t *ctx  service manager.
19  *             char *json          transport message from Cloud.
20  *
21  * @return OTA_TRANSPORT_FAIL     transport errno.
22  */
ota_sevice_parse_msg(ota_service_t * ctx,const char * json)23 int ota_sevice_parse_msg(ota_service_t *ctx, const char *json)
24 {
25     int ret            = 0;
26     int is_get_module  = 0;
27     cJSON *root        = NULL;
28     ota_boot_param_t ota_param = {0};
29     root = cJSON_Parse(json);
30     if (NULL == root || NULL == ctx) {
31         ret = OTA_TRANSPORT_PAR_FAIL;
32         OTA_LOG_E("parse msg param is null");
33         return ret;
34     } else {
35         /* recover the process type */
36         cJSON *cmd = cJSON_GetObjectItem(root, "cmd");
37         if (NULL == cmd) {
38             ctx->ota_process = OTA_PROCESS_NORMAL;
39         }
40         cJSON *message = cJSON_GetObjectItem(root, "message");
41         if (NULL == message) {
42             ret = OTA_MESSAGE_PAR_FAIL;
43             goto EXIT;
44         }
45         if ((strncmp(message->valuestring, "success", strlen("success")))) {
46             ret = OTA_SUCCESS_PAR_FAIL;
47             goto EXIT;
48         }
49         cJSON *json_obj = cJSON_GetObjectItem(root, "data");
50         if (NULL == json_obj) {
51             ret = OTA_DATA_PAR_FAIL;
52             goto EXIT;
53         }
54         cJSON *url = cJSON_GetObjectItem(json_obj, "url");
55         if (NULL == url) {
56             ret = OTA_URL_PAR_FAIL;
57             goto EXIT;
58         }
59         strncpy(ota_param.url, url->valuestring, OTA_URL_LEN - 1);
60         ota_param.url[sizeof(ota_param.url) - 1] = 0;
61         cJSON *submodule = cJSON_GetObjectItem(json_obj, "module");
62         if (NULL != submodule) {
63             is_get_module = 1;
64             strncpy(ctx->module_name, submodule->valuestring, sizeof(ctx->module_name) - 1);
65             OTA_LOG_I("submode = %s\r\n", submodule->valuestring);
66         }
67         cJSON *version = cJSON_GetObjectItem(json_obj, "version");
68         if (NULL == version) {
69             ret = OTA_VER_PAR_FAIL;
70             goto EXIT;
71         }
72         strncpy(ota_param.ver, version->valuestring, sizeof(ota_param.ver));
73         ota_param.ver[sizeof(ota_param.ver) - 1] = 0;
74         cJSON *signMethod = cJSON_GetObjectItem(json_obj, "signMethod");
75         if (signMethod != NULL) {
76             memset(ota_param.hash, 0x00, OTA_HASH_LEN);
77             ret = ota_to_capital(signMethod->valuestring, strlen(signMethod->valuestring));
78             if (ret != 0) {
79                 ret = OTA_VER_PAR_FAIL;
80                 goto EXIT;
81             }
82             if (0 == strncmp(signMethod->valuestring, "MD5", strlen("MD5"))) {
83                 cJSON *md5 = cJSON_GetObjectItem(json_obj, "sign");
84                 if (NULL == md5) {
85                     ret = OTA_MD5_PAR_FAIL;
86                     goto EXIT;
87                 }
88                 ota_param.hash_type = OTA_MD5;
89                 strncpy(ota_param.hash, md5->valuestring, OTA_HASH_LEN - 1);
90                 ret = ota_to_capital(ota_param.hash, strlen(ota_param.hash));
91                 if (ret != 0) {
92                     ret = OTA_VER_PAR_FAIL;
93                     goto EXIT;
94                 }
95             } else if (0 == strncmp(signMethod->valuestring, "SHA256", strlen("SHA256"))) {
96                 cJSON *sha256 = cJSON_GetObjectItem(json_obj, "sign");
97                 if (NULL == sha256) {
98                     ret = OTA_SHA256_PAR_FAIL;
99                     goto EXIT;
100                 }
101                 ota_param.hash_type = OTA_SHA256;
102                 strncpy(ota_param.hash, sha256->valuestring, OTA_HASH_LEN - 1);
103                 ret = ota_to_capital(ota_param.hash, strlen(ota_param.hash));
104                 if (ret != 0) {
105                     ret = OTA_VER_PAR_FAIL;
106                     goto EXIT;
107                 }
108             } else {
109                 ret = OTA_HASH_PAR_FAIL;
110                 goto EXIT;
111             }
112         } else { /* old protocol*/
113             memset(ota_param.hash, 0x00, OTA_HASH_LEN);
114             cJSON *md5 = cJSON_GetObjectItem(json_obj, "md5");
115             if (NULL == md5) {
116                 ret = OTA_MD5_PAR_FAIL;
117                 goto EXIT;
118             }
119             ota_param.hash_type = OTA_MD5;
120             strncpy(ota_param.hash, md5->valuestring, OTA_HASH_LEN - 1);
121             ret = ota_to_capital(ota_param.hash, strlen(ota_param.hash));
122             if (ret != 0) {
123                 ret = OTA_VER_PAR_FAIL;
124                 goto EXIT;
125             }
126         }
127         cJSON *size = cJSON_GetObjectItem(json_obj, "size");
128         if (NULL == size) {
129             ret = OTA_SIZE_PAR_FAIL;
130             goto EXIT;
131         }
132         ota_param.len = size->valueint;
133         cJSON *digestSign = cJSON_GetObjectItem(json_obj, "digestsign");
134         if (digestSign != NULL) {
135             unsigned int sign_len = OTA_SIGN_LEN;
136             memset(ota_param.sign, 0x00, OTA_SIGN_LEN);
137             if (ota_base64_decode((const unsigned char *)digestSign->valuestring, strlen(digestSign->valuestring), (unsigned char*)ota_param.sign, &sign_len) != 0) {
138                 ret = OTA_SIGN_PAR_FAIL;
139                 goto EXIT;
140             }
141         }
142     }
143 
144 EXIT:
145     if (root != NULL) {
146         cJSON_Delete(root);
147         root = NULL;
148     }
149     OTA_LOG_I("Parse ota version:%s url:%s ret:%d\n", ota_param.ver, ota_param.url, ret);
150     if (ret < 0) {
151         ret = OTA_TRANSPORT_PAR_FAIL;
152         if (ctx->report_func.report_status_cb != NULL) {
153             ctx->report_func.report_status_cb(ctx->report_func.param, ret);
154         }
155     } else {
156         if (ctx->report_func.report_status_cb != NULL) {
157             ctx->report_func.report_status_cb(ctx->report_func.param, 1);
158         }
159         ota_param.upg_flag = 0x00;
160         if (ctx->dev_type == 0) {
161             if (is_get_module == 0) {
162                 strncpy(ctx->module_name, "default", 7);
163             }
164         }
165         OTA_LOG_I("upg_flag = %04x", ota_param.upg_flag);
166         ota_param.upg_status = OTA_TRANSPORT;
167         ret = ota_update_parameter(&ota_param);
168         if (ret != 0) {
169             OTA_LOG_I("ota param err.\n");
170             if (ctx->report_func.report_status_cb != NULL) {
171                 ctx->report_func.report_status_cb(ctx->report_func.param, OTA_TRANSPORT_PAR_FAIL);
172             }
173         }
174         if (ctx->ota_triggered_func.triggered_ota_cb != NULL) {
175             ctx->ota_triggered_func.triggered_ota_cb(ctx, ota_param.ver, ctx->module_name, ctx->ota_triggered_func.param);
176         }
177     }
178     return ret;
179 }
180 
181 /**
182  * ota_mqtt_publish message to Cloud
183  *
184  * @param[in] mqtt_client      mqtt client ptr
185  * @param[in] name             topic name
186  * @param[in] msg              message content
187  * @param[in] pk               product key
188  * @param[in] dn               device name
189  *
190  * @return OTA_SUCCESS         OTA success.
191  * @return OTA_TRANSPORT_INT_FAIL  OTA transport init fail.
192  * @return OTA_TRANSPORT_PAR_FAIL  OTA transport parse fail.
193  * @return OTA_TRANSPORT_VER_FAIL  OTA transport verion is too old.
194  */
ota_mqtt_publish(void * mqtt_client,const char * name,char * msg,char * pk,char * dn)195 static int ota_mqtt_publish(void *mqtt_client, const char *name, char *msg, char *pk, char *dn)
196 {
197     int ret = 0;
198     char topic[OTA_MSG_LEN] = {0};
199     if (name == NULL || msg == NULL || pk == NULL || dn == NULL) {
200         return OTA_TRANSPORT_INT_FAIL;
201     }
202     ret = ota_snprintf(topic, OTA_MSG_LEN - 1, "/ota/device/%s/%s/%s", name, pk, dn);
203     if (ret < 0) {
204         return OTA_TRANSPORT_INT_FAIL;
205     }
206     OTA_LOG_I("Public topic:%s msg:%s", topic, msg);
207     ret = ota_hal_mqtt_publish(mqtt_client, topic, 1, (void *)msg, strlen(msg) + 1);
208     if (ret < 0) {
209         return OTA_TRANSPORT_INT_FAIL;
210     }
211     return ret;
212 }
213 
214 /**
215  * ota_mqtt_sub_cb  upgrade callback
216  *
217  * @param[in] pctx      ota context
218  * @param[in] pclient   mqtt pclient
219  * @param[in] msg       mqtt message
220  *
221  * @return void
222  */
ota_mqtt_sub_cb(void * mqtt_client,void * msg,void * pctx)223 static void ota_mqtt_sub_cb(void *mqtt_client, void *msg, void *pctx)
224 {
225     char *payload = NULL;
226     ota_service_t *ctx = (ota_service_t *)pctx;
227     aiot_mqtt_recv_t *mqtt_msg = (aiot_mqtt_recv_t *)msg;
228     if ((msg == NULL) && (ctx == NULL)) {
229         OTA_LOG_E("mqtt sub param err!");
230         return;
231     }
232     if (mqtt_msg->type == AIOT_MQTTRECV_PUB) {
233         payload = (char *)mqtt_msg->data.pub.payload;
234         OTA_LOG_I("pub, qos: %d, topic: %.*s\n", mqtt_msg->data.pub.qos, mqtt_msg->data.pub.topic_len, mqtt_msg->data.pub.topic);
235         if (payload != NULL) {
236             OTA_LOG_I("mqtt cb evt:%d %s", mqtt_msg->type, payload);
237             ota_sevice_parse_msg(ctx, payload);
238         }
239     } else {
240         OTA_LOG_I("mqtt type = %d", mqtt_msg->type);
241         payload = (char *)mqtt_msg->data.pub.payload;
242         // OTA_LOG_I("pub, qos: %d, topic: %.*s\n", mqtt_msg->data.pub.qos, mqtt_msg->data.pub.topic_len, mqtt_msg->data.pub.topic);
243         OTA_LOG_E("mqtt receive err msg type!");
244     }
245 }
246 
247 /**
248  * ota_transport_inform  OTA inform version to cloud.
249  *
250  * @param[in]   void *mqttclient   mqtt client ptr
251  * @param[in]           char *pk   product key value
252  * @param[in]           char *dn   device name
253  * @param[in]  char *module_name   want to report module name, when module_name == NULL, report default module ver
254  * @param[in]          char *ver   version string
255  *
256  * @return OTA_SUCCESS             OTA success.
257  * @return OTA_TRANSPORT_INT_FAIL  OTA transport init fail.
258  * @return OTA_TRANSPORT_PAR_FAIL  OTA transport parse fail.
259  * @return OTA_TRANSPORT_VER_FAIL  OTA transport verion is too old.
260  */
ota_transport_inform(void * mqttclient,char * pk,char * dn,char * module_name,char * ver)261 int ota_transport_inform(void *mqttclient, char *pk, char *dn, char *module_name, char *ver)
262 {
263     int  ret = 0;
264     char msg[OTA_MSG_LEN] = {0};
265     if ((mqttclient == NULL) || (ver == NULL) || (pk == NULL) ||
266         (dn == NULL) || (module_name == NULL)) {
267         OTA_LOG_E("inform version input param err!");
268         goto OTA_TRANS_INFOR_OVER;
269     }
270     if (strncmp(module_name, "default", strlen("default")) == 0) {
271         ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"version\":\"%s\"}}", 0, ver);
272     } else {
273        ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"version\":\"%s\",\"module\":\"%s\"}}", 0, ver, module_name);
274     }
275     if (ret < 0) {
276         OTA_LOG_E("inform version pack msg err!");
277         goto OTA_TRANS_INFOR_OVER;
278     }
279     ret = ota_mqtt_publish(mqttclient, "inform", msg, pk, dn);
280 OTA_TRANS_INFOR_OVER:
281     if (ret < 0) {
282         OTA_LOG_E("inform version failed!");
283     }
284     return ret;
285 }
286 
ota_transport_inform_otaver(ota_service_t * ctx)287 int ota_transport_inform_otaver(ota_service_t *ctx)
288 {
289     int ret = 0;
290     char topic[OTA_MSG_LEN] = {0};
291     char msg[OTA_MSG_LEN] = {0};
292     char keyver[20] = "SYS_OTA_ID";
293     char attver[64] = {0};
294     if (ctx == NULL) {
295         return OTA_TRANSPORT_PAR_FAIL;
296     }
297     ret = ota_snprintf(topic, OTA_MSG_LEN - 1, "/sys/%s/%s/thing/deviceinfo/update", ctx->pk, ctx->dn);
298     if (ret < 0) {
299         return OTA_TRANSPORT_PAR_FAIL;
300     }
301     ret = ota_snprintf(attver, sizeof(attver) - 1, "HOTA-%s-%s-%s-%s", OTA_VERSION, OTA_TRANSTYPE, OTA_OS_TYPE, OTA_BOARD_TYPE);
302     if (ret < 0) {
303         return OTA_TRANSPORT_PAR_FAIL;
304     }
305     OTA_LOG_I("Public topic:%s", topic);
306     ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":\"%d\",\"version\":\"1.0\",\"params\":[{\"attrKey\":\"%s\",\"attrValue\":\"%s\"}],\"method\":\"thing.deviceinfo.update\"}",
307           0, keyver, attver);
308     if (ret < 0) {
309         return OTA_TRANSPORT_PAR_FAIL;
310     }
311     OTA_LOG_I("Public msg:%s", msg);
312     ret = ota_hal_mqtt_publish(ctx->mqtt_client, topic, 1, (void *)msg, strlen(msg) + 1);
313     if (ret < 0) {
314         return OTA_TRANSPORT_INT_FAIL;
315     }
316     return ret;
317 }
318 /**
319  * ota_transport_upgrade  OTA subcribe message from Cloud.
320  *
321  * @param[in] ota_service_t *ctx ctx  ota service context
322  *
323  * @return OTA_SUCCESS         OTA success.
324  * @return OTA_TRANSPORT_INT_FAIL  OTA transport init fail.
325  * @return OTA_TRANSPORT_PAR_FAIL  OTA transport parse fail.
326  * @return OTA_TRANSPORT_VER_FAIL  OTA transport verion is too old.
327  */
ota_transport_upgrade(ota_service_t * ctx)328 int ota_transport_upgrade(ota_service_t *ctx)
329 {
330     int  ret                = OTA_TRANSPORT_INT_FAIL;
331     char topic[OTA_MSG_LEN] = {0};
332 
333     if (ctx == NULL) {
334         return ret;
335     }
336     ret = ota_snprintf(topic, OTA_MSG_LEN - 1, "/ota/device/%s/%s/%s", "upgrade", ctx->pk, ctx->dn);
337     if (ret < 0) {
338         ret = OTA_TRANSPORT_INT_FAIL;
339     } else {
340         ret = ota_hal_mqtt_subscribe(ctx->mqtt_client, topic, ota_mqtt_sub_cb, ctx);
341     }
342     return ret;
343 }
344 
345 /**
346  * ota_transport_status  OTA report status to Cloud
347  *
348  * @param[in] void *param param  ota service context
349  * @param[in] status      [1-100] percent, [<0] error no.
350  *
351  * @return OTA_SUCCESS         OTA success.
352  * @return OTA_TRANSPORT_INT_FAIL  OTA transport init fail.
353  * @return OTA_TRANSPORT_PAR_FAIL  OTA transport parse fail.
354  * @return OTA_TRANSPORT_VER_FAIL  OTA transport verion is too old.
355  */
ota_transport_status(void * param,int status)356 int ota_transport_status(void *param, int status)
357 {
358     int  ret                = OTA_TRANSPORT_INT_FAIL;
359     ota_service_t *ctx      = NULL;
360     char msg[OTA_MSG_LEN]   = {0};
361     char *err_str           = "";
362     int tmp_status          = 0;
363     if (param == NULL) {
364         OTA_LOG_E("report status param is null!");
365         return ret;
366     }
367     ctx = (ota_service_t *)param;
368     tmp_status = status;
369     if (status < 0) {
370         switch (status) {
371             case OTA_INIT_FAIL:
372                 err_str = "OTA init failed";
373                 tmp_status = OTA_REPORT_UPGRADE_ERR;
374                 break;
375             case OTA_TRANSPORT_INT_FAIL:
376                 err_str = "OTA transport init failed";
377                 tmp_status = OTA_REPORT_UPGRADE_ERR;
378                 break;
379             case OTA_TRANSPORT_VER_FAIL:
380                 err_str = "OTA transport verion is too old";
381                 tmp_status = OTA_REPORT_UPGRADE_ERR;
382                 break;
383             case OTA_TRANSPORT_PAR_FAIL:
384                 err_str = "OTA transport parse failed";
385                 tmp_status = OTA_REPORT_UPGRADE_ERR;
386                 break;
387             case OTA_DOWNLOAD_INIT_FAIL:
388                 err_str = "OTA download init failed";
389                 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
390                 break;
391             case OTA_DOWNLOAD_HEAD_FAIL:
392                 err_str = "OTA download header failed";
393                 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
394                 break;
395             case OTA_DOWNLOAD_CON_FAIL:
396                 err_str = "OTA download connect failed";
397                 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
398                 break;
399             case OTA_DOWNLOAD_REQ_FAIL:
400                 err_str = "OTA download request failed";
401                 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
402                 break;
403             case OTA_DOWNLOAD_RECV_FAIL:
404                 err_str = "OTA download receive failed";
405                 tmp_status = OTA_REPORT_DOWNLOAD_ERR;
406                 break;
407             case OTA_VERIFY_MD5_FAIL:
408                 err_str = "OTA verfiy MD5 failed";
409                 tmp_status = OTA_REPORT_VERIFY_ERR;
410                 break;
411             case OTA_VERIFY_SHA2_FAIL:
412                 err_str = "OTA verfiy SHA256 failed";
413                 tmp_status = OTA_REPORT_VERIFY_ERR;
414                 break;
415             case OTA_VERIFY_RSA_FAIL:
416                 err_str = "OTA verfiy RSA failed";
417                 tmp_status = OTA_REPORT_VERIFY_ERR;
418                 break;
419             case OTA_VERIFY_IMAGE_FAIL:
420                 err_str = "OTA verfiy image failed";
421                 tmp_status = OTA_REPORT_VERIFY_ERR;
422                 break;
423             case OTA_UPGRADE_WRITE_FAIL:
424                 err_str = "OTA upgrade write failed";
425                 tmp_status = OTA_REPORT_BURN_ERR;
426                 break;
427             case OTA_UPGRADE_FW_SIZE_FAIL:
428                 err_str = "OTA upgrade FW too big";
429                 tmp_status = OTA_REPORT_BURN_ERR;
430                 break;
431             case OTA_CUSTOM_CALLBAK_FAIL:
432                 err_str = "OTA register callback failed";
433                 tmp_status = OTA_REPORT_BURN_ERR;
434                 break;
435             case OTA_MCU_INIT_FAIL:
436                 err_str = "OTA MCU init failed";
437                 tmp_status = OTA_REPORT_BURN_ERR;
438                 break;
439             case OTA_MCU_VERSION_FAIL:
440                 err_str = "OTA MCU init failed";
441                 tmp_status = OTA_REPORT_BURN_ERR;
442                 break;
443             case OTA_MCU_NOT_READY:
444                 err_str = "OTA MCU not ready";
445                 tmp_status = OTA_REPORT_BURN_ERR;
446                 break;
447             case OTA_MCU_REBOOT_FAIL:
448                 err_str = "OTA MCU fail to reboot";
449                 tmp_status = OTA_REPORT_BURN_ERR;
450                 break;
451             case OTA_MCU_HEADER_FAIL:
452                 err_str = "OTA MCU header error";
453                 tmp_status = OTA_REPORT_BURN_ERR;
454                 break;
455             case OTA_MCU_UPGRADE_FAIL:
456                 err_str = "OTA MCU upgrade fail";
457                 tmp_status = OTA_REPORT_BURN_ERR;
458                 break;
459             case OTA_INVALID_PARAMETER:
460                 err_str = "OTA invalid parameter";
461                 tmp_status = OTA_REPORT_BURN_ERR;
462                 break;
463             default:
464                 err_str = "OTA undefined failed";
465                 tmp_status = OTA_REPORT_UPGRADE_ERR;
466                 break;
467         }
468     }
469     if (strncmp(ctx->module_name, "default", strlen("default")) == 0) {
470         ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"step\": \"%d\",\"desc\":\"%s\"}}", 1, tmp_status, err_str);
471     } else {
472         ret = ota_snprintf(msg, OTA_MSG_LEN - 1, "{\"id\":%d,\"params\":{\"step\": \"%d\",\"desc\":\"%s\",\"module\":\"%s\"}}", 1, tmp_status, err_str, ctx->module_name);
473     }
474     if (ret < 0) {
475         return OTA_TRANSPORT_INT_FAIL;
476     }
477     ret = ota_mqtt_publish(ctx->mqtt_client, "progress", msg, ctx->pk, ctx->dn);
478     if (ret < 0) {
479         OTA_LOG_E("report status failed!");
480         return OTA_TRANSPORT_INT_FAIL;
481     }
482     return ret;
483 }
484 
485