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