b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 1 | #include <sys/socket.h> |
| 2 | #include <sys/un.h> |
| 3 | #include <sys/stat.h> |
| 4 | #include <sys/uio.h> |
| 5 | #include <sys/types.h> |
| 6 | #include <sys/stat.h> |
| 7 | #include <signal.h> |
| 8 | #include <stdio.h> |
| 9 | #include <unistd.h> |
| 10 | #include <fcntl.h> |
| 11 | #include <sys/prctl.h> |
| 12 | |
| 13 | #include <libubox/blob.h> |
| 14 | #include <libubox/uloop.h> |
| 15 | #include <libubox/usock.h> |
| 16 | #include <libubox/list.h> |
| 17 | #include <libubus.h> |
| 18 | #if 0 |
| 19 | #include <curl/curl.h> |
| 20 | #include <curl/easy.h> |
| 21 | #endif |
| 22 | #include <uci.h> |
| 23 | |
| 24 | #include <sys/ioctl.h> |
| 25 | #include <mtd/mtd-user.h> |
| 26 | |
| 27 | #include "libhttpclient/libhttpclient.h" |
| 28 | #include "otad.h" |
| 29 | |
| 30 | #ifdef CONFIG_AB_SYSTEM |
| 31 | #define MEMLOCKPRIV _IO('M', 25) |
| 32 | #define MEMUNLOCKPRIV _IO('M', 26) |
| 33 | |
| 34 | static int complete_read(int fd, char *buf, int size); |
| 35 | static int complete_write(int fd, char *buf, int size); |
| 36 | #include "tim.h" |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 37 | |
| 38 | #if !defined(CONFIG_AB_SYSTEM_DFOTA) |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 39 | #include "tim.c" |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 40 | #endif |
| 41 | |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 42 | #include "getfotav.c" |
| 43 | |
| 44 | #if 0 |
| 45 | /* support dfota upgrade */ |
| 46 | #define CONFIG_AB_SYSTEM_DFOTA |
| 47 | #endif |
| 48 | |
| 49 | /* the main bootloader */ |
| 50 | const char *tmp_obm_main_file = "/tmp/obm_main.bin"; |
| 51 | const char *tmp_timh_main_file = "/tmp/timh_main.bin"; |
| 52 | /* the backup bootloader */ |
| 53 | const char *tmp_obm_bk_file = "/tmp/obm_bk.bin"; |
| 54 | const char *tmp_timh_bk_file = "/tmp/timh_bk.bin"; |
| 55 | /* the target timh for the specific ddr */ |
| 56 | const char *tmp_timh_main_target_file = "/tmp/timh_main_target.bin"; |
| 57 | const char *tmp_timh_bk_target_file = "/tmp/timh_bk_target.bin"; |
| 58 | |
| 59 | static unsigned int obm_real_size = 0; |
| 60 | #endif |
| 61 | |
| 62 | #define OTA_MAX_STRING_LEN 128 |
| 63 | #define OEMDDENTIFIER 0x4F454D44 /* "OEMD" */ |
| 64 | |
| 65 | enum { |
| 66 | UPDATE_STATE_IDLE, |
| 67 | UPDATE_STATE_UPDATING, |
| 68 | UPDATE_STATE_UPDATED, |
| 69 | UPDATE_STATE_FAILED, |
| 70 | }; |
| 71 | static int update_state = UPDATE_STATE_IDLE; |
| 72 | static int update_oemd; |
| 73 | |
| 74 | struct version_info { |
| 75 | char version[OTA_MAX_STRING_LEN]; |
| 76 | char url[OTA_MAX_STRING_LEN]; |
| 77 | char * release_note; |
| 78 | }; |
| 79 | |
| 80 | #ifdef CONFIG_AB_SYSTEM |
| 81 | #define MIN_RLS_VERSION 846 |
| 82 | |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 83 | #if !defined(CONFIG_AB_SYSTEM_DFOTA) |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 84 | static int upgrade_precheck(char *fotav) |
| 85 | { |
| 86 | char *p; |
| 87 | int ver; |
| 88 | |
| 89 | OTA_DEBUG("%s: %s\n", __func__, fotav); |
| 90 | p = strstr(fotav, "_rls"); |
| 91 | if (!p) { |
| 92 | OTA_ERR("not found rls version.\n", __func__); |
| 93 | return -1; |
| 94 | } |
| 95 | |
| 96 | p += 4; |
| 97 | ver = atoi(p); |
| 98 | if (ver < MIN_RLS_VERSION) { |
| 99 | OTA_DEBUG("%s: don't support upgrade to rls%d, min: rls%d\n", __func__, ver, MIN_RLS_VERSION); |
| 100 | return -1; |
| 101 | } |
| 102 | |
| 103 | /* support upgrade */ |
| 104 | return 0; |
| 105 | } |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 106 | #endif |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 107 | |
| 108 | static int complete_read(int fd, char *buf, int size); |
| 109 | static int complete_write(int fd, char *buf, int size); |
| 110 | |
| 111 | // Change by liubin |
| 112 | #define MAX_MTD_PARTITION_CNT 35 |
| 113 | #define FBF_FILE_SECTOR_SIZE (4*1024) |
| 114 | struct image_mtd_info { |
| 115 | char name[32]; |
| 116 | char dev[16]; |
| 117 | unsigned int flash_start_offset; |
| 118 | unsigned int size; |
| 119 | unsigned int erasesize; |
| 120 | unsigned int flag; |
| 121 | }; |
| 122 | |
| 123 | enum { |
| 124 | SYSTEM_SINGLE = 0, |
| 125 | SYSTEM_A = 'a', |
| 126 | SYSTEM_B = 'b' |
| 127 | }; |
| 128 | |
| 129 | static int gInActiveSystem = SYSTEM_SINGLE; |
| 130 | static int gSystemHasRollbackFlag = 0; |
| 131 | #endif |
| 132 | |
| 133 | struct ota_server { |
| 134 | char server_url[OTA_MAX_STRING_LEN]; |
| 135 | int download_immediately; |
| 136 | int progress_notify; |
| 137 | int interval; |
| 138 | int first_interval; |
| 139 | unsigned int fbf_length; |
| 140 | unsigned int block_size; |
| 141 | unsigned int pagesize; |
| 142 | unsigned int emmc_block_size; /* 512B */ |
| 143 | unsigned int fbf_addr; |
| 144 | char mtd_asrflag[64]; |
| 145 | #ifdef CONFIG_AB_SYSTEM |
| 146 | int mtd_cnt; |
| 147 | struct image_mtd_info image_mtd_info[MAX_MTD_PARTITION_CNT]; |
| 148 | unsigned int cpuid; |
| 149 | unsigned int ddrid; |
| 150 | unsigned int max_timh_size; |
| 151 | unsigned int fotav_offset_in_fbf; |
| 152 | char fotav[128]; |
| 153 | #endif |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 154 | char mtd_fbf[300]; |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 155 | struct version_info ver; |
| 156 | }; |
| 157 | struct ota_server server_cfg; |
| 158 | |
| 159 | static struct ubus_context *ctx; |
| 160 | static struct blob_buf b; |
| 161 | static struct ubus_object ota_object; |
| 162 | |
| 163 | enum { |
| 164 | DOWNLOAD_TYPE, |
| 165 | DOWNLOAD_FILE_SIZE, |
| 166 | DOWNLOAD_URL, |
| 167 | DOWNLOAD_NAME, |
| 168 | DOWNLOAD_PSW, |
| 169 | DOWNLOAD_SYNC, |
| 170 | DOWNLOAD_SEGMENT_SIZE, |
| 171 | __DOWNLOAD_MAX |
| 172 | }; |
| 173 | |
| 174 | static const struct blobmsg_policy download_policy[] = { |
| 175 | [DOWNLOAD_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, |
| 176 | [DOWNLOAD_FILE_SIZE] = { .name = "size", .type = BLOBMSG_TYPE_INT32 }, |
| 177 | [DOWNLOAD_URL] = { .name = "url", .type = BLOBMSG_TYPE_STRING }, |
| 178 | [DOWNLOAD_NAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING }, |
| 179 | [DOWNLOAD_PSW] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, |
| 180 | [DOWNLOAD_SYNC] = { .name = "sync", .type = BLOBMSG_TYPE_INT32 }, |
| 181 | [DOWNLOAD_SEGMENT_SIZE] = { .name = "segment_size", .type = BLOBMSG_TYPE_INT32 }, |
| 182 | }; |
| 183 | |
| 184 | #if 0 |
| 185 | static size_t curl_cb(void *buffer, size_t size, size_t nmemb, void *stream) |
| 186 | { |
| 187 | //OTA_ERR(" response: %s(%d:%d)\n", (char *)buffer, size, nmemb); |
| 188 | OTA_ERR(" response:%d:%d\n", size, nmemb); |
| 189 | return size * nmemb; |
| 190 | } |
| 191 | #endif |
| 192 | // FBF file related definition |
| 193 | static int _ota_download_progress = 0; |
| 194 | static int ota_download_progress = 0; |
| 195 | char * fbf_version_string = NULL; |
| 196 | // Add by mbtk |
| 197 | int Download_flag = 0; |
| 198 | #define TR069_FBF_HEADER_SIZE 13 |
| 199 | #define DLCMD_IMAGE_TYPE_FIELD_BIT 4 |
| 200 | #define DLCMD_IMAGE_TYPE_FIELD_SIZE_BITS 4 |
| 201 | #define MAX_NUMBER_OF_FLASH_DEVICES_IN_MASTER_HEADER 4 |
| 202 | #define MAX_NUMBER_OF_FLASH_DEVICES_IN_DEVICE_HEADER 150 |
| 203 | #define BLOCK_DEVICE_SECTOR_SIZE (8*1024) |
| 204 | #define MAX_RESEVERD_LEN 4 |
| 205 | #define MAX_NUM_SKIP_BLOCKS 32 |
| 206 | #define UNIQUE_SIZE 24 |
| 207 | #define NUM_OF_SUPPORTED_FLASH_DEVS 4 |
| 208 | #define RSA_IMAGE_ID 0x52534149 |
| 209 | #define MINI_SIZE (128) |
| 210 | #define CHECKSUM_CACHE_SIZE (128) |
| 211 | #define FILE_VERIFY_RAM_SIZE (server_cfg.block_size) |
| 212 | |
| 213 | struct version_check_context { |
| 214 | char * url; |
| 215 | int size; |
| 216 | int used; |
| 217 | char version[OTA_MAX_STRING_LEN]; |
| 218 | }; |
| 219 | |
| 220 | typedef struct { |
| 221 | unsigned int Image_ID; |
| 222 | unsigned int Image_In_TIM; |
| 223 | unsigned int Flash_partition; |
| 224 | unsigned int Flash_erase_size; |
| 225 | unsigned int commands; |
| 226 | unsigned int First_Sector; |
| 227 | unsigned int length; |
| 228 | unsigned int Flash_Start_Address; |
| 229 | unsigned int reserve[MAX_RESEVERD_LEN]; |
| 230 | unsigned int ChecksumFormatVersion2; |
| 231 | } __attribute__((packed)) ImageStruct_11; |
| 232 | |
| 233 | typedef ImageStruct_11 * PImageStruct_11; |
| 234 | |
| 235 | typedef struct { |
| 236 | unsigned int Total_Number_Of_SkipBlocks; |
| 237 | unsigned int Size_of_Block[MAX_NUM_SKIP_BLOCKS]; |
| 238 | } SkipBlocksInfoStruct; |
| 239 | |
| 240 | typedef struct { |
| 241 | unsigned int EraseAll; |
| 242 | unsigned int ResetBBT; |
| 243 | unsigned int NandID; |
| 244 | unsigned int Reserved[MAX_RESEVERD_LEN - 1]; |
| 245 | SkipBlocksInfoStruct SkipBlocksInfoStruct; |
| 246 | } FlashOptStruct; |
| 247 | |
| 248 | typedef struct { |
| 249 | unsigned int DeviceFlags; |
| 250 | unsigned int DeviceParametes[16]; |
| 251 | FlashOptStruct FlashOpt; |
| 252 | unsigned int ProductionMode; // production mode |
| 253 | unsigned char OptValue; // choice: 0 - Not reset after download, 1 - Reset after download |
| 254 | unsigned char ChipID; |
| 255 | unsigned char BBCS_EN; |
| 256 | unsigned char CRCS_EN; |
| 257 | unsigned int Reserved[MAX_RESEVERD_LEN-2]; |
| 258 | unsigned int nOfImages; |
| 259 | ImageStruct_11 imageStruct_11[MAX_NUMBER_OF_FLASH_DEVICES_IN_MASTER_HEADER]; |
| 260 | } __attribute__((packed)) DeviceHeader_11; |
| 261 | |
| 262 | typedef DeviceHeader_11 * PDeviceHeader_11; |
| 263 | |
| 264 | typedef struct { |
| 265 | char Unique[UNIQUE_SIZE]; |
| 266 | unsigned short int Flash_Device_Spare_Area_Size[NUM_OF_SUPPORTED_FLASH_DEVS]; |
| 267 | unsigned short int Format_Version; |
| 268 | unsigned short int Size_of_Block; |
| 269 | unsigned int Bytes_To_Program; |
| 270 | unsigned int Bytes_To_Verify; |
| 271 | unsigned int Number_of_Bytes_To_Erase; |
| 272 | unsigned int Main_Commands; |
| 273 | unsigned int nOfDevices; |
| 274 | unsigned int DLerVeriosn; |
| 275 | unsigned int deviceHeaderOffset[MAX_NUMBER_OF_FLASH_DEVICES_IN_MASTER_HEADER]; |
| 276 | } __attribute__((packed)) MasterBlockHeader; |
| 277 | |
| 278 | typedef MasterBlockHeader * PMasterBlockHeader; |
| 279 | |
| 280 | struct imginfo_table { |
| 281 | unsigned int Img_Len; |
| 282 | unsigned int Img_Commands; |
| 283 | unsigned int Img_Start_Address; |
| 284 | unsigned int Img_Checksum; |
| 285 | unsigned int Flash_Start_Address; |
| 286 | unsigned int Flash_Erase_Size; |
| 287 | unsigned int Img_ID; |
| 288 | unsigned int Image_In_TIM; |
| 289 | #ifdef CONFIG_AB_SYSTEM |
| 290 | int fd; |
| 291 | char name[32]; |
| 292 | char dev[16]; |
| 293 | unsigned int Img_Remain_Len; |
| 294 | unsigned int cs; |
| 295 | unsigned int Block_Start_Address; |
| 296 | unsigned int partition_size; |
| 297 | int erased; |
| 298 | #endif |
| 299 | struct imginfo_table * next; |
| 300 | }; |
| 301 | |
| 302 | typedef struct imginfo_table ImginfoTable; |
| 303 | |
| 304 | enum { |
| 305 | HEADER, |
| 306 | CONTENT, |
| 307 | }; |
| 308 | |
| 309 | struct image_state { |
| 310 | struct imginfo_table * image_info; |
| 311 | struct image_state * next_image; |
| 312 | int result; |
| 313 | }; |
| 314 | |
| 315 | struct image_process_context { |
| 316 | ImginfoTable * image_info_table; |
| 317 | ImginfoTable * current_process; |
| 318 | unsigned int processed_cnt; |
| 319 | int state; |
| 320 | char * flash_cache; |
| 321 | int flash_cache_index; |
| 322 | int (*flash_cb)(struct image_process_context *, char *, int); |
| 323 | unsigned char * checksum_cache; |
| 324 | int checksum_cache_index; |
| 325 | unsigned int image_checksum; |
| 326 | int ota_download_notification_cnt; |
| 327 | struct image_state * image_state_list; |
| 328 | int download_result; |
| 329 | int fd; |
| 330 | int upgrade_method; |
| 331 | int dual_tim; |
| 332 | int same_tim; |
| 333 | int upgrade_bootloader; |
| 334 | }; |
| 335 | |
| 336 | typedef struct{ |
| 337 | unsigned int CurImageID; |
| 338 | unsigned int ImageType; |
| 339 | unsigned int ImageState; /* 1: new image is backed up, 0: not backed up */ |
| 340 | unsigned int ImageBkAddr; |
| 341 | unsigned int ImageBkLen; |
| 342 | unsigned int SegState; |
| 343 | unsigned int SegIndex; |
| 344 | unsigned int SegDestBkAddr; |
| 345 | unsigned int SegDestBkLen; |
| 346 | unsigned int PreTailAddr; |
| 347 | unsigned int PreTailLen; |
| 348 | unsigned int NextHeadAddr; |
| 349 | unsigned int NextHeadLen; |
| 350 | unsigned int NextSegWriteOffset; |
| 351 | unsigned int NextSegReadOffset; |
| 352 | unsigned int NextSegEraseOffset; |
| 353 | }SDfotaState, *pSDfotaState; |
| 354 | |
| 355 | struct DeviceHeader_11_tr069 { |
| 356 | unsigned int DeviceFlags; |
| 357 | unsigned int DeviceParameters[16]; /* Device Parameters, reserve 16 U32 here, will be defined depending on different devices */ |
| 358 | FlashOptStruct FlashOpt; |
| 359 | unsigned int ProductionMode; // production mode |
| 360 | unsigned char OptValue; // choice: 0 - Not reset after download, 1 - Reset after download |
| 361 | unsigned char ChipID; |
| 362 | unsigned char BBCS_EN; |
| 363 | unsigned char CRCS_EN; |
| 364 | unsigned int Reserved[MAX_RESEVERD_LEN-2]; |
| 365 | unsigned int nOfImages; /* number of images */ |
| 366 | ImageStruct_11 imageStruct_11[0]; /* array of image structs */ |
| 367 | } __attribute__((packed)); // Same as struct 'DeviceHeader_11' but the ImageStruct cnt is zero |
| 368 | |
| 369 | struct DDRT_STATE{ |
| 370 | unsigned int test_proc :1; //1: start, 0: done |
| 371 | unsigned int last_res :1; //1: fail, 0: pass |
| 372 | unsigned int total_times :15; |
| 373 | unsigned int fail_times :15; |
| 374 | }; |
| 375 | |
| 376 | typedef union{ |
| 377 | unsigned int value; |
| 378 | struct DDRT_STATE bits; |
| 379 | }DDRTestState, *pDDRTestState; |
| 380 | |
| 381 | struct tr069_firmware_flag { |
| 382 | unsigned int header; |
| 383 | unsigned int upgrade_flag; //1,upgrade; 2, backup boot |
| 384 | unsigned int fbf_flash_address; |
| 385 | unsigned int fbf_file_size; |
| 386 | unsigned int erase_psm; |
| 387 | unsigned int erase_psm_address; |
| 388 | unsigned int erase_psm_size; |
| 389 | unsigned int erase_fs; |
| 390 | unsigned int fs_erase_address; |
| 391 | unsigned int fs_erase_size; |
| 392 | unsigned int upgrade_method; //1,TR069; 2, SD; 3,WebUI |
| 393 | unsigned int UnlockKeyFlag; |
| 394 | unsigned int production_mode_flag; //for production mode |
| 395 | unsigned int eehP[2]; |
| 396 | unsigned int cpsr[2]; |
| 397 | unsigned int hawk[2]; |
| 398 | unsigned int imsd[2]; |
| 399 | unsigned int pipe[2]; |
| 400 | unsigned int fast[2]; |
| 401 | unsigned int apmf[2]; |
| 402 | unsigned int pid[2]; |
| 403 | unsigned int vid[2]; |
| 404 | unsigned int obmdl[2]; |
| 405 | unsigned int dlflag[2]; |
| 406 | unsigned int ramdump[2]; |
| 407 | unsigned int dfota_n_of_images; |
| 408 | unsigned int dfota_need_copy_only; |
| 409 | unsigned int dfota_conpy_len; |
| 410 | #ifdef CONFIG_AB_SYSTEM |
| 411 | unsigned int active_slot; /* prev active slot */ |
| 412 | unsigned int temp_active_slot; /* current active slot */ |
| 413 | unsigned int reboot_cnt; |
| 414 | unsigned int synced; |
| 415 | unsigned int rsvd[16]; |
| 416 | #endif |
| 417 | unsigned int nocp[2]; |
| 418 | unsigned int TrustBootStatus; |
| 419 | char mversion[128]; |
| 420 | SDfotaState SDfotaInfo; |
| 421 | unsigned int ref_count; |
| 422 | unsigned int flag_len; |
| 423 | unsigned int version; |
| 424 | unsigned int DDR_ID; |
| 425 | unsigned int Flash_ID; |
| 426 | unsigned int cplog[2]; |
| 427 | DDRTestState ddrt_state; |
| 428 | unsigned int svc_state; |
| 429 | char MVersion_B[128]; /* only use for AB system */ |
| 430 | unsigned int Reserved[68]; /* reserved for asr */ |
| 431 | unsigned int ReservedForCustomer[35]; /* reserved for customer */ |
| 432 | /* reserve to make the ASR_Flag length as 1KB */ |
| 433 | |
| 434 | unsigned int crc; |
| 435 | /* NOTICE !!! |
| 436 | * If you change this structure, you must also sync the change to OBM/Uboot/OTA/Telephony |
| 437 | * OBM: obm/Common/Misc/asr_flag.h |
| 438 | * Uboot: uboot/board/Marvell/common/asr_flag.h |
| 439 | * OTA: services/ota/otad.c |
| 440 | * Telephony: lte_telephony/apps/cp_load/cploader.h |
| 441 | * If add a new member to this structure, must decrease the size of Reserved[] |
| 442 | */ |
| 443 | }; |
| 444 | |
| 445 | #define ASRFLAG_HEADER 0x464F5441 |
| 446 | |
| 447 | /* ASR Flag version history |
| 448 | * 1.0.0.1: support dual asr flag |
| 449 | * 1.0.0.2: support asr flag crc |
| 450 | */ |
| 451 | #define ASRFLAG_VERSION_LEGACY 0xFFFFFFFF |
| 452 | #define ASRFLAG_VERSION_DAF 0x31303031 |
| 453 | #define ASRFLAG_VERSION_CRC 0x31303032 |
| 454 | #define ASRFLAG_VERSION ASRFLAG_VERSION_CRC |
| 455 | |
| 456 | struct download_timer_context { |
| 457 | int type; |
| 458 | int size; |
| 459 | int segment_size; |
| 460 | char * url; |
| 461 | char * username; |
| 462 | char * pwd; |
| 463 | int file_size; |
| 464 | int received_size; |
| 465 | }; |
| 466 | |
| 467 | struct download_timer_context download_method_ctx = {0}; |
| 468 | static struct tr069_firmware_flag gAsrFlag; |
| 469 | |
| 470 | static int asrflag_daf_enabled(struct tr069_firmware_flag * p_asrflag) |
| 471 | { |
| 472 | if(p_asrflag->version != ASRFLAG_VERSION_LEGACY && |
| 473 | p_asrflag->version >= ASRFLAG_VERSION_DAF) |
| 474 | return 1; |
| 475 | |
| 476 | return 0; |
| 477 | } |
| 478 | |
| 479 | static int asrflag_crc_enabled(struct tr069_firmware_flag * p_asrflag) |
| 480 | { |
| 481 | if(p_asrflag->version != ASRFLAG_VERSION_LEGACY && |
| 482 | p_asrflag->version >= ASRFLAG_VERSION_CRC) |
| 483 | return 1; |
| 484 | |
| 485 | return 0; |
| 486 | } |
| 487 | |
| 488 | static unsigned int malbrain_crc32(unsigned int crcu32, const unsigned char *ptr, unsigned int buf_len) |
| 489 | { |
| 490 | static const unsigned int s_crc32[16] = { |
| 491 | 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
| 492 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
| 493 | }; |
| 494 | if (!ptr) |
| 495 | return 0; |
| 496 | crcu32 = ~crcu32; |
| 497 | while (buf_len--) |
| 498 | { |
| 499 | unsigned char b = *ptr++; |
| 500 | crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; |
| 501 | crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; |
| 502 | } |
| 503 | return ~crcu32; |
| 504 | } |
| 505 | |
| 506 | static void asrflag_update_crc(struct tr069_firmware_flag * p_asrflag) |
| 507 | { |
| 508 | unsigned int crc_len, crc_val; |
| 509 | crc_len = sizeof(struct tr069_firmware_flag) - 4; /* 4 bytes is CRC itself */ |
| 510 | |
| 511 | crc_val = malbrain_crc32(0, (unsigned char *)p_asrflag, crc_len); |
| 512 | |
| 513 | p_asrflag->crc = crc_val; |
| 514 | |
| 515 | return; |
| 516 | } |
| 517 | |
| 518 | static int asrflag_is_invalid(struct tr069_firmware_flag * p_asrflag) |
| 519 | { |
| 520 | unsigned int crc_len, crc_val; |
| 521 | |
| 522 | if(p_asrflag->header != ASRFLAG_HEADER) |
| 523 | return 1; |
| 524 | |
| 525 | if(!asrflag_crc_enabled(p_asrflag)) |
| 526 | return 0; |
| 527 | |
| 528 | crc_len = sizeof(struct tr069_firmware_flag) - 4; /* 4 bytes is CRC itself */ |
| 529 | crc_val = malbrain_crc32(0, (unsigned char *)p_asrflag, crc_len); |
| 530 | |
| 531 | if(p_asrflag->crc != crc_val) { |
| 532 | OTA_ERR("asr flag mismatch: 0x%x 0x%x\n", crc_val, p_asrflag->crc); |
| 533 | return 1; |
| 534 | } |
| 535 | |
| 536 | return 0; |
| 537 | } |
| 538 | |
| 539 | static int get_asr_flag(struct tr069_firmware_flag *p_asrflag) |
| 540 | { |
| 541 | int fd = 0, ret = 0; |
| 542 | unsigned int step = 0, offset = 0, flaglen = 0; |
| 543 | struct tr069_firmware_flag *main_asrflag = NULL; |
| 544 | struct tr069_firmware_flag *backup_asrflag = NULL; |
| 545 | flaglen = sizeof(struct tr069_firmware_flag); |
| 546 | |
| 547 | main_asrflag = malloc(flaglen); |
| 548 | if(main_asrflag == NULL) { |
| 549 | OTA_ERR("Fail to malloc\n"); |
| 550 | return -1; |
| 551 | } |
| 552 | |
| 553 | fd = open(server_cfg.mtd_asrflag, O_RDONLY); |
| 554 | if (fd < 0) { |
| 555 | free(main_asrflag); |
| 556 | OTA_ERR("Fatal error: can't open asr flag %s\n", server_cfg.mtd_asrflag); |
| 557 | return -1; |
| 558 | } |
| 559 | |
| 560 | if (read(fd, main_asrflag, flaglen) < 0) |
| 561 | goto error; |
| 562 | if ( asrflag_is_invalid(main_asrflag) ) { |
| 563 | backup_asrflag = main_asrflag; |
| 564 | main_asrflag = NULL; |
| 565 | |
| 566 | step = (server_cfg.block_size)?server_cfg.block_size:0x1000; |
| 567 | offset = step; |
| 568 | |
| 569 | while (1) { |
| 570 | if(lseek(fd, offset, SEEK_SET) < 0 ) |
| 571 | goto error; |
| 572 | ret = read(fd, backup_asrflag, flaglen); |
| 573 | if(ret < 0) |
| 574 | goto error; |
| 575 | |
| 576 | if(ret == 0 || !asrflag_is_invalid(backup_asrflag) ) |
| 577 | break; |
| 578 | |
| 579 | offset += step; |
| 580 | } |
| 581 | |
| 582 | /* can't find valid backup ASR Flag */ |
| 583 | if ( asrflag_is_invalid(backup_asrflag) ) { |
| 584 | free(backup_asrflag); backup_asrflag = NULL; |
| 585 | } |
| 586 | } else { |
| 587 | if( asrflag_daf_enabled(main_asrflag) ) { |
| 588 | backup_asrflag = malloc(flaglen); |
| 589 | if(backup_asrflag != NULL) |
| 590 | { |
| 591 | if(lseek(fd, main_asrflag->flag_len, SEEK_SET) < 0) |
| 592 | goto error; |
| 593 | |
| 594 | if (read(fd, backup_asrflag, flaglen) < 0) |
| 595 | goto error; |
| 596 | |
| 597 | if( asrflag_is_invalid(backup_asrflag) ) |
| 598 | { |
| 599 | free(backup_asrflag); |
| 600 | backup_asrflag = NULL; |
| 601 | } |
| 602 | } |
| 603 | } else { |
| 604 | /* old way which doesn't support backup */ |
| 605 | memcpy(p_asrflag, main_asrflag, flaglen); |
| 606 | close(fd); |
| 607 | free(main_asrflag); |
| 608 | return 0; |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | if(main_asrflag == NULL && backup_asrflag == NULL) { |
| 613 | goto error; |
| 614 | } else if(main_asrflag == NULL) { |
| 615 | memcpy(p_asrflag, backup_asrflag, flaglen); |
| 616 | } else if (backup_asrflag == NULL) { |
| 617 | memcpy(p_asrflag, main_asrflag, flaglen); |
| 618 | } else { |
| 619 | if(memcmp(main_asrflag, backup_asrflag, flaglen)) |
| 620 | OTA_ERR("Main asr flag mismatch with backup\n"); |
| 621 | if(backup_asrflag->ref_count > main_asrflag->ref_count) |
| 622 | memcpy(p_asrflag, backup_asrflag, flaglen); |
| 623 | else |
| 624 | memcpy(p_asrflag, main_asrflag, flaglen); |
| 625 | } |
| 626 | |
| 627 | close(fd); |
| 628 | if(main_asrflag) free(main_asrflag); |
| 629 | if(backup_asrflag) free(backup_asrflag); |
| 630 | return 0; |
| 631 | |
| 632 | error: |
| 633 | close(fd); |
| 634 | if(main_asrflag) free(main_asrflag); |
| 635 | if(backup_asrflag) free(backup_asrflag); |
| 636 | return -1; |
| 637 | } |
| 638 | |
| 639 | static int write_asr_flag(struct tr069_firmware_flag *p_asrflag) |
| 640 | { |
| 641 | unsigned int flaglen = 0; |
| 642 | int n = 0; |
| 643 | int fd = open(server_cfg.mtd_asrflag, O_RDWR); |
| 644 | if (fd < 0) { |
| 645 | OTA_ERR("Fatal error: can't open asr flag %s\n", server_cfg.mtd_asrflag); |
| 646 | return -1; |
| 647 | } |
| 648 | |
| 649 | flaglen = sizeof(struct tr069_firmware_flag); |
| 650 | if (p_asrflag->ref_count ++ == 0xFFFFFFFF) |
| 651 | p_asrflag->ref_count = 0; |
| 652 | |
| 653 | asrflag_update_crc(p_asrflag); |
| 654 | |
| 655 | n = write(fd, p_asrflag, flaglen); |
| 656 | if (n != flaglen) { |
| 657 | OTA_ERR("Fatal error: write %d bytes(expect %d) to asr flag\n", n, sizeof(gAsrFlag)); |
| 658 | close(fd); |
| 659 | return -1; |
| 660 | } |
| 661 | |
| 662 | if( asrflag_daf_enabled(p_asrflag) ) { |
| 663 | lseek(fd, p_asrflag->flag_len, SEEK_SET); |
| 664 | |
| 665 | n = write(fd, p_asrflag, flaglen); |
| 666 | if (n != flaglen) { |
| 667 | OTA_ERR("Fatal error: write %d bytes(expect %d) to asr flag\n", n, sizeof(gAsrFlag)); |
| 668 | close(fd); |
| 669 | return -1; |
| 670 | } |
| 671 | } |
| 672 | |
| 673 | close(fd); |
| 674 | return 0; |
| 675 | } |
| 676 | |
| 677 | #ifdef CONFIG_AB_SYSTEM |
| 678 | static int get_inactive_system() |
| 679 | { |
| 680 | if (get_asr_flag(&gAsrFlag)) { |
| 681 | OTA_ERR("Fatal error: can't read asr flag %s\n", server_cfg.mtd_asrflag); |
| 682 | return -1; |
| 683 | } |
| 684 | |
| 685 | OTA_DEBUG("Asr Flag: active_slot: %c(0x%x), temp_active_slot: %c(0x%x), reboot_cnt: %d, synced: %d\n", |
| 686 | gAsrFlag.active_slot, gAsrFlag.active_slot, |
| 687 | gAsrFlag.temp_active_slot, gAsrFlag.temp_active_slot, |
| 688 | gAsrFlag.reboot_cnt, gAsrFlag.synced); |
| 689 | |
| 690 | if (gAsrFlag.active_slot != gAsrFlag.temp_active_slot) { |
| 691 | OTA_DEBUG("System %c is valid, now update the active slot...\n", gAsrFlag.temp_active_slot); |
| 692 | gAsrFlag.active_slot = gAsrFlag.temp_active_slot; |
| 693 | gAsrFlag.reboot_cnt = 0; |
| 694 | gAsrFlag.synced = 0; |
| 695 | if (write_asr_flag(&gAsrFlag)) { |
| 696 | OTA_ERR("Fatal error: fail to write asr flag\n"); |
| 697 | return -1; |
| 698 | } |
| 699 | } else { |
| 700 | if (gAsrFlag.synced == 0) { |
| 701 | /* if active_slot == temp_active_slot & synced = 0, the system rollback must happened */ |
| 702 | gSystemHasRollbackFlag = 1; |
| 703 | } |
| 704 | } |
| 705 | if (gAsrFlag.temp_active_slot == SYSTEM_B) |
| 706 | return SYSTEM_A; |
| 707 | return SYSTEM_B; |
| 708 | } |
| 709 | |
| 710 | static int complete_read(int fd, char *buf, int size) |
| 711 | { |
| 712 | int pos = 0; |
| 713 | while (pos != size) { |
| 714 | int n = read(fd, buf + pos, size - pos); |
| 715 | if (n < 0) { |
| 716 | OTA_ERR("Fatal error: read failed: %d...\n", n); |
| 717 | return -1; |
| 718 | } |
| 719 | pos += n; |
| 720 | } |
| 721 | |
| 722 | return pos; |
| 723 | } |
| 724 | |
| 725 | static int complete_write(int fd, char *buf, int size) |
| 726 | { |
| 727 | int pos = 0; |
| 728 | while (pos != size) { |
| 729 | int n = write(fd, buf + pos, size - pos); |
| 730 | if (n < 0) { |
| 731 | OTA_ERR("Fatal error: write failed: %d...\n", n); |
| 732 | return -1; |
| 733 | } |
| 734 | pos += n; |
| 735 | } |
| 736 | |
| 737 | return pos; |
| 738 | } |
| 739 | |
| 740 | static int __system_compare(char *src, char *dst, int size, int erasesize) |
| 741 | { |
| 742 | char sdev[32] = {0}, ddev[32] = {0}; |
| 743 | sprintf(sdev, "/dev/%s", src); |
| 744 | sprintf(ddev, "/dev/%s", dst); |
| 745 | int fdSrc = open(sdev, O_RDWR | O_SYNC); |
| 746 | int fdDst = open(ddev, O_RDWR | O_SYNC); |
| 747 | |
| 748 | int ret = -1; |
| 749 | char *sbuf = NULL, *dbuf = NULL; |
| 750 | if (fdSrc < 0 || fdDst < 0) { |
| 751 | OTA_ERR("Fatal error: can't open dev, src: %s, fdSrc: %d, dst: %s, fdDst: %d\n", |
| 752 | src, fdSrc, dst, fdDst); |
| 753 | goto err; |
| 754 | } |
| 755 | |
| 756 | sbuf = malloc(erasesize); |
| 757 | if (!sbuf) { |
| 758 | OTA_ERR("Fatal error: can't malloc 0x%x for src buf\n", erasesize); |
| 759 | goto err; |
| 760 | } |
| 761 | |
| 762 | dbuf = malloc(erasesize); |
| 763 | if (!dbuf) { |
| 764 | OTA_ERR("Fatal error: can't malloc 0x%x for dst buf\n", erasesize); |
| 765 | goto err; |
| 766 | } |
| 767 | |
| 768 | OTA_DEBUG("Src: %s, Dst: %s, Size: 0x%x...\n", sdev, ddev, size); |
| 769 | while (size) { |
| 770 | int n = erasesize; |
| 771 | if (size < erasesize) |
| 772 | n = size; |
| 773 | memset(sbuf, 0, erasesize); |
| 774 | memset(dbuf, 0, erasesize); |
| 775 | |
| 776 | if (complete_read(fdSrc, sbuf, n) < 0) |
| 777 | goto err; |
| 778 | if (complete_read(fdDst, dbuf, n) < 0) |
| 779 | goto err; |
| 780 | |
| 781 | if (memcmp(sbuf, dbuf, n) != 0) { |
| 782 | OTA_ERR("Src: %s, Dst: %s, are not same, NEED to sync\n", sdev, ddev); |
| 783 | goto err; |
| 784 | } |
| 785 | size -= n; |
| 786 | } |
| 787 | |
| 788 | ret = 0; |
| 789 | OTA_DEBUG("Src: %s, Dst: %s, are same, NO NEED to sync\n", sdev, ddev); |
| 790 | err: |
| 791 | if (fdSrc >= 0) |
| 792 | close(fdSrc); |
| 793 | if (fdDst >= 0) |
| 794 | close(fdDst); |
| 795 | if (sbuf) |
| 796 | free(sbuf); |
| 797 | if (dbuf) |
| 798 | free(dbuf); |
| 799 | return ret; |
| 800 | } |
| 801 | |
| 802 | static int __system_sync(char *src, char *dst, int size, int erasesize) |
| 803 | { |
| 804 | if (__system_compare(src, dst, size, erasesize) == 0) |
| 805 | return 0; |
| 806 | |
| 807 | int ret = -1; |
| 808 | char *buf = NULL; |
| 809 | char sdev[32] = {0}, ddev[32] = {0}; |
| 810 | sprintf(sdev, "/dev/%s", src); |
| 811 | sprintf(ddev, "/dev/%s", dst); |
| 812 | int fdSrc = open(sdev, O_RDWR | O_SYNC); |
| 813 | int fdDst = open(ddev, O_RDWR | O_SYNC); |
| 814 | #ifndef CONFIG_PARTITION_EMMC |
| 815 | struct erase_info_user mtdEraseInfo; |
| 816 | struct mtd_info_user mtdInfo; |
| 817 | if (ioctl(fdDst, MEMGETINFO, &mtdInfo)) { |
| 818 | OTA_ERR("Could not get MTD device info from %s\n", ddev); |
| 819 | goto err; |
| 820 | } |
| 821 | mtdEraseInfo.start = 0; |
| 822 | mtdEraseInfo.length = mtdInfo.erasesize; |
| 823 | #endif |
| 824 | if (fdSrc < 0 || fdDst < 0) { |
| 825 | OTA_ERR("Fatal error: can't open dev, src: %s, fdSrc: %d, dst: %s, fdDst: %d\n", |
| 826 | src, fdSrc, dst, fdDst); |
| 827 | goto err; |
| 828 | } |
| 829 | |
| 830 | buf = malloc(erasesize); |
| 831 | if (!buf) { |
| 832 | OTA_ERR("Fatal error: can't malloc 0x%x\n", erasesize); |
| 833 | goto err; |
| 834 | } |
| 835 | |
| 836 | OTA_DEBUG("Sync Src: %s to Dst: %s, Size: 0x%x...\n", sdev, ddev, size); |
| 837 | while (size) { |
| 838 | int n = erasesize; |
| 839 | if (size < erasesize) |
| 840 | n = size; |
| 841 | memset(buf, 0, erasesize); |
| 842 | |
| 843 | if (complete_read(fdSrc, buf, n) < 0) |
| 844 | goto err; |
| 845 | #ifndef CONFIG_PARTITION_EMMC |
| 846 | ioctl(fdDst, MEMUNLOCK, &mtdEraseInfo); |
| 847 | ioctl(fdDst, MEMERASE, &mtdEraseInfo); |
| 848 | #endif |
| 849 | if (complete_write(fdDst, buf, n) < 0) |
| 850 | goto err; |
| 851 | size -= n; |
| 852 | #ifndef CONFIG_PARTITION_EMMC |
| 853 | mtdEraseInfo.start += mtdInfo.erasesize; |
| 854 | #endif |
| 855 | } |
| 856 | |
| 857 | ret = 0; |
| 858 | err: |
| 859 | if (fdSrc >= 0) |
| 860 | close(fdSrc); |
| 861 | if (fdDst >= 0) |
| 862 | close(fdDst); |
| 863 | if (buf) |
| 864 | free(buf); |
| 865 | return ret; |
| 866 | } |
| 867 | |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 868 | #if !defined(CONFIG_AB_SYSTEM_DFOTA) |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 869 | static int get_file_size(const char *path) |
| 870 | { |
| 871 | int filesize = -1; |
| 872 | struct stat statbuff; |
| 873 | if(stat(path, &statbuff) < 0) |
| 874 | return filesize; |
| 875 | else |
| 876 | filesize = statbuff.st_size; |
| 877 | return filesize; |
| 878 | } |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 879 | #endif |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 880 | |
| 881 | static int system_sync() |
| 882 | { |
| 883 | int changed = 0; |
| 884 | |
| 885 | OTA_DEBUG("Start to sync system %c to %c...\n", gAsrFlag.temp_active_slot, gInActiveSystem); |
| 886 | for (int i = 0; i < server_cfg.mtd_cnt; i++) { |
| 887 | struct image_mtd_info *pSrc = &server_cfg.image_mtd_info[i]; |
| 888 | if (pSrc->flag == gAsrFlag.active_slot) { |
| 889 | for (int j = 0; j < server_cfg.mtd_cnt; j++) { |
| 890 | struct image_mtd_info *pDst = &server_cfg.image_mtd_info[j]; |
| 891 | if (pDst->flag == gInActiveSystem) { |
| 892 | if (strlen(pSrc->name) == strlen(pDst->name)) { |
| 893 | int len = strlen(pSrc->name); |
| 894 | if (strncmp(pSrc->name, pDst->name, len - 3) == 0) { |
| 895 | /* remove the suffix "-a\n" or "-b\n", 3 bytes */ |
| 896 | OTA_DEBUG("Start to sync %s to %s...\n", pSrc->name, pDst->name); |
| 897 | if (__system_sync(pSrc->dev, pDst->dev, pDst->size, pDst->erasesize) < 0) { |
| 898 | OTA_ERR("Fatal error: sync failed...\n"); |
| 899 | return -1; |
| 900 | } |
| 901 | OTA_DEBUG("Sync %s to %s OK...\n", pSrc->name, pDst->name); |
| 902 | break; |
| 903 | } |
| 904 | } |
| 905 | } |
| 906 | } |
| 907 | } |
| 908 | } |
| 909 | |
| 910 | if (strncmp(gAsrFlag.mversion, gAsrFlag.MVersion_B, 128) != 0) { |
| 911 | changed = 1; |
| 912 | OTA_DEBUG("diff mversion a: %s, mversion b: %s\n", gAsrFlag.mversion, gAsrFlag.MVersion_B); |
| 913 | if (gInActiveSystem == SYSTEM_A) { |
| 914 | OTA_DEBUG("mversion b -> a\n"); |
| 915 | memset(gAsrFlag.mversion, 0, 128); |
| 916 | strncpy(gAsrFlag.mversion, gAsrFlag.MVersion_B, 128); |
| 917 | } else { |
| 918 | OTA_DEBUG("mversion a -> b\n"); |
| 919 | memset(gAsrFlag.MVersion_B, 0, 128); |
| 920 | strncpy(gAsrFlag.MVersion_B, gAsrFlag.mversion, 128); |
| 921 | } |
| 922 | } |
| 923 | |
| 924 | OTA_DEBUG("System sync done, update the synced flag...\n"); |
| 925 | if (!changed && gAsrFlag.synced == 1) { |
| 926 | /* no need to save flag to flash if synced flag is 1 |
| 927 | * directly return to decrease write flash */ |
| 928 | OTA_DEBUG("The synced flag was set already, no need to update.\n"); |
| 929 | return 0; |
| 930 | } |
| 931 | |
| 932 | gAsrFlag.synced = 1; |
| 933 | gAsrFlag.reboot_cnt = 0; |
| 934 | |
| 935 | OTA_DEBUG("Save Asr Flag: active_slot: %c(0x%x), temp_active_slot: %c(0x%x), reboot_cnt: %d, synced: %d\n", |
| 936 | gAsrFlag.active_slot, gAsrFlag.active_slot, |
| 937 | gAsrFlag.temp_active_slot, gAsrFlag.temp_active_slot, |
| 938 | gAsrFlag.reboot_cnt, gAsrFlag.synced); |
| 939 | return write_asr_flag(&gAsrFlag); |
| 940 | } |
| 941 | |
| 942 | #endif |
| 943 | |
| 944 | |
| 945 | static int tr069_fbf_parse(void * img_addr, int len, struct image_process_context * context) |
| 946 | { |
| 947 | MasterBlockHeader* pMasterHeader = NULL; |
| 948 | PDeviceHeader_11 pDevHeader_11=NULL; |
| 949 | PImageStruct_11 pImage_11=NULL; |
| 950 | ImginfoTable * image_table = NULL, * temp_table = NULL; |
| 951 | |
| 952 | unsigned int * temp_p = NULL; |
| 953 | unsigned int img_num,img_start; |
| 954 | |
| 955 | pMasterHeader = (MasterBlockHeader*)img_addr; |
| 956 | if ((pMasterHeader->Format_Version != 11)) { |
| 957 | OTA_ERR("Bad version\n"); |
| 958 | return -1; |
| 959 | } |
| 960 | |
| 961 | if (pMasterHeader->nOfDevices != 1) { |
| 962 | OTA_ERR("Bad content\n"); |
| 963 | return -1; |
| 964 | } |
| 965 | |
| 966 | if ((len + context->processed_cnt) < sizeof(MasterBlockHeader)) { |
| 967 | return len; |
| 968 | } |
| 969 | |
| 970 | if ((len + context->processed_cnt) < |
| 971 | (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069))) { |
| 972 | OTA_ERR("length less than device offset[%d:%d]\n", |
| 973 | pMasterHeader->deviceHeaderOffset[0], sizeof(struct DeviceHeader_11_tr069)); |
| 974 | return len; |
| 975 | } |
| 976 | |
| 977 | { |
| 978 | // Checking FBF vesion string, if present |
| 979 | const char * version = (const char *)&pMasterHeader->Unique[12]; |
| 980 | if (strlen(version)) OTA_DEBUG("Handle FBF version: %s\n", version); |
| 981 | if (fbf_version_string) { |
| 982 | if (strcmp(fbf_version_string, version)) { |
| 983 | OTA_ERR("Version not match: %s\n", fbf_version_string); |
| 984 | return -1; |
| 985 | } |
| 986 | } |
| 987 | } |
| 988 | |
| 989 | temp_p = (unsigned int *)(pMasterHeader->deviceHeaderOffset[0] + (unsigned int)img_addr); |
| 990 | pDevHeader_11 = (PDeviceHeader_11)temp_p; |
| 991 | OTA_DEBUG("parsed image number is :%d\n", pDevHeader_11->nOfImages); |
| 992 | if ((len + context->processed_cnt) < |
| 993 | (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069) + |
| 994 | sizeof(ImageStruct_11) * pDevHeader_11->nOfImages)) { |
| 995 | return len; |
| 996 | } |
| 997 | |
| 998 | update_oemd = 0; |
| 999 | for(img_num = 0; img_num < pDevHeader_11->nOfImages; img_num ++) { |
| 1000 | temp_p = (unsigned int*)&pDevHeader_11->imageStruct_11[img_num]; |
| 1001 | pImage_11 = (PImageStruct_11)temp_p; |
| 1002 | img_start = pImage_11->First_Sector<<TR069_FBF_HEADER_SIZE; |
| 1003 | |
| 1004 | temp_table = image_table; |
| 1005 | #ifdef CONFIG_AB_SYSTEM |
| 1006 | if (pImage_11->Image_ID == FOTA_FBFVERSION_IMAGEID) { |
| 1007 | server_cfg.fotav_offset_in_fbf = img_start; |
| 1008 | OTA_DEBUG("%s: fotav_offset_in_fbf = 0x%x\n", __func__, server_cfg.fotav_offset_in_fbf); |
| 1009 | } |
| 1010 | |
| 1011 | if (pImage_11->reserve[0] != 0) { |
| 1012 | OTA_DEBUG("Found A/B Image, ID: 0x%x, InTim: %d, " |
| 1013 | "Partition: 0x%x, EraseSize: 0x%x, " |
| 1014 | "CMD: 0x%x, FirstSector: 0x%x, Len: 0x%x, " |
| 1015 | "FlashStartAddress(A): 0x%x, FlashStartAddress(B): 0x%x, " |
| 1016 | "CheckSum: 0x%x\n", |
| 1017 | pImage_11->Image_ID, pImage_11->Image_In_TIM, |
| 1018 | pImage_11->Flash_partition, pImage_11->Flash_erase_size, |
| 1019 | pImage_11->commands, pImage_11->First_Sector, pImage_11->length, |
| 1020 | pImage_11->Flash_Start_Address, pImage_11->reserve[0], |
| 1021 | pImage_11->ChecksumFormatVersion2); |
| 1022 | |
| 1023 | if (gInActiveSystem == SYSTEM_B) { |
| 1024 | /* there are no flash address B for obm & timh */ |
| 1025 | if (pImage_11->Image_ID != IMAGE_ID_TIMH && pImage_11->Image_ID != IMAGE_ID_OBM) |
| 1026 | pImage_11->Flash_Start_Address = pImage_11->reserve[0]; |
| 1027 | } |
| 1028 | } |
| 1029 | |
| 1030 | if (pImage_11->Image_ID == IMAGE_ID_OBM) |
| 1031 | obm_real_size = pImage_11->length; |
| 1032 | |
| 1033 | #ifdef CONFIG_PARTITION_EMMC |
| 1034 | /* the unit of address in fbf was: block */ |
| 1035 | pImage_11->Flash_Start_Address *= server_cfg.emmc_block_size; |
| 1036 | #endif |
| 1037 | |
| 1038 | int i; |
| 1039 | struct image_mtd_info *pImageMtdInfo = NULL; |
| 1040 | for (i = 0; i < server_cfg.mtd_cnt; i++) { |
| 1041 | pImageMtdInfo = &server_cfg.image_mtd_info[i]; |
| 1042 | if (pImage_11->Image_ID == IMAGE_ID_TIMH || pImage_11->Image_ID == IMAGE_ID_OBM) { |
| 1043 | context->upgrade_bootloader = 1; |
| 1044 | #ifdef CONFIG_PARTITION_EMMC |
| 1045 | if (pImage_11->Image_In_TIM == TIMH_INC) { |
| 1046 | if (strstr(pImageMtdInfo->name, "bootloader0")) |
| 1047 | goto found_bootloader; |
| 1048 | } else if (pImage_11->Image_In_TIM == TIMH_RECOVERY_INC) { |
| 1049 | if (strstr(pImageMtdInfo->name, "bootloader1")) |
| 1050 | goto found_bootloader; |
| 1051 | } else { |
| 1052 | exit(-1); |
| 1053 | } |
| 1054 | #else |
| 1055 | if (strstr(pImageMtdInfo->name, "bootloader")) |
| 1056 | goto found_bootloader; |
| 1057 | #endif |
| 1058 | } |
| 1059 | |
| 1060 | if (gInActiveSystem != pImageMtdInfo->flag) |
| 1061 | /* skip the active system mtd */ |
| 1062 | continue; |
| 1063 | if ((pImageMtdInfo->flash_start_offset == pImage_11->Flash_Start_Address) || |
| 1064 | ( |
| 1065 | /* handle cpimage */ |
| 1066 | (pImage_11->Flash_Start_Address > pImageMtdInfo->flash_start_offset) && |
| 1067 | (pImage_11->Flash_Start_Address < (pImageMtdInfo->flash_start_offset + pImageMtdInfo->size)) |
| 1068 | )) { |
| 1069 | break; |
| 1070 | } |
| 1071 | } |
| 1072 | |
| 1073 | if (i == server_cfg.mtd_cnt) { |
| 1074 | OTA_ERR("FBF is not match the current system...(0x%x)\n", pImage_11->Flash_Start_Address); |
| 1075 | continue; |
| 1076 | } |
| 1077 | found_bootloader: |
| 1078 | #endif |
| 1079 | image_table = (ImginfoTable *)malloc(sizeof(ImginfoTable)); |
| 1080 | if (!image_table) { |
| 1081 | OTA_ERR("Failed! cannot malloc memory for image infor table\n"); |
| 1082 | return -1; |
| 1083 | } |
| 1084 | |
| 1085 | image_table->Img_Len= pImage_11->length; |
| 1086 | image_table->Img_Commands = pImage_11->commands; |
| 1087 | image_table->Img_Checksum = pImage_11->ChecksumFormatVersion2; |
| 1088 | image_table->Flash_Erase_Size = pImage_11->Flash_erase_size; |
| 1089 | image_table->Img_Start_Address = img_start; |
| 1090 | image_table->Flash_Start_Address = pImage_11->Flash_Start_Address; |
| 1091 | image_table->Img_ID = pImage_11->Image_ID; |
| 1092 | image_table->Image_In_TIM = pImage_11->Image_In_TIM; |
| 1093 | if (pImage_11->Image_ID == OEMDDENTIFIER) |
| 1094 | update_oemd = 1; |
| 1095 | image_table->next = temp_table; |
| 1096 | #ifdef CONFIG_AB_SYSTEM |
| 1097 | char dev[32] = {0}; |
| 1098 | sprintf(dev, "/dev/%s", pImageMtdInfo->dev); |
| 1099 | if (image_table->Img_ID == IMAGE_ID_OBM) { |
| 1100 | if (image_table->Image_In_TIM == TIMH_INC) |
| 1101 | image_table->fd = open(tmp_obm_main_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| 1102 | else if (image_table->Image_In_TIM == TIMH_RECOVERY_INC) { |
| 1103 | image_table->fd = open(tmp_obm_bk_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| 1104 | context->dual_tim = 1; |
| 1105 | } else { |
| 1106 | OTA_ERR("%s %d: fatal error, unkown Image_In_TIM: %d\n", |
| 1107 | __func__, __LINE__, image_table->Image_In_TIM); |
| 1108 | exit(-1); |
| 1109 | } |
| 1110 | } else if (image_table->Img_ID == IMAGE_ID_TIMH) { |
| 1111 | if (image_table->Image_In_TIM == TIMH_INC) |
| 1112 | image_table->fd = open(tmp_timh_main_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| 1113 | else if (image_table->Image_In_TIM == TIMH_RECOVERY_INC) { |
| 1114 | image_table->fd = open(tmp_timh_bk_file, O_CREAT | O_RDWR | O_SYNC, 777); |
| 1115 | context->dual_tim = 1; |
| 1116 | } else { |
| 1117 | OTA_ERR("%s %d: fatal error, unkown Image_In_TIM: %d\n", |
| 1118 | __func__, __LINE__, image_table->Image_In_TIM); |
| 1119 | exit(-1); |
| 1120 | } |
| 1121 | } else { |
| 1122 | image_table->fd = open(dev, O_RDWR | O_SYNC); |
| 1123 | } |
| 1124 | image_table->partition_size = pImageMtdInfo->size; |
| 1125 | image_table->erased = 0; |
| 1126 | memset(image_table->dev, 0, sizeof(image_table->dev)); |
| 1127 | memset(image_table->name, 0, sizeof(image_table->name)); |
| 1128 | sprintf(image_table->dev, "%s", pImageMtdInfo->dev); |
| 1129 | sprintf(image_table->name, "%s", pImageMtdInfo->name); |
| 1130 | /* 4K align */ |
| 1131 | image_table->Img_Remain_Len = ((image_table->Img_Len + FBF_FILE_SECTOR_SIZE - 1) & (~ (FBF_FILE_SECTOR_SIZE - 1))); |
| 1132 | image_table->Block_Start_Address = pImageMtdInfo->flash_start_offset; |
| 1133 | OTA_DEBUG("Parse new image: start: 0x%08x, len: 0x%08x(flash offset: 0x%08x, %s)\n", img_start, image_table->Img_Len, |
| 1134 | image_table->Flash_Start_Address, pImageMtdInfo->name); |
| 1135 | #else |
| 1136 | OTA_DEBUG("Parse new image: 0x%08x~0x%08x\n", img_start, img_start + image_table->Img_Len); |
| 1137 | #endif |
| 1138 | } |
| 1139 | |
| 1140 | context->image_info_table = image_table; |
| 1141 | if(pDevHeader_11->Reserved[0] == 1){ //DFota |
| 1142 | context->upgrade_method = 4; |
| 1143 | } |
| 1144 | else{ |
| 1145 | context->upgrade_method = 0; |
| 1146 | } |
| 1147 | |
| 1148 | OTA_DEBUG(" first offset: %d\n", pMasterHeader->deviceHeaderOffset[0]); |
| 1149 | OTA_DEBUG(" all header size: %d\n", (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069) + |
| 1150 | sizeof(ImageStruct_11) * pDevHeader_11->nOfImages)); |
| 1151 | OTA_DEBUG(" already processed: %d\n", context->processed_cnt); |
| 1152 | #ifdef CONFIG_AB_SYSTEM |
| 1153 | #ifndef CONFIG_AB_SYSTEM_DFOTA |
| 1154 | /* once parse image ok, clear the synced flag immediately */ |
| 1155 | gAsrFlag.synced = 0; |
| 1156 | write_asr_flag(&gAsrFlag); |
| 1157 | #endif |
| 1158 | #endif |
| 1159 | return (pMasterHeader->deviceHeaderOffset[0] + sizeof(struct DeviceHeader_11_tr069) + |
| 1160 | sizeof(ImageStruct_11) * pDevHeader_11->nOfImages) - context->processed_cnt; |
| 1161 | } |
| 1162 | |
| 1163 | static void dump_table(struct image_process_context * context) |
| 1164 | { |
| 1165 | ImginfoTable * temp = context->image_info_table; |
| 1166 | while (temp) { |
| 1167 | #ifdef CONFIG_AB_SYSTEM |
| 1168 | OTA_DEBUG("Get Image from start: 0x%08x, len: 0x%08x, flashoffset: 0x%08x(%s)\n", |
| 1169 | temp->Img_Start_Address, temp->Img_Len, temp->Flash_Start_Address, temp->name); |
| 1170 | #else |
| 1171 | OTA_DEBUG("Get Image from 0x%08x to 0x%08x\n", temp->Img_Start_Address, temp->Img_Start_Address + temp->Img_Len); |
| 1172 | #endif |
| 1173 | temp = temp->next; |
| 1174 | } |
| 1175 | } |
| 1176 | |
| 1177 | static int build_image_list(struct image_process_context * context) |
| 1178 | { |
| 1179 | struct imginfo_table * table = context->image_info_table; |
| 1180 | |
| 1181 | while (table) { |
| 1182 | struct image_state * temp = malloc(sizeof(struct image_state)); |
| 1183 | struct image_state * backup = context->image_state_list; |
| 1184 | if (!temp) { |
| 1185 | OTA_ERR("Cannot malloc memory..\n"); |
| 1186 | return -1; |
| 1187 | } |
| 1188 | temp->result = 0; // Mask this image is not download |
| 1189 | temp->next_image = backup; |
| 1190 | temp->image_info = table; |
| 1191 | context->image_state_list = temp; |
| 1192 | table = table->next; |
| 1193 | } |
| 1194 | return 0; |
| 1195 | } |
| 1196 | |
| 1197 | static int free_image_list(struct image_process_context * context) |
| 1198 | { |
| 1199 | struct image_state * temp = context->image_state_list; |
| 1200 | while (temp) { |
| 1201 | struct image_state * backup = temp->next_image; |
| 1202 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1203 | close(temp->image_info->fd); |
| 1204 | temp->image_info->fd = -1; |
| 1205 | #endif |
| 1206 | free(temp); |
| 1207 | temp = backup; |
| 1208 | } |
| 1209 | return 0; |
| 1210 | } |
| 1211 | |
| 1212 | static unsigned int fbf_checksum(unsigned char * src, unsigned int len, unsigned int checksum) |
| 1213 | { |
| 1214 | unsigned int * start = (unsigned int *)src; |
| 1215 | unsigned int * end = (unsigned int *)(src + len); |
| 1216 | while (start < end) { |
| 1217 | checksum ^= (*start++); |
| 1218 | } |
| 1219 | return checksum; |
| 1220 | } |
| 1221 | |
| 1222 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1223 | static int mark_current_image_processed(struct image_process_context * context) |
| 1224 | { |
| 1225 | struct image_state * temp = context->image_state_list; |
| 1226 | while (temp) { |
| 1227 | if (temp->image_info == context->current_process) { |
| 1228 | temp->result = 1; // Mark it be processed |
| 1229 | return 0; |
| 1230 | } |
| 1231 | temp = temp->next_image; |
| 1232 | } |
| 1233 | OTA_ERR("Why cannot find the processed image?\n"); |
| 1234 | return -1; |
| 1235 | } |
| 1236 | |
| 1237 | static int image_check(struct image_process_context * context, char * data, int len) |
| 1238 | { |
| 1239 | int size, cnt; |
| 1240 | // First check the data belong to same image |
| 1241 | size = (context->processed_cnt + len - context->current_process->Img_Start_Address) >= context->current_process->Img_Len ? |
| 1242 | context->current_process->Img_Start_Address + context->current_process->Img_Len - context->processed_cnt : len; |
| 1243 | cnt = size; |
| 1244 | |
| 1245 | while (cnt) { |
| 1246 | if ((context->checksum_cache_index + cnt) >= CHECKSUM_CACHE_SIZE) { |
| 1247 | int space = CHECKSUM_CACHE_SIZE - context->checksum_cache_index; |
| 1248 | memcpy(context->checksum_cache + context->checksum_cache_index, data, space); |
| 1249 | context->image_checksum = fbf_checksum(context->checksum_cache, CHECKSUM_CACHE_SIZE, context->image_checksum); |
| 1250 | data += space; |
| 1251 | cnt -= space; |
| 1252 | context->checksum_cache_index = 0; |
| 1253 | } else { |
| 1254 | memcpy(context->checksum_cache + context->checksum_cache_index, data, cnt); |
| 1255 | context->checksum_cache_index += cnt; |
| 1256 | cnt -= cnt; |
| 1257 | } |
| 1258 | } |
| 1259 | |
| 1260 | if ((context->processed_cnt + len - context->current_process->Img_Start_Address) >= context->current_process->Img_Len) { |
| 1261 | OTA_DEBUG("Handle image end...\n"); |
| 1262 | if (context->checksum_cache_index != 0) { |
| 1263 | context->image_checksum = fbf_checksum(context->checksum_cache, context->checksum_cache_index, context->image_checksum); |
| 1264 | } |
| 1265 | OTA_DEBUG(" Image[%08x] checksum 0x%08x:0x%08x\n", context->current_process->Img_ID, context->current_process->Img_Checksum, context->image_checksum); |
| 1266 | if (context->current_process->Img_Checksum == context->image_checksum) { |
| 1267 | mark_current_image_processed(context); |
| 1268 | } else if (context->current_process->Img_ID == RSA_IMAGE_ID) { |
| 1269 | OTA_DEBUG(" RSA image, always mark to pass\n"); |
| 1270 | mark_current_image_processed(context); |
| 1271 | } if (context->current_process->Img_Checksum == 0) { |
| 1272 | OTA_DEBUG(" RAW checksum is zero, always mark to pass\n"); |
| 1273 | mark_current_image_processed(context); |
| 1274 | } |
| 1275 | context->checksum_cache_index = 0; |
| 1276 | context->current_process = 0; |
| 1277 | context->image_checksum = 0; |
| 1278 | } |
| 1279 | context->processed_cnt += size; |
| 1280 | return size; |
| 1281 | } |
| 1282 | #endif |
| 1283 | static void notify_progress(int progress) |
| 1284 | { |
| 1285 | char buf[128] = {0}; |
| 1286 | snprintf(buf, 128, "progress[%d]", progress); |
| 1287 | blob_buf_init(&b, 0); |
| 1288 | blobmsg_add_string(&b, "notification", buf); |
| 1289 | ubus_notify(ctx, &ota_object, "notification", b.head, -1); |
| 1290 | } |
| 1291 | |
| 1292 | static void notify_download_start(void) |
| 1293 | { |
| 1294 | blob_buf_init(&b, 0); |
| 1295 | blobmsg_add_string(&b, "notification", "start"); |
| 1296 | ubus_notify(ctx, &ota_object, "notification", b.head, -1); |
| 1297 | } |
| 1298 | |
| 1299 | static void notify_download_end(int success) |
| 1300 | { |
| 1301 | char buf[128] = {0}; |
| 1302 | snprintf(buf, 128, "end[%d]", !!success); |
| 1303 | blob_buf_init(&b, 0); |
| 1304 | blobmsg_add_string(&b, "notification", buf); |
| 1305 | ubus_notify(ctx, &ota_object, "notification", b.head, -1); |
| 1306 | } |
| 1307 | |
| 1308 | static int firmware_download_cb(char * data, int len, int num, void *cbdata) |
| 1309 | { |
| 1310 | struct image_process_context * context = (struct image_process_context *)cbdata; |
| 1311 | int ret = 0; |
| 1312 | unsigned int temp = 0; |
| 1313 | int total=0; |
| 1314 | if(download_method_ctx.type == OTA_TYPE_UDP){ |
| 1315 | download_method_ctx.received_size +=len; |
| 1316 | _ota_download_progress = download_method_ctx.received_size; |
| 1317 | total = download_method_ctx.file_size; |
| 1318 | }else{ |
| 1319 | _ota_download_progress += len; |
| 1320 | total = num; |
| 1321 | } |
| 1322 | temp = (_ota_download_progress * 100); |
| 1323 | ota_download_progress = (temp / total); |
| 1324 | if (ota_download_progress >= 100) { |
| 1325 | ota_download_progress = 99; |
| 1326 | } |
| 1327 | if ((ota_download_progress - context->ota_download_notification_cnt) >= server_cfg.progress_notify) { |
| 1328 | OTA_DEBUG("OTA download progress %d\n", context->ota_download_notification_cnt); |
| 1329 | context->ota_download_notification_cnt = ota_download_progress; |
| 1330 | notify_progress(context->ota_download_notification_cnt); |
| 1331 | } |
| 1332 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1333 | /* len = 4096 for every packet except for the last one */ |
| 1334 | if (total <= FBF_FILE_SECTOR_SIZE) { |
| 1335 | OTA_ERR("Error file total size %d...\n", total); |
| 1336 | return -1; |
| 1337 | } |
| 1338 | |
| 1339 | /* 1. FBF Head sit one the first sector of the FBF file, check it */ |
| 1340 | if (context->state == HEADER) { |
| 1341 | ret = tr069_fbf_parse(data, len, context); |
| 1342 | if (ret < 0) { |
| 1343 | OTA_ERR("Failed, fbf parse failed...\n"); |
| 1344 | return -1; |
| 1345 | } |
| 1346 | |
| 1347 | if (context->image_info_table) { |
| 1348 | context->state = CONTENT; |
| 1349 | dump_table(context); |
| 1350 | // Build image list for trace all image download result |
| 1351 | build_image_list(context); |
| 1352 | } |
| 1353 | context->processed_cnt = len; |
| 1354 | } else if (context->state == CONTENT) { |
| 1355 | if (context->processed_cnt < 0x2000) { |
| 1356 | OTA_DEBUG("skip 2nd 4K...\n"); |
| 1357 | // Add by liubin |
| 1358 | revision_out_find(data, len, context->processed_cnt); |
| 1359 | // End by liubin |
| 1360 | |
| 1361 | context->processed_cnt += len; |
| 1362 | return 0; |
| 1363 | } |
| 1364 | |
| 1365 | if (context->flash_cache_index < server_cfg.block_size) { |
| 1366 | /* flash_cache_index increase by 4096 */ |
| 1367 | char *pos = context->flash_cache + context->flash_cache_index; |
| 1368 | memcpy(pos, data, len); // len = 4096 here |
| 1369 | context->flash_cache_index += len; |
| 1370 | context->processed_cnt += len; |
| 1371 | } |
| 1372 | |
| 1373 | if (server_cfg.fotav_offset_in_fbf && |
| 1374 | context->processed_cnt == (server_cfg.fotav_offset_in_fbf + 0x1000)) |
| 1375 | { |
| 1376 | memcpy(server_cfg.fotav, context->flash_cache, 128); |
| 1377 | temp = strlen(server_cfg.fotav); |
| 1378 | if (server_cfg.fotav[temp - 1] == ';') |
| 1379 | server_cfg.fotav[temp - 1] = 0; /* remove last ; */ |
| 1380 | OTA_DEBUG("%s: got fota version: %s\n", __func__, server_cfg.fotav); |
| 1381 | if (upgrade_precheck(server_cfg.fotav)) |
| 1382 | exit(-1); |
| 1383 | } |
| 1384 | |
| 1385 | //if (context->flash_cache_index == server_cfg.block_size) { |
| 1386 | /* flush the cache to flash */ |
| 1387 | ImginfoTable *p; |
| 1388 | p = context->image_info_table; |
| 1389 | while (p) |
| 1390 | { |
| 1391 | int image_len = p->Img_Len; |
| 1392 | // bool flush_cache = false; |
| 1393 | /* FBF_FILE_SECTOR_SIZE alignment */ |
| 1394 | image_len = ((image_len + FBF_FILE_SECTOR_SIZE - 1) & (~ (FBF_FILE_SECTOR_SIZE - 1))); |
| 1395 | int total_block = ((image_len + server_cfg.block_size - 1) & (~ (server_cfg.block_size - 1))) / server_cfg.block_size; |
| 1396 | if (context->processed_cnt > p->Img_Start_Address) { |
| 1397 | if (context->processed_cnt < (p->Img_Start_Address + image_len)) { |
| 1398 | if (context->flash_cache_index < server_cfg.block_size) { |
| 1399 | break; |
| 1400 | } |
| 1401 | } |
| 1402 | if (context->processed_cnt == (p->Img_Start_Address + image_len) || |
| 1403 | context->flash_cache_index == server_cfg.block_size) { |
| 1404 | p->cs = fbf_checksum((unsigned char *)context->flash_cache, context->flash_cache_index, p->cs); |
| 1405 | int offset = context->processed_cnt - p->Img_Start_Address; |
| 1406 | struct erase_info_user mtdEraseInfo; |
| 1407 | offset += p->Flash_Start_Address - p->Block_Start_Address; |
| 1408 | int block = ((offset + server_cfg.block_size - 1) & (~ (server_cfg.block_size - 1))) / server_cfg.block_size; |
| 1409 | int start = server_cfg.block_size * (block - 1); |
| 1410 | OTA_DEBUG("@ context->processed_cnt: 0x%x, p->Img_Start_Address: 0x%x, len: 0x%x, start: 0x%x\n", |
| 1411 | context->processed_cnt, p->Img_Start_Address, image_len, start); |
| 1412 | OTA_DEBUG("@ found, dev: %s, name: %s, block: %d(total: %d), cs: 0x%x(expect: 0x%x), index: 0x%x\n", |
| 1413 | p->dev, p->name, block - 1,total_block,p->cs, p->Img_Checksum, context->flash_cache_index); |
| 1414 | |
| 1415 | if (p->fd < 0) { |
| 1416 | OTA_ERR("mtd device open failed...\n"); |
| 1417 | return -1; |
| 1418 | } |
| 1419 | |
| 1420 | if (p->erased == 0 && strstr(p->name, "oem_data")) { |
| 1421 | OTA_DEBUG("Need to Erase all of %s(%s)\n", p->dev, p->name); |
| 1422 | mtdEraseInfo.length = p->partition_size; |
| 1423 | mtdEraseInfo.start = 0; |
| 1424 | #ifndef CONFIG_PARTITION_EMMC |
| 1425 | ioctl(p->fd, MEMUNLOCK, &mtdEraseInfo); |
| 1426 | ioctl(p->fd, MEMERASE, &mtdEraseInfo); |
| 1427 | #endif |
| 1428 | p->erased = 1; |
| 1429 | } |
| 1430 | |
| 1431 | if (p->Img_ID != IMAGE_ID_OBM && p->Img_ID != IMAGE_ID_TIMH) { |
| 1432 | ret = lseek(p->fd, start, SEEK_SET); |
| 1433 | if (ret < 0) |
| 1434 | { |
| 1435 | OTA_ERR("seek failed\n"); |
| 1436 | return -1; |
| 1437 | } |
| 1438 | |
| 1439 | mtdEraseInfo.length = server_cfg.block_size; |
| 1440 | mtdEraseInfo.start = start; |
| 1441 | #ifndef CONFIG_PARTITION_EMMC |
| 1442 | ioctl(p->fd, MEMUNLOCK, &mtdEraseInfo); |
| 1443 | ioctl(p->fd, MEMERASE, &mtdEraseInfo); |
| 1444 | #endif |
| 1445 | } |
| 1446 | |
| 1447 | ret = write(p->fd, context->flash_cache, context->flash_cache_index); |
| 1448 | if (ret != context->flash_cache_index) { |
| 1449 | OTA_ERR("error: write incomplete! %d/%d\n", ret, context->flash_cache_index); |
| 1450 | return -1; |
| 1451 | } |
| 1452 | |
| 1453 | memset(context->flash_cache, 0, server_cfg.block_size); |
| 1454 | context->flash_cache_index = 0; |
| 1455 | break; |
| 1456 | } |
| 1457 | } |
| 1458 | p = p->next; |
| 1459 | } |
| 1460 | |
| 1461 | if (!p) { |
| 1462 | //OTA_ERR("not found image, ignore, %d...\n", context->processed_cnt); |
| 1463 | memset(context->flash_cache, 0, server_cfg.block_size); |
| 1464 | context->flash_cache_index = 0; |
| 1465 | } |
| 1466 | //} |
| 1467 | } |
| 1468 | #else |
| 1469 | if (context->flash_cb) context->flash_cb(context, data, len); |
| 1470 | while (len > 0) { |
| 1471 | switch (context->state) { |
| 1472 | case HEADER: { |
| 1473 | OTA_DEBUG("Header cosume %d, len %d\n", context->processed_cnt,len); |
| 1474 | if ((context->processed_cnt + len) < MINI_SIZE) { |
| 1475 | OTA_DEBUG("FBF header not complete, continue recv\n"); |
| 1476 | context->processed_cnt += len; |
| 1477 | return 0; |
| 1478 | } |
| 1479 | ret = tr069_fbf_parse(context->flash_cache, len, context); |
| 1480 | if (ret < 0) { |
| 1481 | OTA_ERR("Failed, fbf parse failed...\n"); |
| 1482 | context->processed_cnt += len; |
| 1483 | len -= len; |
| 1484 | return -1; |
| 1485 | } |
| 1486 | len -= ret; |
| 1487 | data += ret; |
| 1488 | context->processed_cnt += ret; |
| 1489 | if (context->image_info_table) { |
| 1490 | context->state = CONTENT; |
| 1491 | dump_table(context); |
| 1492 | // Build image list for trace all image download result |
| 1493 | build_image_list(context); |
| 1494 | } |
| 1495 | break; |
| 1496 | } |
| 1497 | case CONTENT: |
| 1498 | default: { |
| 1499 | ImginfoTable * temp; |
| 1500 | if (!context->current_process) { |
| 1501 | int discard; |
| 1502 | temp = context->image_info_table; |
| 1503 | while (temp) { |
| 1504 | if (temp->Img_Start_Address <= (context->processed_cnt + len) && |
| 1505 | temp->Img_Start_Address >= context->processed_cnt) { |
| 1506 | OTA_DEBUG("Find new image: start_address 0x%08x, image length %d, write to 0x%08x\n", |
| 1507 | temp->Img_Start_Address, temp->Img_Len, temp->Flash_Start_Address); |
| 1508 | if(temp->Img_Len!=0){ |
| 1509 | break; |
| 1510 | } |
| 1511 | } |
| 1512 | temp = temp->next; |
| 1513 | } |
| 1514 | if (!temp) { |
| 1515 | OTA_DEBUG("Current data[0x%08x~0x%08x] not contain any content\n", |
| 1516 | context->processed_cnt, context->processed_cnt + len); |
| 1517 | context->processed_cnt += len; |
| 1518 | return 0; |
| 1519 | } |
| 1520 | discard = temp->Img_Start_Address - context->processed_cnt; |
| 1521 | if (discard) OTA_DEBUG("Have discard %d...\n", discard); |
| 1522 | len -= discard; |
| 1523 | data += discard; |
| 1524 | context->processed_cnt += discard; |
| 1525 | context->current_process = temp; |
| 1526 | } |
| 1527 | ret = image_check(context, data, len); |
| 1528 | len -= ret; |
| 1529 | data += ret; |
| 1530 | } |
| 1531 | } |
| 1532 | }; |
| 1533 | #endif |
| 1534 | return 0; |
| 1535 | } |
| 1536 | |
| 1537 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1538 | static char *gTempbuf = NULL; |
| 1539 | static int gTempbufPos = 0; |
| 1540 | static int gTotalBytes = 0; |
| 1541 | /* this wrapper function is to guarantee 4K size each package */ |
| 1542 | static int firmware_download_cb_ab(char * data, int len, int num, void *cbdata) |
| 1543 | { |
| 1544 | int bytes = 0, pos = 0, ret = 0; |
| 1545 | if (!gTempbuf) |
| 1546 | gTempbuf = malloc(4096); |
| 1547 | |
| 1548 | while (len) { |
| 1549 | bytes = len; |
| 1550 | if ((gTempbufPos + len) > 4096) |
| 1551 | bytes = 4096 - gTempbufPos; |
| 1552 | memcpy(gTempbuf + gTempbufPos, data + pos, bytes); |
| 1553 | len -= bytes; |
| 1554 | pos += bytes; |
| 1555 | gTempbufPos += bytes; |
| 1556 | gTotalBytes += bytes; |
| 1557 | if (gTempbufPos == 4096 || gTotalBytes == num) { |
| 1558 | ret = firmware_download_cb(gTempbuf, gTempbufPos, num, cbdata); |
| 1559 | gTempbufPos = 0; |
| 1560 | if (ret) { |
| 1561 | OTA_ERR("%s: failed, ret = %d\n", __func__, ret); |
| 1562 | return ret; |
| 1563 | } |
| 1564 | } |
| 1565 | } |
| 1566 | |
| 1567 | if(gTotalBytes == num) { |
| 1568 | struct image_process_context * context = (struct image_process_context *)cbdata; |
| 1569 | context->download_result = 1; |
| 1570 | free(gTempbuf); |
| 1571 | gTempbuf = NULL; |
| 1572 | } |
| 1573 | return 0; |
| 1574 | } |
| 1575 | #endif |
| 1576 | |
| 1577 | static int push2flash(struct image_process_context * context, char * data, int len) |
| 1578 | { |
| 1579 | int ret; |
| 1580 | int block_cnt = 0; |
| 1581 | struct erase_info_user mtdEraseInfo; |
| 1582 | |
| 1583 | while (len && context->flash_cache) { |
| 1584 | if ((context->flash_cache_index + len) >= server_cfg.block_size) { |
| 1585 | int space = server_cfg.block_size - context->flash_cache_index; |
| 1586 | memcpy(context->flash_cache + context->flash_cache_index, data, space); |
| 1587 | data += space; |
| 1588 | len -= space; |
| 1589 | context->flash_cache_index = 0; |
| 1590 | block_cnt = ((context->processed_cnt + space) / server_cfg.block_size); |
| 1591 | OTA_DEBUG(" write to block %d\n", block_cnt); |
| 1592 | // Write to flash |
| 1593 | ret = lseek(context->fd, server_cfg.block_size * block_cnt, SEEK_SET); |
| 1594 | if (ret < 0) { |
| 1595 | OTA_ERR("seek failed\n"); |
| 1596 | return -1; |
| 1597 | } |
| 1598 | if (context->processed_cnt + space >= server_cfg.fbf_length) { |
| 1599 | OTA_ERR("!!! FILE TOO LARGE !!!\n"); |
| 1600 | return 0; |
| 1601 | } |
| 1602 | mtdEraseInfo.length = server_cfg.block_size; |
| 1603 | mtdEraseInfo.start = server_cfg.block_size * ((context->processed_cnt + space) / server_cfg.block_size); |
| 1604 | ioctl(context->fd, MEMUNLOCK, &mtdEraseInfo); |
| 1605 | ioctl(context->fd, MEMERASE, &mtdEraseInfo); |
| 1606 | ret = write(context->fd, context->flash_cache, server_cfg.block_size); |
| 1607 | if (ret != server_cfg.block_size) { |
| 1608 | OTA_ERR("error: write incomplete!\n"); |
| 1609 | } |
| 1610 | //memset(context->flash_cache, 0, server_cfg.block_size); |
| 1611 | } else { |
| 1612 | memcpy(context->flash_cache + context->flash_cache_index, data, len); |
| 1613 | context->flash_cache_index += len; |
| 1614 | len -= len; |
| 1615 | } |
| 1616 | }; |
| 1617 | |
| 1618 | return 0; |
| 1619 | } |
| 1620 | |
| 1621 | static int flush_flash(struct image_process_context * context) |
| 1622 | { |
| 1623 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1624 | int ret; |
| 1625 | int block_cnt; |
| 1626 | if (context->flash_cache_index && context->flash_cache) { |
| 1627 | block_cnt = ((context->processed_cnt) / server_cfg.block_size); |
| 1628 | if (((context->processed_cnt) % server_cfg.block_size) != 0) { |
| 1629 | block_cnt++;; |
| 1630 | } |
| 1631 | OTA_DEBUG("flush at block %d\n", block_cnt); |
| 1632 | ret = lseek(context->fd, server_cfg.block_size * block_cnt, SEEK_SET); |
| 1633 | if (ret < 0) { |
| 1634 | OTA_ERR("seek failed!\n"); |
| 1635 | return -1; |
| 1636 | } |
| 1637 | write(context->fd, context->flash_cache, server_cfg.block_size); |
| 1638 | } |
| 1639 | #endif |
| 1640 | sync(); |
| 1641 | return 0; |
| 1642 | } |
| 1643 | |
| 1644 | static void __download_throgh_sd(const char * url, struct image_process_context * context) |
| 1645 | { |
| 1646 | int fd = -1; |
| 1647 | int total = 0, all = 0; |
| 1648 | char * buf = NULL; |
| 1649 | |
| 1650 | if (url == NULL || context == NULL) { |
| 1651 | OTA_ERR("Bad parameters!\n"); |
| 1652 | // Add by mbtk |
| 1653 | Download_flag = -1; |
| 1654 | return; |
| 1655 | } |
| 1656 | fd = open(url, O_RDONLY); |
| 1657 | if (fd < 0) { |
| 1658 | OTA_ERR("open for SD download failed!\n"); |
| 1659 | // Add by mbtk |
| 1660 | Download_flag = -1; |
| 1661 | goto done; |
| 1662 | } |
| 1663 | total = lseek(fd, 0, SEEK_END); |
| 1664 | if (total < 0) { |
| 1665 | OTA_ERR("seek failed!\n"); |
| 1666 | // Add by mbtk |
| 1667 | Download_flag = -1; |
| 1668 | goto done; |
| 1669 | } |
| 1670 | |
| 1671 | buf = malloc(4096); |
| 1672 | if (buf == NULL) { |
| 1673 | OTA_ERR("malloc failed!\n"); |
| 1674 | // Add by mbtk |
| 1675 | Download_flag = -1; |
| 1676 | goto done; |
| 1677 | } |
| 1678 | |
| 1679 | all = total; |
| 1680 | lseek(fd, 0, SEEK_SET); |
| 1681 | while (total) { |
| 1682 | int remain = total > 4096 ? 4096 : total; |
| 1683 | int size = 0; |
| 1684 | //OTA_ERR("SD download size: %d:%d\n", total, remain); |
| 1685 | memset(buf, 0, 4096); |
| 1686 | size = read(fd, buf, remain); |
| 1687 | if (size != remain) { |
| 1688 | OTA_ERR("read firmware failed!\n"); |
| 1689 | // Add by mbtk |
| 1690 | Download_flag = -1; |
| 1691 | goto done; |
| 1692 | } |
| 1693 | firmware_download_cb(buf, remain, all, context); |
| 1694 | total -= remain; |
| 1695 | } |
| 1696 | flush_flash(context); |
| 1697 | context->download_result = 1; |
| 1698 | done: |
| 1699 | if (fd >= 0) { |
| 1700 | close(fd); |
| 1701 | fd = -1; |
| 1702 | } |
| 1703 | if (buf) { |
| 1704 | free(buf); |
| 1705 | buf = NULL; |
| 1706 | } |
| 1707 | return; |
| 1708 | } |
| 1709 | |
| 1710 | |
| 1711 | static void __download_throgh_http(const char * url, struct image_process_context * context) |
| 1712 | { |
| 1713 | #if 0 |
| 1714 | CURL *curl = curl_easy_init(); |
| 1715 | unsigned int response_code; |
| 1716 | double firmware_size; |
| 1717 | char * temp = NULL; |
| 1718 | *temp = 2; |
| 1719 | |
| 1720 | OTA_ERR("Try access %s through curl\n", url); |
| 1721 | curl_easy_setopt(curl, CURLOPT_URL, url); |
| 1722 | curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20); |
| 1723 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_cb); |
| 1724 | |
| 1725 | curl_easy_perform(curl); |
| 1726 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); |
| 1727 | curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &firmware_size); |
| 1728 | OTA_ERR("Get response code: %d and firmware size: %d\n", response_code, firmware_size); |
| 1729 | |
| 1730 | curl_easy_cleanup(curl); |
| 1731 | #else |
| 1732 | struct http_client * client = NULL; |
| 1733 | int http_response_code = 0; |
| 1734 | client = http_client_init(); |
| 1735 | if (client == NULL) { |
| 1736 | OTA_ERR("HTTP client init failed!\n"); |
| 1737 | return; |
| 1738 | } |
| 1739 | |
| 1740 | OTA_DEBUG("Try access %s through http\n", url); |
| 1741 | http_client_setopt(client, HTTPCLIENT_OPT_URL, url); |
| 1742 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1743 | http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, firmware_download_cb_ab); |
| 1744 | #else |
| 1745 | http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, firmware_download_cb); |
| 1746 | #endif |
| 1747 | http_client_setopt(client, HTTPCLIENT_OPT_METHOD, HTTPCLIENT_REQUEST_GET); |
| 1748 | http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB_DATA, context); |
| 1749 | http_client_perform(client); |
| 1750 | flush_flash(context); |
| 1751 | http_client_getinfo(client, HTTPCLIENT_GETINFO_RESPONSE_CODE, &http_response_code); |
| 1752 | OTA_DEBUG("HTTP result: %d\n", http_response_code); |
| 1753 | if (http_response_code == 200) { |
| 1754 | context->download_result = 1; |
| 1755 | } |
| 1756 | if (client) http_client_shutdown(client); |
| 1757 | #endif |
| 1758 | } |
| 1759 | |
| 1760 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 1761 | static int push2ram(struct image_process_context * context, char * data, int len) |
| 1762 | { |
| 1763 | while (len && context->flash_cache) { |
| 1764 | if ((context->flash_cache_index + len) >= FILE_VERIFY_RAM_SIZE) { |
| 1765 | int space = FILE_VERIFY_RAM_SIZE - context->flash_cache_index; |
| 1766 | memcpy(context->flash_cache + context->flash_cache_index, data, space); |
| 1767 | data += space; |
| 1768 | len -= space; |
| 1769 | context->flash_cache_index = 0; |
| 1770 | } else { |
| 1771 | memcpy(context->flash_cache + context->flash_cache_index, data, len); |
| 1772 | context->flash_cache_index += len; |
| 1773 | len -= len; |
| 1774 | } |
| 1775 | }; |
| 1776 | return 0; |
| 1777 | } |
| 1778 | |
| 1779 | static int verify_flash_image(struct image_process_context * context, int * file_size) |
| 1780 | { |
| 1781 | // Handle all data, try read it from flash, and verify again |
| 1782 | int error = 0; |
| 1783 | unsigned int i; |
| 1784 | int total = context->processed_cnt; |
| 1785 | struct image_process_context new_context = {0}; |
| 1786 | char * temp = malloc(server_cfg.block_size); |
| 1787 | struct image_state * temp_list; |
| 1788 | int fd = -1; |
| 1789 | struct mtd_info_user mtdInfo; |
| 1790 | unsigned int ofs; |
| 1791 | |
| 1792 | new_context.ota_download_notification_cnt = context->ota_download_notification_cnt; |
| 1793 | fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| 1794 | if (fd < 0) { |
| 1795 | OTA_ERR("Open MTD device failed!\n"); |
| 1796 | return -1; |
| 1797 | } |
| 1798 | if (ioctl(fd, MEMGETINFO, &mtdInfo)) { |
| 1799 | OTA_ERR("Could not get MTD device info from %s\n", server_cfg.mtd_fbf); |
| 1800 | } else { |
| 1801 | struct erase_info_user mtdEraseInfo; |
| 1802 | OTA_DEBUG(" MTD size: %d\n", mtdInfo.size); |
| 1803 | OTA_DEBUG(" MTD erase size: %d\n", mtdInfo.erasesize); |
| 1804 | OTA_DEBUG(" MTD type: %d\n", mtdInfo.type); |
| 1805 | mtdEraseInfo.length = mtdInfo.erasesize;; |
| 1806 | if (mtdInfo.type == MTD_NANDFLASH) { |
| 1807 | for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdInfo.size; mtdEraseInfo.start += mtdInfo.erasesize) { |
| 1808 | ofs = mtdEraseInfo.start; |
| 1809 | if (ioctl(fd, MEMGETBADBLOCK, &ofs)) { |
| 1810 | OTA_ERR("Has bad block at %08x\n", (unsigned int)ofs); |
| 1811 | } |
| 1812 | } |
| 1813 | } |
| 1814 | } |
| 1815 | sync(); |
| 1816 | lseek(fd, server_cfg.block_size, SEEK_SET); |
| 1817 | |
| 1818 | if (!temp) { |
| 1819 | OTA_ERR("Cannot malloc memory for image verify"); |
| 1820 | return -1; |
| 1821 | } |
| 1822 | |
| 1823 | new_context.checksum_cache = malloc(CHECKSUM_CACHE_SIZE); |
| 1824 | if (!new_context.checksum_cache) goto done; |
| 1825 | new_context.flash_cache = malloc(FILE_VERIFY_RAM_SIZE); |
| 1826 | if (!new_context.flash_cache) goto done; |
| 1827 | new_context.flash_cb = push2ram; |
| 1828 | i = 1; |
| 1829 | *file_size = context->processed_cnt; |
| 1830 | while (total) { |
| 1831 | int remain_size = total > server_cfg.block_size ? server_cfg.block_size : total; |
| 1832 | int sub_total = remain_size; |
| 1833 | int ret = 0; |
| 1834 | OTA_DEBUG("Verify block %d\n", i); |
| 1835 | ret = read(fd, temp, server_cfg.block_size); |
| 1836 | if (ret != server_cfg.block_size) { |
| 1837 | OTA_ERR("error: data incomplete!\n"); |
| 1838 | } |
| 1839 | while (remain_size) { |
| 1840 | int space = remain_size > 4096 ? 4096 : remain_size; |
| 1841 | firmware_download_cb(temp + (sub_total - remain_size), space, context->processed_cnt, &new_context); |
| 1842 | remain_size -= space; |
| 1843 | } |
| 1844 | total -= sub_total; |
| 1845 | i++; |
| 1846 | } |
| 1847 | free(temp); |
| 1848 | temp = NULL; |
| 1849 | temp_list = new_context.image_state_list; |
| 1850 | while (temp_list) { |
| 1851 | OTA_DEBUG("The verify image(0x%08x) process result %d\n", |
| 1852 | temp_list->image_info->Img_Checksum, temp_list->result); |
| 1853 | if (!temp_list->result) error = 1; |
| 1854 | temp_list = temp_list->next_image; |
| 1855 | } |
| 1856 | done: |
| 1857 | if (temp) free(temp); |
| 1858 | temp = NULL; |
| 1859 | if (new_context.flash_cache) free(new_context.flash_cache); |
| 1860 | new_context.flash_cache = NULL; |
| 1861 | if (new_context.checksum_cache) free(new_context.checksum_cache); |
| 1862 | new_context.checksum_cache = NULL; |
| 1863 | temp = NULL; |
| 1864 | free_image_list(&new_context); |
| 1865 | close(fd); |
| 1866 | return error; |
| 1867 | } |
| 1868 | #endif |
| 1869 | |
| 1870 | |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 1871 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 1872 | #ifdef CONFIG_PARTITION_EMMC |
| 1873 | static int emmc_boot_lock_unlock(int no, int lock) |
| 1874 | { |
| 1875 | char cmd[64] = {0}; |
| 1876 | sprintf(cmd, "echo %d > /sys/block/mmcblk1boot%d/force_ro", lock, no); |
| 1877 | system(cmd); |
| 1878 | return 0; |
| 1879 | } |
| 1880 | #endif |
| 1881 | |
| 1882 | static int mtd_erase(int fd, unsigned int offset, unsigned int length) |
| 1883 | { |
| 1884 | #ifndef CONFIG_PARTITION_EMMC |
| 1885 | struct erase_info_user erase; |
| 1886 | OTA_DEBUG("%s: offset: 0x%x, length: 0x%x\n", __func__, offset, length); |
| 1887 | if (lseek(fd, offset, SEEK_SET) < 0) { |
| 1888 | OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| 1889 | return -1; |
| 1890 | } |
| 1891 | |
| 1892 | erase.length = length; |
| 1893 | erase.start = offset; |
| 1894 | |
| 1895 | ioctl(fd, MEMUNLOCK, &erase); |
| 1896 | if (ioctl(fd, MEMERASE, &erase) < 0) { |
| 1897 | OTA_ERR("%s: erase failed. err: %d\n", __func__, errno); |
| 1898 | return -1; |
| 1899 | } |
| 1900 | #endif |
| 1901 | return 0; |
| 1902 | } |
| 1903 | |
| 1904 | #ifndef CONFIG_PARTITION_EMMC |
| 1905 | static int is_all_ff(char *buf, int size) |
| 1906 | { |
| 1907 | for (int i = 0; i < size; i++) { |
| 1908 | if (0xff != (unsigned char)buf[i]) |
| 1909 | return 0; |
| 1910 | } |
| 1911 | return 1; |
| 1912 | } |
| 1913 | #endif |
| 1914 | |
| 1915 | static int __upgrade_timh(int fd, unsigned int offset, const char *file, |
| 1916 | unsigned int size, char *dst_buf, unsigned int dst_buf_size, unsigned int pagesize) |
| 1917 | { |
| 1918 | int srcfd = -1, r = -1; |
| 1919 | char *buf = NULL, *dst = NULL; |
| 1920 | int dstsize, off; |
| 1921 | |
| 1922 | OTA_DEBUG("%s: offset: 0x%x, file: %s, size: 0x%x, dst_buf_size: %d, " |
| 1923 | "pagesize: %d, max_timh_size: %d\n", |
| 1924 | __func__, offset, file, size, dst_buf_size, pagesize, server_cfg.max_timh_size); |
| 1925 | if ((srcfd = open(file, O_RDONLY)) < 0) { |
| 1926 | OTA_ERR("%s: failed to open file: %s\n", __func__, file); |
| 1927 | goto err; |
| 1928 | } |
| 1929 | |
| 1930 | buf = malloc(size); |
| 1931 | if (!buf) { |
| 1932 | OTA_ERR("%s: no mem\n", __func__); |
| 1933 | goto err; |
| 1934 | } |
| 1935 | |
| 1936 | if (complete_read(srcfd, buf, size) < 0) { |
| 1937 | OTA_ERR("%s: read failed\n", __func__); |
| 1938 | goto err; |
| 1939 | } |
| 1940 | |
| 1941 | if (lseek(fd, offset, SEEK_SET) < 0) { |
| 1942 | OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| 1943 | goto err; |
| 1944 | } |
| 1945 | |
| 1946 | if (dst_buf) { |
| 1947 | dst = dst_buf; |
| 1948 | dstsize = dst_buf_size; |
| 1949 | memcpy(dst, buf, size); |
| 1950 | } else { |
| 1951 | dst = buf; |
| 1952 | dstsize = size; |
| 1953 | } |
| 1954 | |
| 1955 | #ifndef CONFIG_PARTITION_EMMC |
| 1956 | if (dstsize > server_cfg.max_timh_size) { |
| 1957 | /* 1. write all timh */ |
| 1958 | if (complete_write(fd, dst, server_cfg.max_timh_size) < 0) { |
| 1959 | OTA_ERR("%s: write all timh failed\n", __func__); |
| 1960 | goto err; |
| 1961 | } |
| 1962 | |
| 1963 | /* 2. write bbt */ |
| 1964 | for (off = server_cfg.max_timh_size; off < dstsize; off += pagesize) { |
| 1965 | if (!is_all_ff(dst + off, pagesize)) { |
| 1966 | if (complete_write(fd, dst + off, pagesize) < 0) { |
| 1967 | OTA_ERR("%s: write bbt page failed\n", __func__); |
| 1968 | goto err; |
| 1969 | } |
| 1970 | } else { |
| 1971 | OTA_DEBUG("0x%x + 0x%x is all FF, skip write.\n", offset, off); |
| 1972 | } |
| 1973 | } |
| 1974 | } else { |
| 1975 | #endif |
| 1976 | if (complete_write(fd, dst, dstsize) < 0) { |
| 1977 | OTA_ERR("%s: write failed\n", __func__); |
| 1978 | goto err; |
| 1979 | } |
| 1980 | #ifndef CONFIG_PARTITION_EMMC |
| 1981 | } |
| 1982 | #endif |
| 1983 | |
| 1984 | r = 0; |
| 1985 | err: |
| 1986 | if (srcfd >= 0) |
| 1987 | close(srcfd); |
| 1988 | if (buf) |
| 1989 | free(buf); |
| 1990 | return r; |
| 1991 | } |
| 1992 | |
| 1993 | static int write_to_file(void *buf, int size, const char *file) |
| 1994 | { |
| 1995 | int fd; |
| 1996 | int r = -1; |
| 1997 | fd = open(file, O_CREAT | O_RDWR | O_SYNC | O_TRUNC, 777); |
| 1998 | if (fd < 0) { |
| 1999 | OTA_ERR("%s: failed to open %s\n", __func__, file); |
| 2000 | return r; |
| 2001 | } |
| 2002 | |
| 2003 | if (complete_write(fd, buf, size) < 0) { |
| 2004 | OTA_ERR("%s: write failed\n", __func__); |
| 2005 | goto err; |
| 2006 | } |
| 2007 | |
| 2008 | r = 0; |
| 2009 | err: |
| 2010 | if (fd >= 0) |
| 2011 | close(fd); |
| 2012 | return r; |
| 2013 | } |
| 2014 | |
| 2015 | static int retrive_timh_by_ddrid(const char *file, unsigned int *ddr_id, const char *target_file) |
| 2016 | { |
| 2017 | int size, fd = -1, r = -1; |
| 2018 | char *buf = NULL; |
| 2019 | TIM tim; |
| 2020 | |
| 2021 | OTA_DEBUG("%s: ddr id: 0x%x\n", __func__, *ddr_id); |
| 2022 | size = get_file_size(file); |
| 2023 | if (size <= 0) { |
| 2024 | OTA_ERR("failed to get size of file: %s\n", file); |
| 2025 | return r; |
| 2026 | } |
| 2027 | |
| 2028 | buf = malloc(size); |
| 2029 | if (!buf) { |
| 2030 | OTA_ERR("%s: failed to malloc for file: %s, size: %d\n", |
| 2031 | __func__, file, size); |
| 2032 | return r; |
| 2033 | } |
| 2034 | |
| 2035 | fd = open(file, O_RDONLY); |
| 2036 | if (fd < 0) { |
| 2037 | OTA_ERR("%s: failed to open file: %s\n", |
| 2038 | __func__, file); |
| 2039 | r = -1; |
| 2040 | goto err; |
| 2041 | } |
| 2042 | |
| 2043 | if (complete_read(fd, buf, size) < 0) |
| 2044 | goto err; |
| 2045 | |
| 2046 | SetTIMPointers(buf, &tim); |
| 2047 | if (__retrive_timh_by_ddrid(&tim, ddr_id, &size) != NoError) { |
| 2048 | OTA_ERR("%s: failed to retrive timh\n", __func__); |
| 2049 | goto err; |
| 2050 | } |
| 2051 | |
| 2052 | if (write_to_file(tim.pConsTIM, size, target_file) < 0) |
| 2053 | goto err; |
| 2054 | OTA_DEBUG("%s: OK.\n", __func__); |
| 2055 | r = 0; |
| 2056 | err: |
| 2057 | if (buf) |
| 2058 | free(buf); |
| 2059 | if (fd >= 0) |
| 2060 | close(fd); |
| 2061 | return r; |
| 2062 | } |
| 2063 | |
| 2064 | static int __upgrade_obm(int fd, unsigned int offset, const char *obm_file, const char *timh_file) |
| 2065 | { |
| 2066 | int obm_fd = -1, timh_fd = -1, r = -1; |
| 2067 | char *buf = NULL; |
| 2068 | int obm_size = 0, timh_size = 0; |
| 2069 | |
| 2070 | if (obm_file) |
| 2071 | obm_size = get_file_size(obm_file); |
| 2072 | if (timh_file) |
| 2073 | timh_size = get_file_size(timh_file); |
| 2074 | |
| 2075 | OTA_DEBUG("%s: offset: 0x%x, obm file: %s, obm_size: %d(%d), timh file: %s, timh_size: %d\n", |
| 2076 | __func__, offset, obm_file, obm_size, obm_real_size, timh_file, timh_size); |
| 2077 | obm_size = obm_real_size; |
| 2078 | |
| 2079 | if ((obm_fd = open(obm_file, O_RDONLY)) < 0) { |
| 2080 | OTA_ERR("%s: failed to open obm file: %s\n", __func__, obm_file); |
| 2081 | goto err; |
| 2082 | } |
| 2083 | |
| 2084 | if (timh_file) { |
| 2085 | if ((timh_fd = open(timh_file, O_RDONLY)) < 0) { |
| 2086 | OTA_ERR("%s: failed to open timh file: %s\n", __func__, timh_file); |
| 2087 | goto err; |
| 2088 | } |
| 2089 | } |
| 2090 | |
| 2091 | buf = malloc(obm_size + timh_size); |
| 2092 | if (!buf) { |
| 2093 | OTA_ERR("%s: no mem\n", __func__); |
| 2094 | goto err; |
| 2095 | } |
| 2096 | |
| 2097 | if (complete_read(obm_fd, buf, obm_size) < 0) { |
| 2098 | OTA_ERR("%s: read obm failed\n", __func__); |
| 2099 | goto err; |
| 2100 | } |
| 2101 | |
| 2102 | if (timh_file) { |
| 2103 | if (complete_read(timh_fd, buf + obm_size, timh_size) < 0) { |
| 2104 | OTA_ERR("%s: read timh failed\n", __func__); |
| 2105 | goto err; |
| 2106 | } |
| 2107 | } |
| 2108 | |
| 2109 | /* write obm + timh backup */ |
| 2110 | if (lseek(fd, offset, SEEK_SET) < 0) { |
| 2111 | OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| 2112 | goto err; |
| 2113 | } |
| 2114 | |
| 2115 | if (complete_write(fd, buf, obm_size + timh_size) < 0) { |
| 2116 | OTA_ERR("%s: write failed\n", __func__); |
| 2117 | goto err; |
| 2118 | } |
| 2119 | |
| 2120 | r = 0; |
| 2121 | err: |
| 2122 | if (obm_fd >= 0) close(obm_fd); |
| 2123 | if (timh_fd >= 0) close(timh_fd); |
| 2124 | if (buf) free(buf); |
| 2125 | return r; |
| 2126 | } |
| 2127 | |
| 2128 | static int __upgrade_bootloader(struct image_process_context * context, int Image_In_Tim) |
| 2129 | { |
| 2130 | ImginfoTable *obm = NULL, *timh = NULL, *p; |
| 2131 | int fd = -1, r = -1; |
| 2132 | char *bootdev = NULL; |
| 2133 | char *block0 = NULL; |
| 2134 | char *obm_file = NULL, *timh_file = NULL; |
| 2135 | /* put this file right after the obm */ |
| 2136 | char *timh_bk_file = NULL; |
| 2137 | |
| 2138 | #ifdef CONFIG_PARTITION_EMMC |
| 2139 | int emmc_boot_part = 0; |
| 2140 | if (Image_In_Tim == TIMH_INC) { |
| 2141 | bootdev = "/dev/mmcblk1boot0"; |
| 2142 | emmc_boot_part = 0; |
| 2143 | } else if (Image_In_Tim == TIMH_RECOVERY_INC) { |
| 2144 | bootdev = "/dev/mmcblk1boot1"; |
| 2145 | emmc_boot_part = 1; |
| 2146 | } |
| 2147 | #else |
| 2148 | bootdev = "/dev/mtd0"; |
| 2149 | #endif |
| 2150 | |
| 2151 | if (Image_In_Tim == TIMH_INC) { |
| 2152 | obm_file = (char *)tmp_obm_main_file; |
| 2153 | timh_file = (char *)tmp_timh_main_target_file; |
| 2154 | if (context->dual_tim) |
| 2155 | timh_bk_file = (char *)tmp_timh_bk_target_file; |
| 2156 | } else if (Image_In_Tim == TIMH_RECOVERY_INC) { |
| 2157 | obm_file = (char *)tmp_obm_bk_file; |
| 2158 | timh_file = (char *)tmp_timh_bk_target_file; |
| 2159 | timh_bk_file = (char *)tmp_timh_main_target_file; |
| 2160 | } else { |
| 2161 | OTA_ERR("%s: unsupport %d\n", __func__, Image_In_Tim); |
| 2162 | exit(-1); |
| 2163 | } |
| 2164 | |
| 2165 | if (context->same_tim) { |
| 2166 | timh_file = (char *)tmp_timh_main_target_file; /* always use the main tim */ |
| 2167 | timh_bk_file = NULL; /* no need to append tim to obm */ |
| 2168 | } |
| 2169 | |
| 2170 | p = context->image_info_table; |
| 2171 | while (p) { |
| 2172 | if (p->Img_ID == IMAGE_ID_OBM && p->Image_In_TIM == Image_In_Tim) |
| 2173 | obm = p; |
| 2174 | else if (p->Img_ID == IMAGE_ID_TIMH && p->Image_In_TIM == Image_In_Tim) |
| 2175 | timh = p; |
| 2176 | p = p->next; |
| 2177 | } |
| 2178 | |
| 2179 | if (!obm || !timh) { |
| 2180 | OTA_ERR("no obm or timh.\n"); |
| 2181 | goto err; |
| 2182 | } |
| 2183 | |
| 2184 | OTA_DEBUG("%s: start %d...\n", __func__, Image_In_Tim); |
| 2185 | fd = open(bootdev, O_RDWR | O_SYNC); |
| 2186 | if (fd < 0) { |
| 2187 | OTA_ERR("failed to open %s.\n", bootdev); |
| 2188 | goto err; |
| 2189 | } |
| 2190 | |
| 2191 | #ifdef CONFIG_PARTITION_EMMC |
| 2192 | // no bbm for emmc |
| 2193 | #else |
| 2194 | ioctl(fd, MEMUNLOCKPRIV, NULL); |
| 2195 | |
| 2196 | // bbm related things were in block 0, so we need to backup them |
| 2197 | // 1. load block 0 |
| 2198 | block0 = malloc(server_cfg.block_size); |
| 2199 | if (!block0) { |
| 2200 | OTA_ERR("%s: no mem\n", __func__); |
| 2201 | goto err; |
| 2202 | } |
| 2203 | |
| 2204 | if (lseek(fd, timh->Flash_Start_Address, SEEK_SET) < 0) { |
| 2205 | OTA_ERR("%s: seek failed. err: %d\n", __func__, errno); |
| 2206 | goto err; |
| 2207 | } |
| 2208 | |
| 2209 | if (complete_read(fd, block0, server_cfg.block_size) < 0) { |
| 2210 | OTA_ERR("%s: load block0 failed\n", __func__); |
| 2211 | goto err; |
| 2212 | } |
| 2213 | #endif |
| 2214 | |
| 2215 | // 2. erase timh |
| 2216 | if (mtd_erase(fd, timh->Flash_Start_Address, server_cfg.block_size) < 0) { |
| 2217 | OTA_ERR("erase timh failed\n"); |
| 2218 | goto err; |
| 2219 | } |
| 2220 | |
| 2221 | // 3. erase obm |
| 2222 | if (mtd_erase(fd, obm->Flash_Start_Address, server_cfg.block_size) < 0) { |
| 2223 | OTA_ERR("erase obm failed\n"); |
| 2224 | goto err; |
| 2225 | } |
| 2226 | |
| 2227 | #ifdef CONFIG_PARTITION_EMMC |
| 2228 | /* unlock */ |
| 2229 | emmc_boot_lock_unlock(emmc_boot_part, 0); |
| 2230 | #endif |
| 2231 | |
| 2232 | // 4. write obm |
| 2233 | if (__upgrade_obm(fd, obm->Flash_Start_Address, obm_file, timh_bk_file) < 0) { |
| 2234 | OTA_ERR("update obm failed\n"); |
| 2235 | goto err; |
| 2236 | } |
| 2237 | |
| 2238 | // 5. write timh |
| 2239 | if (__upgrade_timh(fd, timh->Flash_Start_Address, timh_file, |
| 2240 | get_file_size(timh_file), block0, server_cfg.block_size, server_cfg.pagesize) < 0) { |
| 2241 | OTA_ERR("update timh failed\n"); |
| 2242 | goto err; |
| 2243 | } |
| 2244 | |
| 2245 | #ifdef CONFIG_PARTITION_EMMC |
| 2246 | /* unlock */ |
| 2247 | emmc_boot_lock_unlock(emmc_boot_part, 1); |
| 2248 | #endif |
| 2249 | OTA_DEBUG("%s: successfully...\n", __func__); |
| 2250 | |
| 2251 | r = 0; |
| 2252 | err: |
| 2253 | if (fd >= 0) { |
| 2254 | #ifndef CONFIG_PARTITION_EMMC |
| 2255 | ioctl(fd, MEMLOCKPRIV, NULL); |
| 2256 | #endif |
| 2257 | close(fd); |
| 2258 | } |
| 2259 | |
| 2260 | if (block0) free(block0); |
| 2261 | return r; |
| 2262 | } |
| 2263 | |
| 2264 | static int get_soc_id(unsigned int *ddrid, unsigned int *cpuid) |
| 2265 | { |
| 2266 | #define CPUID_STR "chip_id: " |
| 2267 | #define DDRID_STR "ddr_id: " |
| 2268 | const char *file = "/dev/soc_id"; |
| 2269 | int fd = -1, ret = -1; |
| 2270 | char buf[64], *p; |
| 2271 | |
| 2272 | fd = open(file, O_RDONLY); |
| 2273 | if (fd < 0) { |
| 2274 | OTA_ERR("%s: open %s failed.\n", __func__, file); |
| 2275 | goto err; |
| 2276 | } |
| 2277 | |
| 2278 | memset(buf, 0, sizeof(buf)); |
| 2279 | if (read(fd, buf, 64) < 0) { |
| 2280 | OTA_ERR("%s: read failed.\n", __func__); |
| 2281 | goto err; |
| 2282 | } |
| 2283 | |
| 2284 | OTA_DEBUG("%s: soc: %s\n", __func__, buf); |
| 2285 | p = strstr(buf, CPUID_STR); |
| 2286 | if (!p) { |
| 2287 | OTA_ERR("%s: not found chip id.\n", __func__); |
| 2288 | goto err; |
| 2289 | } |
| 2290 | *cpuid = strtoul(p + strlen(CPUID_STR), NULL, 16); |
| 2291 | |
| 2292 | p = strstr(buf, DDRID_STR); |
| 2293 | if (!p) { |
| 2294 | OTA_ERR("%s: not found ddr id.\n", __func__); |
| 2295 | goto err; |
| 2296 | } |
| 2297 | *ddrid = strtoul(p + strlen(DDRID_STR), NULL, 16); |
| 2298 | |
| 2299 | OTA_DEBUG("%s: got cpudid: 0x%x, ddrid: 0x%x\n", __func__, *cpuid, *ddrid); |
| 2300 | err: |
| 2301 | if (fd >= 0) close(fd); |
| 2302 | return ret; |
| 2303 | } |
| 2304 | |
| 2305 | /* |
| 2306 | block0 = main timh + bbt |
| 2307 | block1 = backup timh + bbt |
| 2308 | block2 = main obm + backup timh |
| 2309 | block3 = backup obm + main timh |
| 2310 | */ |
| 2311 | static int upgrade_bootloader(struct image_process_context * context) |
| 2312 | { |
| 2313 | int r = -1; |
| 2314 | int cpuid, revision; |
| 2315 | if (context->upgrade_bootloader != 1) |
| 2316 | /* no bootloader */ |
| 2317 | return 0; |
| 2318 | |
| 2319 | get_soc_id(&server_cfg.ddrid, &server_cfg.cpuid); |
| 2320 | cpuid = server_cfg.cpuid & 0xffff; |
| 2321 | revision = (server_cfg.cpuid >> 16) & 0xff; |
| 2322 | context->same_tim = 0; |
| 2323 | |
| 2324 | #ifndef CONFIG_PARTITION_EMMC |
| 2325 | switch (cpuid) { |
| 2326 | case 0x1802: |
| 2327 | case 0x1826: |
| 2328 | server_cfg.max_timh_size = 4 * 1024; |
| 2329 | break; |
| 2330 | case 0x1803: |
| 2331 | case 0x1828: |
| 2332 | server_cfg.max_timh_size = 8 * 1024; |
| 2333 | break; |
| 2334 | case 0x1903: |
| 2335 | if (context->dual_tim && (revision == 0xA0 || revision == 0xB0)) |
| 2336 | context->same_tim = 1; |
| 2337 | case 0x1901: |
| 2338 | case 0x1906: |
| 2339 | case 0x1806: |
| 2340 | server_cfg.max_timh_size = 16 * 1024; |
| 2341 | break; |
| 2342 | default: |
| 2343 | OTA_DEBUG("%s: default cpuid: 0x%x\n", __func__, server_cfg.cpuid); |
| 2344 | server_cfg.max_timh_size = 16 * 1024; |
| 2345 | break; |
| 2346 | } |
| 2347 | #endif |
| 2348 | |
| 2349 | OTA_DEBUG("%s: dual tim: %d, same tim: %d\n", __func__, context->dual_tim, context->same_tim); |
| 2350 | if (access(tmp_obm_main_file, F_OK) || access(tmp_timh_main_file, F_OK)) { |
| 2351 | OTA_ERR("%s: missing main.\n", __func__); |
| 2352 | goto err; |
| 2353 | } |
| 2354 | |
| 2355 | if (context->dual_tim) { |
| 2356 | if (access(tmp_obm_bk_file, F_OK) || access(tmp_timh_bk_file, F_OK)) { |
| 2357 | OTA_ERR("%s: missing backup.\n", __func__); |
| 2358 | goto err; |
| 2359 | } |
| 2360 | } |
| 2361 | |
| 2362 | if (gAsrFlag.DDR_ID == 0 || gAsrFlag.DDR_ID == 0xFFFFFFFF) { |
| 2363 | gAsrFlag.DDR_ID = server_cfg.ddrid; |
| 2364 | OTA_DEBUG("%s: invalid ddrid in asrflag, use current ddrid.\n", __func__); |
| 2365 | } |
| 2366 | |
| 2367 | if (gAsrFlag.DDR_ID != server_cfg.ddrid) |
| 2368 | OTA_DEBUG("%s: Warning: mismatch ddrid, in asrflag: 0x%x, current ddrid: 0x%x\n", |
| 2369 | __func__, gAsrFlag.DDR_ID, server_cfg.ddrid); |
| 2370 | |
| 2371 | if (retrive_timh_by_ddrid(tmp_timh_main_file, &gAsrFlag.DDR_ID, tmp_timh_main_target_file) < 0) { |
| 2372 | OTA_ERR("failed to retrive timh for ddr: 0x%x to %s.\n", gAsrFlag.DDR_ID, tmp_timh_main_target_file); |
| 2373 | goto err; |
| 2374 | } |
| 2375 | |
| 2376 | if (context->dual_tim) { |
| 2377 | if (retrive_timh_by_ddrid(tmp_timh_bk_file, &gAsrFlag.DDR_ID, tmp_timh_bk_target_file) < 0) { |
| 2378 | OTA_ERR("failed to retrive timh for ddr: 0x%x to %s.\n", gAsrFlag.DDR_ID, tmp_timh_bk_target_file); |
| 2379 | goto err; |
| 2380 | } |
| 2381 | } |
| 2382 | |
| 2383 | if (context->dual_tim) { |
| 2384 | /* upgrade the backup bootloader */ |
| 2385 | if (__upgrade_bootloader(context, TIMH_RECOVERY_INC) < 0) |
| 2386 | goto err; |
| 2387 | } |
| 2388 | |
| 2389 | /* then upgrade the main bootloader */ |
| 2390 | if (__upgrade_bootloader(context, TIMH_INC) < 0) |
| 2391 | goto err; |
| 2392 | |
| 2393 | r = 0; |
| 2394 | err: |
| 2395 | remove(tmp_obm_main_file); |
| 2396 | remove(tmp_timh_main_file); |
| 2397 | remove(tmp_timh_main_target_file); |
| 2398 | if (context->dual_tim) { |
| 2399 | remove(tmp_obm_bk_file); |
| 2400 | remove(tmp_timh_bk_file); |
| 2401 | remove(tmp_timh_bk_target_file); |
| 2402 | } |
| 2403 | return r; |
| 2404 | } |
| 2405 | #endif |
| 2406 | |
| 2407 | static int image_recheck(struct image_process_context * context) |
| 2408 | { |
| 2409 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| 2410 | ImginfoTable *p = context->image_info_table; |
| 2411 | char *cache = malloc(FBF_FILE_SECTOR_SIZE); |
| 2412 | int flag = 0; |
| 2413 | if (!cache) { |
| 2414 | OTA_ERR("no memory\n"); |
| 2415 | return -1; |
| 2416 | } |
| 2417 | |
| 2418 | ImginfoTable *tmp = p; |
| 2419 | while (tmp) { |
| 2420 | lseek(tmp->fd, 0, SEEK_SET); |
| 2421 | tmp = tmp->next; |
| 2422 | } |
| 2423 | |
| 2424 | while (p) { |
| 2425 | p->cs = 0; |
| 2426 | OTA_DEBUG("recheck %s, %s, %d\n", p->dev, p->name, p->Flash_Start_Address - p->Block_Start_Address); |
| 2427 | if (p->Img_ID == IMAGE_ID_OBM || p->Img_ID == IMAGE_ID_TIMH) |
| 2428 | lseek(p->fd, 0, SEEK_SET); |
| 2429 | else |
| 2430 | lseek(p->fd, p->Flash_Start_Address - p->Block_Start_Address, SEEK_SET); |
| 2431 | /* |
| 2432 | int ret = lseek(p->fd, 0, SEEK_SET); |
| 2433 | if (ret < 0) |
| 2434 | { |
| 2435 | OTA_ERR("seek failed, %s\n", p->name); |
| 2436 | flag = -1; |
| 2437 | goto next; |
| 2438 | } |
| 2439 | */ |
| 2440 | int remain = p->Img_Len; |
| 2441 | while (remain > 0) { |
| 2442 | int size = remain > FBF_FILE_SECTOR_SIZE ? FBF_FILE_SECTOR_SIZE : remain; |
| 2443 | memset(cache, 0, FBF_FILE_SECTOR_SIZE); |
| 2444 | int n = read(p->fd, cache, size); |
| 2445 | if (n != size) { |
| 2446 | OTA_ERR("read failed, read %d(expect %d), %s\n", n, size, p->name); |
| 2447 | flag = -1; |
| 2448 | goto next; |
| 2449 | } |
| 2450 | p->cs = fbf_checksum((unsigned char *)cache, FBF_FILE_SECTOR_SIZE, p->cs); |
| 2451 | remain -= n; |
| 2452 | } |
| 2453 | |
| 2454 | if (p->cs != p->Img_Checksum) { |
| 2455 | OTA_ERR("%s, cs: 0x%x(expect 0x%x)\n", p->name, p->cs, p->Img_Checksum); |
| 2456 | flag = -1; |
| 2457 | goto next; |
| 2458 | } else { |
| 2459 | OTA_DEBUG("recheck %s, %s OK, cs: 0x%x(expect 0x%x)...\n", p->dev, p->name, p->cs, p->Img_Checksum); |
| 2460 | } |
| 2461 | next: |
| 2462 | p = p->next; |
| 2463 | } |
| 2464 | |
| 2465 | if (flag == 0) { |
| 2466 | if (upgrade_bootloader(context) < 0) { |
| 2467 | flag = -1; |
| 2468 | OTA_ERR("%s: upgrade bootloader failed, don't reboot or powerdown...\n", |
| 2469 | __func__); |
| 2470 | return flag; |
| 2471 | } |
| 2472 | |
| 2473 | /* all image write ok, update the active system slot */ |
| 2474 | //#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
| 2475 | int slot = gInActiveSystem == SYSTEM_A ? 'a' : 'b'; |
| 2476 | /* tell boot to update NVM files from oemd */ |
| 2477 | if (update_oemd) |
| 2478 | system("touch /NVM/oemd && sync"); |
| 2479 | gAsrFlag.temp_active_slot = slot; |
| 2480 | gAsrFlag.reboot_cnt = 0; |
| 2481 | gAsrFlag.synced = 0; |
| 2482 | |
| 2483 | if (gInActiveSystem == SYSTEM_A) { |
| 2484 | OTA_DEBUG("prev mversion a: %s updated to %s\n", gAsrFlag.mversion, server_cfg.fotav); |
| 2485 | memset(gAsrFlag.mversion, 0, 128); |
| 2486 | strncpy(gAsrFlag.mversion, server_cfg.fotav, 128); |
| 2487 | } else { |
| 2488 | OTA_DEBUG("prev mversion b: %s updated to %s\n", gAsrFlag.mversion, server_cfg.fotav); |
| 2489 | memset(gAsrFlag.MVersion_B, 0, 128); |
| 2490 | strncpy(gAsrFlag.MVersion_B, server_cfg.fotav, 128); |
| 2491 | } |
| 2492 | |
| 2493 | write_asr_flag(&gAsrFlag); |
| 2494 | } |
| 2495 | return flag; |
| 2496 | #else |
| 2497 | struct image_state * image_state_list, * image_state_list_org; |
| 2498 | int file_size = 0; |
| 2499 | image_state_list_org = image_state_list = context->image_state_list; |
| 2500 | if ((context->image_state_list == NULL) || (context->download_result != 1)) { |
| 2501 | return -1; |
| 2502 | } |
| 2503 | |
| 2504 | while (image_state_list) { |
| 2505 | OTA_DEBUG("The image(0x%08x) process result %d\n", |
| 2506 | image_state_list->image_info->Img_Checksum, image_state_list->result); |
| 2507 | if (!image_state_list->result) return -1;; |
| 2508 | image_state_list = image_state_list->next_image; |
| 2509 | } |
| 2510 | |
| 2511 | if (!image_state_list && image_state_list_org) { |
| 2512 | if (verify_flash_image(context, &file_size)) { |
| 2513 | return -1; |
| 2514 | } |
| 2515 | } |
| 2516 | /* set dlflag for non-AB */ |
| 2517 | /* tell boot to update NVM files from oemd */ |
| 2518 | if (update_oemd) |
| 2519 | system("touch /NVM/oemd && sync"); |
| 2520 | |
| 2521 | if(get_asr_flag(&gAsrFlag)) { |
| 2522 | OTA_ERR("Fail to get asr flag\n"); |
| 2523 | return -1; |
| 2524 | } |
| 2525 | gAsrFlag.upgrade_flag = 1; |
| 2526 | gAsrFlag.fbf_flash_address = server_cfg.fbf_addr + server_cfg.block_size; |
| 2527 | gAsrFlag.fbf_file_size = context->processed_cnt; |
| 2528 | gAsrFlag.upgrade_method = context->upgrade_method; |
| 2529 | gAsrFlag.dfota_n_of_images = 0xFFFFFFFF; |
| 2530 | |
| 2531 | if(write_asr_flag(&gAsrFlag)) { |
| 2532 | OTA_ERR("Fail to write asr flag\n"); |
| 2533 | return -1; |
| 2534 | } |
| 2535 | #endif |
| 2536 | return 0; |
| 2537 | } |
| 2538 | |
| 2539 | static int build_udp_server(const char * path) |
| 2540 | { |
| 2541 | int fd = -1; |
| 2542 | struct timeval timeout = {10, 0}; |
| 2543 | struct sockaddr_un un = {0}; |
| 2544 | int size; |
| 2545 | |
| 2546 | unlink(path); |
| 2547 | un.sun_family = AF_UNIX; |
| 2548 | sprintf(un.sun_path, "%s", path); |
| 2549 | OTA_DEBUG("Will create socket at %s\n", un.sun_path); |
| 2550 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { |
| 2551 | OTA_ERR("Build socket failed!\n"); |
| 2552 | return -1; |
| 2553 | } |
| 2554 | if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout))) { |
| 2555 | OTA_ERR("Set timeout failed!\n"); |
| 2556 | goto failed; |
| 2557 | } |
| 2558 | |
| 2559 | size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path); |
| 2560 | if (bind(fd, (struct sockaddr*)&un, size)) { |
| 2561 | OTA_ERR("Bind failed!\n"); |
| 2562 | goto failed; |
| 2563 | } |
| 2564 | //(void)chmod(un.sun_path, 0777); |
| 2565 | OTA_DEBUG("will listen on %d\n", fd); |
| 2566 | if (listen(fd, 5) < 0) { |
| 2567 | OTA_ERR("Listen failed!\n"); |
| 2568 | goto failed; |
| 2569 | } |
| 2570 | return fd; |
| 2571 | |
| 2572 | failed: |
| 2573 | if (fd > 0) { |
| 2574 | close(fd); |
| 2575 | } |
| 2576 | return -1; |
| 2577 | } |
| 2578 | |
| 2579 | static int accept_udp(int fd) |
| 2580 | { |
| 2581 | struct timeval timeout = {10, 0}; |
| 2582 | int client; |
| 2583 | |
| 2584 | client = accept(fd, NULL, 0); |
| 2585 | if (client < 0) { |
| 2586 | OTA_ERR("Accept failed!\n"); |
| 2587 | } else { |
| 2588 | setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); |
| 2589 | } |
| 2590 | return client; |
| 2591 | } |
| 2592 | |
| 2593 | static void __download_throgh_udp(int fd, int size, struct image_process_context * context) |
| 2594 | { |
| 2595 | int total = size; |
| 2596 | char * buf = malloc(4096); |
| 2597 | int res=0; |
| 2598 | |
| 2599 | if (buf == NULL) { |
| 2600 | OTA_ERR("memory issue at __download_through_udp!\n"); |
| 2601 | return; |
| 2602 | } |
| 2603 | |
| 2604 | // for debug |
| 2605 | OTA_DEBUG("size: %d.\n", size); |
| 2606 | |
| 2607 | while (total) { |
| 2608 | int recved = 0; |
| 2609 | memset(buf, 0, 4096); |
| 2610 | |
| 2611 | int n = total > 4096 ? 4096 : total; |
| 2612 | int ret; |
| 2613 | repeat: |
| 2614 | ret = recv(fd, buf + recved, n, 0); |
| 2615 | if (ret <= 0) { |
| 2616 | OTA_ERR("recv failed! errno: %d, %s\n", errno, strerror(errno)); |
| 2617 | if (errno == EAGAIN) { |
| 2618 | sleep(1); |
| 2619 | OTA_DEBUG("try again.\n"); |
| 2620 | goto repeat; |
| 2621 | } |
| 2622 | goto done; |
| 2623 | } |
| 2624 | recved += ret; |
| 2625 | n -= ret; |
| 2626 | if (n != 0) { |
| 2627 | //OTA_DEBUG("recved: %d, n: %d, ret: %d\n", recved, n, ret); |
| 2628 | goto repeat; |
| 2629 | } |
| 2630 | |
| 2631 | res=firmware_download_cb(buf, recved, size, context); |
| 2632 | if(res<0){ |
| 2633 | goto done; |
| 2634 | } |
| 2635 | total -= recved; |
| 2636 | }; |
| 2637 | OTA_DEBUG("__download_throgh_udp received_size[%d],file_size[%d]\n", download_method_ctx.received_size,download_method_ctx.file_size); |
| 2638 | if(download_method_ctx.received_size == download_method_ctx.file_size){ |
| 2639 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 2640 | flush_flash(context); |
| 2641 | #endif |
| 2642 | context->download_result = 1; |
| 2643 | } |
| 2644 | done: |
| 2645 | if (buf) { |
| 2646 | free(buf); |
| 2647 | buf = NULL; |
| 2648 | } |
| 2649 | return; |
| 2650 | } |
| 2651 | |
| 2652 | |
| 2653 | |
| 2654 | |
| 2655 | static int erase_ota_fbf_area(void) |
| 2656 | { |
| 2657 | #if defined(CONFIG_AB_SYSTEM) && !defined(CONFIG_AB_SYSTEM_DFOTA) |
| 2658 | return 0; |
| 2659 | #else |
| 2660 | struct erase_info_user mtdEraseInfo; |
| 2661 | struct mtd_info_user mtdInfo; |
| 2662 | int fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| 2663 | if (ioctl(fd, MEMGETINFO, &mtdInfo)) { |
| 2664 | OTA_ERR("Could not get MTD FBF device info from %s\n", server_cfg.mtd_fbf); |
| 2665 | close(fd); |
| 2666 | update_state = UPDATE_STATE_FAILED; |
| 2667 | return -1; |
| 2668 | } |
| 2669 | mtdEraseInfo.length = mtdInfo.erasesize; |
| 2670 | for (mtdEraseInfo.start = 0; mtdEraseInfo.start < mtdInfo.size; mtdEraseInfo.start += mtdInfo.erasesize) { |
| 2671 | ioctl(fd, MEMUNLOCK, &mtdEraseInfo); |
| 2672 | ioctl(fd, MEMERASE, &mtdEraseInfo); |
| 2673 | } |
| 2674 | close(fd); |
| 2675 | fd = -1; |
| 2676 | sync(); |
| 2677 | #endif |
| 2678 | return 0; |
| 2679 | |
| 2680 | } |
| 2681 | |
| 2682 | static struct image_process_context *udp_context=NULL; |
| 2683 | static int udp_download_cb(struct uloop_timeout *timeout) |
| 2684 | { |
| 2685 | //int type = download_method_ctx.type; |
| 2686 | int size = download_method_ctx.size; |
| 2687 | int segment_size = download_method_ctx.segment_size; |
| 2688 | char * url = download_method_ctx.url; |
| 2689 | char * username = download_method_ctx.username; |
| 2690 | char * psw = download_method_ctx.pwd; |
| 2691 | int ret = -1; |
| 2692 | struct image_process_context *context=NULL; |
| 2693 | |
| 2694 | if(size==0 && udp_context==NULL){ |
| 2695 | OTA_ERR("ubus call donwload paramer abnormal!\n");//rm60362 |
| 2696 | notify_download_end(0); |
| 2697 | update_state = UPDATE_STATE_FAILED; |
| 2698 | goto exit; |
| 2699 | } |
| 2700 | |
| 2701 | if(size!=0){ |
| 2702 | if(udp_context){ |
| 2703 | if (udp_context->flash_cache) free(udp_context->flash_cache); |
| 2704 | udp_context->flash_cache = NULL; |
| 2705 | if (udp_context->checksum_cache) free(udp_context->checksum_cache); |
| 2706 | udp_context->checksum_cache = NULL; |
| 2707 | if(udp_context->fd!=-1){ |
| 2708 | close(udp_context->fd); |
| 2709 | udp_context->fd = -1; |
| 2710 | } |
| 2711 | |
| 2712 | if (udp_context->image_state_list) { |
| 2713 | free_image_list(udp_context); |
| 2714 | udp_context->image_state_list=NULL; |
| 2715 | } |
| 2716 | if(udp_context){ |
| 2717 | free(udp_context); |
| 2718 | udp_context = NULL; |
| 2719 | } |
| 2720 | |
| 2721 | } |
| 2722 | |
| 2723 | udp_context = (struct image_process_context *)malloc(sizeof(struct image_process_context)); |
| 2724 | memset(udp_context,0,sizeof(struct image_process_context)); |
| 2725 | } |
| 2726 | context = udp_context; |
| 2727 | |
| 2728 | if(size!=0){ |
| 2729 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 2730 | context->fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| 2731 | if (context->fd < 0) { |
| 2732 | OTA_ERR("Cannot open MTD device!\n"); |
| 2733 | notify_download_end(0); |
| 2734 | update_state = UPDATE_STATE_FAILED; |
| 2735 | return ret; |
| 2736 | } |
| 2737 | #endif |
| 2738 | notify_download_start(); |
| 2739 | _ota_download_progress = ota_download_progress = 0; |
| 2740 | |
| 2741 | download_method_ctx.file_size = size; |
| 2742 | download_method_ctx.received_size = 0; |
| 2743 | // Init firmware download context |
| 2744 | context->flash_cache = malloc(server_cfg.block_size); |
| 2745 | if (!context->flash_cache) { |
| 2746 | OTA_ERR("Cannot malloc memory for download cache\n"); |
| 2747 | goto done; |
| 2748 | } |
| 2749 | #ifdef CONFIG_AB_SYSTEM |
| 2750 | memset(context->flash_cache, 0, server_cfg.block_size); |
| 2751 | #endif |
| 2752 | context->checksum_cache = malloc(CHECKSUM_CACHE_SIZE); |
| 2753 | if (!context->checksum_cache) { |
| 2754 | OTA_ERR("Cannot malloc memory for download cache\n"); |
| 2755 | goto done; |
| 2756 | } |
| 2757 | context->flash_cb = push2flash; |
| 2758 | } |
| 2759 | |
| 2760 | // download from UDP |
| 2761 | int s = -1, c = -1; |
| 2762 | OTA_DEBUG("Download through UDP\n"); |
| 2763 | s = build_udp_server(url); |
| 2764 | if (s >= 0) { |
| 2765 | c = accept_udp(s); |
| 2766 | if (c >= 0) { |
| 2767 | |
| 2768 | if(size!=0){ |
| 2769 | if(erase_ota_fbf_area()) |
| 2770 | goto done; |
| 2771 | } |
| 2772 | |
| 2773 | __download_throgh_udp(c, segment_size, context); |
| 2774 | |
| 2775 | }else{ |
| 2776 | OTA_ERR("accept_udp failed\n"); |
| 2777 | } |
| 2778 | }else{ |
| 2779 | OTA_ERR("build_udp_server failed\n"); |
| 2780 | return 0; |
| 2781 | } |
| 2782 | if (s >= 0) close(s); |
| 2783 | if (c >= 0) close(c); |
| 2784 | ret = 0; |
| 2785 | |
| 2786 | done: |
| 2787 | if(download_method_ctx.file_size == download_method_ctx.received_size){ |
| 2788 | // Clear context |
| 2789 | if (context->flash_cache) free(context->flash_cache); |
| 2790 | context->flash_cache = NULL; |
| 2791 | if (context->checksum_cache) free(context->checksum_cache); |
| 2792 | context->checksum_cache = NULL; |
| 2793 | close(context->fd); |
| 2794 | context->fd = -1; |
| 2795 | if (image_recheck(context) == 0) { |
| 2796 | update_state = UPDATE_STATE_UPDATED; |
| 2797 | OTA_ERR("%s: Image download succssful.\n", __func__); |
| 2798 | notify_download_end(1); |
| 2799 | ret = 0; |
| 2800 | } else { |
| 2801 | update_state = UPDATE_STATE_FAILED; |
| 2802 | OTA_ERR("Image download failed\n"); |
| 2803 | notify_download_end(0); |
| 2804 | ret = -1; |
| 2805 | } |
| 2806 | if (context->image_state_list) { |
| 2807 | free_image_list(context); |
| 2808 | context->image_state_list=NULL; |
| 2809 | } |
| 2810 | if(udp_context){ |
| 2811 | free(udp_context); |
| 2812 | udp_context = NULL; |
| 2813 | } |
| 2814 | |
| 2815 | |
| 2816 | } |
| 2817 | else{ |
| 2818 | //update_state = UPDATE_STATE_IDLE; |
| 2819 | //notify_download_end(1); |
| 2820 | } |
| 2821 | exit: |
| 2822 | |
| 2823 | if (url) free(url); |
| 2824 | url = NULL; |
| 2825 | if (username) free(username); |
| 2826 | username = NULL; |
| 2827 | if (psw) free(psw); |
| 2828 | psw = NULL; |
| 2829 | return ret; |
| 2830 | } |
| 2831 | |
| 2832 | |
| 2833 | static int download_cb(struct uloop_timeout *timeout) |
| 2834 | { |
| 2835 | int type = download_method_ctx.type; |
| 2836 | int size = download_method_ctx.size; |
| 2837 | char * url = download_method_ctx.url; |
| 2838 | char * username = download_method_ctx.username; |
| 2839 | char * psw = download_method_ctx.pwd; |
| 2840 | struct image_process_context context = {0}; |
| 2841 | int ret = -1; |
| 2842 | |
| 2843 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 2844 | context.fd = open(server_cfg.mtd_fbf, O_RDWR | O_SYNC); |
| 2845 | if (context.fd < 0) { |
| 2846 | OTA_ERR("Cannot open MTD device!\n"); |
| 2847 | notify_download_end(0); |
| 2848 | update_state = UPDATE_STATE_FAILED; |
| 2849 | return ret; |
| 2850 | } |
| 2851 | #endif |
| 2852 | notify_download_start(); |
| 2853 | |
| 2854 | _ota_download_progress = ota_download_progress = 0; |
| 2855 | // Init firmware download context |
| 2856 | context.flash_cache = malloc(server_cfg.block_size); |
| 2857 | if (!context.flash_cache) { |
| 2858 | OTA_ERR("Cannot malloc memory for download cache\n"); |
| 2859 | goto done; |
| 2860 | } |
| 2861 | #ifdef CONFIG_AB_SYSTEM |
| 2862 | memset(context.flash_cache, 0, server_cfg.block_size); |
| 2863 | #endif |
| 2864 | context.checksum_cache = malloc(CHECKSUM_CACHE_SIZE); |
| 2865 | if (!context.checksum_cache) { |
| 2866 | OTA_ERR("Cannot malloc memory for download cache\n"); |
| 2867 | goto done; |
| 2868 | } |
| 2869 | context.flash_cb = push2flash; |
| 2870 | |
| 2871 | if (type == OTA_TYPE_HTTP) { |
| 2872 | // download from http |
| 2873 | if(erase_ota_fbf_area()) |
| 2874 | goto done; |
| 2875 | __download_throgh_http(url, &context); |
| 2876 | } else if (type == OTA_TYPE_UDP) { |
| 2877 | // download from UDP |
| 2878 | int s = -1, c = -1; |
| 2879 | OTA_DEBUG("Download through UDP\n"); |
| 2880 | s = build_udp_server(url); |
| 2881 | if (s >= 0) { |
| 2882 | c = accept_udp(s); |
| 2883 | if (c >= 0) { |
| 2884 | if(erase_ota_fbf_area()) |
| 2885 | goto done; |
| 2886 | __download_throgh_udp(c, size, &context); |
| 2887 | } |
| 2888 | } |
| 2889 | if (s >= 0) close(s); |
| 2890 | if (c >= 0) close(c); |
| 2891 | } else if (type == OTA_TYPE_SD) { |
| 2892 | // download from SD |
| 2893 | if(erase_ota_fbf_area()) |
| 2894 | goto done; |
| 2895 | __download_throgh_sd(url, &context); |
| 2896 | } else { |
| 2897 | // assert? |
| 2898 | OTA_ERR("Unknow download type\n"); |
| 2899 | } |
| 2900 | |
| 2901 | done: |
| 2902 | // Clear context |
| 2903 | if (context.flash_cache) free(context.flash_cache); |
| 2904 | context.flash_cache = NULL; |
| 2905 | if (context.checksum_cache) free(context.checksum_cache); |
| 2906 | context.checksum_cache = NULL; |
| 2907 | if (url) free(url); |
| 2908 | url = NULL; |
| 2909 | if (username) free(username); |
| 2910 | username = NULL; |
| 2911 | if (psw) free(psw); |
| 2912 | psw = NULL; |
| 2913 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 2914 | close(context.fd); |
| 2915 | context.fd = -1; |
| 2916 | #endif |
| 2917 | // Change by mbtk |
| 2918 | if ((image_recheck(&context) == 0) && !Download_flag) { |
| 2919 | update_state = UPDATE_STATE_UPDATED; |
| 2920 | OTA_DEBUG("Image download succssful\n"); |
| 2921 | |
| 2922 | // Add by liubin |
| 2923 | revision_out_update(); |
| 2924 | // End by liubin |
| 2925 | |
| 2926 | notify_download_end(1); |
| 2927 | ret = 0; |
| 2928 | } else { |
| 2929 | update_state = UPDATE_STATE_FAILED; |
| 2930 | OTA_ERR("Image download failed\n"); |
| 2931 | notify_download_end(0); |
| 2932 | ret = -1; |
| 2933 | } |
| 2934 | |
| 2935 | if (context.image_state_list) { |
| 2936 | free_image_list(&context); |
| 2937 | } |
| 2938 | return ret; |
| 2939 | } |
| 2940 | |
| 2941 | static struct uloop_timeout download_timer = { .cb = (void*)download_cb }; |
| 2942 | static struct uloop_timeout udp_download_timer = { .cb = (void*)udp_download_cb }; |
| 2943 | |
| 2944 | |
| 2945 | static int download_func(struct ubus_context *ctx, struct ubus_object *obj, |
| 2946 | struct ubus_request_data *req, const char *method, |
| 2947 | struct blob_attr *msg) |
| 2948 | { |
| 2949 | struct blob_attr *tb[__DOWNLOAD_MAX]; |
| 2950 | int ret = -1; |
| 2951 | int sync = 0; /* default is no sync */ |
| 2952 | int type=-1; |
| 2953 | blob_buf_init(&b, 0); |
| 2954 | |
| 2955 | blobmsg_parse(download_policy, ARRAY_SIZE(download_policy), tb, blob_data(msg), blob_len(msg)); |
| 2956 | if (tb[DOWNLOAD_TYPE]) type = blobmsg_get_u32(tb[DOWNLOAD_TYPE]); |
| 2957 | |
| 2958 | |
| 2959 | if ((update_state == UPDATE_STATE_IDLE ||update_state == UPDATE_STATE_FAILED) || |
| 2960 | (type == OTA_TYPE_UDP && update_state == UPDATE_STATE_UPDATING)) { |
| 2961 | update_state = UPDATE_STATE_UPDATING; |
| 2962 | |
| 2963 | OTA_DEBUG("Method call: %s\n", method); |
| 2964 | //memset(&download_method_ctx, 0, sizeof(download_method_ctx)); |
| 2965 | download_method_ctx.url = download_method_ctx.username = download_method_ctx.pwd =NULL; |
| 2966 | download_method_ctx.type = download_method_ctx.size = download_method_ctx.segment_size= 0; |
| 2967 | if (tb[DOWNLOAD_URL]) download_method_ctx.url = strdup(blobmsg_data(tb[DOWNLOAD_URL])); |
| 2968 | if (tb[DOWNLOAD_NAME]) download_method_ctx.username = strdup(blobmsg_data(tb[DOWNLOAD_NAME])); |
| 2969 | if (tb[DOWNLOAD_PSW]) download_method_ctx.pwd = strdup(blobmsg_data(tb[DOWNLOAD_PSW])); |
| 2970 | if (tb[DOWNLOAD_TYPE]) download_method_ctx.type = blobmsg_get_u32(tb[DOWNLOAD_TYPE]); |
| 2971 | if (tb[DOWNLOAD_FILE_SIZE]) download_method_ctx.size = blobmsg_get_u32(tb[DOWNLOAD_FILE_SIZE]); |
| 2972 | if (tb[DOWNLOAD_SYNC]) sync = blobmsg_get_u32(tb[DOWNLOAD_SYNC]); |
| 2973 | if (tb[DOWNLOAD_SEGMENT_SIZE]) download_method_ctx.segment_size = blobmsg_get_u32(tb[DOWNLOAD_SEGMENT_SIZE]); |
| 2974 | |
| 2975 | if (download_method_ctx.url) OTA_DEBUG(" url: %s\n", download_method_ctx.url); |
| 2976 | if (download_method_ctx.username) OTA_DEBUG(" username: %s\n", download_method_ctx.username); |
| 2977 | if (download_method_ctx.pwd) OTA_DEBUG(" password: %s\n", download_method_ctx.pwd); |
| 2978 | OTA_DEBUG(" type: %d, size: %d ,segment size: %d\n", download_method_ctx.type, download_method_ctx.size,download_method_ctx.segment_size); |
| 2979 | |
| 2980 | if (sync != 1) { |
| 2981 | if(download_method_ctx.type == OTA_TYPE_UDP){ |
| 2982 | uloop_timeout_set(&udp_download_timer, 1); |
| 2983 | }else{ |
| 2984 | uloop_timeout_set(&download_timer, 1); |
| 2985 | } |
| 2986 | blobmsg_add_string(&b, "response", "download ready"); |
| 2987 | ret = 0; |
| 2988 | } else { |
| 2989 | if(download_method_ctx.type == OTA_TYPE_UDP){ |
| 2990 | ret = udp_download_cb(&udp_download_timer); |
| 2991 | }else{ |
| 2992 | ret = download_cb(&download_timer); |
| 2993 | } |
| 2994 | if (ret == 0) { |
| 2995 | blobmsg_add_string(&b, "response", "image download succssful"); |
| 2996 | } else { |
| 2997 | blobmsg_add_string(&b, "response", "image download failed"); |
| 2998 | } |
| 2999 | } |
| 3000 | } else { |
| 3001 | OTA_ERR("Error! update already in processing or be processed\n"); |
| 3002 | blobmsg_add_string(&b, "response", "download failed (update already in processing or be processed)"); |
| 3003 | ret = -1; |
| 3004 | } |
| 3005 | |
| 3006 | ubus_send_reply(ctx, req, b.head); |
| 3007 | return ret; |
| 3008 | } |
| 3009 | |
| 3010 | // Version check |
| 3011 | struct xml_parse_context { |
| 3012 | const char * file; |
| 3013 | int i; |
| 3014 | char tag[OTA_MAX_STRING_LEN]; |
| 3015 | char * value; |
| 3016 | int value_size; |
| 3017 | int state; |
| 3018 | }; |
| 3019 | enum { |
| 3020 | XML_STATE_NULL, |
| 3021 | XML_STATE_TAG, |
| 3022 | XML_STATE_VALUE, |
| 3023 | }; |
| 3024 | static int get_next_tag(struct xml_parse_context * context) |
| 3025 | { |
| 3026 | int len = 0; |
| 3027 | int i = context->i; |
| 3028 | int start = 0; |
| 3029 | if (context->file[i++] != '<') { |
| 3030 | return -1; |
| 3031 | } |
| 3032 | if (context->file[i] == '/') { |
| 3033 | return -1; |
| 3034 | } |
| 3035 | start = i; |
| 3036 | while (context->file[i] != '\0') { |
| 3037 | if (context->file[i] == '>') { |
| 3038 | memset(context->tag, 0, OTA_MAX_STRING_LEN); |
| 3039 | if (len > OTA_MAX_STRING_LEN) { |
| 3040 | OTA_ERR("Memory issue in get_next_tag(%d)!\n", len); |
| 3041 | return -1; |
| 3042 | } |
| 3043 | memcpy(context->tag, &context->file[start], len); |
| 3044 | context->i += (len + 2); |
| 3045 | OTA_DEBUG("Tag: %s\n", context->tag); |
| 3046 | return 0; |
| 3047 | } |
| 3048 | len++; |
| 3049 | i++; |
| 3050 | } |
| 3051 | return -1; |
| 3052 | } |
| 3053 | static int get_next_value(struct xml_parse_context * context) |
| 3054 | { |
| 3055 | int len = 0; |
| 3056 | int i = context->i; |
| 3057 | int start = 0; |
| 3058 | if (context->file[i] == '<') { |
| 3059 | return -1; |
| 3060 | } |
| 3061 | while (context->file[i] == '\r' || context->file[i] == '\t' || context->file[i] == '\n') { |
| 3062 | i++; |
| 3063 | } |
| 3064 | start = i; |
| 3065 | while (context->file[i] != '\0') { |
| 3066 | if (context->file[i] == '<') { |
| 3067 | if (context->file[i + 1] != '/') { |
| 3068 | OTA_ERR("Bad file!\n"); |
| 3069 | return -1; |
| 3070 | } |
| 3071 | if (strncmp(&context->file[i + 2], context->tag, strlen(context->tag))) { |
| 3072 | OTA_ERR("tag not match!\n"); |
| 3073 | return -1; |
| 3074 | } |
| 3075 | memset(context->value, 0, context->value_size); |
| 3076 | if (len > context->value_size) { |
| 3077 | OTA_ERR("Memory issue in get_next_vale(%d:%d)!\n", len, context->value_size); |
| 3078 | return -1; |
| 3079 | } |
| 3080 | memcpy(context->value, &context->file[start], len); |
| 3081 | context->i += (len + 3 + strlen(context->tag)); |
| 3082 | OTA_DEBUG("Value: %s\n", context->value); |
| 3083 | return 0; |
| 3084 | } |
| 3085 | len++; |
| 3086 | i++; |
| 3087 | } |
| 3088 | return -1; |
| 3089 | } |
| 3090 | |
| 3091 | static int version_parse(const char * string, struct version_info * ver) |
| 3092 | { |
| 3093 | #define OTA_MARVELL_VERSION_TAG "Marvell" |
| 3094 | #define OTA_MARVELL_VERSION_TAG_VER "Version" |
| 3095 | #define OTA_MARVELL_VERSION_TAG_URL "URL" |
| 3096 | #define OTA_MARVELL_VERSION_TAG_NOTE "ReleaseNote" |
| 3097 | struct xml_parse_context context = {0}; |
| 3098 | #define MAX_XML_VALUE_SIZE 4096 |
| 3099 | int ret = 0; |
| 3100 | |
| 3101 | if (string == NULL || ver == NULL) { |
| 3102 | OTA_ERR("Invalid parameters!\n"); |
| 3103 | return -1; |
| 3104 | } |
| 3105 | |
| 3106 | context.file = string; |
| 3107 | context.value = malloc(MAX_XML_VALUE_SIZE); |
| 3108 | if (context.value == NULL) { |
| 3109 | OTA_ERR("Malloc for context buffer failed!\n"); |
| 3110 | return -1; |
| 3111 | } |
| 3112 | context.value_size = MAX_XML_VALUE_SIZE; |
| 3113 | |
| 3114 | if (get_next_tag(&context) < 0) { |
| 3115 | OTA_ERR("Parse first tag failed!\n"); |
| 3116 | ret = -1; |
| 3117 | goto done; |
| 3118 | } |
| 3119 | if (strcmp(context.tag, OTA_MARVELL_VERSION_TAG)) { |
| 3120 | OTA_ERR("First tag is not %s\n", OTA_MARVELL_VERSION_TAG); |
| 3121 | ret = -1; |
| 3122 | goto done; |
| 3123 | } |
| 3124 | while (get_next_tag(&context) == 0) { |
| 3125 | if (get_next_value(&context) == 0) { |
| 3126 | if (!strcmp(context.tag, OTA_MARVELL_VERSION_TAG_VER)) { |
| 3127 | OTA_DEBUG("Handle version: %s\n", context.value); |
| 3128 | snprintf(ver->version, OTA_MAX_STRING_LEN, "%s", context.value); |
| 3129 | } else if (!strcmp(context.tag, OTA_MARVELL_VERSION_TAG_URL)) { |
| 3130 | OTA_DEBUG("Handle URL: %s\n", context.value); |
| 3131 | snprintf(ver->url, OTA_MAX_STRING_LEN, "%s", context.value); |
| 3132 | } else if (!strcmp(context.tag, OTA_MARVELL_VERSION_TAG_NOTE)) { |
| 3133 | OTA_DEBUG("Handle release note: %s\n", context.value); |
| 3134 | if (ver->release_note) { |
| 3135 | free(ver->release_note); |
| 3136 | ver->release_note = NULL; |
| 3137 | } |
| 3138 | ver->release_note = strdup(context.value); |
| 3139 | } |
| 3140 | } |
| 3141 | } |
| 3142 | done: |
| 3143 | if (context.value) { |
| 3144 | free(context.value); |
| 3145 | } |
| 3146 | return ret; |
| 3147 | } |
| 3148 | |
| 3149 | static int version_check_cb(char * data, int len, int num, void *cbdata) |
| 3150 | { |
| 3151 | struct version_check_context * context = (struct version_check_context *)cbdata; |
| 3152 | if ((context->size - context->used) < len) { |
| 3153 | char * buf = realloc(context->url, context->size + num); |
| 3154 | if (buf == NULL) { |
| 3155 | OTA_ERR("Memory issue at version_check_cb\n"); |
| 3156 | return -1; |
| 3157 | } |
| 3158 | context->size += num; |
| 3159 | context->url = buf; |
| 3160 | memcpy(context->url + context->used, data, len); |
| 3161 | context->used += len; |
| 3162 | } else { |
| 3163 | memcpy(context->url + context->used, data, len); |
| 3164 | context->used += len; |
| 3165 | } |
| 3166 | return 0; |
| 3167 | } |
| 3168 | struct version_check_context version_check_context = {0}; |
| 3169 | static int detect_new_version(struct ota_server * server, char ** firmwar_url) |
| 3170 | { |
| 3171 | struct http_client * client = NULL; |
| 3172 | struct http_client_list * header = NULL; |
| 3173 | int http_response_code = 0; |
| 3174 | int ret = -1; |
| 3175 | char buf[OTA_MAX_STRING_LEN + 30] = {0}; |
| 3176 | |
| 3177 | OTA_DEBUG("Try access %s for version check\n", server->server_url); |
| 3178 | |
| 3179 | client = http_client_init(); |
| 3180 | if (client == NULL) { |
| 3181 | OTA_ERR("HTTP client init failed!\n"); |
| 3182 | return -1; |
| 3183 | } |
| 3184 | |
| 3185 | version_check_context.url = malloc(OTA_MAX_STRING_LEN); |
| 3186 | if (version_check_context.url == NULL) { |
| 3187 | OTA_ERR("Malloc failed!\n"); |
| 3188 | goto done; |
| 3189 | } |
| 3190 | memset(version_check_context.url, 0, OTA_MAX_STRING_LEN); |
| 3191 | version_check_context.size = OTA_MAX_STRING_LEN; |
| 3192 | version_check_context.used = 0; |
| 3193 | |
| 3194 | http_client_setopt(client, HTTPCLIENT_OPT_URL, server->server_url); |
| 3195 | http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB, version_check_cb); |
| 3196 | http_client_setopt(client, HTTPCLIENT_OPT_METHOD, HTTPCLIENT_REQUEST_POST); |
| 3197 | http_client_setopt(client, HTTPCLIENT_OPT_RESPONSECB_DATA, &version_check_context); |
| 3198 | snprintf(buf, sizeof(buf), "MarvellOTA: version=%s\r\n", version_check_context.version); |
| 3199 | header = http_client_list_append(header, buf); |
| 3200 | http_client_setopt(client, HTTPCLIENT_OPT_HTTPHEADER, header); |
| 3201 | http_client_perform(client); |
| 3202 | http_client_getinfo(client, HTTPCLIENT_GETINFO_RESPONSE_CODE, &http_response_code); |
| 3203 | |
| 3204 | OTA_DEBUG("Version check result: %d\n", http_response_code); |
| 3205 | if (http_response_code == 200) { |
| 3206 | version_parse(version_check_context.url, &server_cfg.ver); |
| 3207 | OTA_DEBUG("Detected new version at: %s\n", server_cfg.ver.url); |
| 3208 | *firmwar_url = strdup(server_cfg.ver.url); |
| 3209 | } else { |
| 3210 | // Free memory |
| 3211 | // If http response is HTTP 200 OK, version checking caller should free this memory |
| 3212 | free(version_check_context.url); |
| 3213 | version_check_context.url = NULL; |
| 3214 | version_check_context.size = 0; |
| 3215 | version_check_context.used = 0; |
| 3216 | } |
| 3217 | ret = 0; |
| 3218 | done: |
| 3219 | if (client) http_client_shutdown(client); |
| 3220 | return ret; |
| 3221 | } |
| 3222 | |
| 3223 | enum { |
| 3224 | QUERY_TYPE, |
| 3225 | __QUERY_MAX |
| 3226 | }; |
| 3227 | |
| 3228 | static const struct blobmsg_policy query_policy[] = { |
| 3229 | [QUERY_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }, |
| 3230 | }; |
| 3231 | |
| 3232 | static int query_func(struct ubus_context *ctx, struct ubus_object *obj, |
| 3233 | struct ubus_request_data *req, const char *method, |
| 3234 | struct blob_attr *msg) |
| 3235 | { |
| 3236 | struct blob_attr *tb[__QUERY_MAX]; |
| 3237 | char * type = NULL; |
| 3238 | const char * string = NULL; |
| 3239 | |
| 3240 | OTA_DEBUG("enter: %s\n", __func__); |
| 3241 | blobmsg_parse(query_policy, ARRAY_SIZE(query_policy), tb, blob_data(msg), blob_len(msg)); |
| 3242 | |
| 3243 | if (tb[QUERY_TYPE]) type = blobmsg_data(tb[QUERY_TYPE]); |
| 3244 | if (type == NULL) { |
| 3245 | blob_buf_init(&b, 0); |
| 3246 | blobmsg_add_string(&b, "response", "failed"); |
| 3247 | ubus_send_reply(ctx, req, b.head); |
| 3248 | OTA_ERR("Failed query type\n"); |
| 3249 | return 0; |
| 3250 | } |
| 3251 | if (*type == '1') { |
| 3252 | // Download states |
| 3253 | switch (update_state) { |
| 3254 | case UPDATE_STATE_UPDATING: |
| 3255 | string = "updating"; |
| 3256 | break; |
| 3257 | case UPDATE_STATE_UPDATED: |
| 3258 | string = "success"; |
| 3259 | break; |
| 3260 | case UPDATE_STATE_FAILED: |
| 3261 | string = "failed"; |
| 3262 | break; |
| 3263 | case UPDATE_STATE_IDLE: |
| 3264 | default: |
| 3265 | string = "not start"; |
| 3266 | break; |
| 3267 | } |
| 3268 | blob_buf_init(&b, 0); |
| 3269 | blobmsg_add_string(&b, "response", string); |
| 3270 | ubus_send_reply(ctx, req, b.head); |
| 3271 | return 0; |
| 3272 | } else if (*type == '0' ) { |
| 3273 | // Query new version |
| 3274 | int len = strlen(server_cfg.ver.version); |
| 3275 | if (len != 0) { |
| 3276 | char * buf = malloc(len + 50); |
| 3277 | if (buf == NULL) { |
| 3278 | OTA_ERR("Malloc failed!\n"); |
| 3279 | blob_buf_init(&b, 0); |
| 3280 | blobmsg_add_string(&b, "response", "failed:memory issue"); |
| 3281 | ubus_send_reply(ctx, req, b.head); |
| 3282 | return 0; |
| 3283 | } |
| 3284 | memset(buf, 0, len + 30); |
| 3285 | sprintf(buf, "has new version:[%s]", server_cfg.ver.version); |
| 3286 | blob_buf_init(&b, 0); |
| 3287 | blobmsg_add_string(&b, "response", buf); |
| 3288 | ubus_send_reply(ctx, req, b.head); |
| 3289 | free(buf); |
| 3290 | buf = NULL; |
| 3291 | return 0; |
| 3292 | } else { |
| 3293 | blob_buf_init(&b, 0); |
| 3294 | blobmsg_add_string(&b, "response", "no new version"); |
| 3295 | ubus_send_reply(ctx, req, b.head); |
| 3296 | return 0; |
| 3297 | } |
| 3298 | } else { |
| 3299 | blob_buf_init(&b, 0); |
| 3300 | blobmsg_add_string(&b, "response", "unkonw"); |
| 3301 | ubus_send_reply(ctx, req, b.head); |
| 3302 | OTA_ERR("unkonw query type %s\n", type); |
| 3303 | return 0; |
| 3304 | } |
| 3305 | } |
| 3306 | |
| 3307 | static const struct ubus_method otad_method[] = { |
| 3308 | UBUS_METHOD("download", download_func, download_policy), |
| 3309 | UBUS_METHOD("query", query_func, query_policy), |
| 3310 | }; |
| 3311 | |
| 3312 | static struct ubus_object_type otad_object_type = UBUS_OBJECT_TYPE("ota", otad_method); |
| 3313 | |
| 3314 | static struct ubus_object ota_object = { |
| 3315 | .name = "ota", |
| 3316 | .type = &otad_object_type, |
| 3317 | .methods = otad_method, |
| 3318 | .n_methods = ARRAY_SIZE(otad_method), |
| 3319 | }; |
| 3320 | |
| 3321 | static void version_check(struct uloop_timeout *timeout); |
| 3322 | static struct uloop_timeout version_check_timer = { .cb = version_check }; |
| 3323 | |
| 3324 | |
| 3325 | static void version_check(struct uloop_timeout *timeout) |
| 3326 | { |
| 3327 | char * firmware = NULL; |
| 3328 | OTA_DEBUG("Try checking new version\n"); |
| 3329 | |
| 3330 | if (update_state == UPDATE_STATE_UPDATING) { |
| 3331 | OTA_ERR("Firmware updating... Reset timer.\n"); |
| 3332 | goto reset_timer; |
| 3333 | } else if (update_state == UPDATE_STATE_UPDATED) { |
| 3334 | OTA_ERR("Firmware already be updated, not need detect again\n"); |
| 3335 | return; |
| 3336 | } |
| 3337 | |
| 3338 | detect_new_version(&server_cfg, &firmware); |
| 3339 | if (firmware && strlen(firmware) && server_cfg.download_immediately != 0) { |
| 3340 | OTA_DEBUG("New firmware at: %s\n", firmware); |
| 3341 | do { |
| 3342 | unsigned int id; |
| 3343 | static struct ubus_request req; |
| 3344 | char firmare_url[OTA_MAX_STRING_LEN + 1] = {0}; |
| 3345 | snprintf(firmare_url, sizeof(firmare_url), "%s/%s", server_cfg.server_url, firmware); |
| 3346 | if (ubus_lookup_id(ctx, "ota", &id)) { |
| 3347 | OTA_ERR("Cannot found object...\n"); |
| 3348 | break; |
| 3349 | } |
| 3350 | blob_buf_init(&b, 0); |
| 3351 | blobmsg_add_string(&b, "url", firmare_url); |
| 3352 | blobmsg_add_string(&b, "username", "user name"); |
| 3353 | blobmsg_add_u32(&b, "type", 0); |
| 3354 | ubus_invoke_async(ctx, id, "download", b.head, &req); |
| 3355 | ubus_complete_request_async(ctx, &req); |
| 3356 | } while (0); |
| 3357 | free(firmware); |
| 3358 | firmware = NULL; |
| 3359 | if (update_state == UPDATE_STATE_UPDATED) { |
| 3360 | //1TODO: Post system reset for new image install |
| 3361 | OTA_DEBUG("Firmware download success, will post system reboot\n"); |
| 3362 | return; |
| 3363 | } else { |
| 3364 | uloop_timeout_set(&version_check_timer, server_cfg.interval * 2); |
| 3365 | } |
| 3366 | } |
| 3367 | reset_timer: |
| 3368 | uloop_timeout_set(&version_check_timer, server_cfg.interval * 1000); |
| 3369 | } |
| 3370 | |
| 3371 | static unsigned int get_mtd_offset(int mtd) |
| 3372 | { |
| 3373 | char file[64] = {0}; |
| 3374 | char content[32] = {0}; |
| 3375 | int fd; |
| 3376 | sprintf(file, "/sys/class/mtd/mtd%d/offset", mtd); |
| 3377 | fd = open(file, O_RDONLY); |
| 3378 | if (fd < 0) { |
| 3379 | OTA_ERR("%s: failed to open %s\n", __func__, file); |
| 3380 | return -1; |
| 3381 | } |
| 3382 | |
| 3383 | read(fd, content, 32); |
| 3384 | close(fd); |
| 3385 | return atoi(content); |
| 3386 | } |
| 3387 | |
| 3388 | #ifdef CONFIG_AB_SYSTEM |
| 3389 | #ifndef CONFIG_PARTITION_EMMC |
| 3390 | static int get_mtd_pagesize(int mtd, unsigned int *pagesize) |
| 3391 | { |
| 3392 | struct mtd_info_user mtdinfo; |
| 3393 | char dev[32]; |
| 3394 | int fd; |
| 3395 | |
| 3396 | memset(dev, 0, sizeof(dev)); |
| 3397 | sprintf(dev, "/dev/mtd%d", mtd); |
| 3398 | fd = open(dev, O_RDONLY); |
| 3399 | if (fd < 0) { |
| 3400 | OTA_ERR("%s: failed to open %s.\n", __func__, dev); |
| 3401 | return -1; |
| 3402 | } |
| 3403 | |
| 3404 | if (ioctl(fd, MEMGETINFO, &mtdinfo)) { |
| 3405 | OTA_ERR("%s: Could not get MTD device info from %s\n", __func__, dev); |
| 3406 | close(fd); |
| 3407 | return -1; |
| 3408 | } |
| 3409 | |
| 3410 | *pagesize = mtdinfo.writesize; |
| 3411 | OTA_DEBUG("%s: %s, pagesize: %d\n", __func__, dev, *pagesize); |
| 3412 | |
| 3413 | return 0; |
| 3414 | } |
| 3415 | #endif |
| 3416 | #endif |
| 3417 | |
| 3418 | static int init_cfg(const char * uci_path) |
| 3419 | { |
| 3420 | FILE * fp = NULL; |
| 3421 | #define MAX_LINE_SIZE 128 |
| 3422 | char buf[MAX_LINE_SIZE] = {0}; |
| 3423 | |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 3424 | #if 0 |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 3425 | /* |
| 3426 | ota.@ota[0]=ota |
| 3427 | ota.@ota[0].fbf_address='0x2A60000' |
| 3428 | ota.@ota[0].progress_notify='10' |
| 3429 | ota.@ota[0].interval='5' |
| 3430 | ota.@ota[0].first_interval='1' |
| 3431 | */ |
| 3432 | if (uci_path) { /* If UCI file exist parse it */ |
| 3433 | struct uci_context *uci_ctx = NULL; |
| 3434 | struct uci_package *p = NULL; |
| 3435 | struct uci_section *s = NULL; |
| 3436 | struct uci_element *e1 = NULL, *e2 = NULL; |
| 3437 | uci_ctx = uci_alloc_context(); |
| 3438 | if (uci_load(uci_ctx, uci_path, &p)) { |
| 3439 | OTA_ERR("uci load failed\n"); |
| 3440 | uci_free_context(uci_ctx); |
| 3441 | return -1; |
| 3442 | } |
| 3443 | |
| 3444 | uci_foreach_element(&p->sections, e1) { |
| 3445 | s = uci_to_section(e1); |
| 3446 | if (strcmp(s->type, "ota")) { |
| 3447 | continue; |
| 3448 | } |
| 3449 | |
| 3450 | uci_foreach_element(&s->options, e2) { |
| 3451 | if (!strcmp((uci_to_option(e2))->e.name, "server_url")) { |
| 3452 | OTA_DEBUG("OTA server URL: %s\n", (uci_to_option(e2))->v.string); |
| 3453 | snprintf(server_cfg.server_url, OTA_MAX_STRING_LEN, "%s", (uci_to_option(e2))->v.string); |
| 3454 | } else if (!strcmp((uci_to_option(e2))->e.name, "progress_nofity")) { |
| 3455 | OTA_DEBUG("Download notify interval: %s\n", (uci_to_option(e2))->v.string); |
| 3456 | sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.progress_notify); |
| 3457 | } else if (!strcmp((uci_to_option(e2))->e.name, "interval")) { |
| 3458 | OTA_DEBUG("Download version detect interval: %s\n", (uci_to_option(e2))->v.string); |
| 3459 | sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.interval); |
| 3460 | } else if (!strcmp((uci_to_option(e2))->e.name, "first_interval")) { |
| 3461 | OTA_DEBUG("Download first version detect interval: %s\n", (uci_to_option(e2))->v.string); |
| 3462 | sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.first_interval); |
| 3463 | } else if (!strcmp((uci_to_option(e2))->e.name, "download_immediately")) { |
| 3464 | OTA_DEBUG("Download firmware immediately: %s\n", (uci_to_option(e2))->v.string); |
| 3465 | sscanf((uci_to_option(e2))->v.string, "%d", &server_cfg.download_immediately); |
| 3466 | } |
| 3467 | } |
| 3468 | } |
| 3469 | |
| 3470 | uci_free_context(uci_ctx); |
| 3471 | uci_ctx = NULL; |
| 3472 | } |
| 3473 | #endif |
| 3474 | |
| 3475 | #ifdef CONFIG_PARTITION_EMMC |
| 3476 | fp = fopen("/proc/emmc", "r"); |
| 3477 | #else |
| 3478 | fp = fopen("/proc/mtd", "r"); |
| 3479 | #endif |
| 3480 | if (fp == NULL) { |
| 3481 | OTA_ERR("Open MTD failed!\n"); |
| 3482 | return -1; |
| 3483 | } |
| 3484 | |
| 3485 | #ifdef CONFIG_AB_SYSTEM |
| 3486 | server_cfg.mtd_cnt = 0; |
| 3487 | OTA_DEBUG("Start to retrive the mtd partition info...\n"); |
| 3488 | #ifdef CONFIG_PARTITION_EMMC |
| 3489 | server_cfg.emmc_block_size = 512; /* emmc */ |
| 3490 | server_cfg.block_size = 0x20000; /* only used for buffer cache size */ |
| 3491 | |
| 3492 | struct image_mtd_info *bootdev; |
| 3493 | /* the main bootloader */ |
| 3494 | bootdev = &server_cfg.image_mtd_info[0]; |
| 3495 | sprintf(bootdev->dev, "%s", "mmcblk1boot0"); |
| 3496 | sprintf(bootdev->name, "%s", "bootloader0"); |
| 3497 | bootdev->flag = SYSTEM_SINGLE; |
| 3498 | bootdev->flash_start_offset = 0; |
| 3499 | |
| 3500 | /* the backup bootloader */ |
| 3501 | bootdev = &server_cfg.image_mtd_info[1]; |
| 3502 | sprintf(bootdev->dev, "%s", "mmcblk1boot1"); |
| 3503 | sprintf(bootdev->name, "%s", "bootloader1"); |
| 3504 | bootdev->flag = SYSTEM_SINGLE; |
| 3505 | bootdev->flash_start_offset = 0; |
| 3506 | |
| 3507 | server_cfg.mtd_cnt = 2; |
| 3508 | #else |
| 3509 | server_cfg.block_size = 0x20000; /* nand flash */ |
| 3510 | if (get_mtd_pagesize(0, &server_cfg.pagesize) < 0) { |
| 3511 | fclose(fp); |
| 3512 | return -1; |
| 3513 | } |
| 3514 | #endif |
| 3515 | #endif |
| 3516 | |
| 3517 | /* |
| 3518 | root@OpenWrt:~# cat /proc/mtd |
| 3519 | dev: size erasesize name |
| 3520 | mtd0: 000a0000 00020000 "bootloader" |
| 3521 | mtd1: 00020000 00020000 "cp_reliabledata" |
| 3522 | mtd2: 00020000 00020000 "ap_reliabledata" |
| 3523 | mtd3: 00020000 00020000 "cp_reliabledata_backup" |
| 3524 | mtd4: 00020000 00020000 "ap_reliabledata_backup" |
| 3525 | mtd5: 00020000 00020000 "mep-ota" |
| 3526 | mtd6: 00020000 00020000 "mep-ota_backup" |
| 3527 | mtd7: 00100000 00020000 "asr_flag" |
| 3528 | mtd8: 00040000 00020000 "dtim-a" |
| 3529 | mtd9: 00040000 00020000 "dtim-b" |
| 3530 | mtd10: 00de0000 00020000 "cpimage-a" |
| 3531 | mtd11: 00de0000 00020000 "cpimage-b" |
| 3532 | mtd12: 000c0000 00020000 "u-boot-a" |
| 3533 | mtd13: 000c0000 00020000 "u-boot-b" |
| 3534 | mtd14: 00500000 00020000 "kernel-a" |
| 3535 | mtd15: 00500000 00020000 "kernel-b" |
| 3536 | mtd16: 00040000 00020000 "device_info" |
| 3537 | mtd17: 02800000 00020000 "OTA" |
| 3538 | mtd18: 00040000 00020000 "cust_info" |
| 3539 | mtd19: 00020000 00020000 "rootfs-a-sdtim" |
| 3540 | mtd20: 013e0000 00020000 "rootfs-a-mount" |
| 3541 | mtd21: 01400000 00020000 "rootfs-a" |
| 3542 | mtd22: 00020000 00020000 "rootfs-b-sdtim" |
| 3543 | mtd23: 013e0000 00020000 "rootfs-b-mount" |
| 3544 | mtd24: 01400000 00020000 "rootfs-b" |
| 3545 | mtd25: 00020000 00020000 "oem_data-a-sdtim" |
| 3546 | mtd26: 006e0000 00020000 "oem_data-a-mount" |
| 3547 | mtd27: 00700000 00020000 "oem_data-a" |
| 3548 | mtd28: 00020000 00020000 "oem_data-b-sdtim" |
| 3549 | mtd29: 006e0000 00020000 "oem_data-b-mount" |
| 3550 | mtd30: 00700000 00020000 "oem_data-b" |
| 3551 | mtd31: 01400000 00020000 "rootfs_data" |
| 3552 | mtd32: 05640000 00020000 "user_data" |
| 3553 | mtd33: 00d20000 00020000 "MRVL_BBM" |
| 3554 | */ |
| 3555 | while (fgets(buf, MAX_LINE_SIZE, fp) != NULL) { |
| 3556 | char name[200] = {0}; |
| 3557 | char size[200] = {0}; |
| 3558 | char erasesize[200] = {0}; |
| 3559 | char tag[64] = {0}; |
| 3560 | int cnt = 0; |
| 3561 | int index = 0; |
| 3562 | char * p = buf; |
| 3563 | #ifdef CONFIG_PARTITION_EMMC |
| 3564 | /* skip prev ' ' */ |
| 3565 | while ((index < (MAX_LINE_SIZE-1)) && (buf[index] == ' ')) |
| 3566 | index++; |
| 3567 | p = &buf[index]; |
| 3568 | #endif |
| 3569 | while ((index < (MAX_LINE_SIZE-1)) && (buf[index] != '\0')) { |
| 3570 | if (buf[index] == ' ') { |
| 3571 | buf[index] = '\0'; |
| 3572 | if (cnt == 0) { |
| 3573 | snprintf(name, sizeof(name), "%s", p); |
| 3574 | } else if (cnt == 1) { |
| 3575 | snprintf(size, sizeof(size), "%s", p); |
| 3576 | } else if (cnt == 2) { |
| 3577 | snprintf(erasesize, sizeof(erasesize), "%s", p); |
| 3578 | snprintf(tag, 64, "%s", &buf[index + 1]); |
| 3579 | break; |
| 3580 | } |
| 3581 | cnt++; |
| 3582 | p = &buf[index + 1]; |
| 3583 | } |
| 3584 | index++; |
| 3585 | } |
| 3586 | #ifdef CONFIG_AB_SYSTEM |
| 3587 | if (strncmp(name, "dev", 3) == 0) |
| 3588 | continue; |
| 3589 | /* retrive the mtd partition info */ |
| 3590 | struct image_mtd_info *pCurrentMtdInfo = &server_cfg.image_mtd_info[server_cfg.mtd_cnt]; |
| 3591 | int j = strlen(name); |
| 3592 | if (name[j - 1] == ':') |
| 3593 | name[j - 1] = '\0'; |
| 3594 | sprintf(pCurrentMtdInfo->dev, "%s", name); |
| 3595 | sprintf(pCurrentMtdInfo->name, "%s", tag); |
| 3596 | |
| 3597 | pCurrentMtdInfo->flag = SYSTEM_SINGLE; |
| 3598 | j = strlen(tag); |
| 3599 | /* the last tow chars for tag are "\n */ |
| 3600 | if (tag[j - 4] == '-') { |
| 3601 | if (tag[j - 3] == 'a') |
| 3602 | pCurrentMtdInfo->flag = SYSTEM_A; |
| 3603 | else if (tag[j - 3] == 'b') |
| 3604 | pCurrentMtdInfo->flag = SYSTEM_B; |
| 3605 | } |
| 3606 | |
| 3607 | /* remove the last \n */ |
| 3608 | pCurrentMtdInfo->name[strlen(pCurrentMtdInfo->name) - 1] = 0; |
| 3609 | |
| 3610 | sscanf(size, "%x", &pCurrentMtdInfo->size); |
| 3611 | sscanf(erasesize, "%x", &pCurrentMtdInfo->erasesize); |
| 3612 | |
| 3613 | #ifdef CONFIG_PARTITION_EMMC |
| 3614 | /* dev: size start name */ |
| 3615 | /* the "erasesize" field represent "start" block in emmc */ |
| 3616 | pCurrentMtdInfo->flash_start_offset = pCurrentMtdInfo->erasesize * server_cfg.emmc_block_size; |
| 3617 | pCurrentMtdInfo->size *= server_cfg.emmc_block_size; |
| 3618 | #else |
| 3619 | pCurrentMtdInfo->flash_start_offset = get_mtd_offset(server_cfg.mtd_cnt); |
| 3620 | #endif |
| 3621 | OTA_DEBUG(" Dev: %s, FlashOffset: 0x%x, Size: 0x%x, EraseSize: 0x%x, Name: %s\n", |
| 3622 | pCurrentMtdInfo->dev, pCurrentMtdInfo->flash_start_offset, pCurrentMtdInfo->size, |
| 3623 | pCurrentMtdInfo->erasesize, pCurrentMtdInfo->name); |
| 3624 | if (strstr(pCurrentMtdInfo->name, "asr_flag")) { |
| 3625 | int bln=0; |
| 3626 | #ifdef CONFIG_PARTITION_EMMC |
| 3627 | sscanf(name, "mmcblk1p%d", &bln); |
| 3628 | snprintf(server_cfg.mtd_asrflag, 64, "/dev/mmcblk1p%d", bln); |
| 3629 | #else |
| 3630 | sscanf(name, "mtd%d", &bln); |
| 3631 | snprintf(server_cfg.mtd_asrflag, 64, "/dev/mtdblock%d", bln); |
| 3632 | #endif |
| 3633 | } |
| 3634 | #ifdef CONFIG_AB_SYSTEM_DFOTA |
| 3635 | else if (strstr(pCurrentMtdInfo->name, "OTA")) { |
| 3636 | sscanf(size, "%x", &server_cfg.fbf_length); |
| 3637 | #ifndef CONFIG_PARTITION_EMMC |
| 3638 | sscanf(erasesize, "%x", &server_cfg.block_size); |
| 3639 | #endif |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 3640 | snprintf(server_cfg.mtd_fbf, 300, "/dev/%s", name); |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 3641 | server_cfg.fbf_addr = pCurrentMtdInfo->flash_start_offset; |
| 3642 | OTA_DEBUG("Get MTD info: 0x%x\n", server_cfg.fbf_addr); |
| 3643 | OTA_DEBUG(" name: %s\n", server_cfg.mtd_fbf); |
| 3644 | OTA_DEBUG(" size: %08x\n", server_cfg.fbf_length); |
| 3645 | OTA_DEBUG(" erasesize: %08x\n", server_cfg.block_size); |
| 3646 | OTA_DEBUG(" tag: %s\n", tag); |
| 3647 | } |
| 3648 | #endif |
| 3649 | server_cfg.mtd_cnt++; |
| 3650 | #else |
| 3651 | if (strncmp(tag, "\"asr_flag\"", 10) == 0) { |
| 3652 | int j = strlen(name); |
| 3653 | unsigned int asr_size; |
| 3654 | unsigned int asr_erasesize; |
| 3655 | sscanf(size, "%x", &asr_size); |
| 3656 | sscanf(erasesize, "%x", &asr_erasesize); |
| 3657 | if (name[j - 1] == ':') { |
| 3658 | name[j - 1] = '\0'; |
| 3659 | } |
| 3660 | int bln=0; |
| 3661 | sscanf(name, "mtd%d", &bln); |
| 3662 | //sprintf(asr_flag_path, "/dev/mtdblock%d", bln); |
| 3663 | |
| 3664 | snprintf(server_cfg.mtd_asrflag, 64, "/dev/mtdblock%d", bln); |
| 3665 | OTA_DEBUG("Get MTD info:\n"); |
| 3666 | OTA_DEBUG(" name: %s\n", name); |
| 3667 | OTA_DEBUG(" mtd_asrflag: %s\n", server_cfg.mtd_asrflag); |
| 3668 | OTA_DEBUG(" size: %08x\n", asr_size); |
| 3669 | OTA_DEBUG(" erasesize: %08x\n", asr_erasesize); |
| 3670 | OTA_DEBUG(" tag: %s\n", tag); |
| 3671 | }else if (strncmp(tag, "\"OTA\"", 5) == 0) { |
| 3672 | int j = strlen(name); |
| 3673 | sscanf(size, "%x", &server_cfg.fbf_length); |
| 3674 | sscanf(erasesize, "%x", &server_cfg.block_size); |
| 3675 | if (name[j - 1] == ':') { |
| 3676 | name[j - 1] = '\0'; |
| 3677 | } |
| 3678 | |
| 3679 | int bln=0; |
| 3680 | sscanf(name, "mtd%d", &bln); |
| 3681 | server_cfg.fbf_addr = get_mtd_offset(bln); |
b.liu | 4959615 | 2025-03-31 14:02:15 +0800 | [diff] [blame^] | 3682 | snprintf(server_cfg.mtd_fbf, 300, "/dev/%s", name); |
b.liu | a76c961 | 2025-03-28 13:58:09 +0800 | [diff] [blame] | 3683 | OTA_DEBUG("Get MTD info:\n"); |
| 3684 | OTA_DEBUG(" name: %s\n", server_cfg.mtd_fbf); |
| 3685 | OTA_DEBUG(" size: %08x\n", server_cfg.fbf_length); |
| 3686 | OTA_DEBUG(" erasesize: %08x\n", server_cfg.block_size); |
| 3687 | OTA_DEBUG(" tag: %s\n", tag); |
| 3688 | OTA_DEBUG(" fbf_addr: 0x%08x\n", server_cfg.fbf_addr); |
| 3689 | } |
| 3690 | #endif |
| 3691 | memset(buf, 0, MAX_LINE_SIZE); |
| 3692 | } |
| 3693 | fclose(fp); |
| 3694 | #ifdef CONFIG_AB_SYSTEM |
| 3695 | gInActiveSystem = get_inactive_system(); |
| 3696 | if (gInActiveSystem != SYSTEM_B && gInActiveSystem != SYSTEM_A) { |
| 3697 | OTA_ERR("FATAL ERROR, no legal inactive system flag exist..."); |
| 3698 | return -1; |
| 3699 | } |
| 3700 | OTA_DEBUG("Inactive System is %c...\n", gInActiveSystem); |
| 3701 | system_sync(); |
| 3702 | #endif |
| 3703 | return 0; |
| 3704 | } |
| 3705 | |
| 3706 | static int sync_mversion(void) |
| 3707 | { |
| 3708 | int ret = 0, i; |
| 3709 | int fd_asrflag, fd_mversion; |
| 3710 | int len_asrflag, len_mversion, len; |
| 3711 | char mversion[128]; |
| 3712 | struct tr069_firmware_flag AsrFlag; |
| 3713 | char *p_mversion; |
| 3714 | p_mversion = AsrFlag.mversion; |
| 3715 | |
| 3716 | #ifdef CONFIG_AB_SYSTEM |
| 3717 | if (gInActiveSystem == SYSTEM_A) |
| 3718 | p_mversion = AsrFlag.MVersion_B; |
| 3719 | #endif |
| 3720 | |
| 3721 | memset(mversion, 0, 128); |
| 3722 | |
| 3723 | fd_asrflag = open(server_cfg.mtd_asrflag, O_RDWR); |
| 3724 | if (fd_asrflag < 0) { |
| 3725 | OTA_ERR("Fatal error: can't open asr flag %s\n", server_cfg.mtd_asrflag); |
| 3726 | return -1; |
| 3727 | } |
| 3728 | |
| 3729 | len_asrflag = read(fd_asrflag, &AsrFlag, sizeof(AsrFlag)); |
| 3730 | if (len_asrflag != sizeof(AsrFlag)) { |
| 3731 | OTA_ERR("Fatal error: read %d bytes(expect %d)\n", len_asrflag, sizeof(AsrFlag)); |
| 3732 | close(fd_asrflag); |
| 3733 | return -1; |
| 3734 | } |
| 3735 | |
| 3736 | fd_mversion = open("/etc/mversion", O_RDWR); |
| 3737 | if (fd_mversion < 0) { |
| 3738 | OTA_ERR("Fatal error: can't open /etc/mversion\n"); |
| 3739 | close(fd_asrflag); |
| 3740 | return -1; |
| 3741 | } |
| 3742 | len_mversion = read(fd_mversion, mversion, 128); |
| 3743 | if(len_mversion <= 0) |
| 3744 | { |
| 3745 | OTA_ERR("Fatal error: read mversion\n"); |
| 3746 | ret = -1; |
| 3747 | goto sync_done; |
| 3748 | } |
| 3749 | |
| 3750 | for (i = len_mversion - 1; i >= 0; i--) |
| 3751 | { |
| 3752 | if(mversion[i] == '\n' || mversion[i] == '\r'){ |
| 3753 | len_mversion -- ; |
| 3754 | mversion[i] = 0; |
| 3755 | } |
| 3756 | else |
| 3757 | break; |
| 3758 | } |
| 3759 | |
| 3760 | if(p_mversion[0] == 0xFF || p_mversion[0] == 0x0) |
| 3761 | { |
| 3762 | OTA_ERR("There is no mversion in asr flag\n"); |
| 3763 | goto sync_done; |
| 3764 | } |
| 3765 | |
| 3766 | if(memcmp(mversion, p_mversion, len_mversion) != 0) |
| 3767 | { |
| 3768 | memset(mversion, 0, 128); |
| 3769 | strncpy(mversion, p_mversion, 128); |
| 3770 | mversion[127]=0; |
| 3771 | lseek(fd_mversion, 0, SEEK_SET); |
| 3772 | len = write(fd_mversion, mversion, 128); |
| 3773 | if (len != 128) { |
| 3774 | OTA_ERR("Fail to write mversion: write %d bytes(expected %d)\n", len, 128); |
| 3775 | ret = -1; |
| 3776 | } |
| 3777 | write(fd_mversion, "\n", 1); |
| 3778 | goto sync_done; |
| 3779 | } |
| 3780 | |
| 3781 | sync_done: |
| 3782 | close(fd_asrflag); |
| 3783 | close(fd_mversion); |
| 3784 | return ret; |
| 3785 | } |
| 3786 | |
| 3787 | int main(int argc, char **argv) |
| 3788 | { |
| 3789 | int ret; |
| 3790 | // char * uci_path = NULL; |
| 3791 | |
| 3792 | mbtk_log_init("radio", "MBTK_OTAD"); |
| 3793 | //set_service_log_tag("OTAD"); |
| 3794 | prctl(PR_SET_NAME, "otad"); |
| 3795 | |
| 3796 | #if 0 |
| 3797 | if (argc > 1) { /* UCI file exist */ |
| 3798 | #ifdef CONFIG_AB_SYSTEM |
| 3799 | if (strncmp(argv[1], "-f", 2) == 0) { |
| 3800 | switch (argc) { |
| 3801 | case 2: |
| 3802 | OTA_ERR("miss fota path.\n"); |
| 3803 | return -1; |
| 3804 | case 4: |
| 3805 | default: |
| 3806 | /* go through */ |
| 3807 | uci_path = argv[3]; |
| 3808 | OTA_DEBUG("OTA service start(%s)\n", uci_path); |
| 3809 | case 3: |
| 3810 | ret = get_fota_version(argv[2], server_cfg.fotav, 128); |
| 3811 | if (ret > 0) { |
| 3812 | OTA_ERR("get_fota_version failed, ret: %d\n", ret); |
| 3813 | return -1; |
| 3814 | } |
| 3815 | OTA_DEBUG("got fotav: %s\n", server_cfg.fotav); |
| 3816 | if (upgrade_precheck(server_cfg.fotav) < 0) |
| 3817 | return -1; |
| 3818 | break; |
| 3819 | } |
| 3820 | } else |
| 3821 | #endif |
| 3822 | { |
| 3823 | uci_path = argv[1]; |
| 3824 | OTA_DEBUG("OTA service start(%s)\n", uci_path); |
| 3825 | } |
| 3826 | } else { /* No UCI file - use default values */ |
| 3827 | OTA_DEBUG("OTA service start\n"); |
| 3828 | } |
| 3829 | #endif |
| 3830 | |
| 3831 | uloop_init(); |
| 3832 | ctx = ubus_connect(UBUS_UNIX_SOCKET); |
| 3833 | if (ctx == NULL) { |
| 3834 | OTA_ERR("Connect to UBUSD failed!\n"); |
| 3835 | ret = -1; |
| 3836 | goto done; |
| 3837 | } |
| 3838 | ubus_add_uloop(ctx); |
| 3839 | ret = ubus_add_object(ctx, &ota_object); |
| 3840 | |
| 3841 | memset(&server_cfg, 0, sizeof(server_cfg)); |
| 3842 | // ota |
| 3843 | init_cfg(NULL); |
| 3844 | #if !defined(CONFIG_AB_SYSTEM) || defined(CONFIG_AB_SYSTEM_DFOTA) |
| 3845 | if (server_cfg.fbf_length == 0 || server_cfg.block_size == 0) { |
| 3846 | OTA_ERR("Config file incorrect!\n"); |
| 3847 | return -1; |
| 3848 | } |
| 3849 | #endif |
| 3850 | if (server_cfg.progress_notify == 0) { |
| 3851 | server_cfg.progress_notify = 10; |
| 3852 | } |
| 3853 | if (server_cfg.interval == 0) { |
| 3854 | server_cfg.interval = 5; |
| 3855 | } |
| 3856 | if (server_cfg.first_interval == 0) { |
| 3857 | server_cfg.first_interval = 1; |
| 3858 | } |
| 3859 | if (server_cfg.fbf_addr == 0) { |
| 3860 | server_cfg.fbf_addr = 0x2a60000; |
| 3861 | } |
| 3862 | |
| 3863 | if (strlen(server_cfg.server_url) != 0) { |
| 3864 | int fd = open("/etc/mversion", O_RDONLY); |
| 3865 | if (fd < 0) { |
| 3866 | OTA_ERR("Read version failed!\n"); |
| 3867 | return -1; |
| 3868 | } |
| 3869 | read(fd, version_check_context.version, OTA_MAX_STRING_LEN); |
| 3870 | close(fd); |
| 3871 | uloop_timeout_set(&version_check_timer, 1000 * server_cfg.first_interval); |
| 3872 | } |
| 3873 | |
| 3874 | if(sync_mversion() != 0) |
| 3875 | OTA_ERR("Sync mversion error\n"); |
| 3876 | |
| 3877 | uloop_run(); |
| 3878 | done: |
| 3879 | |
| 3880 | return ret; |
| 3881 | } |
| 3882 | |