• 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 #include "ddk_uevent_handle.h"
16 
17 #include <linux/netlink.h>
18 #include <poll.h>
19 #include <pthread.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include "ddk_device_manager.h"
26 #include "ddk_pnp_listener_mgr.h"
27 #include "ddk_uevent_queue.h"
28 #include "hdf_base.h"
29 #include "hdf_io_service_if.h"
30 #include "hdf_log.h"
31 #include "osal_time.h"
32 #include "securec.h"
33 #include "usbfn_uevent_handle.h"
34 #include "usbd_wrapper.h"
35 #include "usb_accessory_uevent_handle.h"
36 
37 #define HDF_LOG_TAG usb_ddk_uevent
38 
39 #ifdef USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
40 #define UEVENT_MSG_LEN          2048
41 #define UEVENT_SOCKET_GROUPS    0xffffffff
42 #define UEVENT_SOCKET_BUFF_SIZE (64 * 1024)
43 #define TIMEVAL_SECOND          0
44 #define TIMEVAL_USECOND         (100 * 1000)
45 #define UEVENT_POLL_WAIT_TIME   100
46 #define MAX_ERR_TIMES           10
47 
DdkUeventOpen(int * fd)48 static int DdkUeventOpen(int *fd)
49 {
50     struct sockaddr_nl addr;
51     if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != HDF_SUCCESS) {
52         HDF_LOGE("%{public}s: addr memset_s failed!", __func__);
53         return HDF_FAILURE;
54     }
55     addr.nl_family = AF_NETLINK;
56     addr.nl_pid = (uint32_t)getpid();
57     addr.nl_groups = UEVENT_SOCKET_GROUPS;
58 
59     int socketfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
60     if (socketfd < 0) {
61         HDF_LOGE("%{public}s: socketfd failed! ret = %{public}d", __func__, socketfd);
62         return HDF_FAILURE;
63     }
64 
65     int buffSize = UEVENT_SOCKET_BUFF_SIZE;
66     if (setsockopt(socketfd, SOL_SOCKET, SO_RCVBUF, &buffSize, sizeof(buffSize)) != 0) {
67         HDF_LOGE("%{public}s: setsockopt failed!", __func__);
68         close(socketfd);
69         return HDF_FAILURE;
70     }
71 
72     const int32_t on = 1; // turn on passcred
73     if (setsockopt(socketfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) != 0) {
74         HDF_LOGE("setsockopt failed!");
75         close(socketfd);
76         return HDF_FAILURE;
77     }
78 
79     if (bind(socketfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
80         HDF_LOGE("%{public}s: bind socketfd failed!", __func__);
81         close(socketfd);
82         return HDF_FAILURE;
83     }
84     *fd = socketfd;
85     return HDF_SUCCESS;
86 }
87 
DdkHandleUevent(const char msg[],ssize_t rcvLen)88 static void DdkHandleUevent(const char msg[], ssize_t rcvLen)
89 {
90     (void)rcvLen;
91     struct DdkUeventInfo info = {
92         .action = "",
93         .subSystem = "",
94         .busNum = "",
95         .devNum = "",
96         .devPath = "",
97         .devType = "",
98     };
99 
100     const char *msgTmp = msg;
101     while (*msgTmp != '\0') {
102         if (strncmp(msgTmp, "ACTION=", strlen("ACTION=")) == 0) {
103             msgTmp += strlen("ACTION=");
104             info.action = msgTmp;
105         } else if (strncmp(msgTmp, "DEVPATH=", strlen("DEVPATH=")) == 0) {
106             msgTmp += strlen("DEVPATH=");
107             info.devPath = msgTmp;
108         } else if (strncmp(msgTmp, "SUBSYSTEM=", strlen("SUBSYSTEM=")) == 0 &&
109             strlen(info.subSystem) == 0) { // some uevent has more than one SUBSYSTEM property
110             msgTmp += strlen("SUBSYSTEM=");
111             info.subSystem = msgTmp;
112         } else if (strncmp(msgTmp, "DEVTYPE=", strlen("DEVTYPE=")) == 0 &&
113             strlen(info.devType) == 0) { // some uevent has more than one DEVTYPE property
114             msgTmp += strlen("DEVTYPE=");
115             info.devType = msgTmp;
116         } else if (strncmp(msgTmp, "BUSNUM=", strlen("BUSNUM=")) == 0) {
117             msgTmp += strlen("BUSNUM=");
118             info.busNum = msgTmp;
119         } else if (strncmp(msgTmp, "DEVNUM=", strlen("DEVNUM=")) == 0) {
120             msgTmp += strlen("DEVNUM=");
121             info.devNum = msgTmp;
122         }
123         msgTmp += strlen(msgTmp) + 1; // 1 is a skip character '\0'
124     }
125 
126     DdkUeventAddTask(&info);
127     return;
128 }
129 
DdkReadUeventMsg(int sockFd,char * buffer,size_t length)130 static ssize_t DdkReadUeventMsg(int sockFd, char *buffer, size_t length)
131 {
132     struct iovec iov;
133     iov.iov_base = buffer;
134     iov.iov_len = length;
135 
136     struct sockaddr_nl addr;
137     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
138 
139     struct msghdr msghdr = {0};
140     msghdr.msg_name = &addr;
141     msghdr.msg_namelen = sizeof(addr);
142     msghdr.msg_iov = &iov;
143     msghdr.msg_iovlen = 1;
144 
145     char credMsg[CMSG_SPACE(sizeof(struct ucred))] = {0};
146     msghdr.msg_control = credMsg;
147     msghdr.msg_controllen = sizeof(credMsg);
148 
149     ssize_t len = recvmsg(sockFd, &msghdr, 0);
150     if (len <= 0) {
151         return HDF_FAILURE;
152     }
153 
154     struct cmsghdr *hdr = CMSG_FIRSTHDR(&msghdr);
155     if (hdr == NULL || hdr->cmsg_type != SCM_CREDENTIALS) {
156         HDF_LOGE("Unexpected control message, ignored");
157         *buffer = '\0';
158         return HDF_FAILURE;
159     }
160 
161     return len;
162 }
163 
DdkUeventMain(void * param)164 void *DdkUeventMain(void *param)
165 {
166     (void)param;
167     int errorTimes = 0;
168     int socketfd = -1;
169     if (DdkUeventOpen(&socketfd) != HDF_SUCCESS) {
170         HDF_LOGE("DdkUeventOpen failed");
171         return NULL;
172     }
173 
174     ssize_t rcvLen = 0;
175     char msg[UEVENT_MSG_LEN];
176 
177     struct pollfd fd;
178     fd.fd = socketfd;
179     fd.events = POLLIN | POLLERR;
180     fd.revents = 0;
181     do {
182         if (poll(&fd, 1, -1) <= 0) {
183             HDF_LOGE("usb event poll fail %{public}d", errno);
184             OsalMSleep(UEVENT_POLL_WAIT_TIME);
185             continue;
186         }
187 
188         if (((uint32_t)fd.revents & POLLIN) == POLLIN) {
189             errorTimes = 0;
190             (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
191             rcvLen = DdkReadUeventMsg(socketfd, msg, UEVENT_MSG_LEN);
192             if (rcvLen <= 0) {
193                 continue;
194             }
195             DdkHandleUevent(msg, rcvLen);
196             UsbFnHandleUevent(msg, rcvLen);
197             UsbAccessoryUeventHandle(msg, rcvLen);
198         } else if (((uint32_t)fd.revents & POLLERR) == POLLERR) {
199             if (errorTimes < MAX_ERR_TIMES) {
200                 ++errorTimes;
201             } else {
202                 OsalMSleep(UEVENT_POLL_WAIT_TIME);
203             }
204             HDF_LOGE("usb event poll error");
205         }
206     } while (true);
207 
208     close(socketfd);
209     return NULL;
210 }
211 
DdkUeventInit(const char * gadgetEventPath)212 int32_t DdkUeventInit(const char *gadgetEventPath)
213 {
214     DdkUeventStartDispatchThread();
215     return UsbFnUeventInit(gadgetEventPath);
216 }
217 #else  // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
DdkUeventCallBack(void * priv,uint32_t id,struct HdfSBuf * data)218 static int32_t DdkUeventCallBack(void *priv, uint32_t id, struct HdfSBuf *data)
219 {
220     if (id == USB_PNP_NOTIFY_REPORT_INTERFACE) {
221         return HDF_SUCCESS;
222     }
223 
224     if (data == NULL) {
225         HDF_LOGE("%{public}s: HdfIoServiceBind failed.", __func__);
226         return HDF_ERR_INVALID_PARAM;
227     }
228 
229     struct UsbPnpNotifyMatchInfoTable *info = NULL;
230     if (id == USB_PNP_NOTIFY_ADD_DEVICE || id == USB_PNP_NOTIFY_REMOVE_DEVICE) {
231         uint32_t infoSize;
232         bool flag = HdfSbufReadBuffer(data, (const void **)(&info), &infoSize);
233         if (!flag || info == NULL) {
234             HDF_LOGE("%{public}s: HdfSbufReadBuffer failed, flag=%{public}d", __func__, flag);
235             return HDF_ERR_INVALID_PARAM;
236         }
237     }
238 
239     HDF_LOGI("%{public}s: cmd is: %{public}u.", __func__, id);
240     DdkListenerMgrNotifyAll(info, id);
241     return HDF_SUCCESS;
242 }
243 
DdkUeventInit(const char * gadgetEventPath)244 int32_t DdkUeventInit(const char *gadgetEventPath)
245 {
246     (void)gadgetEventPath;
247     struct HdfIoService *usbPnpSrv = HdfIoServiceBind(USB_PNP_NOTIFY_SERVICE_NAME);
248     if (usbPnpSrv == NULL) {
249         HDF_LOGE("%{public}s: HdfIoServiceBind failed.", __func__);
250         return HDF_ERR_INVALID_OBJECT;
251     }
252 
253     static struct HdfDevEventlistener usbPnpListener = {.callBack = DdkUeventCallBack};
254     int32_t ret = HdfDeviceRegisterEventListener(usbPnpSrv, &usbPnpListener);
255     if (ret != HDF_SUCCESS) {
256         HDF_LOGE("%{public}s: HdfDeviceRegisterEventListener failed ret=%{public}d", __func__, ret);
257     }
258     return ret;
259 }
260 #endif // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
261