1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2005-2007 Takahiro Hirofuchi
6 #include "usbip_common.h"
7 #include "vhci_driver.h"
12 #include "sysfs_utils.h"
15 #define PROGNAME "libusbip"
17 struct usbip_vhci_driver
*vhci_driver
;
18 struct udev
*udev_context
;
20 static struct usbip_imported_device
*
21 imported_device_init(struct usbip_imported_device
*idev
, char *busid
)
23 struct udev_device
*sudev
;
25 sudev
= udev_device_new_from_subsystem_sysname(udev_context
,
28 dbg("udev_device_new_from_subsystem_sysname failed: %s", busid
);
31 read_usb_device(sudev
, &idev
->udev
);
32 udev_device_unref(sudev
);
40 static int parse_status(const char *value
)
45 /* skip a header line */
46 c
= strchr(value
, '\n');
52 int port
, status
, speed
, devid
;
54 char lbusid
[SYSFS_BUS_ID_SIZE
];
55 struct usbip_imported_device
*idev
;
58 ret
= sscanf(c
, "%2s %d %d %d %x %u %31s\n",
59 hub
, &port
, &status
, &speed
,
60 &devid
, &sockfd
, lbusid
);
63 dbg("sscanf failed: %d", ret
);
67 dbg("hub %s port %d status %d speed %d devid %x",
68 hub
, port
, status
, speed
, devid
);
69 dbg("sockfd %u lbusid %s", sockfd
, lbusid
);
71 /* if a device is connected, look at it */
72 idev
= &vhci_driver
->idev
[port
];
73 memset(idev
, 0, sizeof(*idev
));
75 if (strncmp("hs", hub
, 2) == 0)
76 idev
->hub
= HUB_SPEED_HIGH
;
77 else /* strncmp("ss", hub, 2) == 0 */
78 idev
->hub
= HUB_SPEED_SUPER
;
81 idev
->status
= status
;
85 idev
->busnum
= (devid
>> 16);
86 idev
->devnum
= (devid
& 0x0000ffff);
88 if (idev
->status
!= VDEV_ST_NULL
89 && idev
->status
!= VDEV_ST_NOTASSIGNED
) {
90 idev
= imported_device_init(idev
, lbusid
);
92 dbg("imported_device_init failed");
97 /* go to the next line */
109 #define MAX_STATUS_NAME 18
111 static int refresh_imported_device_list(void)
113 const char *attr_status
;
114 char status
[MAX_STATUS_NAME
+1] = "status";
117 for (i
= 0; i
< vhci_driver
->ncontrollers
; i
++) {
119 snprintf(status
, sizeof(status
), "status.%d", i
);
121 attr_status
= udev_device_get_sysattr_value(vhci_driver
->hc_device
,
124 err("udev_device_get_sysattr_value failed");
128 dbg("controller %d", i
);
130 ret
= parse_status(attr_status
);
138 static int get_nports(void)
140 const char *attr_nports
;
142 attr_nports
= udev_device_get_sysattr_value(vhci_driver
->hc_device
, "nports");
144 err("udev_device_get_sysattr_value nports failed");
148 return (int)strtoul(attr_nports
, NULL
, 10);
151 static int vhci_hcd_filter(const struct dirent
*dirent
)
153 return strcmp(dirent
->d_name
, "vhci_hcd") >= 0;
156 static int get_ncontrollers(void)
158 struct dirent
**namelist
;
159 struct udev_device
*platform
;
162 platform
= udev_device_get_parent(vhci_driver
->hc_device
);
163 if (platform
== NULL
)
166 n
= scandir(udev_device_get_syspath(platform
), &namelist
, vhci_hcd_filter
, NULL
);
168 err("scandir failed");
170 for (int i
= 0; i
< n
; i
++)
179 * Read the given port's record.
181 * To avoid buffer overflow we will read the entire line and
182 * validate each part's size. The initial buffer is padded by 4 to
183 * accommodate the 2 spaces, 1 newline and an additional character
184 * which is needed to properly validate the 3rd part without it being
185 * truncated to an acceptable length.
187 static int read_record(int rhport
, char *host
, unsigned long host_len
,
188 char *port
, unsigned long port_len
, char *busid
)
192 char path
[PATH_MAX
+1];
193 char *buffer
, *start
, *end
;
194 char delim
[] = {' ', ' ', '\n'};
195 int max_len
[] = {(int)host_len
, (int)port_len
, SYSFS_BUS_ID_SIZE
};
196 size_t buffer_len
= host_len
+ port_len
+ SYSFS_BUS_ID_SIZE
+ 4;
198 buffer
= malloc(buffer_len
);
202 snprintf(path
, PATH_MAX
, VHCI_STATE_PATH
"/port%d", rhport
);
204 file
= fopen(path
, "r");
211 if (fgets(buffer
, buffer_len
, file
) == NULL
) {
219 /* validate the length of each of the 3 parts */
221 for (part
= 0; part
< 3; part
++) {
222 end
= strchr(start
, delim
[part
]);
223 if (end
== NULL
|| (end
- start
) > max_len
[part
]) {
230 if (sscanf(buffer
, "%s %s %s\n", host
, port
, busid
) != 3) {
241 /* ---------------------------------------------------------------------- */
243 int usbip_vhci_driver_open(void)
245 udev_context
= udev_new();
247 err("udev_new failed");
251 vhci_driver
= calloc(1, sizeof(struct usbip_vhci_driver
));
253 /* will be freed in usbip_driver_close() */
254 vhci_driver
->hc_device
=
255 udev_device_new_from_subsystem_sysname(udev_context
,
257 USBIP_VHCI_DEVICE_NAME
);
258 if (!vhci_driver
->hc_device
) {
259 err("udev_device_new_from_subsystem_sysname failed");
263 vhci_driver
->nports
= get_nports();
264 dbg("available ports: %d", vhci_driver
->nports
);
266 if (vhci_driver
->nports
<= 0) {
267 err("no available ports");
269 } else if (vhci_driver
->nports
> MAXNPORT
) {
270 err("port number exceeds %d", MAXNPORT
);
274 vhci_driver
->ncontrollers
= get_ncontrollers();
275 dbg("available controllers: %d", vhci_driver
->ncontrollers
);
277 if (vhci_driver
->ncontrollers
<=0) {
278 err("no available usb controllers");
282 if (refresh_imported_device_list())
288 udev_device_unref(vhci_driver
->hc_device
);
295 udev_unref(udev_context
);
301 void usbip_vhci_driver_close(void)
306 udev_device_unref(vhci_driver
->hc_device
);
312 udev_unref(udev_context
);
316 int usbip_vhci_refresh_device_list(void)
319 if (refresh_imported_device_list())
324 dbg("failed to refresh device list");
329 int usbip_vhci_get_free_port(uint32_t speed
)
331 for (int i
= 0; i
< vhci_driver
->nports
; i
++) {
334 case USB_SPEED_SUPER
:
335 if (vhci_driver
->idev
[i
].hub
!= HUB_SPEED_SUPER
)
339 if (vhci_driver
->idev
[i
].hub
!= HUB_SPEED_HIGH
)
344 if (vhci_driver
->idev
[i
].status
== VDEV_ST_NULL
)
345 return vhci_driver
->idev
[i
].port
;
351 int usbip_vhci_attach_device2(uint8_t port
, int sockfd
, uint32_t devid
,
353 char buff
[200]; /* what size should be ? */
354 char attach_attr_path
[SYSFS_PATH_MAX
];
355 char attr_attach
[] = "attach";
359 snprintf(buff
, sizeof(buff
), "%u %d %u %u",
360 port
, sockfd
, devid
, speed
);
361 dbg("writing: %s", buff
);
363 path
= udev_device_get_syspath(vhci_driver
->hc_device
);
364 snprintf(attach_attr_path
, sizeof(attach_attr_path
), "%s/%s",
366 dbg("attach attribute path: %s", attach_attr_path
);
368 ret
= write_sysfs_attribute(attach_attr_path
, buff
, strlen(buff
));
370 dbg("write_sysfs_attribute failed");
374 dbg("attached port: %d", port
);
379 static unsigned long get_devid(uint8_t busnum
, uint8_t devnum
)
381 return (busnum
<< 16) | devnum
;
384 /* will be removed */
385 int usbip_vhci_attach_device(uint8_t port
, int sockfd
, uint8_t busnum
,
386 uint8_t devnum
, uint32_t speed
)
388 int devid
= get_devid(busnum
, devnum
);
390 return usbip_vhci_attach_device2(port
, sockfd
, devid
, speed
);
393 int usbip_vhci_detach_device(uint8_t port
)
395 char detach_attr_path
[SYSFS_PATH_MAX
];
396 char attr_detach
[] = "detach";
397 char buff
[200]; /* what size should be ? */
401 snprintf(buff
, sizeof(buff
), "%u", port
);
402 dbg("writing: %s", buff
);
404 path
= udev_device_get_syspath(vhci_driver
->hc_device
);
405 snprintf(detach_attr_path
, sizeof(detach_attr_path
), "%s/%s",
407 dbg("detach attribute path: %s", detach_attr_path
);
409 ret
= write_sysfs_attribute(detach_attr_path
, buff
, strlen(buff
));
411 dbg("write_sysfs_attribute failed");
415 dbg("detached port: %d", port
);
420 int usbip_vhci_imported_device_dump(struct usbip_imported_device
*idev
)
422 char product_name
[100];
423 char host
[NI_MAXHOST
] = "unknown host";
424 char serv
[NI_MAXSERV
] = "unknown port";
425 char remote_busid
[SYSFS_BUS_ID_SIZE
];
427 int read_record_error
= 0;
429 if (idev
->status
== VDEV_ST_NULL
|| idev
->status
== VDEV_ST_NOTASSIGNED
)
432 ret
= read_record(idev
->port
, host
, sizeof(host
), serv
, sizeof(serv
),
436 read_record_error
= 1;
439 printf("Port %02d: <%s> at %s\n", idev
->port
,
440 usbip_status_string(idev
->status
),
441 usbip_speed_string(idev
->udev
.speed
));
443 usbip_names_get_product(product_name
, sizeof(product_name
),
444 idev
->udev
.idVendor
, idev
->udev
.idProduct
);
446 printf(" %s\n", product_name
);
448 if (!read_record_error
) {
449 printf("%10s -> usbip://%s:%s/%s\n", idev
->udev
.busid
,
450 host
, serv
, remote_busid
);
451 printf("%10s -> remote bus/dev %03d/%03d\n", " ",
452 idev
->busnum
, idev
->devnum
);
454 printf("%10s -> unknown host, remote port and remote busid\n",
456 printf("%10s -> remote bus/dev %03d/%03d\n", " ",
457 idev
->busnum
, idev
->devnum
);