memmem 函数

memmem 函数
2011年06月02日
  软件研发的面试,除了架构设计和算法之外,还有一类看似简单的问题,但是也挂了相当一部分人,就是让写一些简单例程,比较典型的是要求实现C的一些库函数,比如我曾碰见让当场写一个strcat,一般只要细心一点,还是比较简单的,不过一般来讲在你写出以后,会有一些后续问题,比如递归改非递归等,有人可能觉得这些问题只是拿来考试的,实践中只要调用现成的库就可以了,实际上,某些C库并没有想象得那么好
  memmem是一个C库函数,用于在一块内存中寻找匹配另一块内存的内容的第一个位置,其实本来我想写strstr,后来觉得太麻烦,就直接用memmem了,这个问题的起因是在Python的源码里,看到字符串的find方法没有调用strstr和memmem,而是使用了自己写的一段例程,所以想看看C库的这两个函数是不是真的很烂,环境是linux,gcc
  首先是一个比较直观的myMemmem(如果严格一点,长度应该是size_t型,而且要先判断alen和blen的大小关系,以及是否为正整数,这里都省了)
  int myMemmem(char * a, int alen, char * b, int blen)
  {
  int i, j;
  for (i = 0; i <= alen
/* * 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); }
最新发布
09-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值