diff options
Diffstat (limited to 'drivers/staging/usbip/userspace/src')
-rw-r--r-- | drivers/staging/usbip/userspace/src/Makefile.am | 17 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/bind-driver.c | 643 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip.c | 817 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip.h | 39 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_attach.c | 228 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_bind.c | 277 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_detach.c | 103 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_list.c | 303 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_network.c | 198 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_network.h | 94 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbip_unbind.c | 186 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/usbipd.c | 705 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/utils.c | 283 | ||||
-rw-r--r-- | drivers/staging/usbip/userspace/src/utils.h | 55 |
14 files changed, 1853 insertions, 2095 deletions
diff --git a/drivers/staging/usbip/userspace/src/Makefile.am b/drivers/staging/usbip/userspace/src/Makefile.am index 05a7aa5..3f09f6a 100644 --- a/drivers/staging/usbip/userspace/src/Makefile.am +++ b/drivers/staging/usbip/userspace/src/Makefile.am @@ -1,10 +1,11 @@ -AM_CPPFLAGS := -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' -AM_CFLAGS := @EXTRA_CFLAGS@ @PACKAGE_CFLAGS@ -LDADD := $(top_srcdir)/libsrc/libusbip.la @PACKAGE_LIBS@ +AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' +AM_CFLAGS = @EXTRA_CFLAGS@ @PACKAGE_CFLAGS@ +LDADD = $(top_builddir)/libsrc/libusbip.la @PACKAGE_LIBS@ -sbin_PROGRAMS := usbip usbipd usbip_bind_driver +sbin_PROGRAMS := usbip usbipd -usbip_SOURCES := usbip.c usbip_network.c usbip_network.h -usbipd_SOURCES := usbipd.c usbip_network.c usbip_network.h -usbip_bind_driver_SOURCES := bind-driver.c utils.c utils.h \ - usbip_network.h usbip_network.c +usbip_SOURCES := usbip.c utils.c usbip_network.c \ + usbip_attach.c usbip_detach.c usbip_list.c \ + usbip_bind.c usbip_unbind.c + +usbipd_SOURCES := usbipd.c usbip_network.c diff --git a/drivers/staging/usbip/userspace/src/bind-driver.c b/drivers/staging/usbip/userspace/src/bind-driver.c deleted file mode 100644 index 201ffbb..0000000 --- a/drivers/staging/usbip/userspace/src/bind-driver.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * - * Copyright (C) 2005-2007 Takahiro Hirofuchi - */ - -#include "utils.h" - -#define _GNU_SOURCE -#include <getopt.h> -#include <glib.h> - - - -static const struct option longopts[] = { - {"usbip", required_argument, NULL, 'u'}, - {"other", required_argument, NULL, 'o'}, - {"list", no_argument, NULL, 'l'}, - {"list2", no_argument, NULL, 'L'}, - {"help", no_argument, NULL, 'h'}, -#if 0 - {"allusbip", no_argument, NULL, 'a'}, - {"export-to", required_argument, NULL, 'e'}, - {"unexport", required_argument, NULL, 'x'}, - {"busid", required_argument, NULL, 'b'}, -#endif - - {NULL, 0, NULL, 0} -}; - -static const char match_busid_path[] = "/sys/bus/usb/drivers/usbip/match_busid"; - - -static void show_help(void) -{ - printf("Usage: usbip_bind_driver [OPTION]\n"); - printf("Change driver binding for USB/IP.\n"); - printf(" --usbip busid make a device exportable\n"); - printf(" --other busid use a device by a local driver\n"); - printf(" --list print usb devices and their drivers\n"); - printf(" --list2 print usb devices and their drivers in parseable mode\n"); -#if 0 - printf(" --allusbip make all devices exportable\n"); - printf(" --export-to host export the device to 'host'\n"); - printf(" --unexport host unexport a device previously exported to 'host'\n"); - printf(" --busid busid the busid used for --export-to\n"); -#endif -} - -static int modify_match_busid(char *busid, int add) -{ - int fd; - int ret; - char buff[BUS_ID_SIZE + 4]; - - /* BUS_IS_SIZE includes NULL termination? */ - if (strnlen(busid, BUS_ID_SIZE) > BUS_ID_SIZE - 1) { - g_warning("too long busid"); - return -1; - } - - fd = open(match_busid_path, O_WRONLY); - if (fd < 0) - return -1; - - if (add) - snprintf(buff, BUS_ID_SIZE + 4, "add %s", busid); - else - snprintf(buff, BUS_ID_SIZE + 4, "del %s", busid); - - g_debug("write \"%s\" to %s", buff, match_busid_path); - - ret = write(fd, buff, sizeof(buff)); - if (ret < 0) { - close(fd); - return -1; - } - - close(fd); - - return 0; -} - -static const char unbind_path_format[] = "/sys/bus/usb/devices/%s/driver/unbind"; - -/* buggy driver may cause dead lock */ -static int unbind_interface_busid(char *busid) -{ - char unbind_path[PATH_MAX]; - int fd; - int ret; - - snprintf(unbind_path, sizeof(unbind_path), unbind_path_format, busid); - - fd = open(unbind_path, O_WRONLY); - if (fd < 0) { - g_warning("opening unbind_path failed: %d", fd); - return -1; - } - - ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE)); - if (ret < 0) { - g_warning("write to unbind_path failed: %d", ret); - close(fd); - return -1; - } - - close(fd); - - return 0; -} - -static int unbind_interface(char *busid, int configvalue, int interface) -{ - char inf_busid[BUS_ID_SIZE]; - g_debug("unbinding interface"); - - snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface); - - return unbind_interface_busid(inf_busid); -} - - -static const char bind_path_format[] = "/sys/bus/usb/drivers/%s/bind"; - -static int bind_interface_busid(char *busid, char *driver) -{ - char bind_path[PATH_MAX]; - int fd; - int ret; - - snprintf(bind_path, sizeof(bind_path), bind_path_format, driver); - - fd = open(bind_path, O_WRONLY); - if (fd < 0) - return -1; - - ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE)); - if (ret < 0) { - close(fd); - return -1; - } - - close(fd); - - return 0; -} - -static int bind_interface(char *busid, int configvalue, int interface, char *driver) -{ - char inf_busid[BUS_ID_SIZE]; - - snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface); - - return bind_interface_busid(inf_busid, driver); -} - -static int unbind(char *busid) -{ - int configvalue = 0; - int ninterface = 0; - int devclass = 0; - int i; - int failed = 0; - - configvalue = read_bConfigurationValue(busid); - ninterface = read_bNumInterfaces(busid); - devclass = read_bDeviceClass(busid); - - if (configvalue < 0 || ninterface < 0 || devclass < 0) { - g_warning("read config and ninf value, removed?"); - return -1; - } - - if (devclass == 0x09) { - g_message("skip unbinding of hub"); - return -1; - } - - for (i = 0; i < ninterface; i++) { - char driver[PATH_MAX]; - int ret; - - bzero(&driver, sizeof(driver)); - - getdriver(busid, configvalue, i, driver, PATH_MAX-1); - - g_debug(" %s:%d.%d -> %s ", busid, configvalue, i, driver); - - if (!strncmp("none", driver, PATH_MAX)) - continue; /* unbound interface */ - -#if 0 - if (!strncmp("usbip", driver, PATH_MAX)) - continue; /* already bound to usbip */ -#endif - - /* unbinding */ - ret = unbind_interface(busid, configvalue, i); - if (ret < 0) { - g_warning("unbind driver at %s:%d.%d failed", - busid, configvalue, i); - failed = 1; - } - } - - if (failed) - return -1; - else - return 0; -} - -/* call at unbound state */ -static int bind_to_usbip(char *busid) -{ - int configvalue = 0; - int ninterface = 0; - int i; - int failed = 0; - - configvalue = read_bConfigurationValue(busid); - ninterface = read_bNumInterfaces(busid); - - if (configvalue < 0 || ninterface < 0) { - g_warning("read config and ninf value, removed?"); - return -1; - } - - for (i = 0; i < ninterface; i++) { - int ret; - - ret = bind_interface(busid, configvalue, i, "usbip"); - if (ret < 0) { - g_warning("bind usbip at %s:%d.%d, failed", - busid, configvalue, i); - failed = 1; - /* need to contine binding at other interfaces */ - } - } - - if (failed) - return -1; - else - return 0; -} - - -static int use_device_by_usbip(char *busid) -{ - int ret; - - ret = unbind(busid); - if (ret < 0) { - g_warning("unbind drivers of %s, failed", busid); - return -1; - } - - ret = modify_match_busid(busid, 1); - if (ret < 0) { - g_warning("add %s to match_busid, failed", busid); - return -1; - } - - ret = bind_to_usbip(busid); - if (ret < 0) { - g_warning("bind usbip to %s, failed", busid); - modify_match_busid(busid, 0); - return -1; - } - - g_message("bind %s to usbip, complete!", busid); - - return 0; -} - - - -static int use_device_by_other(char *busid) -{ - int ret; - int config; - - /* read and write the same config value to kick probing */ - config = read_bConfigurationValue(busid); - if (config < 0) { - g_warning("read bConfigurationValue of %s, failed", busid); - return -1; - } - - ret = modify_match_busid(busid, 0); - if (ret < 0) { - g_warning("del %s to match_busid, failed", busid); - return -1; - } - - ret = write_bConfigurationValue(busid, config); - if (ret < 0) { - g_warning("read bConfigurationValue of %s, failed", busid); - return -1; - } - - g_message("bind %s to other drivers than usbip, complete!", busid); - - return 0; -} - - -#include <sys/types.h> -#include <regex.h> - -#include <errno.h> -#include <string.h> -#include <stdio.h> - - - -static int is_usb_device(char *busid) -{ - int ret; - - regex_t regex; - regmatch_t pmatch[1]; - - ret = regcomp(®ex, "^[0-9]+-[0-9]+(\\.[0-9]+)*$", REG_NOSUB|REG_EXTENDED); - if (ret < 0) - g_error("regcomp: %s\n", strerror(errno)); - - ret = regexec(®ex, busid, 0, pmatch, 0); - if (ret) - return 0; /* not matched */ - - return 1; -} - - -#include <dirent.h> -static int show_devices(void) -{ - DIR *dir; - - dir = opendir("/sys/bus/usb/devices/"); - if (!dir) - g_error("opendir: %s", strerror(errno)); - - printf("List USB devices\n"); - for (;;) { - struct dirent *dirent; - char *busid; - - dirent = readdir(dir); - if (!dirent) - break; - - busid = dirent->d_name; - - if (is_usb_device(busid)) { - char name[100] = {'\0'}; - char driver[100] = {'\0'}; - int conf, ninf = 0; - int i; - - conf = read_bConfigurationValue(busid); - ninf = read_bNumInterfaces(busid); - - getdevicename(busid, name, sizeof(name)); - - printf(" - busid %s (%s)\n", busid, name); - - for (i = 0; i < ninf; i++) { - getdriver(busid, conf, i, driver, sizeof(driver)); - printf(" %s:%d.%d -> %s\n", busid, conf, i, driver); - } - printf("\n"); - } - } - - closedir(dir); - - return 0; -} - -static int show_devices2(void) -{ - DIR *dir; - - dir = opendir("/sys/bus/usb/devices/"); - if (!dir) - g_error("opendir: %s", strerror(errno)); - - for (;;) { - struct dirent *dirent; - char *busid; - - dirent = readdir(dir); - if (!dirent) - break; - - busid = dirent->d_name; - - if (is_usb_device(busid)) { - char name[100] = {'\0'}; - char driver[100] = {'\0'}; - int conf, ninf = 0; - int i; - - conf = read_bConfigurationValue(busid); - ninf = read_bNumInterfaces(busid); - - getdevicename(busid, name, sizeof(name)); - - printf("busid=%s#usbid=%s#", busid, name); - - for (i = 0; i < ninf; i++) { - getdriver(busid, conf, i, driver, sizeof(driver)); - printf("%s:%d.%d=%s#", busid, conf, i, driver); - } - printf("\n"); - } - } - - closedir(dir); - - return 0; -} - - -#if 0 -static int export_to(char *host, char *busid) { - - int ret; - - if( host == NULL ) { - printf( "no host given\n\n"); - show_help(); - return -1; - } - if( busid == NULL ) { - /* XXX print device list and ask for busnumber, if none is - * given */ - printf( "no busid given, use --busid switch\n\n"); - show_help(); - return -1; - } - - - ret = use_device_by_usbip(busid); - if( ret != 0 ) { - printf( "could not bind driver to usbip\n"); - return -1; - } - - printf( "DEBUG: exporting device '%s' to '%s'\n", busid, host ); - ret = export_busid_to_host(host, busid); /* usbip_export.[ch] */ - if( ret != 0 ) { - printf( "could not export device to host\n" ); - printf( " host: %s, device: %s\n", host, busid ); - use_device_by_other(busid); - return -1; - } - - return 0; -} - -static int unexport_from(char *host, char *busid) { - - int ret; - - if (!host || !busid) - g_error("no host or no busid\n"); - - g_message("unexport_from: host: '%s', busid: '%s'", host, busid); - - ret = unexport_busid_from_host(host, busid); /* usbip_export.[ch] */ - if( ret != 0 ) { - err( "could not unexport device from host\n" ); - err( " host: %s, device: %s\n", host, busid ); - } - - ret = use_device_by_other(busid); - if (ret < 0) - g_error("could not unbind device from usbip\n"); - - return 0; -} - - -static int allusbip(void) -{ - DIR *dir; - - dir = opendir("/sys/bus/usb/devices/"); - if (!dir) - g_error("opendir: %s", strerror(errno)); - - for (;;) { - struct dirent *dirent; - char *busid; - - dirent = readdir(dir); - if (!dirent) - break; - - busid = dirent->d_name; - - if (!is_usb_device(busid)) - continue; - - { - char name[PATH_MAX]; - int conf, ninf = 0; - int i; - int be_local = 0; - - conf = read_bConfigurationValue(busid); - ninf = read_bNumInterfaces(busid); - - getdevicename(busid, name, sizeof(name)); - - for (i = 0; i < ninf; i++) { - char driver[PATH_MAX]; - - getdriver(busid, conf, i, driver, sizeof(driver)); -#if 0 - if (strncmp(driver, "usbhid", 6) == 0 || strncmp(driver, "usb-storage", 11) == 0) { - be_local = 1; - break; - } -#endif - } - - if (be_local == 0) - use_device_by_usbip(busid); - } - } - - closedir(dir); - - return 0; -} -#endif - -int main(int argc, char **argv) -{ - char *busid = NULL; - char *remote_host __attribute__((unused)) = NULL; - - enum { - cmd_unknown = 0, - cmd_use_by_usbip, - cmd_use_by_other, - cmd_list, - cmd_list2, - cmd_allusbip, - cmd_export_to, - cmd_unexport, - cmd_help, - } cmd = cmd_unknown; - - if (geteuid() != 0) - g_warning("running non-root?"); - - for (;;) { - int c; - int index = 0; - - c = getopt_long(argc, argv, "u:o:hlLae:x:b:", longopts, &index); - if (c == -1) - break; - - switch (c) { - case 'u': - cmd = cmd_use_by_usbip; - busid = optarg; - break; - case 'o' : - cmd = cmd_use_by_other; - busid = optarg; - break; - case 'l' : - cmd = cmd_list; - break; - case 'L' : - cmd = cmd_list2; - break; - case 'a' : - cmd = cmd_allusbip; - break; - case 'b': - busid = optarg; - break; - case 'e': - cmd = cmd_export_to; - remote_host = optarg; - break; - case 'x': - cmd = cmd_unexport; - remote_host = optarg; - break; - case 'h': /* fallthrough */ - case '?': - cmd = cmd_help; - break; - default: - g_error("getopt"); - } - - //if (cmd) - // break; - } - - switch (cmd) { - case cmd_use_by_usbip: - use_device_by_usbip(busid); - break; - case cmd_use_by_other: - use_device_by_other(busid); - break; - case cmd_list: - show_devices(); - break; - case cmd_list2: - show_devices2(); - break; -#if 0 - case cmd_allusbip: - allusbip(); - break; - case cmd_export_to: - export_to(remote_host, busid); - break; - case cmd_unexport: - unexport_from(remote_host, busid); - break; -#endif - case cmd_help: /* fallthrough */ - case cmd_unknown: - show_help(); - break; - default: - g_error("NOT REACHED"); - } - - return 0; -} diff --git a/drivers/staging/usbip/userspace/src/usbip.c b/drivers/staging/usbip/userspace/src/usbip.c index 01a5628..fff4b76 100644 --- a/drivers/staging/usbip/userspace/src/usbip.c +++ b/drivers/staging/usbip/userspace/src/usbip.c @@ -1,723 +1,190 @@ /* + * command structure borrowed from udev + * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git) * - * Copyright (C) 2005-2007 Takahiro Hirofuchi + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif - -#include "usbip.h" -#include "usbip_network.h" -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> +#include <stdio.h> #include <stdlib.h> -#include <fcntl.h> -#include <glib.h> - -static const char version[] = PACKAGE_STRING; - - -/* /sys/devices/platform/vhci_hcd/usb6/6-1/6-1:1.1 -> 1 */ -static int get_interface_number(char *path) -{ - char *c; - - c = strstr(path, vhci_driver->hc_device->bus_id); - if (!c) - return -1; /* hc exist? */ - c++; - /* -> usb6/6-1/6-1:1.1 */ - - c = strchr(c, '/'); - if (!c) - return -1; /* hc exist? */ - c++; - /* -> 6-1/6-1:1.1 */ - - c = strchr(c, '/'); - if (!c) - return -1; /* no interface path */ - c++; - /* -> 6-1:1.1 */ - - c = strchr(c, ':'); - if (!c) - return -1; /* no configuration? */ - c++; - /* -> 1.1 */ - - c = strchr(c, '.'); - if (!c) - return -1; /* no interface? */ - c++; - /* -> 1 */ - - - return atoi(c); -} - - -static struct sysfs_device *open_usb_interface(struct usb_device *udev, int i) -{ - struct sysfs_device *suinf; - char busid[SYSFS_BUS_ID_SIZE]; - - snprintf(busid, SYSFS_BUS_ID_SIZE, "%s:%d.%d", - udev->busid, udev->bConfigurationValue, i); - - suinf = sysfs_open_device("usb", busid); - if (!suinf) - err("sysfs_open_device %s", busid); - - return suinf; -} - - -#define MAX_BUFF 100 -static int record_connection(char *host, char *port, char *busid, int rhport) -{ - int fd; - char path[PATH_MAX+1]; - char buff[MAX_BUFF+1]; - int ret; - - mkdir(VHCI_STATE_PATH, 0700); - snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); +#include <getopt.h> +#include <syslog.h> - fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); - if (fd < 0) - return -1; +#include "usbip_common.h" +#include "usbip.h" - snprintf(buff, MAX_BUFF, "%s %s %s\n", - host, port, busid); +static int usbip_help(int argc, char *argv[]); +static int usbip_version(int argc, char *argv[]); - ret = write(fd, buff, strlen(buff)); - if (ret != (ssize_t) strlen(buff)) { - close(fd); - return -1; - } +static const char usbip_version_string[] = PACKAGE_STRING; - close(fd); +static const char usbip_usage_string[] = + "usbip [--debug] [--log] [version]\n" + " [help] <command> <args>\n"; - return 0; -} - -static int read_record(int rhport, char *host, char *port, char *busid) +static void usbip_usage(void) { - FILE *file; - char path[PATH_MAX+1]; - - snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); - - file = fopen(path, "r"); - if (!file) { - err("fopen"); - return -1; - } - - if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) { - err("fscanf"); - fclose(file); - return -1; - } - - fclose(file); - - return 0; + printf("usage: %s", usbip_usage_string); } +struct command { + const char *name; + int (*fn)(int argc, char *argv[]); + const char *help; + void (*usage)(void); +}; -int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) -{ - char product_name[100]; - char host[NI_MAXHOST] = "unknown host"; - char serv[NI_MAXSERV] = "unknown port"; - char remote_busid[SYSFS_BUS_ID_SIZE]; - int ret; - - if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) { - info("Port %02d: <%s>", idev->port, usbip_status_string(idev->status)); - return 0; - } - - ret = read_record(idev->port, host, serv, remote_busid); - if (ret) { - err("read_record"); - return -1; - } - - info("Port %02d: <%s> at %s", idev->port, - usbip_status_string(idev->status), usbip_speed_string(idev->udev.speed)); - - usbip_names_get_product(product_name, sizeof(product_name), - idev->udev.idVendor, idev->udev.idProduct); - - info(" %s", product_name); - - info("%10s -> usbip://%s:%s/%s (remote devid %08x (bus/dev %03d/%03d))", - idev->udev.busid, host, serv, remote_busid, - idev->devid, - idev->busnum, idev->devnum); - - for (int i=0; i < idev->udev.bNumInterfaces; i++) { - /* show interface information */ - struct sysfs_device *suinf; - - suinf = open_usb_interface(&idev->udev, i); - if (!suinf) - continue; - - info(" %6s used by %-17s", suinf->bus_id, suinf->driver_name); - sysfs_close_device(suinf); - - /* show class device information */ - struct class_device *cdev; - - dlist_for_each_data(idev->cdev_list, cdev, struct class_device) { - int ifnum = get_interface_number(cdev->devpath); - if (ifnum == i) { - info(" %s", cdev->clspath); - } - } - } - - return 0; -} - - - +static const struct command cmds[] = { + { + .name = "help", + .fn = usbip_help, + .help = NULL, + .usage = NULL + }, + { + .name = "version", + .fn = usbip_version, + .help = NULL, + .usage = NULL + }, + { + .name = "attach", + .fn = usbip_attach, + .help = "Attach a remote USB device", + .usage = usbip_attach_usage + }, + { + .name = "detach", + .fn = usbip_detach, + .help = "Detach a remote USB device", + .usage = usbip_detach_usage + }, + { + .name = "list", + .fn = usbip_list, + .help = "List exportable or local USB devices", + .usage = usbip_list_usage + }, + { + .name = "bind", + .fn = usbip_bind, + .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko", + .usage = usbip_bind_usage + }, + { + .name = "unbind", + .fn = usbip_unbind, + .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko", + .usage = usbip_unbind_usage + }, + { NULL, NULL, NULL, NULL } +}; -static int query_exported_devices(int sockfd) +static int usbip_help(int argc, char *argv[]) { - int ret; - struct op_devlist_reply rep; - uint16_t code = OP_REP_DEVLIST; - - bzero(&rep, sizeof(rep)); - - ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); - if (ret < 0) { - err("send op_common"); - return -1; - } - - ret = usbip_recv_op_common(sockfd, &code); - if (ret < 0) { - err("recv op_common"); - return -1; - } - - ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); - if (ret < 0) { - err("recv op_devlist"); - return -1; - } - - PACK_OP_DEVLIST_REPLY(0, &rep); - dbg("exportable %d devices", rep.ndev); - - for (unsigned int i=0; i < rep.ndev; i++) { - char product_name[100]; - char class_name[100]; - struct usb_device udev; - - bzero(&udev, sizeof(udev)); - - ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); - if (ret < 0) { - err("recv usb_device[%d]", i); - return -1; - } - pack_usb_device(0, &udev); - - usbip_names_get_product(product_name, sizeof(product_name), - udev.idVendor, udev.idProduct); - usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, - udev.bDeviceSubClass, udev.bDeviceProtocol); - - info("%8s: %s", udev.busid, product_name); - info("%8s: %s", " ", udev.path); - info("%8s: %s", " ", class_name); - - for (int j=0; j < udev.bNumInterfaces; j++) { - struct usb_interface uinf; + const struct command *cmd; + int i; + int ret = 0; - ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf)); - if (ret < 0) { - err("recv usb_interface[%d]", j); - return -1; + if (argc > 1 && argv++) { + for (i = 0; cmds[i].name != NULL; i++) + if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) { + cmds[i].usage(); + goto done; } - - pack_usb_interface(0, &uinf); - usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass, - uinf.bInterfaceSubClass, uinf.bInterfaceProtocol); - - info("%8s: %2d - %s", " ", j, class_name); - } - - info(" "); - } - - return rep.ndev; -} - -static int import_device(int sockfd, struct usb_device *udev) -{ - int ret; - int port; - - ret = usbip_vhci_driver_open(); - if (ret < 0) { - err("open vhci_driver"); - return -1; - } - - port = usbip_vhci_get_free_port(); - if (port < 0) { - err("no free port"); - usbip_vhci_driver_close(); - return -1; - } - - ret = usbip_vhci_attach_device(port, sockfd, udev->busnum, - udev->devnum, udev->speed); - if (ret < 0) { - err("import device"); - usbip_vhci_driver_close(); - return -1; + ret = -1; } - usbip_vhci_driver_close(); - - return port; -} - - -static int query_import_device(int sockfd, char *busid) -{ - int ret; - struct op_import_request request; - struct op_import_reply reply; - uint16_t code = OP_REP_IMPORT; - - bzero(&request, sizeof(request)); - bzero(&reply, sizeof(reply)); - - - /* send a request */ - ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0); - if (ret < 0) { - err("send op_common"); - return -1; - } - - strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); - - PACK_OP_IMPORT_REQUEST(0, &request); - - ret = usbip_send(sockfd, (void *) &request, sizeof(request)); - if (ret < 0) { - err("send op_import_request"); - return -1; - } - - - /* recieve a reply */ - ret = usbip_recv_op_common(sockfd, &code); - if (ret < 0) { - err("recv op_common"); - return -1; - } - - ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply)); - if (ret < 0) { - err("recv op_import_reply"); - return -1; - } - - PACK_OP_IMPORT_REPLY(0, &reply); - - - /* check the reply */ - if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { - err("recv different busid %s", reply.udev.busid); - return -1; - } - - - /* import a device */ - return import_device(sockfd, &reply.udev); -} - -static int attach_device(char *host, char *busid) -{ - int sockfd; - int ret; - int rhport; - - sockfd = tcp_connect(host, USBIP_PORT_STRING); - if (sockfd < 0) { - err("tcp connect"); - return -1; - } - - rhport = query_import_device(sockfd, busid); - if (rhport < 0) { - err("query"); - return -1; - } - - close(sockfd); - - ret = record_connection(host, USBIP_PORT_STRING, - busid, rhport); - if (ret < 0) { - err("record connection"); - return -1; - } - - return 0; -} - -static int detach_port(char *port) -{ - int ret; - uint8_t portnum; - - for (unsigned int i=0; i < strlen(port); i++) - if (!isdigit(port[i])) { - err("invalid port %s", port); - return -1; - } - - /* check max port */ - - portnum = atoi(port); - - ret = usbip_vhci_driver_open(); - if (ret < 0) { - err("open vhci_driver"); - return -1; - } - - ret = usbip_vhci_detach_device(portnum); - if (ret < 0) - return -1; - - usbip_vhci_driver_close(); - + usbip_usage(); + printf("\n"); + for (cmd = cmds; cmd->name != NULL; cmd++) + if (cmd->help != NULL) + printf(" %-10s %s\n", cmd->name, cmd->help); + printf("\n"); +done: return ret; } -static int show_exported_devices(char *host) -{ - int ret; - int sockfd; - - sockfd = tcp_connect(host, USBIP_PORT_STRING); - if (sockfd < 0) { - err("- %s failed", host); - return -1; - } - - info("- %s", host); - - ret = query_exported_devices(sockfd); - if (ret < 0) { - err("query"); - return -1; - } - - close(sockfd); - return 0; -} - -static int attach_exported_devices(char *host, int sockfd) -{ - int ret; - struct op_devlist_reply rep; - uint16_t code = OP_REP_DEVLIST; - - bzero(&rep, sizeof(rep)); - - ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); - if(ret < 0) { - err("send op_common"); - return -1; - } - - ret = usbip_recv_op_common(sockfd, &code); - if(ret < 0) { - err("recv op_common"); - return -1; - } - - ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); - if(ret < 0) { - err("recv op_devlist"); - return -1; - } - - PACK_OP_DEVLIST_REPLY(0, &rep); - dbg("exportable %d devices", rep.ndev); - - for(unsigned int i=0; i < rep.ndev; i++) { - char product_name[100]; - char class_name[100]; - struct usb_device udev; - - bzero(&udev, sizeof(udev)); - - ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); - if(ret < 0) { - err("recv usb_device[%d]", i); - return -1; - } - pack_usb_device(0, &udev); - - usbip_names_get_product(product_name, sizeof(product_name), - udev.idVendor, udev.idProduct); - usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, - udev.bDeviceSubClass, udev.bDeviceProtocol); - - dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name); - - for (int j=0; j < udev.bNumInterfaces; j++) { - struct usb_interface uinf; - - ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf)); - if (ret < 0) { - err("recv usb_interface[%d]", j); - return -1; - } - - pack_usb_interface(0, &uinf); - usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass, - uinf.bInterfaceSubClass, uinf.bInterfaceProtocol); - - dbg("interface %2d - %s", j, class_name); - } - - attach_device(host, udev.busid); - } - - return rep.ndev; -} - -static int attach_devices_all(char *host) +static int usbip_version(int argc, char *argv[]) { - int ret; - int sockfd; + (void) argc; + (void) argv; - sockfd = tcp_connect(host, USBIP_PORT_STRING); - if(sockfd < 0) { - err("- %s failed", host); - return -1; - } - - info("- %s", host); - - ret = attach_exported_devices(host, sockfd); - if(ret < 0) { - err("query"); - return -1; - } - - close(sockfd); + printf(PROGNAME " (%s)\n", usbip_version_string); return 0; } - -const char help_message[] = "\ -Usage: usbip [options] \n\ - -a, --attach [host] [bus_id] \n\ - Attach a remote USB device. \n\ - \n\ - -x, --attachall [host] \n\ - Attach all remote USB devices on the specific host. \n\ - \n\ - -d, --detach [ports] \n\ - Detach an imported USB device. \n\ - \n\ - -l, --list [hosts] \n\ - List exported USB devices. \n\ - \n\ - -p, --port \n\ - List virtual USB port status. \n\ - \n\ - -D, --debug \n\ - Print debugging information. \n\ - \n\ - -v, --version \n\ - Show version. \n\ - \n\ - -h, --help \n\ - Print this help. \n"; - -static void show_help(void) -{ - printf("%s", help_message); -} - -static int show_port_status(void) +static int run_command(const struct command *cmd, int argc, char *argv[]) { - int ret; - struct usbip_imported_device *idev; - - ret = usbip_vhci_driver_open(); - if (ret < 0) - return ret; - - for (int i = 0; i < vhci_driver->nports; i++) { - idev = &vhci_driver->idev[i]; - - if (usbip_vhci_imported_device_dump(idev) < 0) - ret = -1; - } - - usbip_vhci_driver_close(); - - return ret; + dbg("running command: `%s'", cmd->name); + return cmd->fn(argc, argv); } -#define _GNU_SOURCE -#include <getopt.h> -static const struct option longopts[] = { - {"attach", no_argument, NULL, 'a'}, - {"attachall", no_argument, NULL, 'x'}, - {"detach", no_argument, NULL, 'd'}, - {"port", no_argument, NULL, 'p'}, - {"list", no_argument, NULL, 'l'}, - {"version", no_argument, NULL, 'v'}, - {"help", no_argument, NULL, 'h'}, - {"debug", no_argument, NULL, 'D'}, - {"syslog", no_argument, NULL, 'S'}, - {NULL, 0, NULL, 0} -}; - int main(int argc, char *argv[]) { - int ret; + static const struct option opts[] = { + { "debug", no_argument, NULL, 'd' }, + { "log", no_argument, NULL, 'l' }, + { NULL, 0, NULL, 0 } + }; - enum { - cmd_attach = 1, - cmd_attachall, - cmd_detach, - cmd_port, - cmd_list, - cmd_help, - cmd_version - } cmd = 0; + char *cmd; + int opt; + int i, rc = -1; usbip_use_stderr = 1; - - if (geteuid() != 0) - g_warning("running non-root?"); - - ret = usbip_names_init(USBIDS_FILE); - if (ret) - notice("failed to open %s", USBIDS_FILE); - + opterr = 0; for (;;) { - int c; - int index = 0; - - c = getopt_long(argc, argv, "adplvhDSx", longopts, &index); + opt = getopt_long(argc, argv, "+d", opts, NULL); - if (c == -1) + if (opt == -1) break; - switch(c) { - case 'a': - if (!cmd) - cmd = cmd_attach; - else - cmd = cmd_help; - break; - case 'd': - if (!cmd) - cmd = cmd_detach; - else - cmd = cmd_help; - break; - case 'p': - if (!cmd) - cmd = cmd_port; - else cmd = cmd_help; - break; - case 'l': - if (!cmd) - cmd = cmd_list; - else - cmd = cmd_help; - break; - case 'v': - if (!cmd) - cmd = cmd_version; - else - cmd = cmd_help; - break; - case 'x': - if(!cmd) - cmd = cmd_attachall; - else - cmd = cmd_help; - break; - case 'h': - cmd = cmd_help; - break; - case 'D': - usbip_use_debug = 1; - break; - case 'S': - usbip_use_syslog = 1; - break; - case '?': - break; - - default: - err("getopt"); - } - } - - ret = 0; - switch(cmd) { - case cmd_attach: - if (optind == argc - 2) - ret = attach_device(argv[optind], argv[optind+1]); - else - show_help(); - break; - case cmd_detach: - while (optind < argc) - ret = detach_port(argv[optind++]); - break; - case cmd_port: - ret = show_port_status(); - break; - case cmd_list: - while (optind < argc) - ret = show_exported_devices(argv[optind++]); + switch (opt) { + case 'd': + usbip_use_debug = 1; break; - case cmd_attachall: - while(optind < argc) - ret = attach_devices_all(argv[optind++]); - break; - case cmd_version: - printf("%s\n", version); - break; - case cmd_help: - show_help(); + case 'l': + usbip_use_syslog = 1; + openlog("", LOG_PID, LOG_USER); break; + case '?': + printf("usbip: invalid option\n"); default: - show_help(); + usbip_usage(); + goto out; + } } + cmd = argv[optind]; + if (cmd) { + for (i = 0; cmds[i].name != NULL; i++) + if (!strcmp(cmds[i].name, cmd)) { + argc -= optind; + argv += optind; + optind = 0; + rc = run_command(&cmds[i], argc, argv); + goto out; + } + } - usbip_names_free(); - - exit((ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE); + /* invalid command */ + usbip_help(0, NULL); +out: + return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/drivers/staging/usbip/userspace/src/usbip.h b/drivers/staging/usbip/userspace/src/usbip.h new file mode 100644 index 0000000..14d4a47 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __USBIP_H +#define __USBIP_H + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +/* usbip commands */ +int usbip_attach(int argc, char *argv[]); +int usbip_detach(int argc, char *argv[]); +int usbip_list(int argc, char *argv[]); +int usbip_bind(int argc, char *argv[]); +int usbip_unbind(int argc, char *argv[]); + +void usbip_attach_usage(void); +void usbip_detach_usage(void); +void usbip_list_usage(void); +void usbip_bind_usage(void); +void usbip_unbind_usage(void); + +#endif /* __USBIP_H */ diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c new file mode 100644 index 0000000..b7885a2 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_attach.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/stat.h> +#include <sysfs/libsysfs.h> + +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <fcntl.h> +#include <getopt.h> +#include <unistd.h> + +#include "vhci_driver.h" +#include "usbip_common.h" +#include "usbip_network.h" +#include "usbip.h" + +static const char usbip_attach_usage_string[] = + "usbip attach <args>\n" + " -h, --host=<host> The machine with exported USB devices\n" + " -b, --busid=<busid> Busid of the device on <host>\n"; + +void usbip_attach_usage(void) +{ + printf("usage: %s", usbip_attach_usage_string); +} + +#define MAX_BUFF 100 +static int record_connection(char *host, char *port, char *busid, int rhport) +{ + int fd; + char path[PATH_MAX+1]; + char buff[MAX_BUFF+1]; + int ret; + + mkdir(VHCI_STATE_PATH, 0700); + + snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); + + fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); + if (fd < 0) + return -1; + + snprintf(buff, MAX_BUFF, "%s %s %s\n", + host, port, busid); + + ret = write(fd, buff, strlen(buff)); + if (ret != (ssize_t) strlen(buff)) { + close(fd); + return -1; + } + + close(fd); + + return 0; +} + +static int import_device(int sockfd, struct usbip_usb_device *udev) +{ + int rc; + int port; + + rc = usbip_vhci_driver_open(); + if (rc < 0) { + err("open vhci_driver"); + return -1; + } + + port = usbip_vhci_get_free_port(); + if (port < 0) { + err("no free port"); + usbip_vhci_driver_close(); + return -1; + } + + rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, + udev->devnum, udev->speed); + if (rc < 0) { + err("import device"); + usbip_vhci_driver_close(); + return -1; + } + + usbip_vhci_driver_close(); + + return port; +} + +static int query_import_device(int sockfd, char *busid) +{ + int rc; + struct op_import_request request; + struct op_import_reply reply; + uint16_t code = OP_REP_IMPORT; + + memset(&request, 0, sizeof(request)); + memset(&reply, 0, sizeof(reply)); + + /* send a request */ + rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); + if (rc < 0) { + err("send op_common"); + return -1; + } + + strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); + + PACK_OP_IMPORT_REQUEST(0, &request); + + rc = usbip_net_send(sockfd, (void *) &request, sizeof(request)); + if (rc < 0) { + err("send op_import_request"); + return -1; + } + + /* recieve a reply */ + rc = usbip_net_recv_op_common(sockfd, &code); + if (rc < 0) { + err("recv op_common"); + return -1; + } + + rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply)); + if (rc < 0) { + err("recv op_import_reply"); + return -1; + } + + PACK_OP_IMPORT_REPLY(0, &reply); + + /* check the reply */ + if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { + err("recv different busid %s", reply.udev.busid); + return -1; + } + + /* import a device */ + return import_device(sockfd, &reply.udev); +} + +static int attach_device(char *host, char *busid) +{ + int sockfd; + int rc; + int rhport; + + sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); + if (sockfd < 0) { + err("tcp connect"); + return -1; + } + + rhport = query_import_device(sockfd, busid); + if (rhport < 0) { + err("query"); + return -1; + } + + close(sockfd); + + rc = record_connection(host, USBIP_PORT_STRING, busid, rhport); + if (rc < 0) { + err("record connection"); + return -1; + } + + return 0; +} + +int usbip_attach(int argc, char *argv[]) +{ + static const struct option opts[] = { + { "host", required_argument, NULL, 'h' }, + { "busid", required_argument, NULL, 'b' }, + { NULL, 0, NULL, 0 } + }; + char *host = NULL; + char *busid = NULL; + int opt; + int ret = -1; + + for (;;) { + opt = getopt_long(argc, argv, "h:b:", opts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 'h': + host = optarg; + break; + case 'b': + busid = optarg; + break; + default: + goto err_out; + } + } + + if (!host || !busid) + goto err_out; + + ret = attach_device(host, busid); + goto out; + +err_out: + usbip_attach_usage(); +out: + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c new file mode 100644 index 0000000..9ecaf6e --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_bind.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sysfs/libsysfs.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <getopt.h> + +#include "usbip_common.h" +#include "utils.h" +#include "usbip.h" + +enum unbind_status { + UNBIND_ST_OK, + UNBIND_ST_USBIP_HOST, + UNBIND_ST_FAILED +}; + +static const char usbip_bind_usage_string[] = + "usbip bind <args>\n" + " -b, --busid=<busid> Bind " USBIP_HOST_DRV_NAME ".ko to device " + "on <busid>\n"; + +void usbip_bind_usage(void) +{ + printf("usage: %s", usbip_bind_usage_string); +} + +/* call at unbound state */ +static int bind_usbip(char *busid) +{ + char bus_type[] = "usb"; + char attr_name[] = "bind"; + char sysfs_mntpath[SYSFS_PATH_MAX]; + char bind_attr_path[SYSFS_PATH_MAX]; + char intf_busid[SYSFS_BUS_ID_SIZE]; + struct sysfs_device *busid_dev; + struct sysfs_attribute *bind_attr; + struct sysfs_attribute *bConfValue; + struct sysfs_attribute *bNumIntfs; + int i, failed = 0; + int rc, ret = -1; + + rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); + if (rc < 0) { + err("sysfs must be mounted: %s", strerror(errno)); + return -1; + } + + snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s", + sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, + USBIP_HOST_DRV_NAME, attr_name); + + bind_attr = sysfs_open_attribute(bind_attr_path); + if (!bind_attr) { + dbg("problem getting bind attribute: %s", strerror(errno)); + return -1; + } + + busid_dev = sysfs_open_device(bus_type, busid); + if (!busid_dev) { + dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); + goto err_close_bind_attr; + } + + bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); + bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); + + if (!bConfValue || !bNumIntfs) { + dbg("problem getting device attributes: %s", + strerror(errno)); + goto err_close_busid_dev; + } + + for (i = 0; i < atoi(bNumIntfs->value); i++) { + snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, + bConfValue->value, i); + + rc = sysfs_write_attribute(bind_attr, intf_busid, + SYSFS_BUS_ID_SIZE); + if (rc < 0) { + dbg("bind driver at %s failed", intf_busid); + failed = 1; + } + } + + if (!failed) + ret = 0; + +err_close_busid_dev: + sysfs_close_device(busid_dev); +err_close_bind_attr: + sysfs_close_attribute(bind_attr); + + return ret; +} + +/* buggy driver may cause dead lock */ +static int unbind_other(char *busid) +{ + char bus_type[] = "usb"; + char intf_busid[SYSFS_BUS_ID_SIZE]; + struct sysfs_device *busid_dev; + struct sysfs_device *intf_dev; + struct sysfs_driver *intf_drv; + struct sysfs_attribute *unbind_attr; + struct sysfs_attribute *bConfValue; + struct sysfs_attribute *bDevClass; + struct sysfs_attribute *bNumIntfs; + int i, rc; + enum unbind_status status = UNBIND_ST_OK; + + busid_dev = sysfs_open_device(bus_type, busid); + if (!busid_dev) { + dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); + return -1; + } + + bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); + bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass"); + bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); + if (!bConfValue || !bDevClass || !bNumIntfs) { + dbg("problem getting device attributes: %s", + strerror(errno)); + goto err_close_busid_dev; + } + + if (!strncmp(bDevClass->value, "09", bDevClass->len)) { + dbg("skip unbinding of hub"); + goto err_close_busid_dev; + } + + for (i = 0; i < atoi(bNumIntfs->value); i++) { + snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, + bConfValue->value, i); + intf_dev = sysfs_open_device(bus_type, intf_busid); + if (!intf_dev) { + dbg("could not open interface device: %s", + strerror(errno)); + goto err_close_busid_dev; + } + + dbg("%s -> %s", intf_dev->name, intf_dev->driver_name); + + if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN)) + /* unbound interface */ + continue; + + if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name, + SYSFS_NAME_LEN)) { + /* already bound to usbip-host */ + status = UNBIND_ST_USBIP_HOST; + continue; + } + + /* unbinding */ + intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name); + if (!intf_drv) { + dbg("could not open interface driver on %s: %s", + intf_dev->name, strerror(errno)); + goto err_close_intf_dev; + } + + unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind"); + if (!unbind_attr) { + dbg("problem getting interface driver attribute: %s", + strerror(errno)); + goto err_close_intf_drv; + } + + rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id, + SYSFS_BUS_ID_SIZE); + if (rc < 0) { + /* NOTE: why keep unbinding other interfaces? */ + dbg("unbind driver at %s failed", intf_dev->bus_id); + status = UNBIND_ST_FAILED; + } + + sysfs_close_driver(intf_drv); + sysfs_close_device(intf_dev); + } + + goto out; + +err_close_intf_drv: + sysfs_close_driver(intf_drv); +err_close_intf_dev: + sysfs_close_device(intf_dev); +err_close_busid_dev: + status = UNBIND_ST_FAILED; +out: + sysfs_close_device(busid_dev); + + return status; +} + +static int bind_device(char *busid) +{ + int rc; + + rc = unbind_other(busid); + if (rc == UNBIND_ST_FAILED) { + err("could not unbind driver from device on busid %s", busid); + return -1; + } else if (rc == UNBIND_ST_USBIP_HOST) { + err("device on busid %s is already bound to %s", busid, + USBIP_HOST_DRV_NAME); + return -1; + } + + rc = modify_match_busid(busid, 1); + if (rc < 0) { + err("unable to bind device on %s", busid); + return -1; + } + + rc = bind_usbip(busid); + if (rc < 0) { + err("could not bind device to %s", USBIP_HOST_DRV_NAME); + modify_match_busid(busid, 0); + return -1; + } + + printf("bind device on busid %s: complete\n", busid); + + return 0; +} + +int usbip_bind(int argc, char *argv[]) +{ + static const struct option opts[] = { + { "busid", required_argument, NULL, 'b' }, + { NULL, 0, NULL, 0 } + }; + + int opt; + int ret = -1; + + for (;;) { + opt = getopt_long(argc, argv, "b:", opts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 'b': + ret = bind_device(optarg); + goto out; + default: + goto err_out; + } + } + +err_out: + usbip_bind_usage(); +out: + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c new file mode 100644 index 0000000..89bf3c1 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_detach.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sysfs/libsysfs.h> + +#include <ctype.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <getopt.h> +#include <unistd.h> + +#include "vhci_driver.h" +#include "usbip_common.h" +#include "usbip_network.h" +#include "usbip.h" + +static const char usbip_detach_usage_string[] = + "usbip detach <args>\n" + " -p, --port=<port> " USBIP_VHCI_DRV_NAME + " port the device is on\n"; + +void usbip_detach_usage(void) +{ + printf("usage: %s", usbip_detach_usage_string); +} + +static int detach_port(char *port) +{ + int ret; + uint8_t portnum; + + for (unsigned int i=0; i < strlen(port); i++) + if (!isdigit(port[i])) { + err("invalid port %s", port); + return -1; + } + + /* check max port */ + + portnum = atoi(port); + + ret = usbip_vhci_driver_open(); + if (ret < 0) { + err("open vhci_driver"); + return -1; + } + + ret = usbip_vhci_detach_device(portnum); + if (ret < 0) + return -1; + + usbip_vhci_driver_close(); + + return ret; +} + +int usbip_detach(int argc, char *argv[]) +{ + static const struct option opts[] = { + { "port", required_argument, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + int opt; + int ret = -1; + + for (;;) { + opt = getopt_long(argc, argv, "p:", opts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 'p': + ret = detach_port(optarg); + goto out; + default: + goto err_out; + } + } + +err_out: + usbip_detach_usage(); +out: + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c new file mode 100644 index 0000000..ed30d91 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_list.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sysfs/libsysfs.h> + +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <getopt.h> +#include <netdb.h> +#include <unistd.h> + +#include "usbip_common.h" +#include "usbip_network.h" +#include "usbip.h" + +static const char usbip_list_usage_string[] = + "usbip list [-p|--parsable] <args>\n" + " -p, --parsable Parsable list format\n" + " -r, --remote=<host> List the exportable USB devices on <host>\n" + " -l, --local List the local USB devices\n"; + +void usbip_list_usage(void) +{ + printf("usage: %s", usbip_list_usage_string); +} + +static int get_exported_devices(char *host, int sockfd) +{ + char product_name[100]; + char class_name[100]; + struct op_devlist_reply reply; + uint16_t code = OP_REP_DEVLIST; + struct usbip_usb_device udev; + struct usbip_usb_interface uintf; + unsigned int i; + int j, rc; + + rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); + if (rc < 0) { + dbg("usbip_net_send_op_common failed"); + return -1; + } + + rc = usbip_net_recv_op_common(sockfd, &code); + if (rc < 0) { + dbg("usbip_net_recv_op_common failed"); + return -1; + } + + memset(&reply, 0, sizeof(reply)); + rc = usbip_net_recv(sockfd, &reply, sizeof(reply)); + if (rc < 0) { + dbg("usbip_net_recv_op_devlist failed"); + return -1; + } + PACK_OP_DEVLIST_REPLY(0, &reply); + dbg("exportable devices: %d\n", reply.ndev); + + if (reply.ndev == 0) { + info("no exportable devices found on %s", host); + return 0; + } + + printf("Exportable USB devices\n"); + printf("======================\n"); + printf(" - %s\n", host); + + for (i = 0; i < reply.ndev; i++) { + memset(&udev, 0, sizeof(udev)); + rc = usbip_net_recv(sockfd, &udev, sizeof(udev)); + if (rc < 0) { + dbg("usbip_net_recv failed: usbip_usb_device[%d]", i); + return -1; + } + usbip_net_pack_usb_device(0, &udev); + + usbip_names_get_product(product_name, sizeof(product_name), + udev.idVendor, udev.idProduct); + usbip_names_get_class(class_name, sizeof(class_name), + udev.bDeviceClass, udev.bDeviceSubClass, + udev.bDeviceProtocol); + printf("%11s: %s\n", udev.busid, product_name); + printf("%11s: %s\n", "", udev.path); + printf("%11s: %s\n", "", class_name); + + for (j = 0; j < udev.bNumInterfaces; j++) { + rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); + if (rc < 0) { + dbg("usbip_net_recv failed: usbip_usb_intf[%d]", + j); + + return -1; + } + usbip_net_pack_usb_interface(0, &uintf); + + usbip_names_get_class(class_name, sizeof(class_name), + uintf.bInterfaceClass, + uintf.bInterfaceSubClass, + uintf.bInterfaceProtocol); + printf("%11s: %2d - %s\n", "", j, class_name); + } + printf("\n"); + } + + return 0; +} + +static int list_exported_devices(char *host) +{ + int rc; + int sockfd; + + sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); + if (sockfd < 0) { + err("could not connect to %s:%s: %s", host, + USBIP_PORT_STRING, gai_strerror(sockfd)); + return -1; + } + dbg("connected to %s:%s", host, USBIP_PORT_STRING); + + rc = get_exported_devices(host, sockfd); + if (rc < 0) { + err("failed to get device list from %s", host); + return -1; + } + + close(sockfd); + + return 0; +} + +static void print_device(char *busid, char *vendor, char *product, + bool parsable) +{ + if (parsable) + printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); + else + printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); +} + +static void print_interface(char *busid, char *driver, bool parsable) +{ + if (parsable) + printf("%s=%s#", busid, driver); + else + printf("%9s%s -> %s\n", "", busid, driver); +} + +static int is_device(void *x) +{ + struct sysfs_attribute *devpath; + struct sysfs_device *dev = x; + int ret = 0; + + devpath = sysfs_get_device_attr(dev, "devpath"); + if (devpath && *devpath->value != '0') + ret = 1; + + return ret; +} + +static int devcmp(void *a, void *b) +{ + return strcmp(a, b); +} + +static int list_devices(bool parsable) +{ + char bus_type[] = "usb"; + char busid[SYSFS_BUS_ID_SIZE]; + struct sysfs_bus *ubus; + struct sysfs_device *dev; + struct sysfs_device *intf; + struct sysfs_attribute *idVendor; + struct sysfs_attribute *idProduct; + struct sysfs_attribute *bConfValue; + struct sysfs_attribute *bNumIntfs; + struct dlist *devlist; + int i; + int ret = -1; + + ubus = sysfs_open_bus(bus_type); + if (!ubus) { + err("could not open %s bus: %s", bus_type, strerror(errno)); + return -1; + } + + devlist = sysfs_get_bus_devices(ubus); + if (!devlist) { + err("could not get %s bus devices: %s", bus_type, + strerror(errno)); + goto err_out; + } + + /* remove interfaces and root hubs from device list */ + dlist_filter_sort(devlist, is_device, devcmp); + + if (!parsable) { + printf("Local USB devices\n"); + printf("=================\n"); + } + dlist_for_each_data(devlist, dev, struct sysfs_device) { + idVendor = sysfs_get_device_attr(dev, "idVendor"); + idProduct = sysfs_get_device_attr(dev, "idProduct"); + bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue"); + bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces"); + if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { + err("problem getting device attributes: %s", + strerror(errno)); + goto err_out; + } + + print_device(dev->bus_id, idVendor->value, idProduct->value, + parsable); + + for (i = 0; i < atoi(bNumIntfs->value); i++) { + snprintf(busid, sizeof(busid), "%s:%.1s.%d", + dev->bus_id, bConfValue->value, i); + intf = sysfs_open_device(bus_type, busid); + if (!intf) { + err("could not open device interface: %s", + strerror(errno)); + goto err_out; + } + print_interface(busid, intf->driver_name, parsable); + sysfs_close_device(intf); + } + printf("\n"); + } + + ret = 0; + +err_out: + sysfs_close_bus(ubus); + + return ret; +} + +int usbip_list(int argc, char *argv[]) +{ + static const struct option opts[] = { + { "parsable", no_argument, NULL, 'p' }, + { "remote", required_argument, NULL, 'r' }, + { "local", no_argument, NULL, 'l' }, + { NULL, 0, NULL, 0 } + }; + + bool parsable = false; + int opt; + int ret = -1; + + if (usbip_names_init(USBIDS_FILE)) + err("failed to open %s", USBIDS_FILE); + + for (;;) { + opt = getopt_long(argc, argv, "pr:l", opts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 'p': + parsable = true; + break; + case 'r': + ret = list_exported_devices(optarg); + goto out; + case 'l': + ret = list_devices(parsable); + goto out; + default: + goto err_out; + } + } + +err_out: + usbip_list_usage(); +out: + usbip_names_free(); + + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c index 01be3c7..1a84dd3 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.c +++ b/drivers/staging/usbip/userspace/src/usbip_network.c @@ -1,11 +1,34 @@ /* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi * - * Copyright (C) 2005-2007 Takahiro Hirofuchi + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <sys/socket.h> + +#include <string.h> + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/tcp.h> +#include <unistd.h> + +#include "usbip_common.h" #include "usbip_network.h" -void pack_uint32_t(int pack, uint32_t *num) +void usbip_net_pack_uint32_t(int pack, uint32_t *num) { uint32_t i; @@ -17,7 +40,7 @@ void pack_uint32_t(int pack, uint32_t *num) *num = i; } -void pack_uint16_t(int pack, uint16_t *num) +void usbip_net_pack_uint16_t(int pack, uint16_t *num) { uint16_t i; @@ -29,34 +52,34 @@ void pack_uint16_t(int pack, uint16_t *num) *num = i; } -void pack_usb_device(int pack, struct usb_device *udev) +void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) { - pack_uint32_t(pack, &udev->busnum); - pack_uint32_t(pack, &udev->devnum); - pack_uint32_t(pack, &udev->speed ); + usbip_net_pack_uint32_t(pack, &udev->busnum); + usbip_net_pack_uint32_t(pack, &udev->devnum); + usbip_net_pack_uint32_t(pack, &udev->speed ); - pack_uint16_t(pack, &udev->idVendor ); - pack_uint16_t(pack, &udev->idProduct); - pack_uint16_t(pack, &udev->bcdDevice); + usbip_net_pack_uint16_t(pack, &udev->idVendor); + usbip_net_pack_uint16_t(pack, &udev->idProduct); + usbip_net_pack_uint16_t(pack, &udev->bcdDevice); } -void pack_usb_interface(int pack __attribute__((unused)), - struct usb_interface *udev __attribute__((unused))) +void usbip_net_pack_usb_interface(int pack __attribute__((unused)), + struct usbip_usb_interface *udev + __attribute__((unused))) { /* uint8_t members need nothing */ } - -static ssize_t usbip_xmit(int sockfd, void *buff, size_t bufflen, int sending) +static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen, + int sending) { + ssize_t nbytes; ssize_t total = 0; if (!bufflen) return 0; do { - ssize_t nbytes; - if (sending) nbytes = send(sockfd, buff, bufflen, 0); else @@ -65,80 +88,81 @@ static ssize_t usbip_xmit(int sockfd, void *buff, size_t bufflen, int sending) if (nbytes <= 0) return -1; - buff = (void *) ((intptr_t) buff + nbytes); + buff = (void *)((intptr_t) buff + nbytes); bufflen -= nbytes; total += nbytes; } while (bufflen > 0); - return total; } -ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen) +ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen) { - return usbip_xmit(sockfd, buff, bufflen, 0); + return usbip_net_xmit(sockfd, buff, bufflen, 0); } -ssize_t usbip_send(int sockfd, void *buff, size_t bufflen) +ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) { - return usbip_xmit(sockfd, buff, bufflen, 1); + return usbip_net_xmit(sockfd, buff, bufflen, 1); } -int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status) +int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) { - int ret; struct op_common op_common; + int rc; - bzero(&op_common, sizeof(op_common)); + memset(&op_common, 0, sizeof(op_common)); - op_common.version = USBIP_VERSION; - op_common.code = code; - op_common.status = status; + op_common.version = USBIP_VERSION; + op_common.code = code; + op_common.status = status; PACK_OP_COMMON(1, &op_common); - ret = usbip_send(sockfd, (void *) &op_common, sizeof(op_common)); - if (ret < 0) { - err("send op_common"); + rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); + if (rc < 0) { + dbg("usbip_net_send failed: %d", rc); return -1; } return 0; } -int usbip_recv_op_common(int sockfd, uint16_t *code) +int usbip_net_recv_op_common(int sockfd, uint16_t *code) { - int ret; struct op_common op_common; + int rc; - bzero(&op_common, sizeof(op_common)); + memset(&op_common, 0, sizeof(op_common)); - ret = usbip_recv(sockfd, (void *) &op_common, sizeof(op_common)); - if (ret < 0) { - err("recv op_common, %d", ret); + rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common)); + if (rc < 0) { + dbg("usbip_net_recv failed: %d", rc); goto err; } PACK_OP_COMMON(0, &op_common); if (op_common.version != USBIP_VERSION) { - err("version mismatch, %d %d", op_common.version, USBIP_VERSION); + dbg("version mismatch: %d %d", op_common.version, + USBIP_VERSION); goto err; } - switch(*code) { - case OP_UNSPEC: - break; - default: - if (op_common.code != *code) { - info("unexpected pdu %d for %d", op_common.code, *code); - goto err; - } + switch (*code) { + case OP_UNSPEC: + break; + default: + if (op_common.code != *code) { + dbg("unexpected pdu %#0x for %#0x", op_common.code, + *code); + goto err; + } } if (op_common.status != ST_OK) { - info("request failed at peer, %d", op_common.status); + dbg("request failed at peer: %d", op_common.status); goto err; } @@ -149,103 +173,85 @@ err: return -1; } - -int usbip_set_reuseaddr(int sockfd) +int usbip_net_set_reuseaddr(int sockfd) { const int val = 1; int ret; ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); if (ret < 0) - err("setsockopt SO_REUSEADDR"); + dbg("setsockopt: SO_REUSEADDR"); return ret; } -int usbip_set_nodelay(int sockfd) +int usbip_net_set_nodelay(int sockfd) { const int val = 1; int ret; ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); if (ret < 0) - err("setsockopt TCP_NODELAY"); + dbg("setsockopt: TCP_NODELAY"); return ret; } -int usbip_set_keepalive(int sockfd) +int usbip_net_set_keepalive(int sockfd) { const int val = 1; int ret; ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); if (ret < 0) - err("setsockopt SO_KEEPALIVE"); + dbg("setsockopt: SO_KEEPALIVE"); return ret; } -/* IPv6 Ready */ /* - * moved here from vhci_attach.c + * IPv6 Ready */ -int tcp_connect(char *hostname, char *service) +int usbip_net_tcp_connect(char *hostname, char *service) { - struct addrinfo hints, *res, *res0; + struct addrinfo hints, *res, *rp; int sockfd; - int err; - + int ret; memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* get all possible addresses */ - err = getaddrinfo(hostname, service, &hints, &res0); - if (err) { - err("%s %s: %s", hostname, service, gai_strerror(err)); - return -1; + ret = getaddrinfo(hostname, service, &hints, &res); + if (ret < 0) { + dbg("getaddrinfo: %s service %s: %s", hostname, service, + gai_strerror(ret)); + return ret; } - /* try all the addresses */ - for (res = res0; res; res = res->ai_next) { - char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; - - err = getnameinfo(res->ai_addr, res->ai_addrlen, - hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); - if (err) { - err("%s %s: %s", hostname, service, gai_strerror(err)); - continue; - } - - dbg("trying %s port %s\n", hbuf, sbuf); - - sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sockfd < 0) { - err("socket"); + /* try the addresses */ + for (rp = res; rp; rp = rp->ai_next) { + sockfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sockfd < 0) continue; - } /* should set TCP_NODELAY for usbip */ - usbip_set_nodelay(sockfd); - /* TODO: write code for heatbeat */ - usbip_set_keepalive(sockfd); + usbip_net_set_nodelay(sockfd); + /* TODO: write code for heartbeat */ + usbip_net_set_keepalive(sockfd); - err = connect(sockfd, res->ai_addr, res->ai_addrlen); - if (err < 0) { - close(sockfd); - continue; - } + if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; - /* connected */ - dbg("connected to %s:%s", hbuf, sbuf); - freeaddrinfo(res0); - return sockfd; + close(sockfd); } + if (!rp) + return EAI_SYSTEM; - dbg("%s:%s, %s", hostname, service, "no destination to connect to"); - freeaddrinfo(res0); + freeaddrinfo(res); - return -1; + return sockfd; } diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h index 1225466..2d1e070 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.h +++ b/drivers/staging/usbip/userspace/src/usbip_network.h @@ -2,19 +2,20 @@ * Copyright (C) 2005-2007 Takahiro Hirofuchi */ -#ifndef _USBIP_NETWORK_H -#define _USBIP_NETWORK_H +#ifndef __USBIP_NETWORK_H +#define __USBIP_NETWORK_H -#include "usbip.h" -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/tcp.h> +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif +#include <sys/types.h> +#include <sysfs/libsysfs.h> -/* -------------------------------------------------- */ -/* Define Protocol Format */ -/* -------------------------------------------------- */ +#include <stdint.h> +#define USBIP_PORT 3240 +#define USBIP_PORT_STRING "3240" /* ---------------------------------------------------------------------- */ /* Common header for all the kinds of PDUs. */ @@ -33,12 +34,11 @@ struct op_common { } __attribute__((packed)); #define PACK_OP_COMMON(pack, op_common) do {\ - pack_uint16_t(pack, &(op_common)->version);\ - pack_uint16_t(pack, &(op_common)->code );\ - pack_uint32_t(pack, &(op_common)->status );\ + usbip_net_pack_uint16_t(pack, &(op_common)->version);\ + usbip_net_pack_uint16_t(pack, &(op_common)->code );\ + usbip_net_pack_uint32_t(pack, &(op_common)->status );\ } while (0) - /* ---------------------------------------------------------------------- */ /* Dummy Code */ #define OP_UNSPEC 0x00 @@ -56,11 +56,10 @@ struct op_devinfo_request { } __attribute__((packed)); struct op_devinfo_reply { - struct usb_device udev; - struct usb_interface uinf[]; + struct usbip_usb_device udev; + struct usbip_usb_interface uinf[]; } __attribute__((packed)); - /* ---------------------------------------------------------------------- */ /* Import a remote USB device. */ #define OP_IMPORT 0x03 @@ -72,19 +71,17 @@ struct op_import_request { } __attribute__((packed)); struct op_import_reply { - struct usb_device udev; -// struct usb_interface uinf[]; + struct usbip_usb_device udev; +// struct usbip_usb_interface uinf[]; } __attribute__((packed)); #define PACK_OP_IMPORT_REQUEST(pack, request) do {\ } while (0) #define PACK_OP_IMPORT_REPLY(pack, reply) do {\ - pack_usb_device(pack, &(reply)->udev);\ + usbip_net_pack_usb_device(pack, &(reply)->udev);\ } while (0) - - /* ---------------------------------------------------------------------- */ /* Export a USB device to a remote host. */ #define OP_EXPORT 0x06 @@ -92,7 +89,7 @@ struct op_import_reply { #define OP_REP_EXPORT (OP_REPLY | OP_EXPORT) struct op_export_request { - struct usb_device udev; + struct usbip_usb_device udev; } __attribute__((packed)); struct op_export_reply { @@ -101,7 +98,7 @@ struct op_export_reply { #define PACK_OP_EXPORT_REQUEST(pack, request) do {\ - pack_usb_device(pack, &(request)->udev);\ + usbip_net_pack_usb_device(pack, &(request)->udev);\ } while (0) #define PACK_OP_EXPORT_REPLY(pack, reply) do {\ @@ -114,7 +111,7 @@ struct op_export_reply { #define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT) struct op_unexport_request { - struct usb_device udev; + struct usbip_usb_device udev; } __attribute__((packed)); struct op_unexport_reply { @@ -122,14 +119,12 @@ struct op_unexport_reply { } __attribute__((packed)); #define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\ - pack_usb_device(pack, &(request)->udev);\ + usbip_net_pack_usb_device(pack, &(request)->udev);\ } while (0) #define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\ } while (0) - - /* ---------------------------------------------------------------------- */ /* Negotiate IPSec encryption key. (still not used) */ #define OP_CRYPKEY 0x04 @@ -161,38 +156,29 @@ struct op_devlist_reply { } __attribute__((packed)); struct op_devlist_reply_extra { - struct usb_device udev; - struct usb_interface uinf[]; + struct usbip_usb_device udev; + struct usbip_usb_interface uinf[]; } __attribute__((packed)); #define PACK_OP_DEVLIST_REQUEST(pack, request) do {\ } while (0) #define PACK_OP_DEVLIST_REPLY(pack, reply) do {\ - pack_uint32_t(pack, &(reply)->ndev);\ + usbip_net_pack_uint32_t(pack, &(reply)->ndev);\ } while (0) - -/* -------------------------------------------------- */ -/* Declare Prototype Function */ -/* -------------------------------------------------- */ - -void pack_uint32_t(int pack, uint32_t *num); -void pack_uint16_t(int pack, uint16_t *num); -void pack_usb_device(int pack, struct usb_device *udev); -void pack_usb_interface(int pack, struct usb_interface *uinf); - -ssize_t usbip_recv(int sockfd, void *buff, size_t bufflen); -ssize_t usbip_send(int sockfd, void *buff, size_t bufflen); -int usbip_send_op_common(int sockfd, uint32_t code, uint32_t status); -int usbip_recv_op_common(int sockfd, uint16_t *code); -int usbip_set_reuseaddr(int sockfd); -int usbip_set_nodelay(int sockfd); -int usbip_set_keepalive(int sockfd); - -int tcp_connect(char *hostname, char *service); - -#define USBIP_PORT 3240 -#define USBIP_PORT_STRING "3240" - -#endif +void usbip_net_pack_uint32_t(int pack, uint32_t *num); +void usbip_net_pack_uint16_t(int pack, uint16_t *num); +void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev); +void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf); + +ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen); +ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen); +int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status); +int usbip_net_recv_op_common(int sockfd, uint16_t *code); +int usbip_net_set_reuseaddr(int sockfd); +int usbip_net_set_nodelay(int sockfd); +int usbip_net_set_keepalive(int sockfd); +int usbip_net_tcp_connect(char *hostname, char *port); + +#endif /* __USBIP_NETWORK_H */ diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c new file mode 100644 index 0000000..d5a9ab6 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_unbind.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sysfs/libsysfs.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <getopt.h> + +#include "usbip_common.h" +#include "utils.h" +#include "usbip.h" + +static const char usbip_unbind_usage_string[] = + "usbip unbind <args>\n" + " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from " + "device on <busid>\n"; + +void usbip_unbind_usage(void) +{ + printf("usage: %s", usbip_unbind_usage_string); +} + +static int unbind_device(char *busid) +{ + char bus_type[] = "usb"; + struct sysfs_driver *usbip_host_drv; + struct sysfs_device *dev; + struct dlist *devlist; + int verified = 0; + int rc, ret = -1; + + char attr_name[] = "bConfigurationValue"; + char sysfs_mntpath[SYSFS_PATH_MAX]; + char busid_attr_path[SYSFS_PATH_MAX]; + struct sysfs_attribute *busid_attr; + char *val = NULL; + int len; + + /* verify the busid device is using usbip-host */ + usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME); + if (!usbip_host_drv) { + err("could not open %s driver: %s", USBIP_HOST_DRV_NAME, + strerror(errno)); + return -1; + } + + devlist = sysfs_get_driver_devices(usbip_host_drv); + if (!devlist) { + err("%s is not in use by any devices", USBIP_HOST_DRV_NAME); + goto err_close_usbip_host_drv; + } + + dlist_for_each_data(devlist, dev, struct sysfs_device) { + if (!strncmp(busid, dev->name, strlen(busid)) && + !strncmp(dev->driver_name, USBIP_HOST_DRV_NAME, + strlen(USBIP_HOST_DRV_NAME))) { + verified = 1; + break; + } + } + + if (!verified) { + err("device on busid %s is not using %s", busid, + USBIP_HOST_DRV_NAME); + goto err_close_usbip_host_drv; + } + + /* + * NOTE: A read and write of an attribute value of the device busid + * refers to must be done to start probing. That way a rebind of the + * default driver for the device occurs. + * + * This seems very hackish and adds a lot of pointless code. I think it + * should be done in the kernel by the driver after del_match_busid is + * finished! + */ + + rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); + if (rc < 0) { + err("sysfs must be mounted: %s", strerror(errno)); + return -1; + } + + snprintf(busid_attr_path, sizeof(busid_attr_path), "%s/%s/%s/%s/%s/%s", + sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DEVICES_NAME, + busid, attr_name); + + /* read a device attribute */ + busid_attr = sysfs_open_attribute(busid_attr_path); + if (!busid_attr) { + err("could not open %s/%s: %s", busid, attr_name, + strerror(errno)); + return -1; + } + + if (sysfs_read_attribute(busid_attr) < 0) { + err("problem reading attribute: %s", strerror(errno)); + goto err_out; + } + + len = busid_attr->len; + val = malloc(len); + *val = *busid_attr->value; + sysfs_close_attribute(busid_attr); + + /* notify driver of unbind */ + rc = modify_match_busid(busid, 0); + if (rc < 0) { + err("unable to unbind device on %s", busid); + goto err_out; + } + + /* write the device attribute */ + busid_attr = sysfs_open_attribute(busid_attr_path); + if (!busid_attr) { + err("could not open %s/%s: %s", busid, attr_name, + strerror(errno)); + return -1; + } + + rc = sysfs_write_attribute(busid_attr, val, len); + if (rc < 0) { + err("problem writing attribute: %s", strerror(errno)); + goto err_out; + } + sysfs_close_attribute(busid_attr); + + ret = 0; + printf("unbind device on busid %s: complete\n", busid); + +err_out: + free(val); +err_close_usbip_host_drv: + sysfs_close_driver(usbip_host_drv); + + return ret; +} + +int usbip_unbind(int argc, char *argv[]) +{ + static const struct option opts[] = { + { "busid", required_argument, NULL, 'b' }, + { NULL, 0, NULL, 0 } + }; + + int opt; + int ret = -1; + + for (;;) { + opt = getopt_long(argc, argv, "b:", opts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 'b': + ret = unbind_device(optarg); + goto out; + default: + goto err_out; + } + } + +err_out: + usbip_unbind_usage(); +out: + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c index ec9faac..8668a80 100644 --- a/drivers/staging/usbip/userspace/src/usbipd.c +++ b/drivers/staging/usbip/userspace/src/usbipd.c @@ -1,15 +1,29 @@ /* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi * - * Copyright (C) 2005-2007 Takahiro Hirofuchi + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H #include "../config.h" #endif +#include <errno.h> #include <unistd.h> #include <netdb.h> -#include <strings.h> +#include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> @@ -23,70 +37,160 @@ #define _GNU_SOURCE #include <getopt.h> +#include <glib.h> #include <signal.h> -#include "usbip.h" +#include "usbip_host_driver.h" +#include "usbip_common.h" #include "usbip_network.h" -#include <glib.h> +#undef PROGNAME +#define PROGNAME "usbipd" +#define MAXSOCKFD 20 -static const char version[] = PACKAGE_STRING; +GMainLoop *main_loop; +static const char usbip_version_string[] = PACKAGE_STRING; + +static const char usbipd_help_string[] = + "usage: usbipd [options] \n" + " -D, --daemon \n" + " Run as a daemon process. \n" + " \n" + " -d, --debug \n" + " Print debugging information. \n" + " \n" + " -h, --help \n" + " Print this help. \n" + " \n" + " -v, --version \n" + " Show version. \n"; + +static void usbipd_help(void) +{ + printf("%s\n", usbipd_help_string); +} -static int send_reply_devlist(int sockfd) +static int recv_request_import(int sockfd) { - int ret; + struct op_import_request req; + struct op_common reply; struct usbip_exported_device *edev; - struct op_devlist_reply reply; + struct usbip_usb_device pdu_udev; + int found = 0; + int error = 0; + int rc; + memset(&req, 0, sizeof(req)); + memset(&reply, 0, sizeof(reply)); - reply.ndev = 0; + rc = usbip_net_recv(sockfd, &req, sizeof(req)); + if (rc < 0) { + dbg("usbip_net_recv failed: import request"); + return -1; + } + PACK_OP_IMPORT_REQUEST(0, &req); - /* how many devices are exported ? */ - dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { - reply.ndev += 1; + dlist_for_each_data(host_driver->edev_list, edev, + struct usbip_exported_device) { + if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { + info("found requested device: %s", req.busid); + found = 1; + break; + } } - dbg("%d devices are exported", reply.ndev); + if (found) { + /* should set TCP_NODELAY for usbip */ + usbip_net_set_nodelay(sockfd); - ret = usbip_send_op_common(sockfd, OP_REP_DEVLIST, ST_OK); - if (ret < 0) { - err("send op_common"); - return ret; + /* export device needs a TCP/IP socket descriptor */ + rc = usbip_host_export_device(edev, sockfd); + if (rc < 0) + error = 1; + } else { + info("requested device not found: %s", req.busid); + error = 1; } - PACK_OP_DEVLIST_REPLY(1, &reply); + rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, + (!error ? ST_OK : ST_NA)); + if (rc < 0) { + dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT); + return -1; + } - ret = usbip_send(sockfd, (void *) &reply, sizeof(reply)); - if (ret < 0) { - err("send op_devlist_reply"); - return ret; + if (error) { + dbg("import request busid %s: failed", req.busid); + return -1; + } + + memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); + usbip_net_pack_usb_device(1, &pdu_udev); + + rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev)); + if (rc < 0) { + dbg("usbip_net_send failed: devinfo"); + return -1; } - dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { - struct usb_device pdu_udev; + dbg("import request busid %s: complete", req.busid); + + return 0; +} + +static int send_reply_devlist(int connfd) +{ + struct usbip_exported_device *edev; + struct usbip_usb_device pdu_udev; + struct usbip_usb_interface pdu_uinf; + struct op_devlist_reply reply; + int i; + int rc; + reply.ndev = 0; + /* number of exported devices */ + dlist_for_each_data(host_driver->edev_list, edev, + struct usbip_exported_device) { + reply.ndev += 1; + } + info("exportable devices: %d", reply.ndev); + + rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK); + if (rc < 0) { + dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST); + return -1; + } + PACK_OP_DEVLIST_REPLY(1, &reply); + + rc = usbip_net_send(connfd, &reply, sizeof(reply)); + if (rc < 0) { + dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST); + return -1; + } + + dlist_for_each_data(host_driver->edev_list, edev, + struct usbip_exported_device) { dump_usb_device(&edev->udev); memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); - pack_usb_device(1, &pdu_udev); + usbip_net_pack_usb_device(1, &pdu_udev); - ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev)); - if (ret < 0) { - err("send pdu_udev"); - return ret; + rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev)); + if (rc < 0) { + dbg("usbip_net_send failed: pdu_udev"); + return -1; } - for (int i=0; i < edev->udev.bNumInterfaces; i++) { - struct usb_interface pdu_uinf; - + for (i = 0; i < edev->udev.bNumInterfaces; i++) { dump_usb_interface(&edev->uinf[i]); memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf)); - pack_usb_interface(1, &pdu_uinf); + usbip_net_pack_usb_interface(1, &pdu_uinf); - ret = usbip_send(sockfd, (void *) &pdu_uinf, sizeof(pdu_uinf)); - if (ret < 0) { - err("send pdu_uinf"); - return ret; + rc = usbip_net_send(connfd, &pdu_uinf, + sizeof(pdu_uinf)); + if (rc < 0) { + dbg("usbip_net_send failed: pdu_uinf"); + return -1; } } } @@ -94,283 +198,227 @@ static int send_reply_devlist(int sockfd) return 0; } - -static int recv_request_devlist(int sockfd) +static int recv_request_devlist(int connfd) { - int ret; struct op_devlist_request req; + int rc; - bzero(&req, sizeof(req)); + memset(&req, 0, sizeof(req)); - ret = usbip_recv(sockfd, (void *) &req, sizeof(req)); - if (ret < 0) { - err("recv devlist request"); + rc = usbip_net_recv(connfd, &req, sizeof(req)); + if (rc < 0) { + dbg("usbip_net_recv failed: devlist request"); return -1; } - ret = send_reply_devlist(sockfd); - if (ret < 0) { - err("send devlist reply"); + rc = send_reply_devlist(connfd); + if (rc < 0) { + dbg("send_reply_devlist failed"); return -1; } return 0; } - -static int recv_request_import(int sockfd) +static int recv_pdu(int connfd) { + uint16_t code = OP_UNSPEC; int ret; - struct op_import_request req; - struct op_common reply; - struct usbip_exported_device *edev; - int found = 0; - int error = 0; - bzero(&req, sizeof(req)); - bzero(&reply, sizeof(reply)); - - ret = usbip_recv(sockfd, (void *) &req, sizeof(req)); + ret = usbip_net_recv_op_common(connfd, &code); if (ret < 0) { - err("recv import request"); + dbg("could not receive opcode: %#0x", code); return -1; } - PACK_OP_IMPORT_REQUEST(0, &req); - - dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { - if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { - dbg("found requested device %s", req.busid); - found = 1; - break; - } + ret = usbip_host_refresh_device_list(); + if (ret < 0) { + dbg("could not refresh device list: %d", ret); + return -1; } - if (found) { - /* should set TCP_NODELAY for usbip */ - usbip_set_nodelay(sockfd); - - /* export_device needs a TCP/IP socket descriptor */ - ret = usbip_stub_export_device(edev, sockfd); - if (ret < 0) - error = 1; - } else { - info("not found requested device %s", req.busid); - error = 1; + info("received request: %#0x(%d)", code, connfd); + switch (code) { + case OP_REQ_DEVLIST: + ret = recv_request_devlist(connfd); + break; + case OP_REQ_IMPORT: + ret = recv_request_import(connfd); + break; + case OP_REQ_DEVINFO: + case OP_REQ_CRYPKEY: + default: + err("received an unknown opcode: %#0x", code); + ret = -1; } + if (ret == 0) + info("request %#0x(%d): complete", code, connfd); + else + info("request %#0x(%d): failed", code, connfd); - ret = usbip_send_op_common(sockfd, OP_REP_IMPORT, (!error ? ST_OK : ST_NA)); - if (ret < 0) { - err("send import reply"); - return -1; - } - - if (!error) { - struct usb_device pdu_udev; + return ret; +} - memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); - pack_usb_device(1, &pdu_udev); +#ifdef HAVE_LIBWRAP +static int tcpd_auth(int connfd) +{ + struct request_info request; + int rc; - ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev)); - if (ret < 0) { - err("send devinfo"); - return -1; - } - } + request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0); + fromhost(&request); + rc = hosts_access(&request); + if (rc == 0) + return -1; return 0; } +#endif - - -static int recv_pdu(int sockfd) +static int do_accept(int listenfd) { - int ret; - uint16_t code = OP_UNSPEC; + int connfd; + struct sockaddr_storage ss; + socklen_t len = sizeof(ss); + char host[NI_MAXHOST], port[NI_MAXSERV]; + int rc; + memset(&ss, 0, sizeof(ss)); - ret = usbip_recv_op_common(sockfd, &code); - if (ret < 0) { - err("recv op_common, %d", ret); - return ret; + connfd = accept(listenfd, (struct sockaddr *) &ss, &len); + if (connfd < 0) { + err("failed to accept connection"); + return -1; } + rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host), + port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + if (rc) + err("getnameinfo: %s", gai_strerror(rc)); - ret = usbip_stub_refresh_device_list(); - if (ret < 0) +#ifdef HAVE_LIBWRAP + rc = tcpd_auth(connfd); + if (rc < 0) { + info("denied access from %s", host); + close(connfd); return -1; + } +#endif + info("connection from %s:%s", host, port); - switch(code) { - case OP_REQ_DEVLIST: - ret = recv_request_devlist(sockfd); - break; + return connfd; +} - case OP_REQ_IMPORT: - ret = recv_request_import(sockfd); - break; +gboolean process_request(GIOChannel *gio, GIOCondition condition, + gpointer unused_data) +{ + int listenfd; + int connfd; - case OP_REQ_DEVINFO: - case OP_REQ_CRYPKEY: + (void) unused_data; - default: - err("unknown op_code, %d", code); - ret = -1; + if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { + err("unknown condition"); + BUG(); } + if (condition & G_IO_IN) { + listenfd = g_io_channel_unix_get_fd(gio); + connfd = do_accept(listenfd); + if (connfd < 0) + return TRUE; - return ret; -} - - + recv_pdu(connfd); + close(connfd); + } + return TRUE; +} static void log_addrinfo(struct addrinfo *ai) { - int ret; char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; + int rc; - ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), - sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); - if (ret) - err("getnameinfo, %s", gai_strerror(ret)); - - info("listen at [%s]:%s", hbuf, sbuf); -} - -static struct addrinfo *my_getaddrinfo(char *host, int ai_family) -{ - int ret; - struct addrinfo hints, *ai_head; - - bzero(&hints, sizeof(hints)); - - hints.ai_family = ai_family; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; + rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), + sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); + if (rc) + err("getnameinfo: %s", gai_strerror(rc)); - ret = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head); - if (ret) { - err("%s: %s", USBIP_PORT_STRING, gai_strerror(ret)); - return NULL; - } - - return ai_head; + info("listening on %s:%s", hbuf, sbuf); } -#define MAXSOCK 20 -static int listen_all_addrinfo(struct addrinfo *ai_head, int lsock[]) +static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[]) { struct addrinfo *ai; - int n = 0; /* number of sockets */ + int ret, nsockfd = 0; - for (ai = ai_head; ai && n < MAXSOCK; ai = ai->ai_next) { - int ret; - - lsock[n] = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (lsock[n] < 0) + for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) { + sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype, + ai->ai_protocol); + if (sockfdlist[nsockfd] < 0) continue; - usbip_set_reuseaddr(lsock[n]); - usbip_set_nodelay(lsock[n]); + usbip_net_set_reuseaddr(sockfdlist[nsockfd]); + usbip_net_set_nodelay(sockfdlist[nsockfd]); - if (lsock[n] >= FD_SETSIZE) { - close(lsock[n]); - lsock[n] = -1; + if (sockfdlist[nsockfd] >= FD_SETSIZE) { + close(sockfdlist[nsockfd]); + sockfdlist[nsockfd] = -1; continue; } - ret = bind(lsock[n], ai->ai_addr, ai->ai_addrlen); + ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen); if (ret < 0) { - close(lsock[n]); - lsock[n] = -1; + close(sockfdlist[nsockfd]); + sockfdlist[nsockfd] = -1; continue; } - ret = listen(lsock[n], SOMAXCONN); + ret = listen(sockfdlist[nsockfd], SOMAXCONN); if (ret < 0) { - close(lsock[n]); - lsock[n] = -1; + close(sockfdlist[nsockfd]); + sockfdlist[nsockfd] = -1; continue; } log_addrinfo(ai); - - /* next if succeed */ - n++; + nsockfd++; } - if (n == 0) { - err("no socket to listen to"); + if (nsockfd == 0) return -1; - } - dbg("listen %d address%s", n, (n==1)?"":"es"); + dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); - return n; + return nsockfd; } -#ifdef HAVE_LIBWRAP -static int tcpd_auth(int csock) +static struct addrinfo *do_getaddrinfo(char *host, int ai_family) { - int ret; - struct request_info request; - - request_init(&request, RQ_DAEMON, "usbipd", RQ_FILE, csock, 0); - - fromhost(&request); - - ret = hosts_access(&request); - if (!ret) - return -1; - - return 0; -} -#endif - -static int my_accept(int lsock) -{ - int csock; - struct sockaddr_storage ss; - socklen_t len = sizeof(ss); - char host[NI_MAXHOST], port[NI_MAXSERV]; - int ret; - - bzero(&ss, sizeof(ss)); - - csock = accept(lsock, (struct sockaddr *) &ss, &len); - if (csock < 0) { - err("accept"); - return -1; - } + struct addrinfo hints, *ai_head; + int rc; - ret = getnameinfo((struct sockaddr *) &ss, len, - host, sizeof(host), port, sizeof(port), - (NI_NUMERICHOST | NI_NUMERICSERV)); - if (ret) - err("getnameinfo, %s", gai_strerror(ret)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; -#ifdef HAVE_LIBWRAP - ret = tcpd_auth(csock); - if (ret < 0) { - info("deny access from %s", host); - close(csock); - return -1; + rc = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head); + if (rc) { + err("failed to get a network address %s: %s", USBIP_PORT_STRING, + gai_strerror(rc)); + return NULL; } -#endif - info("connected from %s:%s", host, port); - - return csock; + return ai_head; } - -GMainLoop *main_loop; - static void signal_handler(int i) { - dbg("signal catched, code %d", i); + dbg("received signal: code %d", i); if (main_loop) g_main_loop_quit(main_loop); @@ -380,191 +428,140 @@ static void set_signal(void) { struct sigaction act; - bzero(&act, sizeof(act)); + memset(&act, 0, sizeof(act)); act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); } - -gboolean process_comming_request(GIOChannel *gio, GIOCondition condition, - gpointer data __attribute__((unused))) -{ - int ret; - - if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) - g_error("unknown condition"); - - - if (condition & G_IO_IN) { - int lsock; - int csock; - - lsock = g_io_channel_unix_get_fd(gio); - - csock = my_accept(lsock); - if (csock < 0) - return TRUE; - - ret = recv_pdu(csock); - if (ret < 0) - err("process recieved pdu"); - - close(csock); - } - - return TRUE; -} - - -static void do_standalone_mode(gboolean daemonize) +static int do_standalone_mode(gboolean daemonize) { - int ret; - int lsock[MAXSOCK]; struct addrinfo *ai_head; - int n; - + int sockfdlist[MAXSOCKFD]; + int nsockfd; + int i; + if (usbip_names_init(USBIDS_FILE)) + err("failed to open %s", USBIDS_FILE); - ret = usbip_names_init(USBIDS_FILE); - if (ret) - err("open usb.ids"); - - ret = usbip_stub_driver_open(); - if (ret < 0) - g_error("driver open failed"); + if (usbip_host_driver_open()) { + err("please load " USBIP_CORE_MOD_NAME ".ko and " + USBIP_HOST_DRV_NAME ".ko!"); + return -1; + } if (daemonize) { - if (daemon(0,0) < 0) - g_error("daemonizing failed: %s", g_strerror(errno)); + if (daemon(0,0) < 0) { + err("daemonizing failed: %s", strerror(errno)); + return -1; + } usbip_use_syslog = 1; } - set_signal(); - ai_head = my_getaddrinfo(NULL, PF_UNSPEC); + ai_head = do_getaddrinfo(NULL, PF_UNSPEC); if (!ai_head) - return; + return -1; - n = listen_all_addrinfo(ai_head, lsock); - if (n <= 0) - g_error("no socket to listen to"); + info("starting " PROGNAME " (%s)", usbip_version_string); - for (int i = 0; i < n; i++) { + nsockfd = listen_all_addrinfo(ai_head, sockfdlist); + if (nsockfd <= 0) { + err("failed to open a listening socket"); + return -1; + } + + for (i = 0; i < nsockfd; i++) { GIOChannel *gio; - gio = g_io_channel_unix_new(lsock[i]); + gio = g_io_channel_unix_new(sockfdlist[i]); g_io_add_watch(gio, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), - process_comming_request, NULL); + process_request, NULL); } - - info("usbipd start (%s)", version); - - main_loop = g_main_loop_new(FALSE, FALSE); g_main_loop_run(main_loop); - info("shutdown"); + info("shutting down " PROGNAME); freeaddrinfo(ai_head); + usbip_host_driver_close(); usbip_names_free(); - usbip_stub_driver_close(); - - return; -} - -static const char help_message[] = "\ -Usage: usbipd [options] \n\ - -D, --daemon \n\ - Run as a daemon process. \n\ - \n\ - -d, --debug \n\ - Print debugging information. \n\ - \n\ - -v, --version \n\ - Show version. \n\ - \n\ - -h, --help \n\ - Print this help. \n"; - -static void show_help(void) -{ - printf("%s", help_message); + return 0; } -static const struct option longopts[] = { - {"daemon", no_argument, NULL, 'D'}, - {"debug", no_argument, NULL, 'd'}, - {"version", no_argument, NULL, 'v'}, - {"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 0} -}; - int main(int argc, char *argv[]) { - gboolean daemonize = FALSE; + static const struct option longopts[] = { + { "daemon", no_argument, NULL, 'D' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } + }; enum { cmd_standalone_mode = 1, cmd_help, cmd_version - } cmd = cmd_standalone_mode; + } cmd; + gboolean daemonize = FALSE; + int opt, rc = -1; usbip_use_stderr = 1; usbip_use_syslog = 0; if (geteuid() != 0) - g_warning("running non-root?"); + err("not running as root?"); + cmd = cmd_standalone_mode; for (;;) { - int c; - int index = 0; - - c = getopt_long(argc, argv, "vhdD", longopts, &index); + opt = getopt_long(argc, argv, "Ddhv", longopts, NULL); - if (c == -1) + if (opt == -1) break; - switch (c) { - case 'd': - usbip_use_debug = 1; - continue; - case 'v': - cmd = cmd_version; - break; - case 'h': - cmd = cmd_help; - break; - case 'D': - daemonize = TRUE; - break; - case '?': - show_help(); - exit(EXIT_FAILURE); - default: - err("getopt"); - } - } - - switch (cmd) { - case cmd_standalone_mode: - do_standalone_mode(daemonize); + switch (opt) { + case 'D': + daemonize = TRUE; + break; + case 'd': + usbip_use_debug = 1; break; - case cmd_version: - printf("%s\n", version); + case 'h': + cmd = cmd_help; break; - case cmd_help: - show_help(); + case 'v': + cmd = cmd_version; break; + case '?': + usbipd_help(); default: - info("unknown cmd"); - show_help(); + goto err_out; + } } - return 0; + switch (cmd) { + case cmd_standalone_mode: + rc = do_standalone_mode(daemonize); + break; + case cmd_version: + printf(PROGNAME " (%s)\n", usbip_version_string); + rc = 0; + break; + case cmd_help: + usbipd_help(); + rc = 0; + break; + default: + usbipd_help(); + goto err_out; + } + +err_out: + return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/drivers/staging/usbip/userspace/src/utils.c b/drivers/staging/usbip/userspace/src/utils.c index 8f44108..2d4966e 100644 --- a/drivers/staging/usbip/userspace/src/utils.c +++ b/drivers/staging/usbip/userspace/src/utils.c @@ -1,255 +1,76 @@ /* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi * - * Copyright (C) 2005-2007 Takahiro Hirofuchi + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "utils.h" - -int read_integer(char *path) -{ - char buff[100]; - int fd; - int ret = 0; - - bzero(buff, sizeof(buff)); - - fd = open(path, O_RDONLY); - if (fd < 0) - return -1; - - ret = read(fd, buff, sizeof(buff)); - if (ret < 0) { - close(fd); - return -1; - } - - sscanf(buff, "%d", &ret); - - close(fd); - - return ret; -} - -int read_string(char *path, char *string, size_t len) -{ - int fd; - int ret = 0; - char *p; - - bzero(string, len); - - fd = open(path, O_RDONLY); - if (fd < 0) { - string = NULL; - return -1; - } - - ret = read(fd, string, len-1); - if (ret < 0) { - string = NULL; - close(fd); - return -1; - } - - p = strchr(string, '\n'); - *p = '\0'; +#include <sysfs/libsysfs.h> - close(fd); +#include <errno.h> +#include <stdio.h> +#include <string.h> - return 0; -} +#include "usbip_common.h" +#include "utils.h" -int write_integer(char *path, int value) +int modify_match_busid(char *busid, int add) { - int fd; - int ret; - char buff[100]; - - snprintf(buff, sizeof(buff), "%d", value); - - fd = open(path, O_WRONLY); - if (fd < 0) - return -1; - - ret = write(fd, buff, strlen(buff)); - if (ret < 0) { - close(fd); + char bus_type[] = "usb"; + char attr_name[] = "match_busid"; + char buff[SYSFS_BUS_ID_SIZE + 4]; + char sysfs_mntpath[SYSFS_PATH_MAX]; + char match_busid_attr_path[SYSFS_PATH_MAX]; + struct sysfs_attribute *match_busid_attr; + int rc, ret = 0; + + if (strnlen(busid, SYSFS_BUS_ID_SIZE) > SYSFS_BUS_ID_SIZE - 1) { + dbg("busid is too long"); return -1; } - close(fd); - - return 0; -} - -int read_bConfigurationValue(char *busid) -{ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bConfigurationValue", busid); - - return read_integer(path); -} - -int write_bConfigurationValue(char *busid, int config) -{ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bConfigurationValue", busid); - - return write_integer(path, config); -} - -int read_bNumInterfaces(char *busid) -{ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bNumInterfaces", busid); - - return read_integer(path); -} - -int read_bDeviceClass(char *busid) -{ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/bDeviceClass", busid); - - return read_integer(path); -} - -int getdriver(char *busid, int conf, int infnum, char *driver, size_t len) -{ - char path[PATH_MAX]; - char linkto[PATH_MAX]; - int ret; - - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s:%d.%d/driver", busid, conf, infnum); - - /* readlink does not add NULL */ - bzero(linkto, sizeof(linkto)); - ret = readlink(path, linkto, sizeof(linkto)-1); - if (ret < 0) { - strncpy(driver, "none", len); + rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); + if (rc < 0) { + err("sysfs must be mounted: %s", strerror(errno)); return -1; - } else { - strncpy(driver, basename(linkto), len); - return 0; } -} - -int getdevicename(char *busid, char *name, size_t len) -{ - char path[PATH_MAX]; - char idProduct[10], idVendor[10]; - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/idVendor", busid); - read_string(path, idVendor, sizeof(idVendor)); + snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), + "%s/%s/%s/%s/%s/%s", sysfs_mntpath, SYSFS_BUS_NAME, bus_type, + SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); - snprintf(path, PATH_MAX, "/sys/bus/usb/devices/%s/idProduct", busid); - read_string(path, idProduct, sizeof(idProduct)); - - if (!idVendor[0] || !idProduct[0]) + match_busid_attr = sysfs_open_attribute(match_busid_attr_path); + if (!match_busid_attr) { + dbg("problem getting match_busid attribute: %s", + strerror(errno)); return -1; - - snprintf(name, len, "%s:%s", idVendor, idProduct); - - return 0; -} - -#define MAXLINE 100 - -/* if this cannot read a whole line, return -1 */ -int readline(int sockfd, char *buff, int bufflen) -{ - int ret; - char c; - int index = 0; - - - while (index < bufflen) { - ret = read(sockfd, &c, sizeof(c)); - if (ret < 0 && errno == EINTR) - continue; - if (ret <= 0) { - return -1; - } - - buff[index] = c; - - if ( index > 0 && buff[index-1] == '\r' && buff[index] == '\n') { - /* end of line */ - buff[index-1] = '\0'; /* get rid of delimitor */ - return index; - } else - index++; } - return -1; -} - -#if 0 -int writeline(int sockfd, char *str, int strlen) -{ - int ret; - int index = 0; - int len; - char buff[MAXLINE]; - - if (strlen + 3 > MAXLINE) - return -1; - - strncpy(buff, str, strlen); - buff[strlen+1] = '\r'; - buff[strlen+2] = '\n'; - buff[strlen+3] = '\0'; + if (add) + snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); + else + snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); - len = strlen + 3; + dbg("write \"%s\" to %s", buff, match_busid_attr->path); - while (len > 0) { - ret = write(sockfd, buff+index, len); - if (ret <= 0) { - return -1; - } - - len -= ret; - index += ret; + rc = sysfs_write_attribute(match_busid_attr, buff, sizeof(buff)); + if (rc < 0) { + dbg("failed to write match_busid: %s", strerror(errno)); + ret = -1; } - return index; -} -#endif + sysfs_close_attribute(match_busid_attr); -int writeline(int sockfd, char *str, int strlen) -{ - int ret; - int index = 0; - int len; - char buff[MAXLINE]; - - len = strnlen(str, strlen); - - if (strlen + 2 > MAXLINE) - return -1; - - memcpy(buff, str, strlen); - buff[strlen] = '\r'; - buff[strlen+1] = '\n'; /* strlen+1 <= MAXLINE-1 */ - - len = strlen + 2; - - while (len > 0) { - ret = write(sockfd, buff+index, len); - if (ret < 0 && errno == EINTR) - continue; - if (ret <= 0) { - return -1; - } - - len -= ret; - index += ret; - } - - return index; + return ret; } - diff --git a/drivers/staging/usbip/userspace/src/utils.h b/drivers/staging/usbip/userspace/src/utils.h index 991f662..fdcb14d 100644 --- a/drivers/staging/usbip/userspace/src/utils.h +++ b/drivers/staging/usbip/userspace/src/utils.h @@ -1,37 +1,24 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ -#ifdef HAVE_CONFIG_H -#include "../config.h" -#endif +#ifndef __UTILS_H +#define __UTILS_H -#define _GNU_SOURCE -#include <string.h> -#include <sys/un.h> -#include <sys/types.h> -#include <sys/socket.h> +int modify_match_busid(char *busid, int add); -#include <sysfs/libsysfs.h> -#include <glib.h> -#include <unistd.h> -#include <stdio.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdlib.h> -#include <time.h> -#include <errno.h> - - - -/* Be sync to kernel header */ -#define BUS_ID_SIZE 20 - -int read_string(char *path, char *, size_t len); -int read_integer(char *path); -int getdevicename(char *busid, char *name, size_t len); -int getdriver(char *busid, int conf, int infnum, char *driver, size_t len); -int read_bNumInterfaces(char *busid); -int read_bConfigurationValue(char *busid); -int write_integer(char *path, int value); -int write_bConfigurationValue(char *busid, int config); -int read_bDeviceClass(char *busid); -int readline(int sockfd, char *str, int strlen); -int writeline(int sockfd, char *buff, int bufflen); +#endif /* __UTILS_H */ |