root/tools/usb/usbip/src/usbip_bind.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usbip_bind_usage
  2. bind_usbip
  3. unbind_other
  4. bind_device
  5. usbip_bind

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
   4  *               2005-2007 Takahiro Hirofuchi
   5  */
   6 
   7 #include <libudev.h>
   8 
   9 #include <errno.h>
  10 #include <stdio.h>
  11 #include <stdlib.h>
  12 #include <string.h>
  13 
  14 #include <getopt.h>
  15 
  16 #include "usbip_common.h"
  17 #include "utils.h"
  18 #include "usbip.h"
  19 #include "sysfs_utils.h"
  20 
  21 enum unbind_status {
  22         UNBIND_ST_OK,
  23         UNBIND_ST_USBIP_HOST,
  24         UNBIND_ST_FAILED
  25 };
  26 
  27 static const char usbip_bind_usage_string[] =
  28         "usbip bind <args>\n"
  29         "    -b, --busid=<busid>    Bind " USBIP_HOST_DRV_NAME ".ko to device "
  30         "on <busid>\n";
  31 
  32 void usbip_bind_usage(void)
  33 {
  34         printf("usage: %s", usbip_bind_usage_string);
  35 }
  36 
  37 /* call at unbound state */
  38 static int bind_usbip(char *busid)
  39 {
  40         char attr_name[] = "bind";
  41         char bind_attr_path[SYSFS_PATH_MAX];
  42         int rc = -1;
  43 
  44         snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
  45                  SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
  46                  SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
  47 
  48         rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
  49         if (rc < 0) {
  50                 err("error binding device %s to driver: %s", busid,
  51                     strerror(errno));
  52                 return -1;
  53         }
  54 
  55         return 0;
  56 }
  57 
  58 /* buggy driver may cause dead lock */
  59 static int unbind_other(char *busid)
  60 {
  61         enum unbind_status status = UNBIND_ST_OK;
  62 
  63         char attr_name[] = "unbind";
  64         char unbind_attr_path[SYSFS_PATH_MAX];
  65         int rc = -1;
  66 
  67         struct udev *udev;
  68         struct udev_device *dev;
  69         const char *driver;
  70         const char *bDevClass;
  71 
  72         /* Create libudev context. */
  73         udev = udev_new();
  74 
  75         /* Get the device. */
  76         dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
  77         if (!dev) {
  78                 dbg("unable to find device with bus ID %s", busid);
  79                 goto err_close_busid_dev;
  80         }
  81 
  82         /* Check what kind of device it is. */
  83         bDevClass  = udev_device_get_sysattr_value(dev, "bDeviceClass");
  84         if (!bDevClass) {
  85                 dbg("unable to get bDevClass device attribute");
  86                 goto err_close_busid_dev;
  87         }
  88 
  89         if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
  90                 dbg("skip unbinding of hub");
  91                 goto err_close_busid_dev;
  92         }
  93 
  94         /* Get the device driver. */
  95         driver = udev_device_get_driver(dev);
  96         if (!driver) {
  97                 /* No driver bound to this device. */
  98                 goto out;
  99         }
 100 
 101         if (!strncmp(USBIP_HOST_DRV_NAME, driver,
 102                                 strlen(USBIP_HOST_DRV_NAME))) {
 103                 /* Already bound to usbip-host. */
 104                 status = UNBIND_ST_USBIP_HOST;
 105                 goto out;
 106         }
 107 
 108         /* Unbind device from driver. */
 109         snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
 110                  SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
 111                  SYSFS_DRIVERS_NAME, driver, attr_name);
 112 
 113         rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
 114         if (rc < 0) {
 115                 err("error unbinding device %s from driver", busid);
 116                 goto err_close_busid_dev;
 117         }
 118 
 119         goto out;
 120 
 121 err_close_busid_dev:
 122         status = UNBIND_ST_FAILED;
 123 out:
 124         udev_device_unref(dev);
 125         udev_unref(udev);
 126 
 127         return status;
 128 }
 129 
 130 static int bind_device(char *busid)
 131 {
 132         int rc;
 133         struct udev *udev;
 134         struct udev_device *dev;
 135         const char *devpath;
 136 
 137         /* Check whether the device with this bus ID exists. */
 138         udev = udev_new();
 139         dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
 140         if (!dev) {
 141                 err("device with the specified bus ID does not exist");
 142                 return -1;
 143         }
 144         devpath = udev_device_get_devpath(dev);
 145         udev_unref(udev);
 146 
 147         /* If the device is already attached to vhci_hcd - bail out */
 148         if (strstr(devpath, USBIP_VHCI_DRV_NAME)) {
 149                 err("bind loop detected: device: %s is attached to %s\n",
 150                     devpath, USBIP_VHCI_DRV_NAME);
 151                 return -1;
 152         }
 153 
 154         rc = unbind_other(busid);
 155         if (rc == UNBIND_ST_FAILED) {
 156                 err("could not unbind driver from device on busid %s", busid);
 157                 return -1;
 158         } else if (rc == UNBIND_ST_USBIP_HOST) {
 159                 err("device on busid %s is already bound to %s", busid,
 160                     USBIP_HOST_DRV_NAME);
 161                 return -1;
 162         }
 163 
 164         rc = modify_match_busid(busid, 1);
 165         if (rc < 0) {
 166                 err("unable to bind device on %s", busid);
 167                 return -1;
 168         }
 169 
 170         rc = bind_usbip(busid);
 171         if (rc < 0) {
 172                 err("could not bind device to %s", USBIP_HOST_DRV_NAME);
 173                 modify_match_busid(busid, 0);
 174                 return -1;
 175         }
 176 
 177         info("bind device on busid %s: complete", busid);
 178 
 179         return 0;
 180 }
 181 
 182 int usbip_bind(int argc, char *argv[])
 183 {
 184         static const struct option opts[] = {
 185                 { "busid", required_argument, NULL, 'b' },
 186                 { NULL,    0,                 NULL,  0  }
 187         };
 188 
 189         int opt;
 190         int ret = -1;
 191 
 192         for (;;) {
 193                 opt = getopt_long(argc, argv, "b:", opts, NULL);
 194 
 195                 if (opt == -1)
 196                         break;
 197 
 198                 switch (opt) {
 199                 case 'b':
 200                         ret = bind_device(optarg);
 201                         goto out;
 202                 default:
 203                         goto err_out;
 204                 }
 205         }
 206 
 207 err_out:
 208         usbip_bind_usage();
 209 out:
 210         return ret;
 211 }

/* [<][>][^][v][top][bottom][index][help] */