Add mbtk_otad

Change-Id: I472a8f3acdc6207a17800352bf7ce5e6fff167a9
diff --git a/mbtk/Makefile b/mbtk/Makefile
index c5926ef..20257fa 100755
--- a/mbtk/Makefile
+++ b/mbtk/Makefile
@@ -15,7 +15,7 @@
 DIRS += mbtk_rild mbtk_servicesd mbtk_sdk_ready
 endif
 
-DIRS += aboot-tiny mbtk_adbd mbtk_logd mbtk_utils mbtk_utils_linux mbtk_gnssd mbtk_rtpd
+DIRS += aboot-tiny mbtk_adbd mbtk_logd mbtk_utils mbtk_utils_linux mbtk_gnssd mbtk_rtpd mbtk_otad
 
 # Build test file.
 DIRS += test
diff --git a/mbtk/mbtk_otad/Makefile b/mbtk/mbtk_otad/Makefile
new file mode 100755
index 0000000..28ba357
--- /dev/null
+++ b/mbtk/mbtk_otad/Makefile
@@ -0,0 +1,40 @@
+BUILD_ROOT = $(shell pwd)/..
+include $(BUILD_ROOT)/Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/mbtk_otad
+
+INC_DIR += \
+		-I$(LOCAL_PATH)/inc
+
+LIB_DIR +=
+
+LIBS += -lmbtk_lib -lprop2uci -lubus -lubox -lutil -luci -lhttpclient
+
+# -Wno-error=unused-function
+CFLAGS +=
+
+DEFINE += -DCONFIG_AB_SYSTEM
+
+MY_FILES_PATH:=$(LOCAL_PATH)/src
+
+LOCAL_SRC_FILES = $(wildcard src/*.c) $(wildcard src/*.cpp)
+OBJS = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(LOCAL_SRC_FILES)))
+$(info OBJS = $(OBJS))
+
+dtarget := $(OUT_DIR)/bin/mbtk_otad
+
+all: $(dtarget)
+
+$(dtarget): $(OBJS)
+	@echo "  BIN     $@"
+	$(CC) $(CFLAGS) $(LIB_DIR) $(LIBS) $(OBJS) -o $@
+
+%.o:%.c
+	$(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+%.o:%.cpp
+	$(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+clean:
+	rm -f $(OBJS) $(dtarget)
+
diff --git a/mbtk/mbtk_otad/inc/getfotav.c b/mbtk/mbtk_otad/inc/getfotav.c
new file mode 100755
index 0000000..fb65265
--- /dev/null
+++ b/mbtk/mbtk_otad/inc/getfotav.c
@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <string.h>
+
+#define FOTA_FBFVERSION_IMAGEID	0x464F5456 //"FOTV"
+
+#if 0
+static int get_fota_version(const char *fname, char *mversion, size_t msize)
+{
+	FILE *fp;
+	int ret;
+	fp = fopen(fname, "rb");
+	if (fp == NULL)
+	{
+		perror("fopen");
+		return 1;
+	}
+	ret = 0;
+	do
+	{
+		int num_img;
+		size_t sz;
+		char buf[64];
+		sz = fread(buf, 1, 32, fp);
+		if (sz < 32 || strncmp(buf, "Marvell_FBF", 11)) /* check FBF magic */
+		{
+			ret = 2;
+			break;
+		}
+		sz = fread(buf, 1, 2, fp);
+		if (sz < 2 || buf[0] != 11 || buf[1] != 0) /* check format version */
+		{
+			ret = 3;
+			break;
+		}
+		ret = fseek(fp, 0x13C, SEEK_SET);
+		if (ret)
+		{
+			perror("fseek");
+			ret = 1;
+			break;
+		}
+		sz = fread(&num_img, 1, 4, fp);
+		if (sz < 4 || num_img <= 0) /* check number of images */
+		{
+			ret = 4;
+			break;
+		}
+		ret = 5; /* not found */
+		while (num_img--)
+		{
+			sz = fread(buf, 1, 52, fp);
+			if (sz < 52) /* check ImageStruct_11 size */
+			{
+				ret = 6;
+				break;
+			}
+			if (*(int *)buf == FOTA_FBFVERSION_IMAGEID) /* check image ID */
+			{
+				unsigned offset = ((int *)buf)[5];
+				offset <<= 13; /* 8KB sectors */
+				ret = fseek(fp, offset, SEEK_SET);
+				if (ret)
+				{
+					perror("fseek");
+					ret = 1;
+					break;
+				}
+				sz = fread(mversion, 1, msize, fp);
+				if (sz < msize || strnlen(mversion, sz) == sz) /* check ASCIIZ */
+				{
+					ret = 7;
+					break;
+				}
+				if (strncmp(mversion, "OTA", 3)) /* check prefix */
+				{
+					/* treat as successful */
+				}
+				else
+				{
+					char *p;
+					switch (mversion[3])
+					{
+						case '0': /* FOTA */
+							p = strchr(mversion, ';');
+							if (p)
+							{
+								sz = p - mversion - 4;
+								memmove(mversion, mversion + 4, sz);
+								mversion[sz] = '\0';
+							}
+							else
+							{
+								ret = 8;
+							}
+							break;
+						case '4': /* DFOTA */
+							p = strchr(mversion, ';');
+							if (p)
+							{
+								char *q = p + 1;
+								p = strchr(q, ';');
+								if (p)
+								{
+									sz = p - q;
+									memmove(mversion, q, sz);
+									mversion[sz] = '\0';
+								}
+								else
+								{
+									ret = 9;
+								}
+							}
+							else
+							{
+								ret = 8;
+							}
+							break;
+						default:
+							ret = 7;
+							break;
+					}
+				}
+				break;
+			}
+		}
+	} while (0);
+	fclose(fp);
+	return ret;
+}
+#endif
diff --git a/mbtk/mbtk_otad/inc/otad.h b/mbtk/mbtk_otad/inc/otad.h
new file mode 100755
index 0000000..b4f61e0
--- /dev/null
+++ b/mbtk/mbtk_otad/inc/otad.h
@@ -0,0 +1,23 @@
+#ifndef _OTAD_H_
+#define _OTAD_H_
+
+#include "mbtk_log.h"
+
+
+#define OTA_DEBUG LOGD
+#define OTA_ERR LOGE
+#define UBUS_UNIX_SOCKET "/var/run/ubus/ubus.sock"
+
+enum {
+	OTA_TYPE_HTTP,
+	OTA_TYPE_UDP,
+	OTA_TYPE_SD,
+};
+
+
+// Add by liubin
+void revision_out_find(char *data, int len, unsigned int processed_cnt);
+int revision_out_update();
+// End by liubin
+#endif
+
diff --git a/mbtk/mbtk_otad/inc/tim.c b/mbtk/mbtk_otad/inc/tim.c
new file mode 100755
index 0000000..b7c2ae5
--- /dev/null
+++ b/mbtk/mbtk_otad/inc/tim.c
@@ -0,0 +1,471 @@
+#include "tim.h"
+
+#define DTIM_MAX_SIZE	(128 * 1024)
+
+#if 0
+
+static const char *id2str(unsigned int id)
+{
+ 	switch (id) {
+	case IMAGE_ID_ARBEL:
+		return "ARBEL";
+	case IMAGE_ID_DTIM_A:
+		return "DTIM_A";
+	case IMAGE_ID_DTIM_B:
+		return "DTIM_B";
+	case IMAGE_ID_KERNEL:
+		return "KERNEL";
+	case IMAGE_ID_MSA:
+		return "MSA";
+	case IMAGE_ID_OEMD:
+		return "OEMD";
+	case IMAGE_ID_RF:
+		return "RF";
+	case IMAGE_ID_ROOTFS:
+		return "ROOTFS";
+	case IMAGE_ID_UBOOT:
+		return "UBOOT";
+	default:
+		OTA_ERR("Unkown id: 0x%x\n", id);
+		return "NULL";
+	}
+}
+#endif
+
+static int SetTIMPointers( void *pStartAddr, TIM *pTIM_h)
+{
+	pTIM_h->pConsTIM = (pCTIM) pStartAddr;	// Overlap Contant Part of TIM with actual TIM...
+
+	if ((pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER) ||
+	    (pTIM_h->pConsTIM->VersionBind.Version < TIM_3_2_00)) {
+		/* incorrect tim */
+		pTIM_h->pConsTIM = NULL;
+		return -1;
+	}
+
+	// Assign a pointer to start of Images Area
+	pTIM_h->pImg = (pIMAGE_INFO_3_4_0) (pStartAddr + sizeof (CTIM));
+
+	// Assign a pointer to start of Key Area
+	if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00)
+		pTIM_h->pKey = (pKEY_MOD_3_4_0) ((UINT_T)pTIM_h->pImg + ((pTIM_h->pConsTIM->NumImages) * sizeof (IMAGE_INFO_3_4_0)));
+	else
+		pTIM_h->pKey = (pKEY_MOD_3_4_0) ((UINT_T)pTIM_h->pImg + ((pTIM_h->pConsTIM->NumImages) * sizeof (IMAGE_INFO_3_2_0)));
+
+	// Assign a pointer to start of reserved area
+	if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00)
+		pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_4_0)));
+	else if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_3_00)
+		pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_3_0)));
+	else
+		pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_2_0)));
+
+	// Assign a pointer to start of DS
+	pTIM_h->pTBTIM_DS = (pPLAT_DS) ((UINT_T)pTIM_h->pReserved + pTIM_h->pConsTIM->SizeOfReserved);
+	return (NoError);
+}
+
+#if 0
+static void dump_dtim(pTIM t)
+{
+	int i;
+	pIMAGE_INFO_3_4_0 pImg;
+	OTA_DEBUG("### Image in dtim ###\n");
+	OTA_DEBUG("Images number: %d\n", t->pConsTIM->NumImages);
+	for (i = 0; i < t->pConsTIM->NumImages; i++) {
+		pImg = (pIMAGE_INFO_3_4_0)(t->pImg + i);
+		OTA_DEBUG("[%d] ID: %s, NextID: %s, Offset: 0x%x, "
+			"LoadAddr: 0x%x, Size: %d, SizeToHash: %d, HashAlgorithmID: 0x%x\n", i,
+			id2str(pImg->ImageID), id2str(pImg->NextImageID), pImg->FlashEntryAddr,
+			pImg->LoadAddr, pImg->ImageSize, pImg->ImageSizeToHash,
+			pImg->HashAlgorithmID);
+		OTA_DEBUG("[%d] Hash: 0x%x, 0x%x, 0x%x, 0x%x, "
+							 "0x%x, 0x%x, 0x%x, 0x%x, "
+							 "0x%x, 0x%x, 0x%x, 0x%x, "
+							 "0x%x, 0x%x, 0x%x, 0x%x\n", i,
+			pImg->Hash[0], pImg->Hash[1], pImg->Hash[2], pImg->Hash[3],
+			pImg->Hash[4], pImg->Hash[5], pImg->Hash[6], pImg->Hash[7],
+			pImg->Hash[8], pImg->Hash[9], pImg->Hash[10], pImg->Hash[11],
+			pImg->Hash[12], pImg->Hash[13], pImg->Hash[14], pImg->Hash[15]);
+	}
+}
+
+static void *load_dtim(const char *dev)
+{
+	int fd = -1;
+
+	char _dev[32] = {0};
+	char *buf = malloc(DTIM_MAX_SIZE);
+	if (!buf) {
+		OTA_ERR("failed to malloc 0x%x for dtim.\n", DTIM_MAX_SIZE);
+		goto out;
+	}
+
+	sprintf(_dev, "/dev/%s", dev);
+	fd = open(_dev, O_RDWR | O_SYNC);
+	if (fd < 0) {
+		OTA_ERR("failed to open %s.\n", _dev);
+		free(buf);
+		buf = NULL;
+		goto out;
+	}
+
+	if (complete_read(fd, buf, DTIM_MAX_SIZE) < 0) {
+		OTA_ERR("failed to load %s.\n", _dev);
+		free(buf);
+		buf = NULL;
+		goto out;
+	}
+
+out:
+	if (fd >= 0)
+		close(fd);
+	return buf;
+}
+
+static int __save_dtim(int fd, pTIM pTIM_h)
+{
+	int r = -1;
+	struct erase_info_user mtdEraseInfo;
+	struct mtd_info_user mtdInfo;
+
+	if (ioctl(fd, MEMGETINFO, &mtdInfo)) {
+		OTA_ERR("could not get MTD device info.\n");
+		goto out;
+	}
+	mtdEraseInfo.start = 0;
+	mtdEraseInfo.length = mtdInfo.erasesize;
+
+	ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+	ioctl(fd, MEMERASE, &mtdEraseInfo);
+
+	if (complete_write(fd, (char *)pTIM_h->pConsTIM, DTIM_MAX_SIZE) < 0)
+		goto out;
+
+	r = 0;
+out:
+	return r;
+}
+
+static int save_dtim(const char *dev, pTIM pTIM_h)
+{
+	int fd = -1;
+	int r = -1;
+	char _dev[32] = {0};
+	sprintf(_dev, "/dev/%s", dev);
+	fd = open(_dev, O_RDWR | O_SYNC);
+	if (fd < 0) {
+		OTA_ERR("failed to open %s.\n", _dev);
+		goto out;
+	}
+
+	r = __save_dtim(fd, pTIM_h);
+	if (r)
+		OTA_ERR("failed to save dtim to %s.\n", _dev);
+out:
+	if (fd >= 0)
+		close(fd);
+	return r;
+}
+
+/* sync the new to old */
+static int __sync_dtim(pTIM pNew, pTIM pOld)
+{
+	int r = -1, i, j, found = 0, images;
+	int flag = 0;
+	pIMAGE_INFO_3_4_0 pImgSrc, pImgDst;
+
+	OTA_DEBUG("%s: new dtim mode: %d, old dtim mode: %d.\n", __func__,
+		pNew->pConsTIM->VersionBind.Trusted, pOld->pConsTIM->VersionBind.Trusted);
+	if (pNew->pConsTIM->VersionBind.Trusted != pOld->pConsTIM->VersionBind.Trusted) {
+		OTA_ERR("%s: Fatal Error. Can't sync two different trust mode dtim.\n", __func__);
+		return -1;
+	}
+
+	for (i = 0; i < pNew->pConsTIM->NumImages; i++) {
+		pImgSrc = (pIMAGE_INFO_3_4_0)(pNew->pImg + i);
+		for (j = 0; j < pOld->pConsTIM->NumImages; j++) {
+			pImgDst = (pIMAGE_INFO_3_4_0)(pOld->pImg + j);
+			if (pImgSrc->ImageID == pImgDst->ImageID &&
+				pImgSrc->ImageID != IMAGE_ID_DTIM_A &&
+				pImgSrc->ImageID != IMAGE_ID_DTIM_B) {
+				found++;
+				if (pImgSrc->ImageSize != pImgDst->ImageSize ||
+					pImgSrc->ImageSizeToHash != pImgDst->ImageSizeToHash ||
+					pImgSrc->LoadAddr != pImgDst->LoadAddr ||
+					pImgSrc->HashAlgorithmID != pImgDst->HashAlgorithmID ||
+					memcmp(pImgSrc->Hash, pImgDst->Hash, sizeof(pImgSrc->Hash)) != 0)
+				{
+					OTA_DEBUG("Image: %s has been changed.\n", id2str(pImgSrc->ImageID));
+					pImgDst->ImageID = pImgSrc->ImageID;
+					pImgDst->ImageSize = pImgSrc->ImageSize;
+					pImgDst->ImageSizeToHash = pImgSrc->ImageSizeToHash;
+					pImgDst->LoadAddr = pImgSrc->LoadAddr;
+					pImgDst->HashAlgorithmID = pImgSrc->HashAlgorithmID;
+					memcpy(pImgDst->Hash, pImgSrc->Hash, sizeof(pImgSrc->Hash));
+					flag = 1;
+					break;
+				}
+			}
+		}
+	}
+
+	images = pNew->pConsTIM->NumImages - 1;
+	/* omit the first image(dtim it self) */
+	if (found != images) {
+		OTA_ERR("FATAL ERROR: NumImage: %d, found: %d, not exactly match.\n"
+				, pNew->pConsTIM->NumImages, found);
+		goto out;
+	}
+
+	r = flag;
+out:
+	return r;
+}
+
+static int update_dtim(const char *dev, void *bufNew)
+{
+	int r = -1;
+	TIM tNew, tOld;
+	char *buf = load_dtim(dev);
+
+	if (!buf) {
+		OTA_ERR("%s: failed to load dtim for %s.\n", __func__, dev);
+		goto out;
+	}
+
+	SetTIMPointers(buf, &tOld);
+	SetTIMPointers(bufNew, &tNew);
+
+	OTA_DEBUG("### Dump orignal dtim of %s. ###\n", dev);
+	dump_dtim(&tOld);
+	OTA_DEBUG("### Dump the new dtim. ###\n");
+	dump_dtim(&tNew);
+
+	r = __sync_dtim(&tNew, &tOld);
+	if (r < 0)
+		goto out;
+	if (r > 0) {
+		OTA_DEBUG("Images have been changed, update %s\n", dev);
+		r = save_dtim(dev, &tOld);
+	} else {
+		OTA_DEBUG("Images have NO change, DO NOT need to sync.\n");
+		r = 0;
+	}
+
+	OTA_DEBUG("%s: %s.\n", __func__, (r >= 0) ? "OK" : "FAILED");
+out:
+	if (buf)
+		free(buf);
+	return r;
+}
+
+static int sync_dtim(const char *src, const char *dst)
+{
+	int r = -1;//, i, j, found = 0;
+//	int flag = 0;
+//	pIMAGE_INFO_3_4_0 pImgSrc, pImgDst;
+	TIM tSrc;
+	TIM tDst;
+	char *bufSrc = load_dtim(src);
+	char *bufDst = load_dtim(dst);
+
+	OTA_DEBUG("Start to sync %s to %s.\n", src, dst);
+	if (!bufSrc || !bufDst) {
+		OTA_ERR("failed to sync %s to %s.\n", src, dst);
+		goto out;
+	}
+
+	SetTIMPointers(bufSrc, &tSrc);
+	SetTIMPointers(bufDst, &tDst);
+
+	OTA_DEBUG("Dump dtim info of %s.\n", src);
+	dump_dtim(&tSrc);
+	OTA_DEBUG("Dump dtim info of %s.\n", dst);
+	dump_dtim(&tDst);
+
+	if (tSrc.pConsTIM->NumImages != tDst.pConsTIM->NumImages) {
+		OTA_ERR("FATAL ERROR: NumImages(%s): %d, NumImages(%s): %d.\n",
+			src, tSrc.pConsTIM->NumImages, dst, tDst.pConsTIM->NumImages);
+		goto out;
+	}
+
+	r = __sync_dtim(&tSrc, &tDst);
+	if (r < 0)
+		goto out;
+	if (r > 0) {
+		OTA_DEBUG("Images have been changed, need to sync %s to %s.\n", src, dst);
+		r = save_dtim(dst, &tDst);
+	} else {
+		OTA_DEBUG("Images have NO change, DO NOT need to sync.\n");
+		r = 0;
+	}
+out:
+	if (bufSrc)
+		free(bufSrc);
+	if (bufDst)
+		free(bufDst);
+	return r;
+}
+
+/* dev is the mtd device of dtim */
+static int get_image_mode(const char *dev)
+{
+	char *buf = load_dtim(dev);
+	TIM tim;
+	int mode;
+
+	if (!buf) {
+		OTA_ERR("%s: failed to load dtim for %s.\n", __func__, dev);
+		return -1;
+	}
+
+	SetTIMPointers(buf, &tim);
+	mode = tim.pConsTIM->VersionBind.Trusted;
+	OTA_DEBUG("%s: it is %s mode(%s).\n", __func__, (mode == 1) ? "Trusted" : "NON-Trusted", dev);
+	free(buf);
+	return mode;
+}
+#endif
+
+static UINT_T CheckReserved (pTIM pTIM_h)
+{
+	pWTP_RESERVED_AREA pWRA	= (pWTP_RESERVED_AREA) pTIM_h->pReserved;
+
+	// Make sure that the TIM has a credible size
+	if(pTIM_h->pConsTIM->SizeOfReserved == 0)
+		return NotFoundError;
+
+	// Older TIM's had old reserved fields definition
+	if (pTIM_h->pConsTIM->VersionBind.Version == (0x00030101))
+		return NotFoundError;
+
+	// Was this area in reserved field created by a WTP compliant tool so we can parse?
+	if (pWRA->WTPTP_Reserved_Area_ID != WTPRESERVEDAREAID)
+		return NotFoundError;
+
+	return NoError;
+}
+
+// Finds a Package of WTP recognized information in the reserved area based on identifier
+static pWTP_RESERVED_AREA_HEADER FindPackageInReserved (UINT_T * Retval, pTIM pTIM_h, UINT_T Identifier)
+{
+	UINT_T Count = 0;
+	pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
+	pWTP_RESERVED_AREA pWRA	= (pWTP_RESERVED_AREA) pTIM_h->pReserved;
+
+	*Retval = CheckReserved(pTIM_h);
+	if (*Retval != NoError)
+		return NULL;
+
+	// Start from the begining
+	pWRAH = (pWTP_RESERVED_AREA_HEADER) (pWRA + 1);
+
+	while ((pWRAH->Identifier != Identifier) && (pWRAH->Identifier != TERMINATORID) && (Count < pWRA->NumReservedPackages))
+	{
+		pWRAH = (pWTP_RESERVED_AREA_HEADER)((UINT_T)pWRAH + ((pWRAH->Size + 3) & ~3)); // Skip to the next one
+		Count++;
+	}
+	if (pWRAH->Identifier != Identifier)
+	{
+		*Retval = NotFoundError;
+		pWRAH = NULL;
+	}
+
+	return pWRAH;
+}
+
+// This function has been added to support to isolate backwards compatibility to tim.c
+// It will return a point to pIMAGE_INFO based on TIM version.
+static pIMAGE_INFO_3_4_0 ReturnPImgPtr(pTIM pTIM_h, UINT_T ImageNumber)
+{
+	pIMAGE_INFO_3_4_0 pIMG;
+	pIMG = (pIMAGE_INFO_3_4_0) &pTIM_h->pImg[ImageNumber];
+	return pIMG;
+}
+
+// This function is used to find an image information field in the TIM
+// of the image with the ID passed in
+
+static pIMAGE_INFO_3_4_0 FindImageInTIM(pTIM pTIM_h, UINT_T ImageID)
+{
+	pIMAGE_INFO_3_4_0 pImageInfo = NULL;
+	UINT8_T i;
+
+	if (pTIM_h)
+	{
+		for( i = 0; i < pTIM_h->pConsTIM->NumImages; i++)
+		{
+			pImageInfo = ReturnPImgPtr(pTIM_h, i);
+			if(pImageInfo->ImageID == ImageID)
+				return pImageInfo;
+		}
+	}
+	return NULL;
+}
+
+static int __retrive_timh_by_ddrid(pTIM pTIM_h, unsigned int *DDR_ID, int *imagesize)
+{
+	int i, DDRTimIndex = -1;
+	UINT_T /*LoadAddr, TimSize, */TimLoadAddr, Retval;
+	pIMAGE_INFO_3_4_0 pTimInfo = NULL;
+	pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
+	pDDR_FLASH_MCP_PACKAGE pMCP = NULL;
+#if 0
+	if (DDR_ID == 0xFFFFFFFF || DDR_ID == 0) {
+		OTA_ERR("Warning: no valid DDR ID in ASR Flag\n");
+		return NoError;
+	}
+#endif
+	TimLoadAddr = (UINT_T)pTIM_h->pConsTIM;
+
+	pWRAH = FindPackageInReserved(&Retval, pTIM_h, DDR_FLASH_MCP_PACKAGE_ID);
+	if(pWRAH == NULL) {
+		OTA_ERR("No DFMP found, single DDR TIM\n\r");
+		return NoError;
+	} else {
+		pMCP = (DDR_FLASH_MCP_PACKAGE *) pWRAH;
+		for (i = 0; i < pMCP->NumberVendorDdrFlashSpec; i++) {
+			if(pMCP->ddrFlashSpec[i].VendorDdrPid == *DDR_ID) {
+				DDRTimIndex = i;
+				OTA_DEBUG("%s: [%d] got ddr id: 0x%x\n", __func__, i, *DDR_ID);
+				break;
+			}
+		}
+
+		pTimInfo = FindImageInTIM(pTIM_h, IMAGE_ID_TIMH);
+		if(pTimInfo == NULL) {
+			OTA_ERR("%s %d: No TIMH found, error\n", __func__, __LINE__);
+			return TIMNotFound;
+		}
+
+		if (DDRTimIndex < 0) {
+			OTA_ERR("NOT found ddr id: 0x%x, use the first TIM ddrid: 0x%x",
+				*DDR_ID, pMCP->ddrFlashSpec[0].VendorDdrPid);
+			*DDR_ID = pMCP->ddrFlashSpec[0].VendorDdrPid;
+			goto out;
+		}
+
+		/* go through all the TIMs to the right one */
+		for (i = 0; i < (DDRTimIndex + 1); i++) {
+			Retval = SetTIMPointers((void *)TimLoadAddr, pTIM_h);
+			if(Retval) {
+				OTA_ERR("%s %d: failed\n", __func__, __LINE__);
+				return TIMNotFound;
+			}
+
+			pTimInfo = FindImageInTIM(pTIM_h, IMAGE_ID_TIMH);
+			if(pTimInfo == NULL) {
+				OTA_ERR("%s %d: No TIMH found, error\n", __func__, __LINE__);
+				return TIMNotFound;
+			}
+			TimLoadAddr += pTimInfo->ImageSize;
+		}
+	}
+
+out:
+	*imagesize = pTimInfo->ImageSize;
+	OTA_DEBUG("%s: index: %d, size: 0x%x\n", __func__, DDRTimIndex, pTimInfo->ImageSize);
+	return NoError;
+}
+
diff --git a/mbtk/mbtk_otad/inc/tim.h b/mbtk/mbtk_otad/inc/tim.h
new file mode 100755
index 0000000..5cd20ec
--- /dev/null
+++ b/mbtk/mbtk_otad/inc/tim.h
@@ -0,0 +1,334 @@
+#ifndef __TIM_H__
+#define __TIM_H__
+
+enum {
+	IMAGE_ID_DTIM_A = 0x54494D31, /* dtim primary */
+	IMAGE_ID_DTIM_B = 0x54494d32, /* dtim recovery */
+	IMAGE_ID_UBOOT  = 0x4F534C4F,
+	IMAGE_ID_KERNEL = 0x5A494D47,
+	IMAGE_ID_ROOTFS = 0x5359534A,
+	IMAGE_ID_ARBEL  = 0x41524249,
+	IMAGE_ID_MSA	= 0x47524249,
+	IMAGE_ID_RF		= 0x52464249,
+	IMAGE_ID_OEMD	= 0x4F454D44,
+	IMAGE_ID_OBM	= 0x4f424d49,
+	IMAGE_ID_TIMH	= 0x54494d48,
+
+    // Add by liubin
+    IMAGE_ID_DEVICE	= 0x4F454D55,
+};
+
+#define TIMIDENTIFIER		0x54494D48		// "TIMH"
+// TIM Versions
+#define TIM_3_2_00			0x30200			// Support for Partitioning
+#define TIM_3_3_00			0x30300			// Support for ECDSA-256
+#define TIM_3_4_00			0x30400			// Support for ECDSA-521
+
+// Defined for DTIM support
+typedef enum
+{
+	TIMH_NOTINC				= 0,
+	TIMH_INC				= 1,
+	DTIM_PRIMARY_INC		= 2,
+	DTIM_RECOVERY_INC		= 3,
+	DTIM_CP_INC				= 4,
+	TIMH_RECOVERY_INC		= 5,
+	DTIM_PPSETTING_INC		= 6,
+	// 7-9 reserved
+	DTIM_CUSTMOZIEDTYPE1	= 10,
+	DTIM_CUSTMOZIEDTYPE2	= 11,
+	DTIM_CUSTMOZIEDTYPE3	= 12,
+	DTIM_CUSTMOZIEDTYPE4	= 13,
+	DTIM_CUSTMOZIEDTYPE5	= 14,
+	DTIM_CUSTMOZIEDTYPE6	= 15,
+	DTIM_CUSTMOZIEDTYPE7	= 16,
+	DTIM_CUSTMOZIEDTYPE8	= 17,
+	DTIM_CUSTMOZIEDTYPE9	= 18,
+	DTIM_CUSTMOZIEDTYPE10	= 19,
+	DTIM_CUSTMOZIEDTYPE11	= 20,
+	DTIM_CUSTMOZIEDTYPE12	= 21,
+	DTIM_CUSTMOZIEDTYPE13	= 22,
+	DTIM_CUSTMOZIEDTYPE14	= 23,
+	DTIM_CUSTMOZIEDTYPE15	= 24,
+	DTIM_CUSTMOZIEDTYPE16	= 25,
+	DTIM_CUSTMOZIEDTYPE17	= 26,
+	DTIM_CUSTMOZIEDTYPE18	= 27,
+	DTIM_CUSTMOZIEDTYPE19	= 28,
+	DTIM_CUSTMOZIEDTYPE20	= 29,
+
+	DTIM_CUSTMOZIED_MAX		= 50
+} TIMIncluded_Type;
+
+typedef unsigned int UINT_T, *PUINT;
+typedef unsigned char UINT8_T;
+
+typedef enum
+{
+	SHA160 = 0x00000014,   //20
+	SHA256 = 0x00000020,   //32
+	SHA512 = 0x00000040,   //64
+	DUMMY_HASH = 0x7FFFFFFF
+}
+HASHALGORITHMID_T;
+
+typedef struct
+{
+ UINT_T Version;
+ UINT_T	Identifier;					// "TIMH"
+ UINT_T Trusted;					// 1- Trusted, 0 Non
+ UINT_T IssueDate;
+ UINT_T OEMUniqueID;
+} VERSION_I, *pVERSION_I;			// 0x10 bytes
+
+typedef struct
+{
+ UINT_T WTMFlashSign;
+ UINT_T WTMEntryAddr;
+ UINT_T WTMEntryAddrBack;
+ UINT_T WTMPatchSign;
+ UINT_T WTMPatchAddr;
+ UINT_T BootFlashSign;
+} FLASH_I, *pFLASH_I;				// 0x10 bytes
+
+typedef struct
+{
+	UINT_T PartitionNumber	: 4;
+	UINT_T ImageType		: 8;
+	UINT_T Reserved			: 20;
+}TIM_INT;
+
+typedef union{
+	TIM_INT bits;
+	UINT_T value;
+}PN, *pPN;
+
+typedef struct
+{
+ UINT_T ImageID;					// Indicate which Image
+ UINT_T NextImageID;				// Indicate next image in the chain
+ UINT_T FlashEntryAddr;			 	// Block numbers for NAND
+ UINT_T LoadAddr;
+ UINT_T ImageSize;
+ UINT_T ImageSizeToHash;
+ HASHALGORITHMID_T HashAlgorithmID;            // See HASHALGORITHMID_T
+ UINT_T Hash[16];					// Reserve 512 bits for the hash
+ PN PartitionNumber;
+} IMAGE_INFO_3_4_0, *pIMAGE_INFO_3_4_0;			// 0x60 bytes
+
+typedef struct
+{
+ UINT_T ImageID;					// Indicate which Image
+ UINT_T NextImageID;				// Indicate next image in the chain
+ UINT_T FlashEntryAddr;			 	// Block numbers for NAND
+ UINT_T LoadAddr;
+ UINT_T ImageSize;
+ UINT_T ImageSizeToHash;
+ HASHALGORITHMID_T HashAlgorithmID;			// See HASHALGORITHMID_T
+ UINT_T Hash[8];					// Reserve 256 bits for the hash
+ UINT_T PartitionNumber;			// This is new for V3.2.0
+} IMAGE_INFO_3_2_0, *pIMAGE_INFO_3_2_0;			// 0x40 bytes
+
+// Constant part of the TIMs
+typedef struct
+{
+ VERSION_I      VersionBind;         			// 0
+ FLASH_I        FlashInfo;           			// 0x10
+ UINT_T         NumImages;           			// 0x20
+ UINT_T         NumKeys;						// 0x24
+ UINT_T         SizeOfReserved;					// 0x28
+} CTIM, *pCTIM;									// 0x2C
+
+// TIM structure for use by DKB/OBM/BootROM
+typedef struct
+{
+ pCTIM 				pConsTIM;			// Constant part
+ pIMAGE_INFO_3_4_0	pImg;				// Pointer to Images
+ void				*pKey;				// Pointer to Keys
+ PUINT				pReserved;			// Pointer to Reserved Area
+ void       		*pTBTIM_DS;			// Pointer to Digital Signature
+} TIM, *pTIM;
+
+/**
+ * General error code definitions			0x0 - 0x1F
+ **/
+#define NoError								0x0
+#define NotFoundError						0x1
+#define TIMNotFound							0x6D
+
+// WTP Format Recognized Reserved Area Indicator
+#define WTPRESERVEDAREAID	0x4F505448	  // "OPTH"
+
+// Reserved Area Package Headers
+#define TERMINATORID		0x5465726D		// "Term"
+
+/********** WTP Recognized Reserved Area Layout ********************************
+*
+*	WTPTP_Defined_Reserved_Format_ID	\	  This clues BR, OBM and DKB that the reserved area is in a known format
+*	Number of Reserved Area Packages	/	  For each package there is a header, payload size and payload
+*
+*	Header	 	 		\	  Indicates what type of a Reserved Area Package
+*	Size		  		 \	  Size Comprises a single Reserved Area Package
+*	Payload		  		 /	  There may be any number of Packages so long as TIM/NTIM < 4KB
+*			 			/
+*
+*	Header		 		\	  The Last one should be a Package with a Terminator Header
+*	Size		 		/	  The size should be 8 bytes (the size of this package)
+*
+**********************************************************************************/
+typedef struct
+{
+ UINT_T WTPTP_Reserved_Area_ID;	  	// This clues BR, OBM and DKB that the reserved area is in a known format
+ UINT_T	NumReservedPackages;	  	// For each package there is a header, payload size and payload
+}WTP_RESERVED_AREA, *pWTP_RESERVED_AREA;
+
+typedef struct
+{
+ UINT_T Identifier;					// Identification of this reserved area entry
+ UINT_T Size;						// Size  = Payload Size + 2 words (8 bytes).
+}WTP_RESERVED_AREA_HEADER, *pWTP_RESERVED_AREA_HEADER;
+
+#define DDR_FLASH_MCP_PACKAGE_ID  0X44464D50 // "DFMP"
+typedef struct
+{
+			unsigned int	 VendorDdrPid;
+			unsigned int	 FlashInfo; //for eMMC, FlashInfo is flash size, MB; for nand, FlashInfo is NandID
+} VendorDdrFlashSpec, *pVendorDdrFlashSpec;
+
+
+typedef struct
+{
+			WTP_RESERVED_AREA_HEADER WRAH;
+			unsigned int NumberVendorDdrFlashSpec;
+			VendorDdrFlashSpec  ddrFlashSpec[2];
+} DDR_FLASH_MCP_PACKAGE, *pDDR_FLASH_MCP_PACKAGE;
+
+#define MAXRSAKEYSIZEWORDS	 	64				// 2048 bits
+#define MAXECCKEYSIZEWORDS 		17				// 521 bits+
+
+typedef enum
+{
+	Marvell_DS =		0x00000000,
+	PKCS1_v1_5_Caddo =	0x00000001,
+	PKCS1_v2_1_Caddo =	0x00000002,
+	PKCS1_v1_5_Ippcp =	0x00000003,
+	PKCS1_v2_1_Ippcp =	0x00000004,
+	ECDSA_256 =			0x00000005,
+	ECDSA_521 =			0x00000006,
+	PKCS1_v2_2_Ippcp =	0x00000007,
+	DUMMY_ENALG = 0x7FFFFFFF   // See _Cryptographic_Scheme for additional id's
+}
+ENCRYPTALGORITHMID_T;
+
+typedef struct
+{
+ UINT_T	KeyID;						// Associate an ID with this key
+ HASHALGORITHMID_T HashAlgorithmID;	// See HASHALGORITHMID_T
+ UINT_T KeySize;					// Specified in bits
+ UINT_T PublicKeySize;				// Specified in bits
+ UINT_T RSAPublicExponent[MAXRSAKEYSIZEWORDS]; // Contents depend on PublicKeySize
+ UINT_T RSAModulus[MAXRSAKEYSIZEWORDS]; // Up to 2K bits
+ UINT_T KeyHash[8]; 				// Reserve 256 bits for the hash
+} KEY_MOD_3_2_0, *pKEY_MOD_3_2_0;				// 0x22C bytes
+
+typedef struct
+{
+ UINT_T KeyID;				// Associate an ID with this key
+ HASHALGORITHMID_T HashAlgorithmID;	 // See HASHALGORITHMID_T
+ UINT_T KeySize;			// Specified in bits
+ UINT_T PublicKeySize;		// Specified in bits
+ ENCRYPTALGORITHMID_T EncryptAlgorithmID;	// See ENCRYPTALGORITHMID_T;
+ union
+ {
+	struct
+	{
+ 		UINT_T RSAPublicExponent[MAXRSAKEYSIZEWORDS];	// Contents depend on PublicKeySize
+		UINT_T RSAModulus[MAXRSAKEYSIZEWORDS];			// Up to 2K bits
+	}Rsa;
+
+	struct
+	{
+		UINT_T PublicKeyCompX[MAXECCKEYSIZEWORDS]; // Contents depend on PublicKeySize
+		UINT_T PublicKeyCompY[MAXECCKEYSIZEWORDS]; // Up to 521 bits
+		// Pad this struct so it remains consistent with RSA struct
+		UINT_T Reserved[(2*MAXRSAKEYSIZEWORDS)-(2*MAXECCKEYSIZEWORDS)];
+	}Ecdsa;
+ };
+
+ UINT_T KeyHash[8]; 				// Reserve 256 bits for the hash
+} KEY_MOD_3_3_0, *pKEY_MOD_3_3_0;		//
+
+typedef struct
+{
+ UINT_T KeyID;				// Associate an ID with this key
+ HASHALGORITHMID_T HashAlgorithmID;	// See HASHALGORITHMID_T
+ UINT_T KeySize;			// Specified in bits
+ UINT_T PublicKeySize;		// Specified in bits
+ ENCRYPTALGORITHMID_T EncryptAlgorithmID; // See ENCRYPTALGORITHMID_T;
+ union
+ {
+	struct
+	{
+ 		UINT_T RSAPublicExponent[MAXRSAKEYSIZEWORDS];	// Contents depend on PublicKeySize
+		UINT_T RSAModulus[MAXRSAKEYSIZEWORDS];			// Up to 2K bits
+	}Rsa;
+
+	struct
+	{
+		UINT_T PublicKeyCompX[MAXECCKEYSIZEWORDS]; // Contents depend on PublicKeySize
+		UINT_T PublicKeyCompY[MAXECCKEYSIZEWORDS]; // Up to 521 bits
+		// Pad this struct so it remains consistent with RSA struct
+		UINT_T Reserved[(2*MAXRSAKEYSIZEWORDS)-(2*MAXECCKEYSIZEWORDS)];
+	}Ecdsa;
+
+	struct
+	{
+		UINT_T EncryptedHashRSAPublicExponent[MAXRSAKEYSIZEWORDS];  // Contents depend on PublicKeySize
+		UINT_T EncryptedHashRSAModulus[MAXRSAKEYSIZEWORDS];		 // Up to 2K bits
+	}EncryptedRsa;
+
+	struct
+	{
+		UINT_T EncryptedHashPublicKeyCompX_R[MAXECCKEYSIZEWORDS]; // Contents depend on PublicKeySize
+		UINT_T EncryptedHashPublicKeyCompX_S[MAXECCKEYSIZEWORDS]; // Contents depend on PublicKeySize
+
+		UINT_T EncryptedHashPublicKeyCompY_R[MAXECCKEYSIZEWORDS]; // Up to 521 bits
+		UINT_T EncryptedHashPublicKeyCompY_S[MAXECCKEYSIZEWORDS]; // Up to 521 bits
+
+		// Pad this struct so it remains consistent with encrypted RSA struct
+		UINT_T Reserved[(2 * MAXRSAKEYSIZEWORDS)-(4 * MAXECCKEYSIZEWORDS)];
+	}EncryptedEcdsa;
+ };
+
+ UINT_T KeyHash[16]; 				// Reserve 512 bits for the hash
+} KEY_MOD_3_4_0, *pKEY_MOD_3_4_0;		//
+
+
+typedef struct
+{
+ ENCRYPTALGORITHMID_T DSAlgorithmID;   // See ENCRYPTALGORITHMID_T
+ HASHALGORITHMID_T HashAlgorithmID; // See HASHALGORITHMID_T
+ UINT_T KeySize;			  // Specified in bits
+ UINT_T Hash[8];			  // Reserve 256 bits for optional key hash
+ union 	// Note that this union should not be included as part of the hash for TIM in the Digital Signature
+ {
+	struct
+	{
+		UINT_T RSAPublicExponent[MAXRSAKEYSIZEWORDS];
+		UINT_T RSAModulus[MAXRSAKEYSIZEWORDS];		   	// Up to 2K bits
+		UINT_T RSADigS[MAXRSAKEYSIZEWORDS];				// Contains TIM Hash
+	}Rsa;
+
+	struct
+	{
+		UINT_T ECDSAPublicKeyCompX[MAXECCKEYSIZEWORDS]; // Allow for 544 bits (17 words, 68 bytes for use with EC-521)
+		UINT_T ECDSAPublicKeyCompY[MAXECCKEYSIZEWORDS];
+		UINT_T ECDSADigS_R[MAXECCKEYSIZEWORDS];
+		UINT_T ECDSADigS_S[MAXECCKEYSIZEWORDS];
+		// Pad this struct so it remains consistent with RSA struct
+		UINT_T Reserved[(MAXRSAKEYSIZEWORDS*3)-(MAXECCKEYSIZEWORDS*4)];
+	} Ecdsa;
+ };
+} PLAT_DS, *pPLAT_DS;
+
+#endif
+
diff --git a/mbtk/mbtk_otad/src/mbtk_ota.c b/mbtk/mbtk_otad/src/mbtk_ota.c
new file mode 100755
index 0000000..9e49589
--- /dev/null
+++ b/mbtk/mbtk_otad/src/mbtk_ota.c
@@ -0,0 +1,235 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <mtd/mtd-user.h>
+
+#include "otad.h"
+#include "mbtk_type.h"
+#include "mbtk_device.h"
+
+typedef struct {
+    char name[32];
+    char dev[16];
+    uint32 partition_start;
+    uint32 partition_size;
+    uint32 erase_size;
+} partition_info_t;
+
+/*
+* revision_out start from 0x1000.
+*/
+#define REVISION_OUT_ADDR 0x1000
+
+char revision_out[48] = {0};
+static bool revision_out_found = FALSE;
+
+static int partition_get(char *partition_name, partition_info_t *info)
+{
+    FILE *fp = fopen("/proc/mtd", "r");
+    if(fp == NULL) {
+        OTA_ERR("fopen(/proc/mtd) fail:%d", errno);
+        return -1;
+    }
+
+    char buff[64];
+    char size_str[16];
+    char erase_size_str[16];
+    char name[32];
+    memset(buff, 0x0, sizeof(buff));
+    while(fgets(buff, sizeof(buff), fp)) {
+        if(strstr(buff, partition_name)) {
+            memset(size_str, 0x0, sizeof(size_str));
+            memset(erase_size_str, 0x0, sizeof(erase_size_str));
+            memset(name, 0x0, sizeof(name));
+            memcpy(info->dev, "/dev/", 5);
+            if(4 == sscanf(buff, "%s %s %s %s", info->dev + 5, size_str, erase_size_str, name)) {
+                if(name[0] == '\"' && name[strlen(name) - 1] == '\"') {
+                    memcpy(info->name, name + 1, strlen(name) - 2); // No copy ""
+                } else {
+                    OTA_ERR("partition(%s) name error.", buff);
+                    return -1;
+                }
+
+                if(info->dev[strlen(info->dev) - 1] == ':') {
+                    info->dev[strlen(info->dev) - 1] = '\0';
+                }
+
+                info->partition_size = (uint32)strtoul(size_str, NULL, 16);
+                info->erase_size = (uint32)strtoul(erase_size_str, NULL, 16);
+                //info->partition_start += info->partition_size;
+                break;
+            } else {
+                OTA_ERR("sscanf(%s) fail:%d", buff, errno);
+                return -1;
+            }
+        }
+        memset(buff, 0x0, sizeof(buff));
+    }
+    fclose(fp);
+
+    return 0;
+}
+
+
+void revision_out_find(char *data, int len, unsigned int processed_cnt)
+{
+    if(!revision_out_found) {
+        if(processed_cnt + len > REVISION_OUT_ADDR) { // µ½´ï 0x1000
+            char *start = NULL;
+            if(strlen(revision_out) > 0) {
+                start = data;
+            } else {
+                start = data + REVISION_OUT_ADDR - processed_cnt;
+            }
+
+            if(data[len - 1] == '\0') { // Last char is '\0',get the complete version.
+                if(strlen(start) > 0) {
+                    memcpy(revision_out + strlen(revision_out), start, strlen(start));
+                }
+                revision_out_found = TRUE;
+                OTA_DEBUG("Found complete version : %s", revision_out);
+            } else {
+                memcpy(revision_out + strlen(revision_out), start, data + len - start);
+                OTA_DEBUG("Found version : %s", revision_out);
+            }
+        }
+    }
+}
+
+int revision_out_update()
+{
+    if(strlen(revision_out) == 0) {
+        OTA_ERR("revision_out not set.");
+        revision_out_found = FALSE;
+        return -1;
+    }
+
+    partition_info_t info;
+    memset(&info, 0x0, sizeof(partition_info_t));
+    if(partition_get("device_info", &info)) {
+        OTA_ERR("partition_get() fail.");
+        return -1;
+    }
+
+    OTA_DEBUG("device_info name : %s, dev : %s, addr : %08x, size : %08x, erase_size : %08x", info.name,
+        info.dev, info.partition_start, info.partition_size, info.erase_size);
+
+    if(info.erase_size <= 0 || info.partition_size <= 0) {
+        OTA_ERR("partition info error.");
+        return -1;
+    }
+
+#if 0
+    int fd = open(dev, O_RDWR);
+    if (fd < 0) {
+        OTA_ERR("Fatal error: can't open device_info %s\n", dev);
+        return -1;
+    }
+
+    mbtk_device_info_header_t info_header;
+    memset(&info_header, 0x0, sizeof(mbtk_device_info_header_t));
+    int len = read(fd, &info_header, sizeof(mbtk_device_info_header_t));
+    if (len != sizeof(mbtk_device_info_header_t)) {
+        OTA_ERR("Fatal error: read %d bytes(expect %d)\n", len, sizeof(mbtk_device_info_header_t));
+        goto fail;
+    }
+
+    if(info_header.tag != MBTK_DEVICE_INFO_PARTITION_TAG) {
+        OTA_ERR("TAG error : %08x", info_header.tag);
+        goto fail;
+    }
+
+    if(info_header.version != MBTK_DEVICE_INFO_CURR_VERSION) {
+        OTA_ERR("Version error : %d", info_header.version);
+        goto fail;
+    }
+
+    if(info_header.item_header[MBTK_DEVICE_INFO_ITEM_BASIC].addr == 0) {
+        OTA_ERR("No found item : %d", MBTK_DEVICE_INFO_ITEM_BASIC);
+        goto fail;
+    }
+
+    lseek(fd, info_header.item_header[MBTK_DEVICE_INFO_ITEM_BASIC].addr, SEEK_SET);
+    mbtk_device_info_basic_t info_basic;
+    memset(&info_basic, 0, sizeof(mbtk_device_info_basic_t));
+    if (read(fd, &info_basic, sizeof(mbtk_device_info_basic_t)) != sizeof(mbtk_device_info_basic_t)) {
+        OTA_ERR("Read fail:%d", errno);
+        goto fail;
+    }
+
+    memset(info_basic.revision_out, 0, sizeof(info_basic.revision_out));
+    memcpy(info_basic.revision_out, revision_out, strlen(revision_out));
+
+    lseek(fd, info_header.item_header[MBTK_DEVICE_INFO_ITEM_BASIC].addr, SEEK_SET);
+    if (write(fd, &info_basic, sizeof(mbtk_device_info_basic_t)) != sizeof(mbtk_device_info_basic_t)) {
+        OTA_ERR("Write fail:%d", errno);
+        goto fail;
+    }
+#else
+    int fd = open(info.dev, O_RDWR);
+    if (fd < 0) {
+        OTA_ERR("Fatal error: can't open device_info %s\n", info.dev);
+        return -1;
+    }
+
+    char *mtd_buff = (char*)malloc(info.erase_size);
+    if(mtd_buff == NULL) {
+        OTA_ERR("malloc() failed\n");
+		return -1;
+    }
+    memset(mtd_buff, 0, info.erase_size);
+    int len = read(fd, mtd_buff, info.erase_size);
+    if (len != info.erase_size) {
+        OTA_ERR("Fatal error: read %d[%d] bytes(expect %d)\n", len, errno, info.erase_size);
+        goto fail;
+    }
+
+    struct erase_info_user mtdEraseInfo;
+	if (lseek(fd, 0, SEEK_SET) < 0)
+	{
+		OTA_ERR("seek failed\n");
+		return -1;
+	}
+
+	mtdEraseInfo.length = info.partition_size;
+	mtdEraseInfo.start = 0;
+	ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
+	ioctl(fd, MEMERASE, &mtdEraseInfo);
+
+    mbtk_device_info_header_t *info_header = (mbtk_device_info_header_t*)mtd_buff;
+    mbtk_device_info_basic_t *info_basic = (mbtk_device_info_basic_t*)(mtd_buff + info_header->item_header[MBTK_DEVICE_INFO_ITEM_BASIC].addr);
+    OTA_DEBUG("Old version : %s", info_basic->revision_out);
+    memset(info_basic->revision_out, 0, sizeof(info_basic->revision_out));
+    memcpy(info_basic->revision_out, revision_out, strlen(revision_out));
+
+    lseek(fd, 0, SEEK_SET);
+    if (write(fd, mtd_buff, info.erase_size) != info.erase_size) {
+        OTA_ERR("Write fail:%d", errno);
+        goto fail;
+    }
+
+    if(mtd_buff) {
+        free(mtd_buff);
+    }
+
+#endif
+
+    close(fd);
+
+    OTA_DEBUG("Set revision_out : %s", revision_out);
+
+    memset(revision_out, 0x0, sizeof(revision_out));
+    revision_out_found = FALSE;
+
+    return 0;
+
+fail:
+    close(fd);
+    return -1;
+}
diff --git a/mbtk/mbtk_otad/src/otad.c b/mbtk/mbtk_otad/src/otad.c
new file mode 100755
index 0000000..400c2b9
--- /dev/null
+++ b/mbtk/mbtk_otad/src/otad.c
@@ -0,0 +1,3879 @@
+#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;
+}
+