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