• 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 <errno.h>
17 #include <linux/netlink.h>
18 #include <poll.h>
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22 
23 #include "devmgr_service.h"
24 #include "hdf_dlist.h"
25 #include "hdf_core_log.h"
26 #include "osal_mem.h"
27 #include "osal_thread.h"
28 #include "osal_time.h"
29 #include "securec.h"
30 
31 #define HDF_LOG_TAG devmgr_uevent
32 
33 #define UEVENT_SOCKET_BUFF_SIZE (256 * 1024)
34 
35 #ifndef LINE_MAX
36 #define LINE_MAX 4096
37 #endif
38 
39 #define ACTION_STR          "ACTION=="
40 #define PNP_EVENT_STR       "HDF_PNP_EVENT="
41 #define KEY_VALUE_DELIMITER "==\""
42 #define KEY_DELIMITER       "\","
43 #define UEVENT_DELIMITER    "="
44 
45 enum DEVMGR_ACTION_TYPE {
46     DEVMGR_ACTION_LOAD,
47     DEVMGR_ACTION_UNLOAD,
48     DEVMGR_ACTION_MAX,
49 };
50 
51 struct DevMgrUeventRuleCfg {
52     char *serviceName;
53     enum DEVMGR_ACTION_TYPE action;
54     struct DListHead matchKeyList;
55     struct DListHead entry;
56 };
57 
58 struct DevMgrMatchKey {
59     char *key;
60     char *value;
61     struct DListHead entry;
62 };
63 
DevMgrUeventRuleCfgList(void)64 static struct DListHead *DevMgrUeventRuleCfgList(void)
65 {
66     static struct DListHead ruleCfgList;
67     static bool initFlag = false;
68 
69     if (!initFlag) {
70         DListHeadInit(&ruleCfgList);
71         initFlag = true;
72     }
73 
74     return &ruleCfgList;
75 }
76 
DevMgrUeventReleaseKeyList(struct DListHead * keyList)77 static void DevMgrUeventReleaseKeyList(struct DListHead *keyList)
78 {
79     struct DevMgrMatchKey *matchKey = NULL;
80     struct DevMgrMatchKey *matchKeyTmp = NULL;
81 
82     if (keyList == NULL) {
83         HDF_LOGE("keyList is null");
84         return;
85     }
86     DLIST_FOR_EACH_ENTRY_SAFE(matchKey, matchKeyTmp, keyList, struct DevMgrMatchKey, entry) {
87         DListRemove(&matchKey->entry);
88         OsalMemFree(matchKey->key);
89         OsalMemFree(matchKey->value);
90         OsalMemFree(matchKey);
91     }
92 }
93 
DevMgrUeventReleaseRuleCfgList(void)94 static void DevMgrUeventReleaseRuleCfgList(void)
95 {
96     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
97     struct DevMgrUeventRuleCfg *ruleCfgTmp = NULL;
98     struct DListHead *ruleCfgList = DevMgrUeventRuleCfgList();
99 
100     DLIST_FOR_EACH_ENTRY_SAFE(ruleCfg, ruleCfgTmp, ruleCfgList, struct DevMgrUeventRuleCfg, entry) {
101         DListRemove(&ruleCfg->entry);
102         DevMgrUeventReleaseKeyList(&ruleCfg->matchKeyList);
103         OsalMemFree(ruleCfg->serviceName);
104         OsalMemFree(ruleCfg);
105     }
106 }
107 
108 // replace substrings "\n" or "\r" in a string with characters '\n' or '\r'
DevMgrUeventReplaceLineFeed(char * str,const char * subStr,char c)109 static void DevMgrUeventReplaceLineFeed(char *str, const char *subStr, char c)
110 {
111     char *ptr = NULL;
112 
113     while ((ptr = strstr(str, subStr)) != NULL) {
114         ptr[0] = c;
115         uint32_t i = 1;
116         if (strlen(ptr) < 1 || strlen(ptr) > SIZE_MAX) {
117             HDF_LOGE("strlen(ptr) overflows");
118             return;
119         }
120         const size_t len = strlen(ptr) - 1;
121         for (; i < len; i++) {
122             ptr[i] = ptr[i + 1];
123         }
124         ptr[i] = '\0';
125     }
126 
127     return;
128 }
129 
DevMgrUeventParseKeyValue(char * str,struct DevMgrMatchKey * matchKey,const char * sep)130 static int32_t DevMgrUeventParseKeyValue(char *str, struct DevMgrMatchKey *matchKey, const char *sep)
131 {
132     char *subPtr = strstr(str, sep);
133     if (subPtr == NULL) {
134         if (strstr(str, "@/") == NULL) {
135             HDF_LOGD("parse Key value failed:[%{public}s]", str);
136         }
137         return HDF_FAILURE;
138     }
139 
140     if (strlen(subPtr) < (strlen(sep) + 1)) {
141         HDF_LOGE("value part invalid:[%{public}s]", str);
142         return HDF_FAILURE;
143     }
144 
145     char *value = subPtr + strlen(sep);
146     *subPtr = '\0';
147     HDF_LOGD("key:%{private}s,value:[%{private}s]", str, value);
148     matchKey->key = strdup(str);
149     matchKey->value = strdup(value);
150     if (matchKey->key == NULL || matchKey->value == NULL) {
151         HDF_LOGE("invalid param : matchKey->key or matchKey->value");
152         return HDF_FAILURE;
153     }
154 
155     return HDF_SUCCESS;
156 }
157 
DevMgrUeventCheckRuleValid(const char * line)158 static bool DevMgrUeventCheckRuleValid(const char *line)
159 {
160     if (strlen(line) < strlen(PNP_EVENT_STR) || line[0] == '#') {
161         return false;
162     }
163 
164     if (strstr(line, PNP_EVENT_STR) == NULL) {
165         HDF_LOGE("%{public}s invalid rule: %{public}s", __func__, line);
166         return false;
167     }
168 
169     return true;
170 }
171 
DevMgrUeventParseMatchKey(char * subStr,struct DListHead * matchKeyList)172 static int32_t DevMgrUeventParseMatchKey(char *subStr, struct DListHead *matchKeyList)
173 {
174     if (subStr == NULL || strlen(subStr) == 0) {
175         HDF_LOGE("match key invalid [%{public}s]", subStr);
176         return HDF_FAILURE;
177     }
178 
179     struct DevMgrMatchKey *matchKey = (struct DevMgrMatchKey *)OsalMemCalloc(sizeof(*matchKey));
180     if (matchKey == NULL) {
181         HDF_LOGE("%{public}s OsalMemCalloc matchKey failed", __func__);
182         return HDF_FAILURE;
183     }
184     if (matchKey->value == NULL || matchKey->key == NULL) {
185         HDF_LOGW("%{public}s OsalMemCalloc matchKey->value or matchKey->key failed", __func__);
186     }
187     DListHeadInit(&matchKey->entry);
188 
189     if (DevMgrUeventParseKeyValue(subStr, matchKey, KEY_VALUE_DELIMITER) == HDF_SUCCESS) {
190         DevMgrUeventReplaceLineFeed(matchKey->value, "\\n", '\n');
191         DevMgrUeventReplaceLineFeed(matchKey->value, "\\r", '\r');
192         DListInsertTail(&matchKey->entry, matchKeyList);
193         return HDF_SUCCESS;
194     } else {
195         OsalMemFree(matchKey);
196         return HDF_FAILURE;
197     }
198 }
199 
DevMgrUeventParseHdfEvent(char * subStr,struct DevMgrUeventRuleCfg * ruleCfg)200 static int32_t DevMgrUeventParseHdfEvent(char *subStr, struct DevMgrUeventRuleCfg *ruleCfg)
201 {
202     if (strncmp(subStr, PNP_EVENT_STR, strlen(PNP_EVENT_STR)) != 0 || strlen(subStr) < strlen(PNP_EVENT_STR) + 1) {
203         HDF_LOGE("parse hdf event %{public}s failed", subStr);
204         return HDF_FAILURE;
205     }
206 
207     char *event = subStr + strlen(PNP_EVENT_STR);
208     char *ptr = strchr(event, ':');
209     if (ptr == NULL) {
210         HDF_LOGE("parse event %{public}s fail, no action", subStr);
211         return HDF_FAILURE;
212     }
213 
214     if (strlen(ptr) < strlen(":load")) {
215         HDF_LOGE("event action part invalid [%{public}s]", ptr);
216         return HDF_FAILURE;
217     }
218 
219     *ptr = '\0';
220     char *action = ptr + 1;
221 
222     // replace line feed
223     ptr = strchr(action, '\n');
224     if (ptr != NULL) {
225         *ptr = '\0';
226     }
227 
228     // replace carriage return
229     ptr = strchr(action, '\r');
230     if (ptr != NULL) {
231         *ptr = '\0';
232     }
233 
234     if (strcmp(action, "load") == 0) {
235         ruleCfg->action = DEVMGR_ACTION_LOAD;
236     } else if (strcmp(action, "unload") == 0) {
237         ruleCfg->action = DEVMGR_ACTION_UNLOAD;
238     } else {
239         HDF_LOGE("parse event action fail [%{public}s]", action);
240         return HDF_FAILURE;
241     }
242 
243     HDF_LOGD("event:%{public}s:%{public}d\n", event, ruleCfg->action);
244     ruleCfg->serviceName = strdup(event);
245     if (ruleCfg->serviceName == NULL) {
246         HDF_LOGE("ruleCfg->serviceName is NULL");
247         return HDF_FAILURE;
248     }
249     if (DListGetCount(&ruleCfg->matchKeyList) == 0) {
250         HDF_LOGE("parse failed, no match key");
251         return HDF_FAILURE;
252     }
253 
254     return HDF_SUCCESS;
255 }
256 
DevMgrUeventParseRule(char * line)257 static int32_t DevMgrUeventParseRule(char *line)
258 {
259     if (!DevMgrUeventCheckRuleValid(line)) {
260         return HDF_FAILURE;
261     }
262 
263     struct DevMgrUeventRuleCfg *ruleCfg = (struct DevMgrUeventRuleCfg *)OsalMemCalloc(sizeof(*ruleCfg));
264     if (ruleCfg == NULL) {
265         HDF_LOGE("%{public}s OsalMemCalloc ruleCfg failed", __func__);
266         return HDF_FAILURE;
267     }
268     if (ruleCfg->serviceName == NULL) {
269         HDF_LOGW("%{public}s OsalMemCalloc ruleCfg->serviceName failed", __func__);
270     }
271     DListHeadInit(&ruleCfg->matchKeyList);
272 
273     char *ptr = line;
274     char *subStr = line;
275     while (ptr != NULL && *ptr != '\0') {
276         ptr = strstr(ptr, KEY_DELIMITER);
277         if (ptr != NULL) {
278             *ptr = '\0';
279             if (DevMgrUeventParseMatchKey(subStr, &ruleCfg->matchKeyList) != HDF_SUCCESS) {
280                 goto FAIL;
281             }
282             ptr += strlen(KEY_DELIMITER);
283             subStr = ptr;
284         } else {
285             if (DevMgrUeventParseHdfEvent(subStr, ruleCfg) != HDF_SUCCESS) {
286                 goto FAIL;
287             }
288             DListInsertTail(&ruleCfg->entry, DevMgrUeventRuleCfgList());
289         }
290     }
291 
292     return HDF_SUCCESS;
293 
294 FAIL:
295     DevMgrUeventReleaseKeyList(&ruleCfg->matchKeyList);
296     OsalMemFree(ruleCfg->serviceName);
297     OsalMemFree(ruleCfg);
298     return HDF_FAILURE;
299 }
300 
DevMgrUeventDisplayRuleCfgList(void)301 static void DevMgrUeventDisplayRuleCfgList(void)
302 {
303     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
304     struct DevMgrMatchKey *matchKey = NULL;
305     struct DListHead *ruleCfgList = DevMgrUeventRuleCfgList();
306 
307     DLIST_FOR_EACH_ENTRY(ruleCfg, ruleCfgList, struct DevMgrUeventRuleCfg, entry) {
308         HDF_LOGD("service:%{public}s action:%{public}d", ruleCfg->serviceName, ruleCfg->action);
309         DLIST_FOR_EACH_ENTRY(matchKey, &ruleCfg->matchKeyList, struct DevMgrMatchKey, entry) {
310             HDF_LOGD("key:%{public}s value:%{public}s", matchKey->key, matchKey->value);
311         }
312     }
313 }
314 
DevMgrUeventParseConfig(void)315 static int32_t DevMgrUeventParseConfig(void)
316 {
317     char path[PATH_MAX] = {0};
318     int ret = sprintf_s(path, PATH_MAX - 1, "%s/hdf_pnp.cfg", HDF_CONFIG_DIR);
319     if (ret < 0) {
320         HDF_LOGE("%{public}s generate file path failed", __func__);
321         return HDF_FAILURE;
322     }
323 
324     char resolvedPath[PATH_MAX] = {0};
325     if (realpath(path, resolvedPath) == NULL) {
326         HDF_LOGE("realpath file: %{public}s failed, errno:%{public}d", path, errno);
327         return HDF_FAILURE;
328     }
329     if (strncmp(resolvedPath, HDF_CONFIG_DIR, strlen(HDF_CONFIG_DIR)) != 0) {
330         HDF_LOGE("%{public}s invalid path %{public}s", __func__, resolvedPath);
331         return HDF_FAILURE;
332     }
333     FILE *file = fopen(resolvedPath, "r");
334     if (file == NULL) {
335         HDF_LOGE("%{public}s fopen %{public}s failed:%{public}d", __func__, resolvedPath, errno);
336         return HDF_FAILURE;
337     }
338 
339     char line[LINE_MAX] = {0};
340     while (fgets(line, sizeof(line), file) != NULL) {
341         HDF_LOGD("%{public}s, %{public}s", __func__, line);
342         DevMgrUeventParseRule(line);
343         (void)memset_s(line, sizeof(line), 0, sizeof(line));
344     }
345 
346     (void)fclose(file);
347     DevMgrUeventDisplayRuleCfgList();
348 
349     return HDF_SUCCESS;
350 }
351 
DevMgrUeventSocketInit(void)352 static int32_t DevMgrUeventSocketInit(void)
353 {
354     struct sockaddr_nl addr;
355     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
356     addr.nl_family = AF_NETLINK;
357     addr.nl_pid = (__u32)getpid();
358     addr.nl_groups = 0xffffffff;
359 
360     int32_t sockfd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
361     if (sockfd < 0) {
362         HDF_LOGE("create socket failed, err = %{public}d", errno);
363         return HDF_FAILURE;
364     }
365 
366     int32_t buffSize = UEVENT_SOCKET_BUFF_SIZE;
367     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &buffSize, sizeof(buffSize)) != 0) {
368         HDF_LOGE("setsockopt: SO_RCVBUF failed err = %{public}d", errno);
369         close(sockfd);
370         sockfd = -1;
371         return HDF_FAILURE;
372     }
373 
374     const int32_t on = 1;
375     if (setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) != 0) {
376         HDF_LOGE("setsockopt: SO_PASSCRED failed, err = %{public}d", errno);
377         close(sockfd);
378         sockfd = -1;
379         return HDF_FAILURE;
380     }
381 
382     if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
383         HDF_LOGE("bind socket failed, err = %{public}d", errno);
384         close(sockfd);
385         sockfd = -1;
386         return HDF_FAILURE;
387     }
388 
389     return sockfd;
390 }
391 
DevMgrReadUeventMessage(int sockFd,char * buffer,size_t length)392 static ssize_t DevMgrReadUeventMessage(int sockFd, char *buffer, size_t length)
393 {
394     struct sockaddr_nl addr;
395     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
396 
397     struct iovec iov;
398     iov.iov_base = buffer;
399     iov.iov_len = length;
400 
401     char credMsg[CMSG_SPACE(sizeof(struct ucred))] = {0};
402     struct msghdr msghdr = {0};
403     msghdr.msg_name = &addr;
404     msghdr.msg_namelen = sizeof(addr);
405     msghdr.msg_iov = &iov;
406     msghdr.msg_iovlen = 1;
407     msghdr.msg_control = credMsg;
408     msghdr.msg_controllen = sizeof(credMsg);
409 
410     ssize_t n = recvmsg(sockFd, &msghdr, 0);
411     if (n <= 0) {
412         return HDF_FAILURE;
413     }
414 
415     struct cmsghdr *hdr = CMSG_FIRSTHDR(&msghdr);
416     if (hdr == NULL || hdr->cmsg_type != SCM_CREDENTIALS) {
417         HDF_LOGI("Unexpected control message, ignored");
418         // drop this message
419         *buffer = '\0';
420         return HDF_FAILURE;
421     }
422 
423     return n;
424 }
425 
DevMgrUeventMsgCheckValid(const char * msg,ssize_t msgLen)426 static bool DevMgrUeventMsgCheckValid(const char *msg, ssize_t msgLen)
427 {
428     (void)msgLen;
429     if (strncmp(msg, "libudev", strlen("libudev")) == 0) {
430         return false;
431     }
432     return true;
433 }
434 
DevMgrUeventMatchRule(struct DListHead * keyList,struct DListHead * ruleKeyList)435 static bool DevMgrUeventMatchRule(struct DListHead *keyList, struct DListHead *ruleKeyList)
436 {
437     struct DevMgrMatchKey *key = NULL;
438     struct DevMgrMatchKey *keyMsg = NULL;
439 
440     DLIST_FOR_EACH_ENTRY(key, ruleKeyList, struct DevMgrMatchKey, entry) {
441         bool match = false;
442         DLIST_FOR_EACH_ENTRY(keyMsg, keyList, struct DevMgrMatchKey, entry) {
443             if (strcmp(key->key, keyMsg->key) == 0) {
444                 if (strcmp(key->value, keyMsg->value) == 0) {
445                     match = true;
446                     break;
447                 } else {
448                     return false;
449                 }
450             }
451         }
452         if (!match) {
453             return false;
454         }
455     }
456 
457     return true;
458 }
459 
DevMgrUeventProcessPnPEvent(const struct DevMgrUeventRuleCfg * ruleCfg)460 static void DevMgrUeventProcessPnPEvent(const struct DevMgrUeventRuleCfg *ruleCfg)
461 {
462     struct IDevmgrService *instance = DevmgrServiceGetInstance();
463 
464     if (instance == NULL) {
465         HDF_LOGE("Getting DevmgrService instance failed");
466         return;
467     }
468 
469     if (ruleCfg->action == DEVMGR_ACTION_LOAD) {
470         instance->LoadDevice(instance, ruleCfg->serviceName);
471     } else {
472         instance->UnloadDevice(instance, ruleCfg->serviceName);
473     }
474 }
475 
DevMgrUeventMatchRules(struct DListHead * keyList,struct DListHead * ruleList)476 static bool DevMgrUeventMatchRules(struct DListHead *keyList, struct DListHead *ruleList)
477 {
478     struct DevMgrUeventRuleCfg *ruleCfg = NULL;
479 
480     DLIST_FOR_EACH_ENTRY(ruleCfg, ruleList, struct DevMgrUeventRuleCfg, entry) {
481         if (DevMgrUeventMatchRule(keyList, &ruleCfg->matchKeyList)) {
482             HDF_LOGI("%{public}s %{public}s %{public}d", __func__, ruleCfg->serviceName, ruleCfg->action);
483             DevMgrUeventProcessPnPEvent(ruleCfg);
484             return true;
485         }
486     }
487 
488     return false;
489 }
490 
DevMgrParseUevent(char * msg,ssize_t msgLen)491 static int32_t DevMgrParseUevent(char *msg, ssize_t msgLen)
492 {
493     if (!DevMgrUeventMsgCheckValid(msg, msgLen)) {
494         return HDF_FAILURE;
495     }
496 
497     struct DListHead keyList;
498     DListHeadInit(&keyList);
499     struct DevMgrMatchKey *key = NULL;
500 
501     for (char *ptr = msg; ptr < (msg + msgLen);) {
502         if (*ptr == '0') {
503             ptr++;
504             continue;
505         }
506 
507         if (key == NULL) {
508             key = (struct DevMgrMatchKey *)OsalMemCalloc(sizeof(*key));
509             if (key == NULL) {
510                 DevMgrUeventReleaseKeyList(&keyList);
511                 return HDF_FAILURE;
512             }
513             DListHeadInit(&key->entry);
514         }
515 
516         uint32_t subStrLen = (uint32_t)strlen(ptr) + 1;
517         HDF_LOGD("%{public}s %{public}d [%{private}s]", __func__, subStrLen, ptr);
518         if (DevMgrUeventParseKeyValue(ptr, key, UEVENT_DELIMITER) == HDF_SUCCESS) {
519             DListInsertHead(&key->entry, &keyList);
520             key = NULL;
521         }
522         ptr += subStrLen;
523     }
524 
525     HDF_LOGD("%{public}s {%{public}s} %{public}zd", __func__, msg, msgLen);
526     DevMgrUeventMatchRules(&keyList, DevMgrUeventRuleCfgList());
527     DevMgrUeventReleaseKeyList(&keyList);
528 
529     return HDF_SUCCESS;
530 }
531 
532 #define DEVMGR_UEVENT_MSG_SIZE  2048
533 #define DEVMGR_UEVENT_WAIT_TIME 1000
DevMgrUeventThread(void * arg)534 static int32_t DevMgrUeventThread(void *arg)
535 {
536     (void)arg;
537     int32_t sfd = DevMgrUeventSocketInit();
538     if (sfd < 0) {
539         HDF_LOGE("DevMgrUeventSocketInit get sfd error");
540         return HDF_FAILURE;
541     }
542 
543     char msg[DEVMGR_UEVENT_MSG_SIZE + 1] = {0};
544     ssize_t msgLen;
545     struct pollfd fd;
546     (void)memset_s(&fd, sizeof(fd), 0, sizeof(fd));
547     fd.fd = sfd;
548     fd.events = POLLIN | POLLERR;
549     while (true) {
550         if (poll(&fd, 1, -1) <= 0) {
551             HDF_LOGE("%{public}s poll fail %{public}d", __func__, errno);
552             OsalMSleep(DEVMGR_UEVENT_WAIT_TIME);
553             continue;
554         }
555         if (((uint32_t)fd.revents & (POLLIN | POLLERR)) != 0) {
556             int backErrno = errno;
557             msgLen = DevMgrReadUeventMessage(sfd, msg, DEVMGR_UEVENT_MSG_SIZE);
558             if (((uint32_t)fd.revents & POLLERR) != 0) {
559                 HDF_LOGE("%{public}s poll error", __func__);
560             }
561             if (msgLen <= 0) {
562                 HDF_LOGE("%{public}s recv errno: %{public}d", __func__, backErrno);
563                 continue;
564             }
565             DevMgrParseUevent(msg, msgLen);
566             (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
567         }
568     }
569 
570     DevMgrUeventReleaseRuleCfgList();
571     close(sfd);
572     sfd = -1;
573     return HDF_SUCCESS;
574 }
575 
576 #define DEVMGR_UEVENT_STACK_SIZE 100000
577 
DevMgrUeventReceiveStart(void)578 int32_t DevMgrUeventReceiveStart(void)
579 {
580     HDF_LOGI("DevMgrUeventReceiveStart");
581     if (DevMgrUeventParseConfig() == HDF_FAILURE) {
582         return HDF_FAILURE;
583     }
584 
585     struct OsalThreadParam threadCfg;
586     (void)memset_s(&threadCfg, sizeof(threadCfg), 0, sizeof(threadCfg));
587     threadCfg.name = "DevMgrUevent";
588     threadCfg.priority = OSAL_THREAD_PRI_HIGH;
589     threadCfg.stackSize = DEVMGR_UEVENT_STACK_SIZE;
590 
591     OSAL_DECLARE_THREAD(thread);
592     (void)OsalThreadCreate(&thread, (OsalThreadEntry)DevMgrUeventThread, NULL);
593     (void)OsalThreadStart(&thread, &threadCfg);
594 
595     return HDF_SUCCESS;
596 }
597