• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&notify->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 }