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