Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
usbip_bind.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 matt mooney <[email protected]>
3  * 2005-2007 Takahiro Hirofuchi
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <sysfs/libsysfs.h>
20 
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include <getopt.h>
27 
28 #include "usbip_common.h"
29 #include "utils.h"
30 #include "usbip.h"
31 
36 };
37 
38 static const char usbip_bind_usage_string[] =
39  "usbip bind <args>\n"
40  " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device "
41  "on <busid>\n";
42 
43 void usbip_bind_usage(void)
44 {
45  printf("usage: %s", usbip_bind_usage_string);
46 }
47 
48 /* call at unbound state */
49 static int bind_usbip(char *busid)
50 {
51  char bus_type[] = "usb";
52  char attr_name[] = "bind";
53  char sysfs_mntpath[SYSFS_PATH_MAX];
54  char bind_attr_path[SYSFS_PATH_MAX];
55  char intf_busid[SYSFS_BUS_ID_SIZE];
56  struct sysfs_device *busid_dev;
57  struct sysfs_attribute *bind_attr;
58  struct sysfs_attribute *bConfValue;
59  struct sysfs_attribute *bNumIntfs;
60  int i, failed = 0;
61  int rc, ret = -1;
62 
63  rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
64  if (rc < 0) {
65  err("sysfs must be mounted: %s", strerror(errno));
66  return -1;
67  }
68 
69  snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
70  sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
71  USBIP_HOST_DRV_NAME, attr_name);
72 
73  bind_attr = sysfs_open_attribute(bind_attr_path);
74  if (!bind_attr) {
75  dbg("problem getting bind attribute: %s", strerror(errno));
76  return -1;
77  }
78 
79  busid_dev = sysfs_open_device(bus_type, busid);
80  if (!busid_dev) {
81  dbg("sysfs_open_device %s failed: %s", busid, strerror(errno));
82  goto err_close_bind_attr;
83  }
84 
85  bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue");
86  bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces");
87 
88  if (!bConfValue || !bNumIntfs) {
89  dbg("problem getting device attributes: %s",
90  strerror(errno));
91  goto err_close_busid_dev;
92  }
93 
94  for (i = 0; i < atoi(bNumIntfs->value); i++) {
95  snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid,
96  bConfValue->value, i);
97 
98  rc = sysfs_write_attribute(bind_attr, intf_busid,
99  SYSFS_BUS_ID_SIZE);
100  if (rc < 0) {
101  dbg("bind driver at %s failed", intf_busid);
102  failed = 1;
103  }
104  }
105 
106  if (!failed)
107  ret = 0;
108 
109 err_close_busid_dev:
110  sysfs_close_device(busid_dev);
111 err_close_bind_attr:
112  sysfs_close_attribute(bind_attr);
113 
114  return ret;
115 }
116 
117 /* buggy driver may cause dead lock */
118 static int unbind_other(char *busid)
119 {
120  char bus_type[] = "usb";
121  char intf_busid[SYSFS_BUS_ID_SIZE];
122  struct sysfs_device *busid_dev;
123  struct sysfs_device *intf_dev;
124  struct sysfs_driver *intf_drv;
125  struct sysfs_attribute *unbind_attr;
126  struct sysfs_attribute *bConfValue;
127  struct sysfs_attribute *bDevClass;
128  struct sysfs_attribute *bNumIntfs;
129  int i, rc;
131 
132  busid_dev = sysfs_open_device(bus_type, busid);
133  if (!busid_dev) {
134  dbg("sysfs_open_device %s failed: %s", busid, strerror(errno));
135  return -1;
136  }
137 
138  bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue");
139  bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass");
140  bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces");
141  if (!bConfValue || !bDevClass || !bNumIntfs) {
142  dbg("problem getting device attributes: %s",
143  strerror(errno));
144  goto err_close_busid_dev;
145  }
146 
147  if (!strncmp(bDevClass->value, "09", bDevClass->len)) {
148  dbg("skip unbinding of hub");
149  goto err_close_busid_dev;
150  }
151 
152  for (i = 0; i < atoi(bNumIntfs->value); i++) {
153  snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid,
154  bConfValue->value, i);
155  intf_dev = sysfs_open_device(bus_type, intf_busid);
156  if (!intf_dev) {
157  dbg("could not open interface device: %s",
158  strerror(errno));
159  goto err_close_busid_dev;
160  }
161 
162  dbg("%s -> %s", intf_dev->name, intf_dev->driver_name);
163 
164  if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN))
165  /* unbound interface */
166  continue;
167 
168  if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name,
169  SYSFS_NAME_LEN)) {
170  /* already bound to usbip-host */
171  status = UNBIND_ST_USBIP_HOST;
172  continue;
173  }
174 
175  /* unbinding */
176  intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name);
177  if (!intf_drv) {
178  dbg("could not open interface driver on %s: %s",
179  intf_dev->name, strerror(errno));
180  goto err_close_intf_dev;
181  }
182 
183  unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind");
184  if (!unbind_attr) {
185  dbg("problem getting interface driver attribute: %s",
186  strerror(errno));
187  goto err_close_intf_drv;
188  }
189 
190  rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id,
191  SYSFS_BUS_ID_SIZE);
192  if (rc < 0) {
193  /* NOTE: why keep unbinding other interfaces? */
194  dbg("unbind driver at %s failed", intf_dev->bus_id);
195  status = UNBIND_ST_FAILED;
196  }
197 
198  sysfs_close_driver(intf_drv);
199  sysfs_close_device(intf_dev);
200  }
201 
202  goto out;
203 
204 err_close_intf_drv:
205  sysfs_close_driver(intf_drv);
206 err_close_intf_dev:
207  sysfs_close_device(intf_dev);
208 err_close_busid_dev:
209  status = UNBIND_ST_FAILED;
210 out:
211  sysfs_close_device(busid_dev);
212 
213  return status;
214 }
215 
216 static int bind_device(char *busid)
217 {
218  int rc;
219 
220  rc = unbind_other(busid);
221  if (rc == UNBIND_ST_FAILED) {
222  err("could not unbind driver from device on busid %s", busid);
223  return -1;
224  } else if (rc == UNBIND_ST_USBIP_HOST) {
225  err("device on busid %s is already bound to %s", busid,
227  return -1;
228  }
229 
230  rc = modify_match_busid(busid, 1);
231  if (rc < 0) {
232  err("unable to bind device on %s", busid);
233  return -1;
234  }
235 
236  rc = bind_usbip(busid);
237  if (rc < 0) {
238  err("could not bind device to %s", USBIP_HOST_DRV_NAME);
239  modify_match_busid(busid, 0);
240  return -1;
241  }
242 
243  printf("bind device on busid %s: complete\n", busid);
244 
245  return 0;
246 }
247 
248 int usbip_bind(int argc, char *argv[])
249 {
250  static const struct option opts[] = {
251  { "busid", required_argument, NULL, 'b' },
252  { NULL, 0, NULL, 0 }
253  };
254 
255  int opt;
256  int ret = -1;
257 
258  for (;;) {
259  opt = getopt_long(argc, argv, "b:", opts, NULL);
260 
261  if (opt == -1)
262  break;
263 
264  switch (opt) {
265  case 'b':
266  ret = bind_device(optarg);
267  goto out;
268  default:
269  goto err_out;
270  }
271  }
272 
273 err_out:
275 out:
276  return ret;
277 }