Page MenuHomeFreeBSD

D51865.diff
No OneTemporary

D51865.diff

diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile
--- a/lib/libusb/Makefile
+++ b/lib/libusb/Makefile
@@ -18,7 +18,7 @@
WARNS?= 2
-VERSION_DEF= ${SRCTOP}/lib/libc/Versions.def
+VERSION_DEF= ${.CURDIR}/Versions.def
SYMBOL_MAPS= ${.CURDIR}/Symbol.map
LIBADD= pthread
diff --git a/lib/libusb/Symbol.map b/lib/libusb/Symbol.map
--- a/lib/libusb/Symbol.map
+++ b/lib/libusb/Symbol.map
@@ -120,10 +120,6 @@
libusb_wait_for_event;
libusb_wrap_sys_device;
libusb20_be_add_dev_quirk;
- libusb20_be_alloc;
- libusb20_be_alloc_default;
- libusb20_be_alloc_linux;
- libusb20_be_alloc_ugen20;
libusb20_be_dequeue_device;
libusb20_be_device_foreach;
libusb20_be_enqueue_device;
@@ -258,3 +254,12 @@
usb_set_debug;
usb_strerror;
};
+
+FBSD_1.10 {
+ libusb20_be_alloc;
+ libusb20_be_alloc_default;
+ libusb20_be_alloc_linux;
+ libusb20_be_alloc_ugen20;
+ libusb20_be_ctx_alloc;
+ libusb20_be_ctx_free;
+};
diff --git a/lib/libusb/Versions.def b/lib/libusb/Versions.def
new file mode 100644
--- /dev/null
+++ b/lib/libusb/Versions.def
@@ -0,0 +1,5 @@
+FBSD_1.9 {
+};
+
+FBSD_1.10 {
+} FBSD_1.9;
diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3
--- a/lib/libusb/libusb.3
+++ b/lib/libusb/libusb.3
@@ -945,8 +945,25 @@
.Fn usb_get_driver_np
.Fn usb_detach_kernel_driver_np
.Fn usb_attach_kernel_driver_np
+.Sh CAPABILITY MODE
+Every
+.Nm
+context opens the file descriptors needed to reach the USB devices at
+.Fn libusb_init
+time and opens device nodes relative to a per-context directory
+descriptor using
+.Xr openat 2 .
+All operations on the context, including enumeration of hotplugged
+devices, therefore keep working after entering capability mode, see
+.Xr capsicum 4 .
+The file descriptors are limited with
+.Xr cap_rights_limit 2 .
+Initialise the context before calling
+.Xr cap_enter 2 .
.Sh SEE ALSO
+.Xr cap_enter 2 ,
.Xr libusb20 3 ,
+.Xr capsicum 4 ,
.Xr usb 4 ,
.Xr usbconfig 8 ,
.Xr usbdump 8
diff --git a/lib/libusb/libusb01.c b/lib/libusb/libusb01.c
--- a/lib/libusb/libusb01.c
+++ b/lib/libusb/libusb01.c
@@ -85,6 +85,13 @@
static struct libusb20_backend *usb_backend = NULL;
+/*
+ * The backend context lives for the lifetime of the process, because
+ * opened devices are dequeued from the backend and survive backend
+ * rescans. The libusb v0.1 API has no exit function anyway.
+ */
+static struct libusb20_be_ctx *usb_be_ctx = NULL;
+
struct usb_parse_state {
struct {
@@ -901,8 +908,14 @@
libusb20_be_free(usb_backend);
+ if (usb_be_ctx == NULL) {
+ usb_be_ctx = libusb20_be_ctx_alloc();
+ if (usb_be_ctx == NULL) {
+ return (-1);
+ }
+ }
/* do a new backend device search */
- usb_backend = libusb20_be_alloc_default();
+ usb_backend = libusb20_be_alloc_default(usb_be_ctx);
if (usb_backend == NULL) {
return (-1);
}
diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h
--- a/lib/libusb/libusb10.h
+++ b/lib/libusb/libusb10.h
@@ -120,6 +120,9 @@
void *fd_cb_user_data;
libusb_log_cb log_cb;
int no_discovery;
+
+ /* backend context holding the USB file descriptors */
+ struct libusb20_be_ctx *be_ctx;
};
struct libusb_device {
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
--- a/lib/libusb/libusb10.c
+++ b/lib/libusb/libusb10.c
@@ -302,6 +302,21 @@
return (LIBUSB_ERROR_OTHER);
}
+ /*
+ * The backend context acquires the file descriptors needed to
+ * reach the USB devices, so that the context keeps working
+ * after cap_enter(2) has been called.
+ */
+ ctx->be_ctx = libusb20_be_ctx_alloc();
+ if (ctx->be_ctx == NULL) {
+ close(ctx->event);
+ pthread_mutex_destroy(&ctx->ctx_lock);
+ pthread_mutex_destroy(&ctx->hotplug_lock);
+ pthread_cond_destroy(&ctx->ctx_cond);
+ free(ctx);
+ return (LIBUSB_ERROR_NO_MEM);
+ }
+
libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->event, POLLIN);
pthread_mutex_lock(&default_context_lock);
@@ -353,6 +368,7 @@
libusb10_remove_pollfd(ctx, &ctx->ctx_poll);
close(ctx->event);
+ libusb20_be_ctx_free(ctx->be_ctx);
pthread_mutex_destroy(&ctx->ctx_lock);
pthread_mutex_destroy(&ctx->hotplug_lock);
pthread_cond_destroy(&ctx->ctx_cond);
@@ -384,7 +400,7 @@
if (list == NULL)
return (LIBUSB_ERROR_INVALID_PARAM);
- usb_backend = libusb20_be_alloc_default();
+ usb_backend = libusb20_be_alloc_default(ctx->be_ctx);
if (usb_backend == NULL)
return (LIBUSB_ERROR_NO_MEM);
diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h
--- a/lib/libusb/libusb20.h
+++ b/lib/libusb/libusb20.h
@@ -177,6 +177,7 @@
struct libusb20_transfer;
struct libusb20_backend;
struct libusb20_backend_methods;
+struct libusb20_be_ctx;
struct libusb20_device;
struct libusb20_device_methods;
struct libusb20_config;
@@ -294,11 +295,13 @@
/* USB backend operations */
-struct libusb20_backend *libusb20_be_alloc(const struct libusb20_backend_methods *methods);
-struct libusb20_backend *libusb20_be_alloc_default(void);
-struct libusb20_backend *libusb20_be_alloc_freebsd(void);
-struct libusb20_backend *libusb20_be_alloc_linux(void);
-struct libusb20_backend *libusb20_be_alloc_ugen20(void);
+struct libusb20_backend *libusb20_be_alloc(const struct libusb20_backend_methods *methods, struct libusb20_be_ctx *pctx);
+struct libusb20_backend *libusb20_be_alloc_default(struct libusb20_be_ctx *pctx);
+struct libusb20_backend *libusb20_be_alloc_freebsd(struct libusb20_be_ctx *pctx);
+struct libusb20_backend *libusb20_be_alloc_linux(struct libusb20_be_ctx *pctx);
+struct libusb20_backend *libusb20_be_alloc_ugen20(struct libusb20_be_ctx *pctx);
+struct libusb20_be_ctx *libusb20_be_ctx_alloc(void);
+void libusb20_be_ctx_free(struct libusb20_be_ctx *pctx);
struct libusb20_device *libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device *pdev);
void libusb20_be_dequeue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev);
void libusb20_be_enqueue_device(struct libusb20_backend *pbe, struct libusb20_device *pdev);
diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3
--- a/lib/libusb/libusb20.3
+++ b/lib/libusb/libusb20.3
@@ -198,11 +198,15 @@
.Ft int
.Fn libusb20_be_remove_dev_quirk "struct libusb20_backend *pbe" "struct libusb20_quirk *pq"
.Ft struct libusb20_backend *
-.Fn libusb20_be_alloc_default "void"
+.Fn libusb20_be_alloc_default "struct libusb20_be_ctx *pctx"
.Ft struct libusb20_backend *
-.Fn libusb20_be_alloc_freebsd "void"
+.Fn libusb20_be_alloc_freebsd "struct libusb20_be_ctx *pctx"
.Ft struct libusb20_backend *
-.Fn libusb20_be_alloc_linux "void"
+.Fn libusb20_be_alloc_linux "struct libusb20_be_ctx *pctx"
+.Ft struct libusb20_be_ctx *
+.Fn libusb20_be_ctx_alloc "void"
+.Ft void
+.Fn libusb20_be_ctx_free "struct libusb20_be_ctx *pctx"
.Ft struct libusb20_device *
.Fn libusb20_be_device_foreach "struct libusb20_backend *pbe" "struct libusb20_device *pdev"
.Ft void
@@ -994,6 +998,31 @@
These functions are used to allocate a specific USB backend or the operating system
default USB backend.
Allocating a backend is a way to scan for currently present USB devices.
+The backend and the USB devices it enumerates borrow the given
+backend context, which holds the file descriptors used to reach the
+USB devices and must stay alive for as long as they are in use.
+If the
+.Fa pctx
+argument is NULL, the backend allocates its own context and releases
+it when the backend is freed.
+USB devices which have been dequeued from such a backend must not be
+used after the backend has been freed.
+.Pp
+.
+.Fn libusb20_be_ctx_alloc
+allocates a backend context, which opens and holds the file
+descriptors used to reach the USB devices.
+The context is immutable after allocation and may therefore be shared
+between threads, backends and devices without any locking.
+Sharing one context across multiple backend allocations allows
+devices to be enumerated and opened after the process has entered
+capability mode.
+.
+.Fn libusb20_be_ctx_free
+frees the given backend context.
+No backend or device allocated from the context may be used
+afterwards.
+This function is NULL safe.
.Pp
.
.Fn libusb20_be_device_foreach
@@ -1086,8 +1115,36 @@
.Bl -tag -width Pa
.It Pa /dev/usb
.El
+.Sh CAPABILITY MODE
+The backend context holds file descriptors for
+.Pa /dev/usbctl
+and the
+.Pa /dev/usb
+directory, and device nodes are opened relative to the directory
+descriptor using
+.Xr openat 2 .
+All backend operations, including enumeration of hotplugged devices,
+therefore keep working after entering capability mode, see
+.Xr capsicum 4 ,
+as long as the backend context was allocated before
+.Xr cap_enter 2
+was called.
+Applications which allocate more than one USB backend from capability
+mode must allocate a backend context with
+.Fn libusb20_be_ctx_alloc
+up front and pass it to every backend allocation.
+The file descriptors are limited with
+.Xr cap_rights_limit 2 ,
+and USB device file descriptors derived from the directory descriptor
+inherit the
+.Dv CAP_PREAD , CAP_PWRITE , CAP_EVENT
+and
+.Dv CAP_IOCTL
+rights.
.Sh SEE ALSO
+.Xr cap_enter 2 ,
.Xr libusb 3 ,
+.Xr capsicum 4 ,
.Xr usb 4 ,
.Xr usbconfig 8 ,
.Xr usbdump 8
diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c
--- a/lib/libusb/libusb20.c
+++ b/lib/libusb/libusb20.c
@@ -30,6 +30,7 @@
#else
#include <ctype.h>
#include <poll.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -1273,7 +1274,8 @@
}
struct libusb20_backend *
-libusb20_be_alloc(const struct libusb20_backend_methods *methods)
+libusb20_be_alloc(const struct libusb20_backend_methods *methods,
+ struct libusb20_be_ctx *pctx)
{
struct libusb20_backend *pbe;
@@ -1283,6 +1285,17 @@
}
memset(pbe, 0, sizeof(*pbe));
+ if (pctx == NULL) {
+ /* the backend owns its own context */
+ pctx = libusb20_be_ctx_alloc();
+ if (pctx == NULL) {
+ free(pbe);
+ return (NULL);
+ }
+ pbe->be_ctx_owner = 1;
+ }
+ pbe->be_ctx = pctx;
+
TAILQ_INIT(&(pbe->usb_devs));
pbe->methods = methods; /* set backend methods */
@@ -1295,35 +1308,100 @@
}
struct libusb20_backend *
-libusb20_be_alloc_linux(void)
+libusb20_be_alloc_linux(struct libusb20_be_ctx *pctx)
{
return (NULL);
}
struct libusb20_backend *
-libusb20_be_alloc_ugen20(void)
+libusb20_be_alloc_ugen20(struct libusb20_be_ctx *pctx)
{
- return (libusb20_be_alloc(&libusb20_ugen20_backend));
+ return (libusb20_be_alloc(&libusb20_ugen20_backend, pctx));
}
struct libusb20_backend *
-libusb20_be_alloc_default(void)
+libusb20_be_alloc_default(struct libusb20_be_ctx *pctx)
{
struct libusb20_backend *pbe;
#ifdef __linux__
- pbe = libusb20_be_alloc_linux();
+ pbe = libusb20_be_alloc_linux(pctx);
if (pbe) {
return (pbe);
}
#endif
- pbe = libusb20_be_alloc_ugen20();
+ pbe = libusb20_be_alloc_ugen20(pctx);
+ if (pbe) {
+ return (pbe);
+ }
+ return (NULL); /* no backend found */
+}
+
+#if defined(__FreeBSD__) && !defined(LIBUSB_GLOBAL_INCLUDE_FILE)
+static pthread_once_t fbsd19_be_ctx_once = PTHREAD_ONCE_INIT;
+static struct libusb20_be_ctx *fbsd19_be_ctx;
+
+struct libusb20_backend *fbsd19_libusb20_be_alloc(const struct libusb20_backend_methods *methods);
+struct libusb20_backend *fbsd19_libusb20_be_alloc_default(void);
+struct libusb20_backend *fbsd19_libusb20_be_alloc_linux(void);
+struct libusb20_backend *fbsd19_libusb20_be_alloc_ugen20(void);
+
+static void
+fbsd19_be_ctx_init(void)
+{
+ fbsd19_be_ctx = libusb20_be_ctx_alloc();
+}
+
+static struct libusb20_be_ctx *
+fbsd19_be_ctx_get(void)
+{
+ if (pthread_once(&fbsd19_be_ctx_once, fbsd19_be_ctx_init) != 0)
+ return (NULL);
+ return (fbsd19_be_ctx);
+}
+
+struct libusb20_backend *
+fbsd19_libusb20_be_alloc(const struct libusb20_backend_methods *methods)
+{
+ struct libusb20_be_ctx *pctx;
+
+ pctx = fbsd19_be_ctx_get();
+ if (pctx == NULL) {
+ return (NULL);
+ }
+ return (libusb20_be_alloc(methods, pctx));
+}
+
+struct libusb20_backend *
+fbsd19_libusb20_be_alloc_linux(void)
+{
+ return (NULL);
+}
+
+struct libusb20_backend *
+fbsd19_libusb20_be_alloc_ugen20(void)
+{
+ return (fbsd19_libusb20_be_alloc(&libusb20_ugen20_backend));
+}
+
+struct libusb20_backend *
+fbsd19_libusb20_be_alloc_default(void)
+{
+ struct libusb20_backend *pbe;
+
+ pbe = fbsd19_libusb20_be_alloc_ugen20();
if (pbe) {
return (pbe);
}
return (NULL); /* no backend found */
}
+__sym_compat(libusb20_be_alloc, fbsd19_libusb20_be_alloc, FBSD_1.9);
+__sym_compat(libusb20_be_alloc_default, fbsd19_libusb20_be_alloc_default, FBSD_1.9);
+__sym_compat(libusb20_be_alloc_linux, fbsd19_libusb20_be_alloc_linux, FBSD_1.9);
+__sym_compat(libusb20_be_alloc_ugen20, fbsd19_libusb20_be_alloc_ugen20, FBSD_1.9);
+#endif
+
void
libusb20_be_free(struct libusb20_backend *pbe)
{
@@ -1340,6 +1418,8 @@
if (pbe->methods->exit_backend) {
pbe->methods->exit_backend(pbe);
}
+ if (pbe->be_ctx_owner)
+ libusb20_be_ctx_free(pbe->be_ctx);
/* free backend */
free(pbe);
}
diff --git a/lib/libusb/libusb20_be_device_foreach.3 b/lib/libusb/libusb20_be_device_foreach.3
--- a/lib/libusb/libusb20_be_device_foreach.3
+++ b/lib/libusb/libusb20_be_device_foreach.3
@@ -39,7 +39,7 @@
.Sh EXAMPLES
.Bd -literal
#include <libusb20.h>
- struct libusb20_backend *be = libusb20_be_alloc_default();
+ struct libusb20_backend *be = libusb20_be_alloc_default(NULL);
struct libusb20_device *device = NULL;
while ( (device = libusb20_be_device_foreach(be, device)) != NULL ) {
if (libusb20_dev_open(device, 0) == LIBUSB20_SUCCESS) {
diff --git a/lib/libusb/libusb20_dev_open.3 b/lib/libusb/libusb20_dev_open.3
--- a/lib/libusb/libusb20_dev_open.3
+++ b/lib/libusb/libusb20_dev_open.3
@@ -53,7 +53,7 @@
.Sh EXAMPLES
.Bd -literal
#include <libusb20.h>
- struct libusb20_backend *be = libusb20_be_alloc_default();
+ struct libusb20_backend *be = libusb20_be_alloc_default(NULL);
struct libusb20_device *device = NULL;
while ( (device = libusb20_be_device_foreach(be, device)) != NULL ) {
if (libusb20_dev_open(device, 0) == LIBUSB20_SUCCESS) {
diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h
--- a/lib/libusb/libusb20_int.h
+++ b/lib/libusb/libusb20_int.h
@@ -43,6 +43,21 @@
uint32_t plugtime;
};
+/*
+ * The backend context holds the file descriptors needed to reach the
+ * USB devices. It is immutable after allocation, so it can be shared
+ * between threads, backends and devices without any locking. Sharing
+ * it between backend allocations keeps enumeration working after the
+ * process has entered capability mode, see capsicum(4).
+ *
+ * The context must stay alive for as long as any backend or device
+ * allocated from it is in use.
+ */
+struct libusb20_be_ctx {
+ int ctrl_fd; /* /dev/usbctl */
+ int usb_dfd; /* /dev/usb directory */
+};
+
/* USB backend specific */
typedef const char *(libusb20_get_backend_name_t)(void);
typedef int (libusb20_root_get_dev_quirk_t)(struct libusb20_backend *pbe, uint16_t index, struct libusb20_quirk *pq);
@@ -144,6 +159,10 @@
struct libusb20_backend {
TAILQ_HEAD(, libusb20_device) usb_devs;
const struct libusb20_backend_methods *methods;
+
+ /* borrowed backend context, owned when "be_ctx_owner" is set */
+ struct libusb20_be_ctx *be_ctx;
+ uint8_t be_ctx_owner;
};
struct libusb20_transfer {
@@ -195,6 +214,9 @@
/* backend methods */
const struct libusb20_backend_methods *beMethods;
+ /* borrowed backend context */
+ struct libusb20_be_ctx *be_ctx;
+
/* list of USB transfers */
struct libusb20_transfer *pTransfer;
diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c
--- a/lib/libusb/libusb20_ugen20.c
+++ b/lib/libusb/libusb20_ugen20.c
@@ -35,6 +35,7 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include <sys/capsicum.h>
#include <sys/queue.h>
#include <sys/types.h>
#endif
@@ -69,6 +70,67 @@
LIBUSB20_BACKEND(LIBUSB20_DECLARE, ugen20)
};
+struct libusb20_be_ctx *
+libusb20_be_ctx_alloc(void)
+{
+ cap_rights_t rights;
+ struct libusb20_be_ctx *pctx;
+ int fd;
+
+ pctx = malloc(sizeof(*pctx));
+ if (pctx == NULL)
+ return (NULL);
+
+ /*
+ * The context is immutable once this function returns, which
+ * makes it safe to share between threads without any locking.
+ * Open failures are tolerated, so that allocation also
+ * succeeds on systems without USB support.
+ */
+ fd = open("/dev/" USB_DEVICE_NAME, O_RDONLY | O_CLOEXEC);
+ if (fd > -1) {
+ cap_rights_init(&rights, CAP_READ, CAP_EVENT, CAP_IOCTL);
+ if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ pctx->ctrl_fd = fd;
+
+ fd = open("/dev/" USB_DEVICE_DIR, O_DIRECTORY | O_PATH | O_CLOEXEC);
+ if (fd > -1) {
+ /*
+ * Device descriptors derived through openat(2)
+ * inherit these rights, so they must cover all
+ * operations performed on open devices, including by
+ * applications using libusb20_dev_get_fd().
+ */
+ cap_rights_init(&rights, CAP_LOOKUP, CAP_PREAD, CAP_PWRITE,
+ CAP_EVENT, CAP_IOCTL);
+ if (cap_rights_limit(fd, &rights) == -1 && errno != ENOSYS) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ pctx->usb_dfd = fd;
+
+ return (pctx);
+}
+
+void
+libusb20_be_ctx_free(struct libusb20_be_ctx *pctx)
+{
+ if (pctx == NULL) {
+ /* be NULL safe */
+ return;
+ }
+ if (pctx->ctrl_fd > -1)
+ close(pctx->ctrl_fd);
+ if (pctx->usb_dfd > -1)
+ close(pctx->usb_dfd);
+ free(pctx);
+}
+
/* USB device specific */
static libusb20_get_config_desc_full_t ugen20_get_config_desc_full;
static libusb20_get_config_index_t ugen20_get_config_index;
@@ -173,6 +235,25 @@
return (temp);
}
+static int
+ugen20_open_dev(struct libusb20_be_ctx *pctx, int bus_num, int dev_addr,
+ int flag)
+{
+ char path[48];
+ int usb_dfd;
+
+ usb_dfd = pctx->usb_dfd;
+ if (usb_dfd > -1) {
+ snprintf(path, sizeof(path), "%u.%u.0", bus_num, dev_addr);
+ return (openat(usb_dfd, path, flag));
+ }
+
+ /* fall back when the /dev/usb directory is not available */
+ snprintf(path, sizeof(path), "/dev/" USB_GENERIC_NAME "%u.%u",
+ bus_num, dev_addr);
+ return (open(path, flag));
+}
+
static int
ugen20_enumerate(struct libusb20_device *pdev, const char *id)
{
@@ -181,17 +262,14 @@
struct usb_device_info devinfo;
struct usb_device_port_path udpp;
uint32_t plugtime;
- char buf[64];
int f;
int error;
pdev->bus_number = ugen20_path_convert_one(&tmp);
pdev->device_address = ugen20_path_convert_one(&tmp);
- snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
- pdev->bus_number, pdev->device_address);
-
- f = open(buf, O_RDWR);
+ f = ugen20_open_dev(pdev->be_ctx, pdev->bus_number,
+ pdev->device_address, O_RDWR);
if (f < 0) {
return (LIBUSB20_ERROR_OTHER);
}
@@ -332,7 +410,7 @@
memset(&state, 0, sizeof(state));
- state.f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
+ state.f = pbe->be_ctx->ctrl_fd;
if (state.f < 0)
return (LIBUSB20_ERROR_OTHER);
@@ -348,6 +426,12 @@
if (pdev == NULL) {
continue;
}
+ /*
+ * The device borrows the backend context, which must
+ * stay alive for as long as the device is in use.
+ */
+ pdev->be_ctx = pbe->be_ctx;
+
if (ugen20_enumerate(pdev, state.src + 4)) {
libusb20_dev_free(pdev);
continue;
@@ -355,7 +439,6 @@
/* put the device on the backend list */
libusb20_be_enqueue_device(pbe, pdev);
}
- close(state.f);
return (0); /* success */
}
@@ -422,24 +505,22 @@
ugen20_open_device(struct libusb20_device *pdev, uint16_t nMaxTransfer)
{
uint32_t plugtime;
- char buf[64];
int f;
int g;
int error;
- snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
- pdev->bus_number, pdev->device_address);
-
/*
* We need two file handles, one for the control endpoint and one
* for BULK, INTERRUPT and ISOCHRONOUS transactions due to optimised
* kernel locking.
*/
- g = open(buf, O_RDWR);
+ g = ugen20_open_dev(pdev->be_ctx, pdev->bus_number,
+ pdev->device_address, O_RDWR);
if (g < 0) {
return (LIBUSB20_ERROR_NO_DEVICE);
}
- f = open(buf, O_RDWR);
+ f = ugen20_open_dev(pdev->be_ctx, pdev->bus_number,
+ pdev->device_address, O_RDWR);
if (f < 0) {
close(g);
return (LIBUSB20_ERROR_NO_DEVICE);
@@ -991,12 +1072,12 @@
}
static int
-ugen20_be_ioctl(uint32_t cmd, void *data)
+ugen20_be_ioctl(struct libusb20_be_ctx *pctx, uint32_t cmd, void *data)
{
int f;
int error;
- f = open("/dev/" USB_DEVICE_NAME, O_RDONLY);
+ f = pctx->ctrl_fd;
if (f < 0)
return (LIBUSB20_ERROR_OTHER);
error = ioctl(f, cmd, data);
@@ -1007,7 +1088,6 @@
error = LIBUSB20_ERROR_OTHER;
}
}
- close(f);
return (error);
}
@@ -1050,7 +1130,7 @@
q.index = quirk_index;
- error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_GET), &q);
+ error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_DEV_QUIRK_GET), &q);
if (error) {
if (errno == EINVAL) {
@@ -1077,7 +1157,7 @@
q.index = quirk_index;
- error = ugen20_be_ioctl(IOUSB(USB_QUIRK_NAME_GET), &q);
+ error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_QUIRK_NAME_GET), &q);
if (error) {
if (errno == EINVAL) {
@@ -1104,7 +1184,7 @@
q.bcdDeviceHigh = pq->bcdDeviceHigh;
strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
- error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_ADD), &q);
+ error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_DEV_QUIRK_ADD), &q);
if (error) {
if (errno == ENOMEM) {
return (LIBUSB20_ERROR_NO_MEM);
@@ -1128,7 +1208,7 @@
q.bcdDeviceHigh = pq->bcdDeviceHigh;
strlcpy(q.quirkname, pq->quirkname, sizeof(q.quirkname));
- error = ugen20_be_ioctl(IOUSB(USB_DEV_QUIRK_REMOVE), &q);
+ error = ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_DEV_QUIRK_REMOVE), &q);
if (error) {
if (errno == EINVAL) {
return (LIBUSB20_ERROR_NOT_FOUND);
@@ -1140,11 +1220,11 @@
static int
ugen20_root_set_template(struct libusb20_backend *pbe, int temp)
{
- return (ugen20_be_ioctl(IOUSB(USB_SET_TEMPLATE), &temp));
+ return (ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_SET_TEMPLATE), &temp));
}
static int
ugen20_root_get_template(struct libusb20_backend *pbe, int *ptemp)
{
- return (ugen20_be_ioctl(IOUSB(USB_GET_TEMPLATE), ptemp));
+ return (ugen20_be_ioctl(pbe->be_ctx, IOUSB(USB_GET_TEMPLATE), ptemp));
}
diff --git a/share/examples/libusb20/bulk.c b/share/examples/libusb20/bulk.c
--- a/share/examples/libusb20/bulk.c
+++ b/share/examples/libusb20/bulk.c
@@ -32,6 +32,7 @@
*/
+#include <capsicum_helpers.h>
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
@@ -219,12 +220,18 @@
struct libusb20_backend *be;
struct libusb20_device *dev;
- if ((be = libusb20_be_alloc_default()) == NULL)
+ if ((be = libusb20_be_alloc_default(NULL)) == NULL)
{
perror("libusb20_be_alloc()");
return 1;
}
+ if (caph_enter() < 0)
+ {
+ perror("caph_enter()");
+ return 1;
+ }
+
dev = NULL;
while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
{
diff --git a/share/examples/libusb20/control.c b/share/examples/libusb20/control.c
--- a/share/examples/libusb20/control.c
+++ b/share/examples/libusb20/control.c
@@ -30,6 +30,7 @@
*/
+#include <capsicum_helpers.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
@@ -391,12 +392,18 @@
struct libusb20_backend *be;
struct libusb20_device *dev;
- if ((be = libusb20_be_alloc_default()) == NULL)
+ if ((be = libusb20_be_alloc_default(NULL)) == NULL)
{
perror("libusb20_be_alloc()");
return 1;
}
+ if (caph_enter() < 0)
+ {
+ perror("caph_enter()");
+ return 1;
+ }
+
dev = NULL;
while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
{
diff --git a/tools/tools/usbtest/usb_msc_test.c b/tools/tools/usbtest/usb_msc_test.c
--- a/tools/tools/usbtest/usb_msc_test.c
+++ b/tools/tools/usbtest/usb_msc_test.c
@@ -870,7 +870,7 @@
const char *ptr;
top:
- pbe = libusb20_be_alloc_default();
+ pbe = libusb20_be_alloc_default(usb_be_ctx);
pdev = NULL;
index = 0;
@@ -916,7 +916,7 @@
struct libusb20_device *
find_usb_device(struct uaddr uaddr)
{
- struct libusb20_backend *pbe = libusb20_be_alloc_default();
+ struct libusb20_backend *pbe = libusb20_be_alloc_default(usb_be_ctx);
struct libusb20_device *pdev = NULL;
struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
diff --git a/tools/tools/usbtest/usbtest.h b/tools/tools/usbtest/usbtest.h
--- a/tools/tools/usbtest/usbtest.h
+++ b/tools/tools/usbtest/usbtest.h
@@ -65,4 +65,7 @@
extern uint8_t usb_ts_show_menu(uint8_t, const char *, const char *,...);
extern int32_t usb_ts_rand_noise(void);
+struct libusb20_be_ctx;
+extern struct libusb20_be_ctx *usb_be_ctx;
+
#endif /* _USBTEST_H_ */
diff --git a/tools/tools/usbtest/usbtest.c b/tools/tools/usbtest/usbtest.c
--- a/tools/tools/usbtest/usbtest.c
+++ b/tools/tools/usbtest/usbtest.c
@@ -31,9 +31,13 @@
#include <stdarg.h>
#include <stdlib.h>
+#include <capsicum_helpers.h>
+
#include <sys/types.h>
#include <sys/sysctl.h>
+#include <libusb20.h>
+
#include <dev/usb/usb_ioctl.h>
#include "usbtest.h"
@@ -45,6 +49,8 @@
static uint8_t usb_ts_select[USB_TS_MAX_LEVELS];
+struct libusb20_be_ctx *usb_be_ctx;
+
const char *indent[USB_TS_MAX_LEVELS] = {
" ",
" ",
@@ -805,7 +811,20 @@
int
main(int argc, char **argv)
{
+ /*
+ * The backend context acquires the descriptors needed to
+ * reach the USB devices before entering capability mode.
+ */
+ usb_be_ctx = libusb20_be_ctx_alloc();
+ if (usb_be_ctx == NULL)
+ err(1, "could not allocate USB backend context");
+
+ if (caph_enter() < 0)
+ err(1, "caph_enter() failed");
+
show_mode_select(1);
+ libusb20_be_ctx_free(usb_be_ctx);
+
return (0);
}
diff --git a/usr.sbin/usbconfig/dump.h b/usr.sbin/usbconfig/dump.h
--- a/usr.sbin/usbconfig/dump.h
+++ b/usr.sbin/usbconfig/dump.h
@@ -28,6 +28,7 @@
#ifndef _DUMP_H_
#define _DUMP_H_
+void dump_vendors_init(void);
const char *dump_mode(uint8_t value);
const char *dump_speed(uint8_t value);
const char *dump_power_mode(uint8_t value);
diff --git a/usr.sbin/usbconfig/dump.c b/usr.sbin/usbconfig/dump.c
--- a/usr.sbin/usbconfig/dump.c
+++ b/usr.sbin/usbconfig/dump.c
@@ -42,7 +42,6 @@
#include <pwd.h>
#include <grp.h>
#include <ctype.h>
-#include <fcntl.h>
#include <libusb20.h>
#include <libusb20_desc.h>
@@ -52,10 +51,6 @@
#include "dump.h"
#include "pathnames.h"
-#ifndef IOUSB
-#define IOUSB(a) a
-#endif
-
#define DUMP0(n,type,field,...) dump_field(pdev, " ", #field, n->field);
#define DUMP0L(n,type,field,...) dump_fieldl(pdev, " ", #field, n->field);
#define DUMP1(n,type,field,...) dump_field(pdev, " ", #field, n->field);
@@ -77,6 +72,8 @@
STAILQ_HEAD(usb_vendors, usb_vendor_info);
+static struct usb_vendors *usb_vendors = NULL;
+
const char *
dump_mode(uint8_t value)
{
@@ -352,18 +349,24 @@
}
}
-static struct usb_vendors *
-load_vendors(void)
+/*
+ * Read the USB vendor database. This has to happen before entering
+ * capability mode, because the database is looked up by pathname.
+ */
+void
+dump_vendors_init(void)
{
const char *dbf;
FILE *db = NULL;
struct usb_vendor_info *cv;
struct usb_product_info *cd;
- struct usb_vendors *usb_vendors;
char buf[1024], str[1024];
char *ch;
int id;
+ if (usb_vendors != NULL)
+ return;
+
usb_vendors = malloc(sizeof(*usb_vendors));
if (usb_vendors == NULL)
err(1, "out of memory");
@@ -375,7 +378,7 @@
if ((db = fopen(dbf, "r")) == NULL) {
dbf = _PATH_USBVDB;
if ((db = fopen(dbf, "r")) == NULL)
- return (usb_vendors);
+ return;
}
}
cv = NULL;
@@ -433,7 +436,6 @@
fclose(db);
/* cleanup */
- return (usb_vendors);
}
enum _device_descr_list_type {
@@ -446,7 +448,6 @@
_device_desc(struct libusb20_device *pdev,
enum _device_descr_list_type list_type)
{
- static struct usb_vendors *usb_vendors = NULL;
char *desc = NULL;
const char *vendor = NULL, *product = NULL;
uint16_t vid;
@@ -465,8 +466,7 @@
vid = libusb20_dev_get_device_desc(pdev)->idVendor;
pid = libusb20_dev_get_device_desc(pdev)->idProduct;
- if (usb_vendors == NULL)
- usb_vendors = load_vendors();
+ dump_vendors_init();
STAILQ_FOREACH(vi, usb_vendors, link) {
if (vi->id == vid) {
@@ -483,34 +483,18 @@
}
}
- /*
- * Try to gather the information; libusb2 unfortunately seems to
- * only build an entire string but not save vendor/product individually.
- */
if (vendor == NULL || product == NULL) {
- char buf[64];
- int f;
-
- snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
- libusb20_dev_get_bus_number(pdev),
- libusb20_dev_get_address(pdev));
-
- f = open(buf, O_RDWR);
- if (f < 0)
- goto skip_vp_recovery;
-
- if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo))
- goto skip_vp_recovery;
-
-
- if (vendor == NULL)
- vendor = devinfo.udi_vendor;
- if (product == NULL)
- product = devinfo.udi_product;
-
-skip_vp_recovery:
- if (f >= 0)
- close(f);
+ /*
+ * Ask through the already open device, rather than
+ * reopening it by pathname, so that this keeps working
+ * in capability mode.
+ */
+ if (libusb20_dev_get_info(pdev, &devinfo) == 0) {
+ if (vendor == NULL)
+ vendor = devinfo.udi_vendor;
+ if (product == NULL)
+ product = devinfo.udi_product;
+ }
}
if (list_type == _DEVICE_DESCR_LIST_TYPE_PRODUCT_VENDOR) {
diff --git a/usr.sbin/usbconfig/usbconfig.c b/usr.sbin/usbconfig/usbconfig.c
--- a/usr.sbin/usbconfig/usbconfig.c
+++ b/usr.sbin/usbconfig/usbconfig.c
@@ -37,6 +37,7 @@
#include <grp.h>
#include <errno.h>
#include <ctype.h>
+#include <capsicum_helpers.h>
#include <sys/param.h>
#include <libusb20_desc.h>
@@ -568,10 +569,20 @@
if (argc < 1) {
usage(EX_USAGE);
}
- pbe = libusb20_be_alloc_default();
+ pbe = libusb20_be_alloc_default(NULL);
if (pbe == NULL)
err(1, "could not access USB backend\n");
+ /* The USB vendor database is looked up by pathname. */
+ dump_vendors_init();
+
+ /*
+ * The backend has cached the descriptors needed to reach the
+ * USB devices, so the rest can run in capability mode.
+ */
+ if (caph_enter() < 0)
+ err(1, "caph_enter() failed");
+
while ((ch = getopt(argc, argv, "a:d:hi:lu:v")) != -1) {
switch (ch) {
case 'a':

File Metadata

Mime Type
text/plain
Expires
Fri, Aug 14, 1:29 PM (22 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36730734
Default Alt Text
D51865.diff (29 KB)

Event Timeline