/********************************************************************* * @fn OADTarget_validateNewImage * * @brief Determine if a new image should be downloaded or not based on * target specific criteria. * * @param pValue - pointer to new Image header information * @param ImgHdr - pointer to contents of current image header * @param blkTot - total number of blocks comprising new image. * * @return TRUE to begin OAD otherwise FALSE to reject the image. */ uint8_t OADTarget_validateNewImage(uint8_t *pValue, img_hdr_t *ImgHdr, uint16_t blkTot) { uint8_t ret = FALSE; img_hdr_t rxHdr; rxHdr.ver = BUILD_UINT16(pValue[0], pValue[1]); rxHdr.len = BUILD_UINT16(pValue[2], pValue[3]); /* Requirements to begin OAD: * 1) LSB of image version cannot be the same, this would imply a code overlap * between currently running image and new image. * 2) Total blocks of new image must not exceed maximum blocks supported, else * the new image cannot fit. * 3) Block total must be greater than 0. * 4) Optional: Add additional criteria for initiating OAD here. */ if ((OAD_IMG_ID(ImgHdr->ver) != OAD_IMG_ID(rxHdr.ver)) && (blkTot <= OAD_BLOCK_MAX) && (blkTot != 0)) { ret = TRUE; } return ret; }
/********************************************************************* * @fn oadImgIdentifyWrite * * @brief Process the Image Identify Write. * * @param connHandle - connection message was received on * @param pValue - pointer to data to be written * * @return status */ static bStatus_t oadImgIdentifyWrite( uint16 connHandle, uint8 *pValue ) { img_hdr_t rxHdr; img_hdr_t ImgHdr; rxHdr.ver = BUILD_UINT16( pValue[0], pValue[1] ); rxHdr.len = BUILD_UINT16( pValue[2], pValue[3] ); (void)osal_memcpy(rxHdr.uid, pValue+4, sizeof(rxHdr.uid)); HalFlashRead(OAD_IMG_R_PAGE, OAD_IMG_HDR_OSET, (uint8 *)&ImgHdr, sizeof(img_hdr_t)); oadBlkTot = rxHdr.len / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE); if ( (OAD_IMG_ID( ImgHdr.ver ) != OAD_IMG_ID( rxHdr.ver )) && // TBD: add customer criteria for initiating OAD here. (oadBlkTot <= OAD_BLOCK_MAX) && (oadBlkTot != 0) ) { oadBlkNum = 0; oadImgBlockReq(connHandle, 0); } else { oadImgIdentifyReq(connHandle, &ImgHdr); } return ( SUCCESS ); }
/********************************************************************* * @fn oadManagerHandleNoti * * @brief Handle Notifications and Indications. * * @return none */ static void oadManagerHandleNoti(attHandleValueNoti_t *pNoti) { if (pNoti->handle == oadManagerHandles[OAD_CHAR_IMG_IDENTIFY]) { #if (defined HAL_LCD && (HAL_LCD == TRUE)) uint16 ver = BUILD_UINT16(pNoti->value[0], pNoti->value[1]); uint8 userId[12] = "UserId "; osal_memcpy(&(userId[7]), &(pNoti->value[4]), 4); userId[11] = '\0'; if ( OAD_IMG_ID( ver ) == 0 ) { HalLcdWriteStringValueValue("ImgA Id", OAD_VER_NUM( ver ), 16, BUILD_UINT16(pNoti->value[2], pNoti->value[3]), 16, HAL_LCD_LINE_2); } else { HalLcdWriteStringValueValue("ImgB Id", OAD_VER_NUM( ver ), 16, BUILD_UINT16(pNoti->value[2], pNoti->value[3]), 16, HAL_LCD_LINE_2); } HalLcdWriteString((char*)userId, HAL_LCD_LINE_3); #endif } else if (pNoti->handle == oadManagerHandles[OAD_CHAR_IMG_BLOCK]) { oadBlkNum = BUILD_UINT16(pNoti->value[0], pNoti->value[1]); attWriteReq_t req; req.handle = oadManagerHandles[OAD_CHAR_IMG_BLOCK]; req.len = 2 + OAD_BLOCK_SIZE; req.sig = FALSE; req.cmd = TRUE; req.value[0] = LO_UINT16(oadBlkNum); req.value[1] = HI_UINT16(oadBlkNum); uint8 page = oadBlkNum / OAD_BLOCKS_PER_PAGE; uint16 oset = (oadBlkNum - (OAD_BLOCKS_PER_PAGE * page)) * OAD_BLOCK_SIZE; HalFlashRead(page+OAD_IMG_B_PAGE, oset, req.value+2, OAD_BLOCK_SIZE); #if (defined HAL_LCD) && (HAL_LCD == TRUE) if (oadBlkNum == 0) { HalLcdWriteString("", HAL_LCD_LINE_3); } HalLcdDisplayPercentBar( "OAD Progress...", (oadBlkNum / (oadBlkTot / 100)) ); #endif VOID GATT_WriteNoRsp(oadManagerConnHandle, &req); VOID osal_start_timerEx( oadManagerTaskId, OAD_DOWNLOAD_EVT, OAD_DOWNLOAD_TIMEOUT ); } }
/********************************************************************* * @fn oadImgBlockWrite * * @brief Process the Image Block Write. * * @param connHandle - connection message was received on * @param pValue - pointer to data to be written * * @return status */ static bStatus_t oadImgBlockWrite( uint16 connHandle, uint8 *pValue ) { uint16 blkNum = BUILD_UINT16( pValue[0], pValue[1] ); // make sure this is the image we're expecting if ( blkNum == 0 ) { img_hdr_t ImgHdr; uint16 ver = BUILD_UINT16( pValue[6], pValue[7] ); uint16 blkTot = BUILD_UINT16( pValue[8], pValue[9] ) / (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE); HalFlashRead(OAD_IMG_R_PAGE, OAD_IMG_HDR_OSET, (uint8 *)&ImgHdr, sizeof(img_hdr_t)); if ( ( oadBlkNum != blkNum ) || ( oadBlkTot != blkTot ) || ( OAD_IMG_ID( ImgHdr.ver ) == OAD_IMG_ID( ver ) ) ) { return ( ATT_ERR_WRITE_NOT_PERMITTED ); } } if (oadBlkNum == blkNum) { uint16 addr = oadBlkNum * (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE) + (OAD_IMG_D_PAGE * OAD_FLASH_PAGE_MULT); oadBlkNum++; #if defined FEATURE_OAD_SECURE if (blkNum == 0) { // Stop attack with crc0==crc1 by forcing crc1=0xffff. pValue[4] = 0xFF; pValue[5] = 0xFF; } #endif #if defined HAL_IMAGE_B // Skip the Image-B area which lies between the lower & upper Image-A parts. if (addr >= (OAD_IMG_B_PAGE * OAD_FLASH_PAGE_MULT)) { addr += OAD_IMG_B_AREA * OAD_FLASH_PAGE_MULT; } #endif if ((addr % OAD_FLASH_PAGE_MULT) == 0) { HalFlashErase(addr / OAD_FLASH_PAGE_MULT); } HalFlashWrite(addr, pValue+2, (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE)); } if (oadBlkNum == oadBlkTot) // If the OAD Image is complete. { #if defined FEATURE_OAD_SECURE HAL_SYSTEM_RESET(); // Only the secure OAD boot loader has the security key to decrypt. #else if (checkDL()) { #if !defined HAL_IMAGE_A // The BIM always checks for a valid Image-B before Image-A, // so Image-A never has to invalidate itself. uint16 crc[2] = { 0x0000, 0xFFFF }; uint16 addr = OAD_IMG_R_PAGE * OAD_FLASH_PAGE_MULT + OAD_IMG_CRC_OSET / HAL_FLASH_WORD_SIZE; HalFlashWrite(addr, (uint8 *)crc, 1); #endif HAL_SYSTEM_RESET(); } #endif } else // Request the next OAD Image block. { oadImgBlockReq(connHandle, oadBlkNum); } return ( SUCCESS ); }