/*********************************************************************
 * @fn      OADTarget_imgBlockWrite
 *
 * @brief   Process the Image Block Write.
 *
 * @param   connHandle - connection message was received on
 * @param   pValue - pointer to data to be written
 *
 * @return  status
 */
bStatus_t OADTarget_imgBlockWrite(uint16_t connHandle, uint8_t *pValue)
{
  volatile uint16_t blkNum;
 
  blkNum  = BUILD_UINT16(pValue[0], pValue[1]);

  // First block of OAD which included image header and CRC and CRC shadow
  // values. Do a sanity check on the received image header
  if (blkNum == 0)
  {
    img_hdr_t ImgHdr;
    uint16_t blkTot;
   
    blkTot = BUILD_UINT16(pValue[8], pValue[9]) / 
                                  (OAD_BLOCK_SIZE / HAL_FLASH_WORD_SIZE);

    // Read out running image's header.
    uint8_t *flashAddr = (uint8_t *)(APP_IMAGE_START + OAD_IMG_HDR_OSET);
    memcpy(&ImgHdr,flashAddr,sizeof(img_hdr_t));

    // Note:  if additional customer criteria was checked in the Image
    // Identification step, it may be important to check again here.
    if ((oadBlkNum != blkNum) || (oadBlkTot != blkTot) )
    {
      // Cancel download
      OADTarget_rejectImage(connHandle, &ImgHdr);

      // NB! This is meaningless for a WriteNoResp operation
      return (ATT_ERR_WRITE_NOT_PERMITTED);
    }
#ifdef POWER_SAVING
    Power_setConstraint(Power_SB_DISALLOW);
#endif
  }

  // Check that this is the expected block number.
  if (oadBlkNum == blkNum && flashOk)
  {
    uint32_t addr;
   
    // Calculate address to write as (start of OAD range) + (offset)
    addr = APP_IMAGE_START + oadBlkNum * OAD_BLOCK_SIZE;

    // If address starts a new page, erase that page first.
    if ((addr % HAL_FLASH_PAGE_SIZE) == 0)
    {
      flashOk = extFlashErase(addr, HAL_FLASH_PAGE_SIZE);
    }

    // Write a 16 byte block to Flash.
    if (flashOk)
    {
      flashOk = extFlashWrite(addr, OAD_BLOCK_SIZE, pValue+2);
    
      // Increment received block count.
      if (flashOk)
        oadBlkNum++;
    }

    // Toggle Green LED for every 8th block
    if ( (oadBlkNum % 8) == 0)
    {
      GPIO_toggle(Board_LED2);
    }
  }
  else
  {
    img_hdr_t ImgHdr;
    
     // Toggle RED LED and sound buzzer when overflow
     GPIO_toggle(Board_LED1);
     GPIO_toggle(Board_BUZZER);
#ifdef POWER_SAVING
    Power_releaseConstraint(Power_SB_DISALLOW);
#endif     
    
    // Cancel download
    ImgHdr.len = 0; // Don't care content
    OADTarget_rejectImage(connHandle, &ImgHdr);
  }
  
  // Check if the OAD Image is complete.
  if (oadBlkNum == oadBlkTot)
  {
    extFlashClose();
    
    // Run CRC check on new image.
    if (checkDL())
    {
      HAL_SYSTEM_RESET();
    }
    else
    {
      GPIO_toggle(Board_LED1);
    }
#ifdef POWER_SAVING
    Power_releaseConstraint(Power_SB_DISALLOW);
#endif     
  }
  else
  {
    // Request the next OAD Image block.
    OADTarget_getNextBlockReq(connHandle, oadBlkNum);
  }

  return (SUCCESS);
}
Example #2
0
/*********************************************************************
 * @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 );
}