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