1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "dslm_hidumper.h"
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <sys/time.h>
21
22#include "securec.h"
23
24#include "utils_datetime.h"
25#include "utils_log.h"
26
27#include "dslm_credential.h"
28#include "dslm_device_list.h"
29#include "dslm_fsm_process.h"
30#include "dslm_messenger_wrapper.h"
31#include "dslm_notify_node.h"
32
33#define SPLIT_LINE "------------------------------------------------------"
34#define END_LINE "\n"
35
36#define TIME_STRING_LEN 256
37#define COST_STRING_LEN 64
38#define NOTIFY_NODE_MAX_CNT 1024
39
40static pthread_mutex_t g_buffMutex = PTHREAD_MUTEX_INITIALIZER;
41
42static const char *GetTimeStringFromTimeStamp(uint64_t timeStamp)
43{
44    static char timeBuff[TIME_STRING_LEN] = {0};
45    DateTime dateTime = {0};
46    bool success = false;
47    int lockRet = pthread_mutex_lock(&g_buffMutex);
48    if (lockRet != 0) {
49        SECURITY_LOG_ERROR("pthread_mutex_lock error");
50        return "";
51    }
52    do {
53        (void)memset_s(timeBuff, TIME_STRING_LEN, 0, TIME_STRING_LEN);
54        if (timeStamp == 0) {
55            break;
56        }
57        if (!GetDateTimeByMillisecondSinceBoot(timeStamp, &dateTime)) {
58            SECURITY_LOG_ERROR("GetTimeStringFromTimeStamp GetDateTimeByMillisecondSinceBoot error");
59            break;
60        }
61        int ret =
62            snprintf_s(timeBuff, TIME_STRING_LEN, TIME_STRING_LEN - 1, "%04hu-%02hu-%02hu %02hu:%02hu:%02hu.%03hu",
63                dateTime.year, dateTime.mon, dateTime.day, dateTime.hour, dateTime.min, dateTime.sec, dateTime.msec);
64        if (ret < 0) {
65            break;
66        }
67        success = true;
68    } while (0);
69
70    if (!success) {
71        if (snprintf_s(timeBuff, TIME_STRING_LEN, TIME_STRING_LEN - 1, "-") < 0) {
72            SECURITY_LOG_ERROR("GetTimeStringFromTimeStamp snprintf_s error");
73        }
74    }
75
76    lockRet = pthread_mutex_unlock(&g_buffMutex);
77    if (lockRet != 0) {
78        SECURITY_LOG_ERROR("pthread_mutex_unlock error");
79    }
80    return timeBuff;
81}
82
83static const char *GetCostTime(const uint64_t beginTime, const uint64_t endTime)
84{
85    static char costBuff[COST_STRING_LEN] = {0};
86
87    if (beginTime == 0 || endTime == 0) {
88        return "";
89    }
90
91    if (endTime < beginTime) {
92        return "";
93    }
94    uint32_t cost = (uint32_t)(endTime - beginTime);
95
96    int ret = pthread_mutex_lock(&g_buffMutex);
97    if (ret != 0) {
98        SECURITY_LOG_ERROR("pthread_mutex_lock error");
99        return "";
100    }
101
102    if (snprintf_s(costBuff, COST_STRING_LEN, COST_STRING_LEN - 1, "(cost %ums)", cost) < 0) {
103        ret = pthread_mutex_unlock(&g_buffMutex);
104        if (ret != 0) {
105            SECURITY_LOG_ERROR("pthread_mutex_unlock error");
106        }
107        return "";
108    };
109
110    ret = pthread_mutex_unlock(&g_buffMutex);
111    if (ret != 0) {
112        SECURITY_LOG_ERROR("pthread_mutex_unlock error");
113    }
114    return costBuff;
115}
116
117static const char *GetMachineState(const DslmDeviceInfo *info)
118{
119    uint32_t state = GetCurrentMachineState(info);
120    switch (state) {
121        case STATE_INIT:
122            return "STATE_INIT";
123        case STATE_WAITING_CRED_RSP:
124            return "STATE_WAITING_CRED_RSP";
125        case STATE_SUCCESS:
126            return "STATE_SUCCESS";
127        case STATE_FAILED:
128            return "STATE_FAILED";
129        default:
130            return "STATE_UNKOWN";
131    }
132}
133
134static const char *GetCreadType(const DslmDeviceInfo *info)
135{
136    switch (info->credInfo.credType) {
137        case CRED_TYPE_MINI:
138            return "mini";
139        case CRED_TYPE_SMALL:
140            return "small";
141        case CRED_TYPE_STANDARD:
142            return "standard";
143        case CRED_TYPE_LARGE:
144            return "large";
145        default:
146            return "default";
147    }
148}
149
150static int32_t GetPendingNotifyNodeCnt(const DslmDeviceInfo *info)
151{
152    int result = 0;
153    LockDslmStateMachine((DslmDeviceInfo *)info);
154    ListNode *node = NULL;
155    FOREACH_LIST_NODE (node, &info->notifyList) {
156        result++;
157        if (result >= NOTIFY_NODE_MAX_CNT) {
158            break;
159        }
160    }
161    UnLockDslmStateMachine((DslmDeviceInfo *)info);
162    return result;
163}
164
165static void GetDefaultStatus(int32_t *requestResult, int32_t *verifyResult, uint32_t *credLevel)
166{
167    if (requestResult == NULL || verifyResult == NULL || credLevel == NULL) {
168        return;
169    }
170
171    int32_t level = 0;
172    const DeviceIdentify *device = GetSelfDevice(&level);
173    RequestObject object;
174
175    object.arraySize = (uint32_t)GetSupportedCredTypes(object.credArray, MAX_CRED_ARRAY_SIZE);
176    object.challenge = 0x0;
177    object.version = GetCurrentVersion();
178
179    DslmCredBuff *cred = NULL;
180    *requestResult = DefaultRequestDslmCred(device, &object, &cred);
181
182    DslmCredInfo info;
183    (void)memset_s(&info, sizeof(DslmCredInfo), 0, sizeof(DslmCredInfo));
184
185    *verifyResult = DefaultVerifyDslmCred(device, object.challenge, cred, &info);
186    *credLevel = info.credLevel;
187    DestroyDslmCred(cred);
188}
189
190static void PrintBanner(int fd)
191{
192    dprintf(fd, " ___  ___ _    __  __   ___  _   _ __  __ ___ ___ ___ " END_LINE);
193    dprintf(fd, "|   \\/ __| |  |  \\/  | |   \\| | | |  \\/  | _ \\ __| _ \\" END_LINE);
194    dprintf(fd, "| |) \\__ \\ |__| |\\/| | | |) | |_| | |\\/| |  _/ __|   /" END_LINE);
195    dprintf(fd, "|___/|___/____|_|  |_| |___/ \\___/|_|  |_|_| |___|_|_\\" END_LINE);
196}
197
198static void DumpDeviceDetails(const DslmDeviceInfo *info, int32_t fd)
199{
200    dprintf(fd, "DEVICE_ID                 : %x" END_LINE, info->machine.machineId);
201    dprintf(fd, END_LINE);
202
203    dprintf(fd, "DEVICE_ONLINE_STATUS      : %s" END_LINE, (info->onlineStatus != 0) ? "online" : "offline");
204    dprintf(fd, "DEVICE_ONLINE_TIME        : %s" END_LINE, GetTimeStringFromTimeStamp(info->lastOnlineTime));
205    dprintf(fd, "DEVICE_OFFLINE_TIME       : %s" END_LINE, GetTimeStringFromTimeStamp(info->lastOfflineTime));
206    dprintf(fd, "DEVICE_REQUEST_TIME       : %s" END_LINE, GetTimeStringFromTimeStamp(info->lastRequestTime));
207    dprintf(fd, "DEVICE_RESPONSE_TIME      : %s%s" END_LINE, GetTimeStringFromTimeStamp(info->lastResponseTime),
208        GetCostTime(info->lastRequestTime, info->lastResponseTime));
209    dprintf(fd, "DEVICE_VERIFY_TIME        : %s%s" END_LINE, GetTimeStringFromTimeStamp(info->lastVerifyTime),
210        GetCostTime(info->lastResponseTime, info->lastVerifyTime));
211    dprintf(fd, END_LINE);
212
213    dprintf(fd, "DEVICE_PENDING_CNT        : %d" END_LINE, GetPendingNotifyNodeCnt(info));
214    dprintf(fd, "DEVICE_MACHINE_STATUS     : %s" END_LINE, GetMachineState(info));
215    dprintf(fd, "DEVICE_VERIFIED_LEVEL     : %u" END_LINE, info->credInfo.credLevel);
216    dprintf(fd, "DEVICE_VERIFIED_RESULT    : %s" END_LINE, (info->result == 0) ? "success" : "failed");
217    dprintf(fd, END_LINE);
218
219    dprintf(fd, "CRED_TYPE                 : %s" END_LINE, GetCreadType(info));
220    dprintf(fd, "CRED_RELEASE_TYPE         : %s" END_LINE, info->credInfo.releaseType);
221    dprintf(fd, "CRED_SIGN_TIME            : %s" END_LINE, info->credInfo.signTime);
222    dprintf(fd, "CRED_MANUFACTURE          : %s" END_LINE, info->credInfo.manufacture);
223    dprintf(fd, "CRED_BAND                 : %s" END_LINE, info->credInfo.brand);
224    dprintf(fd, "CRED_MODEL                : %s" END_LINE, info->credInfo.model);
225    dprintf(fd, "CRED_SOFTWARE_VERSION     : %s" END_LINE, info->credInfo.softwareVersion);
226    dprintf(fd, "CRED_SECURITY_LEVEL       : %s" END_LINE, info->credInfo.securityLevel);
227    dprintf(fd, "CRED_VERSION              : %s" END_LINE, info->credInfo.version);
228    dprintf(fd, END_LINE);
229}
230
231static void DumpHistoryCalls(const DslmDeviceInfo *info, int32_t fd)
232{
233    dprintf(fd, "SDK_CALL_HISTORY: " END_LINE);
234    ListNode *node = NULL;
235    int32_t index = 0;
236    FOREACH_LIST_NODE (node, &info->historyList) {
237        index++;
238        DslmNotifyListNode *notifyNode = LIST_ENTRY(node, DslmNotifyListNode, linkNode);
239
240        char timeStart[TIME_STRING_LEN] = {0};
241        if (strcpy_s(timeStart, TIME_STRING_LEN, GetTimeStringFromTimeStamp(notifyNode->start)) != EOK) {
242            continue;
243        }
244        char timeStop[TIME_STRING_LEN] = {0};
245        if (strcpy_s(timeStop, TIME_STRING_LEN, GetTimeStringFromTimeStamp(notifyNode->stop)) != EOK) {
246            continue;
247        }
248
249        uint32_t cost = (notifyNode->stop > notifyNode->start) ? (notifyNode->stop - notifyNode->start) : 0;
250        dprintf(fd, "#%-4d pid:%-6u seq:%-4u req:%-26s res:%-26s ret:%-4u cost:%ums" END_LINE, index, notifyNode->owner,
251            notifyNode->cookie, timeStart, timeStop, notifyNode->result, cost);
252
253        if (index >= NOTIFY_NODE_MAX_CNT) {
254            break;
255        }
256    }
257}
258
259static void DumpOneDevice(const DslmDeviceInfo *info, int32_t fd)
260{
261    if (info == NULL) {
262        return;
263    }
264
265    dprintf(fd, SPLIT_LINE END_LINE);
266    DumpDeviceDetails(info, fd);
267    DumpHistoryCalls(info, fd);
268    dprintf(fd, SPLIT_LINE END_LINE);
269}
270
271static void PrintAllDevices(int fd)
272{
273    ForEachDeviceDump(DumpOneDevice, fd);
274}
275
276static void PrintDefaultStatus(int fd)
277{
278    int32_t requestResult = 0;
279    int32_t verifyResult = 0;
280    uint32_t credLevel = 0;
281
282    GetDefaultStatus(&requestResult, &verifyResult, &credLevel);
283
284    const time_t YEAR_TIME_2023 = 1699977600;
285    struct timeval timeVal = {0};
286    gettimeofday(&timeVal, NULL);
287    char *notice = timeVal.tv_sec <= YEAR_TIME_2023 ? "(please check the system time)" : "";
288
289    dprintf(fd, SPLIT_LINE END_LINE);
290    dprintf(fd, "REQUEST_TEST              : %s" END_LINE, requestResult == SUCCESS ? "success" : "failed");
291    dprintf(fd, "VERIFY_TEST               : %s%s" END_LINE, verifyResult == SUCCESS ? "success" : "failed", notice);
292    dprintf(fd, "SELF_CRED_LEVEL           : %u" END_LINE, credLevel);
293    dprintf(fd, SPLIT_LINE END_LINE);
294}
295
296void DslmDumper(int fd)
297{
298    PrintBanner(fd);
299    PrintDefaultStatus(fd);
300    PrintAllDevices(fd);
301}