1094332d3Sopenharmony_ci/*
2094332d3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3094332d3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4094332d3Sopenharmony_ci * you may not use this file except in compliance with the License.
5094332d3Sopenharmony_ci * You may obtain a copy of the License at
6094332d3Sopenharmony_ci *
7094332d3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8094332d3Sopenharmony_ci *
9094332d3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10094332d3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11094332d3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12094332d3Sopenharmony_ci * See the License for the specific language governing permissions and
13094332d3Sopenharmony_ci * limitations under the License.
14094332d3Sopenharmony_ci */
15094332d3Sopenharmony_ci#include "ddk_uevent_handle.h"
16094332d3Sopenharmony_ci
17094332d3Sopenharmony_ci#include <linux/netlink.h>
18094332d3Sopenharmony_ci#include <poll.h>
19094332d3Sopenharmony_ci#include <pthread.h>
20094332d3Sopenharmony_ci#include <string.h>
21094332d3Sopenharmony_ci#include <sys/socket.h>
22094332d3Sopenharmony_ci#include <sys/types.h>
23094332d3Sopenharmony_ci#include <unistd.h>
24094332d3Sopenharmony_ci
25094332d3Sopenharmony_ci#include "ddk_device_manager.h"
26094332d3Sopenharmony_ci#include "ddk_pnp_listener_mgr.h"
27094332d3Sopenharmony_ci#include "ddk_uevent_queue.h"
28094332d3Sopenharmony_ci#include "hdf_base.h"
29094332d3Sopenharmony_ci#include "hdf_io_service_if.h"
30094332d3Sopenharmony_ci#include "hdf_log.h"
31094332d3Sopenharmony_ci#include "osal_time.h"
32094332d3Sopenharmony_ci#include "securec.h"
33094332d3Sopenharmony_ci#include "usbfn_uevent_handle.h"
34094332d3Sopenharmony_ci#include "usbd_wrapper.h"
35094332d3Sopenharmony_ci
36094332d3Sopenharmony_ci#define HDF_LOG_TAG usb_ddk_uevent
37094332d3Sopenharmony_ci
38094332d3Sopenharmony_ci#ifdef USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
39094332d3Sopenharmony_ci#define UEVENT_MSG_LEN          2048
40094332d3Sopenharmony_ci#define UEVENT_SOCKET_GROUPS    0xffffffff
41094332d3Sopenharmony_ci#define UEVENT_SOCKET_BUFF_SIZE (64 * 1024)
42094332d3Sopenharmony_ci#define TIMEVAL_SECOND          0
43094332d3Sopenharmony_ci#define TIMEVAL_USECOND         (100 * 1000)
44094332d3Sopenharmony_ci#define UEVENT_POLL_WAIT_TIME   100
45094332d3Sopenharmony_ci
46094332d3Sopenharmony_cistatic int DdkUeventOpen(int *fd)
47094332d3Sopenharmony_ci{
48094332d3Sopenharmony_ci    struct sockaddr_nl addr;
49094332d3Sopenharmony_ci    if (memset_s(&addr, sizeof(addr), 0, sizeof(addr)) != HDF_SUCCESS) {
50094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: addr memset_s failed!", __func__);
51094332d3Sopenharmony_ci        return HDF_FAILURE;
52094332d3Sopenharmony_ci    }
53094332d3Sopenharmony_ci    addr.nl_family = AF_NETLINK;
54094332d3Sopenharmony_ci    addr.nl_pid = (uint32_t)getpid();
55094332d3Sopenharmony_ci    addr.nl_groups = UEVENT_SOCKET_GROUPS;
56094332d3Sopenharmony_ci
57094332d3Sopenharmony_ci    int socketfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
58094332d3Sopenharmony_ci    if (socketfd < 0) {
59094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: socketfd failed! ret = %{public}d", __func__, socketfd);
60094332d3Sopenharmony_ci        return HDF_FAILURE;
61094332d3Sopenharmony_ci    }
62094332d3Sopenharmony_ci
63094332d3Sopenharmony_ci    int buffSize = UEVENT_SOCKET_BUFF_SIZE;
64094332d3Sopenharmony_ci    if (setsockopt(socketfd, SOL_SOCKET, SO_RCVBUF, &buffSize, sizeof(buffSize)) != 0) {
65094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: setsockopt failed!", __func__);
66094332d3Sopenharmony_ci        close(socketfd);
67094332d3Sopenharmony_ci        return HDF_FAILURE;
68094332d3Sopenharmony_ci    }
69094332d3Sopenharmony_ci
70094332d3Sopenharmony_ci    const int32_t on = 1; // turn on passcred
71094332d3Sopenharmony_ci    if (setsockopt(socketfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) != 0) {
72094332d3Sopenharmony_ci        HDF_LOGE("setsockopt failed!");
73094332d3Sopenharmony_ci        close(socketfd);
74094332d3Sopenharmony_ci        return HDF_FAILURE;
75094332d3Sopenharmony_ci    }
76094332d3Sopenharmony_ci
77094332d3Sopenharmony_ci    if (bind(socketfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
78094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: bind socketfd failed!", __func__);
79094332d3Sopenharmony_ci        close(socketfd);
80094332d3Sopenharmony_ci        return HDF_FAILURE;
81094332d3Sopenharmony_ci    }
82094332d3Sopenharmony_ci    *fd = socketfd;
83094332d3Sopenharmony_ci    return HDF_SUCCESS;
84094332d3Sopenharmony_ci}
85094332d3Sopenharmony_ci
86094332d3Sopenharmony_cistatic void DdkHandleUevent(const char msg[], ssize_t rcvLen)
87094332d3Sopenharmony_ci{
88094332d3Sopenharmony_ci    (void)rcvLen;
89094332d3Sopenharmony_ci    struct DdkUeventInfo info = {
90094332d3Sopenharmony_ci        .action = "",
91094332d3Sopenharmony_ci        .subSystem = "",
92094332d3Sopenharmony_ci        .busNum = "",
93094332d3Sopenharmony_ci        .devNum = "",
94094332d3Sopenharmony_ci        .devPath = "",
95094332d3Sopenharmony_ci        .devType = "",
96094332d3Sopenharmony_ci    };
97094332d3Sopenharmony_ci
98094332d3Sopenharmony_ci    const char *msgTmp = msg;
99094332d3Sopenharmony_ci    while (*msgTmp != '\0') {
100094332d3Sopenharmony_ci        if (strncmp(msgTmp, "ACTION=", strlen("ACTION=")) == 0) {
101094332d3Sopenharmony_ci            msgTmp += strlen("ACTION=");
102094332d3Sopenharmony_ci            info.action = msgTmp;
103094332d3Sopenharmony_ci        } else if (strncmp(msgTmp, "DEVPATH=", strlen("DEVPATH=")) == 0) {
104094332d3Sopenharmony_ci            msgTmp += strlen("DEVPATH=");
105094332d3Sopenharmony_ci            info.devPath = msgTmp;
106094332d3Sopenharmony_ci        } else if (strncmp(msgTmp, "SUBSYSTEM=", strlen("SUBSYSTEM=")) == 0 &&
107094332d3Sopenharmony_ci            strlen(info.subSystem) == 0) { // some uevent has more than one SUBSYSTEM property
108094332d3Sopenharmony_ci            msgTmp += strlen("SUBSYSTEM=");
109094332d3Sopenharmony_ci            info.subSystem = msgTmp;
110094332d3Sopenharmony_ci        } else if (strncmp(msgTmp, "DEVTYPE=", strlen("DEVTYPE=")) == 0 &&
111094332d3Sopenharmony_ci            strlen(info.devType) == 0) { // some uevent has more than one DEVTYPE property
112094332d3Sopenharmony_ci            msgTmp += strlen("DEVTYPE=");
113094332d3Sopenharmony_ci            info.devType = msgTmp;
114094332d3Sopenharmony_ci        } else if (strncmp(msgTmp, "BUSNUM=", strlen("BUSNUM=")) == 0) {
115094332d3Sopenharmony_ci            msgTmp += strlen("BUSNUM=");
116094332d3Sopenharmony_ci            info.busNum = msgTmp;
117094332d3Sopenharmony_ci        } else if (strncmp(msgTmp, "DEVNUM=", strlen("DEVNUM=")) == 0) {
118094332d3Sopenharmony_ci            msgTmp += strlen("DEVNUM=");
119094332d3Sopenharmony_ci            info.devNum = msgTmp;
120094332d3Sopenharmony_ci        }
121094332d3Sopenharmony_ci        msgTmp += strlen(msgTmp) + 1; // 1 is a skip character '\0'
122094332d3Sopenharmony_ci    }
123094332d3Sopenharmony_ci
124094332d3Sopenharmony_ci    DdkUeventAddTask(&info);
125094332d3Sopenharmony_ci    return;
126094332d3Sopenharmony_ci}
127094332d3Sopenharmony_ci
128094332d3Sopenharmony_cistatic ssize_t DdkReadUeventMsg(int sockFd, char *buffer, size_t length)
129094332d3Sopenharmony_ci{
130094332d3Sopenharmony_ci    struct iovec iov;
131094332d3Sopenharmony_ci    iov.iov_base = buffer;
132094332d3Sopenharmony_ci    iov.iov_len = length;
133094332d3Sopenharmony_ci
134094332d3Sopenharmony_ci    struct sockaddr_nl addr;
135094332d3Sopenharmony_ci    (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
136094332d3Sopenharmony_ci
137094332d3Sopenharmony_ci    struct msghdr msghdr = {0};
138094332d3Sopenharmony_ci    msghdr.msg_name = &addr;
139094332d3Sopenharmony_ci    msghdr.msg_namelen = sizeof(addr);
140094332d3Sopenharmony_ci    msghdr.msg_iov = &iov;
141094332d3Sopenharmony_ci    msghdr.msg_iovlen = 1;
142094332d3Sopenharmony_ci
143094332d3Sopenharmony_ci    char credMsg[CMSG_SPACE(sizeof(struct ucred))] = {0};
144094332d3Sopenharmony_ci    msghdr.msg_control = credMsg;
145094332d3Sopenharmony_ci    msghdr.msg_controllen = sizeof(credMsg);
146094332d3Sopenharmony_ci
147094332d3Sopenharmony_ci    ssize_t len = recvmsg(sockFd, &msghdr, 0);
148094332d3Sopenharmony_ci    if (len <= 0) {
149094332d3Sopenharmony_ci        return HDF_FAILURE;
150094332d3Sopenharmony_ci    }
151094332d3Sopenharmony_ci
152094332d3Sopenharmony_ci    struct cmsghdr *hdr = CMSG_FIRSTHDR(&msghdr);
153094332d3Sopenharmony_ci    if (hdr == NULL || hdr->cmsg_type != SCM_CREDENTIALS) {
154094332d3Sopenharmony_ci        HDF_LOGE("Unexpected control message, ignored");
155094332d3Sopenharmony_ci        *buffer = '\0';
156094332d3Sopenharmony_ci        return HDF_FAILURE;
157094332d3Sopenharmony_ci    }
158094332d3Sopenharmony_ci
159094332d3Sopenharmony_ci    return len;
160094332d3Sopenharmony_ci}
161094332d3Sopenharmony_ci
162094332d3Sopenharmony_civoid *DdkUeventMain(void *param)
163094332d3Sopenharmony_ci{
164094332d3Sopenharmony_ci    (void)param;
165094332d3Sopenharmony_ci    int socketfd = -1;
166094332d3Sopenharmony_ci    if (DdkUeventOpen(&socketfd) != HDF_SUCCESS) {
167094332d3Sopenharmony_ci        HDF_LOGE("DdkUeventOpen failed");
168094332d3Sopenharmony_ci        return NULL;
169094332d3Sopenharmony_ci    }
170094332d3Sopenharmony_ci
171094332d3Sopenharmony_ci    ssize_t rcvLen = 0;
172094332d3Sopenharmony_ci    char msg[UEVENT_MSG_LEN];
173094332d3Sopenharmony_ci
174094332d3Sopenharmony_ci    struct pollfd fd;
175094332d3Sopenharmony_ci    fd.fd = socketfd;
176094332d3Sopenharmony_ci    fd.events = POLLIN | POLLERR;
177094332d3Sopenharmony_ci    fd.revents = 0;
178094332d3Sopenharmony_ci    do {
179094332d3Sopenharmony_ci        if (poll(&fd, 1, -1) <= 0) {
180094332d3Sopenharmony_ci            HDF_LOGE("usb event poll fail %{public}d", errno);
181094332d3Sopenharmony_ci            OsalMSleep(UEVENT_POLL_WAIT_TIME);
182094332d3Sopenharmony_ci            continue;
183094332d3Sopenharmony_ci        }
184094332d3Sopenharmony_ci
185094332d3Sopenharmony_ci        if (((uint32_t)fd.revents & POLLIN) == POLLIN) {
186094332d3Sopenharmony_ci            (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
187094332d3Sopenharmony_ci            rcvLen = DdkReadUeventMsg(socketfd, msg, UEVENT_MSG_LEN);
188094332d3Sopenharmony_ci            if (rcvLen <= 0) {
189094332d3Sopenharmony_ci                continue;
190094332d3Sopenharmony_ci            }
191094332d3Sopenharmony_ci            DdkHandleUevent(msg, rcvLen);
192094332d3Sopenharmony_ci            UsbFnHandleUevent(msg, rcvLen);
193094332d3Sopenharmony_ci        } else if (((uint32_t)fd.revents & POLLERR) == POLLERR) {
194094332d3Sopenharmony_ci            HDF_LOGE("usb event poll error");
195094332d3Sopenharmony_ci        }
196094332d3Sopenharmony_ci    } while (true);
197094332d3Sopenharmony_ci
198094332d3Sopenharmony_ci    close(socketfd);
199094332d3Sopenharmony_ci    return NULL;
200094332d3Sopenharmony_ci}
201094332d3Sopenharmony_ci
202094332d3Sopenharmony_ciint32_t DdkUeventInit(const char *gadgetEventPath)
203094332d3Sopenharmony_ci{
204094332d3Sopenharmony_ci    DdkUeventStartDispatchThread();
205094332d3Sopenharmony_ci    return UsbFnUeventInit(gadgetEventPath);
206094332d3Sopenharmony_ci}
207094332d3Sopenharmony_ci#else  // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
208094332d3Sopenharmony_cistatic int32_t DdkUeventCallBack(void *priv, uint32_t id, struct HdfSBuf *data)
209094332d3Sopenharmony_ci{
210094332d3Sopenharmony_ci    if (id == USB_PNP_NOTIFY_REPORT_INTERFACE) {
211094332d3Sopenharmony_ci        return HDF_SUCCESS;
212094332d3Sopenharmony_ci    }
213094332d3Sopenharmony_ci
214094332d3Sopenharmony_ci    if (data == NULL) {
215094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: HdfIoServiceBind failed.", __func__);
216094332d3Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
217094332d3Sopenharmony_ci    }
218094332d3Sopenharmony_ci
219094332d3Sopenharmony_ci    struct UsbPnpNotifyMatchInfoTable *info = NULL;
220094332d3Sopenharmony_ci    if (id == USB_PNP_NOTIFY_ADD_DEVICE || id == USB_PNP_NOTIFY_REMOVE_DEVICE) {
221094332d3Sopenharmony_ci        uint32_t infoSize;
222094332d3Sopenharmony_ci        bool flag = HdfSbufReadBuffer(data, (const void **)(&info), &infoSize);
223094332d3Sopenharmony_ci        if (!flag || info == NULL) {
224094332d3Sopenharmony_ci            HDF_LOGE("%{public}s: HdfSbufReadBuffer failed, flag=%{public}d", __func__, flag);
225094332d3Sopenharmony_ci            return HDF_ERR_INVALID_PARAM;
226094332d3Sopenharmony_ci        }
227094332d3Sopenharmony_ci    }
228094332d3Sopenharmony_ci
229094332d3Sopenharmony_ci    HDF_LOGI("%{public}s: cmd is: %{public}u.", __func__, id);
230094332d3Sopenharmony_ci    DdkListenerMgrNotifyAll(info, id);
231094332d3Sopenharmony_ci    return HDF_SUCCESS;
232094332d3Sopenharmony_ci}
233094332d3Sopenharmony_ci
234094332d3Sopenharmony_ciint32_t DdkUeventInit(const char *gadgetEventPath)
235094332d3Sopenharmony_ci{
236094332d3Sopenharmony_ci    (void)gadgetEventPath;
237094332d3Sopenharmony_ci    struct HdfIoService *usbPnpSrv = HdfIoServiceBind(USB_PNP_NOTIFY_SERVICE_NAME);
238094332d3Sopenharmony_ci    if (usbPnpSrv == NULL) {
239094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: HdfIoServiceBind failed.", __func__);
240094332d3Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
241094332d3Sopenharmony_ci    }
242094332d3Sopenharmony_ci
243094332d3Sopenharmony_ci    static struct HdfDevEventlistener usbPnpListener = {.callBack = DdkUeventCallBack};
244094332d3Sopenharmony_ci    int32_t ret = HdfDeviceRegisterEventListener(usbPnpSrv, &usbPnpListener);
245094332d3Sopenharmony_ci    if (ret != HDF_SUCCESS) {
246094332d3Sopenharmony_ci        HDF_LOGE("%{public}s: HdfDeviceRegisterEventListener failed ret=%{public}d", __func__, ret);
247094332d3Sopenharmony_ci    }
248094332d3Sopenharmony_ci    return ret;
249094332d3Sopenharmony_ci}
250094332d3Sopenharmony_ci#endif // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
251