/* * Copyright (c) @CompanyNameMagicTag 2021-2021. All rights reserved. * Description: transmit data * This file should be changed only infrequently and with great care. */ #include "transmit_src.h" #include "transmit_dst.h" #include "transmit_st.h" #include "transmit_item.h" #include "transmit_send_recv_pkt.h" #include "transmit_write_read.h" #include "dfx_feature_config.h" #if CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES #include "dfx_file_operation.h" #endif #include "transmit_debug.h" #include "transmit_cmd_id.h" #include "string.h" #include "securec.h" #include "zdiag_adapt_layer.h" #include "errcode.h" STATIC uint32_t transmit_data_read(transmit_item_t *item, uint32_t offset, uint8_t *buf, uint32_t size) { transmit_read_hook read_handler = (transmit_read_hook)item->write_read; return (uint32_t)read_handler(item->usr_wr_data, offset, buf, size); } /* 作为源端(读取数据并发送数据的一端)读取并发送数据 */ STATIC errcode_t transmit_process_data_request_one(transmit_item_t *item, uint32_t offset, uint32_t size, diag_option_t *option, bool down_machine) { transmit_data_reply_pkt_t *pkt = NULL; uint32_t data_size; uint32_t tlv_ext_len; uint32_t pkt_size; int32_t send_size = 0; int32_t left_size = (int32_t)size; int32_t read_size, readed_size; uint16_t block_size = (item->data_block_size == 0) ? DEFAULT_TRANSMIT_BLOCK_SIZE : item->data_block_size; transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, sizeof(transmit_pkt_tlv_t) + sizeof(uint16_t) + sizeof(transmit_data_reply_pkt_t) + block_size); if (tlv == NULL) { return ERRCODE_MALLOC; } while ((left_size) != 0) { read_size = uapi_min(left_size, block_size); data_size = (uint32_t)sizeof(transmit_data_reply_pkt_t) + (uint32_t)read_size; tlv_ext_len = transmit_get_tlv_ext_len(data_size); pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + tlv_ext_len + data_size; tlv->type = transmit_build_tlv_type(1, 1); tlv->len = transmit_build_tlv_len(data_size); if (tlv_ext_len > 0) { (void)memcpy_s(tlv->data, tlv_ext_len, ((uint8_t *)&data_size), tlv_ext_len); } pkt = (transmit_data_reply_pkt_t *)((uint8_t *)tlv + sizeof(transmit_pkt_tlv_t) + tlv_ext_len); (void)memset_s(pkt->data, (uint32_t)read_size, 0, (uint32_t)read_size); readed_size = (int32_t)transmit_data_read(item, offset + send_size, pkt->data, (uint32_t)read_size); if (readed_size <= 0) { dfx_log_err("[ERR][transmit src] read data failed!, offset = 0x%x, read_size = %d readed_size = %d\r\n", offset + send_size, read_size, readed_size); transmit_send_failed_pkt(item->transmit_id, &item->option, item->down_machine); goto end; } pkt->transmit_id = item->transmit_id; pkt->offset = offset + (uint32_t)send_size; pkt->size = (uint32_t)readed_size; transmit_send_packet(DIAG_CMD_ID_TRANSMIT_REPLY, (uint8_t *)tlv, pkt_size, option, down_machine); left_size -= readed_size; send_size += readed_size; } end: transmit_item_free_pkt_buf(item, (void *)tlv); return ERRCODE_SUCC; } /* 作为源端(读取数据并发送数据的一端)发送NEGOTIATE(协商)ACK帧 */ STATIC void transmit_src_item_send_negotiate_ack(transmit_item_t *item) { uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_negotiate_ack_pkt_t); transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size); if (tlv == NULL) { return; } tlv->type = transmit_build_tlv_type(1, 2); /* the type is assigned 2 in ack command */ tlv->len = transmit_build_tlv_len(sizeof(transmit_negotiate_ack_pkt_t)); transmit_negotiate_ack_pkt_t *pkt = (transmit_negotiate_ack_pkt_t *)tlv->data; (void)memset_s((uint8_t *)pkt, sizeof(transmit_negotiate_ack_pkt_t), 0, sizeof(transmit_negotiate_ack_pkt_t)); pkt->transmit_id = item->transmit_id; pkt->data_block_number = item->data_block_number; pkt->data_block_size = item->data_block_size; pkt->info_size = 0; (void)transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NEGOTIATE, (uint8_t *)tlv, pkt_size, &item->option, item->down_machine); transmit_item_free_pkt_buf(item, (void *)tlv); } STATIC void transmit_src_item_send_negotiate(transmit_item_t *item) { uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_negotiate_pkt_t); transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size); if (tlv == NULL) { return; } tlv->type = transmit_build_tlv_type(1, 1); tlv->len = transmit_build_tlv_len(sizeof(transmit_negotiate_pkt_t)); transmit_negotiate_pkt_t *pkt = (transmit_negotiate_pkt_t *)tlv->data; (void)memset_s((uint8_t *)pkt, sizeof(transmit_negotiate_pkt_t), 0, sizeof(transmit_negotiate_pkt_t)); pkt->transmit_id = item->transmit_id; pkt->src_send = 0; pkt->transmit_type = item->remote_type; pkt->total_size = item->total_size; (void)transmit_send_packet(DIAG_CMD_ID_TRANSMIT_NEGOTIATE, (uint8_t *)tlv, pkt_size, &item->option, item->down_machine); transmit_item_free_pkt_buf(item, (void *)tlv); } STATIC transmit_item_t *transmit_src_item_init(uint32_t transmit_id) { transmit_item_t *item = transmit_item_match_id(transmit_id); if (item != NULL) { transmit_item_disable(item, 0); transmit_item_deinit(item); } item = transmit_item_init(transmit_id); return item; } STATIC void transmit_src_item_init_info(transmit_item_t *item, uint16_t transmit_type, uint32_t total_size, bool re_trans) { unused(re_trans); transmit_item_init_permanent(item, false); transmit_item_init_local_start(item, false); transmit_item_init_local_src(item, true); transmit_item_init_remote_type(item, transmit_type); switch (transmit_type) { case TRANSMIT_TYPE_READ_FILE: case TRANSMIT_TYPE_DUMP: case TRANSMIT_TYPE_READ_MEMORY: transmit_item_init_local_type(item, TRANSMIT_LOCAL_TYPE_READ_FILE); break; case TRANSMIT_TYPE_READ_FLASH: transmit_item_init_local_type(item, TRANSMIT_LOCAL_TYPE_READ_DATA); break; default: break; } transmit_item_init_read_handler(item, file_read_data, (uintptr_t)item); transmit_item_init_total_size(item, total_size); } STATIC errcode_t transmit_src_item_start_negotiate_ack(transmit_item_t *item) { if (transmit_item_init_is_success(item) == false) { transmit_item_deinit(item); dfx_log_err("[ERR][transmit src]init is failed\r\n"); return ERRCODE_FAIL; } #if (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_YES) item->file_fd = dfx_file_open_for_read(item->file_name); if (item->file_fd < 0) { dfx_log_err("[ERR][transmit src]file : %s open failed, fd = %d\r\n", item->file_name, item->file_fd); transmit_send_failed_pkt(item->transmit_id, &item->option, item->down_machine); item->file_fd = 0; transmit_item_deinit(item); return ERRCODE_FAIL; } #endif transmit_item_enable(item); if (item->data_block_number == DEFAULT_TRANSMIT_BLOCK_NUMBER && item->data_block_size == DEFAULT_TRANSMIT_BLOCK_SIZE) { transmit_src_item_send_negotiate(item); } else { transmit_src_item_send_negotiate_ack(item); } return ERRCODE_SUCC; } /* 作为源端(读取数据并发送数据的一端)处理REQUEST帧 */ errcode_t transmit_src_item_process_data_request_frame(transmit_data_request_pkt_t *request_pkt, diag_option_t *option, bool from_upper_machine) { uint32_t i; uint32_t cur_time = dfx_get_cur_second(); transmit_item_t *item = transmit_item_match_id(request_pkt->transmit_id); if (item == NULL) { dfx_log_err("[ERR][transmit src]request match id failed!, id = 0x%x\r\n", request_pkt->transmit_id); return transmit_send_invalid_id(request_pkt->transmit_id, option, from_upper_machine); } item->last_rcv_pkt_time = cur_time; item->last_send_pkt_time = cur_time; if ((item->local_start != 0) && (item->step == TRANSMIT_STEP_START)) { item->step = TRANSMIT_STEP_TRANSMIT; } for (i = 0; i < request_pkt->cnt; i++) { transmit_process_data_request_one(item, request_pkt->item[i].offset, request_pkt->item[i].size, option, from_upper_machine); } return ERRCODE_SUCC; } /* 作为源端(读取数据并发送数据的一端)处理START帧 */ errcode_t transmit_src_item_process_start_frame(transmit_start_pkt_t *start_pkt, diag_option_t *option, bool from_upper_machine) { dfx_assert(start_pkt); transmit_save_info_t *file_info = (transmit_save_info_t *)start_pkt->info; transmit_save_data_info_t *data_info = (transmit_save_data_info_t *)start_pkt->info; transmit_item_t *item = transmit_src_item_init(start_pkt->transmit_id); if (item == NULL) { dfx_log_err("[ERR][transmit src]init failed\r\n"); return ERRCODE_FAIL; } switch (start_pkt->transmit_type) { case TRANSMIT_TYPE_READ_FILE: case TRANSMIT_TYPE_DUMP: case TRANSMIT_TYPE_READ_MEMORY: transmit_src_item_init_info(item, start_pkt->transmit_type, start_pkt->total_size, start_pkt->re_trans); transmit_item_init_file_name(item, file_info->file_name, file_info->name_size); break; case TRANSMIT_TYPE_READ_FLASH: transmit_src_item_init_info(item, start_pkt->transmit_type, start_pkt->total_size, start_pkt->re_trans); transmit_item_init_local_bus_addr(item, data_info->start_addr); break; default: break; } transmit_item_init_option(item, option); transmit_item_init_down_machine(item, from_upper_machine); transmit_item_init_data_block_size(item, DEFAULT_TRANSMIT_BLOCK_SIZE); transmit_item_init_data_block_number(item, DEFAULT_TRANSMIT_BLOCK_NUMBER); return transmit_src_item_start_negotiate_ack(item); } /* 作为源端(读取数据并发送数据的一端)处理START帧 */ errcode_t transmit_src_item_process_negotiate_frame(transmit_negotiate_pkt_t *negotiate_pkt, diag_option_t *option, bool from_upper_machine) { dfx_assert(negotiate_pkt); transmit_save_info_t *file_info = (transmit_save_info_t *)negotiate_pkt->info; transmit_item_t *item = transmit_src_item_init(negotiate_pkt->transmit_id); if (item == NULL) { dfx_log_err("[ERR][transmit src]init failed\r\n"); return ERRCODE_FAIL; } transmit_src_item_init_info(item, negotiate_pkt->transmit_type, negotiate_pkt->total_size, negotiate_pkt->re_trans); transmit_item_init_option(item, option); transmit_item_init_down_machine(item, from_upper_machine); transmit_item_init_file_name(item, file_info->file_name, file_info->name_size); transmit_item_init_data_block_size(item, negotiate_pkt->data_block_size); transmit_item_init_data_block_number(item, negotiate_pkt->data_block_number); return transmit_src_item_start_negotiate_ack(item); } #if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES) STATIC void zdiag_save_file_send_start_pkt(transmit_item_t *item) { transmit_start_pkt_t *start_pkt = NULL; transmit_save_info_t *save_file_info = NULL; uint32_t name_size = 0; uint32_t info_size = 0; if (item->file_name != NULL) { name_size = (uint32_t)strlen(item->file_name) + 1; info_size = (uint32_t)sizeof(transmit_save_info_t) + name_size; } uint32_t data_size = (uint32_t)sizeof(transmit_start_pkt_t) + info_size; uint32_t tlv_ext_len = transmit_get_tlv_ext_len(data_size); uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + tlv_ext_len + data_size; transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size); if (tlv == NULL) { goto end; } tlv->type = transmit_build_tlv_type(1, 1); tlv->len = transmit_build_tlv_len(data_size); if (tlv_ext_len > 0) { (void)memcpy_s(tlv->data, tlv_ext_len, ((uint8_t *)&data_size), tlv_ext_len); } start_pkt = (transmit_start_pkt_t *)((uint8_t *)tlv + sizeof(transmit_pkt_tlv_t) + tlv_ext_len); if (item->file_name != NULL) { save_file_info = (transmit_save_info_t *)start_pkt->info; save_file_info->name_size = (uint16_t)name_size; memcpy_s(save_file_info->file_name, name_size, item->file_name, name_size); } start_pkt->transmit_id = item->transmit_id; start_pkt->transmit_type = item->remote_type; start_pkt->total_size = item->total_size; start_pkt->info_size = info_size; start_pkt->pad = 0; start_pkt->re_trans = item->re_trans; start_pkt->src_send = 1; start_pkt->struct_ver = 0; transmit_send_packet(DIAG_CMD_ID_TRANSMIT_START, (uint8_t *)tlv, pkt_size, &item->option, item->down_machine); end: transmit_item_free_pkt_buf(item, tlv); return; } #endif void transmit_src_item_send_start_frame(transmit_item_t *item, uint32_t cur_time) { #if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES) switch (item->remote_type) { case TRANSMIT_TYPE_SAVE_FILE: case TRANSMIT_TYPE_SAVE_OTA_IMG: case TRANSMIT_TYPE_WRITE_MEMORY: case TRANSMIT_TYPE_WRITE_FLASH: zdiag_save_file_send_start_pkt(item); break; default: break; } #endif item->last_send_pkt_time = cur_time; return; } void transmit_src_item_process_timer(transmit_item_t *item, uint32_t cur_time) { uint32_t out_time = item->last_rcv_pkt_time + TRANSMIT_OUT_TIME; if (cur_time > out_time) { transmit_item_finish(item, TRANSMIT_DISABLE_TIME_OUT); #if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES) transmit_result_hook result_hook = (transmit_result_hook)item->result_hook; if (result_hook != NULL && item->local_start == true) { result_hook(false, (uintptr_t)NULL); } #endif return; } #if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES) uint32_t retry_time = uapi_min(item->last_send_pkt_time, item->last_rcv_pkt_time) + TRANSMIT_RETRY_TIME; if ((item->local_start != 0) && (item->step == TRANSMIT_STEP_START) && (cur_time > retry_time)) { /* send pkt and modify retry time */ transmit_src_item_send_start_frame(item, cur_time); } #endif } #if (CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE == DFX_YES) /* 作为上位机源端(接收数据端)发送START帧 */ errcode_t transmit_src_send_file_start(transmit_type_t transmit_type, diag_addr dst, uint32_t total_size, bool re_transmit, transmit_result_hook handler) { diag_option_t option = DIAG_OPTION_INIT_VAL; option.peer_addr = dst; switch (transmit_type) { case TRANSMIT_TYPE_SAVE_FILE: case TRANSMIT_TYPE_SAVE_OTA_IMG: case TRANSMIT_TYPE_WRITE_MEMORY: case TRANSMIT_TYPE_WRITE_FLASH: break; default: return ERRCODE_INVALID_PARAM; } transmit_item_t *item = transmit_item_init(0); if (item == NULL) { return ERRCODE_FAIL; } transmit_item_init_permanent(item, false); transmit_item_init_local_start(item, true); transmit_item_init_local_src(item, true); transmit_item_init_remote_type(item, transmit_type); transmit_item_init_local_type(item, TRANSMIT_LOCAL_TYPE_READ_FILE); transmit_item_init_read_handler(item, file_read_data, (uintptr_t)item); transmit_item_init_option(item, &option); transmit_item_init_down_machine(item, false); transmit_item_init_total_size(item, total_size); transmit_item_init_result_handler(item, handler, (uintptr_t)item); transmit_item_init_re_trans(item, re_transmit); if (transmit_item_init_is_success(item) == false) { transmit_item_deinit(item); return ERRCODE_FAIL; } transmit_item_enable(item); return ERRCODE_SUCC; } /* 作为上位机源端(接收数据端)发送STOP帧 */ errcode_t transmit_src_send_file_stop(transmit_type_t transmit_type, diag_addr dst) { errcode_t ret; diag_option_t option = DIAG_OPTION_INIT_VAL; option.peer_addr = dst; transmit_item_t *item = transmit_item_match_type_and_dst(transmit_type, dst); if (item == NULL) { dfx_log_debug("stop match id failed!, type = 0x%x, dst = 0x%x\r\n", transmit_type, dst); return transmit_send_invalid_id(0, &option, false); } transmit_item_finish(item, TRANSMIT_DISABLE_USER_STOP); uint32_t pkt_size = (uint32_t)sizeof(transmit_pkt_tlv_t) + (uint32_t)sizeof(transmit_stop_pkt_t); transmit_pkt_tlv_t *tlv = transmit_item_get_pkt_buf(item, pkt_size); tlv->type = transmit_build_tlv_type(1, 2); /* the type is assigned 2 in ack command */ tlv->len = transmit_build_tlv_len(sizeof(transmit_stop_pkt_t)); transmit_stop_pkt_t *stop_pkt = (transmit_stop_pkt_t *)tlv->data; stop_pkt->transmit_id = item->transmit_id; stop_pkt->reason = ERRCODE_SUCC; ret = transmit_send_packet(DIAG_CMD_ID_TRANSMIT_STOP, (uint8_t *)tlv, pkt_size, &option, false); transmit_item_free_pkt_buf(item, tlv); return ret; } #endif