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