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_fsm_process.h"
17
18 #include <securec.h>
19 #include <stdbool.h>
20 #include <stddef.h>
21
22 #include "device_security_defines.h"
23 #include "utils_datetime.h"
24 #include "utils_hexstring.h"
25 #include "utils_list.h"
26 #include "utils_log.h"
27 #include "utils_mem.h"
28 #include "utils_mutex.h"
29 #include "utils_state_machine.h"
30 #include "utils_timer.h"
31
32 #include "dslm_callback_info.h"
33 #include "dslm_core_defines.h"
34 #include "dslm_cred.h"
35 #include "dslm_device_list.h"
36 #include "dslm_hitrace.h"
37 #include "dslm_inner_process.h"
38 #include "dslm_msg_serialize.h"
39 #include "dslm_notify_node.h"
40
41 #define REQUEST_INTERVAL (24 * 60 * 60 * 1000)
42
43 typedef bool DslmInfoChecker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
44 uint32_t *result);
45
46 static bool SdkTimeoutChecker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
47 uint32_t *result);
48 static bool RequestDoneChecker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
49 uint32_t *result);
50
51 static uint32_t GenerateMachineId(const DeviceIdentify *identity);
52 static bool CheckTimesAndSendCredRequest(DslmDeviceInfo *info, bool enforce);
53 static void StopSendDeviceInfoRequestTimer(DslmDeviceInfo *info);
54 static void ProcessSendDeviceInfoCallback(DslmDeviceInfo *info, DslmInfoChecker checker);
55
56 static void TimerProcessSendDeviceInfoRequestTimeOut(const void *context);
57 static void TimerProcessSdkRequestTimeout(const void *context);
58
59 static bool ProcessDeviceOnline(const StateMachine *machine, uint32_t event, const void *para);
60 static bool ProcessSendCredRequest(const StateMachine *machine, uint32_t event, const void *para);
61 static bool ProcessSdkRequest(const StateMachine *machine, uint32_t event, const void *para);
62 static bool ProcessSendRequestFailed(const StateMachine *machine, uint32_t event, const void *para);
63 static bool ProcessDeviceOffline(const StateMachine *machine, uint32_t event, const void *para);
64 static bool ProcessVerifyCredMessage(const StateMachine *machine, uint32_t event, const void *para);
65 static bool ProcessSdkTimeout(const StateMachine *machine, uint32_t event, const void *para);
66
67 static void RefreshNotifyList(DslmDeviceInfo *info);
68 static void RefreshHistoryList(DslmDeviceInfo *info);
69
GenerateMachineId(const DeviceIdentify * identity)70 static uint32_t GenerateMachineId(const DeviceIdentify *identity)
71 {
72 #define MASK_LOW 0x00ffU
73 #define MACHINE_ID_LENGTH 4U
74 #define SHIFT_LENGTH 8U
75 #define MASK_HIGH 0xff00U
76 uint16_t machineId = 0;
77 HexStringToByte((const char *)identity->identity, MACHINE_ID_LENGTH, (uint8_t *)&machineId, sizeof(machineId));
78 return ((machineId & MASK_HIGH) >> SHIFT_LENGTH) | ((machineId & MASK_LOW) << SHIFT_LENGTH);
79 }
80
TimerProcessSendDeviceInfoRequestTimeOut(const void * context)81 static void TimerProcessSendDeviceInfoRequestTimeOut(const void *context)
82 {
83 if (context == NULL) {
84 return;
85 }
86 // the context info will never be freed, so feel free use it.
87 ScheduleDslmStateMachine((DslmDeviceInfo *)context, EVENT_TIME_OUT, NULL);
88 }
89
TimerProcessSdkRequestTimeout(const void * context)90 static void TimerProcessSdkRequestTimeout(const void *context)
91 {
92 if (context == NULL) {
93 return;
94 }
95 // the context info will never be freed, so feel free use it.
96 ScheduleDslmStateMachine((DslmDeviceInfo *)context, EVENT_SDK_TIMEOUT, NULL);
97 }
98
StopSendDeviceInfoRequestTimer(DslmDeviceInfo * info)99 static void StopSendDeviceInfoRequestTimer(DslmDeviceInfo *info)
100 {
101 if (info->timeHandle != 0) {
102 UtilsStopTimerTask(info->timeHandle);
103 info->timeHandle = 0;
104 }
105 }
106
StartSendDeviceInfoRequestTimer(DslmDeviceInfo * info)107 static void StartSendDeviceInfoRequestTimer(DslmDeviceInfo *info)
108 {
109 info->timeHandle = UtilsStartOnceTimerTask(SEND_MSG_TIMEOUT_LEN, TimerProcessSendDeviceInfoRequestTimeOut, info);
110 }
111
CheckTimesAndSendCredRequest(DslmDeviceInfo * info,bool enforce)112 static bool CheckTimesAndSendCredRequest(DslmDeviceInfo *info, bool enforce)
113 {
114 #ifndef MAX_SEND_TIMES
115 #define MAX_SEND_TIMES 5
116 #endif
117
118 #ifndef SEND_MSG_TIMEOUT_LEN
119 #define SEND_MSG_TIMEOUT_LEN 40000
120 #endif
121
122 if (!enforce && info->queryTimes > MAX_SEND_TIMES) {
123 return false;
124 }
125 DslmStartProcessTraceAsync("SendCredRequest", info->machine.machineId, info->queryTimes + 1);
126 CheckAndGenerateChallenge(info);
127 SendDeviceInfoRequest(info);
128 info->queryTimes++;
129 info->lastRequestTime = GetMillisecondSinceBoot();
130
131 StopSendDeviceInfoRequestTimer(info);
132 StartSendDeviceInfoRequestTimer(info);
133 return true;
134 }
135
ProcessSendDeviceInfoCallback(DslmDeviceInfo * info,DslmInfoChecker checker)136 static void ProcessSendDeviceInfoCallback(DslmDeviceInfo *info, DslmInfoChecker checker)
137 {
138 #ifndef MAX_HISTORY_CNT
139 #define MAX_HISTORY_CNT 30U
140 #endif
141
142 if (info == NULL || checker == NULL) {
143 return;
144 }
145 ListNode *node = NULL;
146 ListNode *temp = NULL;
147 SECURITY_LOG_DEBUG("ProcessSendDeviceInfoCallback for device %{public}x.", info->machine.machineId);
148 FOREACH_LIST_NODE_SAFE (node, &info->notifyList, temp) {
149 DslmNotifyListNode *notifyNode = LIST_ENTRY(node, DslmNotifyListNode, linkNode);
150 uint32_t result;
151 DslmCallbackInfo cbInfo;
152 bool check = checker(info, notifyNode, &cbInfo, &result);
153 if (!check) {
154 continue;
155 }
156 SECURITY_LOG_DEBUG("ProcessSendDeviceInfoCallback result %{public}u for device %{public}x, level %{public}u.",
157 result, info->machine.machineId, cbInfo.level);
158
159 notifyNode->requestCallback(notifyNode->owner, notifyNode->cookie, result, &cbInfo);
160 notifyNode->stop = GetMillisecondSinceBoot();
161 notifyNode->result = result;
162
163 RemoveListNode(node);
164 DslmFinishProcessTraceAsync("SDK_GET", notifyNode->owner, notifyNode->cookie);
165
166 AddListNodeBefore(node, &info->historyList);
167 }
168
169 RefreshNotifyList(info);
170 RefreshHistoryList(info);
171 }
172
CheckNeedToResend(const DslmDeviceInfo * info)173 static bool CheckNeedToResend(const DslmDeviceInfo *info)
174 {
175 if (info->credInfo.credLevel == 0) {
176 return true;
177 }
178 if (info->lastOnlineTime < info->lastRequestTime) {
179 return true;
180 }
181 if (info->lastOnlineTime - info->lastRequestTime > (uint64_t)REQUEST_INTERVAL) {
182 return true;
183 }
184 return false;
185 }
186
ProcessDeviceOnline(const StateMachine * machine,uint32_t event,const void * para)187 static bool ProcessDeviceOnline(const StateMachine *machine, uint32_t event, const void *para)
188 {
189 DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
190 if (para != NULL) {
191 info->deviceType = *(uint32_t *)para;
192 }
193 info->onlineStatus = ONLINE_STATUS_ONLINE;
194 info->queryTimes = 0;
195 info->lastOnlineTime = GetMillisecondSinceBoot();
196 if (!CheckNeedToResend(info)) {
197 SECURITY_LOG_DEBUG("last request time is last than 24 hours");
198 ScheduleDslmStateMachine(info, EVENT_TO_SYNC, NULL);
199 return true;
200 }
201 return ProcessSendCredRequest(machine, event, para);
202 }
203
ProcessSendCredRequest(const StateMachine * machine,uint32_t event,const void * para)204 static bool ProcessSendCredRequest(const StateMachine *machine, uint32_t event, const void *para)
205 {
206 DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
207 bool enforce = (para != NULL);
208 return CheckTimesAndSendCredRequest(info, enforce);
209 }
210
ProcessSdkRequest(const StateMachine * machine,uint32_t event,const void * para)211 static bool ProcessSdkRequest(const StateMachine *machine, uint32_t event, const void *para)
212 {
213 DslmDeviceInfo *deviceInfo = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
214 DslmNotifyListNode *inputNotify = (DslmNotifyListNode *)para;
215 if (inputNotify == NULL) {
216 return false;
217 }
218
219 DslmNotifyListNode *notify = MALLOC(sizeof(DslmNotifyListNode));
220 if (notify == NULL) {
221 SECURITY_LOG_ERROR("malloc failed, notifyNode is null");
222 return false;
223 }
224 (void)memset_s(notify, sizeof(DslmNotifyListNode), 0, sizeof(DslmNotifyListNode));
225 notify->owner = inputNotify->owner;
226 notify->cookie = inputNotify->cookie;
227 notify->requestCallback = inputNotify->requestCallback;
228 notify->start = inputNotify->start;
229 notify->keep = inputNotify->keep;
230 if (notify->cookie == 0 || notify->requestCallback == NULL) {
231 SECURITY_LOG_ERROR("ProcessSdkRequest invalid cookie or callback.");
232 FREE(notify);
233 notify = NULL;
234 return false;
235 }
236
237 DslmStartProcessTraceAsync("SDK_GET", notify->owner, notify->cookie);
238 AddListNode(¬ify->linkNode, &deviceInfo->notifyList);
239 RefreshNotifyList(deviceInfo);
240 SECURITY_LOG_DEBUG(
241 "ProcessSdkRequest, device is %{public}x, owner is %{public}u, cookie is %{public}u, keep is %{public}u",
242 deviceInfo->machine.machineId, notify->owner, notify->cookie, notify->keep);
243 uint32_t state = GetCurrentMachineState(deviceInfo);
244 if (state == STATE_SUCCESS || state == STATE_FAILED || deviceInfo->credInfo.credLevel != 0) {
245 ProcessSendDeviceInfoCallback(deviceInfo, RequestDoneChecker);
246 return true;
247 }
248
249 UtilsStartOnceTimerTask(notify->keep, TimerProcessSdkRequestTimeout, deviceInfo);
250 return true;
251 }
252
ProcessSendRequestFailed(const StateMachine * machine,uint32_t event,const void * para)253 static bool ProcessSendRequestFailed(const StateMachine *machine, uint32_t event, const void *para)
254 {
255 #define ERR_SESSION_OPEN_FAILED 2
256 DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
257 if (para == NULL) {
258 return false;
259 }
260
261 uint32_t reason = *(uint32_t *)para;
262 info->result = reason;
263 if (reason == ERR_SESSION_OPEN_FAILED) {
264 info->result = ERR_MSG_OPEN_SESSION;
265 StopSendDeviceInfoRequestTimer(info);
266 ProcessSendDeviceInfoCallback(info, RequestDoneChecker);
267 return false;
268 }
269
270 return CheckTimesAndSendCredRequest(info, false);
271 }
272
ProcessDeviceOffline(const StateMachine * machine,uint32_t event,const void * para)273 static bool ProcessDeviceOffline(const StateMachine *machine, uint32_t event, const void *para)
274 {
275 DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
276 info->onlineStatus = ONLINE_STATUS_OFFLINE;
277 info->queryTimes = 0;
278 info->lastOfflineTime = GetMillisecondSinceBoot();
279 StopSendDeviceInfoRequestTimer(info);
280 ProcessSendDeviceInfoCallback(info, RequestDoneChecker);
281 return true;
282 }
283
ProcessVerifyCredMessage(const StateMachine * machine,uint32_t event,const void * para)284 static bool ProcessVerifyCredMessage(const StateMachine *machine, uint32_t event, const void *para)
285 {
286 DslmDeviceInfo *deviceInfo = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
287 MessageBuff *buff = (MessageBuff *)para;
288
289 deviceInfo->lastResponseTime = GetMillisecondSinceBoot();
290 deviceInfo->result = (uint32_t)VerifyDeviceInfoResponse(deviceInfo, buff);
291 deviceInfo->lastVerifyTime = GetMillisecondSinceBoot();
292 DslmFinishProcessTraceAsync("SendCredRequest", machine->machineId, deviceInfo->queryTimes);
293 ProcessSendDeviceInfoCallback(deviceInfo, RequestDoneChecker);
294
295 if (deviceInfo->result == SUCCESS) {
296 SECURITY_LOG_INFO("ProcessVerifyCredMessage success, level is %{public}u", deviceInfo->credInfo.credLevel);
297 StopSendDeviceInfoRequestTimer(deviceInfo);
298 return true;
299 }
300
301 (void)CheckTimesAndSendCredRequest(deviceInfo, false);
302 return false;
303 }
304
ProcessSdkTimeout(const StateMachine * machine,uint32_t event,const void * para)305 static bool ProcessSdkTimeout(const StateMachine *machine, uint32_t event, const void *para)
306 {
307 DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
308 ProcessSendDeviceInfoCallback(info, SdkTimeoutChecker);
309 return true;
310 }
311
SdkTimeoutChecker(const DslmDeviceInfo * devInfo,const DslmNotifyListNode * node,DslmCallbackInfo * cbInfo,uint32_t * result)312 static bool SdkTimeoutChecker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
313 uint32_t *result)
314 {
315 uint64_t curr = GetMillisecondSinceBoot();
316 if (node->start + node->keep > curr) {
317 return false;
318 }
319
320 SECURITY_LOG_INFO("SdkTimeout, device is %{public}x, owner is %{public}u, cookie is %{public}u, keep is %{public}u",
321 devInfo->machine.machineId, node->owner, node->cookie, node->keep);
322
323 *result = ERR_TIMEOUT;
324 cbInfo->level = 0;
325 cbInfo->extraLen = 0;
326 cbInfo->extraBuff = NULL;
327 return true;
328 }
329
RequestDoneChecker(const DslmDeviceInfo * devInfo,const DslmNotifyListNode * node,DslmCallbackInfo * cbInfo,uint32_t * result)330 static bool RequestDoneChecker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
331 uint32_t *result)
332 {
333 *result = devInfo->result;
334 cbInfo->level = devInfo->credInfo.credLevel;
335 cbInfo->extraLen = 0;
336 cbInfo->extraBuff = NULL;
337
338 SECURITY_LOG_INFO(
339 "RequestDone, device is %{public}x, owner is %{public}u, cookie is %{public}u, keep is %{public}u",
340 devInfo->machine.machineId, node->owner, node->cookie, node->keep);
341
342 return true;
343 }
344
RefreshNotifyList(DslmDeviceInfo * info)345 static void RefreshNotifyList(DslmDeviceInfo *info)
346 {
347 if (info == NULL) {
348 return;
349 }
350
351 // just refresh the notify list size
352 ListNode *node = NULL;
353 uint32_t size = 0;
354 FOREACH_LIST_NODE (node, &info->notifyList) {
355 size++;
356 }
357 info->notifyListSize = size;
358
359 SECURITY_LOG_INFO("device %{public}x 's notify list size update to %{public}u", info->machine.machineId,
360 info->notifyListSize);
361 }
362
RefreshHistoryList(DslmDeviceInfo * info)363 static void RefreshHistoryList(DslmDeviceInfo *info)
364 {
365 if (info == NULL) {
366 return;
367 }
368
369 // only hold the lasted MAX_HISTORY_CNT node
370 ListNode *node = NULL;
371 ListNode *temp = NULL;
372
373 uint32_t historyCnt = 0;
374 FOREACH_LIST_NODE_SAFE (node, &info->historyList, temp) {
375 historyCnt++;
376 }
377 uint32_t delCnt = historyCnt > MAX_HISTORY_CNT ? (historyCnt - MAX_HISTORY_CNT) : 0;
378
379 info->historyListSize = historyCnt - delCnt;
380
381 FOREACH_LIST_NODE_SAFE (node, &info->historyList, temp) {
382 if (delCnt <= 0) {
383 break;
384 }
385 delCnt--;
386 DslmNotifyListNode *notifyNode = LIST_ENTRY(node, DslmNotifyListNode, linkNode);
387 RemoveListNode(node);
388 FREE(notifyNode);
389 }
390 }
391
InitDslmStateMachine(DslmDeviceInfo * info)392 void InitDslmStateMachine(DslmDeviceInfo *info)
393 {
394 if (info == NULL) {
395 return;
396 }
397 uint32_t machineId = GenerateMachineId(&info->identity);
398 InitStateMachine(&info->machine, machineId, STATE_INIT);
399 SECURITY_LOG_INFO("InitDslmStateMachine success, machineId is %{public}x", machineId);
400 }
401
ScheduleDslmStateMachine(DslmDeviceInfo * info,uint32_t event,const void * para)402 void ScheduleDslmStateMachine(DslmDeviceInfo *info, uint32_t event, const void *para)
403 {
404 if (info == NULL) {
405 return;
406 }
407
408 static const StateNode stateNodes[] = {
409 {STATE_INIT, EVENT_DEVICE_ONLINE, ProcessDeviceOnline, STATE_WAITING_CRED_RSP, STATE_FAILED},
410 {STATE_INIT, EVENT_SDK_GET, ProcessSdkRequest, STATE_INIT, STATE_INIT},
411 {STATE_WAITING_CRED_RSP, EVENT_DEVICE_ONLINE, ProcessDeviceOnline, STATE_WAITING_CRED_RSP, STATE_FAILED},
412 {STATE_WAITING_CRED_RSP, EVENT_CRED_RSP, ProcessVerifyCredMessage, STATE_SUCCESS, STATE_FAILED},
413 {STATE_WAITING_CRED_RSP, EVENT_MSG_SEND_FAILED, ProcessSendRequestFailed, STATE_WAITING_CRED_RSP, STATE_FAILED},
414 {STATE_WAITING_CRED_RSP, EVENT_TIME_OUT, ProcessSendCredRequest, STATE_WAITING_CRED_RSP, STATE_FAILED},
415 {STATE_WAITING_CRED_RSP, EVENT_DEVICE_OFFLINE, ProcessDeviceOffline, STATE_INIT, STATE_INIT},
416 {STATE_WAITING_CRED_RSP, EVENT_TO_SYNC, NULL, STATE_SUCCESS, STATE_SUCCESS},
417 {STATE_WAITING_CRED_RSP, EVENT_SDK_GET, ProcessSdkRequest, STATE_WAITING_CRED_RSP, STATE_WAITING_CRED_RSP},
418 {STATE_WAITING_CRED_RSP, EVENT_SDK_TIMEOUT, ProcessSdkTimeout, STATE_WAITING_CRED_RSP, STATE_WAITING_CRED_RSP},
419 {STATE_SUCCESS, EVENT_DEVICE_OFFLINE, ProcessDeviceOffline, STATE_INIT, STATE_INIT},
420 {STATE_SUCCESS, EVENT_SDK_GET, ProcessSdkRequest, STATE_SUCCESS, STATE_SUCCESS},
421 {STATE_FAILED, EVENT_DEVICE_ONLINE, ProcessDeviceOnline, STATE_WAITING_CRED_RSP, STATE_FAILED},
422 {STATE_FAILED, EVENT_CRED_RSP, ProcessVerifyCredMessage, STATE_SUCCESS, STATE_FAILED},
423 {STATE_FAILED, EVENT_DEVICE_OFFLINE, ProcessDeviceOffline, STATE_INIT, STATE_INIT},
424 {STATE_FAILED, EVENT_CHECK, ProcessSendCredRequest, STATE_WAITING_CRED_RSP, STATE_WAITING_CRED_RSP},
425 {STATE_FAILED, EVENT_SDK_GET, ProcessSdkRequest, STATE_FAILED, STATE_FAILED},
426 {STATE_FAILED, EVENT_SDK_TIMEOUT, ProcessSdkTimeout, STATE_FAILED, STATE_FAILED},
427 };
428
429 static const uint32_t nodeCnt = sizeof(stateNodes) / sizeof(StateNode);
430 DslmStartStateMachineTrace(info->machine.machineId, event);
431 ScheduleMachine(stateNodes, nodeCnt, &info->machine, event, para);
432 DslmFinishProcessTrace();
433 }
434
GetCurrentMachineState(const DslmDeviceInfo * info)435 uint32_t GetCurrentMachineState(const DslmDeviceInfo *info)
436 {
437 if (info == NULL) {
438 return STATE_FAILED;
439 }
440 return info->machine.currState;
441 }
442
LockDslmStateMachine(DslmDeviceInfo * info)443 void LockDslmStateMachine(DslmDeviceInfo *info)
444 {
445 LockMutex(&info->machine.mutex);
446 }
447
UnLockDslmStateMachine(DslmDeviceInfo * info)448 void UnLockDslmStateMachine(DslmDeviceInfo *info)
449 {
450 UnlockMutex(&info->machine.mutex);
451 }