320 lines
15 KiB
C
320 lines
15 KiB
C
//
|
||
// Created by cfif on 12.07.2024.
|
||
//
|
||
#include "EgtsUpdateFirmware.h"
|
||
#include "InternalFlashPage.h"
|
||
#include "AtGsmSimComA7600_SSL_LOAD_CA.h"
|
||
#include "FirmwareLoader.h"
|
||
#include "aes.h"
|
||
#include "EgtsProcessing.h"
|
||
#include "SystemDelayInterface.h"
|
||
#include "egts_crc.h"
|
||
#include "GsmWithGnss_Info.h"
|
||
|
||
#define LOG_SIGN "EGTS_UPDATE"
|
||
#define LOGGER &env->slog->logger
|
||
|
||
extern tFirmwareLoader FIRMWARE_LOADER;
|
||
|
||
void receivedUpdateFirmware(tEgtsProcessing *env) {
|
||
if(env->isTimerUpdate == false){
|
||
env->isTimerUpdate = true;
|
||
env->timerUpdate = SystemGetMs()+60*5*1000;
|
||
}
|
||
LoggerFormatInfo(LOGGER, LOG_SIGN,
|
||
"Получен пакет прошивки, %d из %d (%d байт данных)",
|
||
env->egtsEnv.firmware->PartNumber,
|
||
env->egtsEnv.firmware->ExpectedPartsQuantity,
|
||
env->egtsEnv.firmware->dataLength);
|
||
|
||
|
||
eEgtsFirmwareResult isFirmwareResult = EGTS_FIRMWARE_OK;
|
||
uint8_t rst = EGTS_PC_IN_PROGRESS;
|
||
|
||
// Пришел первый пакет обновления
|
||
if (env->egtsEnv.firmware->PartNumber == 1) {
|
||
|
||
// Останов навигации
|
||
//LoggerInfoStatic(LOGGER, LOG_SIGN, "Остановка потока навигации");
|
||
//SetConfigureStaticRMCThreadStop(env->gsm);
|
||
|
||
env->firmwareOffset = 0;
|
||
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Подготовка ПЗУ");
|
||
env->firmwareBufCrc = env->egtsEnv.firmware->WholeObjectSignature;
|
||
|
||
if (osMutexAcquire(EXT_ENV_TELE.store.accessDumper, 5000) == osOK) {
|
||
if (FirmwareLoader_ClearUpdateFlash(&FIRMWARE_LOADER)) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "ПЗУ очищено");
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка очистки ПЗУ");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_WRITE_PZU;
|
||
}
|
||
|
||
osMutexRelease(EXT_ENV_TELE.store.accessDumper);
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка доступа receivedUpdateFirmware");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_ACCESS;
|
||
}
|
||
|
||
}
|
||
|
||
if (env->firmwareOffset + env->egtsEnv.firmware->dataLength > FIRMWARE_LOADER.fwSize) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Переполнение буфера ПЗУ");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_OVERFLOW_PZU;
|
||
} else {
|
||
|
||
if (osMutexAcquire(EXT_ENV_TELE.store.accessDumper, 5000) == osOK) {
|
||
if (sInternalFlashPage_Write(FIRMWARE_LOADER.update.address,
|
||
env->firmwareOffset,
|
||
env->egtsEnv.firmware->dataPointer,
|
||
env->egtsEnv.firmware->dataLength) == env->egtsEnv.firmware->dataLength) {
|
||
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Успешно записан в ПЗУ");
|
||
|
||
env->firmwareOffset += env->egtsEnv.firmware->dataLength;
|
||
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка записи в ПЗУ");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_WRITE_PZU;
|
||
}
|
||
|
||
osMutexRelease(EXT_ENV_TELE.store.accessDumper);
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка доступа receivedUpdateFirmware");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_ACCESS;
|
||
}
|
||
|
||
if (env->egtsEnv.firmware->PartNumber == env->egtsEnv.firmware->ExpectedPartsQuantity) {
|
||
|
||
uint16_t crcEgts16 = CRC16EGTS((uint8_t *) (FIRMWARE_LOADER.update.address), env->firmwareOffset);
|
||
|
||
if (crcEgts16 != env->firmwareBufCrc) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка контрольной суммы (ЕГТС)");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_EGTS_CRC;
|
||
}
|
||
|
||
uint32_t pos = env->firmwareOffset - 256;
|
||
|
||
uint32_t offsetMetaCrc = *(uint32_t *) &((uint8_t *) (FIRMWARE_LOADER.update.address))[pos];
|
||
pos += 4;
|
||
uint32_t offsetMetaSize = *(uint32_t *) &((uint8_t *) (FIRMWARE_LOADER.update.address))[pos];
|
||
pos += 4;
|
||
|
||
tString32 FW_NAME;
|
||
|
||
FW_NAME.length = *(uint8_t *) &((uint8_t *) (FIRMWARE_LOADER.update.address))[pos];
|
||
pos += 1;
|
||
|
||
if (FW_NAME.length > 32) {
|
||
FW_NAME.length = 0;
|
||
} else {
|
||
memcpy(FW_NAME.data, &((uint8_t *) (FIRMWARE_LOADER.update.address))[pos], FW_NAME.length);
|
||
}
|
||
|
||
uint8_t posDel = findDelimiter(&FW_NAME, '_') + 1;
|
||
|
||
if (memcmp(&FW_NAME.data[posDel], "TELE", 4) == 0) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Получена прошивка телематики");
|
||
} else if (memcmp(&FW_NAME.data[0], "CERT", 4) == 0) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Получена прошивка ключей");
|
||
} else if (memcmp(&FW_NAME.data[posDel], "UVEOS", 5) == 0) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Получена прошивка УВЭОС");
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Получена неизвестная прошивка");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_UNKNOWN;
|
||
}
|
||
|
||
if (isFirmwareResult == EGTS_FIRMWARE_OK) {
|
||
|
||
uint32_t crc32 = 0;
|
||
for (uint32_t i = 0; i < offsetMetaSize; ++i) {
|
||
crc32 += ((uint8_t *) FIRMWARE_LOADER.update.address)[i];
|
||
}
|
||
|
||
if (crc32 != offsetMetaCrc) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка контрольной суммы (ПРОШИВКИ)");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_MY_CRC;
|
||
} else {
|
||
|
||
if (memcmp(&FW_NAME.data[posDel], "TELE", 4) == 0) {
|
||
|
||
EXT_ENV_TELE.store.AdditionalSettings->REGION_SIZE_UPDATE = env->firmwareOffset;
|
||
|
||
EraGlonassUveosDumper_ForceDump(EXT_ENV_TELE.store.uveosDumper);
|
||
|
||
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Загрузка прошивки телематики завершена");
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Необходимо перезагрузить устройство");
|
||
rst = EGTS_PC_OK;
|
||
env->rebootFirmware = true;
|
||
|
||
} else if (memcmp(&FW_NAME.data[posDel], "UVEOS", 5) == 0) {
|
||
|
||
EXT_ENV_TELE.store.AdditionalSettings->REGION_SIZE_UPDATE = env->firmwareOffset;
|
||
|
||
EraGlonassUveosDumper_ForceDump(EXT_ENV_TELE.store.uveosDumper);
|
||
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Загрузка прошивки УВЭОС завершена");
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Необходимо перезагрузить устройство");
|
||
rst = EGTS_PC_OK;
|
||
env->rebootFirmware = true;
|
||
|
||
|
||
} else if (memcmp(&FW_NAME.data[0], "CERT", 4) == 0) {
|
||
|
||
tIsFind check;
|
||
memset(&check, 0, sizeof(check));
|
||
|
||
tEgtsCertInfo *egtsCertInfo = (tEgtsCertInfo *) ((uint8_t *) (FIRMWARE_LOADER.update.address));
|
||
|
||
uint8_t *firmwareKeyBuf = &env->wb[0];
|
||
|
||
|
||
if (offsetMetaSize > (sizeof(env->wb))) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка выделения ОЗУ при загрузке ключей")
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка загрузки ключей");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_KEY;
|
||
} else {
|
||
memcpy(firmwareKeyBuf, (uint8_t *) (FIRMWARE_LOADER.update.address), offsetMetaSize);
|
||
|
||
// Если ключи зашифрованы
|
||
if (egtsCertInfo->ENC) {
|
||
|
||
struct AES_ctx ctx;
|
||
uint8_t key[16];
|
||
uint8_t iv[16];
|
||
memset(iv, '3', sizeof(key));
|
||
memset(key, '0', sizeof(key));
|
||
uint8_t offsetKey = 0;
|
||
|
||
uint32_t lenEnc = offsetMetaSize - sizeof(tEgtsCertInfo);
|
||
|
||
uint8_t IMEI_len = EXT_ENV_TELE.store.device->cgsmid.length;
|
||
if (EXT_ENV_TELE.store.device->cgsmid.length >= 2) {
|
||
if ((EXT_ENV_TELE.store.device->cgsmid.data[IMEI_len - 1] == '\n') &&
|
||
(EXT_ENV_TELE.store.device->cgsmid.data[IMEI_len - 2] == '\r')) {
|
||
IMEI_len = EXT_ENV_TELE.store.device->cgsmid.length - 2;
|
||
}
|
||
}
|
||
|
||
if (IMEI_len < 16)
|
||
offsetKey = 16 - IMEI_len;
|
||
|
||
memcpy(&key[offsetKey], EXT_ENV_TELE.store.device->cgsmid.data, IMEI_len);
|
||
|
||
|
||
AES_init_ctx_iv(&ctx, key, iv);
|
||
AES_CBC_decrypt_buffer(&ctx, &firmwareKeyBuf[sizeof(tEgtsCertInfo)],
|
||
lenEnc);
|
||
}
|
||
|
||
if (osMutexAcquire(env->gsm->gsmAt->access, 15000) == osOK) {
|
||
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Удаление старых ключей");
|
||
|
||
check = AtGsmSimComA7600_SSL_CHECK_CA(env->gsm->gsmAt,
|
||
file_ca, strlen(file_ca),
|
||
file_crt, strlen(file_crt),
|
||
file_key, strlen(file_key), 2000);
|
||
|
||
if ((!check.isFind1) && (!check.isFind2) && (!check.isFind3))
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Старые ключи удалены");
|
||
|
||
|
||
AtGsmSimComA7600_SSL_LOAD_CA(env->gsm->gsmAt,
|
||
file_ca, strlen(file_ca),
|
||
&firmwareKeyBuf[sizeof(tEgtsCertInfo)],
|
||
egtsCertInfo->SIZE_ROOT_CA,
|
||
2000);
|
||
|
||
AtGsmSimComA7600_SSL_LOAD_CA(env->gsm->gsmAt,
|
||
file_key, strlen(file_key),
|
||
&firmwareKeyBuf[sizeof(tEgtsCertInfo) +
|
||
egtsCertInfo->SIZE_ROOT_CA],
|
||
egtsCertInfo->SIZE_CLIENT_KEY, 2000);
|
||
|
||
AtGsmSimComA7600_SSL_LOAD_CA(env->gsm->gsmAt,
|
||
file_crt, strlen(file_crt),
|
||
&firmwareKeyBuf[sizeof(tEgtsCertInfo) +
|
||
egtsCertInfo->SIZE_ROOT_CA +
|
||
egtsCertInfo->SIZE_CLIENT_KEY],
|
||
egtsCertInfo->SIZE_CLIENT_CRT, 2000);
|
||
|
||
check = AtGsmSimComA7600_SSL_CHECK_CA(env->gsm->gsmAt,
|
||
file_ca, strlen(file_ca),
|
||
file_crt, strlen(file_crt),
|
||
file_key, strlen(file_key), 2000);
|
||
|
||
if ((check.isFind1) && (check.isFind2) && (check.isFind3)) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Новые ключи загружены");
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Необходимо перезагрузить устройство");
|
||
rst = EGTS_PC_OK;
|
||
env->rebootFirmware = true;
|
||
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка загрузки ключей");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_KEY;
|
||
}
|
||
|
||
osMutexRelease(env->gsm->gsmAt->access);
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Ошибка доступа при загрузке ключей");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_ACCESS;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
} else {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Получена неизвестная прошивка");
|
||
isFirmwareResult = EGTS_FIRMWARE_ERROR_UNKNOWN;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
if ((isFirmwareResult != EGTS_FIRMWARE_OK)) {
|
||
|
||
if (isFirmwareResult == EGTS_FIRMWARE_ERROR_OVERFLOW_PZU) {
|
||
rst = EGTS_PC_MODULE_MEM_FLT;
|
||
}
|
||
|
||
if ((isFirmwareResult == EGTS_FIRMWARE_ERROR_ACCESS) || (isFirmwareResult == EGTS_FIRMWARE_ERROR_KEY)) {
|
||
rst = EGTS_PC_MODULE_PROC_FLT;
|
||
}
|
||
|
||
if (isFirmwareResult == EGTS_FIRMWARE_ERROR_WRITE_PZU) {
|
||
rst = EGTS_PC_MODULE_IO_FLT;
|
||
}
|
||
|
||
if (isFirmwareResult == EGTS_FIRMWARE_ERROR_UNKNOWN) {
|
||
rst = EGTS_PC_MODULE_FW_FLT;
|
||
}
|
||
|
||
if ((isFirmwareResult == EGTS_FIRMWARE_ERROR_EGTS_CRC) || (isFirmwareResult == EGTS_FIRMWARE_ERROR_MY_CRC)) {
|
||
rst = EGTS_PC_DATACRC_ERROR;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
EgtsProcessing_SendResponse(env, EGTS_FIRMWARE_SERVICE,
|
||
EGTS_FIRMWARE_SERVICE,
|
||
EGTS_SERVICE_FLAGS_FIRMWARE,
|
||
rst,
|
||
env->egtsEnv.recordNumber);
|
||
|
||
if (env->rebootFirmware) {
|
||
LoggerInfoStatic(LOGGER, LOG_SIGN, "Автоматическая перезагрузка, через 5 сек");
|
||
SystemDelayMs(5000);
|
||
NVIC_SystemReset();
|
||
}
|
||
|
||
} |