1*1ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2588b48caSValentina Manea /*
3588b48caSValentina Manea * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
4588b48caSValentina Manea * 2005-2007 Takahiro Hirofuchi
5588b48caSValentina Manea */
6588b48caSValentina Manea
7588b48caSValentina Manea #include <libudev.h>
8588b48caSValentina Manea
9588b48caSValentina Manea #include <errno.h>
10588b48caSValentina Manea #include <stdio.h>
11588b48caSValentina Manea #include <stdlib.h>
12588b48caSValentina Manea #include <string.h>
13588b48caSValentina Manea
14588b48caSValentina Manea #include <getopt.h>
15588b48caSValentina Manea
16588b48caSValentina Manea #include "usbip_common.h"
17588b48caSValentina Manea #include "utils.h"
18588b48caSValentina Manea #include "usbip.h"
19588b48caSValentina Manea #include "sysfs_utils.h"
20588b48caSValentina Manea
21588b48caSValentina Manea enum unbind_status {
22588b48caSValentina Manea UNBIND_ST_OK,
23588b48caSValentina Manea UNBIND_ST_USBIP_HOST,
24588b48caSValentina Manea UNBIND_ST_FAILED
25588b48caSValentina Manea };
26588b48caSValentina Manea
27588b48caSValentina Manea static const char usbip_bind_usage_string[] =
28588b48caSValentina Manea "usbip bind <args>\n"
29588b48caSValentina Manea " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
30588b48caSValentina Manea "on <busid>\n";
31588b48caSValentina Manea
usbip_bind_usage(void)32588b48caSValentina Manea void usbip_bind_usage(void)
33588b48caSValentina Manea {
34588b48caSValentina Manea printf("usage: %s", usbip_bind_usage_string);
35588b48caSValentina Manea }
36588b48caSValentina Manea
37588b48caSValentina Manea /* call at unbound state */
bind_usbip(char * busid)38588b48caSValentina Manea static int bind_usbip(char *busid)
39588b48caSValentina Manea {
40588b48caSValentina Manea char attr_name[] = "bind";
41588b48caSValentina Manea char bind_attr_path[SYSFS_PATH_MAX];
42588b48caSValentina Manea int rc = -1;
43588b48caSValentina Manea
44588b48caSValentina Manea snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
45588b48caSValentina Manea SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
46588b48caSValentina Manea SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
47588b48caSValentina Manea
48588b48caSValentina Manea rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
49588b48caSValentina Manea if (rc < 0) {
50588b48caSValentina Manea err("error binding device %s to driver: %s", busid,
51588b48caSValentina Manea strerror(errno));
52588b48caSValentina Manea return -1;
53588b48caSValentina Manea }
54588b48caSValentina Manea
55588b48caSValentina Manea return 0;
56588b48caSValentina Manea }
57588b48caSValentina Manea
58588b48caSValentina Manea /* buggy driver may cause dead lock */
unbind_other(char * busid)59588b48caSValentina Manea static int unbind_other(char *busid)
60588b48caSValentina Manea {
61588b48caSValentina Manea enum unbind_status status = UNBIND_ST_OK;
62588b48caSValentina Manea
63588b48caSValentina Manea char attr_name[] = "unbind";
64588b48caSValentina Manea char unbind_attr_path[SYSFS_PATH_MAX];
65588b48caSValentina Manea int rc = -1;
66588b48caSValentina Manea
67588b48caSValentina Manea struct udev *udev;
68588b48caSValentina Manea struct udev_device *dev;
69588b48caSValentina Manea const char *driver;
70588b48caSValentina Manea const char *bDevClass;
71588b48caSValentina Manea
72588b48caSValentina Manea /* Create libudev context. */
73588b48caSValentina Manea udev = udev_new();
74588b48caSValentina Manea
75588b48caSValentina Manea /* Get the device. */
76588b48caSValentina Manea dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
77588b48caSValentina Manea if (!dev) {
78588b48caSValentina Manea dbg("unable to find device with bus ID %s", busid);
79588b48caSValentina Manea goto err_close_busid_dev;
80588b48caSValentina Manea }
81588b48caSValentina Manea
82588b48caSValentina Manea /* Check what kind of device it is. */
83588b48caSValentina Manea bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass");
84588b48caSValentina Manea if (!bDevClass) {
85588b48caSValentina Manea dbg("unable to get bDevClass device attribute");
86588b48caSValentina Manea goto err_close_busid_dev;
87588b48caSValentina Manea }
88588b48caSValentina Manea
89588b48caSValentina Manea if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
90588b48caSValentina Manea dbg("skip unbinding of hub");
91588b48caSValentina Manea goto err_close_busid_dev;
92588b48caSValentina Manea }
93588b48caSValentina Manea
94588b48caSValentina Manea /* Get the device driver. */
95588b48caSValentina Manea driver = udev_device_get_driver(dev);
96588b48caSValentina Manea if (!driver) {
97588b48caSValentina Manea /* No driver bound to this device. */
98588b48caSValentina Manea goto out;
99588b48caSValentina Manea }
100588b48caSValentina Manea
101588b48caSValentina Manea if (!strncmp(USBIP_HOST_DRV_NAME, driver,
102588b48caSValentina Manea strlen(USBIP_HOST_DRV_NAME))) {
103588b48caSValentina Manea /* Already bound to usbip-host. */
104588b48caSValentina Manea status = UNBIND_ST_USBIP_HOST;
105588b48caSValentina Manea goto out;
106588b48caSValentina Manea }
107588b48caSValentina Manea
108588b48caSValentina Manea /* Unbind device from driver. */
109588b48caSValentina Manea snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
110588b48caSValentina Manea SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
111588b48caSValentina Manea SYSFS_DRIVERS_NAME, driver, attr_name);
112588b48caSValentina Manea
113588b48caSValentina Manea rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
114588b48caSValentina Manea if (rc < 0) {
115588b48caSValentina Manea err("error unbinding device %s from driver", busid);
116588b48caSValentina Manea goto err_close_busid_dev;
117588b48caSValentina Manea }
118588b48caSValentina Manea
119588b48caSValentina Manea goto out;
120588b48caSValentina Manea
121588b48caSValentina Manea err_close_busid_dev:
122588b48caSValentina Manea status = UNBIND_ST_FAILED;
123588b48caSValentina Manea out:
124588b48caSValentina Manea udev_device_unref(dev);
125588b48caSValentina Manea udev_unref(udev);
126588b48caSValentina Manea
127588b48caSValentina Manea return status;
128588b48caSValentina Manea }
129588b48caSValentina Manea
bind_device(char * busid)130588b48caSValentina Manea static int bind_device(char *busid)
131588b48caSValentina Manea {
132588b48caSValentina Manea int rc;
133588b48caSValentina Manea struct udev *udev;
134588b48caSValentina Manea struct udev_device *dev;
135ef54cf0cSShuah Khan const char *devpath;
136588b48caSValentina Manea
137588b48caSValentina Manea /* Check whether the device with this bus ID exists. */
138588b48caSValentina Manea udev = udev_new();
139588b48caSValentina Manea dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
140588b48caSValentina Manea if (!dev) {
141588b48caSValentina Manea err("device with the specified bus ID does not exist");
142588b48caSValentina Manea return -1;
143588b48caSValentina Manea }
144ef54cf0cSShuah Khan devpath = udev_device_get_devpath(dev);
145588b48caSValentina Manea udev_unref(udev);
146588b48caSValentina Manea
147ef54cf0cSShuah Khan /* If the device is already attached to vhci_hcd - bail out */
148ef54cf0cSShuah Khan if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
149ef54cf0cSShuah Khan err("bind loop detected: device: %s is attached to %s\n",
150ef54cf0cSShuah Khan devpath, USBIP_VHCI_DRV_NAME);
151ef54cf0cSShuah Khan return -1;
152ef54cf0cSShuah Khan }
153ef54cf0cSShuah Khan
154588b48caSValentina Manea rc = unbind_other(busid);
155588b48caSValentina Manea if (rc == UNBIND_ST_FAILED) {
156588b48caSValentina Manea err("could not unbind driver from device on busid %s", busid);
157588b48caSValentina Manea return -1;
158588b48caSValentina Manea } else if (rc == UNBIND_ST_USBIP_HOST) {
159588b48caSValentina Manea err("device on busid %s is already bound to %s", busid,
160588b48caSValentina Manea USBIP_HOST_DRV_NAME);
161588b48caSValentina Manea return -1;
162588b48caSValentina Manea }
163588b48caSValentina Manea
164588b48caSValentina Manea rc = modify_match_busid(busid, 1);
165588b48caSValentina Manea if (rc < 0) {
166588b48caSValentina Manea err("unable to bind device on %s", busid);
167588b48caSValentina Manea return -1;
168588b48caSValentina Manea }
169588b48caSValentina Manea
170588b48caSValentina Manea rc = bind_usbip(busid);
171588b48caSValentina Manea if (rc < 0) {
172588b48caSValentina Manea err("could not bind device to %s", USBIP_HOST_DRV_NAME);
173588b48caSValentina Manea modify_match_busid(busid, 0);
174588b48caSValentina Manea return -1;
175588b48caSValentina Manea }
176588b48caSValentina Manea
177588b48caSValentina Manea info("bind device on busid %s: complete", busid);
178588b48caSValentina Manea
179588b48caSValentina Manea return 0;
180588b48caSValentina Manea }
181588b48caSValentina Manea
usbip_bind(int argc,char * argv[])182588b48caSValentina Manea int usbip_bind(int argc, char *argv[])
183588b48caSValentina Manea {
184588b48caSValentina Manea static const struct option opts[] = {
185588b48caSValentina Manea { "busid", required_argument, NULL, 'b' },
186588b48caSValentina Manea { NULL, 0, NULL, 0 }
187588b48caSValentina Manea };
188588b48caSValentina Manea
189588b48caSValentina Manea int opt;
190588b48caSValentina Manea int ret = -1;
191588b48caSValentina Manea
192588b48caSValentina Manea for (;;) {
193588b48caSValentina Manea opt = getopt_long(argc, argv, "b:", opts, NULL);
194588b48caSValentina Manea
195588b48caSValentina Manea if (opt == -1)
196588b48caSValentina Manea break;
197588b48caSValentina Manea
198588b48caSValentina Manea switch (opt) {
199588b48caSValentina Manea case 'b':
200588b48caSValentina Manea ret = bind_device(optarg);
201588b48caSValentina Manea goto out;
202588b48caSValentina Manea default:
203588b48caSValentina Manea goto err_out;
204588b48caSValentina Manea }
205588b48caSValentina Manea }
206588b48caSValentina Manea
207588b48caSValentina Manea err_out:
208588b48caSValentina Manea usbip_bind_usage();
209588b48caSValentina Manea out:
210588b48caSValentina Manea return ret;
211588b48caSValentina Manea }
212