* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <config.h>
+#include "libusbi.h"
+#include "linux_usbfs.h"
-#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <pthread.h>
#include <string.h>
#include <unistd.h>
-#include <sys/types.h>
#ifdef HAVE_ASM_TYPES_H
#include <asm/types.h>
#endif
-
-#include <sys/socket.h>
#include <linux/netlink.h>
-
-#include "libusbi.h"
-#include "linux_usbfs.h"
+#include <sys/socket.h>
#define NL_GROUP_KERNEL 1
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+
static int linux_netlink_socket = -1;
static int netlink_control_pipe[2] = { -1, -1 };
static pthread_t libusb_linux_event_thread;
static void *linux_netlink_event_thread_main(void *arg);
-static int set_fd_cloexec_nb(int fd)
+static int set_fd_cloexec_nb(int fd, int socktype)
{
int flags;
#if defined(FD_CLOEXEC)
- flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd flags (%d)", errno);
- return -1;
- }
+ /* Make sure the netlink socket file descriptor is marked as CLOEXEC */
+ if (!(socktype & SOCK_CLOEXEC)) {
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ usbi_err(NULL, "failed to get netlink fd flags, errno=%d", errno);
+ return -1;
+ }
- if (!(flags & FD_CLOEXEC)) {
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
- usbi_err(NULL, "failed to set netlink fd flags (%d)", errno);
+ usbi_err(NULL, "failed to set netlink fd flags, errno=%d", errno);
return -1;
}
}
#endif
- flags = fcntl(fd, F_GETFL);
- if (flags == -1) {
- usbi_err(NULL, "failed to get netlink fd status flags (%d)", errno);
- return -1;
- }
+ /* Make sure the netlink socket is non-blocking */
+ if (!(socktype & SOCK_NONBLOCK)) {
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ usbi_err(NULL, "failed to get netlink fd status flags, errno=%d", errno);
+ return -1;
+ }
- if (!(flags & O_NONBLOCK)) {
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
- usbi_err(NULL, "failed to set netlink fd status flags (%d)", errno);
+ usbi_err(NULL, "failed to set netlink fd status flags, errno=%d", errno);
return -1;
}
}
int linux_netlink_start_event_monitor(void)
{
struct sockaddr_nl sa_nl = { .nl_family = AF_NETLINK, .nl_groups = NL_GROUP_KERNEL };
- int socktype = SOCK_RAW;
+ int socktype = SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC;
int opt = 1;
int ret;
-#if defined(SOCK_CLOEXEC)
- socktype |= SOCK_CLOEXEC;
-#endif
-#if defined(SOCK_NONBLOCK)
- socktype |= SOCK_NONBLOCK;
-#endif
-
linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
if (linux_netlink_socket == -1 && errno == EINVAL) {
usbi_dbg("failed to create netlink socket of type %d, attempting SOCK_RAW", socktype);
- linux_netlink_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
+ socktype = SOCK_RAW;
+ linux_netlink_socket = socket(PF_NETLINK, socktype, NETLINK_KOBJECT_UEVENT);
}
if (linux_netlink_socket == -1) {
- usbi_err(NULL, "failed to create netlink socket (%d)", errno);
+ usbi_err(NULL, "failed to create netlink socket, errno=%d", errno);
goto err;
}
- ret = set_fd_cloexec_nb(linux_netlink_socket);
+ ret = set_fd_cloexec_nb(linux_netlink_socket, socktype);
if (ret == -1)
goto err_close_socket;
ret = bind(linux_netlink_socket, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
if (ret == -1) {
- usbi_err(NULL, "failed to bind netlink socket (%d)", errno);
+ usbi_err(NULL, "failed to bind netlink socket, errno=%d", errno);
goto err_close_socket;
}
ret = setsockopt(linux_netlink_socket, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt));
if (ret == -1) {
- usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option (%d)", errno);
+ usbi_err(NULL, "failed to set netlink socket SO_PASSCRED option, errno=%d", errno);
goto err_close_socket;
}
len = recvmsg(linux_netlink_socket, &msg, 0);
if (len == -1) {
if (errno != EAGAIN && errno != EINTR)
- usbi_err(NULL, "error receiving message from netlink (%d)", errno);
+ usbi_err(NULL, "error receiving message from netlink, errno=%d", errno);
return -1;
}