uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t err_code; uint32_t total_image_size = p_packet->params.init_packet.total_image_size; dfu_update_status_t update_status; switch (m_dfu_state) { case DFU_STATE_IDLE: case DFU_STATE_RDY: case DFU_STATE_RX_DATA_PKT: m_dfu_state = DFU_STATE_RX_INIT_PKT; /* fall-through */ case DFU_STATE_RX_INIT_PKT: // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } // Reset the number of data received and the original m_storage_handle_app's start address. m_data_received = 0; m_storage_handle_app.block_id = CODE_REGION_1_START; // Prepare the flash buffer for the upcoming image. if (total_image_size > DFU_IMAGE_MAX_SIZE_BANKED) { update_status.status_code = DFU_UPDATE_AP_INVALIDATED; bootloader_dfu_update_process(update_status); err_code = pstorage_raw_clear(&m_storage_handle_app, DFU_IMAGE_MAX_SIZE_FULL); m_active_bank = NEW_IMAGE_BANK_0; } else if ((total_image_size < DFU_IMAGE_MAX_SIZE_BANKED) && (total_image_size != 0)) { err_code = pstorage_raw_clear(&m_storage_handle_swap, DFU_IMAGE_MAX_SIZE_BANKED); m_active_bank = NEW_IMAGE_BANK_1; } else { // do nothing } break; default: // Either the start packet was not received or dfu_init function was not called before. err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t err_code = NRF_SUCCESS; uint32_t length; switch (m_dfu_state) { case DFU_STATE_RDY: m_dfu_state = DFU_STATE_RX_INIT_PKT; // When receiving init packet in state ready just update and fall through this case. case DFU_STATE_RX_INIT_PKT: // DFU initialization has been done and a start packet has been received. if (IMAGE_WRITE_IN_PROGRESS()) { // Image write is already in progress. Cannot handle an init packet now. return NRF_ERROR_INVALID_STATE; } // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); if ((m_init_packet_length + length) > sizeof(m_init_packet)) { return NRF_ERROR_INVALID_LENGTH; } memcpy(&m_init_packet[m_init_packet_length], &p_packet->params.data_packet.p_data_packet[0], length); m_init_packet_length += length; break; default: // Either the start packet was not received or dfu_init function was not called before. err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_image_validate() { uint32_t err_code; uint16_t received_crc; switch (m_dfu_state) { case DFU_STATE_RX_DATA_PKT: m_dfu_state = DFU_STATE_VALIDATE; // Check if the application image write has finished. if (m_app_data_received != m_image_size) { // Image not yet fully transfered by the peer or the peer has attempted to write // too much data. Hence the validation should fail. err_code = NRF_ERROR_INVALID_STATE; } else { // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code == NRF_SUCCESS) { // calculate CRC from DFU_BANK_1_REGION_START to mp_app_write_address. m_image_crc = crc16_compute((uint8_t*)DFU_BANK_1_REGION_START, m_image_size, NULL); received_crc = uint16_decode((uint8_t*)&m_init_packet[0]); if ((m_init_packet_length != 0) && (m_image_crc != received_crc)) { return NRF_ERROR_INVALID_DATA; } m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; } } break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_image_validate(uint16_t crc_seed) { uint32_t err_code; switch (m_dfu_state) { case DFU_STATE_RX_DATA_PKT: m_dfu_state = DFU_STATE_VALIDATE; // Check if the application image write has finished. if (m_data_received != m_image_size) { // Image not yet fully transfered by the peer or the peer has attempted to write // too much data. Hence the validation should fail. err_code = NRF_ERROR_INVALID_STATE; } else { // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code == NRF_SUCCESS) { if(crc_crc16_update(crc_seed, (uint32_t*)dfu_storage_start_address_get(), m_image_size) == 0) { m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; err_code = NRF_SUCCESS; } else { err_code = NRF_ERROR_INTERNAL; } } } break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_image_validate() { uint32_t err_code; switch (m_dfu_state) { case DFU_STATE_RX_DATA_PKT: // Check if the application image write has finished. if (m_data_received != m_image_size) { // Image not yet fully transfered by the peer or the peer has attempted to write // too much data. Hence the validation should fail. err_code = NRF_ERROR_INVALID_STATE; } else { m_dfu_state = DFU_STATE_VALIDATE; // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code == NRF_SUCCESS) { if(IS_UPDATING_BL(m_start_packet)) { m_image_size = m_image_size - ((uint32_t)(&__end_protected_data) - (uint32_t)(&__start_protected_data)); } err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id, m_image_size); VERIFY_SUCCESS(err_code); m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; } } break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t err_code; uint32_t i; switch (m_dfu_state) { case DFU_STATE_RDY: m_dfu_state = DFU_STATE_RX_INIT_PKT; /* fall-through */ case DFU_STATE_RX_INIT_PKT: // DFU initialization has been done and a start packet has been received. if (IMAGE_WRITE_IN_PROGRESS()) { // Image write is already in progress. Cannot handle an init packet now. return NRF_ERROR_INVALID_STATE; } // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } for (i = 0; i < p_packet->packet_length; i++) { m_init_packet[m_init_packet_length++] = p_packet->p_data_packet[i]; } break; default: // Either the start packet was not received or dfu_init function was not called before. err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_image_size_set(uint32_t image_size) { uint32_t err_code; if (image_size > m_new_app_max_size) { return NRF_ERROR_DATA_SIZE; } if ((image_size & (sizeof(uint32_t) - 1)) != 0) { // Image_size is not a multiple of 4 (word size). return NRF_ERROR_NOT_SUPPORTED; } switch (m_dfu_state) { case DFU_STATE_IDLE: // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } m_image_size = image_size; m_dfu_state = DFU_STATE_RDY; break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t data_length; uint32_t err_code; uint32_t * p_data; if (p_packet == NULL) { return NRF_ERROR_NULL; } // Check pointer alignment. if (!is_word_aligned(p_packet->params.data_packet.p_data_packet)) { // The p_data_packet is not word aligned address. return NRF_ERROR_INVALID_ADDR; } switch (m_dfu_state) { case DFU_STATE_RDY: case DFU_STATE_RX_INIT_PKT: return NRF_ERROR_INVALID_STATE; case DFU_STATE_RX_DATA_PKT: data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); if ((m_data_received + data_length) > m_image_size) { // The caller is trying to write more bytes into the flash than the size provided to // the dfu_image_size_set function. This is treated as a serious error condition and // an unrecoverable one. Hence point the variable mp_app_write_address to the top of // the flash area. This will ensure that all future application data packet writes // will be blocked because of the above check. m_data_received = 0xFFFFFFFF; return NRF_ERROR_DATA_SIZE; } // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet; err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); if (err_code != NRF_SUCCESS) { return err_code; } m_data_received += data_length; if (m_data_received != m_image_size) { // The entire image is not received yet. More data is expected. err_code = NRF_ERROR_INVALID_LENGTH; } else { // The entire image has been received. Return NRF_SUCCESS. err_code = NRF_SUCCESS; } break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t err_code; m_start_packet = *(p_packet->params.start_packet); // Check that the requested update procedure is supported. // Currently the following combinations are allowed: // - Application // - SoftDevice // - Bootloader // - SoftDevice with Bootloader if (IS_UPDATING_APP(m_start_packet) && (IS_UPDATING_SD(m_start_packet) || IS_UPDATING_BL(m_start_packet))) { // App update is only supported independently. return NRF_ERROR_NOT_SUPPORTED; } if (!(IS_WORD_SIZED(m_start_packet.sd_image_size) && IS_WORD_SIZED(m_start_packet.bl_image_size) && IS_WORD_SIZED(m_start_packet.app_image_size))) { // Image_sizes are not a multiple of 4 (word size). return NRF_ERROR_NOT_SUPPORTED; } m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size + m_start_packet.app_image_size; if (m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE) { return NRF_ERROR_DATA_SIZE; } if (m_image_size > (DFU_IMAGE_MAX_SIZE_FULL)) { return NRF_ERROR_DATA_SIZE; } m_functions.prepare = dfu_prepare_func_app_erase; m_functions.cleared = dfu_cleared_func_app; if (IS_UPDATING_SD(m_start_packet)) { m_functions.activate = dfu_activate_sd; } else if (IS_UPDATING_BL(m_start_packet)) { m_functions.activate = dfu_activate_bl; } else { m_functions.activate = dfu_activate_app; } switch (m_dfu_state) { case DFU_STATE_IDLE: // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } m_functions.prepare(m_image_size); break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t err_code = NRF_SUCCESS; m_start_packet = p_packet->params.start_packet; // Check that the requested update procedure is supported. // Currently the following combinations are allowed: // - Application // - SoftDevice // - Bootloader // - SoftDevice with Bootloader if (IS_UPDATING_APP() && //lint !e655 suppress lint warning 655: bit-wise operations (IS_UPDATING_SD() || //lint !e655 suppress Lint Warning 655: Bit-wise operations IS_UPDATING_BL() || //lint !e655 suppress lint warning 655: bit-wise operations ((m_start_packet.app_image_size & (sizeof(uint32_t) - 1)) != 0))) { // Image_size is not a multiple of 4 (word size). return NRF_ERROR_NOT_SUPPORTED; } if (IS_UPDATING_SD() && //lint !e655 suppress lint warning 655: bit-wise operations ((m_start_packet.sd_image_size & (sizeof(uint32_t) - 1)) != 0)) { // Image_size is not a multiple of 4 (word size). return NRF_ERROR_NOT_SUPPORTED; } if (IS_UPDATING_BL() && //lint !e655 suppress lint warning 655: bit-wise operations ((m_start_packet.bl_image_size & (sizeof(uint32_t) - 1)) != 0)) { // Image_size is not a multiple of 4 (word size). return NRF_ERROR_NOT_SUPPORTED; } m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size + m_start_packet.app_image_size + m_start_packet.info_bytes_size; if (IS_UPDATING_BL() && m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE)//lint !e655 suppress Lint Warning 655: Bit-wise operations { return NRF_ERROR_DATA_SIZE; } else if (m_image_size > DFU_IMAGE_MAX_SIZE_FULL) { return NRF_ERROR_DATA_SIZE; } else { // Do nothing. } // If new softdevice size is greater than the code region 1 boundary if (IS_UPDATING_SD() && m_start_packet.sd_image_size > (CODE_REGION_1_START - SOFTDEVICE_REGION_START))//lint !e655 suppress Lint Warning 655: Bit-wise operations { //calculate storage starting offset. uint32_t storage_starting_offset; storage_starting_offset = m_start_packet.sd_image_size - (CODE_REGION_1_START - SOFTDEVICE_REGION_START); storage_starting_offset = CODE_REGION_1_START + storage_starting_offset; if (storage_starting_offset & ~(NRF_FICR->CODEPAGESIZE - 1)) { storage_starting_offset &= ~(NRF_FICR->CODEPAGESIZE - 1); storage_starting_offset += NRF_FICR->CODEPAGESIZE; } m_storage_handle_app.block_id = storage_starting_offset; } switch (m_dfu_state) { case DFU_STATE_RX_INIT_PKT: // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); if (err_code != NRF_SUCCESS) { return err_code; } m_dfu_state = DFU_STATE_RDY; //break; fallthrough case DFU_STATE_RDY: break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }
uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) { uint32_t data_length; uint32_t err_code; uint32_t * p_data; VERIFY_PARAM_NOT_NULL(p_packet); // Check pointer alignment. if (!is_word_aligned(p_packet->params.data_packet.p_data_packet)) { // The p_data_packet is not word aligned address. return NRF_ERROR_INVALID_ADDR; } switch (m_dfu_state) { case DFU_STATE_RDY: case DFU_STATE_RX_INIT_PKT: return NRF_ERROR_INVALID_STATE; case DFU_STATE_RX_DATA_PKT: data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); if ((m_data_received + data_length) > m_image_size) { // The caller is trying to write more bytes into the flash than the size provided to // the dfu_image_size_set function. This is treated as a serious error condition and // an unrecoverable one. Hence point the variable mp_app_write_address to the top of // the flash area. This will ensure that all future application data packet writes // will be blocked because of the above check. m_data_received = 0xFFFFFFFF; return NRF_ERROR_DATA_SIZE; } // Valid peer activity detected. Hence restart the DFU timer. err_code = dfu_timer_restart(); VERIFY_SUCCESS(err_code); p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet; // Do AES Decrption. dfu_aes_128_ofb_decrypt(p_data, data_length/sizeof(uint32_t), m_data_received); // Check the protected data before copying it and make sure its retain or update the data. uint32_t bootloader_position = m_data_received - m_start_packet.sd_image_size; for (int w = 0; w < data_length/sizeof(uint32_t); w++) { bootloader_position = bootloader_position + 4; if(m_start_packet.bl_image_size > 0 && (m_data_received > m_start_packet.sd_image_size) && (bootloader_position >= ((uint32_t)(&__start_protected_data) - m_uicr_bootloader_start_address))) { if(p_data[w] == 0x00000000) { p_data[w] = 0xFFFFFFFF; } else if(p_data[w] == 0xFFFFFFFF) p_data[w] = (uint32_t)(*((uint32_t *)(bootloader_position - 4 + m_uicr_bootloader_start_address))); } } err_code = pstorage_store(mp_storage_handle_active, (uint8_t *)p_data, data_length, m_data_received); VERIFY_SUCCESS(err_code); m_data_received += data_length; if (m_data_received != m_image_size) { // The entire image is not received yet. More data is expected. err_code = NRF_ERROR_INVALID_LENGTH; } else { // The entire image has been received. Return NRF_SUCCESS. err_code = NRF_SUCCESS; } break; default: err_code = NRF_ERROR_INVALID_STATE; break; } return err_code; }