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