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