/*
* Copyright 1994, 1995, 2000 Neil Russell.
* (See License)
* Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
*/
#include "http_upgrade.h"
#include <command.h>
#include <net.h>
#include <asm/byteorder.h>
#include "lib_uip.h"
#include "rsaVerify.h"
#include "md5.h"
#include "malloc.h"
#include "uip_drv.h"
DECLARE_GLOBAL_DATA_PTR;
#ifdef CFG_EXTRA_FW
#define WORD_ALIGN(p) (((unsigned int)(p)+3)&~3)
typedef struct _FileBlockEntry
{
uint32_t blk_type;
uint32_t length;
}FileBlockEntry;
/*
* file block partition format is as this:
* file_block_header - block entries - file block 1 - file block 2 ...
*/
typedef struct file_block_header
{
uint32_t nBlk;
FileBlockEntry BlkEntries[1];
}file_block_header_t;
#endif
#ifndef UIP_FLASH_BASE
#define UIP_FLASH_BASE CFG_FLASH_BASE
#endif
#ifndef UIP_FLASH_SIZE
#define UIP_FLASH_SIZE CFG_FLASH_SIZE
#endif
#define MD5SUM_LEN 16
#define HW_ID_LEN 16
#define FW_ID_LEN 16
#define FINFO_DEVNAME_LEN 64
#define FINFO_HWVER_LEN 21
#define FACTORY_INFO_MAC_KEY "mac:"
#define FACTORY_INFO_HWID_KEY "hwId:"
#define FACTORY_INFO_FWID_KEY "RcvrfwId:"
#define FACTORY_INFO_DEV_NAME_KEY "devName:"
#define FACTORY_INFO_HW_VER_KEY "hwVer:"
/* Vendor Id's. */
#define VENDOR_ID_TP 0x00
#define VENDOR_ID_MECURY 0x01
#define VENDOR_ID_FAST 0x02
#define VENDOR_ID_PROWARE 0x35
/* RSA public Keys. */
char publicKeyTP[] = "BgIAAACkAABSU0ExAAQAAAEAAQA1Ccyu85b65TawjvSQTaryGNk1gBJVn6kEIJq6m0hagsqkiy32v4ui41ucp6tKfaoqb7AHDBq41dcEMgM6YBF2e3aRKQqZ6EwgCvAi3O81n7UbE97lD+FhvqlYxyqqMbSdvNmCiAoujheUs9DUaOCHq4K3McDxATMVOnCtT1H+wQ==";
char publicKeyMercury[] = "BgIAAACkAABSU0ExAAQAAAEAAQD7Bk7f7fdnL9drucbr+P9wA2JUlYP/OH4zvIS69eY3KKmUB1fs9ND06EINqTQ4vQ4gCeekU1dRi3WiZLgVjo/UzovplddUezNMWq0gk4TVbsGf/xzXZN+pDWid9zYsSr9qvINId6cnMR+s/wXB1TOE6t6wfzHvnbkJR0r1mqG4yA==";
char publicKeyFast[] = "BgIAAACkAABSU0ExAAQAAAEAAQAHNt5fFl0BUlLkPjKJloZFlVFkegFjEsVJCRjwbRD6i646tpvc/Z5MK6SuXcz3yizxDGMnZ6BJdqCR9SJTdd3b11F7Q+pgetcAgX5X9NZTzo1MCvpkKAlEyZG0rXMpSbADNNqtACNT0BLhHu4nyiDBBIIOSZljQAzHiqSquxHDsg==";
char publicKeyProware[] = "BgIAAACkAABSU0ExAAQAAAEAAQArjNXuvBeCGfOD19AGJGmceW+ip5W76C+sOHk0bJgrtZhk+t/ZzZwAv/TLA+MwNipNZSd+fOysmqDsA53cEIKdzor0WbWGq0n/BYr1o8fh4Pm656mOn9C6LH6nCf6w48Nog84Pc+NuwHcB93p6Wj0y3YVl8sGn+eeokA8ltZzLnA==";
/* Firmware information structure. */
typedef struct _FW_INFO
{
unsigned char* buf;
int size;
int uhTagLength;
int local_fw_size;
}FW_INFO;
static FW_INFO fw_info = {0};
/* Local uboot infomation structure. */
typedef struct _LOCAL_INFO /* 保存本地设备信息(如 MAC、HwID、FwID、设备型号等) */
{
uint8_t hwID[HW_ID_LEN];
uint8_t fwID[FW_ID_LEN];
uint8_t mac[6];
#ifdef UNIFY_FIRMWARE
uint8_t device_model[FINFO_DEVNAME_LEN];
uint8_t hw_version[FINFO_HWVER_LEN];
#endif
} LOCAL_INFO;
static LOCAL_INFO localInfo = {{0}};
/* define tp header */
#define TP_HEADER_VERSION 0x00000100
#define MAGIC_LEN 20
#define CRC_LEN 16
#define FW_DESC_LEN 12
#define PARTITION_NUMBER 9
typedef struct _TP_HEADER /* 定义了固件的头部信息,包括各分区的偏移、长度、CRC 值等。 */
{
unsigned int headerVersion;
unsigned char magicNumber[MAGIC_LEN];
unsigned int kernelLoadAddress;
unsigned int kernelEntryPoint;
unsigned short vendorId;
unsigned short zoneCode;
unsigned int partitionNum;
unsigned int factoryBootOffset;
unsigned int factoryBootLen;
unsigned int factoryInfoOffset; /* 出厂信息分区 */
unsigned int factoryInfoLen;
unsigned int radioOffset;
unsigned int radioLen;
unsigned int ucOffset;
unsigned int ucLen;
unsigned int bootloaderOffset;
unsigned int bootloaderLen;
unsigned int tpHeaderOffset;
unsigned int tpHeaderLen;
unsigned int kernelOffset; /* 内核分区 */
unsigned int kernelLen; /* 和长度 */
unsigned int romFsOffset; /* ROM 文件系统分区 */
unsigned int romFsLen;
unsigned int jffs2FsOffset;
unsigned int jffs2FsLen;
unsigned char factoryInfoCRC[CRC_LEN];
unsigned char radioCRC[CRC_LEN];
unsigned char ubootCRC[CRC_LEN];
unsigned char kernelAndRomfsCRC[CRC_LEN];
unsigned char fwId[FW_ID_LEN];
unsigned char fwDescription[FW_DESC_LEN];
unsigned int fwIdBLNum;
unsigned char fwIdBL[0][FW_ID_LEN];
} TP_HEADER;
/* content type flags. */
#define CONTENT_TYPE_BOOTLOADER 0x0001
#define CONTENT_TYPE_KERNEL 0x0002
#define CONTENT_TYPE_ROMFS 0x0004
#define CONTENT_TYPE_JFFS2FS 0x0008
#define CONTENT_TYPE_ISP_CONFIG 0x0010
/* partition type flags. */
#define PARTITION_TYPE_BOOTLOADER CONTENT_TYPE_BOOTLOADER
#define PARTITION_TYPE_KERNEL CONTENT_TYPE_KERNEL
#define PARTITION_TYPE_FACTORY_INFO 0x0100
#define PARTITION_TYPE_RADIO_DATA 0x0200
/* firmware bin contents */
#define PARTS_UP_BOOT (CONTENT_TYPE_BOOTLOADER | CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS | CONTENT_TYPE_JFFS2FS)
#define PARTS_UP (CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS | CONTENT_TYPE_JFFS2FS)
#define PARTS_UP_BOOT_NOJFS (CONTENT_TYPE_BOOTLOADER | CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS)
#define PARTS_UP_NOJFS (CONTENT_TYPE_KERNEL | CONTENT_TYPE_ROMFS)
/* define upgrade header */
#define UPGRADE_HEADER_VERSION 0x00000100
#define UPGRADE_HEADER_LEN 512
#define UPGRADE_HEADER_LEN_WIDE (2 * UPGRADE_HEADER_LEN)
#define RSA_SIGN_LEN 128
#define FWID_FL_MASK_LEN 12
#define HW_ID_LEN 16
typedef struct _UPGRADE_HEADER /* 用于固件升级时的头部信息,包含签名、厂商 ID、硬件支持列表等。 */
{
unsigned int headerVersion;
unsigned char magicNumber[MAGIC_LEN];
unsigned short tagLength;
unsigned short vendorId;
unsigned short zoneCode;
unsigned short contentTypes;
unsigned char rsaSignature[RSA_SIGN_LEN];
unsigned short hwIdNum;
unsigned short fwIdFLNum;
unsigned char fwIdFLMask[FWID_FL_MASK_LEN];
unsigned char hwIdList[0][HW_ID_LEN];
// unsigned char fwIdFL[0][FW_ID_LEN];
} UPGRADE_HEADER;
/* Allowed recovery FwID */
const char RECOVERY_FW_ID[FW_ID_LEN] = {WEBFAILSAFE_FW_ID}; /* 定义恢复模式下的固件 ID。 */
/* 恢复模式(Recovery Mode) 是嵌入式设备(如路由器、智能设备)在启动失败、
固件损坏或用户主动进入时的一种特殊运行状态。它提供一个最小化的系统环境,用于修复或重新安装主系统固件。*/
#ifdef UNIFY_FIRMWARE
static unsigned char blockHdrMagicNumber[] = {0x12, 0x34, 0x56, 0x78};
/* Magic Number 是一个特殊的字节序列,用于识别数据结构是否合法;
*这里用于判断固件中是否包含有效的扩展固件块。*/
/* 声明两个用于处理 ISP 配置的函数。
checkFirmwareIsp:校验 ISP 配置是否适用于当前设备;
upgradeFirmwareIsp:将 ISP 配置写入 Flash。*/
static int checkFirmwareIsp(BLOCK_HEADER* blockHdr, void* thisHandler);
static int upgradeFirmwareIsp(EXT_FW_HEADER* block);
static EXT_FW_BLOCK_HANDLER blockHdrTbl[] = /* 定义扩展固件块的处理表,用于匹配和处理不同类型的扩展固件内容。*/
{
{
CONTENT_TYPE_ISP_CONFIG,
EXT_FW_CHANGED,
NULL,
checkFirmwareIsp,
upgradeFirmwareIsp
},
{
0,
0,
NULL,
NULL,
NULL
}
};
#endif
void get_eth_addr(uint8_t* addr) /* 获取设备的以太网(MAC)地址。 */
{
memcpy(addr, localInfo.mac, 6);
}
/*
* Function Name: localInfoInit
* Author: CaiBin
* Date: 2014-11-07
* Description: Initialize local firmware information(currently only HwID).
* Parameter:
* VOID
* return:
* 0: Succeeded;
* ERR_GENERIC: No HwID found.
* ERR_READ_FLASH: Read command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
*/
static int localInfoInit(void) /* 初始化 localInfo 结构体变量,从 Flash 中读取出厂信息并填充到该结构体中。 */
{
int ret = 0;
uint8_t *buf = NULL;
uint8_t *p = NULL;
memset(&localInfo, 0, sizeof(localInfo));
memcpy(localInfo.fwID, RECOVERY_FW_ID, FW_ID_LEN);/* RECOVERY_FW_ID(恢复模式下的固件 ID)复制到 localInfo.fwID 中; */
buf = (uint8_t*)malloc(FACTORY_INFO_LEN);
if (!buf)
{
ERR("malloc failed.");
ret = ERR_MEMORY_ALLOC;
goto out;
}
ret = readFlash(FACTORY_INFO_OFFSET, buf, FACTORY_INFO_LEN);/* 从 Flash 的偏移地址 FACTORY_INFO_OFFSET 处读取长度为 FACTORY_INFO_LEN 的数据,存入 buf; */
if (ret < 0)
{
ERR("read flash failed.");
goto out_free_buf;
}
#ifdef RECOVERY_UPGRADE_UNIT_TEST
{
int i;
DBG_UNIT("content:");
for (i=0, p = buf; i < FACTORY_INFO_LEN; p++, i++)
{
if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9'))
{
printf("%c ", *p);
}
else
{
printf("%02X ", (int)*p);
}
}
printf("\n");
}
#endif
//read mac address
p = (uint8_t *)memmem(buf, FACTORY_INFO_LEN, FACTORY_INFO_MAC_KEY, strlen(FACTORY_INFO_MAC_KEY)); /* 使用 memmem 函数在 buf 缓冲区中查找一段特定字符串 FACTORY_INFO_MAC_KEY; */
if (NULL == p)
{
ERR("no mac address found");
ret = ERR_HWID_NOT_FOUND;
goto out_free_buf;
}
DBG_UNIT("find offset:%d", p-buf);
memcpy(localInfo.mac, p + strlen(FACTORY_INFO_MAC_KEY), 6);
//read hwID
p = (uint8_t *)memmem(buf, FACTORY_INFO_LEN, FACTORY_INFO_HWID_KEY, strlen(FACTORY_INFO_HWID_KEY));
if (NULL == p)
{
ERR("no HwID found");
ret = ERR_HWID_NOT_FOUND;
goto out_free_buf;
}
DBG_UNIT("find offset:%d", p-buf);
memcpy(localInfo.hwID, p + strlen(FACTORY_INFO_HWID_KEY), HW_ID_LEN);
//read fwID
#ifdef FETCH_FW_ID_FROM_FACTORY_INFO
p = (uint8_t *)memmem(buf, FACTORY_INFO_LEN, FACTORY_INFO_FWID_KEY, strlen(FACTORY_INFO_FWID_KEY));
if (NULL == p)
{
ERR("no FwID found");
ret = ERR_FWID_NOT_FOUND;
goto out_free_buf;
}
DBG_UNIT("find offset:%d", p-buf);
memcpy(localInfo.fwID, p + strlen(FACTORY_INFO_FWID_KEY), FW_ID_LEN);
#endif
#ifdef UNIFY_FIRMWARE
//read device_model
p = (uint8_t *)memmem(buf, FACTORY_INFO_LEN, FACTORY_INFO_DEV_NAME_KEY, strlen(FACTORY_INFO_DEV_NAME_KEY));
if (NULL == p || strlen(FACTORY_INFO_DEV_NAME_KEY) == strlen(p))
{
ERR("no device_model found");
ret = ERR_DEV_NAME_NOT_FOUND;
goto out_free_buf;
}
memcpy(localInfo.device_model, p + strlen(FACTORY_INFO_DEV_NAME_KEY), strlen(p) - strlen(FACTORY_INFO_DEV_NAME_KEY));
DBG_UNIT("localInfo.device_model: %s", localInfo.device_model);
//read hw_version
p = (uint8_t *)memmem(buf, FACTORY_INFO_LEN, FACTORY_INFO_HW_VER_KEY, strlen(FACTORY_INFO_HW_VER_KEY));
if (NULL == p|| strlen(FACTORY_INFO_HW_VER_KEY) == strlen(p))
{
ERR("no hw_version found");
ret = ERR_HW_VER_NOT_FOUND;
goto out_free_buf;
}
memcpy(localInfo.hw_version, p + strlen(FACTORY_INFO_HW_VER_KEY), strlen(p) - strlen(FACTORY_INFO_HW_VER_KEY));
DBG_UNIT("localInfo.hw_version: %s", localInfo.hw_version);
#endif
#ifdef RECOVERY_UPGRADE_UNIT_TEST
{
int i;
DBG_UNIT("got MAC:");
for(i=0; i<6; i++)
{
printf("%02X ",localInfo.mac[i]);
}
printf("\n");
DBG_UNIT("got hwID:");
for(i=0; i<HW_ID_LEN; i++)
{
printf("%02X ",localInfo.hwID[i]);
}
printf("\n");
DBG_UNIT("got fwID:");
for(i=0; i<FW_ID_LEN; i++)
{
printf("%02X ",localInfo.fwID[i]);
}
printf("\n");
}
#endif
out_free_buf:
free(buf);
out:
return ret;
}
/*
* Function Name: check_file_size
* Author: CaiBin
* Date: 2014-11-07
* Description: Check if firmware has valid size.
* Parameter:
* size: Size of the firmware in bytes.
* return:
* 0: Succeeded;
* ERR_INCORRECT_FILE_SIZE: File size is incorrect.
*/
static int check_file_size(ulong size) /* 检查固件文件大小是否符合预期范围 */
{
#ifdef UNIFY_FIRMWARE
if (size < BOOTLOADER_LEN)
#else
if ((size < BOOTLOADER_LEN) || (size > CFG_FLASH_SIZE))
#endif
{
ERR("data size check failed.");
return ERR_INCORRECT_FILE_SIZE;
}
return 0;
}
/*
* Function Name: calcMd5
* Author: CaiBin
* Date: 2014-11-07
* Description: Compute MD5 checksum.
* Parameter:
* data: Source data .
* size: Source data length.
* md5: return the result md5 value.
* return:
* VOID
*/
static void calcMd5(char *data, int size, char *md5) /* 计算MD5校验和。 */
{
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, data, size);
MD5_Final(md5, &ctx);
}
/*
* Function Name: checkFirmwareRSA
* Author: CaiBin
* Date: 2014-11-07
* Description: Check RSA signature of the upgrading firmware.
* Parameter:
* uHeader: Points to the upgrade header of the firmware.
* info: Points to the information of the firmware.
* return:
* 0: Succeeded;
* ERR_RSA_CHECK_FAIL: Signature is incorrect.
*/
static int checkFirmwareRSA(UPGRADE_HEADER* uHeader, FW_INFO* info) /* 固件升级过程中,确保固件由合法厂商签名,防止非法或被篡改的固件被加载。 */
{
int signCheckOk = 0; /* for RSA sign check result */
unsigned char md5Tmp[MD5SUM_LEN] = {0};
unsigned char rsaTmp[RSA_SIGN_LEN] = {0};
char* publicKey = NULL;
//get public key by vendorId.
switch (ntohs(uHeader->vendorId))
{
case VENDOR_ID_TP:
DBG_UNIT("TP key selected.");
publicKey = publicKeyTP;
break;
case VENDOR_ID_MECURY:
DBG_UNIT("Mercury key selected.");
publicKey = publicKeyMercury;
break;
case VENDOR_ID_FAST:
DBG_UNIT("Fast key selected.");
publicKey = publicKeyFast;
break;
case VENDOR_ID_PROWARE:
DBG_UNIT("Proware key selected.");
publicKey = publicKeyProware;
break;
default:
DBG_UNIT("no key available.");
//VendorID not exist, regard as RSA check failed.
ERR("RSA check failed.");
return ERR_RSA_CHECK_FAIL;
}
//backup RSA sign first.
memcpy(rsaTmp, uHeader->rsaSignature, RSA_SIGN_LEN);
memset(uHeader->rsaSignature, 0x0, RSA_SIGN_LEN);
DBG_UNIT("calc MD5.")
calcMd5((char*)uHeader, info->size, (char*)md5Tmp);
#ifdef RECOVERY_UPGRADE_UNIT_TEST
{
int i;
DBG_UNIT("Desired RSA:");
for (i=0; i<RSA_SIGN_LEN; i++)
{
printf("%02X ",rsaTmp[i]);
}
printf("\n");
DBG_UNIT("MD5:");
for (i=0; i<MD5SUM_LEN; i++)
{
printf("%02X ",md5Tmp[i]);
}
printf("\n");
}
#endif
DBG_UNIT("RSA verify...");
signCheckOk = rsaVerifySignByBase64EncodePublicKeyBlob(
(unsigned char*)publicKey,
strlen(publicKey),
md5Tmp,
MD5SUM_LEN,
rsaTmp,
RSA_SIGN_LEN);
if (!signCheckOk)
{
ERR("RSA check failed.");
return ERR_RSA_CHECK_FAIL;
}
//restore RSA sign.
memcpy(uHeader->rsaSignature, rsaTmp, RSA_SIGN_LEN);
DBG("firmware RSA signiture check OK");
return 0;
}
/*
* Function Name: checkFirmwareHwList
* Author: CaiBin
* Date: 2014-11-07
* Description: Check if HwID is supported in the HwID List of the firmware.
* Parameter:
* uHeader: Points to the upgrade header of the firmware.
* return:
* 0: Succeeded;
* ERR_HWID_NOT_SUPPORTED: HwID is not supported.
*/
static int checkFirmwareHwList(UPGRADE_HEADER* uHeader) /* 检查当前设备的硬件 ID(HwID)是否在固件头中指定的支持列表中,从而决定该固件是否适用于当前设备。*/
{
int i = 0;
int hwIdIsSupported = ERR_HWID_NOT_SUPPORTED;
for (i = 0; i < ntohs(uHeader->hwIdNum); i++)
{
int j;
DBG_UNIT("HwID:");
#ifdef RECOVERY_UPGRADE_UNIT_TEST
for (j = 0; j < HW_ID_LEN; j++)
{
printf("%02X ", uHeader->hwIdList[i][j]);
}
printf("\n");
#endif
if (memcmp(localInfo.hwID, uHeader->hwIdList[i], HW_ID_LEN) == 0)
{
DBG("firmware support my HwID");
hwIdIsSupported = 0;
break;
}
}
if (hwIdIsSupported < 0)
{
DBG("firmware not support my HwID");
}
return hwIdIsSupported;
}
/*
* Function Name: checkFirmwareID
* Author: CaiBin
* Date: 2014-11-07
* Description: Check if FwID is supported in the HwID List of the firmware.
* Only the designated FwID is permitted.
* Parameter:
* Header: Points to the TP Header of the upgrading firmware.
* return:
* 0: Succeeded;
* ERR_FWID_NOT_SUPPORTED: FwID is not supported.
*/
static int checkFirmwareID(TP_HEADER* header) /* 验证固件头中的固件 ID(fwId)是否与当前设备中存储的固件 ID(localInfo.fwID一致) */
{
if(memcmp(header->fwId, localInfo.fwID, FW_ID_LEN) != 0)
{
ERR("Firmware ID not supported.");
return ERR_FWID_NOT_SUPPORTED;
}
return 0;
}
/*
* Function Name: checkFirmwarePartition
* Author: CaiBin
* Date: 2014-11-07
* Description: Check if firmware has all partitions.
* Parameter:
* uHeader: Points to the upgrade header of the firmware.
* info: Points to the information of the firmware.
* return:
* 0: Succeeded;
* ERR_PARTITION_TYPE_NOT_SUPPORTED: Firmware has not all partitions.
*/
static int checkFirmwarePartition(UPGRADE_HEADER* uHeader, FW_INFO* info) /* 检查固件是否具有所有分区。 */
{
//firmware content type.
uint32_t fwContents = 0x0;
//get the content parts of firmware.
fwContents = ntohs(uHeader->contentTypes);
//up_boot.bin only.
if ((fwContents & PARTS_UP_BOOT) != PARTS_UP_BOOT)
{
ERR("content-type not supported.");
return ERR_PARTITION_TYPE_NOT_SUPPORTED;
}
return 0;
}
/*
* Function Name: validatePartitions
* Author: CaiBin
* Date: 2014-11-07
* Description: Check valid firmware partitions.
* Validate partition offsets,lengths and CRC's in TP Header.
* Parameter:
* header: Points to the TP Header partition of the firmware image to validate.
* return:
* 0: Succeeded;
* ERR_INVALID_TP_HEADER: Firmware has not all partitions.
* ERR_PARTITION_VALIDATION_FAILED: Partition CRC verification failed.
*/
static int validatePartitions(TP_HEADER* header, uint32_t partition_type) /* 先检查这个固件的结构Bootloader、内核、文件系统等等是否正确,然后对每一块计算 MD5,确认它们没有被篡改或损坏。 */
{
int ret = 0;
//array of validation crc's.
unsigned char* crc[] = {header ->factoryInfoCRC, header->radioCRC,
header->ubootCRC, header->kernelAndRomfsCRC};
//array of partition offsets.
uint32_t offset[] = {FACTORY_INFO_OFFSET, RADIO_OFFSET,
BOOTLOADER_OFFSET, KERNEL_ROMFS_OFFSET};
//array of partition lengths.
uint32_t length[] = {FACTORY_INFO_LEN, RADIO_LEN,
BOOTLOADER_LEN, ntohl(header->kernelLen) + ntohl(header->romFsLen)};
//array of messages.
char* dbg_msg[] = {"factory info", "radio data", "uboot", "kernel and romfs"};
//array of partition type flags to decide which partition to be validated.
uint32_t partition_flags[] = {PARTITION_TYPE_FACTORY_INFO, PARTITION_TYPE_RADIO_DATA,
PARTITION_TYPE_BOOTLOADER, PARTITION_TYPE_KERNEL};
unsigned char md5Tmp[MD5SUM_LEN] = {0};
unsigned char* base = NULL;
int i;
#ifndef CONFIG_RELOC_FIXUP_WORKS
//relocate pointers
for (i=0; i<sizeof(dbg_msg)/sizeof(char*); i++)
{
dbg_msg[i] += gd->reloc_off;
}
#endif
/* 检查每个分区在固件中的偏移地址和长度是否与预定义的常量一致; */
DBG_UNIT("Validating partitions...");
DBG_UNIT("Factory Boot Offset: %x, Length: %x", ntohl(header->factoryBootOffset), ntohl(header->factoryBootLen));
if(ntohl(header->factoryBootOffset) != FACTORY_BOOT_OFFSET
|| ntohl(header->factoryBootLen) != FACTORY_BOOT_LEN)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("Factory Info Offset: %x, Length: %x", ntohl(header->factoryInfoOffset), ntohl(header->factoryInfoLen));
if(ntohl(header->factoryInfoOffset) != FACTORY_INFO_OFFSET
|| ntohl(header->factoryInfoLen) != FACTORY_INFO_LEN)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("Radio Offset: %x, Length: %x", ntohl(header->radioOffset), ntohl(header->radioLen));
if(ntohl(header->radioOffset) != RADIO_OFFSET
|| ntohl(header->radioLen) != RADIO_LEN)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("User Config Offset: %x, Length: %x", ntohl(header->ucOffset), ntohl(header->ucLen));
if(ntohl(header->ucOffset) != UC_OFFSET
|| ntohl(header->ucLen) != UC_LEN)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("UBoot Offset: %x, Length: %x", ntohl(header->bootloaderOffset), ntohl(header->bootloaderLen));
if(ntohl(header->bootloaderOffset) != BOOTLOADER_OFFSET
|| ntohl(header->bootloaderLen) != BOOTLOADER_LEN)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("TP Header Offset: %x, Length: %x", ntohl(header->tpHeaderOffset), ntohl(header->tpHeaderLen));
if(ntohl(header->tpHeaderOffset) != TP_HEADER_OFFSET
|| ntohl(header->tpHeaderLen) != TP_HEADER_LEN)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("Kernel Offset: %x, Length: %x", ntohl(header->kernelOffset), ntohl(header->kernelLen));
if(ntohl(header->kernelOffset) != KERNEL_ROMFS_OFFSET)
{
return ERR_INVALID_TP_HEADER;
}
DBG_UNIT("Romfs Offset: %x, Length: %x", ntohl(header->romFsOffset), ntohl(header->romFsLen));
DBG_UNIT("JFFS2 Offset: %x, Length: %x", ntohl(header->jffs2FsOffset), ntohl(header->jffs2FsLen));
if(ntohl(header->kernelLen) + ntohl(header->romFsLen)
+ ntohl(header->jffs2FsLen) + KERNEL_ROMFS_OFFSET != UIP_FLASH_SIZE)
{
return ERR_INVALID_TP_HEADER;
}
//verifying partition CRC.
base = (char *)header - ntohl(header->tpHeaderOffset); /* 计算出固件起始地址 */
for (i = 0; i < sizeof(crc)/sizeof(char*); i++)
{
if(partition_type & partition_flags[i])
{
DBG("verifying %s partition...", dbg_msg[i]);
memset(md5Tmp, 0, MD5SUM_LEN);
DBG_UNIT("base: %p, offset: %p, length: %x", base, base+offset[i], (int)length[i]);
calcMd5((char *)(base+offset[i]), (int)length[i], (char *)md5Tmp);
if (memcmp(md5Tmp, crc[i], MD5SUM_LEN) == 0)
{
DBG("ok");
}
else
{
DBG("failed");
ret = ERR_PARTITION_VALIDATION_FAILED;
break;
}
}
}
return ret;
}
/*
* Function Name: checkFirmware
* Author: CaiBin
* Date: 2014-11-07
* Description: Check if firmware is valid.
* Parameter:
* info: Points to the information of the firmware.
* return:
* 0: Succeeded;
* ERR_INCORRECT_FILE_SIZE: File size is incorrect.
* ERR_RSA_CHECK_FAIL: Signature is incorrect.
* ERR_HWID_NOT_SUPPORTED: HwID is not supported.
* ERR_PARTITION_TYPE_NOT_SUPPORTED: Firmware has not all partitions.
*/
static int checkFirmware(FW_INFO* info) /* 固件校验函数 执行上边的函数 */
{
int ret = 0;
UPGRADE_HEADER* uHeader = NULL;
TP_HEADER* header;
unsigned char* buf = info->buf;
uHeader = (UPGRADE_HEADER*)buf;
//get firmware's upgrade header length and get its tp header.
info->uhTagLength = ntohs(uHeader->tagLength);
header = (TP_HEADER*)(buf + info->uhTagLength + BOOTLOADER_LEN);
DBG_UNIT("taglength: %d", info->uhTagLength);
//check file size.
ret = check_file_size(info->size);
if(ret < 0)
{
return ret;
}
#ifdef WEBFAILSAFE_UPGRADE_CHECK_RSA
//check rsa signiture if needed.
ret = checkFirmwareRSA(uHeader, info);
if (ret < 0)
{
return ret;
}
#endif
//check if HwID in firmware support HwID list.
ret = checkFirmwareHwList(uHeader);
if (ret < 0)
{
ERR("Hardware not supported.");
return ret;
}
//check FwID of the upgrading firmware.
/*ret = checkFirmwareID(header);
if(ret < 0)
{
return ret;
}*/
//check firmware partitions are enough and if contents are changed
ret = checkFirmwarePartition(uHeader, info);
if (ret < 0)
{
return ret;
}
//validate uploaded firmware partitions.
ret = validatePartitions(header, ntohs(uHeader->contentTypes));
if (ret < 0)
{
return ret;
}
DBG("firmware check finished, ok to upgrade");
return 0;
}
/*
* Function Name: executeUpgrade
* Author: CaiBin
* Date: 2014-11-07
* Description: Do actual upgrade work.
* Parameter:
* addrOffset: Flash address to be copyed to. 写入 Flash 的目标偏移地址;
* base: Points to the data to be copyed. 指向固件数据的起始地址;
* size: Data size to be copyed in bytes. 要写入的数据大小;
* return:
* 0: Succeeded;
* ERR_WRITE_FLASH: Write command execution error.
* ERR_READ_FLASH: Read command execution error.
* ERR_ERASE_FLASH: Erase command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
*/
static int executeUpgrade(uint32_t addrOffset, char* base, uint32_t size) /* 将固件数据写入指定偏移地址的 Flash 存储区域,完成实际的固件升级操作 */
{
int ret = 0;
DBG("execute upgrade...");
DBG_UNIT("write offset: %x, from: %p, size: %x", addrOffset, base, size);
//erase copy region.
ret = eraseFlash(addrOffset, size); /* 调用 eraseFlash 函数擦除目标 Flash 区域;Flash 在写入前必须先擦除,否则写入会失败*/
if (ret < 0)
{
ERR("erase flash failed!");
return ret;
}
//start to write firmware.
ret = writeFlash(addrOffset, (uint8_t*)base, size); /* 写到flash */
if (ret < 0)
{
ERR("write flash failed!");
return ret;
}
return 0;
}
/*
* Function Name: upgradeFirmware
* Author: CaiBin
* Date: 2014-11-07
* Description: Do upgrade.
* Parameter:
* info: Points to the information of the firmware.
* return:
* 0: Succeeded;
* ERR_WRITE_FLASH: Write command execution error.
* ERR_READ_FLASH: Read command execution error.
* ERR_ERASE_FLASH: Erase command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
*/
static int upgradeFirmware(FW_INFO* info) /* 根据FW_INFO* info解读信息,实现升级*/
{
int ret = 0;
TP_HEADER* header;
char* base = 0;
uint32_t size = 0;
char* buf = (char*)info->buf;
uint32_t addrOffset;
base = buf + info->uhTagLength; /* 缓冲区指针 buf 跳过标签长度 uhTagLength。 buf是开头*/
header = (TP_HEADER*)(buf + info->uhTagLength + BOOTLOADER_LEN); /* 找到固件头部信息TP_HEADER */
#ifdef UNIFY_FIRMWARE
/* 共用固件方案的升级文件尾部还有各机型的ISP_CONFIG文件 */
size = ntohl(header->bootloaderLen) + ntohl(header->tpHeaderLen) +
ntohl(header->kernelLen) + ntohl(header->romFsLen) + ntohl(header->jffs2FsLen);
#else
size = info->size - info->uhTagLength;
#endif
addrOffset = ntohl(header->bootloaderOffset);
ret = executeUpgrade(addrOffset, base, size);
if (ret < 0)
{
printf("%s failed\n", __func__);
return ret;
}
#if 0
/* erase user config */
addrOffset = ntohl(header->ucOffset);
ret = eraseFlash(addrOffset, ntohl(header->ucLen));
#endif
return ret;
}
#ifdef UNIFY_FIRMWARE
/******************************************************************************
* FUNCTION : checkFirmwareIsp()
* AUTHOR : He Shufan (heshufan@tp-link.com.cn)
* DESCRIPTION : check isp content and if they are newer or not.
* INPUT : BLOCK_HEADER, pointer to block_handler of this function
*
* OUTPUT : N/A
* RETURN : ret code
* OTHERS :
******************************************************************************/
static int checkFirmwareIsp(BLOCK_HEADER* hdr, void* thisHandler) /* 校验固件中 ISP(图像信号处理)模块的配置块 是否合法 */
{
int ret = 0;
int i = 0;
int blockNum = 0;
char md5Tmp[MD5SUM_LEN] = {0};
char devName[EXT_FW_DEVNAME_LEN + 1] = {0};
char* base = (char*)hdr;
EXT_FW_HEADER* iHdr = NULL;
EXT_FW_BLOCK_HANDLER* pointer = thisHandler;
if (NULL == hdr || NULL == thisHandler)
{
ret = ERR_GENERIC;
goto out;
}
blockNum = ntohl(hdr->num);
base += sizeof(BLOCK_HEADER);
/* 由device_model和hw_version通过"_"拼凑而成 */
snprintf(devName, EXT_FW_DEVNAME_LEN, "%s_%s", localInfo.device_model, localInfo.hw_version);
DBG("Local devName: %s", devName);
for (i = 0; i < blockNum; i++)
{
if (CONTENT_TYPE_ISP_CONFIG == ntohl(hdr->info[i].type))
{
iHdr = (EXT_FW_HEADER *)base;
DBG("iHdr->devName = %s", iHdr->devName);
if (0 == memcmp(iHdr->devName, devName, strlen(devName)))
{
pointer->block = iHdr;
DBG("isp: device name supported");
break;
}
}
base += ntohl(hdr->info[i].length);
}
if (i == blockNum)
{
DBG("isp: device name not supported");
ret = ERR_SLP_BAD_EXT_FW;
goto out;
}
calcMd5((char*)iHdr + sizeof(EXT_FW_HEADER), ntohl(iHdr->length), md5Tmp);
ret = memcmp(iHdr->md5, md5Tmp, MD5SUM_LEN);
if (ret)
{
DBG("Invalid isp data in firmware");
goto out;
}
out:
return ret;
}
/******************************************************************************
* FUNCTION : upgradeFirmwareIsp()
* AUTHOR : He Shufan (heshufan@tp-link.com.cn)
* DESCRIPTION : upgrade isp in flash
* INPUT : EXT_FW_HEADER
*
* OUTPUT : N/A
* RETURN : ret code
* OTHERS :
******************************************************************************/
static int upgradeFirmwareIsp(EXT_FW_HEADER* block) /* 将isp写入flash */
{
int ret = 0;
char ispBuf[RADIO_LEN] = {0};
uint32_t addrOffset = 0;
uint32_t size = 0;
if (NULL == block)
{
return ERR_GENERIC;
}
addrOffset = RADIO_OFFSET;
size = ntohl(block->length) + sizeof(EXT_FW_HEADER);
memset(ispBuf, 0xff, RADIO_LEN);
memcpy(ispBuf, (void *)block, size);
ret = eraseFlash(addrOffset, RADIO_LEN);
if (ret < 0)
{
DBG("erase radio flash failed!");
return ret;
}
ret = writeFlash(addrOffset, ispBuf, RADIO_LEN);
if (ret)
{
return ret;
}
DBG("upgrade isp done");
return ERR_NONE;
}
static int checkExtFirmware(FW_INFO* info) /* 校验扩展固件块(ext_fw)合法性 */
{
int i = 0;
int ret = 0;
unsigned short handlerFound = 0;
unsigned short upContents = 0;
BLOCK_HEADER* blockHdr = NULL;
UPGRADE_HEADER* uHeader = NULL;
TP_HEADER *header = NULL;
if (NULL == info)
{
return ERR_GENERIC;
}
uHeader = (UPGRADE_HEADER*)info->buf;
header = (TP_HEADER*)(info->buf + info->uhTagLength + BOOTLOADER_LEN);
upContents = ntohs(uHeader->contentTypes);
/* 新nvmp平台去除了jffs2FsLen的部分,因此将header->jffs2FsLen去除 */
blockHdr = (BLOCK_HEADER*)((char*)header + ntohl(header->jffs2FsOffset
- header->tpHeaderOffset/* + header->jffs2FsLen*/));
if (0 != memcmp(blockHdrMagicNumber, blockHdr->magicNumber, BLOCK_MAGIC_NUMBER_LEN))
{
DBG("invalid ext_fw block header");
return ERR_SLP_BAD_EXT_FW;
}
for (i = 0; i < sizeof(blockHdrTbl) / sizeof(EXT_FW_BLOCK_HANDLER); i++)
{
if (0 != blockHdrTbl[i].type & upContents)
{
handlerFound |= blockHdrTbl[i].type;
ret = blockHdrTbl[i].checkExtFw(blockHdr, &blockHdrTbl[i]);
if (ret)
{
DBG("check ext_fw failed, type:0x%x", blockHdrTbl[i].type);
return ERR_SLP_BAD_EXT_FW;
}
}
}
if ((upContents & ~(PARTS_UP_BOOT)) != handlerFound)
{
return ERR_SLP_BAD_EXT_FW;
}
DBG("ext_fw check ok.");
return ERR_NONE;
}
static int upgradeExtFirmware() /* 写入flash */
{
int i = 0;
int ret = 0;
for (i = 0; i < sizeof(blockHdrTbl) / sizeof(EXT_FW_BLOCK_HANDLER); i++)
{
if (blockHdrTbl[i].bNeedUpgrade)
{
ret = blockHdrTbl[i].upgradeExtFw(blockHdrTbl[i].block);
if (ret)
{
DBG("upgrade ext_fw failed, type:0x%x", blockHdrTbl[i].type);
return ret;
}
}
}
DBG("ext_fw upgrade ok.");
return ERR_NONE;
}
#endif
/*
* Function Name: validateLocalFirmware
* Author: CaiBin
* Date: 2014-11-07
* Description: Check if local firmware is valid.
* Validate partition offsets,lengths and CRC's in TP Header.
* Note: According to the newly designed flash layout and upload firmware
* layout. Only uboot partition, TP Header partition, kernel and fs partitions
* is validated.
* Parameter:
* header: Points to the TP Header partition of the firmware image to validate.
* return:
* 0: Succeeded;
* ERR_INVALID_TP_HEADER: Firmware has not all partitions.
* ERR_PARTITION_VALIDATION_FAILED: Partition CRC verification failed.
*/
int validateLocalFirmware(void) /* 检查本地固件是否有效。*/
{
volatile int ret = 0;
TP_HEADER* header = (TP_HEADER*)(UIP_FLASH_BASE + TP_HEADER_OFFSET);
uint32_t partitions = PARTITION_TYPE_BOOTLOADER | PARTITION_TYPE_KERNEL; /* 默认校验 Bootloader 和 Kernel 分区;*/
/*
* Note: As TP Header may be upgraded with crc's of these partitions changed, but the
* content of these partitions is never changed during upgrading. Normal check may result error.
*/
#ifdef WEBFAILSAFE_DO_FULL_LOCAL_VALIDATION /* 如果定义了 WEBFAILSAFE_DO_FULL_LOCAL_VALIDATION,还会校验:工厂信息和无线校准数据 */
partitions |= (PARTITION_TYPE_FACTORY_INFO | PARTITION_TYPE_RADIO_DATA);
#endif
#ifdef WEBFAILSAFE_LOCAL_VALIDATION_IN_RAM /* 启用该宏,会将 Flash 内容复制到 RAM 中再进行校验; */
//copy flash image to RAM.
DBG("copying flash to 0x%x", WEBFAILSAFE_UPLOAD_RAM_ADDRESS);
ret = readFlash(0, WEBFAILSAFE_UPLOAD_RAM_ADDRESS, UIP_FLASH_SIZE);
if (ret < 0)
{
ERR("reading flash to RAM failed.");
return ret;
}
header = (TP_HEADER*)(WEBFAILSAFE_UPLOAD_RAM_ADDRESS + TP_HEADER_OFFSET);
#endif
DBG_UNIT("validate local firmware...\nTP Header at %p", header);
#ifdef UIP_CACHE_OPERATION
uip_cache_enable();
#endif
ret = validatePartitions(header, partitions); /* 调用 validatePartitions() 校验关键分区 */
#ifdef UIP_CACHE_OPERATION
uip_cache_disable();
#endif
return ret;
}
/*
* Function Name: upgrade_init
* Author: CaiBin
* Date: 2014-11-07
* Description: Initiate local data and server page info.
* Parameter:
* N/A
* return:
* 0: Succeeded;
* ERR_HWID_NOT_FOUND: current hardware id not found.
* ERR_FWID_NOT_FOUND: allowed firmware id not found.
* ERR_READ_FLASH: Read command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
* ERR_GENERIC: Web content error.
*/
int upgrade_init()
{
int ret = 0;
//init local IDs.
ret = localInfoInit(); /* 初始化 localInfo 结构体全局变量,从 Flash 中读取出厂信息并填充到该结构体中。 */
if (ret < 0)
{
DBG("local info init failed, exit");
return ret;
}
return 0;
}
/*
* Function Name: do_http_check
* Author: CaiBin
* Date: 2014-11-07
* Description: Firmware check.
* Parameter:
* size: Upgrading firmware size.
* return:
* 0: Succeeded;
* ERR_INCORRECT_FILE_SIZE: File size is incorrect.
* ERR_RSA_CHECK_FAIL: Signature is incorrect.
* ERR_HWID_NOT_SUPPORTED: HwID is not supported.
* ERR_PARTITION_TYPE_NOT_SUPPORTED: Firmware has not all partitions.
* ERR_WRITE_FLASH: Write command execution error.
* ERR_READ_FLASH: Read command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
*/
int do_http_check(const ulong size) /* 校验从 HTTP 接收到的固件是否合法*/
{
volatile int ret = 0;
fw_info.buf = (unsigned char*)WEBFAILSAFE_UPLOAD_RAM_ADDRESS;
fw_info.size = size;
fw_info.uhTagLength = 0;
#ifdef UIP_CACHE_OPERATION
uip_cache_enable();
#endif
//check firmware size, RSA signature, HwID, content type, and validate partitions.
ret = checkFirmware(&fw_info);
#ifdef UNIFY_FIRMWARE
if (ret < 0)
{
goto goon;
}
ret = checkExtFirmware(&fw_info);
#endif
goon:
#ifdef UIP_CACHE_OPERATION
uip_cache_disable();
#endif
if (ret < 0)
{
DBG("check firmware failed, exit");
return ret;
}
return ret;
}
/*
* Function Name: do_http_upgrade
* Author: CaiBin
* Date: 2014-11-07
* Description: Firmware upgrade.
* Parameter:
* size: Upgrading firmware size.
* return:
* 0: Succeeded;
* ERR_WRITE_FLASH: Write command execution error.
* ERR_READ_FLASH: Read command execution error.
* ERR_ERASE_FLASH: Erase command execution error.
* ERR_BAD_ADDRESS: Invalid address values passed.
*/
int do_http_upgrade(const ulong size)
{
int ret = 0;
//write upgrade data into flash.
ret = upgradeFirmware(&fw_info);
if (ret < 0)
{
DBG("upgrade firmware failed, exit");
return ret;
}
#ifdef UNIFY_FIRMWARE
ret = upgradeExtFirmware();
#endif
return ret;
}
// info about current progress of failsafe mode
int do_http_progress(const int state){
unsigned char i = 0;
/* toggle LED's here */
switch(state){
case WEBFAILSAFE_PROGRESS_START:
/* turn on sys led. */
all_leds_on(1);
printf("HTTP server is ready!\n\n");
break;
case WEBFAILSAFE_PROGRESS_TIMEOUT:
//printf("Waiting for request...\n");
break;
case WEBFAILSAFE_PROGRESS_UPLOAD_READY:
all_leds_on(0);
printf("HTTP upload is done! Upgrading...\n");
break;
case WEBFAILSAFE_PROGRESS_UPGRADE_READY:
all_leds_on(0);
printf("HTTP ugrade is done! Rebooting...\n\n");
break;
case WEBFAILSAFE_PROGRESS_UPGRADE_ABORTED:
all_leds_on(0);
printf("\nWeb failsafe mode aborted!\n\n");
break;
case WEBFAILSAFE_PROGRESS_UPGRADE_FAILED:
all_leds_on(0);
printf("## Error: HTTP ugrade failed!\n\n");
// wait 1 sec
milisecdelay(1000);
break;
}
return(0);
}
最新发布