Home | History | Annotate | Download | only in os
      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 (at) gentoo.org>
      5  * Copyright (c) 2001 Johannes Erdfelt <johannes (at) erdfelt.com>
      6  * Copyright (c) 2013 Nathan Hjelm <hjelmn (at) mac.com>
      7  * Copyright (c) 2016 Chris Dickens <christopher.a.dickens (at) 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 static int linux_netlink_socket = -1;
     49 static int netlink_control_pipe[2] = { -1, -1 };
     50 static pthread_t libusb_linux_event_thread;
     51 
     52 static void *linux_netlink_event_thread_main(void *arg);
     53 
     54 static int set_fd_cloexec_nb(int fd)
     55 {
     56 	int flags;
     57 
     58 #if defined(FD_CLOEXEC)
     59 	flags = fcntl(fd, F_GETFD);
     60 	if (flags == -1) {
     61 		usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
     62 		return -1;
     63 	}
     64 
     65 	if (!(flags & FD_CLOEXEC)) {
     66 		if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
     67 			usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
     68 			return -1;
     69 		}
     70 	}
     71 #endif
     72 
     73 	flags = fcntl(fd, F_GETFL);
     74 	if (flags == -1) {
     75 		usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
     76 		return -1;
     77 	}
     78 
     79 	if (!(flags & O_NONBLOCK)) {
     80 		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
     81 			usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
     82 			return -1;
     83 		}
     84 	}
     85 
     86 	return 0;
     87 }
     88 
     89 int linux_netlink_start_event_monitor(void)
     90 {
     91 	struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
     92 	int socktype = SOCK_RAW;
     93 	int opt = 1;
     94 	int ret;
     95 
     96 #if defined(SOCK_CLOEXEC)
     97 	socktype |= SOCK_CLOEXEC;
     98 #endif
     99 #if defined(SOCK_NONBLOCK)
    100 	socktype |= SOCK_NONBLOCK;
    101 #endif
    102 
    103 	linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
    104 	if (linux_netlink_socket == -1 && errno == EINVAL) {
    105 		usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
    106 		linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    107 	}
    108 
    109 	if (linux_netlink_socket == -1) {
    110 		usbi_err(NULL, "failed to create netlink socket (%d)", errno);
    111 		goto err;
    112 	}
    113 
    114 	ret = set_fd_cloexec_nb(linux_netlink_socket);
    115 	if (ret == -1)
    116 		goto err_close_socket;
    117 
    118 	ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
    119 	if (ret == -1) {
    120 		usbi_err(NULL, "failed to bind netlink socket (%d)", errno);
    121 		goto err_close_socket;
    122 	}
    123 
    124 	ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
    125 	if (ret == -1) {
    126 		usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option (%d)", errno);
    127 		goto err_close_socket;
    128 	}
    129 
    130 	ret = usbi_pipe(netlink_control_pipe);
    131 	if (ret) {
    132 		usbi_err(NULL, "failed to create netlink control pipe");
    133 		goto err_close_socket;
    134 	}
    135 
    136 	ret = pthread_create(&libusb_linux_event_thread, NULL, linux_netlink_event_thread_main, NULL);
    137 	if (ret != 0) {
    138 		usbi_err(NULL, "failed to create netlink event thread (%d)", ret);
    139 		goto err_close_pipe;
    140 	}
    141 
    142 	return LIBUSB_SUCCESS;
    143 
    144 err_close_pipe:
    145 	close(netlink_control_pipe[0]);
    146 	close(netlink_control_pipe[1]);
    147 	netlink_control_pipe[0] = -1;
    148 	netlink_control_pipe[1] = -1;
    149 err_close_socket:
    150 	close(linux_netlink_socket);
    151 	linux_netlink_socket = -1;
    152 err:
    153 	return LIBUSB_ERROR_OTHER;
    154 }
    155 
    156 int linux_netlink_stop_event_monitor(void)
    157 {
    158 	char dummy = 1;
    159 	ssize_t r;
    160 
    161 	assert(linux_netlink_socket != -1);
    162 
    163 	/* Write some dummy data to the control pipe and
    164 	 * wait for the thread to exit */
    165 	r = usbi_write(netlink_control_pipe[1], &dummy, sizeof(dummy));
    166 	if (r <= 0)
    167 		usbi_warn(NULL, "netlink control pipe signal failed");
    168 
    169 	pthread_join(libusb_linux_event_thread, NULL);
    170 
    171 	close(linux_netlink_socket);
    172 	linux_netlink_socket = -1;
    173 
    174 	/* close and reset control pipe */
    175 	close(netlink_control_pipe[0]);
    176 	close(netlink_control_pipe[1]);
    177 	netlink_control_pipe[0] = -1;
    178 	netlink_control_pipe[1] = -1;
    179 
    180 	return LIBUSB_SUCCESS;
    181 }
    182 
    183 static const char *netlink_message_parse(const char *buffer, size_t len, const char *key)
    184 {
    185 	const char *end = buffer + len;
    186 	size_t keylen = strlen(key);
    187 
    188 	while (buffer < end && *buffer) {
    189 		if (strncmp(buffer, key, keylen) == 0 && buffer[keylen] == '=')
    190 			return buffer + keylen + 1;
    191 		buffer += strlen(buffer) + 1;
    192 	}
    193 
    194 	return NULL;
    195 }
    196 
    197 /* parse parts of netlink message common to both libudev and the kernel */
    198 static int linux_netlink_parse(const char *buffer, size_t len, int *detached,
    199 	const char **sys_name, uint8_t *busnum, uint8_t *devaddr)
    200 {
    201 	const char *tmp, *slash;
    202 
    203 	errno = 0;
    204 
    205 	*sys_name = NULL;
    206 	*detached = 0;
    207 	*busnum   = 0;
    208 	*devaddr  = 0;
    209 
    210 	tmp = netlink_message_parse(buffer, len, "ACTION");
    211 	if (!tmp) {
    212 		return -1;
    213 	} else if (strcmp(tmp, "remove") == 0) {
    214 		*detached = 1;
    215 	} else if (strcmp(tmp, "add") != 0) {
    216 		usbi_dbg("unknown device action %s", tmp);
    217 		return -1;
    218 	}
    219 
    220 	/* check that this is a usb message */
    221 	tmp = netlink_message_parse(buffer, len, "SUBSYSTEM");
    222 	if (!tmp || strcmp(tmp, "usb") != 0) {
    223 		/* not usb. ignore */
    224 		return -1;
    225 	}
    226 
    227 	/* check that this is an actual usb device */
    228 	tmp = netlink_message_parse(buffer, len, "DEVTYPE");
    229 	if (!tmp || strcmp(tmp, "usb_device") != 0) {
    230 		/* not usb. ignore */
    231 		return -1;
    232 	}
    233 
    234 	tmp = netlink_message_parse(buffer, len, "BUSNUM");
    235 	if (tmp) {
    236 		*busnum = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
    237 		if (errno) {
    238 			errno = 0;
    239 			return -1;
    240 		}
    241 
    242 		tmp = netlink_message_parse(buffer, len, "DEVNUM");
    243 		if (NULL == tmp)
    244 			return -1;
    245 
    246 		*devaddr = (uint8_t)(strtoul(tmp, NULL, 10) & 0xff);
    247 		if (errno) {
    248 			errno = 0;
    249 			return -1;
    250 		}
    251 	} else {
    252 		/* no bus number. try "DEVICE" */
    253 		tmp = netlink_message_parse(buffer, len, "DEVICE");
    254 		if (!tmp) {
    255 			/* not usb. ignore */
    256 			return -1;
    257 		}
    258 
    259 		/* Parse a device path such as /dev/bus/usb/003/004 */
    260 		slash = strrchr(tmp, '/');
    261 		if (!slash)
    262 			return -1;
    263 
    264 		*busnum = (uint8_t)(strtoul(slash - 3, NULL, 10) & 0xff);
    265 		if (errno) {
    266 			errno = 0;
    267 			return -1;
    268 		}
    269 
    270 		*devaddr = (uint8_t)(strtoul(slash + 1, NULL, 10) & 0xff);
    271 		if (errno) {
    272 			errno = 0;
    273 			return -1;
    274 		}
    275 
    276 		return 0;
    277 	}
    278 
    279 	tmp = netlink_message_parse(buffer, len, "DEVPATH");
    280 	if (!tmp)
    281 		return -1;
    282 
    283 	slash = strrchr(tmp, '/');
    284 	if (slash)
    285 		*sys_name = slash + 1;
    286 
    287 	/* found a usb device */
    288 	return 0;
    289 }
    290 
    291 static int linux_netlink_read_message(void)
    292 {
    293 	char cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
    294 	char msg_buffer[2048];
    295 	const char *sys_name = NULL;
    296 	uint8_t busnum, devaddr;
    297 	int detached, r;
    298 	ssize_t len;
    299 	struct cmsghdr *cmsg;
    300 	struct ucred *cred;
    301 	struct sockaddr_nl sa_nl;
    302 	struct iovec iov = { .iov_base = msg_buffer, .iov_len = sizeof(msg_buffer) };
    303 	struct msghdr msg = {
    304 		.msg_iov = &iov, .msg_iovlen = 1,
    305 		.msg_control = cred_buffer, .msg_controllen = sizeof(cred_buffer),
    306 		.msg_name = &sa_nl, .msg_namelen = sizeof(sa_nl)
    307 	};
    308 
    309 	/* read netlink message */
    310 	len = recvmsg(linux_netlink_socket, &msg, 0);
    311 	if (len == -1) {
    312 		if (errno != EAGAIN && errno != EINTR)
    313 			usbi_err(NULL, "error receiving message from netlink (%d)", errno);
    314 		return -1;
    315 	}
    316 
    317 	if (len < 32 || (msg.msg_flags & MSG_TRUNC)) {
    318 		usbi_err(NULL, "invalid netlink message length");
    319 		return -1;
    320 	}
    321 
    322 	if (sa_nl.nl_groups != NL_GROUP_KERNEL || sa_nl.nl_pid != 0) {
    323 		usbi_dbg("ignoring netlink message from unknown group/PID (%u/%u)",
    324 			 (unsigned int)sa_nl.nl_groups, (unsigned int)sa_nl.nl_pid);
    325 		return -1;
    326 	}
    327 
    328 	cmsg = CMSG_FIRSTHDR(&msg);
    329 	if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
    330 		usbi_dbg("ignoring netlink message with no sender credentials");
    331 		return -1;
    332 	}
    333 
    334 	cred = (struct ucred *)CMSG_DATA(cmsg);
    335 	if (cred->uid != 0) {
    336 		usbi_dbg("ignoring netlink message with non-zero sender UID %u", (unsigned int)cred->uid);
    337 		return -1;
    338 	}
    339 
    340 	r = linux_netlink_parse(msg_buffer, (size_t)len, &detached, &sys_name, &busnum, &devaddr);
    341 	if (r)
    342 		return r;
    343 
    344 	usbi_dbg("netlink hotplug found device busnum: %hhu, devaddr: %hhu, sys_name: %s, removed: %s",
    345 		 busnum, devaddr, sys_name, detached ? "yes" : "no");
    346 
    347 	/* signal device is available (or not) to all contexts */
    348 	if (detached)
    349 		linux_device_disconnected(busnum, devaddr);
    350 	else
    351 		linux_hotplug_enumerate(busnum, devaddr, sys_name);
    352 
    353 	return 0;
    354 }
    355 
    356 static void *linux_netlink_event_thread_main(void *arg)
    357 {
    358 	char dummy;
    359 	ssize_t r;
    360 	struct pollfd fds[] = {
    361 		{ .fd = netlink_control_pipe[0],
    362 		  .events = POLLIN },
    363 		{ .fd = linux_netlink_socket,
    364 		  .events = POLLIN },
    365 	};
    366 
    367 	UNUSED(arg);
    368 
    369 	usbi_dbg("netlink event thread entering");
    370 
    371 	while (poll(fds, 2, -1) >= 0) {
    372 		if (fds[0].revents & POLLIN) {
    373 			/* activity on control pipe, read the byte and exit */
    374 			r = usbi_read(netlink_control_pipe[0], &dummy, sizeof(dummy));
    375 			if (r <= 0)
    376 				usbi_warn(NULL, "netlink control pipe read failed");
    377 			break;
    378 		}
    379 		if (fds[1].revents & POLLIN) {
    380 			usbi_mutex_static_lock(&linux_hotplug_lock);
    381 			linux_netlink_read_message();
    382 			usbi_mutex_static_unlock(&linux_hotplug_lock);
    383 		}
    384 	}
    385 
    386 	usbi_dbg("netlink event thread exiting");
    387 
    388 	return NULL;
    389 }
    390 
    391 void linux_netlink_hotplug_poll(void)
    392 {
    393 	int r;
    394 
    395 	usbi_mutex_static_lock(&linux_hotplug_lock);
    396 	do {
    397 		r = linux_netlink_read_message();
    398 	} while (r == 0);
    399 	usbi_mutex_static_unlock(&linux_hotplug_lock);
    400 }
    401