• 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_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