2 * Copyright (c) 2019-2022 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 * SPDX-License-Identifier: BSD-2-Clause
10 #include <sys/ioctl.h>
12 #include <linux/hidraw.h>
13 #include <linux/input.h>
25 size_t report_out_len;
27 const sigset_t *sigmaskp;
31 get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd)
35 if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) == -1) {
36 fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__);
40 if (s < 0 || (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
41 fido_log_debug("%s: HIDIOCGRDESCSIZE %d", __func__, s);
45 hrd->size = (unsigned)s;
47 if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) == -1) {
48 fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__);
56 is_fido(const char *path)
59 uint32_t usage_page = 0;
60 struct hidraw_report_descriptor *hrd = NULL;
62 if ((hrd = calloc(1, sizeof(*hrd))) == NULL ||
63 (fd = fido_hid_unix_open(path)) == -1)
65 if (get_report_descriptor(fd, hrd) < 0 ||
66 fido_hid_get_usage(hrd->value, hrd->size, &usage_page) < 0)
72 if (fd != -1 && close(fd) == -1)
73 fido_log_error(errno, "%s: close", __func__);
75 return (usage_page == 0xf1d0);
79 parse_uevent(const char *uevent, int *bus, int16_t *vendor_id,
90 if ((s = cp = strdup(uevent)) == NULL)
93 while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') {
94 if (strncmp(p, "HID_ID=", 7) == 0) {
95 if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) {
97 *vendor_id = (int16_t)y;
98 *product_id = (int16_t)z;
111 get_parent_attr(struct udev_device *dev, const char *subsystem,
112 const char *devtype, const char *attr)
114 struct udev_device *parent;
117 if ((parent = udev_device_get_parent_with_subsystem_devtype(dev,
118 subsystem, devtype)) == NULL || (value =
119 udev_device_get_sysattr_value(parent, attr)) == NULL)
122 return (strdup(value));
126 get_usb_attr(struct udev_device *dev, const char *attr)
128 return (get_parent_attr(dev, "usb", "usb_device", attr));
132 copy_info(fido_dev_info_t *di, struct udev *udev,
133 struct udev_list_entry *udev_entry)
138 struct udev_device *dev = NULL;
142 memset(di, 0, sizeof(*di));
144 if ((name = udev_list_entry_get_name(udev_entry)) == NULL ||
145 (dev = udev_device_new_from_syspath(udev, name)) == NULL ||
146 (path = udev_device_get_devnode(dev)) == NULL ||
150 if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL ||
151 parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) {
152 fido_log_debug("%s: uevent", __func__);
157 if (bus != BUS_USB) {
158 fido_log_debug("%s: bus", __func__);
163 di->path = strdup(path);
164 if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL)
165 di->manufacturer = strdup("");
166 if ((di->product = get_usb_attr(dev, "product")) == NULL)
167 di->product = strdup("");
168 if (di->path == NULL || di->manufacturer == NULL || di->product == NULL)
174 udev_device_unref(dev);
180 free(di->manufacturer);
182 explicit_bzero(di, sizeof(*di));
189 fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
191 struct udev *udev = NULL;
192 struct udev_enumerate *udev_enum = NULL;
193 struct udev_list_entry *udev_list;
194 struct udev_list_entry *udev_entry;
195 int r = FIDO_ERR_INTERNAL;
200 return (FIDO_OK); /* nothing to do */
203 return (FIDO_ERR_INVALID_ARGUMENT);
205 if ((udev = udev_new()) == NULL ||
206 (udev_enum = udev_enumerate_new(udev)) == NULL)
209 if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 ||
210 udev_enumerate_scan_devices(udev_enum) < 0)
213 if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) {
214 r = FIDO_OK; /* zero hidraw devices */
218 udev_list_entry_foreach(udev_entry, udev_list) {
219 if (copy_info(&devlist[*olen], udev, udev_entry) == 0) {
220 devlist[*olen].io = (fido_dev_io_t) {
226 if (++(*olen) == ilen)
233 if (udev_enum != NULL)
234 udev_enumerate_unref(udev_enum);
242 fido_hid_open(const char *path)
244 struct hid_linux *ctx;
245 struct hidraw_report_descriptor *hrd;
246 struct timespec tv_pause;
247 long interval_ms, retries = 0;
253 if ((ctx = calloc(1, sizeof(*ctx))) == NULL ||
254 (ctx->fd = fido_hid_unix_open(path)) == -1) {
259 while (flock(ctx->fd, LOCK_EX|LOCK_NB) == -1) {
260 if (errno != EWOULDBLOCK) {
261 fido_log_error(errno, "%s: flock", __func__);
266 if (retries++ >= 20) {
267 fido_log_debug("%s: flock timeout", __func__);
271 interval_ms = retries * 100000000L;
272 tv_pause.tv_sec = interval_ms / 1000000000L;
273 tv_pause.tv_nsec = interval_ms % 1000000000L;
274 if (nanosleep(&tv_pause, NULL) == -1) {
275 fido_log_error(errno, "%s: nanosleep", __func__);
282 fido_log_debug("%s: retrying", __func__);
287 if ((hrd = calloc(1, sizeof(*hrd))) == NULL ||
288 get_report_descriptor(ctx->fd, hrd) < 0 ||
289 fido_hid_get_report_len(hrd->value, hrd->size, &ctx->report_in_len,
290 &ctx->report_out_len) < 0 || ctx->report_in_len == 0 ||
291 ctx->report_out_len == 0) {
292 fido_log_debug("%s: using default report sizes", __func__);
293 ctx->report_in_len = CTAP_MAX_REPORT_LEN;
294 ctx->report_out_len = CTAP_MAX_REPORT_LEN;
303 fido_hid_close(void *handle)
305 struct hid_linux *ctx = handle;
307 if (close(ctx->fd) == -1)
308 fido_log_error(errno, "%s: close", __func__);
314 fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
316 struct hid_linux *ctx = handle;
318 ctx->sigmask = *sigmask;
319 ctx->sigmaskp = &ctx->sigmask;
325 fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
327 struct hid_linux *ctx = handle;
330 if (len != ctx->report_in_len) {
331 fido_log_debug("%s: len %zu", __func__, len);
335 if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) {
336 fido_log_debug("%s: fd not ready", __func__);
340 if ((r = read(ctx->fd, buf, len)) == -1) {
341 fido_log_error(errno, "%s: read", __func__);
345 if (r < 0 || (size_t)r != len) {
346 fido_log_debug("%s: %zd != %zu", __func__, r, len);
354 fido_hid_write(void *handle, const unsigned char *buf, size_t len)
356 struct hid_linux *ctx = handle;
359 if (len != ctx->report_out_len + 1) {
360 fido_log_debug("%s: len %zu", __func__, len);
364 if ((r = write(ctx->fd, buf, len)) == -1) {
365 fido_log_error(errno, "%s: write", __func__);
369 if (r < 0 || (size_t)r != len) {
370 fido_log_debug("%s: %zd != %zu", __func__, r, len);
378 fido_hid_report_in_len(void *handle)
380 struct hid_linux *ctx = handle;
382 return (ctx->report_in_len);
386 fido_hid_report_out_len(void *handle)
388 struct hid_linux *ctx = handle;
390 return (ctx->report_out_len);