mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
libusb: capsicumize libusb
FreeBSD's libusb has three components: libusb01, libusb10, and libusb20. libusb20 handles communication with character devices. We now requires a backend context for libusb20. The backend context contains contains the capsicumized usbctrl fd and usb directory (/dev/usb) fd so that the library user can enter the capiblity mode safely while using libusb. libusb10 is updated to support capabilities via a context option. Since libusb allows general read/write access, we preserve all possible capabilities when passing backend context to libusb20. It is the responsibility of the libusb user to call cap_enter() at an appropriate time. All base system tools using libusb and libusb20 have been updated to support Capsicum. Reviewed by: adrian, markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D51865
This commit is contained in:
1 parent
7144a1d58c
commit
749318f2ae
20 files changed
+354
-91
No files matched your search
@@ -120,10 +120,6 @@ FBSD_1.8 {
|
||||
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 @@ FBSD_1.8 {
|
||||
usb_set_debug;
|
||||
usb_strerror;
|
||||
};
|
||||
|
||||
FBSD_1.9 {
|
||||
libusb20_be_alloc;
|
||||
libusb20_be_alloc_default;
|
||||
libusb20_be_alloc_linux;
|
||||
libusb20_be_alloc_ugen20;
|
||||
libusb20_be_ctx_alloc;
|
||||
libusb20_be_ctx_free;
|
||||
};
|
||||
@@ -945,8 +945,25 @@ The library is also compliant with LibUSB version 0.1.12.
|
||||
.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
|
||||
|
||||
+14
-1
@@ -85,6 +85,13 @@ static struct usb_bus usb_global_bus = {
|
||||
|
||||
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 @@ usb_find_devices(void)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+17
-1
@@ -302,6 +302,21 @@ libusb_init_context(libusb_context **context,
|
||||
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 @@ libusb_exit(libusb_context *ctx)
|
||||
|
||||
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 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
|
||||
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);
|
||||
|
||||
|
||||
@@ -120,6 +120,9 @@ struct libusb_context {
|
||||
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 {
|
||||
|
||||
+62
-3
@@ -198,11 +198,15 @@ USB access library (libusb -lusb)
|
||||
.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,33 @@ returned.
|
||||
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
|
||||
.Dv 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 +1117,36 @@ This function does not return NULL.
|
||||
.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
|
||||
|
||||
+22
-7
@@ -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 @@ libusb20_be_device_foreach(struct libusb20_backend *pbe, struct libusb20_device
|
||||
}
|
||||
|
||||
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 @@ libusb20_be_alloc(const struct libusb20_backend_methods *methods)
|
||||
}
|
||||
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,29 +1308,29 @@ libusb20_be_alloc(const struct libusb20_backend_methods *methods)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1340,6 +1353,8 @@ libusb20_be_free(struct libusb20_backend *pbe)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -177,6 +177,7 @@ struct usb_device_info;
|
||||
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 @@ int libusb20_be_set_template(struct libusb20_backend *pbe, int temp);
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -39,7 +39,7 @@ Otherwise this is a pointer to the next device.
|
||||
.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) {
|
||||
|
||||
@@ -53,7 +53,7 @@ and
|
||||
.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) {
|
||||
|
||||
@@ -43,6 +43,21 @@ union libusb20_session_data {
|
||||
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_device_methods {
|
||||
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 @@ struct libusb20_device {
|
||||
/* 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;
|
||||
|
||||
|
||||
+102
-22
@@ -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 @@ const struct libusb20_backend_methods libusb20_ugen20_backend = {
|
||||
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 @@ ugen20_path_convert_one(const char **pp)
|
||||
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 @@ ugen20_enumerate(struct libusb20_device *pdev, const char *id)
|
||||
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 @@ ugen20_init_backend(struct libusb20_backend *pbe)
|
||||
|
||||
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 @@ ugen20_init_backend(struct libusb20_backend *pbe)
|
||||
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 @@ ugen20_init_backend(struct libusb20_backend *pbe)
|
||||
/* put the device on the backend list */
|
||||
libusb20_be_enqueue_device(pbe, pdev);
|
||||
}
|
||||
close(state.f);
|
||||
return (0); /* success */
|
||||
}
|
||||
|
||||
@@ -422,24 +505,22 @@ static int
|
||||
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 @@ ugen20_tr_cancel_async(struct libusb20_transfer *xfer)
|
||||
}
|
||||
|
||||
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 @@ ugen20_be_ioctl(uint32_t cmd, void *data)
|
||||
error = LIBUSB20_ERROR_OTHER;
|
||||
}
|
||||
}
|
||||
close(f);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@@ -1050,7 +1130,7 @@ ugen20_root_get_dev_quirk(struct libusb20_backend *pbe,
|
||||
|
||||
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 @@ ugen20_root_get_quirk_name(struct libusb20_backend *pbe, uint16_t quirk_index,
|
||||
|
||||
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 @@ ugen20_root_add_dev_quirk(struct libusb20_backend *pbe,
|
||||
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 @@ ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
|
||||
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 @@ ugen20_root_remove_dev_quirk(struct libusb20_backend *pbe,
|
||||
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));
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <capsicum_helpers.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
@@ -219,12 +220,18 @@ main(int argc, char **argv)
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <capsicum_helpers.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
@@ -391,12 +392,18 @@ main(int argc, char **argv)
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -870,7 +870,7 @@ show_host_device_selection(uint8_t level, struct uaddr *puaddr)
|
||||
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 @@ top:
|
||||
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;
|
||||
|
||||
|
||||
@@ -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 @@ show_mode_select(uint8_t level)
|
||||
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);
|
||||
}
|
||||
@@ -65,4 +65,7 @@ extern int get_integer(void);
|
||||
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_ */
|
||||
+23
-41
@@ -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 @@ struct usb_vendor_info {
|
||||
|
||||
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 @@ dump_iface(struct libusb20_device *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ load_vendors(void)
|
||||
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 @@ load_vendors(void)
|
||||
|
||||
fclose(db);
|
||||
/* cleanup */
|
||||
return (usb_vendors);
|
||||
}
|
||||
|
||||
enum _device_descr_list_type {
|
||||
@@ -446,7 +448,6 @@ static char *
|
||||
_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,9 +466,6 @@ _device_desc(struct libusb20_device *pdev,
|
||||
vid = libusb20_dev_get_device_desc(pdev)->idVendor;
|
||||
pid = libusb20_dev_get_device_desc(pdev)->idProduct;
|
||||
|
||||
if (usb_vendors == NULL)
|
||||
usb_vendors = load_vendors();
|
||||
|
||||
STAILQ_FOREACH(vi, usb_vendors, link) {
|
||||
if (vi->id == vid) {
|
||||
vendor = vi->desc;
|
||||
@@ -483,34 +481,18 @@ _device_desc(struct libusb20_device *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 @@ main(int argc, char **argv)
|
||||
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':
|
||||
|
||||
Reference in new issue
Block a user