c1ad1ec51faf8be6369a77eaf29e731f91e31d17
[rtmpclient.git] / app / src / main / jni / libusb-1.0.22 / libusb / os / linux_netlink.c
1 /* -*- Mode: C; c-basic-offset:8 ; indent-tabs-mode:t -*- */
2 /*
3  * Linux usbfs backend for libusb
4  * Copyright (C) 2007-2009 Daniel Drake <dsd@gentoo.org>
5  * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com>
6  * Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.com>
7  * Copyright (c) 2016 Chris Dickens <christopher.a.dickens@gmail.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23
24 #include <config.h>
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <poll.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35
36 #ifdef HAVE_ASM_TYPES_H
37 #include <asm/types.h>
38 #endif
39
40 #include <sys/socket.h>
41 #include <linux/netlink.h>
42
43 #include "libusbi.h"
44 #include "linux_usbfs.h"
45
46 #define NL_GROUP_KERNEL 1
47
48 #ifndef SOCK_CLOEXEC
49 #define SOCK_CLOEXEC    0
50 #endif
51
52 #ifndef SOCK_NONBLOCK
53 #define SOCK_NONBLOCK   0
54 #endif
55
56 static int linux_netlink_socket = -1;
57 static int netlink_control_pipe[2] = { -1, -1 };
58 static pthread_t libusb_linux_event_thread;
59
60 static void *linux_netlink_event_thread_main(void *arg);
61
62 static int set_fd_cloexec_nb(int fd, int socktype)
63 {
64         int flags;
65
66 #if defined(FD_CLOEXEC)
67         /* Make sure the netlink socket file descriptor is marked as CLOEXEC */
68         if (!(socktype & SOCK_CLOEXEC)) {
69                 flags = fcntl(fd, F_GETFD);
70                 if (flags == -1) {
71                         usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
72                         return -1;
73                 }
74
75                 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
76                         usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
77                         return -1;
78                 }
79         }
80 #endif
81
82         /* Make sure the netlink socket is non-blocking */
83         if (!(socktype & SOCK_NONBLOCK)) {
84                 flags = fcntl(fd, F_GETFL);
85                 if (flags == -1) {
86                         usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
87                         return -1;
88                 }
89
90                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
91                         usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
92                         return -1;
93                 }
94         }
95
96         return 0;
97 }
98
99 int linux_netlink_start_event_monitor(void)
100 {
101         struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
102         int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
103         int opt = 1;
104         int ret;
105
106         linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
107         if (linux_netlink_socket == -1 && errno == EINVAL) {
108                 usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
109                 socktype = SOCK_RAW;
110                 linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
111         }
112
113         if (linux_netlink_socket == -1) {
114                 usbi_err(NULL, "failed to create netlink socket (%d)", errno);
115                 goto err;
116         }
117
118         ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
119         if (ret == -1)
120                 goto err_close_socket;
121
122         ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
123         if (ret == -1) {
124                 usbi_err(NULL, "failed to bind netlink socket (%d)", errno);
125                 goto err_close_socket;
126         }
127
128         ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
129         if (ret == -1) {
130                 usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option (%d)", errno);
131                 goto err_close_socket;
132         }
133
134         ret = usbi_pipe(netlink_control_pipe);
135         if (ret) {
136                 usbi_err(NULL, "failed to create netlink control pipe");
137                 goto err_close_socket;
138         }
139
140         ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
141         if (ret != 0) {
142                 usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
143                 goto err_close_pipe;
144         }
145
146         return LIBUSB_SUCCESS;
147
148 err_close_pipe:
149         close(netlink_control_pipe[0]);
150         close(netlink_control_pipe[1]);
151         netlink_control_pipe[0] = -1;
152         netlink_control_pipe[1] = -1;
153 err_close_socket:
154         close(linux_netlink_socket);
155         linux_netlink_socket = -1;
156 err:
157         return LIBUSB_ERROR_OTHER;
158 }
159
160 int linux_netlink_stop_event_monitor(void)
161 {
162         char dummy = 1;
163         ssize_t r;
164
165         assert(linux_netlink_socket != -1);
166
167         /* Write some dummy data to the control pipe and
168          * wait for the thread to exit */
169         r = write(netlink_control_pipe[1], &dummy, sizeof(dummy));
170         if (r <= 0)
171                 usbi_warn(NULL, "netlink control pipe signal failed");
172
173         pthread_join(libusb_linux_event_thread, NULL);
174
175         close(linux_netlink_socket);
176         linux_netlink_socket = -1;
177
178         /* close and reset control pipe */
179         close(netlink_control_pipe[0]);
180         close(netlink_control_pipe[1]);
181         netlink_control_pipe[0] = -1;
182         netlink_control_pipe[1] = -1;
183
184         return LIBUSB_SUCCESS;
185 }
186
187 static const char *netlink_message_parse(const char *buffer, size_t len, const char *key)
188 {
189         const char *end = buffer + len;
190         size_t keylen = strlen(key);
191
192         while (buffer < end && *buffer) {
193                 if (strncmp(buffer, key, keylen) == 0 && buffer[keylen] == '=')
194                         return buffer + keylen + 1;
195                 buffer += strlen(buffer) + 1;
196         }
197
198         return NULL;
199 }
200
201 /* parse parts of netlink message common to both libudev and the kernel */
202 static int linux_netlink_parse(const char *buffer, size_t len, int *detached,
203         const char **sys_name, uint8_t *busnum, uint8_t *devaddr)
204 {
205         const char *tmp, *slash;
206
207         errno = 0;
208
209         *sys_name = NULL;
210         *detached = 0;
211         *busnum   = 0;
212         *devaddr  = 0;
213
214         tmp = netlink_message_parse(buffer, len, "ACTION");
215         if (!tmp) {
216                 return -1;
217         } else if (strcmp(tmp, "remove") == 0) {
218                 *detached = 1;
219         } else if (strcmp(tmp, "add") != 0) {
220                 usbi_dbg("unknown device action %s", tmp);
221                 return -1;
222         }
223
224         /* check that this is a usb message */
225         tmp = netlink_message_parse(buffer, len, "SUBSYSTEM");
226         if (!tmp || strcmp(tmp, "usb") != 0) {
227                 /* not usb. ignore */
228                 return -1;
229         }
230
231         /* check that this is an actual usb device */
232         tmp = netlink_message_parse(buffer, len, "DEVTYPE");
233         if (!tmp || strcmp(tmp, "usb_device") != 0) {
234                 /* not usb. ignore */
235                 return -1;
236         }
237
238         tmp = netlink_message_parse(buffer, len, "BUSNUM");
239         if (tmp) {
240                 *busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
241                 if (errno) {
242                         errno = 0;
243                         return -1;
244                 }
245
246                 tmp = netlink_message_parse(buffer, len, "DEVNUM");
247                 if (NULL == tmp)
248                         return -1;
249
250                 *devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
251                 if (errno) {
252                         errno = 0;
253                         return -1;
254                 }
255         } else {
256                 /* no bus number. try "DEVICE" */
257                 tmp = netlink_message_parse(buffer, len, "DEVICE");
258                 if (!tmp) {
259                         /* not usb. ignore */
260                         return -1;
261                 }
262
263                 /* Parse a device path such as /dev/bus/usb/003/004 */
264                 slash = strrchr(tmp, '/');
265                 if (!slash)
266                         return -1;
267
268                 *busnum = (uint8_t)(strtoul(slash - 3, NULL, 10) & 0xff);
269                 if (errno) {
270                         errno = 0;
271                         return -1;
272                 }
273
274                 *devaddr = (uint8_t)(strtoul(slash + 1, NULL, 10) & 0xff);
275                 if (errno) {
276                         errno = 0;
277                         return -1;
278                 }
279
280                 return 0;
281         }
282
283         tmp = netlink_message_parse(buffer, len, "DEVPATH");
284         if (!tmp)
285                 return -1;
286
287         slash = strrchr(tmp, '/');
288         if (slash)
289                 *sys_name = slash + 1;
290
291         /* found a usb device */
292         return 0;
293 }
294
295 static int linux_netlink_read_message(void)
296 {
297         char cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
298         char msg_buffer[2048];
299         const char *sys_name = NULL;
300         uint8_t busnum, devaddr;
301         int detached, r;
302         ssize_t len;
303         struct cmsghdr *cmsg;
304         struct ucred *cred;
305         struct sockaddr_nl sa_nl;
306         struct iovec iov = { .iov_base = msg_buffer, .iov_len = sizeof(msg_buffer) };
307         struct msghdr msg = {
308                 .msg_iov = &iov, .msg_iovlen = 1,
309                 .msg_control = cred_buffer, .msg_controllen = sizeof(cred_buffer),
310                 .msg_name = &sa_nl, .msg_namelen = sizeof(sa_nl)
311         };
312
313         /* read netlink message */
314         len = recvmsg(linux_netlink_socket, &msg, 0);
315         if (len == -1) {
316                 if (errno != EAGAIN && errno != EINTR)
317                         usbi_err(NULL, "error receiving message from netlink (%d)", errno);
318                 return -1;
319         }
320
321         if (len < 32 || (msg.msg_flags & MSG_TRUNC)) {
322                 usbi_err(NULL, "invalid netlink message length");
323                 return -1;
324         }
325
326         if (sa_nl.nl_groups != NL_GROUP_KERNEL || sa_nl.nl_pid != 0) {
327                 usbi_dbg("ignoring netlink message from unknown group/PID (%u/%u)",
328                          (unsigned int)sa_nl.nl_groups, (unsigned int)sa_nl.nl_pid);
329                 return -1;
330         }
331
332         cmsg = CMSG_FIRSTHDR(&msg);
333         if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
334                 usbi_dbg("ignoring netlink message with no sender credentials");
335                 return -1;
336         }
337
338         cred = (struct ucred *)CMSG_DATA(cmsg);
339         if (cred->uid != 0) {
340                 usbi_dbg("ignoring netlink message with non-zero sender UID %u", (unsigned int)cred->uid);
341                 return -1;
342         }
343
344         r = linux_netlink_parse(msg_buffer, (size_t)len, &detached, &sys_name, &busnum, &devaddr);
345         if (r)
346                 return r;
347
348         usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
349                  busnum, devaddr, sys_name, detached ? "yes" : "no");
350
351         /* signal device is available (or not) to all contexts */
352         if (detached)
353                 linux_device_disconnected(busnum, devaddr);
354         else
355                 linux_hotplug_enumerate(busnum, devaddr, sys_name);
356
357         return 0;
358 }
359
360 static void *linux_netlink_event_thread_main(void *arg)
361 {
362         char dummy;
363         int r;
364         ssize_t nb;
365         struct pollfd fds[] = {
366                 { .fd = netlink_control_pipe[0],
367                   .events = POLLIN },
368                 { .fd = linux_netlink_socket,
369                   .events = POLLIN },
370         };
371
372         UNUSED(arg);
373
374         usbi_dbg("netlink event thread entering");
375
376         while ((r = poll(fds, 2, -1)) >= 0 || errno == EINTR) {
377                 if (r < 0) {
378                         /* temporary failure */
379                         continue;
380                 }
381                 if (fds[0].revents & POLLIN) {
382                         /* activity on control pipe, read the byte and exit */
383                         nb = read(netlink_control_pipe[0], &dummy, sizeof(dummy));
384                         if (nb <= 0)
385                                 usbi_warn(NULL, "netlink control pipe read failed");
386                         break;
387                 }
388                 if (fds[1].revents & POLLIN) {
389                         usbi_mutex_static_lock(&linux_hotplug_lock);
390                         linux_netlink_read_message();
391                         usbi_mutex_static_unlock(&linux_hotplug_lock);
392                 }
393         }
394
395         usbi_dbg("netlink event thread exiting");
396
397         return NULL;
398 }
399
400 void linux_netlink_hotplug_poll(void)
401 {
402         int r;
403
404         usbi_mutex_static_lock(&linux_hotplug_lock);
405         do {
406                 r = linux_netlink_read_message();
407         } while (r == 0);
408         usbi_mutex_static_unlock(&linux_hotplug_lock);
409 }