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(¬ify->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 }