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 
40 static pthread_mutex_t g_buffMutex = PTHREAD_MUTEX_INITIALIZER;
41 
GetTimeStringFromTimeStamp(uint64_t timeStamp)42 static 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 
GetCostTime(const uint64_t beginTime, const uint64_t endTime)83 static 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 
GetMachineState(const DslmDeviceInfo *info)117 static 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 
GetCreadType(const DslmDeviceInfo *info)134 static 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 
GetPendingNotifyNodeCnt(const DslmDeviceInfo *info)150 static 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 
GetDefaultStatus(int32_t *requestResult, int32_t *verifyResult, uint32_t *credLevel)165 static 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 
PrintBanner(int fd)190 static 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 
DumpDeviceDetails(const DslmDeviceInfo *info, int32_t fd)198 static 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 
DumpHistoryCalls(const DslmDeviceInfo *info, int32_t fd)231 static 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 
DumpOneDevice(const DslmDeviceInfo *info, int32_t fd)259 static 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 
PrintAllDevices(int fd)271 static void PrintAllDevices(int fd)
272 {
273     ForEachDeviceDump(DumpOneDevice, fd);
274 }
275 
PrintDefaultStatus(int fd)276 static 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 
DslmDumper(int fd)296 void DslmDumper(int fd)
297 {
298     PrintBanner(fd);
299     PrintDefaultStatus(fd);
300     PrintAllDevices(fd);
301 }