• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <stdbool.h>
19 
20 #include "utils_datetime.h"
21 #include "utils_hexstring.h"
22 #include "utils_log.h"
23 #include "utils_mem.h"
24 #include "utils_state_machine.h"
25 #include "utils_timer.h"
26 
27 #include "dslm_device_list.h"
28 #include "dslm_inner_process.h"
29 #include "dslm_notify_node.h"
30 
31 typedef bool DslmInfoChecker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
32     uint32_t *result);
33 
34 static bool SdkTimeoutCheker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
35     uint32_t *result);
36 static bool RequestDoneCheker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
37     uint32_t *result);
38 
39 static uint32_t GenerateMachineId(const DeviceIdentify *identity);
40 static bool CheckTimesAndSendCredRequest(DslmDeviceInfo *info, bool enforce);
41 static void StopSendDeviceInfoRequestTimer(DslmDeviceInfo *info);
42 static void ProcessSendDeviceInfoCallback(DslmDeviceInfo *info, DslmInfoChecker checker);
43 
44 static void TimerProcessSendDeviceInfoRequestTimeOut(const void *context);
45 static void TimerProcessSdkRequestTimeout(const void *context);
46 
47 static bool ProcessDeviceOnline(const StateMachine *machine, uint32_t event, const void *para);
48 static bool ProcessSendCredRequest(const StateMachine *machine, uint32_t event, const void *para);
49 static bool ProcessSdkRequest(const StateMachine *machine, uint32_t event, const void *para);
50 static bool ProcessSendRequestFailed(const StateMachine *machine, uint32_t event, const void *para);
51 static bool ProcessDeviceOffline(const StateMachine *machine, uint32_t event, const void *para);
52 static bool ProcessVerifyCredMessage(const StateMachine *machine, uint32_t event, const void *para);
53 static bool ProcessSdkTimeout(const StateMachine *machine, uint32_t event, const void *para);
54 
GenerateMachineId(const DeviceIdentify * identity)55 static uint32_t GenerateMachineId(const DeviceIdentify *identity)
56 {
57 #define MASK_LOW 0x00ff
58 #define MACHINE_ID_LENGTH 4
59 #define SHIFT_LENGTH 8
60 #define MASK_HIGH 0xff00
61     uint16_t machineId = 0;
62     HexStringToByte((const char *)identity->identity, MACHINE_ID_LENGTH, (uint8_t *)&machineId, sizeof(machineId));
63     return ((machineId & MASK_HIGH) >> SHIFT_LENGTH) | ((machineId & MASK_LOW) << SHIFT_LENGTH);
64 }
65 
TimerProcessSendDeviceInfoRequestTimeOut(const void * context)66 static void TimerProcessSendDeviceInfoRequestTimeOut(const void *context)
67 {
68     if (context == NULL) {
69         return;
70     }
71     // the context info will nerver be freed, so feel free use it.
72     ScheduleDslmStateMachine((DslmDeviceInfo *)context, EVENT_TIME_OUT, NULL);
73 }
74 
TimerProcessSdkRequestTimeout(const void * context)75 static void TimerProcessSdkRequestTimeout(const void *context)
76 {
77     if (context == NULL) {
78         return;
79     }
80     // the context info will nerver be freed, so feel free use it.
81     ScheduleDslmStateMachine((DslmDeviceInfo *)context, EVENT_SDK_TIMEOUT, NULL);
82 }
83 
StopSendDeviceInfoRequestTimer(DslmDeviceInfo * info)84 static void StopSendDeviceInfoRequestTimer(DslmDeviceInfo *info)
85 {
86     if (info->timeHandle != 0) {
87         StopTimerTask(info->timeHandle);
88         info->timeHandle = 0;
89     }
90 }
91 
StartSendDeviceInfoRequestTimer(DslmDeviceInfo * info)92 static void StartSendDeviceInfoRequestTimer(DslmDeviceInfo *info)
93 {
94     info->timeHandle = StartOnceTimerTask(SEND_MSG_TIMEOUT_LEN, TimerProcessSendDeviceInfoRequestTimeOut, info);
95 }
96 
CheckTimesAndSendCredRequest(DslmDeviceInfo * info,bool enforce)97 static bool CheckTimesAndSendCredRequest(DslmDeviceInfo *info, bool enforce)
98 {
99 #ifndef MAX_SEND_TIMES
100 #define MAX_SEND_TIMES 5
101 #endif
102 
103 #ifndef SEND_MSG_TIMEOUT_LEN
104 #define SEND_MSG_TIMEOUT_LEN 40000
105 #endif
106 
107     if (!enforce && info->queryTimes > MAX_SEND_TIMES) {
108         return false;
109     }
110 
111     CheckAndGenerateChallenge(info);
112     SendDeviceInfoRequest(info);
113     info->queryTimes++;
114     info->lastRequestTime = GetMillisecondSinceBoot();
115     StopSendDeviceInfoRequestTimer(info);
116     StartSendDeviceInfoRequestTimer(info);
117     return true;
118 }
119 
ProcessSendDeviceInfoCallback(DslmDeviceInfo * info,DslmInfoChecker checker)120 static void ProcessSendDeviceInfoCallback(DslmDeviceInfo *info, DslmInfoChecker checker)
121 {
122     if (info == NULL || checker == NULL) {
123         return;
124     }
125     ListNode *node = NULL;
126     ListNode *temp = NULL;
127     SECURITY_LOG_DEBUG("ProcessSendDeviceInfoCallback for device %{public}x.", info->machine.machineId);
128     FOREACH_LIST_NODE_SAFE (node, &info->notifyList, temp) {
129         DslmNotifyListNode *notifyNode = LIST_ENTRY(node, DslmNotifyListNode, linkNode);
130         uint32_t result;
131         DslmCallbackInfo cbInfo;
132         bool check = checker(info, notifyNode, &cbInfo, &result);
133         if (!check) {
134             continue;
135         }
136         SECURITY_LOG_DEBUG("ProcessSendDeviceInfoCallback result %{public}u for device %{public}x, level %{public}u.",
137             result, info->machine.machineId, cbInfo.level);
138         notifyNode->requestCallback(notifyNode->owner, notifyNode->cookie, result, &cbInfo);
139         RemoveListNode(node);
140         FREE(notifyNode);
141     }
142 }
143 
ProcessDeviceOnline(const StateMachine * machine,uint32_t event,const void * para)144 static bool ProcessDeviceOnline(const StateMachine *machine, uint32_t event, const void *para)
145 {
146     DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
147     if (para != NULL) {
148         info->deviceType = *(uint32_t *)para;
149     }
150     info->onlineStatus = ONLINE_STATUS_ONLINE;
151     info->queryTimes = 0;
152     info->lastOnlineTime = GetMillisecondSinceBoot();
153     return ProcessSendCredRequest(machine, event, para);
154 }
155 
ProcessSendCredRequest(const StateMachine * machine,uint32_t event,const void * para)156 static bool ProcessSendCredRequest(const StateMachine *machine, uint32_t event, const void *para)
157 {
158     DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
159     bool enforce = (para != NULL);
160     return CheckTimesAndSendCredRequest(info, enforce);
161 }
162 
ProcessSdkRequest(const StateMachine * machine,uint32_t event,const void * para)163 static bool ProcessSdkRequest(const StateMachine *machine, uint32_t event, const void *para)
164 {
165     DslmDeviceInfo *deviceInfo = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
166     DslmNotifyListNode *notify = (DslmNotifyListNode *)para;
167     if (notify == NULL) {
168         return false;
169     }
170 
171     if (notify->cookie == 0 || notify->requestCallback == NULL) {
172         SECURITY_LOG_ERROR("ProcessSdkRequest invalied cookie or callback.");
173         FREE(notify);
174         return false;
175     }
176 
177     AddListNode(&notify->linkNode, &deviceInfo->notifyList);
178     SECURITY_LOG_DEBUG(
179         "ProcessSdkRequest, device is %{public}x, owner is %{public}u, cookie is %{public}u, keep is %{public}u",
180         deviceInfo->machine.machineId, notify->owner, notify->cookie, notify->keep);
181     uint32_t state = GetCurrentMachineState(deviceInfo);
182     if (state == STATE_SUCCESS || state == STATE_FAILED || deviceInfo->credInfo.credLevel != 0) {
183         ProcessSendDeviceInfoCallback(deviceInfo, RequestDoneCheker);
184         return true;
185     }
186 
187     StartOnceTimerTask(notify->keep, TimerProcessSdkRequestTimeout, deviceInfo);
188     return true;
189 }
190 
ProcessSendRequestFailed(const StateMachine * machine,uint32_t event,const void * para)191 static bool ProcessSendRequestFailed(const StateMachine *machine, uint32_t event, const void *para)
192 {
193 #define ERR_SESSION_OPEN_FAILED 2
194     DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
195     if (para == NULL) {
196         return false;
197     }
198 
199     uint32_t reason = *(uint32_t *)para;
200     info->result = reason;
201     if (reason == ERR_SESSION_OPEN_FAILED) {
202         info->result = ERR_MSG_OPEN_SESSION;
203         StopSendDeviceInfoRequestTimer(info);
204         ProcessSendDeviceInfoCallback(info, RequestDoneCheker);
205         return false;
206     }
207 
208     return CheckTimesAndSendCredRequest(info, false);
209 }
210 
ProcessDeviceOffline(const StateMachine * machine,uint32_t event,const void * para)211 static bool ProcessDeviceOffline(const StateMachine *machine, uint32_t event, const void *para)
212 {
213     DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
214     info->onlineStatus = ONLINE_STATUS_OFFLINE;
215     info->queryTimes = 0;
216     info->lastOfflineTime = GetMillisecondSinceBoot();
217     StopSendDeviceInfoRequestTimer(info);
218     return true;
219 }
220 
ProcessVerifyCredMessage(const StateMachine * machine,uint32_t event,const void * para)221 static bool ProcessVerifyCredMessage(const StateMachine *machine, uint32_t event, const void *para)
222 {
223     DslmDeviceInfo *deviceInfo = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
224     MessageBuff *buff = (MessageBuff *)para;
225 
226     deviceInfo->lastResponseTime = GetMillisecondSinceBoot();
227 
228     deviceInfo->result = (uint32_t)VerifyDeviceInfoResponse(deviceInfo, buff);
229     ProcessSendDeviceInfoCallback(deviceInfo, RequestDoneCheker);
230 
231     if (deviceInfo->result == SUCCESS) {
232         SECURITY_LOG_INFO("ProcessVerifyCredMessage success, level is %{public}u", deviceInfo->credInfo.credLevel);
233         StopSendDeviceInfoRequestTimer(deviceInfo);
234         return true;
235     }
236 
237     CheckTimesAndSendCredRequest(deviceInfo, false);
238     return false;
239 }
240 
ProcessSdkTimeout(const StateMachine * machine,uint32_t event,const void * para)241 static bool ProcessSdkTimeout(const StateMachine *machine, uint32_t event, const void *para)
242 {
243     DslmDeviceInfo *info = STATE_MACHINE_ENTRY(machine, DslmDeviceInfo, machine);
244     ProcessSendDeviceInfoCallback(info, SdkTimeoutCheker);
245     return true;
246 }
247 
SdkTimeoutCheker(const DslmDeviceInfo * devInfo,const DslmNotifyListNode * node,DslmCallbackInfo * cbInfo,uint32_t * result)248 static bool SdkTimeoutCheker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
249     uint32_t *result)
250 {
251     uint64_t curr = GetMillisecondSinceBoot();
252     if (node->start + node->keep > curr) {
253         return false;
254     }
255 
256     SECURITY_LOG_INFO("SdkTimeout, device is %{public}x, owner is %{public}u, cookie is %{public}u, keep is %{public}u",
257         devInfo->machine.machineId, node->owner, node->cookie, node->keep);
258 
259     *result = ERR_TIMEOUT;
260     cbInfo->level = 0;
261     cbInfo->extraLen = 0;
262     cbInfo->extraBuff = NULL;
263     return true;
264 }
265 
RequestDoneCheker(const DslmDeviceInfo * devInfo,const DslmNotifyListNode * node,DslmCallbackInfo * cbInfo,uint32_t * result)266 static bool RequestDoneCheker(const DslmDeviceInfo *devInfo, const DslmNotifyListNode *node, DslmCallbackInfo *cbInfo,
267     uint32_t *result)
268 {
269     *result = devInfo->result;
270     cbInfo->level = devInfo->credInfo.credLevel;
271     cbInfo->extraLen = 0;
272     cbInfo->extraBuff = NULL;
273 
274     SECURITY_LOG_INFO(
275         "RequestDone, device is %{public}x, owner is %{public}u, cookie is %{public}u, keep is %{public}u",
276         devInfo->machine.machineId, node->owner, node->cookie, node->keep);
277 
278     return true;
279 }
280 
InitDslmStateMachine(DslmDeviceInfo * info)281 void InitDslmStateMachine(DslmDeviceInfo *info)
282 {
283     if (info == NULL) {
284         return;
285     }
286     uint32_t machineId = GenerateMachineId(&info->identity);
287     InitStateMachine(&info->machine, machineId, STATE_INIT);
288     SECURITY_LOG_INFO("InitDslmStateMachine success, machineId is %{public}x", machineId);
289 }
290 
ScheduleDslmStateMachine(DslmDeviceInfo * info,uint32_t event,const void * para)291 void ScheduleDslmStateMachine(DslmDeviceInfo *info, uint32_t event, const void *para)
292 {
293     if (info == NULL) {
294         return;
295     }
296 
297     static const StateNode stateNodes[] = {
298         {STATE_INIT, EVENT_DEVICE_ONLINE, ProcessDeviceOnline, STATE_WAITING_CRED_RSP, STATE_FAILED},
299         {STATE_INIT, EVENT_SDK_GET, ProcessSdkRequest, STATE_INIT, STATE_INIT},
300         {STATE_WAITING_CRED_RSP, EVENT_DEVICE_ONLINE, ProcessDeviceOnline, STATE_WAITING_CRED_RSP, STATE_FAILED},
301         {STATE_WAITING_CRED_RSP, EVENT_CRED_RSP, ProcessVerifyCredMessage, STATE_SUCCESS, STATE_FAILED},
302         {STATE_WAITING_CRED_RSP, EVENT_MSG_SEND_FAILED, ProcessSendRequestFailed, STATE_WAITING_CRED_RSP, STATE_FAILED},
303         {STATE_WAITING_CRED_RSP, EVENT_TIME_OUT, ProcessSendCredRequest, STATE_WAITING_CRED_RSP, STATE_FAILED},
304         {STATE_WAITING_CRED_RSP, EVENT_DEVICE_OFFLINE, ProcessDeviceOffline, STATE_INIT, STATE_INIT},
305         {STATE_WAITING_CRED_RSP, EVENT_SDK_GET, ProcessSdkRequest, STATE_WAITING_CRED_RSP, STATE_WAITING_CRED_RSP},
306         {STATE_WAITING_CRED_RSP, EVENT_SDK_TIMEOUT, ProcessSdkTimeout, STATE_WAITING_CRED_RSP, STATE_WAITING_CRED_RSP},
307         {STATE_SUCCESS, EVENT_DEVICE_OFFLINE, ProcessDeviceOffline, STATE_INIT, STATE_INIT},
308         {STATE_SUCCESS, EVENT_SDK_GET, ProcessSdkRequest, STATE_SUCCESS, STATE_SUCCESS},
309         {STATE_FAILED, EVENT_DEVICE_ONLINE, ProcessDeviceOnline, STATE_WAITING_CRED_RSP, STATE_FAILED},
310         {STATE_FAILED, EVENT_CRED_RSP, ProcessVerifyCredMessage, STATE_SUCCESS, STATE_FAILED},
311         {STATE_FAILED, EVENT_DEVICE_OFFLINE, ProcessDeviceOffline, STATE_INIT, STATE_INIT},
312         {STATE_FAILED, EVENT_CHECK, ProcessSendCredRequest, STATE_WAITING_CRED_RSP, STATE_WAITING_CRED_RSP},
313         {STATE_FAILED, EVENT_SDK_GET, ProcessSdkRequest, STATE_FAILED, STATE_FAILED},
314         {STATE_FAILED, EVENT_SDK_TIMEOUT, ProcessSdkTimeout, STATE_FAILED, STATE_FAILED},
315     };
316 
317     static const uint32_t nodeCnt = sizeof(stateNodes) / sizeof(StateNode);
318 
319     ScheduleMachine(stateNodes, nodeCnt, &info->machine, event, para);
320 }
321 
GetCurrentMachineState(const DslmDeviceInfo * info)322 uint32_t GetCurrentMachineState(const DslmDeviceInfo *info)
323 {
324     if (info == NULL) {
325         return STATE_FAILED;
326     }
327     return info->machine.currState;
328 }