| #include <sys/socket.h> |
| #include <sys/un.h> |
| #include <sys/stat.h> |
| #include <sys/uio.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <sys/prctl.h> |
| |
| #include <libubox/blob.h> |
| #include <libubox/uloop.h> |
| #include <libubox/usock.h> |
| #include <libubox/list.h> |
| #include <libubus.h> |
| #if 0 |
| #include <curl/curl.h> |
| #include <curl/easy.h> |
| #endif |
| #include <uci.h> |
| |
| #include <sys/ioctl.h> |
| #include <mtd/mtd-user.h> |
| |
| #include "libhttpclient/libhttpclient.h" |
| #include "otad.h" |
| |
| #ifdef CONFIG_AB_SYSTEM |
| #define MEMLOCKPRIV _IO('M', 25) |
| #define MEMUNLOCKPRIV _IO('M', 26) |
| |
| static int complete_read(int fd, char *buf, int size); |
| static int complete_write(int fd, char *buf, int size); |
| #include "tim.h" |
| |
| #if !defined(CONFIG_AB_SYSTEM_DFOTA) |
| #include "tim.c" |
| #endif |
| |
| #include "getfotav.c" |
| |
| #if 0 |
| /* support dfota upgrade */ |
| #define CONFIG_AB_SYSTEM_DFOTA |
| #endif |
| |
| /* the main bootloader */ |
| const char *tmp_obm_main_file = "/tmp/obm_main.bin"; |
| const char *tmp_timh_main_file = "/tmp/timh_main.bin"; |
| /* the backup bootloader */ |
| const char *tmp_obm_bk_file = "/tmp/obm_bk.bin"; |
| const char *tmp_timh_bk_file = "/tmp/timh_bk.bin"; |
| /* the target timh for the specific ddr */ |
| const char *tmp_timh_main_target_file = "/tmp/timh_main_target.bin"; |
| const char *tmp_timh_bk_target_file = "/tmp/timh_bk_target.bin"; |
| |
| static unsigned int obm_real_size = 0; |
| #endif |
| |
| #define OTA_MAX_STRING_LEN 128 |
| #define OEMDDENTIFIER 0x4F454D44 /* "OEMD" */ |
| |
| enum { |
| UPDATE_STATE_IDLE, |
| UPDATE_STATE_UPDATING, |
| UPDATE_STATE_UPDATED, |
| UPDATE_STATE_FAILED, |
| }; |
| static int update_state = UPDATE_STATE_IDLE; |
| static int update_oemd; |
| |
| struct version_info { |
| char version[OTA_MAX_STRING_LEN]; |
| char url[OTA_MAX_STRING_LEN]; |
| char * release_note; |
| }; |
| |
| #ifdef CONFIG_AB_SYSTEM |
| #define MIN_RLS_VERSION 846 |
| |
| #if !defined(CONFIG_AB_SYSTEM_DFOTA) |
| static int upgrade_precheck(char *fotav) |
| { |
| char *p; |
| int ver; |
| |
| OTA_DEBUG("%s: %s\n", __func__, fotav); |
| p = strstr(fotav, "_rls"); |
| if (!p) { |
| OTA_ERR("not found rls version.\n", __func__); |
| return -1; |
| } |
| |
| p += 4; |
| ver = atoi(p); |
| if (ver < MIN_RLS_VERSION) { |
| OTA_DEBUG("%s: don't support upgrade to rls%d, min: rls%d\n", __func__, ver, MIN_RLS_VERSION); |
| return -1; |
| } |
| |
| /* support upgrade */ |
| return 0; |
| } |
| #endif |
| |
| static int complete_read(int fd, char *buf, int size); |
| static int complete_write(int fd, char *buf, int size); |
| |
| // Change by liubin |
| #define MAX_MTD_PARTITION_CNT 35 |
| #define FBF_FILE_SECTOR_SIZE (4*1024) |
| struct image_mtd_info { |
| char name[32]; |
| char dev[16]; |
| unsigned int flash_start_offset; |
| unsigned int size; |
| unsigned int erasesize; |
| unsigned int flag; |
| }; |
| |
| enum { |
| SYSTEM_SINGLE = 0, |
| SYSTEM_A = 'a', |
| SYSTEM_B = 'b' |
| }; |
| |
| static int gInActiveSystem = SYSTEM_SINGLE; |
| static int gSystemHasRollbackFlag = 0; |
| #endif |
| |
| struct ota_server { |
| char server_url[OTA_MAX_STRING_LEN]; |
| int download_immediately; |
| int progress_notify; |
| int interval; |
| int first_interval; |
| unsigned int fbf_length; |
| unsigned int block_size; |
| unsigned int pagesize; |
| unsigned int emmc_block_size; /* 512B */ |
| unsigned int fbf_addr; |
| char mtd_asrflag[64]; |
| #ifdef CONFIG_AB_SYSTEM |
| int mtd_cnt; |
| struct image_mtd_info image_mtd_info[MAX_MTD_PARTITION_CNT]; |
| unsigned int cpuid; |
| unsigned int ddrid; |
| unsigned int max_timh_size; |
| unsigned int fotav_offset_in_fbf; |
| char fotav[128]; |
| #endif |
| char mtd_fbf[300]; |
| struct version_info ver; |
| }; |
| struct ota_server server_cfg; |
| |
| static struct ubus_context *ctx; |
| static struct blob_buf b; |
| static struct ubus_object ota_object; |
| |
| enum { |
| DOWNLOAD_TYPE, |
| DOWNLOAD_FILE_SIZE, |
| DOWNLOAD_URL, |
| DOWNLOAD_NAME, |
| DOWNLOAD_PSW, |
| DOWNLOAD_SYNC, |
| DOWNLOAD_SEGMENT_SIZE, |
| __DOWNLOAD_MAX |
| }; |
| |
| static const struct blobmsg_policy download_policy[] = { |
| [DOWNLOAD_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, |
| [DOWNLOAD_FILE_SIZE] = { .name = "size", .type = BLOBMSG_TYPE_INT32 }, |
| [DOWNLOAD_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING }, |
| [DOWNLOAD_NAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING }, |
| [DOWNLOAD_PSW] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, |
| [DOWNLOAD_SYNC] = { .name = "sync", .type = BLOBMSG_TYPE_INT32 }, |
| [DOWNLOAD_SEGMENT_SIZE] = { .name = "segment_size", .type = BLOBMSG_TYPE_INT32 }, |
| }; |
| |
| #if 0 |
| static size_t curl_cb(void *buffer, size_t size, size_t nmemb, void *stream) |
| { |
| //OTA_ERR(" response: %s(%d:%d)\n", (char *)buffer, size, nmemb); |
| OTA_ERR(" response:%d:%d\n", size, nmemb); |
| return size * nmemb; |
| } |
| #endif |
| // FBF file related definition |
| static int _ota_download_progress = 0; |
| static int ota_download_progress = 0; |
| char * fbf_version_string = NULL; |
| // Add by mbtk |
| int Download_flag = 0; |
| #define TR069_FBF_HEADER_SIZE 13 |
| #define DLCMD_IMAGE_TYPE_FIELD_BIT 4 |
| #define DLCMD_IMAGE_TYPE_FIELD_SIZE_BITS 4 |
| #define MAX_NUMBER_OF_FLASH_DEVICES_IN_MASTER_HEADER 4 |
| #define MAX_NUMBER_OF_FLASH_DEVICES_IN_DEVICE_HEADER 150 |
| #define BLOCK_DEVICE_SECTOR_SIZE (8*1024) |
| #define MAX_RESEVERD_LEN 4 |
| #define MAX_NUM_SKIP_BLOCKS 32 |
| #define UNIQUE_SIZE 24 |
| #define NUM_OF_SUPPORTED_FLASH_DEVS 4 |
| #define RSA_IMAGE_ID 0x52534149 |
| #define MINI_SIZE (128) |
| #define CHECKSUM_CACHE_SIZE (128) |
| #define FILE_VERIFY_RAM_SIZE (server_cfg.block_size) |
| |
| struct version_check_context { |
| char * url; |
| int size; |
| int used; |
| char version[OTA_MAX_STRING_LEN]; |
| }; |
| |
| typedef struct { |
| unsigned int Image_ID; |
| unsigned int Image_In_TIM; |
| unsigned int Flash_partition; |
| unsigned int Flash_erase_size; |
| unsigned int commands; |
| unsigned int First_Sector; |
| unsigned int length; |
| unsigned int Flash_Start_Address; |
| unsigned int reserve[MAX_RESEVERD_LEN]; |
| unsigned int ChecksumFormatVersion2; |
| } __attribute__((packed)) ImageStruct_11; |
| |
| typedef ImageStruct_11 * PImageStruct_11; |
| |
| typedef struct { |
| unsigned int Total_Number_Of_SkipBlocks; |
| unsigned int Size_of_Block[MAX_NUM_SKIP_BLOCKS]; |
| } SkipBlocksInfoStruct; |
| |
| typedef struct { |
| unsigned int EraseAll; |
| unsigned int ResetBBT; |
| unsigned int NandID; |
| unsigned int Reserved[MAX_RESEVERD_LEN - 1]; |
| SkipBlocksInfoStruct SkipBlocksInfoStruct; |
| } FlashOptStruct; |
| |
| typedef struct { |
| unsigned int DeviceFlags; |
| unsigned int DeviceParametes[16]; |
| FlashOptStruct FlashOpt; |
| unsigned int ProductionMode; // production mode |
| unsigned char OptValue; // choice: 0 - Not reset after download, 1 - Reset after download |
| unsigned char ChipID; |
| unsigned char BBCS_EN; |
| unsigned char CRCS_EN; |
| unsigned int Reserved[MAX_RESEVERD_LEN-2]; |
| unsigned int nOfImages; |
| ImageStruct_11 imageStruct_11[MAX_NUMBER_OF_FLASH_DEVICES_IN_MASTER_HEADER]; |
| } __attribute__((packed)) DeviceHeader_11; |
| |
| typedef DeviceHeader_11 * PDeviceHeader_11; |
| |
| typedef struct { |
| char Unique[UNIQUE_SIZE]; |
| unsigned short int Flash_Device_Spare_Area_Size[NUM_OF_SUPPORTED_FLASH_DEVS]; |
| unsigned short int Format_Version; |
| unsigned short int Size_of_Block; |
| unsigned int Bytes_To_Program; |
| unsigned int Bytes_To_Verify; |
| unsigned int Number_of_Bytes_To_Erase; |
| unsigned int Main_Commands; |
| unsigned int nOfDevices; |
| unsigned int DLerVeriosn; |
| unsigned int deviceHeaderOffset[MAX_NUMBER_OF_FLASH_DEVICES_IN_MASTER_HEADER]; |
| } __attribute__((packed)) MasterBlockHeader; |
| |
| typedef MasterBlockHeader * PMasterBlockHeader; |
| |
| struct imginfo_table { |
| unsigned int Img_Len; |
| unsigned int Img_Commands; |
| unsigned int Img_Start_Address; |
| unsigned int Img_Checksum; |
| unsigned int Flash_Start_Address; |
| unsigned int Flash_Erase_Size; |
| unsigned int Img_ID; |
| unsigned int Image_In_TIM; |
| #ifdef CONFIG_AB_SYSTEM |
| int fd; |
| char name[32]; |
| char dev[16]; |
| unsigned int Img_Remain_Len; |
| unsigned int cs; |
| unsigned int Block_Start_Address; |
| unsigned int partition_size; |
| int erased; |
| #endif |
| struct imginfo_table * next; |
| }; |
| |
| typedef struct imginfo_table ImginfoTable; |
| |
| enum { |
| HEADER, |
| CONTENT, |
| }; |
| |
| struct image_state { |
| struct imginfo_table * image_info; |
| struct image_state * next_image; |
| int result; |
| }; |
| |
| struct image_process_context { |
| ImginfoTable * image_info_table; |
| ImginfoTable * current_process; |
| unsigned int processed_cnt; |
| int state; |
| char * flash_cache; |
| int flash_cache_index; |
| int (*flash_cb)(struct image_process_context *, char *, int); |
| unsigned char * checksum_cache; |
| int checksum_cache_index; |
| unsigned int image_checksum; |
| int ota_download_notification_cnt; |
| struct image_state * image_state_list; |
| int download_result; |
| int fd; |
| int upgrade_method; |
| int dual_tim; |
| int same_tim; |
| int upgrade_bootloader; |
| }; |
| |
| typedef struct{ |
| unsigned int CurImageID; |
| unsigned int ImageType; |
| unsigned int ImageState; /* 1: new image is backed up, 0: not backed up */ |
| unsigned int ImageBkAddr; |
| unsigned int ImageBkLen; |
| unsigned int SegState; |
| unsigned int SegIndex; |
| unsigned int SegDestBkAddr; |
| unsigned int SegDestBkLen; |
| unsigned int PreTailAddr; |
| unsigned int PreTailLen; |
| unsigned int NextHeadAddr; |
| unsigned int NextHeadLen; |
| unsigned int NextSegWriteOffset; |
| unsigned int NextSegReadOffset; |
| unsigned int NextSegEraseOffset; |
| }SDfotaState, *pSDfotaState; |
| |
| struct DeviceHeader_11_tr069 { |
| unsigned int DeviceFlags; |
| unsigned int DeviceParameters[16]; /* Device Parameters, reserve 16 U32 here, will be defined depending on different devices */ |
| FlashOptStruct FlashOpt; |
| unsigned int ProductionMode; // production mode |
| unsigned char OptValue; // choice: 0 - Not reset after download, 1 - Reset after download |
| unsigned char ChipID; |
| unsigned char BBCS_EN; |
| unsigned char CRCS_EN; |
| unsigned int Reserved[MAX_RESEVERD_LEN-2]; |
| unsigned int nOfImages; /* number of images */ |
| ImageStruct_11 imageStruct_11[0]; /* array of image structs */ |
| } __attribute__((packed)); // Same as struct 'DeviceHeader_11' but the ImageStruct cnt is zero |
| |
| struct DDRT_STATE{ |
| unsigned int test_proc :1; //1: start, 0: done |
| unsigned int last_res :1; //1: fail, 0: pass |
| unsigned int total_times :15; |
| unsigned int fail_times :15; |
| }; |
| |
| typedef union{ |
| unsigned int value; |
| struct DDRT_STATE bits; |
| }DDRTestState, *pDDRTestState; |
| |
| struct tr069_firmware_flag { |
| unsigned int header; |
| unsigned int upgrade_flag; //1,upgrade; 2, backup boot |
| unsigned int fbf_flash_address; |
| unsigned int fbf_file_size; |
| unsigned int erase_psm; |
| unsigned int erase_psm_address; |
| unsigned int erase_psm_size; |
| unsigned int erase_fs; |
| unsigned int fs_erase_address; |
| unsigned int fs_erase_size; |
| unsigned int upgrade_method; //1,TR069; 2, SD; 3,WebUI |
| unsigned int UnlockKeyFlag; |
| unsigned int production_mode_flag; //for production mode |
| unsigned int eehP[2]; |
| unsigned int cpsr[2]; |
| unsigned int hawk[2]; |
| unsigned int imsd[2]; |
| unsigned int pipe[2]; |
| unsigned int fast[2]; |
| unsigned int apmf[2]; |
| unsigned int pid[2]; |
| unsigned int vid[2]; |
| unsigned int obmdl[2]; |
| unsigned int dlflag[2]; |
| unsigned int ramdump[2]; |
| unsigned int dfota_n_of_images; |
| unsigned int dfota_need_copy_only; |
| unsigned int dfota_conpy_len; |
| #ifdef CONFIG_AB_SYSTEM |
| unsigned int active_slot; /* prev active slot */ |
| unsigned int temp_active_slot; /* current active slot */ |
| unsigned int reboot_cnt; |
| unsigned int synced; |
| unsigned int rsvd[16]; |
| #endif |
| unsigned int nocp[2]; |
| unsigned int TrustBootStatus; |
| char mversion[128]; |
| SDfotaState SDfotaInfo; |
| unsigned int ref_count; |
| unsigned int flag_len; |
| unsigned int version; |
| unsigned int DDR_ID; |
| unsigned int Flash_ID; |
| unsigned int cplog[2]; |
| DDRTestState ddrt_state; |
| unsigned int svc_state; |
| char MVersion_B[128]; /* only use for AB system */ |
| unsigned int Reserved[68]; /* reserved for asr */ |
| unsigned int ReservedForCustomer[35]; /* reserved for customer */ |
| /* reserve to make the ASR_Flag length as 1KB */ |
| |
| unsigned int crc; |
| /* NOTICE !!! |
| * If you change this structure, you must also sync the change to OBM/Uboot/OTA/Telephony |
| * OBM: obm/Common/Misc/asr_flag.h |
| * Uboot: uboot/board/Marvell/common/asr_flag.h |
| * OTA: services/ota/otad.c |
| * Telephony: lte_telephony/apps/cp_load/cploader.h |
| * If add a new member to this structure, must decrease the size of Reserved[] |
| */ |
| }; |
| |
| #define ASRFLAG_HEADER 0x464F5441 |
| |
| /* ASR Flag version history |
| * 1.0.0.1: support dual asr flag |
| * 1.0.0.2: support asr flag crc |
| */ |
| #define ASRFLAG_VERSION_LEGACY 0xFFFFFFFF |
| #define ASRFLAG_VERSION_DAF 0x31303031 |
| #define ASRFLAG_VERSION_CRC 0x31303032 |
| #define ASRFLAG_VERSION ASRFLAG_VERSION_CRC |
| |
| struct download_timer_context { |
| int type; |
| int size; |
| int segment_size; |
| char * url; |
| char * username; |
| char * pwd; |
| int file_size; |
| int received_size; |
| }; |
| |
| struct download_timer_context download_method_ctx = {0}; |
| static struct tr069_firmware_flag gAsrFlag; |
| |
| static int asrflag_daf_enabled(struct tr069_firmware_flag * p_asrflag) |
| { |
| if(p_asrflag->version != ASRFLAG_VERSION_LEGACY && |
| p_asrflag->version >= ASRFLAG_VERSION_DAF) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int asrflag_crc_enabled(struct tr069_firmware_flag * p_asrflag) |
| { |
| if(p_asrflag->version != ASRFLAG_VERSION_LEGACY && |
| p_asrflag->version >= ASRFLAG_VERSION_CRC) |
| return 1; |
| |
| return 0; |
| } |
| |
| static unsigned int malbrain_crc32(unsigned int crcu32, const unsigned char *ptr, unsigned int buf_len) |
| { |
| static const unsigned int s_crc32[16] = { |
| 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
| 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
| }; |
| if (!ptr) |
| return 0; |
| crcu32 = ~crcu32; |
| while (buf_len--) |
| { |
| unsigned char b = *ptr++; |
| crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; |
| crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; |
| } |
| return ~crcu32; |
| } |
| |
| static void asrflag_update_crc(struct tr069_firmware_flag * p_asrflag) |
| { |
| unsigned int crc_len, crc_val; |
| crc_len = sizeof(struct tr069_firmware_flag) - 4; /* 4 bytes is CRC itself */ |
| |
| crc_val = malbrain_crc32(0, (unsigned char *)p_asrflag, crc_len); |
| |
| p_asrflag->crc = crc_val; |
| |
| return; |
| } |
| |
| static int asrflag_is_invalid(struct tr069_firmware_flag * p_asrflag) |
| { |
| unsigned int crc_len, crc_val; |
| |
| if(p_asrflag->header != ASRFLAG_HEADER) |
| return 1; |
| |
| if(!asrflag_crc_enabled(p_asrflag)) |
| return 0; |
| |
| crc_len = sizeof(struct tr069_firmware_flag) - 4; /* 4 bytes is CRC itself */ |
| crc_val = malbrain_crc32(0, (unsigned char *)p_asrflag, crc_len); |
| |
| if(p_asrflag->crc != crc_val) { |
| OTA_ERR("asr flag mismatch: 0x%x 0x%x\n", crc_val, p_asrflag->crc); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static int get_asr_flag(struct tr069_firmware_flag *p_asrflag) |
| { |
| int fd = 0, ret = 0; |
| unsigned int step = 0, offset = 0, flaglen = 0; |
| struct tr069_firmware_flag *main_asrflag = NULL; |
| struct tr069_firmware_flag *backup_asrflag = NULL; |
| flaglen = sizeof(struct tr069_firmware_flag); |
| |
| main_asrflag = malloc(flaglen); |
| if(main_asrflag == NULL) { |
| OTA_ERR("Fail to malloc\n"); |
| return -1; |
| } |
| |
| fd = open(server_cfg.mtd_asrflag, O_RDONLY); |
| if (fd < 0) { |
| free(main_asrflag); |
| OTA_ERR("Fatal error: can't open asr flag %s\n", server_cfg.mtd_asrflag); |
| return -1; |
| } |
| |
| if (read(fd, main_asrflag, flaglen) < 0) |
| goto error; |
| if ( asrflag_is_invalid(main_asrflag) ) { |
| backup_asrflag = main_asrflag; |
| main_asrflag = NULL; |
| |
| step = (server_cfg.block_size)?server_cfg.block_size:0x1000; |
| offset = step; |
| |
| while (1) { |
| if(lseek(fd, offset, SEEK_SET) < 0 ) |
| goto error; |
| ret = read(fd, backup_asrflag, flaglen); |
| if(ret < 0) |
| goto error; |
| |
| if(ret == 0 || !asrflag_is_invalid(backup_asrflag) ) |
| break; |
| |
| offset += step; |
| } |
| |
| /* can't find valid backup ASR Flag */ |
| if ( asrflag_is_invalid(backup_asrflag) ) { |
| free(backup_asrflag); backup_asrflag = NULL; |
| } |
| } else { |
| if( asrflag_daf_enabled(main_asrflag) ) { |
| backup_asrflag = malloc(flaglen); |
| if(backup_asrflag != NULL) |
| { |
| if(lseek(fd, main_asrflag->flag_len, SEEK_SET) < 0) |
| goto error; |
| |
| if (read(fd, backup_asrflag, flaglen) < 0) |
| goto error; |
| |
| if( asrflag_is_invalid(backup_asrflag) ) |
| { |
| free(backup_asrflag); |
| backup_asrflag = NULL; |
| } |
| } |
| } else { |
| /* old way which doesn't support backup */ |
| memcpy(p_asrflag, main_asrflag, flaglen); |
| close(fd); |
| free(main_asrflag); |
| return 0; |
| } |
| } |
| |
| if(main_asrflag == NULL && backup_asrflag == NULL) { |
| goto error; |
| } else if(main_asrflag == NULL) { |
| memcpy(p_asrflag, backup_asrflag, flaglen); |
| } else if (backup_asrflag == NULL) { |
| memcpy(p_asrflag, main_asrflag, flaglen); |
| } else { |
| if(memcmp(main_asrflag, backup_asrflag, flaglen)) |
| OTA_ERR("Main asr flag mismatch with backup\n"); |
| if(backup_asrflag->ref_count > main_asrflag->ref_count) |
| memcpy(p_asrflag, backup_asrflag, flaglen); |
| else |
| memcpy(p_asrflag, main_asrflag, flaglen); |
| } |
| |
| close(fd); |
| if(main_asrflag) free(main_asrflag); |
| if(backup_asrflag) free(backup_asrflag); |
| return 0; |
| |
| error: |
| close(fd); |
| if(main_asrflag) free(main_asrflag); |
| if(backup_asrflag) free(backup_asrflag); |
| return -1; |
| } |
| |
| static int write_asr_flag(struct tr069_firmware_flag *p_asrflag) |
| { |
| unsigned int flaglen = 0; |
| int n = 0; |
| int fd = open(server_cfg.mtd_asrflag, O_RDWR); |
| if (fd < 0) { |
| OTA_ERR("Fatal error: can't open asr flag %s\n", server_cfg.mtd_asrflag); |
| return -1; |
| } |
| |
| flaglen = sizeof(struct tr069_firmware_flag); |
| if (p_asrflag->ref_count ++ == 0xFFFFFFFF) |
| p_asrflag->ref_count = 0; |
| |
| asrflag_update_crc(p_asrflag); |
| |
| n = write(fd, p_asrflag, flaglen); |
| if (n != flaglen) { |
| OTA_ERR("Fatal error: write %d bytes(expect %d) to asr flag\n", n, sizeof(gAsrFlag)); |
| close(fd); |
| return -1; |
| } |
| |
| if( asrflag_daf_enabled(p_asrflag) ) { |
| lseek(fd, p_asrflag->flag_len, SEEK_SET); |
| |
| n = write(fd, p_asrflag, flaglen); |
| if (n != flaglen) { |
| OTA_ERR("Fatal error: write %d bytes(expect %d) to asr flag\n", n, sizeof(gAsrFlag)); |
| close(fd); |
| return -1; |
| } |
| } |
| |
| close(fd); |
| return 0; |
| } |
| |
| #ifdef CONFIG_AB_SYSTEM |
| static int get_inactive_system() |
| { |
| if (get_asr_flag(&gAsrFlag)) { |
| OTA_ERR("Fatal error: can't read asr flag %s\n", server_cfg.mtd_asrflag); |
| return -1; |
| } |
| |
| OTA_DEBUG("Asr Flag: active_slot: %c(0x%x), temp_active_slot: %c(0x%x), reboot_cnt: %d, synced: %d\n", |
| gAsrFlag.active_slot, gAsrFlag.active_slot, |
| gAsrFlag.temp_active_slot, gAsrFlag.temp_active_slot, |
| gAsrFlag.reboot_cnt, gAsrFlag.synced); |
| |
| if (gAsrFlag.active_slot != gAsrFlag.temp_active_slot) { |
| OTA_DEBUG("System %c is valid, now update the active slot...\n", gAsrFlag.temp_active_slot); |
| gAsrFlag.active_slot = gAsrFlag.temp_active_slot; |
| gAsrFlag.reboot_cnt = 0; |
| gAsrFlag.synced = 0; |
| if (write_asr_flag(&gAsrFlag)) { |
| OTA_ERR("Fatal error: fail to write asr flag\n"); |
| return -1; |
| } |
| } else { |
| if (gAsrFlag.synced == 0) { |
| /* if active_slot == temp_active_slot & synced = 0, the system rollback must happened */ |
| gSystemHasRollbackFlag = 1; |
| } |
| } |
| if (gAsrFlag.temp_active_slot == SYSTEM_B) |
| return SYSTEM_A; |
| return SYSTEM_B; |
| } |
| |
| static int complete_read(int fd, char *buf, int size) |
| { |
| int pos = 0; |
| while (pos != size) { |
| int n = read(fd, buf + pos, size - pos); |
| if (n < 0) { |
| OTA_ERR("Fatal error: read failed: %d...\n", n); |
| return -1; |
| } |
| pos += n; |
| } |
| |
| return pos; |
| } |
| |
| static int complete_write(int fd, char *buf, int size) |
| { |
| int pos = 0; |
| while (pos != size) { |
| int n = write(fd, buf + pos, size - pos); |
| if (n < 0) { |
| OTA_ERR("Fatal error: write failed: %d...\n", n); |
| return -1; |
| } |
| pos += n; |
| } |
| |
| return pos; |
| } |
| |
| static int __system_compare(char *src, char *dst, int size, int erasesize) |
| { |
| char sdev[32] = {0}, ddev[32] = {0}; |
| sprintf(sdev, "/dev/%s", src); |
| sprintf(ddev, "/dev/%s", dst); |
| int fdSrc = open(sdev, O_RDWR | O_SYNC); |
| int fdDst = open(ddev, O_RDWR | O_SYNC); |
| |
| int ret = -1; |
| char *sbuf = NULL, *dbuf = NULL; |
| if (fdSrc < 0 || fdDst < 0) { |
| OTA_ERR("Fatal error: can't open dev, src: %s, fdSrc: %d, dst: %s, fdDst: %d\n", |
| src, fdSrc, dst, fdDst); |
| goto err; |
| } |
| |
| sbuf = malloc(erasesize); |
| if (!sbuf) { |
| OTA_ERR("Fatal error: can't malloc 0x%x for src buf\n", erasesize); |
| goto err; |
| } |
| |
| dbuf = malloc(erasesize); |
| if (!dbuf) { |
| OTA_ERR("Fatal error: can't malloc 0x%x for dst buf\n", erasesize); |
| goto err; |
| } |
| |
| OTA_DEBUG("Src: %s, Dst: %s, Size: 0x%x...\n", sdev, ddev, size); |
| while (size) { |
| int n = erasesize; |
| if (size < erasesize) |
| n = size; |
| memset(sbuf, 0, erasesize); |
| memset(dbuf, 0, erasesize); |
| |
| if (complete_read(fdSrc, sbuf, n) < 0) |
| goto err; |
| if (complete_read(fdDst, dbuf, n) < 0) |
| goto err; |
| |
| if (memcmp(sbuf, dbuf, n) != 0) { |
| OTA_ERR("Src: %s, Dst: %s, are not same, NEED to sync\n", sdev, ddev); |
| goto err; |
| } |
| size -= n; |
| } |
| |
| ret = 0; |
| OTA_DEBUG("Src: %s, Dst: %s, are same, NO NEED to sync\n", sdev, ddev); |
| err: |
| if (fdSrc >= 0) |
| close(fdSrc); |
| if (fdDst >= 0) |
| close(fdDst); |
| if (sbuf) |
| free(sbuf); |
| if (dbuf) |
| free(dbuf); |
| return ret; |
| } |
| |
| static int __system_sync(char *src, char *dst, int size, int erasesize) |
| { |
| if (__system_compare(src, dst, size, erasesize) == 0) |
| return 0; |
| |
| int ret = -1; |
| char *buf = NULL; |
| char sdev[32] = {0}, ddev[32] = {0}; |
| sprintf(sdev, "/dev/%s", src); |
| sprintf(ddev, "/dev/%s", dst); |
| int fdSrc = open(sdev, O_RDWR | O_SYNC); |
| int fdDst = open(ddev, O_RDWR | O_SYNC); |
| #ifndef CONFIG_PARTITION_EMMC |
| struct erase_info_user mtdEraseInfo; |
| struct mtd_info_user mtdInfo; |
| if (ioctl(fdDst, MEMGETINFO, &mtdInfo)) { |
| OTA_ERR("Could not get MTD device info from %s\n", ddev); |
| goto err; |
| } |
| mtdEraseInfo.start = 0; |
| mtdEraseInfo.length = mtdInfo.erasesize; |
| #endif |
| if (fdSrc < 0 || fdDst < 0) { |
| OTA_ERR("Fatal error: can't open dev, src: %s, fdSrc: %d, dst: %s, fdDst: %d\n", |
| src, fdSrc, dst, fdDst); |
| goto err; |
| } |
| |
| buf = malloc(erasesize); |
| if (!buf) { |
| OTA_ERR("Fatal error: can't malloc 0x%x\n", erasesize); |
| goto err; |
| } |
| |
| OTA_DEBUG("Sync Src: %s to Dst: %s, Size: 0x%x...\n", sdev, ddev, size); |
| while (size) { |
| int n = erasesize; |
| if (size < erasesize) |
| n = size; |
| memset(buf, 0, erasesize); |
| |
| if (complete_read(fdSrc, buf, n) < 0) |
| goto err; |
| #ifndef CONFIG_PARTITION_EMMC |
| ioctl(fdDst, MEMUNLOCK, &mtdEraseInfo); |
| ioctl(fdDst, MEMERASE, &mtdEraseInfo); |
| #endif |
| if (complete_write(fdDst, buf, n) < 0) |
| goto err; |
| size -= n; |
| #ifndef CONFIG_PARTITION_EMMC |
| mtdEraseInfo.start += mtdInfo.erasesize; |
| #endif |
| } |
| |
| ret = 0; |
| err: |
| if (fdSrc >= 0) |
| close(fdSrc); |
| if (fdDst >= 0) |
| close(fdDst); |
| if (buf) |
| free(buf); |
| return ret; |
| } |
| |
| #if !defined(CONFIG_AB_SYSTEM_DFOTA) |
| static int get_file_size(const char *path) |
| { |
| int filesize = -1; |
| struct stat statbuff; |
| if(stat(path, &statbuff) < 0) |
| return filesize; |
| else |
| filesize = statbuff.st_size; |
| return filesize; |
| } |
| #endif |
| |
| static int system_sync() |
| { |
| int changed = 0; |
| |
| OTA_DEBUG("Start to sync system %c to %c...\n", gAsrFlag.temp_active_slot, gInActiveSystem); |
| for (int i = 0; i < server_cfg.mtd_cnt; i++) { |
| struct image_mtd_info *pSrc = &server_cfg.image_mtd_info[i]; |
| if (pSrc->flag == gAsrFlag.active_slot) { |
| for (int j = 0; j < server_cfg.mtd_cnt; j++) { |
| struct image_mtd_info *pDst = &server_cfg.image_mtd_info[j]; |
| if (pDst->flag == gInActiveSystem) { |
| if (strlen(pSrc->name) == strlen(pDst->name)) { |
| int len = strlen(pSrc->name); |
| if (strncmp(pSrc->name, pDst->name, len - 3) == 0) { |
| /* remove the suffix "-a\n" or "-b\n", 3 bytes */ |
| OTA_DEBUG("Start to sync %s to %s...\n", pSrc->name, pDst->name); |
| if (__system_sync(pSrc->dev, pDst->dev, pDst->size, pDst->erasesize) < 0) { |
| OTA_ERR("Fatal error: sync failed...\n"); |
| return -1; |
| } |
| OTA_DEBUG("Sync %s to %s OK...\n", pSrc->name, pDst->name); |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| if (strncmp(gAsrFlag.mversion, gAsrFlag.MVersion_B, 128) != 0) { |
| changed = 1; |
| OTA_DEBUG("diff mversion a: %s, mversion b: %s\n", gAsrFlag.mversion, gAsrFlag.MVersion_B); |
| if (gInActiveSystem == SYSTEM_A) { |
| OTA_DEBUG("mversion b -> a\n"); |
| memset(gAsrFlag.mversion, 0, 128); |
| strncpy(gAsrFlag.mversion, gAsrFlag.MVersion_B, 128); |
| } else { |
| OTA_DEBUG("mversion a -> b\n"); |
| memset(gAsrFlag.MVersion_B, 0, 128); |
| strncpy(gAsrFlag.MVersion_B, gAsrFlag.mversion, 128); |
| } |
| } |
| |
| OTA_DEBUG("System sync done, update the synced flag...\n"); |
| if (!changed && gAsrFlag.synced == 1) { |
| /* no need to save flag to flash if synced flag is 1 |
| * directly return to decrease write flash */ |
| OTA_DEBUG("The synced flag was set already, no need to update.\n"); |
| return 0; |
| } |
| |
| gAsrFlag.synced = 1; |
| gAsrFlag.reboot_cnt = 0; |
| |
| OTA_DEBUG("Save Asr Flag: active_slot: %c(0x%x), temp_active_slot: %c(0x%x), reboot_cnt: %d, synced: %d\n", |
| gAsrFlag.active_slot, gAsrFlag.active_slot, |
| gAsrFlag.temp_active_slot, gAsrFlag.temp_active_slot, |
| gAsrFlag.reboot_cnt, gAsrFlag.synced); |
| return write_asr_flag(&gAsrFlag); |
| } |
| |
| #endif |
| |
| |
| static int tr069_fbf_parse(void * img_addr, int len, struct image_process_context * context) |
| { |
| MasterBlockHeader* pMasterHeader = NULL; |
| PDeviceHeader_11 pDevHeader_11=NULL; |
| PImageStruct_11 pImage_11=NULL; |
| ImginfoTable * image_table = NULL, * temp_table = NULL; |
| |
| unsigned int * temp_p = NULL; |
| unsigned int img_num,img_start; |
| |
| pMasterHeader = (MasterBlockHeader*)img_addr; |
| if ((pMasterHeader->Format_Version != 11)) { |
| OTA_ERR("Bad version\n"); |
| return -1; |
| } |
| |
| if (pMasterHeader->nOfDevices != 1) { |
| OTA_ERR("Bad content\n"); |
| return -1; |
| } |
| |
| if ((len + context->processed_cnt) < sizeof(MasterBlockHeader)) { |
| return len; |
| } |
| |
| if ((len + context->processed_cnt) < |
| (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069))) { |
| OTA_ERR("length less than device offset[%d:%d]\n", |
| pMasterHeader->deviceHeaderOffset[0], sizeof(struct DeviceHeader_11_tr069)); |
| return len; |
| } |
| |
| { |
| // Checking FBF vesion string, if present |
| const char * version = (const char *)&pMasterHeader->Unique[12]; |
| if (strlen(version)) OTA_DEBUG("Handle FBF version: %s\n", version); |
| if (fbf_version_string) { |
| if (strcmp(fbf_version_string, version)) { |
| OTA_ERR("Version not match: %s\n", fbf_version_string); |
| return -1; |
| } |
| } |
| } |
| |
| temp_p = (unsigned int *)(pMasterHeader->deviceHeaderOffset[0] + (unsigned int)img_addr); |
| pDevHeader_11 = (PDeviceHeader_11)temp_p; |
| OTA_DEBUG("parsed image number is :%d\n", pDevHeader_11->nOfImages); |
| if ((len + context->processed_cnt) < |
| (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069) + |
| sizeof(ImageStruct_11) * pDevHeader_11->nOfImages)) { |
| return len; |
| } |
| |
| update_oemd = 0; |
| for(img_num = 0; img_num < pDevHeader_11->nOfImages; img_num ++) { |
| temp_p = (unsigned int*)&pDevHeader_11->imageStruct_11[img_num]; |
| pImage_11 = (PImageStruct_11)temp_p; |
| img_start = pImage_11->First_Sector<<TR069_FBF_HEADER_SIZE; |
| |
| temp_table = image_table; |
| #ifdef CONFIG_AB_SYSTEM |
| if (pImage_11->Image_ID == FOTA_FBFVERSION_IMAGEID) { |
| server_cfg.fotav_offset_in_fbf = img_start; |
| OTA_DEBUG("%s: fotav_offset_in_fbf = 0x%x\n", __func__, server_cfg.fotav_offset_in_fbf); |
| } |
| |
| if (pImage_11->reserve[0] != 0) { |
| OTA_DEBUG("Found A/B Image, ID: 0x%x, InTim: %d, " |
| "Partition: 0x%x, EraseSize: 0x%x, " |
| "CMD: 0x%x, FirstSector: 0x%x, Len: 0x%x, " |
| "FlashStartAddress(A): 0x%x, FlashStartAddress(B): 0x%x, " |
| "CheckSum: 0x%x\n", |
| pImage_11->Image_ID, pImage_11->Image_In_TIM, |
| pImage_11->Flash_partition, pImage_11->Flash_erase_size, |
| pImage_11->commands, pImage_11->First_Sector, pImage_11->length, |
| pImage_11->Flash_Start_Address, pImage_11->reserve[0], |
| pImage_11->ChecksumFormatVersion2); |
| |
| if (gInActiveSystem == SYSTEM_B) { |
| /* there are no flash address B for obm & timh */ |
| if (pImage_11->Image_ID != IMAGE_ID_TIMH && pImage_11->Image_ID != IMAGE_ID_OBM) |
| pImage_11->Flash_Start_Address = pImage_11->reserve[0]; |
| } |
| } |
| |
| if (pImage_11->Image_ID == IMAGE_ID_OBM) |
| obm_real_size = pImage_11->length; |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| /* the unit of address in fbf was: block */ |
| pImage_11->Flash_Start_Address *= server_cfg.emmc_block_size; |
| #endif |
| |
| int i; |
| struct image_mtd_info *pImageMtdInfo = NULL; |
| for (i = 0; i < server_cfg.mtd_cnt; i++) { |
| pImageMtdInfo = &server_cfg.image_mtd_info[i]; |
| if (pImage_11->Image_ID == IMAGE_ID_TIMH || pImage_11->Image_ID == IMAGE_ID_OBM) { |
| context->upgrade_bootloader = 1; |
| #ifdef CONFIG_PARTITION_EMMC |
| if (pImage_11->Image_In_TIM == TIMH_INC) { |
| if (strstr(pImageMtdInfo->name, "bootloader0")) |
| goto found_bootloader; |
| } else if (pImage_11->Image_In_TIM == TIMH_RECOVERY_INC) { |
| if (strstr(pImageMtdInfo->name, "bootloader1")) |
| goto found_bootloader; |
| } else { |
| exit(-1); |
| } |
| #else |
| if (strstr(pImageMtdInfo->name, "bootloader")) |
| goto found_bootloader; |
| #endif |
| } |
| |
| if (gInActiveSystem != pImageMtdInfo->flag) |
| /* skip the active system mtd */ |
| continue; |
| if ((pImageMtdInfo->flash_start_offset == pImage_11->Flash_Start_Address) || |
| ( |
| /* handle cpimage */ |
| (pImage_11->Flash_Start_Address > pImageMtdInfo->flash_start_offset) && |
| (pImage_11->Flash_Start_Address < (pImageMtdInfo->flash_start_offset + pImageMtdInfo->size)) |
| )) { |
| break; |
| } |
| } |
| |
| if (i == server_cfg.mtd_cnt) { |
| OTA_ERR("FBF is not match the current system...(0x%x)\n", pImage_11->Flash_Start_Address); |
| continue; |
| } |
| found_bootloader: |
| #endif |
| image_table = (ImginfoTable *)malloc(sizeof(ImginfoTable)); |
| if (!image_table) { |
| OTA_ERR("Failed! cannot malloc memory for image infor table\n"); |
| return -1; |
| } |
| |
| image_table->Img_Len= pImage_11->length; |
| image_table->Img_Commands = pImage_11->commands; |
| image_table->Img_Checksum = pImage_11->ChecksumFormatVersion2; |
| image_table->Flash_Erase_Size = pImage_11->Flash_erase_size; |
| image_table->Img_Start_Address = img_start; |
| image_table->Flash_Start_Address = pImage_11->Flash_Start_Address; |
| image_table->Img_ID = pImage_11->Image_ID; |
| image_table->Image_In_TIM = pImage_11->Image_In_TIM; |
| if (pImage_11->Image_ID == OEMDDENTIFIER) |
| update_oemd = 1; |
| image_table->next = temp_table; |
| #ifdef CONFIG_AB_SYSTEM |
| char dev[32] = {0}; |
| sprintf(dev, "/dev/%s", pImageMtdInfo->dev); |
| if (image_table->Img_ID == IMAGE_ID_OBM) { |
| if (image_table->Image_In_TIM == TIMH_INC) |
| image_table->fd = open(tmp_obm_main_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| else if (image_table->Image_In_TIM == TIMH_RECOVERY_INC) { |
| image_table->fd = open(tmp_obm_bk_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| context->dual_tim = 1; |
| } else { |
| OTA_ERR("%s %d: fatal error, unkown Image_In_TIM: %d\n", |
| __func__, __LINE__, image_table->Image_In_TIM); |
| exit(-1); |
| } |
| } else if (image_table->Img_ID == IMAGE_ID_TIMH) { |
| if (image_table->Image_In_TIM == TIMH_INC) |
| image_table->fd = open(tmp_timh_main_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| else if (image_table->Image_In_TIM == TIMH_RECOVERY_INC) { |
| image_table->fd = open(tmp_timh_bk_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| context->dual_tim = 1; |
| } else { |
| OTA_ERR("%s %d: fatal error, unkown Image_In_TIM: %d\n", |
| __func__, __LINE__, image_table->Image_In_TIM); |
| exit(-1); |
| } |
| } else { |
| image_table->fd = open(dev, O_RDWR | O_SYNC); |
| } |
| image_table->partition_size = pImageMtdInfo->size; |
| image_table->erased = 0; |
| memset(image_table->dev, 0, sizeof(image_table->dev)); |
| memset(image_table->name, 0, sizeof(image_table->name)); |
| sprintf(image_table->dev, "%s", pImageMtdInfo->dev); |
| sprintf(image_table->name, "%s", pImageMtdInfo->name); |
| /* 4K align */ |
| image_table->Img_Remain_Len = ((image_table->Img_Len + FBF_FILE_SECTOR_SIZE - 1) & (~ (FBF_FILE_SECTOR_SIZE - 1))); |
| image_table->Block_Start_Address = pImageMtdInfo->flash_start_offset; |
| OTA_DEBUG("Parse new image: start: 0x%08x, len: 0x%08x(flash offset: 0x%08x, %s)\n", img_start, image_table->Img_Len, |
| image_table->Flash_Start_Address, pImageMtdInfo->name); |
| #else |
| OTA_DEBUG("Parse new image: 0x%08x~0x%08x\n", img_start, img_start + image_table->Img_Len); |
| #endif |
| } |
| |
| context->image_info_table = image_table; |
| if(pDevHeader_11->Reserved[0] == 1){ //DFota |
| context->upgrade_method = 4; |
| } |
| else{ |
| context->upgrade_method = 0; |
| } |
| |
| OTA_DEBUG(" first offset: %d\n", pMasterHeader->deviceHeaderOffset[0]); |
| OTA_DEBUG(" all header size: %d\n", (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069) + |
| sizeof(ImageStruct_11) * pDevHeader_11->nOfImages)); |
| OTA_DEBUG(" already processed: %d\n", context->processed_cnt); |
| #ifdef CONFIG_AB_SYSTEM |
| #ifndef CONFIG_AB_SYSTEM_DFOTA |
| /* once parse image ok, clear the synced flag immediately */ |
| gAsrFlag.synced = 0; |
| write_asr_flag(&gAsrFlag); |
| #endif |
| #endif |
| return (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069) + |
| sizeof(ImageStruct_11) * pDevHeader_11->nOfImages) - context->processed_cnt; |
| } |
| |
| static void dump_table(struct image_process_context * context) |
| { |
| ImginfoTable * temp = context->image_info_table; |
| while (temp) { |
| #ifdef CONFIG_AB_SYSTEM |
| OTA_DEBUG("Get Image from start: 0x%08x, len: 0x%08x, flashoffset: 0x%08x(%s)\n", |
| temp->Img_Start_Address, temp->Img_Len, temp->Flash_Start_Address, temp->name); |
| #else |
| OTA_DEBUG("Get Image from 0x%08x to 0x%08x\n", temp->Img_Start_Address, temp->Img_Start_Address + temp->Img_Len); |
| #endif |
| temp = temp->next; |
| } |
| } |
| |
| static int build_image_list(struct image_process_context * context) |
| { |
| struct imginfo_table * table = context->image_info_table; |
| |
| while (table) { |
| struct image_state * temp = malloc(sizeof(struct image_state)); |
| struct image_state * backup = context->image_state_list; |
| if (!temp) { |
| OTA_ERR("Cannot malloc memory..\n"); |
| return -1; |
| } |
| temp->result = 0; // Mask this image is not download |
| temp->next_image = backup; |
| temp->image_info = table; |
| context->image_state_list = temp; |
| table = table->next; |
| } |
| return 0; |
| } |
| |
| static int free_image_list(struct image_process_context * context) |
| { |
| struct image_state * temp = context->image_state_list; |
| while (temp) { |
| struct image_state * backup = temp->next_image; |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| close(temp->image_info->fd); |
| temp->image_info->fd = -1; |
| #endif |
| free(temp); |
| temp = backup; |
| } |
| return 0; |
| } |
| |
| static unsigned int fbf_checksum(unsigned char * src, unsigned int len, unsigned int checksum) |
| { |
| unsigned int * start = (unsigned int *)src; |
| unsigned int * end = (unsigned int *)(src + len); |
| while (start < end) { |
| checksum ^= (*start++); |
| } |
| return checksum; |
| } |
| |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| static int mark_current_image_processed(struct image_process_context * context) |
| { |
| struct image_state * temp = context->image_state_list; |
| while (temp) { |
| if (temp->image_info == context->current_process) { |
| temp->result = 1; // Mark it be processed |
| return 0; |
| } |
| temp = temp->next_image; |
| } |
| OTA_ERR("Why cannot find the processed image?\n"); |
| return -1; |
| } |
| |
| static int image_check(struct image_process_context * context, char * data, int len) |
| { |
| int size, cnt; |
| // First check the data belong to same image |
| size = (context->processed_cnt + len - context->current_process->Img_Start_Address) >= context->current_process->Img_Len ? |
| context->current_process->Img_Start_Address + context->current_process->Img_Len - context->processed_cnt : len; |
| cnt = size; |
| |
| while (cnt) { |
| if ((context->checksum_cache_index + cnt) >= CHECKSUM_CACHE_SIZE) { |
| int space = CHECKSUM_CACHE_SIZE - context->checksum_cache_index; |
| memcpy(context->checksum_cache + context->checksum_cache_index, data, space); |
| context->image_checksum = fbf_checksum(context->checksum_cache, CHECKSUM_CACHE_SIZE, context->image_checksum); |
| data += space; |
| cnt -= space; |
| context->checksum_cache_index = 0; |
| } else { |
| memcpy(context->checksum_cache + context->checksum_cache_index, data, cnt); |
| context->checksum_cache_index += cnt; |
| cnt -= cnt; |
| } |
| } |
| |
| if ((context->processed_cnt + len - context->current_process->Img_Start_Address) >= context->current_process->Img_Len) { |
| OTA_DEBUG("Handle image end...\n"); |
| if (context->checksum_cache_index != 0) { |
| context->image_checksum = fbf_checksum(context->checksum_cache, context->checksum_cache_index, context->image_checksum); |
| } |
| OTA_DEBUG(" Image[%08x] checksum 0x%08x:0x%08x\n", context->current_process->Img_ID, context->current_process->Img_Checksum, context->image_checksum); |
| if (context->current_process->Img_Checksum == context->image_checksum) { |
| mark_current_image_processed(context); |
| } else if (context->current_process->Img_ID == RSA_IMAGE_ID) { |
| OTA_DEBUG(" RSA image, always mark to pass\n"); |
| mark_current_image_processed(context); |
| } if (context->current_process->Img_Checksum == 0) { |
| OTA_DEBUG(" RAW checksum is zero, always mark to pass\n"); |
| mark_current_image_processed(context); |
| } |
| context->checksum_cache_index = 0; |
| context->current_process = 0; |
| context->image_checksum = 0; |
| } |
| context->processed_cnt += size; |
| return size; |
| } |
| #endif |
| static void notify_progress(int progress) |
| { |
| char buf[128] = {0}; |
| snprintf(buf, 128, "progress[%d]", progress); |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "notification", buf); |
| ubus_notify(ctx, &ota_object, "notification", b.head, -1); |
| } |
| |
| static void notify_download_start(void) |
| { |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "notification", "start"); |
| ubus_notify(ctx, &ota_object, "notification", b.head, -1); |
| } |
| |
| static void notify_download_end(int success) |
| { |
| char buf[128] = {0}; |
| snprintf(buf, 128, "end[%d]", !!success); |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "notification", buf); |
| ubus_notify(ctx, &ota_object, "notification", b.head, -1); |
| } |
| |
| static int firmware_download_cb(char * data, int len, int num, void *cbdata) |
| { |
| struct image_process_context * context = (struct image_process_context *)cbdata; |
| int ret = 0; |
| unsigned int temp = 0; |
| int total=0; |
| if(download_method_ctx.type == OTA_TYPE_UDP){ |
| download_method_ctx.received_size +=len; |
| _ota_download_progress = download_method_ctx.received_size; |
| total = download_method_ctx.file_size; |
| }else{ |
| _ota_download_progress += len; |
| total = num; |
| } |
| temp = (_ota_download_progress * 100); |
| ota_download_progress = (temp / total); |
| if (ota_download_progress >= 100) { |
| ota_download_progress = 99; |
| } |
| if ((ota_download_progress - context->ota_download_notification_cnt) >= server_cfg.progress_notify) { |
| OTA_DEBUG("OTA download progress %d\n", context->ota_download_notification_cnt); |
| context->ota_download_notification_cnt = ota_download_progress; |
| notify_progress(context->ota_download_notification_cnt); |
| } |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| /* len = 4096 for every packet except for the last one */ |
| if (total <= FBF_FILE_SECTOR_SIZE) { |
| OTA_ERR("Error file total size %d...\n", total); |
| return -1; |
| } |
| |
| /* 1. FBF Head sit one the first sector of the FBF file, check it */ |
| if (context->state == HEADER) { |
| ret = tr069_fbf_parse(data, len, context); |
| if (ret < 0) { |
| OTA_ERR("Failed, fbf parse failed...\n"); |
| return -1; |
| } |
| |
| if (context->image_info_table) { |
| context->state = CONTENT; |
| dump_table(context); |
| // Build image list for trace all image download result |
| build_image_list(context); |
| } |
| context->processed_cnt = len; |
| } else if (context->state == CONTENT) { |
| if (context->processed_cnt < 0x2000) { |
| OTA_DEBUG("skip 2nd 4K...\n"); |
| // Add by liubin |
| revision_out_find(data, len, context->processed_cnt); |
| // End by liubin |
| |
| context->processed_cnt += len; |
| return 0; |
| } |
| |
| if (context->flash_cache_index < server_cfg.block_size) { |
| /* flash_cache_index increase by 4096 */ |
| char *pos = context->flash_cache + context->flash_cache_index; |
| memcpy(pos, data, len); // len = 4096 here |
| context->flash_cache_index += len; |
| context->processed_cnt += len; |
| } |
| |
| if (server_cfg.fotav_offset_in_fbf && |
| context->processed_cnt == (server_cfg.fotav_offset_in_fbf + 0x1000)) |
| { |
| memcpy(server_cfg.fotav, context->flash_cache, 128); |
| temp = strlen(server_cfg.fotav); |
| if (server_cfg.fotav[temp - 1] == ';') |
| server_cfg.fotav[temp - 1] = 0; /* remove last ; */ |
| OTA_DEBUG("%s: got fota version: %s\n", __func__, server_cfg.fotav); |
| if (upgrade_precheck(server_cfg.fotav)) |
| exit(-1); |
| } |
| |
| //if (context->flash_cache_index == server_cfg.block_size) { |
| /* flush the cache to flash */ |
| ImginfoTable *p; |
| p = context->image_info_table; |
| while (p) |
| { |
| int image_len = p->Img_Len; |
| // bool flush_cache = false; |
| /* FBF_FILE_SECTOR_SIZE alignment */ |
| image_len = ((image_len + FBF_FILE_SECTOR_SIZE - 1) & (~ (FBF_FILE_SECTOR_SIZE - 1))); |
| int total_block = ((image_len + server_cfg.block_size - 1) & (~ (server_cfg.block_size - 1))) / server_cfg.block_size; |
| if (context->processed_cnt > p->Img_Start_Address) { |
| if (context->processed_cnt < (p->Img_Start_Address + image_len)) { |
| if (context->flash_cache_index < server_cfg.block_size) { |
| break; |
| } |
| } |
| if (context->processed_cnt == (p->Img_Start_Address + image_len) || |
| context->flash_cache_index == server_cfg.block_size) { |
| p->cs = fbf_checksum((unsigned char *)context->flash_cache, context->flash_cache_index, p->cs); |
| int offset = context->processed_cnt - p->Img_Start_Address; |
| struct erase_info_user mtdEraseInfo; |
| offset += p->Flash_Start_Address - p->Block_Start_Address; |
| int block = ((offset + server_cfg.block_size - 1) & (~ (server_cfg.block_size - 1))) / server_cfg.block_size; |
| int start = server_cfg.block_size * (block - 1); |
| OTA_DEBUG("@ context->processed_cnt: 0x%x, p->Img_Start_Address: 0x%x, len: 0x%x, start: 0x%x\n", |
| context->processed_cnt, p->Img_Start_Address, image_len, start); |
| OTA_DEBUG("@ found, dev: %s, name: %s, block: %d(total: %d), cs: 0x%x(expect: 0x%x), index: 0x%x\n", |
| p->dev, p->name, block - 1,total_block,p->cs, p->Img_Checksum, context->flash_cache_index); |
| |
| if (p->fd < 0) { |
| OTA_ERR("mtd device open failed...\n"); |
| return -1; |
| } |
| |
| if (p->erased == 0 && strstr(p->name, "oem_data")) { |
| OTA_DEBUG("Need to Erase all of %s(%s)\n", p->dev, p->name); |
| mtdEraseInfo.length = p->partition_size; |
| mtdEraseInfo.start = 0; |
| #ifndef CONFIG_PARTITION_EMMC |
| ioctl(p->fd, MEMUNLOCK, &mtdEraseInfo); |
| ioctl(p->fd, MEMERASE, &mtdEraseInfo); |
| #endif |
| p->erased = 1; |
| } |
| |
| if (p->Img_ID != IMAGE_ID_OBM && p->Img_ID != IMAGE_ID_TIMH) { |
| ret = lseek(p->fd, start, SEEK_SET); |
| if (ret < 0) |
| { |
| OTA_ERR("seek failed\n"); |
| return -1; |
| } |
| |
| mtdEraseInfo.length = server_cfg.block_size; |
| mtdEraseInfo.start = start; |
| #ifndef CONFIG_PARTITION_EMMC |
| ioctl(p->fd, MEMUNLOCK, &mtdEraseInfo); |
| ioctl(p->fd, MEMERASE, &mtdEraseInfo); |
| #endif |
| } |
| |
| ret = write(p->fd, context->flash_cache, context->flash_cache_index); |
| if (ret != context->flash_cache_index) { |
| OTA_ERR("error: write incomplete! %d/%d\n", ret, context->flash_cache_index); |
| return -1; |
| } |
| |
| memset(context->flash_cache, 0, server_cfg.block_size); |
| context->flash_cache_index = 0; |
| break; |
| } |
| } |
| p = p->next; |
| } |
| |
| if (!p) { |
| //OTA_ERR("not found image, ignore, %d...\n", context->processed_cnt); |
| memset(context->flash_cache, 0, server_cfg.block_size); |
| context->flash_cache_index = 0; |
| } |
| //} |
| } |
| #else |
| if (context->flash_cb) context->flash_cb(context, data, len); |
| while (len > 0) { |
| switch (context->state) { |
| case HEADER: { |
| OTA_DEBUG("Header cosume %d, len %d\n", context->processed_cnt,len); |
| if ((context->processed_cnt + len) < MINI_SIZE) { |
| OTA_DEBUG("FBF header not complete, continue recv\n"); |
| context->processed_cnt += len; |
| return 0; |
| } |
| ret = tr069_fbf_parse(context->flash_cache, len, context); |
| if (ret < 0) { |
| OTA_ERR("Failed, fbf parse failed...\n"); |
| context->processed_cnt += len; |
| len -= len; |
| return -1; |
| } |
| len -= ret; |
| data += ret; |
| context->processed_cnt += ret; |
| if (context->image_info_table) { |
| context->state = CONTENT; |
| dump_table(context); |
| // Build image list for trace all image download result |
| build_image_list(context); |
| } |
| break; |
| } |
| case CONTENT: |
| default: { |
| ImginfoTable * temp; |
| if (!context->current_process) { |
| int discard; |
| temp = context->image_info_table; |
| while (temp) { |
| if (temp->Img_Start_Address <= (context->processed_cnt + len) && |
| temp->Img_Start_Address >= context->processed_cnt) { |
| OTA_DEBUG("Find new image: start_address 0x%08x, image length %d, write to 0x%08x\n", |
| temp->Img_Start_Address, temp->Img_Len, temp->Flash_Start_Address); |
| if(temp->Img_Len!=0){ |
| break; |
| } |
| } |
| temp = temp->next; |
| } |
| if (!temp) { |
| OTA_DEBUG("Current data[0x%08x~0x%08x] not contain any content\n", |
| context->processed_cnt, context->processed_cnt + len); |
| context->processed_cnt += len; |
| return 0; |
| } |
| discard = temp->Img_Start_Address - context->processed_cnt; |
| if (discard) OTA_DEBUG("Have discard %d...\n", discard); |
| len -= discard; |
| data += discard; |
| context->processed_cnt += discard; |
| context->current_process = temp; |
| } |
| ret = image_check(context, data, len); |
| len -= ret; |
| data += ret; |
| } |
| } |
| }; |
| #endif |
| return 0; |
| } |
| |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| static char *gTempbuf = NULL; |
| static int gTempbufPos = 0; |
| static int gTotalBytes = 0; |
| /* this wrapper function is to guarantee 4K size each package */ |
| static int firmware_download_cb_ab(char * data, int len, int num, void *cbdata) |
| { |
| int bytes = 0, pos = 0, ret = 0; |
| if (!gTempbuf) |
| gTempbuf = malloc(4096); |
| |
| while (len) { |
| bytes = len; |
| if ((gTempbufPos + len) > 4096) |
| bytes = 4096 - gTempbufPos; |
| memcpy(gTempbuf + gTempbufPos, data + pos, bytes); |
| len -= bytes; |
| pos += bytes; |
| gTempbufPos += bytes; |
| gTotalBytes += bytes; |
| if (gTempbufPos == 4096 || gTotalBytes == num) { |
| ret = firmware_download_cb(gTempbuf, gTempbufPos, num, cbdata); |
| gTempbufPos = 0; |
| if (ret) { |
| OTA_ERR("%s: failed, ret = %d\n", __func__, ret); |
| return ret; |
| } |
| } |
| } |
| |
| if(gTotalBytes == num) { |
| struct image_process_context * context = (struct image_process_context *)cbdata; |
| context->download_result = 1; |
| free(gTempbuf); |
| gTempbuf = NULL; |
| } |
| return 0; |
| } |
| #endif |
| |
| static int push2flash(struct image_process_context * context, char * data, int len) |
| { |
| int ret; |
| int block_cnt = 0; |
| struct erase_info_user mtdEraseInfo; |
| |
| while (len && context->flash_cache) { |
| if ((context->flash_cache_index + len) >= server_cfg.block_size) { |
| int space = server_cfg.block_size - context->flash_cache_index; |
| memcpy(context->flash_cache + context->flash_cache_index, data, space); |
| data += space; |
| len -= space; |
| context->flash_cache_index = 0; |
| block_cnt = ((context->processed_cnt + space) / server_cfg.block_size); |
| OTA_DEBUG(" write to block %d\n", block_cnt); |
| // Write to flash |
| ret = lseek(context->fd, server_cfg.block_size * block_cnt, SEEK_SET); |
| if (ret < 0) { |
| OTA_ERR("seek failed\n"); |
| return -1; |
| } |
| if (context->processed_cnt + space >= server_cfg.fbf_length) { |
| OTA_ERR("!!! FILE TOO LARGE !!!\n"); |
| return 0; |
| } |
| mtdEraseInfo.length = server_cfg.block_size; |
| mtdEraseInfo.start = server_cfg.block_size * ((context->processed_cnt + space) / server_cfg.block_size); |
| ioctl(context->fd, MEMUNLOCK, &mtdEraseInfo); |
| ioctl(context->fd, MEMERASE, &mtdEraseInfo); |
| ret = write(context->fd, context->flash_cache, server_cfg.block_size); |
| if (ret != server_cfg.block_size) { |
| OTA_ERR("error: write incomplete!\n"); |
| } |
| //memset(context->flash_cache, 0, server_cfg.block_size); |
| } else { |
| memcpy(context->flash_cache + context->flash_cache_index, data, len); |
| context->flash_cache_index += len; |
| len -= len; |
| } |
| }; |
| |
| return 0; |
| } |
| |
| static int flush_flash(struct image_process_context * context) |
| { |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| int ret; |
| int block_cnt; |
| if (context->flash_cache_index && context->flash_cache) { |
| block_cnt = ((context->processed_cnt) / server_cfg.block_size); |
| if (((context->processed_cnt) % server_cfg.block_size) != 0) { |
| block_cnt++;; |
| } |
| OTA_DEBUG("flush at block %d\n", block_cnt); |
| ret = lseek(context->fd, server_cfg.block_size * block_cnt, SEEK_SET); |
| if (ret < 0) { |
| OTA_ERR("seek failed!\n"); |
| return -1; |
| } |
| write(context->fd, context->flash_cache, server_cfg.block_size); |
| } |
| #endif |
| sync(); |
| return 0; |
| } |
| |
| static void __download_throgh_sd(const char * url, struct image_process_context * context) |
| { |
| int fd = -1; |
| int total = 0, all = 0; |
| char * buf = NULL; |
| |
| if (url == NULL || context == NULL) { |
| OTA_ERR("Bad parameters!\n"); |
| // Add by mbtk |
| Download_flag = -1; |
| return; |
| } |
| fd = open(url, O_RDONLY); |
| if (fd < 0) { |
| OTA_ERR("open for SD download failed!\n"); |
| // Add by mbtk |
| Download_flag = -1; |
| goto done; |
| } |
| total = lseek(fd, 0, SEEK_END); |
| if (total < 0) { |
| OTA_ERR("seek failed!\n"); |
| // Add by mbtk |
| Download_flag = -1; |
| goto done; |
| } |
| |
| buf = malloc(4096); |
| if (buf == NULL) { |
| OTA_ERR("malloc failed!\n"); |
| // Add by mbtk |
| Download_flag = -1; |
| goto done; |
| } |
| |
| all = total; |
| lseek(fd, 0, SEEK_SET); |
| while (total) { |
| int remain = total > 4096 ? 4096 : total; |
| int size = 0; |
| //OTA_ERR("SD download size: %d:%d\n", total, remain); |
| memset(buf, 0, 4096); |
| size = read(fd, buf, remain); |
| if (size != remain) { |
| OTA_ERR("read firmware failed!\n"); |
| // Add by mbtk |
| Download_flag = -1; |
| goto done; |
| } |
| firmware_download_cb(buf, remain, all, context); |
| total -= remain; |
| } |
| flush_flash(context); |
| context->download_result = 1; |
| done: |
| if (fd >= 0) { |
| close(fd); |
| fd = -1; |
| } |
| if (buf) { |
| free(buf); |
| buf = NULL; |
| } |
| return; |
| } |
| |
| |
| static void __download_throgh_http(const char * url, struct image_process_context * context) |
| { |
| #if 0 |
| CURL *curl = curl_easy_init(); |
| unsigned int response_code; |
| double firmware_size; |
| char * temp = NULL; |
| *temp = 2; |
| |
| OTA_ERR("Try access %s through curl\n", url); |
| curl_easy_setopt(curl, CURLOPT_URL, url); |
| curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20); |
| curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb); |
| |
| curl_easy_perform(curl); |
| curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); |
| curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &firmware_size); |
| OTA_ERR("Get response code: %d and firmware size: %d\n", response_code, firmware_size); |
| |
| curl_easy_cleanup(curl); |
| #else |
| struct http_client * client = NULL; |
| int http_response_code = 0; |
| client = http_client_init(); |
| if (client == NULL) { |
| OTA_ERR("HTTP client init failed!\n"); |
| return; |
| } |
| |
| OTA_DEBUG("Try access %s through http\n", url); |
| http_client_setopt(client, HTTPCLIENT_OPT_URL, url); |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, firmware_download_cb_ab); |
| #else |
| http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, firmware_download_cb); |
| #endif |
| http_client_setopt(client, HTTPCLIENT_OPT_METHOD, HTTPCLIENT_REQUEST_GET); |
| http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB_DATA, context); |
| http_client_perform(client); |
| flush_flash(context); |
| http_client_getinfo(client, HTTPCLIENT_GETINFO_RESPONSE_CODE, &http_response_code); |
| OTA_DEBUG("HTTP result: %d\n", http_response_code); |
| if (http_response_code == 200) { |
| context->download_result = 1; |
| } |
| if (client) http_client_shutdown(client); |
| #endif |
| } |
| |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| static int push2ram(struct image_process_context * context, char * data, int len) |
| { |
| while (len && context->flash_cache) { |
| if ((context->flash_cache_index + len) >= FILE_VERIFY_RAM_SIZE) { |
| int space = FILE_VERIFY_RAM_SIZE - context->flash_cache_index; |
| memcpy(context->flash_cache + context->flash_cache_index, data, space); |
| data += space; |
| len -= space; |
| context->flash_cache_index = 0; |
| } else { |
| memcpy(context->flash_cache + context->flash_cache_index, data, len); |
| context->flash_cache_index += len; |
| len -= len; |
| } |
| }; |
| return 0; |
| } |
| |
| static int verify_flash_image(struct image_process_context * context, int * file_size) |
| { |
| // Handle all data, try read it from flash, and verify again |
| int error = 0; |
| unsigned int i; |
| int total = context->processed_cnt; |
| struct image_process_context new_context = {0}; |
| char * temp = malloc(server_cfg.block_size); |
| struct image_state * temp_list; |
| int fd = -1; |
| struct mtd_info_user mtdInfo; |
| unsigned int ofs; |
| |
| new_context.ota_download_notification_cnt = context->ota_download_notification_cnt; |
| fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| if (fd < 0) { |
| OTA_ERR("Open MTD device failed!\n"); |
| return -1; |
| } |
| if (ioctl(fd, MEMGETINFO, &mtdInfo)) { |
| OTA_ERR("Could not get MTD device info from %s\n", server_cfg.mtd_fbf); |
| } else { |
| struct erase_info_user mtdEraseInfo; |
| OTA_DEBUG(" MTD size: %d\n", mtdInfo.size); |
| OTA_DEBUG(" MTD erase size: %d\n", mtdInfo.erasesize); |
| OTA_DEBUG(" MTD type: %d\n", mtdInfo.type); |
| mtdEraseInfo.length = mtdInfo.erasesize;; |
| if (mtdInfo.type == MTD_NANDFLASH) { |
| for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdInfo.size; mtdEraseInfo.start += mtdInfo.erasesize) { |
| ofs = mtdEraseInfo.start; |
| if (ioctl(fd, MEMGETBADBLOCK, &ofs)) { |
| OTA_ERR("Has bad block at %08x\n", (unsigned int)ofs); |
| } |
| } |
| } |
| } |
| sync(); |
| lseek(fd, server_cfg.block_size, SEEK_SET); |
| |
| if (!temp) { |
| OTA_ERR("Cannot malloc memory for image verify"); |
| return -1; |
| } |
| |
| new_context.checksum_cache = malloc(CHECKSUM_CACHE_SIZE); |
| if (!new_context.checksum_cache) goto done; |
| new_context.flash_cache = malloc(FILE_VERIFY_RAM_SIZE); |
| if (!new_context.flash_cache) goto done; |
| new_context.flash_cb = push2ram; |
| i = 1; |
| *file_size = context->processed_cnt; |
| while (total) { |
| int remain_size = total > server_cfg.block_size ? server_cfg.block_size : total; |
| int sub_total = remain_size; |
| int ret = 0; |
| OTA_DEBUG("Verify block %d\n", i); |
| ret = read(fd, temp, server_cfg.block_size); |
| if (ret != server_cfg.block_size) { |
| OTA_ERR("error: data incomplete!\n"); |
| } |
| while (remain_size) { |
| int space = remain_size > 4096 ? 4096 : remain_size; |
| firmware_download_cb(temp + (sub_total - remain_size), space, context->processed_cnt, &new_context); |
| remain_size -= space; |
| } |
| total -= sub_total; |
| i++; |
| } |
| free(temp); |
| temp = NULL; |
| temp_list = new_context.image_state_list; |
| while (temp_list) { |
| OTA_DEBUG("The verify image(0x%08x) process result %d\n", |
| temp_list->image_info->Img_Checksum, temp_list->result); |
| if (!temp_list->result) error = 1; |
| temp_list = temp_list->next_image; |
| } |
| done: |
| if (temp) free(temp); |
| temp = NULL; |
| if (new_context.flash_cache) free(new_context.flash_cache); |
| new_context.flash_cache = NULL; |
| if (new_context.checksum_cache) free(new_context.checksum_cache); |
| new_context.checksum_cache = NULL; |
| temp = NULL; |
| free_image_list(&new_context); |
| close(fd); |
| return error; |
| } |
| #endif |
| |
| |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| #ifdef CONFIG_PARTITION_EMMC |
| static int emmc_boot_lock_unlock(int no, int lock) |
| { |
| char cmd[64] = {0}; |
| sprintf(cmd, "echo %d > /sys/block/mmcblk1boot%d/force_ro", lock, no); |
| system(cmd); |
| return 0; |
| } |
| #endif |
| |
| static int mtd_erase(int fd, unsigned int offset, unsigned int length) |
| { |
| #ifndef CONFIG_PARTITION_EMMC |
| struct erase_info_user erase; |
| OTA_DEBUG("%s: offset: 0x%x, length: 0x%x\n", __func__, offset, length); |
| if (lseek(fd, offset, SEEK_SET) < 0) { |
| OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| return -1; |
| } |
| |
| erase.length = length; |
| erase.start = offset; |
| |
| ioctl(fd, MEMUNLOCK, &erase); |
| if (ioctl(fd, MEMERASE, &erase) < 0) { |
| OTA_ERR("%s: erase failed. err: %d\n", __func__, errno); |
| return -1; |
| } |
| #endif |
| return 0; |
| } |
| |
| #ifndef CONFIG_PARTITION_EMMC |
| static int is_all_ff(char *buf, int size) |
| { |
| for (int i = 0; i < size; i++) { |
| if (0xff != (unsigned char)buf[i]) |
| return 0; |
| } |
| return 1; |
| } |
| #endif |
| |
| static int __upgrade_timh(int fd, unsigned int offset, const char *file, |
| unsigned int size, char *dst_buf, unsigned int dst_buf_size, unsigned int pagesize) |
| { |
| int srcfd = -1, r = -1; |
| char *buf = NULL, *dst = NULL; |
| int dstsize, off; |
| |
| OTA_DEBUG("%s: offset: 0x%x, file: %s, size: 0x%x, dst_buf_size: %d, " |
| "pagesize: %d, max_timh_size: %d\n", |
| __func__, offset, file, size, dst_buf_size, pagesize, server_cfg.max_timh_size); |
| if ((srcfd = open(file, O_RDONLY)) < 0) { |
| OTA_ERR("%s: failed to open file: %s\n", __func__, file); |
| goto err; |
| } |
| |
| buf = malloc(size); |
| if (!buf) { |
| OTA_ERR("%s: no mem\n", __func__); |
| goto err; |
| } |
| |
| if (complete_read(srcfd, buf, size) < 0) { |
| OTA_ERR("%s: read failed\n", __func__); |
| goto err; |
| } |
| |
| if (lseek(fd, offset, SEEK_SET) < 0) { |
| OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| goto err; |
| } |
| |
| if (dst_buf) { |
| dst = dst_buf; |
| dstsize = dst_buf_size; |
| memcpy(dst, buf, size); |
| } else { |
| dst = buf; |
| dstsize = size; |
| } |
| |
| #ifndef CONFIG_PARTITION_EMMC |
| if (dstsize > server_cfg.max_timh_size) { |
| /* 1. write all timh */ |
| if (complete_write(fd, dst, server_cfg.max_timh_size) < 0) { |
| OTA_ERR("%s: write all timh failed\n", __func__); |
| goto err; |
| } |
| |
| /* 2. write bbt */ |
| for (off = server_cfg.max_timh_size; off < dstsize; off += pagesize) { |
| if (!is_all_ff(dst + off, pagesize)) { |
| if (complete_write(fd, dst + off, pagesize) < 0) { |
| OTA_ERR("%s: write bbt page failed\n", __func__); |
| goto err; |
| } |
| } else { |
| OTA_DEBUG("0x%x + 0x%x is all FF, skip write.\n", offset, off); |
| } |
| } |
| } else { |
| #endif |
| if (complete_write(fd, dst, dstsize) < 0) { |
| OTA_ERR("%s: write failed\n", __func__); |
| goto err; |
| } |
| #ifndef CONFIG_PARTITION_EMMC |
| } |
| #endif |
| |
| r = 0; |
| err: |
| if (srcfd >= 0) |
| close(srcfd); |
| if (buf) |
| free(buf); |
| return r; |
| } |
| |
| static int write_to_file(void *buf, int size, const char *file) |
| { |
| int fd; |
| int r = -1; |
| fd = open(file, O_CREAT | O_RDWR | O_SYNC | O_TRUNC, 777); |
| if (fd < 0) { |
| OTA_ERR("%s: failed to open %s\n", __func__, file); |
| return r; |
| } |
| |
| if (complete_write(fd, buf, size) < 0) { |
| OTA_ERR("%s: write failed\n", __func__); |
| goto err; |
| } |
| |
| r = 0; |
| err: |
| if (fd >= 0) |
| close(fd); |
| return r; |
| } |
| |
| static int retrive_timh_by_ddrid(const char *file, unsigned int *ddr_id, const char *target_file) |
| { |
| int size, fd = -1, r = -1; |
| char *buf = NULL; |
| TIM tim; |
| |
| OTA_DEBUG("%s: ddr id: 0x%x\n", __func__, *ddr_id); |
| size = get_file_size(file); |
| if (size <= 0) { |
| OTA_ERR("failed to get size of file: %s\n", file); |
| return r; |
| } |
| |
| buf = malloc(size); |
| if (!buf) { |
| OTA_ERR("%s: failed to malloc for file: %s, size: %d\n", |
| __func__, file, size); |
| return r; |
| } |
| |
| fd = open(file, O_RDONLY); |
| if (fd < 0) { |
| OTA_ERR("%s: failed to open file: %s\n", |
| __func__, file); |
| r = -1; |
| goto err; |
| } |
| |
| if (complete_read(fd, buf, size) < 0) |
| goto err; |
| |
| SetTIMPointers(buf, &tim); |
| if (__retrive_timh_by_ddrid(&tim, ddr_id, &size) != NoError) { |
| OTA_ERR("%s: failed to retrive timh\n", __func__); |
| goto err; |
| } |
| |
| if (write_to_file(tim.pConsTIM, size, target_file) < 0) |
| goto err; |
| OTA_DEBUG("%s: OK.\n", __func__); |
| r = 0; |
| err: |
| if (buf) |
| free(buf); |
| if (fd >= 0) |
| close(fd); |
| return r; |
| } |
| |
| static int __upgrade_obm(int fd, unsigned int offset, const char *obm_file, const char *timh_file) |
| { |
| int obm_fd = -1, timh_fd = -1, r = -1; |
| char *buf = NULL; |
| int obm_size = 0, timh_size = 0; |
| |
| if (obm_file) |
| obm_size = get_file_size(obm_file); |
| if (timh_file) |
| timh_size = get_file_size(timh_file); |
| |
| OTA_DEBUG("%s: offset: 0x%x, obm file: %s, obm_size: %d(%d), timh file: %s, timh_size: %d\n", |
| __func__, offset, obm_file, obm_size, obm_real_size, timh_file, timh_size); |
| obm_size = obm_real_size; |
| |
| if ((obm_fd = open(obm_file, O_RDONLY)) < 0) { |
| OTA_ERR("%s: failed to open obm file: %s\n", __func__, obm_file); |
| goto err; |
| } |
| |
| if (timh_file) { |
| if ((timh_fd = open(timh_file, O_RDONLY)) < 0) { |
| OTA_ERR("%s: failed to open timh file: %s\n", __func__, timh_file); |
| goto err; |
| } |
| } |
| |
| buf = malloc(obm_size + timh_size); |
| if (!buf) { |
| OTA_ERR("%s: no mem\n", __func__); |
| goto err; |
| } |
| |
| if (complete_read(obm_fd, buf, obm_size) < 0) { |
| OTA_ERR("%s: read obm failed\n", __func__); |
| goto err; |
| } |
| |
| if (timh_file) { |
| if (complete_read(timh_fd, buf + obm_size, timh_size) < 0) { |
| OTA_ERR("%s: read timh failed\n", __func__); |
| goto err; |
| } |
| } |
| |
| /* write obm + timh backup */ |
| if (lseek(fd, offset, SEEK_SET) < 0) { |
| OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| goto err; |
| } |
| |
| if (complete_write(fd, buf, obm_size + timh_size) < 0) { |
| OTA_ERR("%s: write failed\n", __func__); |
| goto err; |
| } |
| |
| r = 0; |
| err: |
| if (obm_fd >= 0) close(obm_fd); |
| if (timh_fd >= 0) close(timh_fd); |
| if (buf) free(buf); |
| return r; |
| } |
| |
| static int __upgrade_bootloader(struct image_process_context * context, int Image_In_Tim) |
| { |
| ImginfoTable *obm = NULL, *timh = NULL, *p; |
| int fd = -1, r = -1; |
| char *bootdev = NULL; |
| char *block0 = NULL; |
| char *obm_file = NULL, *timh_file = NULL; |
| /* put this file right after the obm */ |
| char *timh_bk_file = NULL; |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| int emmc_boot_part = 0; |
| if (Image_In_Tim == TIMH_INC) { |
| bootdev = "/dev/mmcblk1boot0"; |
| emmc_boot_part = 0; |
| } else if (Image_In_Tim == TIMH_RECOVERY_INC) { |
| bootdev = "/dev/mmcblk1boot1"; |
| emmc_boot_part = 1; |
| } |
| #else |
| bootdev = "/dev/mtd0"; |
| #endif |
| |
| if (Image_In_Tim == TIMH_INC) { |
| obm_file = (char *)tmp_obm_main_file; |
| timh_file = (char *)tmp_timh_main_target_file; |
| if (context->dual_tim) |
| timh_bk_file = (char *)tmp_timh_bk_target_file; |
| } else if (Image_In_Tim == TIMH_RECOVERY_INC) { |
| obm_file = (char *)tmp_obm_bk_file; |
| timh_file = (char *)tmp_timh_bk_target_file; |
| timh_bk_file = (char *)tmp_timh_main_target_file; |
| } else { |
| OTA_ERR("%s: unsupport %d\n", __func__, Image_In_Tim); |
| exit(-1); |
| } |
| |
| if (context->same_tim) { |
| timh_file = (char *)tmp_timh_main_target_file; /* always use the main tim */ |
| timh_bk_file = NULL; /* no need to append tim to obm */ |
| } |
| |
| p = context->image_info_table; |
| while (p) { |
| if (p->Img_ID == IMAGE_ID_OBM && p->Image_In_TIM == Image_In_Tim) |
| obm = p; |
| else if (p->Img_ID == IMAGE_ID_TIMH && p->Image_In_TIM == Image_In_Tim) |
| timh = p; |
| p = p->next; |
| } |
| |
| if (!obm || !timh) { |
| OTA_ERR("no obm or timh.\n"); |
| goto err; |
| } |
| |
| OTA_DEBUG("%s: start %d...\n", __func__, Image_In_Tim); |
| fd = open(bootdev, O_RDWR | O_SYNC); |
| if (fd < 0) { |
| OTA_ERR("failed to open %s.\n", bootdev); |
| goto err; |
| } |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| // no bbm for emmc |
| #else |
| ioctl(fd, MEMUNLOCKPRIV, NULL); |
| |
| // bbm related things were in block 0, so we need to backup them |
| // 1. load block 0 |
| block0 = malloc(server_cfg.block_size); |
| if (!block0) { |
| OTA_ERR("%s: no mem\n", __func__); |
| goto err; |
| } |
| |
| if (lseek(fd, timh->Flash_Start_Address, SEEK_SET) < 0) { |
| OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| goto err; |
| } |
| |
| if (complete_read(fd, block0, server_cfg.block_size) < 0) { |
| OTA_ERR("%s: load block0 failed\n", __func__); |
| goto err; |
| } |
| #endif |
| |
| // 2. erase timh |
| if (mtd_erase(fd, timh->Flash_Start_Address, server_cfg.block_size) < 0) { |
| OTA_ERR("erase timh failed\n"); |
| goto err; |
| } |
| |
| // 3. erase obm |
| if (mtd_erase(fd, obm->Flash_Start_Address, server_cfg.block_size) < 0) { |
| OTA_ERR("erase obm failed\n"); |
| goto err; |
| } |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| /* unlock */ |
| emmc_boot_lock_unlock(emmc_boot_part, 0); |
| #endif |
| |
| // 4. write obm |
| if (__upgrade_obm(fd, obm->Flash_Start_Address, obm_file, timh_bk_file) < 0) { |
| OTA_ERR("update obm failed\n"); |
| goto err; |
| } |
| |
| // 5. write timh |
| if (__upgrade_timh(fd, timh->Flash_Start_Address, timh_file, |
| get_file_size(timh_file), block0, server_cfg.block_size, server_cfg.pagesize) < 0) { |
| OTA_ERR("update timh failed\n"); |
| goto err; |
| } |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| /* unlock */ |
| emmc_boot_lock_unlock(emmc_boot_part, 1); |
| #endif |
| OTA_DEBUG("%s: successfully...\n", __func__); |
| |
| r = 0; |
| err: |
| if (fd >= 0) { |
| #ifndef CONFIG_PARTITION_EMMC |
| ioctl(fd, MEMLOCKPRIV, NULL); |
| #endif |
| close(fd); |
| } |
| |
| if (block0) free(block0); |
| return r; |
| } |
| |
| static int get_soc_id(unsigned int *ddrid, unsigned int *cpuid) |
| { |
| #define CPUID_STR "chip_id: " |
| #define DDRID_STR "ddr_id: " |
| const char *file = "/dev/soc_id"; |
| int fd = -1, ret = -1; |
| char buf[64], *p; |
| |
| fd = open(file, O_RDONLY); |
| if (fd < 0) { |
| OTA_ERR("%s: open %s failed.\n", __func__, file); |
| goto err; |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| if (read(fd, buf, 64) < 0) { |
| OTA_ERR("%s: read failed.\n", __func__); |
| goto err; |
| } |
| |
| OTA_DEBUG("%s: soc: %s\n", __func__, buf); |
| p = strstr(buf, CPUID_STR); |
| if (!p) { |
| OTA_ERR("%s: not found chip id.\n", __func__); |
| goto err; |
| } |
| *cpuid = strtoul(p + strlen(CPUID_STR), NULL, 16); |
| |
| p = strstr(buf, DDRID_STR); |
| if (!p) { |
| OTA_ERR("%s: not found ddr id.\n", __func__); |
| goto err; |
| } |
| *ddrid = strtoul(p + strlen(DDRID_STR), NULL, 16); |
| |
| OTA_DEBUG("%s: got cpudid: 0x%x, ddrid: 0x%x\n", __func__, *cpuid, *ddrid); |
| err: |
| if (fd >= 0) close(fd); |
| return ret; |
| } |
| |
| /* |
| block0 = main timh + bbt |
| block1 = backup timh + bbt |
| block2 = main obm + backup timh |
| block3 = backup obm + main timh |
| */ |
| static int upgrade_bootloader(struct image_process_context * context) |
| { |
| int r = -1; |
| int cpuid, revision; |
| if (context->upgrade_bootloader != 1) |
| /* no bootloader */ |
| return 0; |
| |
| get_soc_id(&server_cfg.ddrid, &server_cfg.cpuid); |
| cpuid = server_cfg.cpuid & 0xffff; |
| revision = (server_cfg.cpuid >> 16) & 0xff; |
| context->same_tim = 0; |
| |
| #ifndef CONFIG_PARTITION_EMMC |
| switch (cpuid) { |
| case 0x1802: |
| case 0x1826: |
| server_cfg.max_timh_size = 4 * 1024; |
| break; |
| case 0x1803: |
| case 0x1828: |
| server_cfg.max_timh_size = 8 * 1024; |
| break; |
| case 0x1903: |
| if (context->dual_tim && (revision == 0xA0 || revision == 0xB0)) |
| context->same_tim = 1; |
| case 0x1901: |
| case 0x1906: |
| case 0x1806: |
| server_cfg.max_timh_size = 16 * 1024; |
| break; |
| default: |
| OTA_DEBUG("%s: default cpuid: 0x%x\n", __func__, server_cfg.cpuid); |
| server_cfg.max_timh_size = 16 * 1024; |
| break; |
| } |
| #endif |
| |
| OTA_DEBUG("%s: dual tim: %d, same tim: %d\n", __func__, context->dual_tim, context->same_tim); |
| if (access(tmp_obm_main_file, F_OK) || access(tmp_timh_main_file, F_OK)) { |
| OTA_ERR("%s: missing main.\n", __func__); |
| goto err; |
| } |
| |
| if (context->dual_tim) { |
| if (access(tmp_obm_bk_file, F_OK) || access(tmp_timh_bk_file, F_OK)) { |
| OTA_ERR("%s: missing backup.\n", __func__); |
| goto err; |
| } |
| } |
| |
| if (gAsrFlag.DDR_ID == 0 || gAsrFlag.DDR_ID == 0xFFFFFFFF) { |
| gAsrFlag.DDR_ID = server_cfg.ddrid; |
| OTA_DEBUG("%s: invalid ddrid in asrflag, use current ddrid.\n", __func__); |
| } |
| |
| if (gAsrFlag.DDR_ID != server_cfg.ddrid) |
| OTA_DEBUG("%s: Warning: mismatch ddrid, in asrflag: 0x%x, current ddrid: 0x%x\n", |
| __func__, gAsrFlag.DDR_ID, server_cfg.ddrid); |
| |
| if (retrive_timh_by_ddrid(tmp_timh_main_file, &gAsrFlag.DDR_ID, tmp_timh_main_target_file) < 0) { |
| OTA_ERR("failed to retrive timh for ddr: 0x%x to %s.\n", gAsrFlag.DDR_ID, tmp_timh_main_target_file); |
| goto err; |
| } |
| |
| if (context->dual_tim) { |
| if (retrive_timh_by_ddrid(tmp_timh_bk_file, &gAsrFlag.DDR_ID, tmp_timh_bk_target_file) < 0) { |
| OTA_ERR("failed to retrive timh for ddr: 0x%x to %s.\n", gAsrFlag.DDR_ID, tmp_timh_bk_target_file); |
| goto err; |
| } |
| } |
| |
| if (context->dual_tim) { |
| /* upgrade the backup bootloader */ |
| if (__upgrade_bootloader(context, TIMH_RECOVERY_INC) < 0) |
| goto err; |
| } |
| |
| /* then upgrade the main bootloader */ |
| if (__upgrade_bootloader(context, TIMH_INC) < 0) |
| goto err; |
| |
| r = 0; |
| err: |
| remove(tmp_obm_main_file); |
| remove(tmp_timh_main_file); |
| remove(tmp_timh_main_target_file); |
| if (context->dual_tim) { |
| remove(tmp_obm_bk_file); |
| remove(tmp_timh_bk_file); |
| remove(tmp_timh_bk_target_file); |
| } |
| return r; |
| } |
| #endif |
| |
| static int image_recheck(struct image_process_context * context) |
| { |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| ImginfoTable *p = context->image_info_table; |
| char *cache = malloc(FBF_FILE_SECTOR_SIZE); |
| int flag = 0; |
| if (!cache) { |
| OTA_ERR("no memory\n"); |
| return -1; |
| } |
| |
| ImginfoTable *tmp = p; |
| while (tmp) { |
| lseek(tmp->fd, 0, SEEK_SET); |
| tmp = tmp->next; |
| } |
| |
| while (p) { |
| p->cs = 0; |
| OTA_DEBUG("recheck %s, %s, %d\n", p->dev, p->name, p->Flash_Start_Address - p->Block_Start_Address); |
| if (p->Img_ID == IMAGE_ID_OBM || p->Img_ID == IMAGE_ID_TIMH) |
| lseek(p->fd, 0, SEEK_SET); |
| else |
| lseek(p->fd, p->Flash_Start_Address - p->Block_Start_Address, SEEK_SET); |
| /* |
| int ret = lseek(p->fd, 0, SEEK_SET); |
| if (ret < 0) |
| { |
| OTA_ERR("seek failed, %s\n", p->name); |
| flag = -1; |
| goto next; |
| } |
| */ |
| int remain = p->Img_Len; |
| while (remain > 0) { |
| int size = remain > FBF_FILE_SECTOR_SIZE ? FBF_FILE_SECTOR_SIZE : remain; |
| memset(cache, 0, FBF_FILE_SECTOR_SIZE); |
| int n = read(p->fd, cache, size); |
| if (n != size) { |
| OTA_ERR("read failed, read %d(expect %d), %s\n", n, size, p->name); |
| flag = -1; |
| goto next; |
| } |
| p->cs = fbf_checksum((unsigned char *)cache, FBF_FILE_SECTOR_SIZE, p->cs); |
| remain -= n; |
| } |
| |
| if (p->cs != p->Img_Checksum) { |
| OTA_ERR("%s, cs: 0x%x(expect 0x%x)\n", p->name, p->cs, p->Img_Checksum); |
| flag = -1; |
| goto next; |
| } else { |
| OTA_DEBUG("recheck %s, %s OK, cs: 0x%x(expect 0x%x)...\n", p->dev, p->name, p->cs, p->Img_Checksum); |
| } |
| next: |
| p = p->next; |
| } |
| |
| if (flag == 0) { |
| if (upgrade_bootloader(context) < 0) { |
| flag = -1; |
| OTA_ERR("%s: upgrade bootloader failed, don't reboot or powerdown...\n", |
| __func__); |
| return flag; |
| } |
| |
| /* all image write ok, update the active system slot */ |
| //#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| int slot = gInActiveSystem == SYSTEM_A ? 'a' : 'b'; |
| /* tell boot to update NVM files from oemd */ |
| if (update_oemd) |
| system("touch /NVM/oemd && sync"); |
| gAsrFlag.temp_active_slot = slot; |
| gAsrFlag.reboot_cnt = 0; |
| gAsrFlag.synced = 0; |
| |
| if (gInActiveSystem == SYSTEM_A) { |
| OTA_DEBUG("prev mversion a: %s updated to %s\n", gAsrFlag.mversion, server_cfg.fotav); |
| memset(gAsrFlag.mversion, 0, 128); |
| strncpy(gAsrFlag.mversion, server_cfg.fotav, 128); |
| } else { |
| OTA_DEBUG("prev mversion b: %s updated to %s\n", gAsrFlag.mversion, server_cfg.fotav); |
| memset(gAsrFlag.MVersion_B, 0, 128); |
| strncpy(gAsrFlag.MVersion_B, server_cfg.fotav, 128); |
| } |
| |
| write_asr_flag(&gAsrFlag); |
| } |
| return flag; |
| #else |
| struct image_state * image_state_list, * image_state_list_org; |
| int file_size = 0; |
| image_state_list_org = image_state_list = context->image_state_list; |
| if ((context->image_state_list == NULL) || (context->download_result != 1)) { |
| return -1; |
| } |
| |
| while (image_state_list) { |
| OTA_DEBUG("The image(0x%08x) process result %d\n", |
| image_state_list->image_info->Img_Checksum, image_state_list->result); |
| if (!image_state_list->result) return -1;; |
| image_state_list = image_state_list->next_image; |
| } |
| |
| if (!image_state_list && image_state_list_org) { |
| if (verify_flash_image(context, &file_size)) { |
| return -1; |
| } |
| } |
| /* set dlflag for non-AB */ |
| /* tell boot to update NVM files from oemd */ |
| if (update_oemd) |
| system("touch /NVM/oemd && sync"); |
| |
| if(get_asr_flag(&gAsrFlag)) { |
| OTA_ERR("Fail to get asr flag\n"); |
| return -1; |
| } |
| gAsrFlag.upgrade_flag = 1; |
| gAsrFlag.fbf_flash_address = server_cfg.fbf_addr + server_cfg.block_size; |
| gAsrFlag.fbf_file_size = context->processed_cnt; |
| gAsrFlag.upgrade_method = context->upgrade_method; |
| gAsrFlag.dfota_n_of_images = 0xFFFFFFFF; |
| |
| if(write_asr_flag(&gAsrFlag)) { |
| OTA_ERR("Fail to write asr flag\n"); |
| return -1; |
| } |
| #endif |
| return 0; |
| } |
| |
| static int build_udp_server(const char * path) |
| { |
| int fd = -1; |
| struct timeval timeout = {10, 0}; |
| struct sockaddr_un un = {0}; |
| int size; |
| |
| unlink(path); |
| un.sun_family = AF_UNIX; |
| sprintf(un.sun_path, "%s", path); |
| OTA_DEBUG("Will create socket at %s\n", un.sun_path); |
| if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
| OTA_ERR("Build socket failed!\n"); |
| return -1; |
| } |
| if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))) { |
| OTA_ERR("Set timeout failed!\n"); |
| goto failed; |
| } |
| |
| size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path); |
| if (bind(fd, (struct sockaddr*)&un, size)) { |
| OTA_ERR("Bind failed!\n"); |
| goto failed; |
| } |
| //(void)chmod(un.sun_path, 0777); |
| OTA_DEBUG("will listen on %d\n", fd); |
| if (listen(fd, 5) < 0) { |
| OTA_ERR("Listen failed!\n"); |
| goto failed; |
| } |
| return fd; |
| |
| failed: |
| if (fd > 0) { |
| close(fd); |
| } |
| return -1; |
| } |
| |
| static int accept_udp(int fd) |
| { |
| struct timeval timeout = {10, 0}; |
| int client; |
| |
| client = accept(fd, NULL, 0); |
| if (client < 0) { |
| OTA_ERR("Accept failed!\n"); |
| } else { |
| setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); |
| } |
| return client; |
| } |
| |
| static void __download_throgh_udp(int fd, int size, struct image_process_context * context) |
| { |
| int total = size; |
| char * buf = malloc(4096); |
| int res=0; |
| |
| if (buf == NULL) { |
| OTA_ERR("memory issue at __download_through_udp!\n"); |
| return; |
| } |
| |
| // for debug |
| OTA_DEBUG("size: %d.\n", size); |
| |
| while (total) { |
| int recved = 0; |
| memset(buf, 0, 4096); |
| |
| int n = total > 4096 ? 4096 : total; |
| int ret; |
| repeat: |
| ret = recv(fd, buf + recved, n, 0); |
| if (ret <= 0) { |
| OTA_ERR("recv failed! errno: %d, %s\n", errno, strerror(errno)); |
| if (errno == EAGAIN) { |
| sleep(1); |
| OTA_DEBUG("try again.\n"); |
| goto repeat; |
| } |
| goto done; |
| } |
| recved += ret; |
| n -= ret; |
| if (n != 0) { |
| //OTA_DEBUG("recved: %d, n: %d, ret: %d\n", recved, n, ret); |
| goto repeat; |
| } |
| |
| res=firmware_download_cb(buf, recved, size, context); |
| if(res<0){ |
| goto done; |
| } |
| total -= recved; |
| }; |
| OTA_DEBUG("__download_throgh_udp received_size[%d],file_size[%d]\n", download_method_ctx.received_size,download_method_ctx.file_size); |
| if(download_method_ctx.received_size == download_method_ctx.file_size){ |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| flush_flash(context); |
| #endif |
| context->download_result = 1; |
| } |
| done: |
| if (buf) { |
| free(buf); |
| buf = NULL; |
| } |
| return; |
| } |
| |
| |
| |
| |
| static int erase_ota_fbf_area(void) |
| { |
| #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| return 0; |
| #else |
| struct erase_info_user mtdEraseInfo; |
| struct mtd_info_user mtdInfo; |
| int fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| if (ioctl(fd, MEMGETINFO, &mtdInfo)) { |
| OTA_ERR("Could not get MTD FBF device info from %s\n", server_cfg.mtd_fbf); |
| close(fd); |
| update_state = UPDATE_STATE_FAILED; |
| return -1; |
| } |
| mtdEraseInfo.length = mtdInfo.erasesize; |
| for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdInfo.size; mtdEraseInfo.start += mtdInfo.erasesize) { |
| ioctl(fd, MEMUNLOCK, &mtdEraseInfo); |
| ioctl(fd, MEMERASE, &mtdEraseInfo); |
| } |
| close(fd); |
| fd = -1; |
| sync(); |
| #endif |
| return 0; |
| |
| } |
| |
| static struct image_process_context *udp_context=NULL; |
| static int udp_download_cb(struct uloop_timeout *timeout) |
| { |
| //int type = download_method_ctx.type; |
| int size = download_method_ctx.size; |
| int segment_size = download_method_ctx.segment_size; |
| char * url = download_method_ctx.url; |
| char * username = download_method_ctx.username; |
| char * psw = download_method_ctx.pwd; |
| int ret = -1; |
| struct image_process_context *context=NULL; |
| |
| if(size==0 && udp_context==NULL){ |
| OTA_ERR("ubus call donwload paramer abnormal!\n");//rm60362 |
| notify_download_end(0); |
| update_state = UPDATE_STATE_FAILED; |
| goto exit; |
| } |
| |
| if(size!=0){ |
| if(udp_context){ |
| if (udp_context->flash_cache) free(udp_context->flash_cache); |
| udp_context->flash_cache = NULL; |
| if (udp_context->checksum_cache) free(udp_context->checksum_cache); |
| udp_context->checksum_cache = NULL; |
| if(udp_context->fd!=-1){ |
| close(udp_context->fd); |
| udp_context->fd = -1; |
| } |
| |
| if (udp_context->image_state_list) { |
| free_image_list(udp_context); |
| udp_context->image_state_list=NULL; |
| } |
| if(udp_context){ |
| free(udp_context); |
| udp_context = NULL; |
| } |
| |
| } |
| |
| udp_context = (struct image_process_context *)malloc(sizeof(struct image_process_context)); |
| memset(udp_context,0,sizeof(struct image_process_context)); |
| } |
| context = udp_context; |
| |
| if(size!=0){ |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| context->fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| if (context->fd < 0) { |
| OTA_ERR("Cannot open MTD device!\n"); |
| notify_download_end(0); |
| update_state = UPDATE_STATE_FAILED; |
| return ret; |
| } |
| #endif |
| notify_download_start(); |
| _ota_download_progress = ota_download_progress = 0; |
| |
| download_method_ctx.file_size = size; |
| download_method_ctx.received_size = 0; |
| // Init firmware download context |
| context->flash_cache = malloc(server_cfg.block_size); |
| if (!context->flash_cache) { |
| OTA_ERR("Cannot malloc memory for download cache\n"); |
| goto done; |
| } |
| #ifdef CONFIG_AB_SYSTEM |
| memset(context->flash_cache, 0, server_cfg.block_size); |
| #endif |
| context->checksum_cache = malloc(CHECKSUM_CACHE_SIZE); |
| if (!context->checksum_cache) { |
| OTA_ERR("Cannot malloc memory for download cache\n"); |
| goto done; |
| } |
| context->flash_cb = push2flash; |
| } |
| |
| // download from UDP |
| int s = -1, c = -1; |
| OTA_DEBUG("Download through UDP\n"); |
| s = build_udp_server(url); |
| if (s >= 0) { |
| c = accept_udp(s); |
| if (c >= 0) { |
| |
| if(size!=0){ |
| if(erase_ota_fbf_area()) |
| goto done; |
| } |
| |
| __download_throgh_udp(c, segment_size, context); |
| |
| }else{ |
| OTA_ERR("accept_udp failed\n"); |
| } |
| }else{ |
| OTA_ERR("build_udp_server failed\n"); |
| return 0; |
| } |
| if (s >= 0) close(s); |
| if (c >= 0) close(c); |
| ret = 0; |
| |
| done: |
| if(download_method_ctx.file_size == download_method_ctx.received_size){ |
| // Clear context |
| if (context->flash_cache) free(context->flash_cache); |
| context->flash_cache = NULL; |
| if (context->checksum_cache) free(context->checksum_cache); |
| context->checksum_cache = NULL; |
| close(context->fd); |
| context->fd = -1; |
| if (image_recheck(context) == 0) { |
| update_state = UPDATE_STATE_UPDATED; |
| OTA_ERR("%s: Image download succssful.\n", __func__); |
| notify_download_end(1); |
| ret = 0; |
| } else { |
| update_state = UPDATE_STATE_FAILED; |
| OTA_ERR("Image download failed\n"); |
| notify_download_end(0); |
| ret = -1; |
| } |
| if (context->image_state_list) { |
| free_image_list(context); |
| context->image_state_list=NULL; |
| } |
| if(udp_context){ |
| free(udp_context); |
| udp_context = NULL; |
| } |
| |
| |
| } |
| else{ |
| //update_state = UPDATE_STATE_IDLE; |
| //notify_download_end(1); |
| } |
| exit: |
| |
| if (url) free(url); |
| url = NULL; |
| if (username) free(username); |
| username = NULL; |
| if (psw) free(psw); |
| psw = NULL; |
| return ret; |
| } |
| |
| |
| static int download_cb(struct uloop_timeout *timeout) |
| { |
| int type = download_method_ctx.type; |
| int size = download_method_ctx.size; |
| char * url = download_method_ctx.url; |
| char * username = download_method_ctx.username; |
| char * psw = download_method_ctx.pwd; |
| struct image_process_context context = {0}; |
| int ret = -1; |
| |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| context.fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| if (context.fd < 0) { |
| OTA_ERR("Cannot open MTD device!\n"); |
| notify_download_end(0); |
| update_state = UPDATE_STATE_FAILED; |
| return ret; |
| } |
| #endif |
| notify_download_start(); |
| |
| _ota_download_progress = ota_download_progress = 0; |
| // Init firmware download context |
| context.flash_cache = malloc(server_cfg.block_size); |
| if (!context.flash_cache) { |
| OTA_ERR("Cannot malloc memory for download cache\n"); |
| goto done; |
| } |
| #ifdef CONFIG_AB_SYSTEM |
| memset(context.flash_cache, 0, server_cfg.block_size); |
| #endif |
| context.checksum_cache = malloc(CHECKSUM_CACHE_SIZE); |
| if (!context.checksum_cache) { |
| OTA_ERR("Cannot malloc memory for download cache\n"); |
| goto done; |
| } |
| context.flash_cb = push2flash; |
| |
| if (type == OTA_TYPE_HTTP) { |
| // download from http |
| if(erase_ota_fbf_area()) |
| goto done; |
| __download_throgh_http(url, &context); |
| } else if (type == OTA_TYPE_UDP) { |
| // download from UDP |
| int s = -1, c = -1; |
| OTA_DEBUG("Download through UDP\n"); |
| s = build_udp_server(url); |
| if (s >= 0) { |
| c = accept_udp(s); |
| if (c >= 0) { |
| if(erase_ota_fbf_area()) |
| goto done; |
| __download_throgh_udp(c, size, &context); |
| } |
| } |
| if (s >= 0) close(s); |
| if (c >= 0) close(c); |
| } else if (type == OTA_TYPE_SD) { |
| // download from SD |
| if(erase_ota_fbf_area()) |
| goto done; |
| __download_throgh_sd(url, &context); |
| } else { |
| // assert? |
| OTA_ERR("Unknow download type\n"); |
| } |
| |
| done: |
| // Clear context |
| if (context.flash_cache) free(context.flash_cache); |
| context.flash_cache = NULL; |
| if (context.checksum_cache) free(context.checksum_cache); |
| context.checksum_cache = NULL; |
| if (url) free(url); |
| url = NULL; |
| if (username) free(username); |
| username = NULL; |
| if (psw) free(psw); |
| psw = NULL; |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| close(context.fd); |
| context.fd = -1; |
| #endif |
| // Change by mbtk |
| if ((image_recheck(&context) == 0) && !Download_flag) { |
| update_state = UPDATE_STATE_UPDATED; |
| OTA_DEBUG("Image download succssful\n"); |
| |
| // Add by liubin |
| revision_out_update(); |
| // End by liubin |
| |
| notify_download_end(1); |
| ret = 0; |
| } else { |
| update_state = UPDATE_STATE_FAILED; |
| OTA_ERR("Image download failed\n"); |
| notify_download_end(0); |
| ret = -1; |
| } |
| |
| if (context.image_state_list) { |
| free_image_list(&context); |
| } |
| return ret; |
| } |
| |
| static struct uloop_timeout download_timer = { .cb = (void*)download_cb }; |
| static struct uloop_timeout udp_download_timer = { .cb = (void*)udp_download_cb }; |
| |
| |
| static int download_func(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, |
| struct blob_attr *msg) |
| { |
| struct blob_attr *tb[__DOWNLOAD_MAX]; |
| int ret = -1; |
| int sync = 0; /* default is no sync */ |
| int type=-1; |
| blob_buf_init(&b, 0); |
| |
| blobmsg_parse(download_policy, ARRAY_SIZE(download_policy), tb, blob_data(msg), blob_len(msg)); |
| if (tb[DOWNLOAD_TYPE]) type = blobmsg_get_u32(tb[DOWNLOAD_TYPE]); |
| |
| |
| if ((update_state == UPDATE_STATE_IDLE ||update_state == UPDATE_STATE_FAILED) || |
| (type == OTA_TYPE_UDP && update_state == UPDATE_STATE_UPDATING)) { |
| update_state = UPDATE_STATE_UPDATING; |
| |
| OTA_DEBUG("Method call: %s\n", method); |
| //memset(&download_method_ctx, 0, sizeof(download_method_ctx)); |
| download_method_ctx.url = download_method_ctx.username = download_method_ctx.pwd =NULL; |
| download_method_ctx.type = download_method_ctx.size = download_method_ctx.segment_size= 0; |
| if (tb[DOWNLOAD_URL]) download_method_ctx.url = strdup(blobmsg_data(tb[DOWNLOAD_URL])); |
| if (tb[DOWNLOAD_NAME]) download_method_ctx.username = strdup(blobmsg_data(tb[DOWNLOAD_NAME])); |
| if (tb[DOWNLOAD_PSW]) download_method_ctx.pwd = strdup(blobmsg_data(tb[DOWNLOAD_PSW])); |
| if (tb[DOWNLOAD_TYPE]) download_method_ctx.type = blobmsg_get_u32(tb[DOWNLOAD_TYPE]); |
| if (tb[DOWNLOAD_FILE_SIZE]) download_method_ctx.size = blobmsg_get_u32(tb[DOWNLOAD_FILE_SIZE]); |
| if (tb[DOWNLOAD_SYNC]) sync = blobmsg_get_u32(tb[DOWNLOAD_SYNC]); |
| if (tb[DOWNLOAD_SEGMENT_SIZE]) download_method_ctx.segment_size = blobmsg_get_u32(tb[DOWNLOAD_SEGMENT_SIZE]); |
| |
| if (download_method_ctx.url) OTA_DEBUG(" url: %s\n", download_method_ctx.url); |
| if (download_method_ctx.username) OTA_DEBUG(" username: %s\n", download_method_ctx.username); |
| if (download_method_ctx.pwd) OTA_DEBUG(" password: %s\n", download_method_ctx.pwd); |
| OTA_DEBUG(" type: %d, size: %d ,segment size: %d\n", download_method_ctx.type, download_method_ctx.size,download_method_ctx.segment_size); |
| |
| if (sync != 1) { |
| if(download_method_ctx.type == OTA_TYPE_UDP){ |
| uloop_timeout_set(&udp_download_timer, 1); |
| }else{ |
| uloop_timeout_set(&download_timer, 1); |
| } |
| blobmsg_add_string(&b, "response", "download ready"); |
| ret = 0; |
| } else { |
| if(download_method_ctx.type == OTA_TYPE_UDP){ |
| ret = udp_download_cb(&udp_download_timer); |
| }else{ |
| ret = download_cb(&download_timer); |
| } |
| if (ret == 0) { |
| blobmsg_add_string(&b, "response", "image download succssful"); |
| } else { |
| blobmsg_add_string(&b, "response", "image download failed"); |
| } |
| } |
| } else { |
| OTA_ERR("Error! update already in processing or be processed\n"); |
| blobmsg_add_string(&b, "response", "download failed (update already in processing or be processed)"); |
| ret = -1; |
| } |
| |
| ubus_send_reply(ctx, req, b.head); |
| return ret; |
| } |
| |
| // Version check |
| struct xml_parse_context { |
| const char * file; |
| int i; |
| char tag[OTA_MAX_STRING_LEN]; |
| char * value; |
| int value_size; |
| int state; |
| }; |
| enum { |
| XML_STATE_NULL, |
| XML_STATE_TAG, |
| XML_STATE_VALUE, |
| }; |
| static int get_next_tag(struct xml_parse_context * context) |
| { |
| int len = 0; |
| int i = context->i; |
| int start = 0; |
| if (context->file[i++] != '<') { |
| return -1; |
| } |
| if (context->file[i] == '/') { |
| return -1; |
| } |
| start = i; |
| while (context->file[i] != '\0') { |
| if (context->file[i] == '>') { |
| memset(context->tag, 0, OTA_MAX_STRING_LEN); |
| if (len > OTA_MAX_STRING_LEN) { |
| OTA_ERR("Memory issue in get_next_tag(%d)!\n", len); |
| return -1; |
| } |
| memcpy(context->tag, &context->file[start], len); |
| context->i += (len + 2); |
| OTA_DEBUG("Tag: %s\n", context->tag); |
| return 0; |
| } |
| len++; |
| i++; |
| } |
| return -1; |
| } |
| static int get_next_value(struct xml_parse_context * context) |
| { |
| int len = 0; |
| int i = context->i; |
| int start = 0; |
| if (context->file[i] == '<') { |
| return -1; |
| } |
| while (context->file[i] == '\r' || context->file[i] == '\t' || context->file[i] == '\n') { |
| i++; |
| } |
| start = i; |
| while (context->file[i] != '\0') { |
| if (context->file[i] == '<') { |
| if (context->file[i + 1] != '/') { |
| OTA_ERR("Bad file!\n"); |
| return -1; |
| } |
| if (strncmp(&context->file[i + 2], context->tag, strlen(context->tag))) { |
| OTA_ERR("tag not match!\n"); |
| return -1; |
| } |
| memset(context->value, 0, context->value_size); |
| if (len > context->value_size) { |
| OTA_ERR("Memory issue in get_next_vale(%d:%d)!\n", len, context->value_size); |
| return -1; |
| } |
| memcpy(context->value, &context->file[start], len); |
| context->i += (len + 3 + strlen(context->tag)); |
| OTA_DEBUG("Value: %s\n", context->value); |
| return 0; |
| } |
| len++; |
| i++; |
| } |
| return -1; |
| } |
| |
| static int version_parse(const char * string, struct version_info * ver) |
| { |
| #define OTA_MARVELL_VERSION_TAG "Marvell" |
| #define OTA_MARVELL_VERSION_TAG_VER "Version" |
| #define OTA_MARVELL_VERSION_TAG_URL "URL" |
| #define OTA_MARVELL_VERSION_TAG_NOTE "ReleaseNote" |
| struct xml_parse_context context = {0}; |
| #define MAX_XML_VALUE_SIZE 4096 |
| int ret = 0; |
| |
| if (string == NULL || ver == NULL) { |
| OTA_ERR("Invalid parameters!\n"); |
| return -1; |
| } |
| |
| context.file = string; |
| context.value = malloc(MAX_XML_VALUE_SIZE); |
| if (context.value == NULL) { |
| OTA_ERR("Malloc for context buffer failed!\n"); |
| return -1; |
| } |
| context.value_size = MAX_XML_VALUE_SIZE; |
| |
| if (get_next_tag(&context) < 0) { |
| OTA_ERR("Parse first tag failed!\n"); |
| ret = -1; |
| goto done; |
| } |
| if (strcmp(context.tag, OTA_MARVELL_VERSION_TAG)) { |
| OTA_ERR("First tag is not %s\n", OTA_MARVELL_VERSION_TAG); |
| ret = -1; |
| goto done; |
| } |
| while (get_next_tag(&context) == 0) { |
| if (get_next_value(&context) == 0) { |
| if (!strcmp(context.tag, OTA_MARVELL_VERSION_TAG_VER)) { |
| OTA_DEBUG("Handle version: %s\n", context.value); |
| snprintf(ver->version, OTA_MAX_STRING_LEN, "%s", context.value); |
| } else if (!strcmp(context.tag, OTA_MARVELL_VERSION_TAG_URL)) { |
| OTA_DEBUG("Handle URL: %s\n", context.value); |
| snprintf(ver->url, OTA_MAX_STRING_LEN, "%s", context.value); |
| } else if (!strcmp(context.tag, OTA_MARVELL_VERSION_TAG_NOTE)) { |
| OTA_DEBUG("Handle release note: %s\n", context.value); |
| if (ver->release_note) { |
| free(ver->release_note); |
| ver->release_note = NULL; |
| } |
| ver->release_note = strdup(context.value); |
| } |
| } |
| } |
| done: |
| if (context.value) { |
| free(context.value); |
| } |
| return ret; |
| } |
| |
| static int version_check_cb(char * data, int len, int num, void *cbdata) |
| { |
| struct version_check_context * context = (struct version_check_context *)cbdata; |
| if ((context->size - context->used) < len) { |
| char * buf = realloc(context->url, context->size + num); |
| if (buf == NULL) { |
| OTA_ERR("Memory issue at version_check_cb\n"); |
| return -1; |
| } |
| context->size += num; |
| context->url = buf; |
| memcpy(context->url + context->used, data, len); |
| context->used += len; |
| } else { |
| memcpy(context->url + context->used, data, len); |
| context->used += len; |
| } |
| return 0; |
| } |
| struct version_check_context version_check_context = {0}; |
| static int detect_new_version(struct ota_server * server, char ** firmwar_url) |
| { |
| struct http_client * client = NULL; |
| struct http_client_list * header = NULL; |
| int http_response_code = 0; |
| int ret = -1; |
| char buf[OTA_MAX_STRING_LEN + 30] = {0}; |
| |
| OTA_DEBUG("Try access %s for version check\n", server->server_url); |
| |
| client = http_client_init(); |
| if (client == NULL) { |
| OTA_ERR("HTTP client init failed!\n"); |
| return -1; |
| } |
| |
| version_check_context.url = malloc(OTA_MAX_STRING_LEN); |
| if (version_check_context.url == NULL) { |
| OTA_ERR("Malloc failed!\n"); |
| goto done; |
| } |
| memset(version_check_context.url, 0, OTA_MAX_STRING_LEN); |
| version_check_context.size = OTA_MAX_STRING_LEN; |
| version_check_context.used = 0; |
| |
| http_client_setopt(client, HTTPCLIENT_OPT_URL, server->server_url); |
| http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, version_check_cb); |
| http_client_setopt(client, HTTPCLIENT_OPT_METHOD, HTTPCLIENT_REQUEST_POST); |
| http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB_DATA, &version_check_context); |
| snprintf(buf, sizeof(buf), "MarvellOTA: version=%s\r\n", version_check_context.version); |
| header = http_client_list_append(header, buf); |
| http_client_setopt(client, HTTPCLIENT_OPT_HTTPHEADER, header); |
| http_client_perform(client); |
| http_client_getinfo(client, HTTPCLIENT_GETINFO_RESPONSE_CODE, &http_response_code); |
| |
| OTA_DEBUG("Version check result: %d\n", http_response_code); |
| if (http_response_code == 200) { |
| version_parse(version_check_context.url, &server_cfg.ver); |
| OTA_DEBUG("Detected new version at: %s\n", server_cfg.ver.url); |
| *firmwar_url = strdup(server_cfg.ver.url); |
| } else { |
| // Free memory |
| // If http response is HTTP 200 OK, version checking caller should free this memory |
| free(version_check_context.url); |
| version_check_context.url = NULL; |
| version_check_context.size = 0; |
| version_check_context.used = 0; |
| } |
| ret = 0; |
| done: |
| if (client) http_client_shutdown(client); |
| return ret; |
| } |
| |
| enum { |
| QUERY_TYPE, |
| __QUERY_MAX |
| }; |
| |
| static const struct blobmsg_policy query_policy[] = { |
| [QUERY_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }, |
| }; |
| |
| static int query_func(struct ubus_context *ctx, struct ubus_object *obj, |
| struct ubus_request_data *req, const char *method, |
| struct blob_attr *msg) |
| { |
| struct blob_attr *tb[__QUERY_MAX]; |
| char * type = NULL; |
| const char * string = NULL; |
| |
| OTA_DEBUG("enter: %s\n", __func__); |
| blobmsg_parse(query_policy, ARRAY_SIZE(query_policy), tb, blob_data(msg), blob_len(msg)); |
| |
| if (tb[QUERY_TYPE]) type = blobmsg_data(tb[QUERY_TYPE]); |
| if (type == NULL) { |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "response", "failed"); |
| ubus_send_reply(ctx, req, b.head); |
| OTA_ERR("Failed query type\n"); |
| return 0; |
| } |
| if (*type == '1') { |
| // Download states |
| switch (update_state) { |
| case UPDATE_STATE_UPDATING: |
| string = "updating"; |
| break; |
| case UPDATE_STATE_UPDATED: |
| string = "success"; |
| break; |
| case UPDATE_STATE_FAILED: |
| string = "failed"; |
| break; |
| case UPDATE_STATE_IDLE: |
| default: |
| string = "not start"; |
| break; |
| } |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "response", string); |
| ubus_send_reply(ctx, req, b.head); |
| return 0; |
| } else if (*type == '0' ) { |
| // Query new version |
| int len = strlen(server_cfg.ver.version); |
| if (len != 0) { |
| char * buf = malloc(len + 50); |
| if (buf == NULL) { |
| OTA_ERR("Malloc failed!\n"); |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "response", "failed:memory issue"); |
| ubus_send_reply(ctx, req, b.head); |
| return 0; |
| } |
| memset(buf, 0, len + 30); |
| sprintf(buf, "has new version:[%s]", server_cfg.ver.version); |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "response", buf); |
| ubus_send_reply(ctx, req, b.head); |
| free(buf); |
| buf = NULL; |
| return 0; |
| } else { |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "response", "no new version"); |
| ubus_send_reply(ctx, req, b.head); |
| return 0; |
| } |
| } else { |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "response", "unkonw"); |
| ubus_send_reply(ctx, req, b.head); |
| OTA_ERR("unkonw query type %s\n", type); |
| return 0; |
| } |
| } |
| |
| static const struct ubus_method otad_method[] = { |
| UBUS_METHOD("download", download_func, download_policy), |
| UBUS_METHOD("query", query_func, query_policy), |
| }; |
| |
| static struct ubus_object_type otad_object_type = UBUS_OBJECT_TYPE("ota", otad_method); |
| |
| static struct ubus_object ota_object = { |
| .name = "ota", |
| .type = &otad_object_type, |
| .methods = otad_method, |
| .n_methods = ARRAY_SIZE(otad_method), |
| }; |
| |
| static void version_check(struct uloop_timeout *timeout); |
| static struct uloop_timeout version_check_timer = { .cb = version_check }; |
| |
| |
| static void version_check(struct uloop_timeout *timeout) |
| { |
| char * firmware = NULL; |
| OTA_DEBUG("Try checking new version\n"); |
| |
| if (update_state == UPDATE_STATE_UPDATING) { |
| OTA_ERR("Firmware updating... Reset timer.\n"); |
| goto reset_timer; |
| } else if (update_state == UPDATE_STATE_UPDATED) { |
| OTA_ERR("Firmware already be updated, not need detect again\n"); |
| return; |
| } |
| |
| detect_new_version(&server_cfg, &firmware); |
| if (firmware && strlen(firmware) && server_cfg.download_immediately != 0) { |
| OTA_DEBUG("New firmware at: %s\n", firmware); |
| do { |
| unsigned int id; |
| static struct ubus_request req; |
| char firmare_url[OTA_MAX_STRING_LEN + 1] = {0}; |
| snprintf(firmare_url, sizeof(firmare_url), "%s/%s", server_cfg.server_url, firmware); |
| if (ubus_lookup_id(ctx, "ota", &id)) { |
| OTA_ERR("Cannot found object...\n"); |
| break; |
| } |
| blob_buf_init(&b, 0); |
| blobmsg_add_string(&b, "url", firmare_url); |
| blobmsg_add_string(&b, "username", "user name"); |
| blobmsg_add_u32(&b, "type", 0); |
| ubus_invoke_async(ctx, id, "download", b.head, &req); |
| ubus_complete_request_async(ctx, &req); |
| } while (0); |
| free(firmware); |
| firmware = NULL; |
| if (update_state == UPDATE_STATE_UPDATED) { |
| //1TODO: Post system reset for new image install |
| OTA_DEBUG("Firmware download success, will post system reboot\n"); |
| return; |
| } else { |
| uloop_timeout_set(&version_check_timer, server_cfg.interval * 2); |
| } |
| } |
| reset_timer: |
| uloop_timeout_set(&version_check_timer, server_cfg.interval * 1000); |
| } |
| |
| static unsigned int get_mtd_offset(int mtd) |
| { |
| char file[64] = {0}; |
| char content[32] = {0}; |
| int fd; |
| sprintf(file, "/sys/class/mtd/mtd%d/offset", mtd); |
| fd = open(file, O_RDONLY); |
| if (fd < 0) { |
| OTA_ERR("%s: failed to open %s\n", __func__, file); |
| return -1; |
| } |
| |
| read(fd, content, 32); |
| close(fd); |
| return atoi(content); |
| } |
| |
| #ifdef CONFIG_AB_SYSTEM |
| #ifndef CONFIG_PARTITION_EMMC |
| static int get_mtd_pagesize(int mtd, unsigned int *pagesize) |
| { |
| struct mtd_info_user mtdinfo; |
| char dev[32]; |
| int fd; |
| |
| memset(dev, 0, sizeof(dev)); |
| sprintf(dev, "/dev/mtd%d", mtd); |
| fd = open(dev, O_RDONLY); |
| if (fd < 0) { |
| OTA_ERR("%s: failed to open %s.\n", __func__, dev); |
| return -1; |
| } |
| |
| if (ioctl(fd, MEMGETINFO, &mtdinfo)) { |
| OTA_ERR("%s: Could not get MTD device info from %s\n", __func__, dev); |
| close(fd); |
| return -1; |
| } |
| |
| *pagesize = mtdinfo.writesize; |
| OTA_DEBUG("%s: %s, pagesize: %d\n", __func__, dev, *pagesize); |
| |
| return 0; |
| } |
| #endif |
| #endif |
| |
| static int init_cfg(const char * uci_path) |
| { |
| FILE * fp = NULL; |
| #define MAX_LINE_SIZE 128 |
| char buf[MAX_LINE_SIZE] = {0}; |
| |
| #if 0 |
| /* |
| ota.@ota[0]=ota |
| ota.@ota[0].fbf_address='0x2A60000' |
| ota.@ota[0].progress_notify='10' |
| ota.@ota[0].interval='5' |
| ota.@ota[0].first_interval='1' |
| */ |
| if (uci_path) { /* If UCI file exist parse it */ |
| struct uci_context *uci_ctx = NULL; |
| struct uci_package *p = NULL; |
| struct uci_section *s = NULL; |
| struct uci_element *e1 = NULL, *e2 = NULL; |
| uci_ctx = uci_alloc_context(); |
| if (uci_load(uci_ctx, uci_path, &p)) { |
| OTA_ERR("uci load failed\n"); |
| uci_free_context(uci_ctx); |
| return -1; |
| } |
| |
| uci_foreach_element(&p->sections, e1) { |
| s = uci_to_section(e1); |
| if (strcmp(s->type, "ota")) { |
| continue; |
| } |
| |
| uci_foreach_element(&s->options, e2) { |
| if (!strcmp((uci_to_option(e2))->e.name, "server_url")) { |
| OTA_DEBUG("OTA server URL: %s\n", (uci_to_option(e2))->v.string); |
| snprintf(server_cfg.server_url, OTA_MAX_STRING_LEN, "%s", (uci_to_option(e2))->v.string); |
| } else if (!strcmp((uci_to_option(e2))->e.name, "progress_nofity")) { |
| OTA_DEBUG("Download notify interval: %s\n", (uci_to_option(e2))->v.string); |
| sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.progress_notify); |
| } else if (!strcmp((uci_to_option(e2))->e.name, "interval")) { |
| OTA_DEBUG("Download version detect interval: %s\n", (uci_to_option(e2))->v.string); |
| sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.interval); |
| } else if (!strcmp((uci_to_option(e2))->e.name, "first_interval")) { |
| OTA_DEBUG("Download first version detect interval: %s\n", (uci_to_option(e2))->v.string); |
| sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.first_interval); |
| } else if (!strcmp((uci_to_option(e2))->e.name, "download_immediately")) { |
| OTA_DEBUG("Download firmware immediately: %s\n", (uci_to_option(e2))->v.string); |
| sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.download_immediately); |
| } |
| } |
| } |
| |
| uci_free_context(uci_ctx); |
| uci_ctx = NULL; |
| } |
| #endif |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| fp = fopen("/proc/emmc", "r"); |
| #else |
| fp = fopen("/proc/mtd", "r"); |
| #endif |
| if (fp == NULL) { |
| OTA_ERR("Open MTD failed!\n"); |
| return -1; |
| } |
| |
| #ifdef CONFIG_AB_SYSTEM |
| server_cfg.mtd_cnt = 0; |
| OTA_DEBUG("Start to retrive the mtd partition info...\n"); |
| #ifdef CONFIG_PARTITION_EMMC |
| server_cfg.emmc_block_size = 512; /* emmc */ |
| server_cfg.block_size = 0x20000; /* only used for buffer cache size */ |
| |
| struct image_mtd_info *bootdev; |
| /* the main bootloader */ |
| bootdev = &server_cfg.image_mtd_info[0]; |
| sprintf(bootdev->dev, "%s", "mmcblk1boot0"); |
| sprintf(bootdev->name, "%s", "bootloader0"); |
| bootdev->flag = SYSTEM_SINGLE; |
| bootdev->flash_start_offset = 0; |
| |
| /* the backup bootloader */ |
| bootdev = &server_cfg.image_mtd_info[1]; |
| sprintf(bootdev->dev, "%s", "mmcblk1boot1"); |
| sprintf(bootdev->name, "%s", "bootloader1"); |
| bootdev->flag = SYSTEM_SINGLE; |
| bootdev->flash_start_offset = 0; |
| |
| server_cfg.mtd_cnt = 2; |
| #else |
| server_cfg.block_size = 0x20000; /* nand flash */ |
| if (get_mtd_pagesize(0, &server_cfg.pagesize) < 0) { |
| fclose(fp); |
| return -1; |
| } |
| #endif |
| #endif |
| |
| /* |
| root@OpenWrt:~# cat /proc/mtd |
| dev: size erasesize name |
| mtd0: 000a0000 00020000 "bootloader" |
| mtd1: 00020000 00020000 "cp_reliabledata" |
| mtd2: 00020000 00020000 "ap_reliabledata" |
| mtd3: 00020000 00020000 "cp_reliabledata_backup" |
| mtd4: 00020000 00020000 "ap_reliabledata_backup" |
| mtd5: 00020000 00020000 "mep-ota" |
| mtd6: 00020000 00020000 "mep-ota_backup" |
| mtd7: 00100000 00020000 "asr_flag" |
| mtd8: 00040000 00020000 "dtim-a" |
| mtd9: 00040000 00020000 "dtim-b" |
| mtd10: 00de0000 00020000 "cpimage-a" |
| mtd11: 00de0000 00020000 "cpimage-b" |
| mtd12: 000c0000 00020000 "u-boot-a" |
| mtd13: 000c0000 00020000 "u-boot-b" |
| mtd14: 00500000 00020000 "kernel-a" |
| mtd15: 00500000 00020000 "kernel-b" |
| mtd16: 00040000 00020000 "device_info" |
| mtd17: 02800000 00020000 "OTA" |
| mtd18: 00040000 00020000 "cust_info" |
| mtd19: 00020000 00020000 "rootfs-a-sdtim" |
| mtd20: 013e0000 00020000 "rootfs-a-mount" |
| mtd21: 01400000 00020000 "rootfs-a" |
| mtd22: 00020000 00020000 "rootfs-b-sdtim" |
| mtd23: 013e0000 00020000 "rootfs-b-mount" |
| mtd24: 01400000 00020000 "rootfs-b" |
| mtd25: 00020000 00020000 "oem_data-a-sdtim" |
| mtd26: 006e0000 00020000 "oem_data-a-mount" |
| mtd27: 00700000 00020000 "oem_data-a" |
| mtd28: 00020000 00020000 "oem_data-b-sdtim" |
| mtd29: 006e0000 00020000 "oem_data-b-mount" |
| mtd30: 00700000 00020000 "oem_data-b" |
| mtd31: 01400000 00020000 "rootfs_data" |
| mtd32: 05640000 00020000 "user_data" |
| mtd33: 00d20000 00020000 "MRVL_BBM" |
| */ |
| while (fgets(buf, MAX_LINE_SIZE, fp) != NULL) { |
| char name[200] = {0}; |
| char size[200] = {0}; |
| char erasesize[200] = {0}; |
| char tag[64] = {0}; |
| int cnt = 0; |
| int index = 0; |
| char * p = buf; |
| #ifdef CONFIG_PARTITION_EMMC |
| /* skip prev ' ' */ |
| while ((index < (MAX_LINE_SIZE-1)) && (buf[index] == ' ')) |
| index++; |
| p = &buf[index]; |
| #endif |
| while ((index < (MAX_LINE_SIZE-1)) && (buf[index] != '\0')) { |
| if (buf[index] == ' ') { |
| buf[index] = '\0'; |
| if (cnt == 0) { |
| snprintf(name, sizeof(name), "%s", p); |
| } else if (cnt == 1) { |
| snprintf(size, sizeof(size), "%s", p); |
| } else if (cnt == 2) { |
| snprintf(erasesize, sizeof(erasesize), "%s", p); |
| snprintf(tag, 64, "%s", &buf[index + 1]); |
| break; |
| } |
| cnt++; |
| p = &buf[index + 1]; |
| } |
| index++; |
| } |
| #ifdef CONFIG_AB_SYSTEM |
| if (strncmp(name, "dev", 3) == 0) |
| continue; |
| /* retrive the mtd partition info */ |
| struct image_mtd_info *pCurrentMtdInfo = &server_cfg.image_mtd_info[server_cfg.mtd_cnt]; |
| int j = strlen(name); |
| if (name[j - 1] == ':') |
| name[j - 1] = '\0'; |
| sprintf(pCurrentMtdInfo->dev, "%s", name); |
| sprintf(pCurrentMtdInfo->name, "%s", tag); |
| |
| pCurrentMtdInfo->flag = SYSTEM_SINGLE; |
| j = strlen(tag); |
| /* the last tow chars for tag are "\n */ |
| if (tag[j - 4] == '-') { |
| if (tag[j - 3] == 'a') |
| pCurrentMtdInfo->flag = SYSTEM_A; |
| else if (tag[j - 3] == 'b') |
| pCurrentMtdInfo->flag = SYSTEM_B; |
| } |
| |
| /* remove the last \n */ |
| pCurrentMtdInfo->name[strlen(pCurrentMtdInfo->name) - 1] = 0; |
| |
| sscanf(size, "%x", &pCurrentMtdInfo->size); |
| sscanf(erasesize, "%x", &pCurrentMtdInfo->erasesize); |
| |
| #ifdef CONFIG_PARTITION_EMMC |
| /* dev: size start name */ |
| /* the "erasesize" field represent "start" block in emmc */ |
| pCurrentMtdInfo->flash_start_offset = pCurrentMtdInfo->erasesize * server_cfg.emmc_block_size; |
| pCurrentMtdInfo->size *= server_cfg.emmc_block_size; |
| #else |
| pCurrentMtdInfo->flash_start_offset = get_mtd_offset(server_cfg.mtd_cnt); |
| #endif |
| OTA_DEBUG(" Dev: %s, FlashOffset: 0x%x, Size: 0x%x, EraseSize: 0x%x, Name: %s\n", |
| pCurrentMtdInfo->dev, pCurrentMtdInfo->flash_start_offset, pCurrentMtdInfo->size, |
| pCurrentMtdInfo->erasesize, pCurrentMtdInfo->name); |
| if (strstr(pCurrentMtdInfo->name, "asr_flag")) { |
| int bln=0; |
| #ifdef CONFIG_PARTITION_EMMC |
| sscanf(name, "mmcblk1p%d", &bln); |
| snprintf(server_cfg.mtd_asrflag, 64, "/dev/mmcblk1p%d", bln); |
| #else |
| sscanf(name, "mtd%d", &bln); |
| snprintf(server_cfg.mtd_asrflag, 64, "/dev/mtdblock%d", bln); |
| #endif |
| } |
| #ifdef CONFIG_AB_SYSTEM_DFOTA |
| else if (strstr(pCurrentMtdInfo->name, "OTA")) { |
| sscanf(size, "%x", &server_cfg.fbf_length); |
| #ifndef CONFIG_PARTITION_EMMC |
| sscanf(erasesize, "%x", &server_cfg.block_size); |
| #endif |
| snprintf(server_cfg.mtd_fbf, 300, "/dev/%s", name); |
| server_cfg.fbf_addr = pCurrentMtdInfo->flash_start_offset; |
| OTA_DEBUG("Get MTD info: 0x%x\n", server_cfg.fbf_addr); |
| OTA_DEBUG(" name: %s\n", server_cfg.mtd_fbf); |
| OTA_DEBUG(" size: %08x\n", server_cfg.fbf_length); |
| OTA_DEBUG(" erasesize: %08x\n", server_cfg.block_size); |
| OTA_DEBUG(" tag: %s\n", tag); |
| } |
| #endif |
| server_cfg.mtd_cnt++; |
| #else |
| if (strncmp(tag, "\"asr_flag\"", 10) == 0) { |
| int j = strlen(name); |
| unsigned int asr_size; |
| unsigned int asr_erasesize; |
| sscanf(size, "%x", &asr_size); |
| sscanf(erasesize, "%x", &asr_erasesize); |
| if (name[j - 1] == ':') { |
| name[j - 1] = '\0'; |
| } |
| int bln=0; |
| sscanf(name, "mtd%d", &bln); |
| //sprintf(asr_flag_path, "/dev/mtdblock%d", bln); |
| |
| snprintf(server_cfg.mtd_asrflag, 64, "/dev/mtdblock%d", bln); |
| OTA_DEBUG("Get MTD info:\n"); |
| OTA_DEBUG(" name: %s\n", name); |
| OTA_DEBUG(" mtd_asrflag: %s\n", server_cfg.mtd_asrflag); |
| OTA_DEBUG(" size: %08x\n", asr_size); |
| OTA_DEBUG(" erasesize: %08x\n", asr_erasesize); |
| OTA_DEBUG(" tag: %s\n", tag); |
| }else if (strncmp(tag, "\"OTA\"", 5) == 0) { |
| int j = strlen(name); |
| sscanf(size, "%x", &server_cfg.fbf_length); |
| sscanf(erasesize, "%x", &server_cfg.block_size); |
| if (name[j - 1] == ':') { |
| name[j - 1] = '\0'; |
| } |
| |
| int bln=0; |
| sscanf(name, "mtd%d", &bln); |
| server_cfg.fbf_addr = get_mtd_offset(bln); |
| snprintf(server_cfg.mtd_fbf, 300, "/dev/%s", name); |
| OTA_DEBUG("Get MTD info:\n"); |
| OTA_DEBUG(" name: %s\n", server_cfg.mtd_fbf); |
| OTA_DEBUG(" size: %08x\n", server_cfg.fbf_length); |
| OTA_DEBUG(" erasesize: %08x\n", server_cfg.block_size); |
| OTA_DEBUG(" tag: %s\n", tag); |
| OTA_DEBUG(" fbf_addr: 0x%08x\n", server_cfg.fbf_addr); |
| } |
| #endif |
| memset(buf, 0, MAX_LINE_SIZE); |
| } |
| fclose(fp); |
| #ifdef CONFIG_AB_SYSTEM |
| gInActiveSystem = get_inactive_system(); |
| if (gInActiveSystem != SYSTEM_B && gInActiveSystem != SYSTEM_A) { |
| OTA_ERR("FATAL ERROR, no legal inactive system flag exist..."); |
| return -1; |
| } |
| OTA_DEBUG("Inactive System is %c...\n", gInActiveSystem); |
| system_sync(); |
| #endif |
| return 0; |
| } |
| |
| static int sync_mversion(void) |
| { |
| int ret = 0, i; |
| int fd_asrflag, fd_mversion; |
| int len_asrflag, len_mversion, len; |
| char mversion[128]; |
| struct tr069_firmware_flag AsrFlag; |
| char *p_mversion; |
| p_mversion = AsrFlag.mversion; |
| |
| #ifdef CONFIG_AB_SYSTEM |
| if (gInActiveSystem == SYSTEM_A) |
| p_mversion = AsrFlag.MVersion_B; |
| #endif |
| |
| memset(mversion, 0, 128); |
| |
| fd_asrflag = open(server_cfg.mtd_asrflag, O_RDWR); |
| if (fd_asrflag < 0) { |
| OTA_ERR("Fatal error: can't open asr flag %s\n", server_cfg.mtd_asrflag); |
| return -1; |
| } |
| |
| len_asrflag = read(fd_asrflag, &AsrFlag, sizeof(AsrFlag)); |
| if (len_asrflag != sizeof(AsrFlag)) { |
| OTA_ERR("Fatal error: read %d bytes(expect %d)\n", len_asrflag, sizeof(AsrFlag)); |
| close(fd_asrflag); |
| return -1; |
| } |
| |
| fd_mversion = open("/etc/mversion", O_RDWR); |
| if (fd_mversion < 0) { |
| OTA_ERR("Fatal error: can't open /etc/mversion\n"); |
| close(fd_asrflag); |
| return -1; |
| } |
| len_mversion = read(fd_mversion, mversion, 128); |
| if(len_mversion <= 0) |
| { |
| OTA_ERR("Fatal error: read mversion\n"); |
| ret = -1; |
| goto sync_done; |
| } |
| |
| for (i = len_mversion - 1; i >= 0; i--) |
| { |
| if(mversion[i] == '\n' || mversion[i] == '\r'){ |
| len_mversion -- ; |
| mversion[i] = 0; |
| } |
| else |
| break; |
| } |
| |
| if(p_mversion[0] == 0xFF || p_mversion[0] == 0x0) |
| { |
| OTA_ERR("There is no mversion in asr flag\n"); |
| goto sync_done; |
| } |
| |
| if(memcmp(mversion, p_mversion, len_mversion) != 0) |
| { |
| memset(mversion, 0, 128); |
| strncpy(mversion, p_mversion, 128); |
| mversion[127]=0; |
| lseek(fd_mversion, 0, SEEK_SET); |
| len = write(fd_mversion, mversion, 128); |
| if (len != 128) { |
| OTA_ERR("Fail to write mversion: write %d bytes(expected %d)\n", len, 128); |
| ret = -1; |
| } |
| write(fd_mversion, "\n", 1); |
| goto sync_done; |
| } |
| |
| sync_done: |
| close(fd_asrflag); |
| close(fd_mversion); |
| return ret; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| int ret; |
| // char * uci_path = NULL; |
| |
| mbtk_log_init("radio", "MBTK_OTAD"); |
| //set_service_log_tag("OTAD"); |
| prctl(PR_SET_NAME, "otad"); |
| |
| #if 0 |
| if (argc > 1) { /* UCI file exist */ |
| #ifdef CONFIG_AB_SYSTEM |
| if (strncmp(argv[1], "-f", 2) == 0) { |
| switch (argc) { |
| case 2: |
| OTA_ERR("miss fota path.\n"); |
| return -1; |
| case 4: |
| default: |
| /* go through */ |
| uci_path = argv[3]; |
| OTA_DEBUG("OTA service start(%s)\n", uci_path); |
| case 3: |
| ret = get_fota_version(argv[2], server_cfg.fotav, 128); |
| if (ret > 0) { |
| OTA_ERR("get_fota_version failed, ret: %d\n", ret); |
| return -1; |
| } |
| OTA_DEBUG("got fotav: %s\n", server_cfg.fotav); |
| if (upgrade_precheck(server_cfg.fotav) < 0) |
| return -1; |
| break; |
| } |
| } else |
| #endif |
| { |
| uci_path = argv[1]; |
| OTA_DEBUG("OTA service start(%s)\n", uci_path); |
| } |
| } else { /* No UCI file - use default values */ |
| OTA_DEBUG("OTA service start\n"); |
| } |
| #endif |
| |
| uloop_init(); |
| ctx = ubus_connect(UBUS_UNIX_SOCKET); |
| if (ctx == NULL) { |
| OTA_ERR("Connect to UBUSD failed!\n"); |
| ret = -1; |
| goto done; |
| } |
| ubus_add_uloop(ctx); |
| ret = ubus_add_object(ctx, &ota_object); |
| |
| memset(&server_cfg, 0, sizeof(server_cfg)); |
| // ota |
| init_cfg(NULL); |
| #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| if (server_cfg.fbf_length == 0 || server_cfg.block_size == 0) { |
| OTA_ERR("Config file incorrect!\n"); |
| return -1; |
| } |
| #endif |
| if (server_cfg.progress_notify == 0) { |
| server_cfg.progress_notify = 10; |
| } |
| if (server_cfg.interval == 0) { |
| server_cfg.interval = 5; |
| } |
| if (server_cfg.first_interval == 0) { |
| server_cfg.first_interval = 1; |
| } |
| if (server_cfg.fbf_addr == 0) { |
| server_cfg.fbf_addr = 0x2a60000; |
| } |
| |
| if (strlen(server_cfg.server_url) != 0) { |
| int fd = open("/etc/mversion", O_RDONLY); |
| if (fd < 0) { |
| OTA_ERR("Read version failed!\n"); |
| return -1; |
| } |
| read(fd, version_check_context.version, OTA_MAX_STRING_LEN); |
| close(fd); |
| uloop_timeout_set(&version_check_timer, 1000 * server_cfg.first_interval); |
| } |
| |
| if(sync_mversion() != 0) |
| OTA_ERR("Sync mversion error\n"); |
| |
| uloop_run(); |
| done: |
| |
| return ret; |
| } |
| |