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