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