* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dslm_hidumper.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "securec.h"
#include "utils_datetime.h"
#include "utils_log.h"
#include "dslm_credential.h"
#include "dslm_device_list.h"
#include "dslm_fsm_process.h"
#include "dslm_messenger_wrapper.h"
#include "dslm_notify_node.h"
#define SPLIT_LINE "------------------------------------------------------"
#define END_LINE "\n"
#define TIME_STRING_LEN 256
#define COST_STRING_LEN 64
#define NOTIFY_NODE_MAX_CNT 1024
static pthread_mutex_t g_buffMutex = PTHREAD_MUTEX_INITIALIZER;
static const char *GetTimeStringFromTimeStamp(uint64_t timeStamp)
{
static char timeBuff[TIME_STRING_LEN] = {0};
DateTime dateTime = {0};
bool success = false;
int lockRet = pthread_mutex_lock(&g_buffMutex);
if (lockRet != 0) {
SECURITY_LOG_ERROR("pthread_mutex_lock error");
return "";
}
do {
(void)memset_s(timeBuff, TIME_STRING_LEN, 0, TIME_STRING_LEN);
if (timeStamp == 0) {
break;
}
if (!GetDateTimeByMillisecondSinceBoot(timeStamp, &dateTime)) {
SECURITY_LOG_ERROR("GetTimeStringFromTimeStamp GetDateTimeByMillisecondSinceBoot error");
break;
}
int ret =
snprintf_s(timeBuff, TIME_STRING_LEN, TIME_STRING_LEN - 1, "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.%03hu",
dateTime.year, dateTime.mon, dateTime.day, dateTime.hour, dateTime.min, dateTime.sec, dateTime.msec);
if (ret < 0) {
break;
}
success = true;
} while (0);
if (!success) {
if (snprintf_s(timeBuff, TIME_STRING_LEN, TIME_STRING_LEN - 1, "-") < 0) {
SECURITY_LOG_ERROR("GetTimeStringFromTimeStamp snprintf_s error");
}
}
lockRet = pthread_mutex_unlock(&g_buffMutex);
if (lockRet != 0) {
SECURITY_LOG_ERROR("pthread_mutex_unlock error");
}
return timeBuff;
}
static const char *GetCostTime(const uint64_t beginTime, const uint64_t endTime)
{
static char costBuff[COST_STRING_LEN] = {0};
if (beginTime == 0 || endTime == 0) {
return "";
}
if (endTime < beginTime) {
return "";
}
uint32_t cost = (uint32_t)(endTime - beginTime);
int ret = pthread_mutex_lock(&g_buffMutex);
if (ret != 0) {
SECURITY_LOG_ERROR("pthread_mutex_lock error");
return "";
}
if (snprintf_s(costBuff, COST_STRING_LEN, COST_STRING_LEN - 1, "(cost %ums)", cost) < 0) {
ret = pthread_mutex_unlock(&g_buffMutex);
if (ret != 0) {
SECURITY_LOG_ERROR("pthread_mutex_unlock error");
}
return "";
};
ret = pthread_mutex_unlock(&g_buffMutex);
if (ret != 0) {
SECURITY_LOG_ERROR("pthread_mutex_unlock error");
}
return costBuff;
}
static const char *GetMachineState(const DslmDeviceInfo *info)
{
uint32_t state = GetCurrentMachineState(info);
switch (state) {
case STATE_INIT:
return "STATE_INIT";
case STATE_WAITING_CRED_RSP:
return "STATE_WAITING_CRED_RSP";
case STATE_SUCCESS:
return "STATE_SUCCESS";
case STATE_FAILED:
return "STATE_FAILED";
default:
return "STATE_UNKOWN";
}
}
static const char *GetCreadType(const DslmDeviceInfo *info)
{
switch (info->credInfo.credType) {
case CRED_TYPE_MINI:
return "mini";
case CRED_TYPE_SMALL:
return "small";
case CRED_TYPE_STANDARD:
return "standard";
case CRED_TYPE_LARGE:
return "large";
default:
return "default";
}
}
static int32_t GetPendingNotifyNodeCnt(const DslmDeviceInfo *info)
{
int result = 0;
LockDslmStateMachine((DslmDeviceInfo *)info);
ListNode *node = NULL;
FOREACH_LIST_NODE (node, &info->notifyList) {
result++;
if (result >= NOTIFY_NODE_MAX_CNT) {
break;
}
}
UnLockDslmStateMachine((DslmDeviceInfo *)info);
return result;
}
static void GetDefaultStatus(int32_t *requestResult, int32_t *verifyResult, uint32_t *credLevel)
{
if (requestResult == NULL || verifyResult == NULL || credLevel == NULL) {
return;
}
int32_t level = 0;
const DeviceIdentify *device = GetSelfDevice(&level);
RequestObject object;
object.arraySize = (uint32_t)GetSupportedCredTypes(object.credArray, MAX_CRED_ARRAY_SIZE);
object.challenge = 0x0;
object.version = GetCurrentVersion();
DslmCredBuff *cred = NULL;
*requestResult = DefaultRequestDslmCred(device, &object, &cred);
DslmCredInfo info;
(void)memset_s(&info, sizeof(DslmCredInfo), 0, sizeof(DslmCredInfo));
*verifyResult = DefaultVerifyDslmCred(device, object.challenge, cred, &info);
*credLevel = info.credLevel;
DestroyDslmCred(cred);
}
static void PrintBanner(int fd)
{
dprintf(fd, " ___ ___ _ __ __ ___ _ _ __ __ ___ ___ ___ " END_LINE);
dprintf(fd, "| \\/ __| | | \\/ | | \\| | | | \\/ | _ \\ __| _ \\" END_LINE);
dprintf(fd, "| |) \\__ \\ |__| |\\/| | | |) | |_| | |\\/| | _/ __| /" END_LINE);
dprintf(fd, "|___/|___/____|_| |_| |___/ \\___/|_| |_|_| |___|_|_\\" END_LINE);
}
static void DumpDeviceDetails(const DslmDeviceInfo *info, int32_t fd)
{
dprintf(fd, "DEVICE_ID : %x" END_LINE, info->machine.machineId);
dprintf(fd, END_LINE);
dprintf(fd, "DEVICE_ONLINE_STATUS : %s" END_LINE, (info->onlineStatus != 0) ? "online" : "offline");
dprintf(fd, "DEVICE_ONLINE_TIME : %s" END_LINE, GetTimeStringFromTimeStamp(info->lastOnlineTime));
dprintf(fd, "DEVICE_OFFLINE_TIME : %s" END_LINE, GetTimeStringFromTimeStamp(info->lastOfflineTime));
dprintf(fd, "DEVICE_REQUEST_TIME : %s" END_LINE, GetTimeStringFromTimeStamp(info->lastRequestTime));
dprintf(fd, "DEVICE_RESPONSE_TIME : %s%s" END_LINE, GetTimeStringFromTimeStamp(info->lastResponseTime),
GetCostTime(info->lastRequestTime, info->lastResponseTime));
dprintf(fd, "DEVICE_VERIFY_TIME : %s%s" END_LINE, GetTimeStringFromTimeStamp(info->lastVerifyTime),
GetCostTime(info->lastResponseTime, info->lastVerifyTime));
dprintf(fd, END_LINE);
dprintf(fd, "DEVICE_PENDING_CNT : %d" END_LINE, GetPendingNotifyNodeCnt(info));
dprintf(fd, "DEVICE_MACHINE_STATUS : %s" END_LINE, GetMachineState(info));
dprintf(fd, "DEVICE_VERIFIED_LEVEL : %u" END_LINE, info->credInfo.credLevel);
dprintf(fd, "DEVICE_VERIFIED_RESULT : %s" END_LINE, (info->result == 0) ? "success" : "failed");
dprintf(fd, END_LINE);
dprintf(fd, "CRED_TYPE : %s" END_LINE, GetCreadType(info));
dprintf(fd, "CRED_RELEASE_TYPE : %s" END_LINE, info->credInfo.releaseType);
dprintf(fd, "CRED_SIGN_TIME : %s" END_LINE, info->credInfo.signTime);
dprintf(fd, "CRED_MANUFACTURE : %s" END_LINE, info->credInfo.manufacture);
dprintf(fd, "CRED_BAND : %s" END_LINE, info->credInfo.brand);
dprintf(fd, "CRED_MODEL : %s" END_LINE, info->credInfo.model);
dprintf(fd, "CRED_SOFTWARE_VERSION : %s" END_LINE, info->credInfo.softwareVersion);
dprintf(fd, "CRED_SECURITY_LEVEL : %s" END_LINE, info->credInfo.securityLevel);
dprintf(fd, "CRED_VERSION : %s" END_LINE, info->credInfo.version);
dprintf(fd, END_LINE);
}
static void DumpHistoryCalls(const DslmDeviceInfo *info, int32_t fd)
{
dprintf(fd, "SDK_CALL_HISTORY: " END_LINE);
ListNode *node = NULL;
int32_t index = 0;
FOREACH_LIST_NODE (node, &info->historyList) {
index++;
DslmNotifyListNode *notifyNode = LIST_ENTRY(node, DslmNotifyListNode, linkNode);
char timeStart[TIME_STRING_LEN] = {0};
if (strcpy_s(timeStart, TIME_STRING_LEN, GetTimeStringFromTimeStamp(notifyNode->start)) != EOK) {
continue;
}
char timeStop[TIME_STRING_LEN] = {0};
if (strcpy_s(timeStop, TIME_STRING_LEN, GetTimeStringFromTimeStamp(notifyNode->stop)) != EOK) {
continue;
}
uint32_t cost = (notifyNode->stop > notifyNode->start) ? (notifyNode->stop - notifyNode->start) : 0;
dprintf(fd, "#%-4d pid:%-6u seq:%-4u req:%-26s res:%-26s ret:%-4u cost:%ums" END_LINE, index, notifyNode->owner,
notifyNode->cookie, timeStart, timeStop, notifyNode->result, cost);
if (index >= NOTIFY_NODE_MAX_CNT) {
break;
}
}
}
static void DumpOneDevice(const DslmDeviceInfo *info, int32_t fd)
{
if (info == NULL) {
return;
}
dprintf(fd, SPLIT_LINE END_LINE);
DumpDeviceDetails(info, fd);
DumpHistoryCalls(info, fd);
dprintf(fd, SPLIT_LINE END_LINE);
}
static void PrintAllDevices(int fd)
{
ForEachDeviceDump(DumpOneDevice, fd);
}
static void PrintDefaultStatus(int fd)
{
int32_t requestResult = 0;
int32_t verifyResult = 0;
uint32_t credLevel = 0;
GetDefaultStatus(&requestResult, &verifyResult, &credLevel);
const time_t YEAR_TIME_2023 = 1699977600;
struct timeval timeVal = {0};
gettimeofday(&timeVal, NULL);
char *notice = timeVal.tv_sec <= YEAR_TIME_2023 ? "(please check the system time)" : "";
dprintf(fd, SPLIT_LINE END_LINE);
dprintf(fd, "REQUEST_TEST : %s" END_LINE, requestResult == SUCCESS ? "success" : "failed");
dprintf(fd, "VERIFY_TEST : %s%s" END_LINE, verifyResult == SUCCESS ? "success" : "failed", notice);
dprintf(fd, "SELF_CRED_LEVEL : %u" END_LINE, credLevel);
dprintf(fd, SPLIT_LINE END_LINE);
}
void DslmDumper(int fd)
{
PrintBanner(fd);
PrintDefaultStatus(fd);
PrintAllDevices(fd);
}