├── usb.ids ├── AUTHORS ├── autogen.sh ├── libsrc ├── sysfs_utils.h ├── Makefile.am ├── sysfs_utils.c ├── usbip_host_driver.h ├── usbip_device_driver.h ├── vhci_driver.h ├── names.h ├── usbip_host_driver.c ├── usbip_host_common.h ├── usbip_common.h ├── list.h ├── usbip_device_driver.c ├── usbip_host_common.c ├── usbip_common.c ├── vhci_driver.c └── names.c ├── Makefile.am ├── cleanup.sh ├── src ├── Makefile.am ├── utils.h ├── usbip.h ├── utils.c ├── usbip_port.c ├── usbip_detach.c ├── usbip_unbind.c ├── usbip.c ├── usbip_bind.c ├── usbip_network.h ├── usbip_attach.c ├── usbip_network.c ├── usbip_list.c └── usbipd.c ├── .gitignore ├── README.android ├── Android.mk ├── doc ├── usbip.8 └── usbipd.8 ├── configure.ac ├── README ├── INSTALL └── COPYING /usb.ids: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trevd/android_external_usbip/HEAD/usb.ids -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Takahiro Hirofuchi 2 | Robert Leibl 3 | matt mooney 4 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | 3 | #aclocal 4 | #autoheader 5 | #libtoolize --copy --force 6 | #automake-1.9 -acf 7 | #autoconf 8 | 9 | autoreconf -i -f -v 10 | -------------------------------------------------------------------------------- /libsrc/sysfs_utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __SYSFS_UTILS_H 3 | #define __SYSFS_UTILS_H 4 | 5 | int write_sysfs_attribute(const char *attr_path, const char *new_value, 6 | size_t len); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS := libsrc src 2 | includedir = @includedir@/usbip 3 | include_HEADERS := $(addprefix libsrc/, \ 4 | usbip_common.h vhci_driver.h usbip_host_driver.h) 5 | 6 | dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) 7 | -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -r Makefile ]; then 4 | make distclean 5 | fi 6 | 7 | FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \ 8 | config.status config.sub configure cscope.out depcomp install-sh \ 9 | libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile \ 10 | Makefile.in missing src/Makefile src/Makefile.in" 11 | 12 | rm -vRf $FILES 13 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' 2 | AM_CFLAGS = @EXTRA_CFLAGS@ 3 | LDADD = $(top_builddir)/libsrc/libusbip.la 4 | 5 | sbin_PROGRAMS := usbip usbipd 6 | 7 | usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \ 8 | usbip_attach.c usbip_detach.c usbip_list.c \ 9 | usbip_bind.c usbip_unbind.c usbip_port.c 10 | 11 | usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c 12 | -------------------------------------------------------------------------------- /libsrc/Makefile.am: -------------------------------------------------------------------------------- 1 | libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' 2 | libusbip_la_CFLAGS = @EXTRA_CFLAGS@ 3 | libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@ 4 | 5 | lib_LTLIBRARIES := libusbip.la 6 | libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ 7 | usbip_device_driver.c usbip_device_driver.h \ 8 | usbip_common.c usbip_common.h usbip_host_common.h \ 9 | usbip_host_common.c vhci_driver.c vhci_driver.h \ 10 | sysfs_utils.c sysfs_utils.h 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | aclocal.m4 4 | autom4te.cache/ 5 | config.guess 6 | config.h 7 | config.h.in 8 | config.log 9 | config.status 10 | config.sub 11 | configure 12 | depcomp 13 | install-sh 14 | libsrc/Makefile 15 | libsrc/Makefile.in 16 | libtool 17 | ltmain.sh 18 | missing 19 | src/Makefile 20 | src/Makefile.in 21 | stamp-h1 22 | libsrc/libusbip.la 23 | libsrc/libusbip_la-names.lo 24 | libsrc/libusbip_la-usbip_common.lo 25 | libsrc/libusbip_la-usbip_host_driver.lo 26 | libsrc/libusbip_la-vhci_driver.lo 27 | src/usbip 28 | src/usbipd 29 | -------------------------------------------------------------------------------- /README.android: -------------------------------------------------------------------------------- 1 | USBIP Userland tools for Android 2 | ================================ 3 | 4 | Yanked for the linux kernel sources tools/usb/usbip 5 | Your kernel must have the required modules compiled for the thing to 6 | work 7 | 8 | Depends on libudev ( https://github.com/trevd/android_external_libudev ) 9 | 10 | Place usb.ids in /system/etc 11 | 12 | usage: In Android shell 13 | usbip attach -r 192.168.1.2 -b 1-5 14 | 15 | Note: Version info must match that of the server "usbip (usbip-utils 2.0)" 16 | 17 | You can use the same sources to compile the server and client side tools 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /libsrc/sysfs_utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "sysfs_utils.h" 7 | #include "usbip_common.h" 8 | 9 | int write_sysfs_attribute(const char *attr_path, const char *new_value, 10 | size_t len) 11 | { 12 | int fd; 13 | int length; 14 | 15 | fd = open(attr_path, O_WRONLY); 16 | if (fd < 0) { 17 | dbg("error opening attribute %s", attr_path); 18 | return -1; 19 | } 20 | 21 | length = write(fd, new_value, len); 22 | if (length < 0) { 23 | dbg("error writing to attribute %s", attr_path); 24 | close(fd); 25 | return -1; 26 | } 27 | 28 | close(fd); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef __UTILS_H 20 | #define __UTILS_H 21 | 22 | int modify_match_busid(char *busid, int add); 23 | 24 | #endif /* __UTILS_H */ 25 | 26 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := libusbip 6 | LOCAL_MODULE_TAGS := optional 7 | LOCAL_SRC_FILES := libsrc/names.c \ 8 | libsrc/sysfs_utils.c \ 9 | libsrc/usbip_common.c \ 10 | libsrc/usbip_device_driver.c \ 11 | libsrc/usbip_host_common.c \ 12 | libsrc/usbip_host_driver.c \ 13 | libsrc/vhci_driver.c 14 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/libsrc external/libudev/include 15 | 16 | include $(BUILD_STATIC_LIBRARY) 17 | 18 | 19 | 20 | 21 | include $(CLEAR_VARS) 22 | 23 | LOCAL_MODULE := usbip 24 | LOCAL_MODULE_TAGS := optional 25 | LOCAL_SRC_FILES := src/usbip_attach.c \ 26 | src/usbip_bind.c \ 27 | src/usbip.c \ 28 | src/usbip_detach.c \ 29 | src/usbip_list.c \ 30 | src/usbip_network.c \ 31 | src/usbip_port.c \ 32 | src/usbip_unbind.c \ 33 | src/utils.c 34 | 35 | LOCAL_CFLAGS += -DPACKAGE_STRING=\"usbip-utils\ 2.0\" -DUSBIP_VERSION=0x00000111 36 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/libsrc 37 | LOCAL_FORCE_STATIC_EXECUTABLE := true 38 | LOCAL_WHOLE_STATIC_LIBRARIES += libudev libusbip 39 | include $(BUILD_EXECUTABLE) 40 | -------------------------------------------------------------------------------- /libsrc/usbip_host_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * Copyright (C) 2015-2016 Samsung Electronics 5 | * Igor Kotrasinski 6 | * Krzysztof Opasiak 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #ifndef __USBIP_HOST_DRIVER_H 23 | #define __USBIP_HOST_DRIVER_H 24 | 25 | #include 26 | #include "usbip_common.h" 27 | #include "list.h" 28 | #include "usbip_host_common.h" 29 | 30 | extern struct usbip_host_driver host_driver; 31 | 32 | #endif /* __USBIP_HOST_DRIVER_H */ 33 | -------------------------------------------------------------------------------- /libsrc/usbip_device_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Karol Kosik 3 | * 2015 Samsung Electronics 4 | * Author: Igor Kotrasinski 5 | * 6 | * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is: 7 | * Copyright (C) 2011 matt mooney 8 | * 2005-2007 Takahiro Hirofuchi 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #ifndef __USBIP_DEVICE_DRIVER_H 25 | #define __USBIP_DEVICE_DRIVER_H 26 | 27 | #include 28 | #include "usbip_common.h" 29 | #include "usbip_host_common.h" 30 | #include "list.h" 31 | 32 | extern struct usbip_host_driver device_driver; 33 | 34 | #endif /* __USBIP_DEVICE_DRIVER_H */ 35 | -------------------------------------------------------------------------------- /libsrc/vhci_driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef __VHCI_DRIVER_H 6 | #define __VHCI_DRIVER_H 7 | 8 | #include 9 | #include 10 | 11 | #include "usbip_common.h" 12 | 13 | #define USBIP_VHCI_BUS_TYPE "platform" 14 | #define MAXNPORT 128 15 | 16 | struct usbip_imported_device { 17 | uint8_t port; 18 | uint32_t status; 19 | 20 | uint32_t devid; 21 | 22 | uint8_t busnum; 23 | uint8_t devnum; 24 | 25 | /* usbip_class_device list */ 26 | struct usbip_usb_device udev; 27 | }; 28 | 29 | struct usbip_vhci_driver { 30 | 31 | /* /sys/devices/platform/vhci_hcd */ 32 | struct udev_device *hc_device; 33 | 34 | int nports; 35 | struct usbip_imported_device idev[MAXNPORT]; 36 | }; 37 | 38 | 39 | extern struct usbip_vhci_driver *vhci_driver; 40 | 41 | int usbip_vhci_driver_open(void); 42 | void usbip_vhci_driver_close(void); 43 | 44 | int usbip_vhci_refresh_device_list(void); 45 | 46 | 47 | int usbip_vhci_get_free_port(void); 48 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, 49 | uint32_t speed); 50 | 51 | /* will be removed */ 52 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, 53 | uint8_t devnum, uint32_t speed); 54 | 55 | int usbip_vhci_detach_device(uint8_t port); 56 | 57 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev); 58 | 59 | #endif /* __VHCI_DRIVER_H */ 60 | -------------------------------------------------------------------------------- /src/usbip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #ifndef __USBIP_H 20 | #define __USBIP_H 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "../config.h" 24 | #endif 25 | 26 | /* usbip commands */ 27 | int usbip_attach(int argc, char *argv[]); 28 | int usbip_detach(int argc, char *argv[]); 29 | int usbip_list(int argc, char *argv[]); 30 | int usbip_bind(int argc, char *argv[]); 31 | int usbip_unbind(int argc, char *argv[]); 32 | int usbip_port_show(int argc, char *argv[]); 33 | 34 | void usbip_attach_usage(void); 35 | void usbip_detach_usage(void); 36 | void usbip_list_usage(void); 37 | void usbip_bind_usage(void); 38 | void usbip_unbind_usage(void); 39 | 40 | #endif /* __USBIP_H */ 41 | -------------------------------------------------------------------------------- /libsrc/names.h: -------------------------------------------------------------------------------- 1 | /* 2 | * names.h -- USB name database manipulation routines 3 | * 4 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | * 21 | * 22 | * Copyright (C) 2005 Takahiro Hirofuchi 23 | * - names_free() is added. 24 | */ 25 | 26 | #ifndef _NAMES_H 27 | #define _NAMES_H 28 | 29 | #include 30 | 31 | /* used by usbip_common.c */ 32 | extern const char *names_vendor(u_int16_t vendorid); 33 | extern const char *names_product(u_int16_t vendorid, u_int16_t productid); 34 | extern const char *names_class(u_int8_t classid); 35 | extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid); 36 | extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, 37 | u_int8_t protocolid); 38 | extern int names_init(char *n); 39 | extern void names_free(void); 40 | 41 | #endif /* _NAMES_H */ 42 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "usbip_common.h" 24 | #include "utils.h" 25 | #include "sysfs_utils.h" 26 | 27 | int modify_match_busid(char *busid, int add) 28 | { 29 | char attr_name[] = "match_busid"; 30 | char command[SYSFS_BUS_ID_SIZE + 4]; 31 | char match_busid_attr_path[SYSFS_PATH_MAX]; 32 | int rc; 33 | 34 | snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), 35 | "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, 36 | SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, 37 | attr_name); 38 | 39 | if (add) 40 | snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); 41 | else 42 | snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); 43 | 44 | rc = write_sysfs_attribute(match_busid_attr_path, command, 45 | sizeof(command)); 46 | if (rc < 0) { 47 | dbg("failed to write match_busid: %s", strerror(errno)); 48 | return -1; 49 | } 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/usbip_port.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | */ 15 | 16 | #include "vhci_driver.h" 17 | #include "usbip_common.h" 18 | 19 | static int list_imported_devices(void) 20 | { 21 | int i; 22 | struct usbip_imported_device *idev; 23 | int ret; 24 | 25 | if (usbip_names_init(USBIDS_FILE)) 26 | err("failed to open %s", USBIDS_FILE); 27 | 28 | ret = usbip_vhci_driver_open(); 29 | if (ret < 0) { 30 | err("open vhci_driver"); 31 | goto err_names_free; 32 | } 33 | 34 | printf("Imported USB devices\n"); 35 | printf("====================\n"); 36 | 37 | for (i = 0; i < vhci_driver->nports; i++) { 38 | idev = &vhci_driver->idev[i]; 39 | 40 | if (usbip_vhci_imported_device_dump(idev) < 0) 41 | goto err_driver_close; 42 | } 43 | 44 | usbip_vhci_driver_close(); 45 | usbip_names_free(); 46 | 47 | return ret; 48 | 49 | err_driver_close: 50 | usbip_vhci_driver_close(); 51 | err_names_free: 52 | usbip_names_free(); 53 | return -1; 54 | } 55 | 56 | int usbip_port_show(__attribute__((unused)) int argc, 57 | __attribute__((unused)) char *argv[]) 58 | { 59 | int ret; 60 | 61 | ret = list_imported_devices(); 62 | if (ret < 0) 63 | err("list imported devices"); 64 | 65 | return ret; 66 | } 67 | -------------------------------------------------------------------------------- /doc/usbip.8: -------------------------------------------------------------------------------- 1 | .TH USBIP "8" "February 2009" "usbip" "System Administration Utilities" 2 | .SH NAME 3 | usbip \- manage USB/IP devices 4 | .SH SYNOPSIS 5 | .B usbip 6 | [\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR> 7 | 8 | .SH DESCRIPTION 9 | On a USB/IP server, devices can be listed, bound, and unbound using 10 | this program. On a USB/IP client, devices exported by USB/IP servers 11 | can be listed, attached and detached. 12 | 13 | .SH OPTIONS 14 | .HP 15 | \fB\-\-debug\fR 16 | .IP 17 | Print debugging information. 18 | .PP 19 | 20 | .HP 21 | \fB\-\-log\fR 22 | .IP 23 | Log to syslog. 24 | .PP 25 | 26 | .HP 27 | \fB\-\-tcp-port PORT\fR 28 | .IP 29 | Connect to PORT on remote host (used for attach and list --remote). 30 | .PP 31 | 32 | .SH COMMANDS 33 | .HP 34 | \fBversion\fR 35 | .IP 36 | Show version and exit. 37 | .PP 38 | 39 | .HP 40 | \fBhelp\fR [\fIcommand\fR] 41 | .IP 42 | Print the program help message, or help on a specific command, and 43 | then exit. 44 | .PP 45 | 46 | .HP 47 | \fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR> 48 | .IP 49 | Attach a remote USB device. 50 | .PP 51 | 52 | .HP 53 | \fBdetach\fR \-\-port=<\fIport\fR> 54 | .IP 55 | Detach an imported USB device. 56 | .PP 57 | 58 | .HP 59 | \fBbind\fR \-\-busid=<\fIbusid\fR> 60 | .IP 61 | Make a device exportable. 62 | .PP 63 | 64 | .HP 65 | \fBunbind\fR \-\-busid=<\fIbusid\fR> 66 | .IP 67 | Stop exporting a device so it can be used by a local driver. 68 | .PP 69 | 70 | .HP 71 | \fBlist\fR \-\-remote=<\fIhost\fR> 72 | .IP 73 | List USB devices exported by a remote host. 74 | .PP 75 | 76 | .HP 77 | \fBlist\fR \-\-local 78 | .IP 79 | List local USB devices. 80 | .PP 81 | 82 | 83 | .SH EXAMPLES 84 | 85 | client:# usbip list --remote=server 86 | - List exportable usb devices on the server. 87 | 88 | client:# usbip attach --remote=server --busid=1-2 89 | - Connect the remote USB device. 90 | 91 | client:# usbip detach --port=0 92 | - Detach the usb device. 93 | 94 | .SH "SEE ALSO" 95 | \fBusbipd\fP\fB(8)\fB\fP 96 | -------------------------------------------------------------------------------- /doc/usbipd.8: -------------------------------------------------------------------------------- 1 | .TH USBIP "8" "February 2009" "usbip" "System Administration Utilities" 2 | .SH NAME 3 | usbipd \- USB/IP server daemon 4 | .SH SYNOPSIS 5 | .B usbipd 6 | [\fIoptions\fR] 7 | 8 | .SH DESCRIPTION 9 | .B usbipd 10 | provides USB/IP clients access to exported USB devices. 11 | 12 | Devices have to explicitly be exported using 13 | .B usbip bind 14 | before usbipd makes them available to other hosts. 15 | 16 | The daemon accepts connections from USB/IP clients 17 | on TCP port 3240 by default. 18 | 19 | .SH OPTIONS 20 | .HP 21 | \fB\-4\fR, \fB\-\-ipv4\fR 22 | .IP 23 | Bind to IPv4. Default is both. 24 | .PP 25 | 26 | .HP 27 | \fB\-6\fR, \fB\-\-ipv6\fR 28 | .IP 29 | Bind to IPv6. Default is both. 30 | .PP 31 | 32 | .HP 33 | \fB\-D\fR, \fB\-\-daemon\fR 34 | .IP 35 | Run as a daemon process. 36 | .PP 37 | 38 | .HP 39 | \fB\-d\fR, \fB\-\-debug\fR 40 | .IP 41 | Print debugging information. 42 | .PP 43 | 44 | .HP 45 | \fB\-PFILE\fR, \fB\-\-pid FILE\fR 46 | .IP 47 | Write process id to FILE. 48 | .br 49 | If no FILE specified, use /var/run/usbipd.pid 50 | .PP 51 | 52 | \fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR 53 | .IP 54 | Listen on TCP/IP port PORT. 55 | .PP 56 | 57 | \fB\-h\fR, \fB\-\-help\fR 58 | .IP 59 | Print the program help message and exit. 60 | .PP 61 | 62 | .HP 63 | \fB\-v\fR, \fB\-\-version\fR 64 | .IP 65 | Show version. 66 | .PP 67 | 68 | .SH LIMITATIONS 69 | 70 | .B usbipd 71 | offers no authentication or authorization for USB/IP. Any 72 | USB/IP client can connect and use exported devices. 73 | 74 | .SH EXAMPLES 75 | 76 | server:# modprobe usbip 77 | 78 | server:# usbipd -D 79 | - Start usbip daemon. 80 | 81 | server:# usbip list --local 82 | - List driver assignments for usb devices. 83 | 84 | server:# usbip bind --busid=1-2 85 | - Bind usbip-host.ko to the device of busid 1-2. 86 | - A usb device 1-2 is now exportable to other hosts! 87 | - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally. 88 | 89 | .SH "SEE ALSO" 90 | \fBusbip\fP\fB(8)\fB\fP 91 | 92 | -------------------------------------------------------------------------------- /libsrc/usbip_host_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * Copyright (C) 2015-2016 Samsung Electronics 5 | * Igor Kotrasinski 6 | * Krzysztof Opasiak 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #include "usbip_host_common.h" 26 | #include "usbip_host_driver.h" 27 | 28 | #undef PROGNAME 29 | #define PROGNAME "libusbip" 30 | 31 | static int is_my_device(struct udev_device *dev) 32 | { 33 | const char *driver; 34 | 35 | driver = udev_device_get_driver(dev); 36 | return driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME); 37 | } 38 | 39 | static int usbip_host_driver_open(struct usbip_host_driver *hdriver) 40 | { 41 | int ret; 42 | 43 | hdriver->ndevs = 0; 44 | INIT_LIST_HEAD(&hdriver->edev_list); 45 | 46 | ret = usbip_generic_driver_open(hdriver); 47 | if (ret) 48 | err("please load " USBIP_CORE_MOD_NAME ".ko and " 49 | USBIP_HOST_DRV_NAME ".ko!"); 50 | return ret; 51 | } 52 | 53 | struct usbip_host_driver host_driver = { 54 | .edev_list = LIST_HEAD_INIT(host_driver.edev_list), 55 | .udev_subsystem = "usb", 56 | .ops = { 57 | .open = usbip_host_driver_open, 58 | .close = usbip_generic_driver_close, 59 | .refresh_device_list = usbip_generic_refresh_device_list, 60 | .get_device = usbip_generic_get_device, 61 | .read_device = read_usb_device, 62 | .read_interface = read_usb_interface, 63 | .is_my_device = is_my_device, 64 | }, 65 | }; 66 | -------------------------------------------------------------------------------- /src/usbip_detach.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include "vhci_driver.h" 30 | #include "usbip_common.h" 31 | #include "usbip_network.h" 32 | #include "usbip.h" 33 | 34 | static const char usbip_detach_usage_string[] = 35 | "usbip detach \n" 36 | " -p, --port= " USBIP_VHCI_DRV_NAME 37 | " port the device is on\n"; 38 | 39 | void usbip_detach_usage(void) 40 | { 41 | printf("usage: %s", usbip_detach_usage_string); 42 | } 43 | 44 | static int detach_port(char *port) 45 | { 46 | int ret; 47 | uint8_t portnum; 48 | char path[PATH_MAX+1]; 49 | 50 | unsigned int port_len = strlen(port); 51 | 52 | for (unsigned int i = 0; i < port_len; i++) 53 | if (!isdigit(port[i])) { 54 | err("invalid port %s", port); 55 | return -1; 56 | } 57 | 58 | /* check max port */ 59 | 60 | portnum = atoi(port); 61 | 62 | /* remove the port state file */ 63 | 64 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); 65 | 66 | remove(path); 67 | rmdir(VHCI_STATE_PATH); 68 | 69 | ret = usbip_vhci_driver_open(); 70 | if (ret < 0) { 71 | err("open vhci_driver"); 72 | return -1; 73 | } 74 | 75 | ret = usbip_vhci_detach_device(portnum); 76 | if (ret < 0) 77 | return -1; 78 | 79 | usbip_vhci_driver_close(); 80 | 81 | return ret; 82 | } 83 | 84 | int usbip_detach(int argc, char *argv[]) 85 | { 86 | static const struct option opts[] = { 87 | { "port", required_argument, NULL, 'p' }, 88 | { NULL, 0, NULL, 0 } 89 | }; 90 | int opt; 91 | int ret = -1; 92 | 93 | for (;;) { 94 | opt = getopt_long(argc, argv, "p:", opts, NULL); 95 | 96 | if (opt == -1) 97 | break; 98 | 99 | switch (opt) { 100 | case 'p': 101 | ret = detach_port(optarg); 102 | goto out; 103 | default: 104 | goto err_out; 105 | } 106 | } 107 | 108 | err_out: 109 | usbip_detach_usage(); 110 | out: 111 | return ret; 112 | } 113 | -------------------------------------------------------------------------------- /libsrc/usbip_host_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2016 Samsung Electronics 3 | * Igor Kotrasinski 4 | * Krzysztof Opasiak 5 | * 6 | * Refactored from usbip_host_driver.c, which is: 7 | * Copyright (C) 2011 matt mooney 8 | * 2005-2007 Takahiro Hirofuchi 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #ifndef __USBIP_HOST_COMMON_H 25 | #define __USBIP_HOST_COMMON_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include "list.h" 31 | #include "usbip_common.h" 32 | #include "sysfs_utils.h" 33 | 34 | struct usbip_host_driver; 35 | 36 | struct usbip_host_driver_ops { 37 | int (*open)(struct usbip_host_driver *hdriver); 38 | void (*close)(struct usbip_host_driver *hdriver); 39 | int (*refresh_device_list)(struct usbip_host_driver *hdriver); 40 | struct usbip_exported_device * (*get_device)( 41 | struct usbip_host_driver *hdriver, int num); 42 | 43 | int (*read_device)(struct udev_device *sdev, 44 | struct usbip_usb_device *dev); 45 | int (*read_interface)(struct usbip_usb_device *udev, int i, 46 | struct usbip_usb_interface *uinf); 47 | int (*is_my_device)(struct udev_device *udev); 48 | }; 49 | 50 | struct usbip_host_driver { 51 | int ndevs; 52 | /* list of exported device */ 53 | struct list_head edev_list; 54 | const char *udev_subsystem; 55 | struct usbip_host_driver_ops ops; 56 | }; 57 | 58 | struct usbip_exported_device { 59 | struct udev_device *sudev; 60 | int32_t status; 61 | struct usbip_usb_device udev; 62 | struct list_head node; 63 | struct usbip_usb_interface uinf[]; 64 | }; 65 | 66 | /* External API to access the driver */ 67 | static inline int usbip_driver_open(struct usbip_host_driver *hdriver) 68 | { 69 | if (!hdriver->ops.open) 70 | return -EOPNOTSUPP; 71 | return hdriver->ops.open(hdriver); 72 | } 73 | 74 | static inline void usbip_driver_close(struct usbip_host_driver *hdriver) 75 | { 76 | if (!hdriver->ops.close) 77 | return; 78 | hdriver->ops.close(hdriver); 79 | } 80 | 81 | static inline int usbip_refresh_device_list(struct usbip_host_driver *hdriver) 82 | { 83 | if (!hdriver->ops.refresh_device_list) 84 | return -EOPNOTSUPP; 85 | return hdriver->ops.refresh_device_list(hdriver); 86 | } 87 | 88 | static inline struct usbip_exported_device * 89 | usbip_get_device(struct usbip_host_driver *hdriver, int num) 90 | { 91 | if (!hdriver->ops.get_device) 92 | return NULL; 93 | return hdriver->ops.get_device(hdriver, num); 94 | } 95 | 96 | /* Helper functions for implementing driver backend */ 97 | int usbip_generic_driver_open(struct usbip_host_driver *hdriver); 98 | void usbip_generic_driver_close(struct usbip_host_driver *hdriver); 99 | int usbip_generic_refresh_device_list(struct usbip_host_driver *hdriver); 100 | int usbip_export_device(struct usbip_exported_device *edev, int sockfd); 101 | struct usbip_exported_device *usbip_generic_get_device( 102 | struct usbip_host_driver *hdriver, int num); 103 | 104 | #endif /* __USBIP_HOST_COMMON_H */ 105 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | 3 | AC_PREREQ(2.59) 4 | AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org]) 5 | AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number]) 6 | 7 | CURRENT=0 8 | REVISION=1 9 | AGE=0 10 | AC_SUBST([LIBUSBIP_VERSION], [$CURRENT:$REVISION:$AGE], [library version]) 11 | 12 | AC_CONFIG_SRCDIR([src/usbipd.c]) 13 | AC_CONFIG_HEADERS([config.h]) 14 | 15 | AM_INIT_AUTOMAKE([foreign]) 16 | LT_INIT 17 | 18 | # Silent build for automake >= 1.11 19 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 20 | 21 | AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu99"]) 22 | 23 | # Checks for programs. 24 | AC_PROG_CC 25 | AC_PROG_INSTALL 26 | AC_PROG_MAKE_SET 27 | 28 | # Checks for header files. 29 | AC_HEADER_DIRENT 30 | AC_HEADER_STDC 31 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl 32 | string.h sys/socket.h syslog.h unistd.h]) 33 | 34 | # Checks for typedefs, structures, and compiler characteristics. 35 | AC_TYPE_INT32_T 36 | AC_TYPE_SIZE_T 37 | AC_TYPE_SSIZE_T 38 | AC_TYPE_UINT16_T 39 | AC_TYPE_UINT32_T 40 | AC_TYPE_UINT8_T 41 | 42 | # Checks for library functions. 43 | AC_FUNC_REALLOC 44 | AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl 45 | strtoul]) 46 | 47 | AC_CHECK_HEADER([libudev.h], 48 | [AC_CHECK_LIB([udev], [udev_new], 49 | [LIBS="$LIBS -ludev"], 50 | [AC_MSG_ERROR([Missing udev library!])])], 51 | [AC_MSG_ERROR([Missing /usr/include/libudev.h])]) 52 | 53 | # Checks for libwrap library. 54 | AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library]) 55 | AC_ARG_WITH([tcp-wrappers], 56 | [AS_HELP_STRING([--with-tcp-wrappers], 57 | [use the libwrap (TCP wrappers) library])], 58 | dnl [ACTION-IF-GIVEN] 59 | [if test "$withval" = "yes"; then 60 | AC_MSG_RESULT([yes]) 61 | AC_MSG_CHECKING([for hosts_access in -lwrap]) 62 | saved_LIBS="$LIBS" 63 | LIBS="-lwrap $saved_LIBS" 64 | AC_TRY_LINK( 65 | [int hosts_access(); int allow_severity, deny_severity;], 66 | [hosts_access()], 67 | [AC_MSG_RESULT([yes]); 68 | AC_DEFINE([HAVE_LIBWRAP], [1], 69 | [use tcp wrapper]) wrap_LIB="-lwrap"], 70 | [AC_MSG_RESULT([not found]); exit 1]) 71 | else 72 | AC_MSG_RESULT([no]); 73 | fi], 74 | dnl [ACTION-IF-NOT-GIVEN] 75 | [AC_MSG_RESULT([(default)]) 76 | AC_MSG_CHECKING([for hosts_access in -lwrap]) 77 | saved_LIBS="$LIBS" 78 | LIBS="-lwrap $saved_LIBS" 79 | AC_TRY_LINK( 80 | [int hosts_access(); int allow_severity, deny_severity;], 81 | [hosts_access()], 82 | [AC_MSG_RESULT([yes]); 83 | AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])], 84 | [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])]) 85 | 86 | # Sets directory containing usb.ids. 87 | AC_ARG_WITH([usbids-dir], 88 | [AS_HELP_STRING([--with-usbids-dir=DIR], 89 | [where usb.ids is found (default /usr/share/hwdata/)])], 90 | [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"]) 91 | AC_SUBST([USBIDS_DIR]) 92 | 93 | # use _FORTIFY_SOURCE 94 | AC_MSG_CHECKING([whether to use fortify]) 95 | AC_ARG_WITH([fortify], 96 | [AS_HELP_STRING([--with-fortify], 97 | [use _FORTIFY_SROUCE option when compiling)])], 98 | dnl [ACTION-IF-GIVEN] 99 | [if test "$withval" = "yes"; then 100 | AC_MSG_RESULT([yes]) 101 | CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O" 102 | else 103 | AC_MSG_RESULT([no]) 104 | CFLAGS="$CFLAGS -U_FORTIFY_SOURCE" 105 | fi 106 | ], 107 | dnl [ACTION-IF-NOT-GIVEN] 108 | [AC_MSG_RESULT([default])]) 109 | 110 | AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile]) 111 | AC_OUTPUT 112 | -------------------------------------------------------------------------------- /libsrc/usbip_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef __USBIP_COMMON_H 6 | #define __USBIP_COMMON_H 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef USBIDS_FILE 21 | #define USBIDS_FILE "/system/etc/usb.ids" 22 | #endif 23 | 24 | #ifndef VHCI_STATE_PATH 25 | #define VHCI_STATE_PATH "/var/run/vhci_hcd" 26 | #endif 27 | 28 | #define VUDC_DEVICE_DESCR_FILE "dev_desc" 29 | 30 | /* kernel module names */ 31 | #define USBIP_CORE_MOD_NAME "usbip-core" 32 | #define USBIP_HOST_DRV_NAME "usbip-host" 33 | #define USBIP_DEVICE_DRV_NAME "usbip-vudc" 34 | #define USBIP_VHCI_DRV_NAME "vhci_hcd" 35 | 36 | /* sysfs constants */ 37 | #define SYSFS_MNT_PATH "/sys" 38 | #define SYSFS_BUS_NAME "bus" 39 | #define SYSFS_BUS_TYPE "usb" 40 | #define SYSFS_DRIVERS_NAME "drivers" 41 | 42 | #define SYSFS_PATH_MAX 256 43 | #define SYSFS_BUS_ID_SIZE 32 44 | 45 | extern int usbip_use_syslog; 46 | extern int usbip_use_stderr; 47 | extern int usbip_use_debug ; 48 | 49 | #define PROGNAME "usbip" 50 | 51 | #define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME 52 | #define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \ 53 | __FILE__, __LINE__, __func__ 54 | 55 | #define err(fmt, args...) \ 56 | do { \ 57 | if (usbip_use_syslog) { \ 58 | syslog(LOG_ERR, pr_fmt(fmt), "error", ##args); \ 59 | } \ 60 | if (usbip_use_stderr) { \ 61 | fprintf(stderr, pr_fmt(fmt), "error", ##args); \ 62 | } \ 63 | } while (0) 64 | 65 | #define info(fmt, args...) \ 66 | do { \ 67 | if (usbip_use_syslog) { \ 68 | syslog(LOG_INFO, pr_fmt(fmt), "info", ##args); \ 69 | } \ 70 | if (usbip_use_stderr) { \ 71 | fprintf(stderr, pr_fmt(fmt), "info", ##args); \ 72 | } \ 73 | } while (0) 74 | 75 | #define dbg(fmt, args...) \ 76 | do { \ 77 | if (usbip_use_debug) { \ 78 | if (usbip_use_syslog) { \ 79 | syslog(LOG_DEBUG, dbg_fmt(fmt), ##args); \ 80 | } \ 81 | if (usbip_use_stderr) { \ 82 | fprintf(stderr, dbg_fmt(fmt), ##args); \ 83 | } \ 84 | } \ 85 | } while (0) 86 | 87 | #define BUG() \ 88 | do { \ 89 | err("sorry, it's a bug!"); \ 90 | abort(); \ 91 | } while (0) 92 | 93 | struct usbip_usb_interface { 94 | uint8_t bInterfaceClass; 95 | uint8_t bInterfaceSubClass; 96 | uint8_t bInterfaceProtocol; 97 | uint8_t padding; /* alignment */ 98 | } __attribute__((packed)); 99 | 100 | struct usbip_usb_device { 101 | char path[SYSFS_PATH_MAX]; 102 | char busid[SYSFS_BUS_ID_SIZE]; 103 | 104 | uint32_t busnum; 105 | uint32_t devnum; 106 | uint32_t speed; 107 | 108 | uint16_t idVendor; 109 | uint16_t idProduct; 110 | uint16_t bcdDevice; 111 | 112 | uint8_t bDeviceClass; 113 | uint8_t bDeviceSubClass; 114 | uint8_t bDeviceProtocol; 115 | uint8_t bConfigurationValue; 116 | uint8_t bNumConfigurations; 117 | uint8_t bNumInterfaces; 118 | } __attribute__((packed)); 119 | 120 | #define to_string(s) #s 121 | 122 | void dump_usb_interface(struct usbip_usb_interface *); 123 | void dump_usb_device(struct usbip_usb_device *); 124 | int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev); 125 | int read_attr_value(struct udev_device *dev, const char *name, 126 | const char *format); 127 | int read_usb_interface(struct usbip_usb_device *udev, int i, 128 | struct usbip_usb_interface *uinf); 129 | 130 | const char *usbip_speed_string(int num); 131 | const char *usbip_status_string(int32_t status); 132 | 133 | int usbip_names_init(char *); 134 | void usbip_names_free(void); 135 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, 136 | uint16_t product); 137 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, 138 | uint8_t subclass, uint8_t protocol); 139 | 140 | #endif /* __USBIP_COMMON_H */ 141 | -------------------------------------------------------------------------------- /src/usbip_unbind.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "usbip_common.h" 28 | #include "utils.h" 29 | #include "usbip.h" 30 | #include "sysfs_utils.h" 31 | 32 | static const char usbip_unbind_usage_string[] = 33 | "usbip unbind \n" 34 | " -b, --busid= Unbind " USBIP_HOST_DRV_NAME ".ko from " 35 | "device on \n"; 36 | 37 | void usbip_unbind_usage(void) 38 | { 39 | printf("usage: %s", usbip_unbind_usage_string); 40 | } 41 | 42 | static int unbind_device(char *busid) 43 | { 44 | char bus_type[] = "usb"; 45 | int rc, ret = -1; 46 | 47 | char unbind_attr_name[] = "unbind"; 48 | char unbind_attr_path[SYSFS_PATH_MAX]; 49 | char rebind_attr_name[] = "rebind"; 50 | char rebind_attr_path[SYSFS_PATH_MAX]; 51 | 52 | struct udev *udev; 53 | struct udev_device *dev; 54 | const char *driver; 55 | 56 | /* Create libudev context. */ 57 | udev = udev_new(); 58 | 59 | /* Check whether the device with this bus ID exists. */ 60 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); 61 | if (!dev) { 62 | err("device with the specified bus ID does not exist"); 63 | goto err_close_udev; 64 | } 65 | 66 | /* Check whether the device is using usbip-host driver. */ 67 | driver = udev_device_get_driver(dev); 68 | if (!driver || strcmp(driver, "usbip-host")) { 69 | err("device is not bound to usbip-host driver"); 70 | goto err_close_udev; 71 | } 72 | 73 | /* Unbind device from driver. */ 74 | snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", 75 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, 76 | USBIP_HOST_DRV_NAME, unbind_attr_name); 77 | 78 | rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); 79 | if (rc < 0) { 80 | err("error unbinding device %s from driver", busid); 81 | goto err_close_udev; 82 | } 83 | 84 | /* Notify driver of unbind. */ 85 | rc = modify_match_busid(busid, 0); 86 | if (rc < 0) { 87 | err("unable to unbind device on %s", busid); 88 | goto err_close_udev; 89 | } 90 | 91 | /* Trigger new probing. */ 92 | snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", 93 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, 94 | USBIP_HOST_DRV_NAME, rebind_attr_name); 95 | 96 | rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid)); 97 | if (rc < 0) { 98 | err("error rebinding"); 99 | goto err_close_udev; 100 | } 101 | 102 | ret = 0; 103 | info("unbind device on busid %s: complete", busid); 104 | 105 | err_close_udev: 106 | udev_device_unref(dev); 107 | udev_unref(udev); 108 | 109 | return ret; 110 | } 111 | 112 | int usbip_unbind(int argc, char *argv[]) 113 | { 114 | static const struct option opts[] = { 115 | { "busid", required_argument, NULL, 'b' }, 116 | { NULL, 0, NULL, 0 } 117 | }; 118 | 119 | int opt; 120 | int ret = -1; 121 | 122 | for (;;) { 123 | opt = getopt_long(argc, argv, "b:", opts, NULL); 124 | 125 | if (opt == -1) 126 | break; 127 | 128 | switch (opt) { 129 | case 'b': 130 | ret = unbind_device(optarg); 131 | goto out; 132 | default: 133 | goto err_out; 134 | } 135 | } 136 | 137 | err_out: 138 | usbip_unbind_usage(); 139 | out: 140 | return ret; 141 | } 142 | -------------------------------------------------------------------------------- /libsrc/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIST_H 2 | #define _LIST_H 3 | 4 | /* Stripped down implementation of linked list taken 5 | * from the Linux Kernel. 6 | */ 7 | 8 | /* 9 | * Simple doubly linked list implementation. 10 | * 11 | * Some of the internal functions ("__xxx") are useful when 12 | * manipulating whole lists rather than single entries, as 13 | * sometimes we already know the next/prev entries and we can 14 | * generate better code by using them directly rather than 15 | * using the generic single-entry routines. 16 | */ 17 | 18 | struct list_head { 19 | struct list_head *next, *prev; 20 | }; 21 | 22 | #define LIST_HEAD_INIT(name) { &(name), &(name) } 23 | 24 | #define LIST_HEAD(name) \ 25 | struct list_head name = LIST_HEAD_INIT(name) 26 | 27 | static inline void INIT_LIST_HEAD(struct list_head *list) 28 | { 29 | list->next = list; 30 | list->prev = list; 31 | } 32 | 33 | /* 34 | * Insert a new entry between two known consecutive entries. 35 | * 36 | * This is only for internal list manipulation where we know 37 | * the prev/next entries already! 38 | */ 39 | static inline void __list_add(struct list_head *new, 40 | struct list_head *prev, 41 | struct list_head *next) 42 | { 43 | next->prev = new; 44 | new->next = next; 45 | new->prev = prev; 46 | prev->next = new; 47 | } 48 | 49 | /** 50 | * list_add - add a new entry 51 | * @new: new entry to be added 52 | * @head: list head to add it after 53 | * 54 | * Insert a new entry after the specified head. 55 | * This is good for implementing stacks. 56 | */ 57 | static inline void list_add(struct list_head *new, struct list_head *head) 58 | { 59 | __list_add(new, head, head->next); 60 | } 61 | 62 | /* 63 | * Delete a list entry by making the prev/next entries 64 | * point to each other. 65 | * 66 | * This is only for internal list manipulation where we know 67 | * the prev/next entries already! 68 | */ 69 | static inline void __list_del(struct list_head * prev, struct list_head * next) 70 | { 71 | next->prev = prev; 72 | prev->next = next; 73 | } 74 | 75 | #define POISON_POINTER_DELTA 0 76 | #define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) 77 | #define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) 78 | 79 | /** 80 | * list_del - deletes entry from list. 81 | * @entry: the element to delete from the list. 82 | * Note: list_empty() on entry does not return true after this, the entry is 83 | * in an undefined state. 84 | */ 85 | static inline void __list_del_entry(struct list_head *entry) 86 | { 87 | __list_del(entry->prev, entry->next); 88 | } 89 | 90 | static inline void list_del(struct list_head *entry) 91 | { 92 | __list_del(entry->prev, entry->next); 93 | entry->next = LIST_POISON1; 94 | entry->prev = LIST_POISON2; 95 | } 96 | 97 | /** 98 | * list_entry - get the struct for this entry 99 | * @ptr: the &struct list_head pointer. 100 | * @type: the type of the struct this is embedded in. 101 | * @member: the name of the list_head within the struct. 102 | */ 103 | #define list_entry(ptr, type, member) \ 104 | container_of(ptr, type, member) 105 | /** 106 | * list_for_each - iterate over a list 107 | * @pos: the &struct list_head to use as a loop cursor. 108 | * @head: the head for your list. 109 | */ 110 | #define list_for_each(pos, head) \ 111 | for (pos = (head)->next; pos != (head); pos = pos->next) 112 | 113 | /** 114 | * list_for_each_safe - iterate over a list safe against removal of list entry 115 | * @pos: the &struct list_head to use as a loop cursor. 116 | * @n: another &struct list_head to use as temporary storage 117 | * @head: the head for your list. 118 | */ 119 | #define list_for_each_safe(pos, n, head) \ 120 | for (pos = (head)->next, n = pos->next; pos != (head); \ 121 | pos = n, n = pos->next) 122 | 123 | //#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 124 | 125 | /** 126 | * container_of - cast a member of a structure out to the containing structure 127 | * @ptr: the pointer to the member. 128 | * @type: the type of the container struct this is embedded in. 129 | * @member: the name of the member within the struct. 130 | * 131 | */ 132 | #define container_of(ptr, type, member) ({ \ 133 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 134 | (type *)( (char *)__mptr - offsetof(type,member) );}) 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /libsrc/usbip_device_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Karol Kosik 3 | * 2015 Samsung Electronics 4 | * Author: Igor Kotrasinski 5 | * 6 | * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is: 7 | * Copyright (C) 2011 matt mooney 8 | * 2005-2007 Takahiro Hirofuchi 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include "usbip_host_common.h" 31 | #include "usbip_device_driver.h" 32 | 33 | #undef PROGNAME 34 | #define PROGNAME "libusbip" 35 | 36 | #define copy_descr_attr16(dev, descr, attr) \ 37 | ((dev)->attr = le16toh((descr)->attr)) \ 38 | 39 | #define copy_descr_attr(dev, descr, attr) \ 40 | ((dev)->attr = (descr)->attr) \ 41 | 42 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 43 | 44 | static struct { 45 | enum usb_device_speed speed; 46 | const char *name; 47 | } speed_names[] = { 48 | { 49 | .speed = USB_SPEED_UNKNOWN, 50 | .name = "UNKNOWN", 51 | }, 52 | { 53 | .speed = USB_SPEED_LOW, 54 | .name = "low-speed", 55 | }, 56 | { 57 | .speed = USB_SPEED_FULL, 58 | .name = "full-speed", 59 | }, 60 | { 61 | .speed = USB_SPEED_HIGH, 62 | .name = "high-speed", 63 | }, 64 | { 65 | .speed = USB_SPEED_WIRELESS, 66 | .name = "wireless", 67 | }, 68 | { 69 | .speed = USB_SPEED_SUPER, 70 | .name = "super-speed", 71 | }, 72 | }; 73 | 74 | static 75 | int read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev) 76 | { 77 | const char *path, *name; 78 | char filepath[SYSFS_PATH_MAX]; 79 | struct usb_device_descriptor descr; 80 | unsigned i; 81 | FILE *fd = NULL; 82 | struct udev_device *plat; 83 | const char *speed; 84 | int ret = 0; 85 | 86 | plat = udev_device_get_parent(sdev); 87 | path = udev_device_get_syspath(plat); 88 | snprintf(filepath, SYSFS_PATH_MAX, "%s/%s", 89 | path, VUDC_DEVICE_DESCR_FILE); 90 | fd = fopen(filepath, "r"); 91 | if (!fd) 92 | return -1; 93 | ret = fread((char *) &descr, sizeof(descr), 1, fd); 94 | if (ret < 0) 95 | return -1; 96 | fclose(fd); 97 | 98 | copy_descr_attr(dev, &descr, bDeviceClass); 99 | copy_descr_attr(dev, &descr, bDeviceSubClass); 100 | copy_descr_attr(dev, &descr, bDeviceProtocol); 101 | copy_descr_attr(dev, &descr, bNumConfigurations); 102 | copy_descr_attr16(dev, &descr, idVendor); 103 | copy_descr_attr16(dev, &descr, idProduct); 104 | copy_descr_attr16(dev, &descr, bcdDevice); 105 | 106 | strncpy(dev->path, path, SYSFS_PATH_MAX); 107 | 108 | dev->speed = USB_SPEED_UNKNOWN; 109 | speed = udev_device_get_sysattr_value(sdev, "current_speed"); 110 | if (speed) { 111 | for (i = 0; i < ARRAY_SIZE(speed_names); i++) { 112 | if (!strcmp(speed_names[i].name, speed)) { 113 | dev->speed = speed_names[i].speed; 114 | break; 115 | } 116 | } 117 | } 118 | 119 | /* Only used for user output, little sense to output them in general */ 120 | dev->bNumInterfaces = 0; 121 | dev->bConfigurationValue = 0; 122 | dev->busnum = 0; 123 | 124 | name = udev_device_get_sysname(plat); 125 | strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE); 126 | return 0; 127 | } 128 | 129 | static int is_my_device(struct udev_device *dev) 130 | { 131 | const char *driver; 132 | 133 | driver = udev_device_get_property_value(dev, "USB_UDC_NAME"); 134 | return driver != NULL && !strcmp(driver, USBIP_DEVICE_DRV_NAME); 135 | } 136 | 137 | static int usbip_device_driver_open(struct usbip_host_driver *hdriver) 138 | { 139 | int ret; 140 | 141 | hdriver->ndevs = 0; 142 | INIT_LIST_HEAD(&hdriver->edev_list); 143 | 144 | ret = usbip_generic_driver_open(hdriver); 145 | if (ret) 146 | err("please load " USBIP_CORE_MOD_NAME ".ko and " 147 | USBIP_DEVICE_DRV_NAME ".ko!"); 148 | 149 | return ret; 150 | } 151 | 152 | struct usbip_host_driver device_driver = { 153 | .edev_list = LIST_HEAD_INIT(device_driver.edev_list), 154 | .udev_subsystem = "udc", 155 | .ops = { 156 | .open = usbip_device_driver_open, 157 | .close = usbip_generic_driver_close, 158 | .refresh_device_list = usbip_generic_refresh_device_list, 159 | .get_device = usbip_generic_get_device, 160 | .read_device = read_usb_vudc_device, 161 | .is_my_device = is_my_device, 162 | }, 163 | }; 164 | -------------------------------------------------------------------------------- /src/usbip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * command structure borrowed from udev 3 | * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git) 4 | * 5 | * Copyright (C) 2011 matt mooney 6 | * 2005-2007 Takahiro Hirofuchi 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | #include "usbip_common.h" 29 | #include "usbip_network.h" 30 | #include "usbip.h" 31 | 32 | static int usbip_help(int argc, char *argv[]); 33 | static int usbip_version(int argc, char *argv[]); 34 | 35 | static const char usbip_version_string[] = PACKAGE_STRING; 36 | 37 | static const char usbip_usage_string[] = 38 | "usbip [--debug] [--log] [--tcp-port PORT] [version]\n" 39 | " [help] \n"; 40 | 41 | static void usbip_usage(void) 42 | { 43 | printf("usage: %s", usbip_usage_string); 44 | } 45 | 46 | struct command { 47 | const char *name; 48 | int (*fn)(int argc, char *argv[]); 49 | const char *help; 50 | void (*usage)(void); 51 | }; 52 | 53 | static const struct command cmds[] = { 54 | { 55 | .name = "help", 56 | .fn = usbip_help, 57 | .help = NULL, 58 | .usage = NULL 59 | }, 60 | { 61 | .name = "version", 62 | .fn = usbip_version, 63 | .help = NULL, 64 | .usage = NULL 65 | }, 66 | { 67 | .name = "attach", 68 | .fn = usbip_attach, 69 | .help = "Attach a remote USB device", 70 | .usage = usbip_attach_usage 71 | }, 72 | { 73 | .name = "detach", 74 | .fn = usbip_detach, 75 | .help = "Detach a remote USB device", 76 | .usage = usbip_detach_usage 77 | }, 78 | { 79 | .name = "list", 80 | .fn = usbip_list, 81 | .help = "List exportable or local USB devices", 82 | .usage = usbip_list_usage 83 | }, 84 | { 85 | .name = "bind", 86 | .fn = usbip_bind, 87 | .help = "Bind device to " USBIP_HOST_DRV_NAME ".ko", 88 | .usage = usbip_bind_usage 89 | }, 90 | { 91 | .name = "unbind", 92 | .fn = usbip_unbind, 93 | .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko", 94 | .usage = usbip_unbind_usage 95 | }, 96 | { 97 | .name = "port", 98 | .fn = usbip_port_show, 99 | .help = "Show imported USB devices", 100 | .usage = NULL 101 | }, 102 | { NULL, NULL, NULL, NULL } 103 | }; 104 | 105 | static int usbip_help(int argc, char *argv[]) 106 | { 107 | const struct command *cmd; 108 | int i; 109 | int ret = 0; 110 | 111 | if (argc > 1 && argv++) { 112 | for (i = 0; cmds[i].name != NULL; i++) 113 | if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) { 114 | cmds[i].usage(); 115 | goto done; 116 | } 117 | ret = -1; 118 | } 119 | 120 | usbip_usage(); 121 | printf("\n"); 122 | for (cmd = cmds; cmd->name != NULL; cmd++) 123 | if (cmd->help != NULL) 124 | printf(" %-10s %s\n", cmd->name, cmd->help); 125 | printf("\n"); 126 | done: 127 | return ret; 128 | } 129 | 130 | static int usbip_version(int argc, char *argv[]) 131 | { 132 | (void) argc; 133 | (void) argv; 134 | 135 | printf(PROGNAME " (%s)\n", usbip_version_string); 136 | return 0; 137 | } 138 | 139 | static int run_command(const struct command *cmd, int argc, char *argv[]) 140 | { 141 | dbg("running command: `%s'", cmd->name); 142 | return cmd->fn(argc, argv); 143 | } 144 | 145 | int main(int argc, char *argv[]) 146 | { 147 | static const struct option opts[] = { 148 | { "debug", no_argument, NULL, 'd' }, 149 | { "log", no_argument, NULL, 'l' }, 150 | { "tcp-port", required_argument, NULL, 't' }, 151 | { NULL, 0, NULL, 0 } 152 | }; 153 | 154 | char *cmd; 155 | int opt; 156 | int i, rc = -1; 157 | 158 | usbip_use_stderr = 1; 159 | opterr = 0; 160 | for (;;) { 161 | opt = getopt_long(argc, argv, "+dlt:", opts, NULL); 162 | 163 | if (opt == -1) 164 | break; 165 | 166 | switch (opt) { 167 | case 'd': 168 | usbip_use_debug = 1; 169 | break; 170 | case 'l': 171 | usbip_use_syslog = 1; 172 | openlog("", LOG_PID, LOG_USER); 173 | break; 174 | case 't': 175 | usbip_setup_port_number(optarg); 176 | break; 177 | case '?': 178 | printf("usbip: invalid option\n"); 179 | default: 180 | usbip_usage(); 181 | goto out; 182 | } 183 | } 184 | 185 | cmd = argv[optind]; 186 | if (cmd) { 187 | for (i = 0; cmds[i].name != NULL; i++) 188 | if (!strcmp(cmds[i].name, cmd)) { 189 | argc -= optind; 190 | argv += optind; 191 | optind = 0; 192 | rc = run_command(&cmds[i], argc, argv); 193 | goto out; 194 | } 195 | } 196 | 197 | /* invalid command */ 198 | usbip_help(0, NULL); 199 | out: 200 | return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE); 201 | } 202 | -------------------------------------------------------------------------------- /src/usbip_bind.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #include "usbip_common.h" 29 | #include "utils.h" 30 | #include "usbip.h" 31 | #include "sysfs_utils.h" 32 | 33 | enum unbind_status { 34 | UNBIND_ST_OK, 35 | UNBIND_ST_USBIP_HOST, 36 | UNBIND_ST_FAILED 37 | }; 38 | 39 | static const char usbip_bind_usage_string[] = 40 | "usbip bind \n" 41 | " -b, --busid= Bind " USBIP_HOST_DRV_NAME ".ko to device " 42 | "on \n"; 43 | 44 | void usbip_bind_usage(void) 45 | { 46 | printf("usage: %s", usbip_bind_usage_string); 47 | } 48 | 49 | /* call at unbound state */ 50 | static int bind_usbip(char *busid) 51 | { 52 | char attr_name[] = "bind"; 53 | char bind_attr_path[SYSFS_PATH_MAX]; 54 | int rc = -1; 55 | 56 | snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s", 57 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, 58 | SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); 59 | 60 | rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid)); 61 | if (rc < 0) { 62 | err("error binding device %s to driver: %s", busid, 63 | strerror(errno)); 64 | return -1; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | /* buggy driver may cause dead lock */ 71 | static int unbind_other(char *busid) 72 | { 73 | enum unbind_status status = UNBIND_ST_OK; 74 | 75 | char attr_name[] = "unbind"; 76 | char unbind_attr_path[SYSFS_PATH_MAX]; 77 | int rc = -1; 78 | 79 | struct udev *udev; 80 | struct udev_device *dev; 81 | const char *driver; 82 | const char *bDevClass; 83 | 84 | /* Create libudev context. */ 85 | udev = udev_new(); 86 | 87 | /* Get the device. */ 88 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); 89 | if (!dev) { 90 | dbg("unable to find device with bus ID %s", busid); 91 | goto err_close_busid_dev; 92 | } 93 | 94 | /* Check what kind of device it is. */ 95 | bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass"); 96 | if (!bDevClass) { 97 | dbg("unable to get bDevClass device attribute"); 98 | goto err_close_busid_dev; 99 | } 100 | 101 | if (!strncmp(bDevClass, "09", strlen(bDevClass))) { 102 | dbg("skip unbinding of hub"); 103 | goto err_close_busid_dev; 104 | } 105 | 106 | /* Get the device driver. */ 107 | driver = udev_device_get_driver(dev); 108 | if (!driver) { 109 | /* No driver bound to this device. */ 110 | goto out; 111 | } 112 | 113 | if (!strncmp(USBIP_HOST_DRV_NAME, driver, 114 | strlen(USBIP_HOST_DRV_NAME))) { 115 | /* Already bound to usbip-host. */ 116 | status = UNBIND_ST_USBIP_HOST; 117 | goto out; 118 | } 119 | 120 | /* Unbind device from driver. */ 121 | snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", 122 | SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, 123 | SYSFS_DRIVERS_NAME, driver, attr_name); 124 | 125 | rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); 126 | if (rc < 0) { 127 | err("error unbinding device %s from driver", busid); 128 | goto err_close_busid_dev; 129 | } 130 | 131 | goto out; 132 | 133 | err_close_busid_dev: 134 | status = UNBIND_ST_FAILED; 135 | out: 136 | udev_device_unref(dev); 137 | udev_unref(udev); 138 | 139 | return status; 140 | } 141 | 142 | static int bind_device(char *busid) 143 | { 144 | int rc; 145 | struct udev *udev; 146 | struct udev_device *dev; 147 | 148 | /* Check whether the device with this bus ID exists. */ 149 | udev = udev_new(); 150 | dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); 151 | if (!dev) { 152 | err("device with the specified bus ID does not exist"); 153 | return -1; 154 | } 155 | udev_unref(udev); 156 | 157 | rc = unbind_other(busid); 158 | if (rc == UNBIND_ST_FAILED) { 159 | err("could not unbind driver from device on busid %s", busid); 160 | return -1; 161 | } else if (rc == UNBIND_ST_USBIP_HOST) { 162 | err("device on busid %s is already bound to %s", busid, 163 | USBIP_HOST_DRV_NAME); 164 | return -1; 165 | } 166 | 167 | rc = modify_match_busid(busid, 1); 168 | if (rc < 0) { 169 | err("unable to bind device on %s", busid); 170 | return -1; 171 | } 172 | 173 | rc = bind_usbip(busid); 174 | if (rc < 0) { 175 | err("could not bind device to %s", USBIP_HOST_DRV_NAME); 176 | modify_match_busid(busid, 0); 177 | return -1; 178 | } 179 | 180 | info("bind device on busid %s: complete", busid); 181 | 182 | return 0; 183 | } 184 | 185 | int usbip_bind(int argc, char *argv[]) 186 | { 187 | static const struct option opts[] = { 188 | { "busid", required_argument, NULL, 'b' }, 189 | { NULL, 0, NULL, 0 } 190 | }; 191 | 192 | int opt; 193 | int ret = -1; 194 | 195 | for (;;) { 196 | opt = getopt_long(argc, argv, "b:", opts, NULL); 197 | 198 | if (opt == -1) 199 | break; 200 | 201 | switch (opt) { 202 | case 'b': 203 | ret = bind_device(optarg); 204 | goto out; 205 | default: 206 | goto err_out; 207 | } 208 | } 209 | 210 | err_out: 211 | usbip_bind_usage(); 212 | out: 213 | return ret; 214 | } 215 | -------------------------------------------------------------------------------- /src/usbip_network.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #ifndef __USBIP_NETWORK_H 6 | #define __USBIP_NETWORK_H 7 | 8 | #ifdef HAVE_CONFIG_H 9 | #include "../config.h" 10 | #endif 11 | 12 | #include 13 | 14 | #include 15 | 16 | extern int usbip_port; 17 | extern char *usbip_port_string; 18 | void usbip_setup_port_number(char *arg); 19 | 20 | /* ---------------------------------------------------------------------- */ 21 | /* Common header for all the kinds of PDUs. */ 22 | struct op_common { 23 | uint16_t version; 24 | 25 | #define OP_REQUEST (0x80 << 8) 26 | #define OP_REPLY (0x00 << 8) 27 | uint16_t code; 28 | 29 | /* add more error code */ 30 | #define ST_OK 0x00 31 | #define ST_NA 0x01 32 | uint32_t status; /* op_code status (for reply) */ 33 | 34 | } __attribute__((packed)); 35 | 36 | #define PACK_OP_COMMON(pack, op_common) do {\ 37 | usbip_net_pack_uint16_t(pack, &(op_common)->version);\ 38 | usbip_net_pack_uint16_t(pack, &(op_common)->code);\ 39 | usbip_net_pack_uint32_t(pack, &(op_common)->status);\ 40 | } while (0) 41 | 42 | /* ---------------------------------------------------------------------- */ 43 | /* Dummy Code */ 44 | #define OP_UNSPEC 0x00 45 | #define OP_REQ_UNSPEC OP_UNSPEC 46 | #define OP_REP_UNSPEC OP_UNSPEC 47 | 48 | /* ---------------------------------------------------------------------- */ 49 | /* Retrieve USB device information. (still not used) */ 50 | #define OP_DEVINFO 0x02 51 | #define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO) 52 | #define OP_REP_DEVINFO (OP_REPLY | OP_DEVINFO) 53 | 54 | struct op_devinfo_request { 55 | char busid[SYSFS_BUS_ID_SIZE]; 56 | } __attribute__((packed)); 57 | 58 | struct op_devinfo_reply { 59 | struct usbip_usb_device udev; 60 | struct usbip_usb_interface uinf[]; 61 | } __attribute__((packed)); 62 | 63 | /* ---------------------------------------------------------------------- */ 64 | /* Import a remote USB device. */ 65 | #define OP_IMPORT 0x03 66 | #define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT) 67 | #define OP_REP_IMPORT (OP_REPLY | OP_IMPORT) 68 | 69 | struct op_import_request { 70 | char busid[SYSFS_BUS_ID_SIZE]; 71 | } __attribute__((packed)); 72 | 73 | struct op_import_reply { 74 | struct usbip_usb_device udev; 75 | // struct usbip_usb_interface uinf[]; 76 | } __attribute__((packed)); 77 | 78 | #define PACK_OP_IMPORT_REQUEST(pack, request) do {\ 79 | } while (0) 80 | 81 | #define PACK_OP_IMPORT_REPLY(pack, reply) do {\ 82 | usbip_net_pack_usb_device(pack, &(reply)->udev);\ 83 | } while (0) 84 | 85 | /* ---------------------------------------------------------------------- */ 86 | /* Export a USB device to a remote host. */ 87 | #define OP_EXPORT 0x06 88 | #define OP_REQ_EXPORT (OP_REQUEST | OP_EXPORT) 89 | #define OP_REP_EXPORT (OP_REPLY | OP_EXPORT) 90 | 91 | struct op_export_request { 92 | struct usbip_usb_device udev; 93 | } __attribute__((packed)); 94 | 95 | struct op_export_reply { 96 | int returncode; 97 | } __attribute__((packed)); 98 | 99 | 100 | #define PACK_OP_EXPORT_REQUEST(pack, request) do {\ 101 | usbip_net_pack_usb_device(pack, &(request)->udev);\ 102 | } while (0) 103 | 104 | #define PACK_OP_EXPORT_REPLY(pack, reply) do {\ 105 | } while (0) 106 | 107 | /* ---------------------------------------------------------------------- */ 108 | /* un-Export a USB device from a remote host. */ 109 | #define OP_UNEXPORT 0x07 110 | #define OP_REQ_UNEXPORT (OP_REQUEST | OP_UNEXPORT) 111 | #define OP_REP_UNEXPORT (OP_REPLY | OP_UNEXPORT) 112 | 113 | struct op_unexport_request { 114 | struct usbip_usb_device udev; 115 | } __attribute__((packed)); 116 | 117 | struct op_unexport_reply { 118 | int returncode; 119 | } __attribute__((packed)); 120 | 121 | #define PACK_OP_UNEXPORT_REQUEST(pack, request) do {\ 122 | usbip_net_pack_usb_device(pack, &(request)->udev);\ 123 | } while (0) 124 | 125 | #define PACK_OP_UNEXPORT_REPLY(pack, reply) do {\ 126 | } while (0) 127 | 128 | /* ---------------------------------------------------------------------- */ 129 | /* Negotiate IPSec encryption key. (still not used) */ 130 | #define OP_CRYPKEY 0x04 131 | #define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY) 132 | #define OP_REP_CRYPKEY (OP_REPLY | OP_CRYPKEY) 133 | 134 | struct op_crypkey_request { 135 | /* 128bit key */ 136 | uint32_t key[4]; 137 | } __attribute__((packed)); 138 | 139 | struct op_crypkey_reply { 140 | uint32_t __reserved; 141 | } __attribute__((packed)); 142 | 143 | 144 | /* ---------------------------------------------------------------------- */ 145 | /* Retrieve the list of exported USB devices. */ 146 | #define OP_DEVLIST 0x05 147 | #define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST) 148 | #define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST) 149 | 150 | struct op_devlist_request { 151 | } __attribute__((packed)); 152 | 153 | struct op_devlist_reply { 154 | uint32_t ndev; 155 | /* followed by reply_extra[] */ 156 | } __attribute__((packed)); 157 | 158 | struct op_devlist_reply_extra { 159 | struct usbip_usb_device udev; 160 | struct usbip_usb_interface uinf[]; 161 | } __attribute__((packed)); 162 | 163 | #define PACK_OP_DEVLIST_REQUEST(pack, request) do {\ 164 | } while (0) 165 | 166 | #define PACK_OP_DEVLIST_REPLY(pack, reply) do {\ 167 | usbip_net_pack_uint32_t(pack, &(reply)->ndev);\ 168 | } while (0) 169 | 170 | void usbip_net_pack_uint32_t(int pack, uint32_t *num); 171 | void usbip_net_pack_uint16_t(int pack, uint16_t *num); 172 | void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev); 173 | void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf); 174 | 175 | ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen); 176 | ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen); 177 | int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status); 178 | int usbip_net_recv_op_common(int sockfd, uint16_t *code); 179 | int usbip_net_set_reuseaddr(int sockfd); 180 | int usbip_net_set_nodelay(int sockfd); 181 | int usbip_net_set_keepalive(int sockfd); 182 | int usbip_net_set_v6only(int sockfd); 183 | int usbip_net_tcp_connect(char *hostname, char *port); 184 | 185 | #endif /* __USBIP_NETWORK_H */ 186 | -------------------------------------------------------------------------------- /src/usbip_attach.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * Copyright (C) 2015-2016 Samsung Electronics 5 | * Igor Kotrasinski 6 | * Krzysztof Opasiak 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "vhci_driver.h" 35 | #include "usbip_common.h" 36 | #include "usbip_network.h" 37 | #include "usbip.h" 38 | 39 | static const char usbip_attach_usage_string[] = 40 | "usbip attach \n" 41 | " -r, --remote= The machine with exported USB devices\n" 42 | " -b, --busid= Busid of the device on \n" 43 | " -d, --device= Id of the virtual UDC on \n"; 44 | 45 | void usbip_attach_usage(void) 46 | { 47 | printf("usage: %s", usbip_attach_usage_string); 48 | } 49 | 50 | #define MAX_BUFF 100 51 | static int record_connection(char *host, char *port, char *busid, int rhport) 52 | { 53 | int fd; 54 | char path[PATH_MAX+1]; 55 | char buff[MAX_BUFF+1]; 56 | int ret; 57 | 58 | ret = mkdir(VHCI_STATE_PATH, 0700); 59 | if (ret < 0) { 60 | /* if VHCI_STATE_PATH exists, then it better be a directory */ 61 | if (errno == EEXIST) { 62 | struct stat s; 63 | 64 | ret = stat(VHCI_STATE_PATH, &s); 65 | if (ret < 0) 66 | return -1; 67 | if (!(s.st_mode & S_IFDIR)) 68 | return -1; 69 | } else 70 | return -1; 71 | } 72 | 73 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); 74 | 75 | fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU); 76 | if (fd < 0) 77 | return -1; 78 | 79 | snprintf(buff, MAX_BUFF, "%s %s %s\n", 80 | host, port, busid); 81 | 82 | ret = write(fd, buff, strlen(buff)); 83 | if (ret != (ssize_t) strlen(buff)) { 84 | close(fd); 85 | return -1; 86 | } 87 | 88 | close(fd); 89 | 90 | return 0; 91 | } 92 | 93 | static int import_device(int sockfd, struct usbip_usb_device *udev) 94 | { 95 | int rc; 96 | int port; 97 | 98 | rc = usbip_vhci_driver_open(); 99 | if (rc < 0) { 100 | err("open vhci_driver"); 101 | return -1; 102 | } 103 | 104 | port = usbip_vhci_get_free_port(); 105 | if (port < 0) { 106 | err("no free port"); 107 | usbip_vhci_driver_close(); 108 | return -1; 109 | } 110 | 111 | rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, 112 | udev->devnum, udev->speed); 113 | if (rc < 0) { 114 | err("import device"); 115 | usbip_vhci_driver_close(); 116 | return -1; 117 | } 118 | 119 | usbip_vhci_driver_close(); 120 | 121 | return port; 122 | } 123 | 124 | static int query_import_device(int sockfd, char *busid) 125 | { 126 | int rc; 127 | struct op_import_request request; 128 | struct op_import_reply reply; 129 | uint16_t code = OP_REP_IMPORT; 130 | 131 | memset(&request, 0, sizeof(request)); 132 | memset(&reply, 0, sizeof(reply)); 133 | 134 | /* send a request */ 135 | rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0); 136 | if (rc < 0) { 137 | err("send op_common"); 138 | return -1; 139 | } 140 | 141 | strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); 142 | 143 | PACK_OP_IMPORT_REQUEST(0, &request); 144 | 145 | rc = usbip_net_send(sockfd, (void *) &request, sizeof(request)); 146 | if (rc < 0) { 147 | err("send op_import_request"); 148 | return -1; 149 | } 150 | 151 | /* receive a reply */ 152 | rc = usbip_net_recv_op_common(sockfd, &code); 153 | if (rc < 0) { 154 | err("recv op_common"); 155 | return -1; 156 | } 157 | 158 | rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply)); 159 | if (rc < 0) { 160 | err("recv op_import_reply"); 161 | return -1; 162 | } 163 | 164 | PACK_OP_IMPORT_REPLY(0, &reply); 165 | 166 | /* check the reply */ 167 | if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { 168 | err("recv different busid %s", reply.udev.busid); 169 | return -1; 170 | } 171 | 172 | /* import a device */ 173 | return import_device(sockfd, &reply.udev); 174 | } 175 | 176 | static int attach_device(char *host, char *busid) 177 | { 178 | int sockfd; 179 | int rc; 180 | int rhport; 181 | 182 | sockfd = usbip_net_tcp_connect(host, usbip_port_string); 183 | if (sockfd < 0) { 184 | err("tcp connect"); 185 | return -1; 186 | } 187 | 188 | rhport = query_import_device(sockfd, busid); 189 | if (rhport < 0) { 190 | err("query"); 191 | return -1; 192 | } 193 | 194 | close(sockfd); 195 | 196 | rc = record_connection(host, usbip_port_string, busid, rhport); 197 | if (rc < 0) { 198 | err("record connection"); 199 | return -1; 200 | } 201 | 202 | return 0; 203 | } 204 | 205 | int usbip_attach(int argc, char *argv[]) 206 | { 207 | static const struct option opts[] = { 208 | { "remote", required_argument, NULL, 'r' }, 209 | { "busid", required_argument, NULL, 'b' }, 210 | { "device", required_argument, NULL, 'd' }, 211 | { NULL, 0, NULL, 0 } 212 | }; 213 | char *host = NULL; 214 | char *busid = NULL; 215 | int opt; 216 | int ret = -1; 217 | 218 | for (;;) { 219 | opt = getopt_long(argc, argv, "d:r:b:", opts, NULL); 220 | 221 | if (opt == -1) 222 | break; 223 | 224 | switch (opt) { 225 | case 'r': 226 | host = optarg; 227 | break; 228 | case 'd': 229 | case 'b': 230 | busid = optarg; 231 | break; 232 | default: 233 | goto err_out; 234 | } 235 | } 236 | 237 | if (!host || !busid) 238 | goto err_out; 239 | 240 | ret = attach_device(host, busid); 241 | goto out; 242 | 243 | err_out: 244 | usbip_attach_usage(); 245 | out: 246 | return ret; 247 | } 248 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | # 2 | # README for usbip-utils 3 | # 4 | # Copyright (C) 2011 matt mooney 5 | # 2005-2008 Takahiro Hirofuchi 6 | 7 | 8 | [Requirements] 9 | - USB/IP device drivers 10 | Found in the staging directory of the Linux kernel. 11 | 12 | - libudev >= 2.0 13 | libudev library 14 | 15 | - libwrap0-dev 16 | tcp wrapper library 17 | 18 | - gcc >= 4.0 19 | 20 | - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config 21 | 22 | [Optional] 23 | - hwdata 24 | Contains USB device identification data. 25 | 26 | 27 | [Install] 28 | 0. Generate configuration scripts. 29 | $ ./autogen.sh 30 | 31 | 1. Compile & install the userspace utilities. 32 | $ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=] 33 | $ make install 34 | 35 | 2. Compile & install USB/IP drivers. 36 | 37 | 38 | [Usage] 39 | server:# (Physically attach your USB device.) 40 | 41 | server:# insmod usbip-core.ko 42 | server:# insmod usbip-host.ko 43 | 44 | server:# usbipd -D 45 | - Start usbip daemon. 46 | 47 | server:# usbip list -l 48 | - List driver assignments for USB devices. 49 | 50 | server:# usbip bind --busid 1-2 51 | - Bind usbip-host.ko to the device with busid 1-2. 52 | - The USB device 1-2 is now exportable to other hosts! 53 | - Use `usbip unbind --busid 1-2' to stop exporting the device. 54 | 55 | client:# insmod usbip-core.ko 56 | client:# insmod vhci-hcd.ko 57 | 58 | client:# usbip list --remote 59 | - List exported USB devices on the . 60 | 61 | client:# usbip attach --remote --busid 1-2 62 | - Connect the remote USB device. 63 | 64 | client:# usbip port 65 | - Show virtual port status. 66 | 67 | client:# usbip detach --port 68 | - Detach the USB device. 69 | 70 | 71 | [Example] 72 | --------------------------- 73 | SERVER SIDE 74 | --------------------------- 75 | Physically attach your USB devices to this host. 76 | 77 | trois:# insmod path/to/usbip-core.ko 78 | trois:# insmod path/to/usbip-host.ko 79 | trois:# usbipd -D 80 | 81 | In another terminal, let's look up what USB devices are physically 82 | attached to this host. 83 | 84 | trois:# usbip list -l 85 | Local USB devices 86 | ================= 87 | - busid 1-1 (05a9:a511) 88 | 1-1:1.0 -> ov511 89 | 90 | - busid 3-2 (0711:0902) 91 | 3-2:1.0 -> none 92 | 93 | - busid 3-3.1 (08bb:2702) 94 | 3-3.1:1.0 -> snd-usb-audio 95 | 3-3.1:1.1 -> snd-usb-audio 96 | 97 | - busid 3-3.2 (04bb:0206) 98 | 3-3.2:1.0 -> usb-storage 99 | 100 | - busid 3-3 (0409:0058) 101 | 3-3:1.0 -> hub 102 | 103 | - busid 4-1 (046d:08b2) 104 | 4-1:1.0 -> none 105 | 4-1:1.1 -> none 106 | 4-1:1.2 -> none 107 | 108 | - busid 5-2 (058f:9254) 109 | 5-2:1.0 -> hub 110 | 111 | A USB storage device of busid 3-3.2 is now bound to the usb-storage 112 | driver. To export this device, we first mark the device as 113 | "exportable"; the device is bound to the usbip-host driver. Please 114 | remember you can not export a USB hub. 115 | 116 | Mark the device of busid 3-3.2 as exportable: 117 | 118 | trois:# usbip --debug bind --busid 3-3.2 119 | ... 120 | usbip debug: usbip_bind.c:162:[unbind_other] 3-3.2:1.0 -> usb-storage 121 | ... 122 | bind device on busid 3-3.2: complete 123 | 124 | trois:# usbip list -l 125 | Local USB devices 126 | ================= 127 | ... 128 | 129 | - busid 3-3.2 (04bb:0206) 130 | 3-3.2:1.0 -> usbip-host 131 | ... 132 | 133 | --------------------------- 134 | CLIENT SIDE 135 | --------------------------- 136 | First, let's list available remote devices that are marked as 137 | exportable on the host. 138 | 139 | deux:# insmod path/to/usbip-core.ko 140 | deux:# insmod path/to/vhci-hcd.ko 141 | 142 | deux:# usbip list --remote 10.0.0.3 143 | Exportable USB devices 144 | ====================== 145 | - 10.0.0.3 146 | 1-1: Prolific Technology, Inc. : unknown product (067b:3507) 147 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1 148 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 149 | : 0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50) 150 | 151 | 1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203) 152 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1 153 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 154 | : 0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01) 155 | 156 | 1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511) 157 | : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3 158 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 159 | : 0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00) 160 | 161 | 3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2) 162 | : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1 163 | : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00) 164 | : 0 - Data / unknown subclass / unknown protocol (0a/ff/00) 165 | : 1 - Audio / Control Device / unknown protocol (01/01/00) 166 | : 2 - Audio / Streaming / unknown protocol (01/02/00) 167 | 168 | Attach a remote USB device: 169 | 170 | deux:# usbip attach --remote 10.0.0.3 --busid 1-1 171 | port 0 attached 172 | 173 | Show the devices attached to this client: 174 | 175 | deux:# usbip port 176 | Port 00: at Full Speed(12Mbps) 177 | Prolific Technology, Inc. : unknown product (067b:3507) 178 | 6-1 -> usbip://10.0.0.3:3240/1-1 (remote bus/dev 001/004) 179 | 6-1:1.0 used by usb-storage 180 | /sys/class/scsi_device/0:0:0:0/device 181 | /sys/class/scsi_host/host0/device 182 | /sys/block/sda/device 183 | 184 | Detach the imported device: 185 | 186 | deux:# usbip detach --port 0 187 | port 0 detached 188 | 189 | 190 | [Checklist] 191 | - See 'Debug Tips' on the project wiki. 192 | - http://usbip.wiki.sourceforge.net/how-to-debug-usbip 193 | - usbip-host.ko must be bound to the target device. 194 | - See /proc/bus/usb/devices and find "Driver=..." lines of the device. 195 | - Shutdown firewall. 196 | - usbip now uses TCP port 3240. 197 | - Disable SELinux. 198 | - Check the kernel and daemon messages. 199 | 200 | 201 | [Contact] 202 | Mailing List: linux-usb@vger.kernel.org 203 | -------------------------------------------------------------------------------- /src/usbip_network.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef HAVE_LIBWRAP 29 | #include 30 | #endif 31 | 32 | #include "usbip_common.h" 33 | #include "usbip_network.h" 34 | 35 | int usbip_port = 3240; 36 | char *usbip_port_string = "3240"; 37 | 38 | void usbip_setup_port_number(char *arg) 39 | { 40 | dbg("parsing port arg '%s'", arg); 41 | char *end; 42 | unsigned long int port = strtoul(arg, &end, 10); 43 | 44 | if (end == arg) { 45 | err("port: could not parse '%s' as a decimal integer", arg); 46 | return; 47 | } 48 | 49 | if (*end != '\0') { 50 | err("port: garbage at end of '%s'", arg); 51 | return; 52 | } 53 | 54 | if (port > UINT16_MAX) { 55 | err("port: %s too high (max=%d)", 56 | arg, UINT16_MAX); 57 | return; 58 | } 59 | 60 | usbip_port = port; 61 | usbip_port_string = arg; 62 | info("using port %d (\"%s\")", usbip_port, usbip_port_string); 63 | } 64 | 65 | void usbip_net_pack_uint32_t(int pack, uint32_t *num) 66 | { 67 | uint32_t i; 68 | 69 | if (pack) 70 | i = htonl(*num); 71 | else 72 | i = ntohl(*num); 73 | 74 | *num = i; 75 | } 76 | 77 | void usbip_net_pack_uint16_t(int pack, uint16_t *num) 78 | { 79 | uint16_t i; 80 | 81 | if (pack) 82 | i = htons(*num); 83 | else 84 | i = ntohs(*num); 85 | 86 | *num = i; 87 | } 88 | 89 | void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) 90 | { 91 | usbip_net_pack_uint32_t(pack, &udev->busnum); 92 | usbip_net_pack_uint32_t(pack, &udev->devnum); 93 | usbip_net_pack_uint32_t(pack, &udev->speed); 94 | 95 | usbip_net_pack_uint16_t(pack, &udev->idVendor); 96 | usbip_net_pack_uint16_t(pack, &udev->idProduct); 97 | usbip_net_pack_uint16_t(pack, &udev->bcdDevice); 98 | } 99 | 100 | void usbip_net_pack_usb_interface(int pack __attribute__((unused)), 101 | struct usbip_usb_interface *udev 102 | __attribute__((unused))) 103 | { 104 | /* uint8_t members need nothing */ 105 | } 106 | 107 | static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen, 108 | int sending) 109 | { 110 | ssize_t nbytes; 111 | ssize_t total = 0; 112 | 113 | if (!bufflen) 114 | return 0; 115 | 116 | do { 117 | if (sending) 118 | nbytes = send(sockfd, buff, bufflen, 0); 119 | else 120 | nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL); 121 | 122 | if (nbytes <= 0) 123 | return -1; 124 | 125 | buff = (void *)((intptr_t) buff + nbytes); 126 | bufflen -= nbytes; 127 | total += nbytes; 128 | 129 | } while (bufflen > 0); 130 | 131 | return total; 132 | } 133 | 134 | ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen) 135 | { 136 | return usbip_net_xmit(sockfd, buff, bufflen, 0); 137 | } 138 | 139 | ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen) 140 | { 141 | return usbip_net_xmit(sockfd, buff, bufflen, 1); 142 | } 143 | 144 | int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status) 145 | { 146 | struct op_common op_common; 147 | int rc; 148 | 149 | memset(&op_common, 0, sizeof(op_common)); 150 | 151 | op_common.version = USBIP_VERSION; 152 | op_common.code = code; 153 | op_common.status = status; 154 | 155 | PACK_OP_COMMON(1, &op_common); 156 | 157 | rc = usbip_net_send(sockfd, &op_common, sizeof(op_common)); 158 | if (rc < 0) { 159 | dbg("usbip_net_send failed: %d", rc); 160 | return -1; 161 | } 162 | 163 | return 0; 164 | } 165 | 166 | int usbip_net_recv_op_common(int sockfd, uint16_t *code) 167 | { 168 | struct op_common op_common; 169 | int rc; 170 | 171 | memset(&op_common, 0, sizeof(op_common)); 172 | 173 | rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common)); 174 | if (rc < 0) { 175 | dbg("usbip_net_recv failed: %d", rc); 176 | goto err; 177 | } 178 | 179 | PACK_OP_COMMON(0, &op_common); 180 | 181 | if (op_common.version != USBIP_VERSION) { 182 | dbg("version mismatch: %d %d", op_common.version, 183 | USBIP_VERSION); 184 | goto err; 185 | } 186 | 187 | switch (*code) { 188 | case OP_UNSPEC: 189 | break; 190 | default: 191 | if (op_common.code != *code) { 192 | dbg("unexpected pdu %#0x for %#0x", op_common.code, 193 | *code); 194 | goto err; 195 | } 196 | } 197 | 198 | if (op_common.status != ST_OK) { 199 | dbg("request failed at peer: %d", op_common.status); 200 | goto err; 201 | } 202 | 203 | *code = op_common.code; 204 | 205 | return 0; 206 | err: 207 | return -1; 208 | } 209 | 210 | int usbip_net_set_reuseaddr(int sockfd) 211 | { 212 | const int val = 1; 213 | int ret; 214 | 215 | ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 216 | if (ret < 0) 217 | dbg("setsockopt: SO_REUSEADDR"); 218 | 219 | return ret; 220 | } 221 | 222 | int usbip_net_set_nodelay(int sockfd) 223 | { 224 | const int val = 1; 225 | int ret; 226 | 227 | ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); 228 | if (ret < 0) 229 | dbg("setsockopt: TCP_NODELAY"); 230 | 231 | return ret; 232 | } 233 | 234 | int usbip_net_set_keepalive(int sockfd) 235 | { 236 | const int val = 1; 237 | int ret; 238 | 239 | ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); 240 | if (ret < 0) 241 | dbg("setsockopt: SO_KEEPALIVE"); 242 | 243 | return ret; 244 | } 245 | 246 | int usbip_net_set_v6only(int sockfd) 247 | { 248 | const int val = 1; 249 | int ret; 250 | 251 | ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); 252 | if (ret < 0) 253 | dbg("setsockopt: IPV6_V6ONLY"); 254 | 255 | return ret; 256 | } 257 | 258 | /* 259 | * IPv6 Ready 260 | */ 261 | int usbip_net_tcp_connect(char *hostname, char *service) 262 | { 263 | struct addrinfo hints, *res, *rp; 264 | int sockfd; 265 | int ret; 266 | 267 | memset(&hints, 0, sizeof(hints)); 268 | hints.ai_family = AF_UNSPEC; 269 | hints.ai_socktype = SOCK_STREAM; 270 | 271 | /* get all possible addresses */ 272 | ret = getaddrinfo(hostname, service, &hints, &res); 273 | if (ret < 0) { 274 | dbg("getaddrinfo: %s service %s: %s", hostname, service, 275 | gai_strerror(ret)); 276 | return ret; 277 | } 278 | 279 | /* try the addresses */ 280 | for (rp = res; rp; rp = rp->ai_next) { 281 | sockfd = socket(rp->ai_family, rp->ai_socktype, 282 | rp->ai_protocol); 283 | if (sockfd < 0) 284 | continue; 285 | 286 | /* should set TCP_NODELAY for usbip */ 287 | usbip_net_set_nodelay(sockfd); 288 | /* TODO: write code for heartbeat */ 289 | usbip_net_set_keepalive(sockfd); 290 | 291 | if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) 292 | break; 293 | 294 | close(sockfd); 295 | } 296 | 297 | freeaddrinfo(res); 298 | 299 | if (!rp) 300 | return EAI_SYSTEM; 301 | 302 | return sockfd; 303 | } 304 | -------------------------------------------------------------------------------- /libsrc/usbip_host_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2016 Samsung Electronics 3 | * Igor Kotrasinski 4 | * Krzysztof Opasiak 5 | * 6 | * Refactored from usbip_host_driver.c, which is: 7 | * Copyright (C) 2011 matt mooney 8 | * 2005-2007 Takahiro Hirofuchi 9 | * 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | #include "usbip_common.h" 34 | #include "usbip_host_common.h" 35 | #include "list.h" 36 | #include "sysfs_utils.h" 37 | 38 | struct udev *udev_context; 39 | 40 | static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) 41 | { 42 | char status_attr_path[SYSFS_PATH_MAX]; 43 | int fd; 44 | int length; 45 | char status; 46 | int value = 0; 47 | 48 | snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", 49 | udev->path); 50 | 51 | fd = open(status_attr_path, O_RDONLY); 52 | if (fd < 0) { 53 | err("error opening attribute %s", status_attr_path); 54 | return -1; 55 | } 56 | 57 | length = read(fd, &status, 1); 58 | if (length < 0) { 59 | err("error reading attribute %s", status_attr_path); 60 | close(fd); 61 | return -1; 62 | } 63 | 64 | value = atoi(&status); 65 | 66 | return value; 67 | } 68 | 69 | static 70 | struct usbip_exported_device *usbip_exported_device_new( 71 | struct usbip_host_driver *hdriver, const char *sdevpath) 72 | { 73 | struct usbip_exported_device *edev = NULL; 74 | struct usbip_exported_device *edev_old; 75 | size_t size; 76 | int i; 77 | 78 | edev = calloc(1, sizeof(struct usbip_exported_device)); 79 | 80 | edev->sudev = 81 | udev_device_new_from_syspath(udev_context, sdevpath); 82 | if (!edev->sudev) { 83 | err("udev_device_new_from_syspath: %s", sdevpath); 84 | goto err; 85 | } 86 | 87 | if (hdriver->ops.read_device(edev->sudev, &edev->udev) < 0) 88 | goto err; 89 | 90 | edev->status = read_attr_usbip_status(&edev->udev); 91 | if (edev->status < 0) 92 | goto err; 93 | 94 | /* reallocate buffer to include usb interface data */ 95 | size = sizeof(struct usbip_exported_device) + 96 | edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); 97 | 98 | edev_old = edev; 99 | edev = realloc(edev, size); 100 | if (!edev) { 101 | edev = edev_old; 102 | dbg("realloc failed"); 103 | goto err; 104 | } 105 | 106 | for (i = 0; i < edev->udev.bNumInterfaces; i++) { 107 | /* vudc does not support reading interfaces */ 108 | if (!hdriver->ops.read_interface) 109 | break; 110 | hdriver->ops.read_interface(&edev->udev, i, &edev->uinf[i]); 111 | } 112 | 113 | return edev; 114 | err: 115 | if (edev->sudev) 116 | udev_device_unref(edev->sudev); 117 | if (edev) 118 | free(edev); 119 | 120 | return NULL; 121 | } 122 | 123 | static int refresh_exported_devices(struct usbip_host_driver *hdriver) 124 | { 125 | struct usbip_exported_device *edev; 126 | struct udev_enumerate *enumerate; 127 | struct udev_list_entry *devices, *dev_list_entry; 128 | struct udev_device *dev; 129 | const char *path; 130 | 131 | enumerate = udev_enumerate_new(udev_context); 132 | udev_enumerate_add_match_subsystem(enumerate, hdriver->udev_subsystem); 133 | udev_enumerate_scan_devices(enumerate); 134 | 135 | devices = udev_enumerate_get_list_entry(enumerate); 136 | 137 | udev_list_entry_foreach(dev_list_entry, devices) { 138 | path = udev_list_entry_get_name(dev_list_entry); 139 | dev = udev_device_new_from_syspath(udev_context, 140 | path); 141 | if (dev == NULL) 142 | continue; 143 | 144 | /* Check whether device uses usbip driver. */ 145 | if (hdriver->ops.is_my_device(dev)) { 146 | edev = usbip_exported_device_new(hdriver, path); 147 | if (!edev) { 148 | dbg("usbip_exported_device_new failed"); 149 | continue; 150 | } 151 | 152 | list_add(&edev->node, &hdriver->edev_list); 153 | hdriver->ndevs++; 154 | } 155 | } 156 | 157 | return 0; 158 | } 159 | 160 | static void usbip_exported_device_destroy(struct list_head *devs) 161 | { 162 | struct list_head *i, *tmp; 163 | struct usbip_exported_device *edev; 164 | 165 | list_for_each_safe(i, tmp, devs) { 166 | edev = list_entry(i, struct usbip_exported_device, node); 167 | list_del(i); 168 | free(edev); 169 | } 170 | } 171 | 172 | int usbip_generic_driver_open(struct usbip_host_driver *hdriver) 173 | { 174 | int rc; 175 | 176 | udev_context = udev_new(); 177 | if (!udev_context) { 178 | err("udev_new failed"); 179 | return -1; 180 | } 181 | 182 | rc = refresh_exported_devices(hdriver); 183 | if (rc < 0) 184 | goto err; 185 | return 0; 186 | err: 187 | udev_unref(udev_context); 188 | return -1; 189 | } 190 | 191 | void usbip_generic_driver_close(struct usbip_host_driver *hdriver) 192 | { 193 | if (!hdriver) 194 | return; 195 | 196 | usbip_exported_device_destroy(&hdriver->edev_list); 197 | 198 | udev_unref(udev_context); 199 | } 200 | 201 | int usbip_generic_refresh_device_list(struct usbip_host_driver *hdriver) 202 | { 203 | int rc; 204 | 205 | usbip_exported_device_destroy(&hdriver->edev_list); 206 | 207 | hdriver->ndevs = 0; 208 | INIT_LIST_HEAD(&hdriver->edev_list); 209 | 210 | rc = refresh_exported_devices(hdriver); 211 | if (rc < 0) 212 | return -1; 213 | 214 | return 0; 215 | } 216 | 217 | int usbip_export_device(struct usbip_exported_device *edev, int sockfd) 218 | { 219 | char attr_name[] = "usbip_sockfd"; 220 | char sockfd_attr_path[SYSFS_PATH_MAX]; 221 | char sockfd_buff[30]; 222 | int ret; 223 | 224 | if (edev->status != SDEV_ST_AVAILABLE) { 225 | dbg("device not available: %s", edev->udev.busid); 226 | switch (edev->status) { 227 | case SDEV_ST_ERROR: 228 | dbg("status SDEV_ST_ERROR"); 229 | break; 230 | case SDEV_ST_USED: 231 | dbg("status SDEV_ST_USED"); 232 | break; 233 | default: 234 | dbg("status unknown: 0x%x", edev->status); 235 | } 236 | return -1; 237 | } 238 | 239 | /* only the first interface is true */ 240 | snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", 241 | edev->udev.path, attr_name); 242 | 243 | snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); 244 | 245 | ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, 246 | strlen(sockfd_buff)); 247 | if (ret < 0) { 248 | err("write_sysfs_attribute failed: sockfd %s to %s", 249 | sockfd_buff, sockfd_attr_path); 250 | return ret; 251 | } 252 | 253 | info("connect: %s", edev->udev.busid); 254 | 255 | return ret; 256 | } 257 | 258 | struct usbip_exported_device *usbip_generic_get_device( 259 | struct usbip_host_driver *hdriver, int num) 260 | { 261 | struct list_head *i; 262 | struct usbip_exported_device *edev; 263 | int cnt = 0; 264 | 265 | list_for_each(i, &hdriver->edev_list) { 266 | edev = list_entry(i, struct usbip_exported_device, node); 267 | if (num == cnt) 268 | return edev; 269 | cnt++; 270 | } 271 | 272 | return NULL; 273 | } 274 | -------------------------------------------------------------------------------- /libsrc/usbip_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #include 6 | #include "usbip_common.h" 7 | #include "names.h" 8 | 9 | #undef PROGNAME 10 | #define PROGNAME "libusbip" 11 | 12 | int usbip_use_syslog; 13 | int usbip_use_stderr; 14 | int usbip_use_debug; 15 | 16 | extern struct udev *udev_context; 17 | 18 | struct speed_string { 19 | int num; 20 | char *speed; 21 | char *desc; 22 | }; 23 | 24 | static const struct speed_string speed_strings[] = { 25 | { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"}, 26 | { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, 27 | { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, 28 | { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, 29 | { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, 30 | { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, 31 | { 0, NULL, NULL } 32 | }; 33 | 34 | struct portst_string { 35 | int num; 36 | char *desc; 37 | }; 38 | 39 | static struct portst_string portst_strings[] = { 40 | { SDEV_ST_AVAILABLE, "Device Available" }, 41 | { SDEV_ST_USED, "Device in Use" }, 42 | { SDEV_ST_ERROR, "Device Error"}, 43 | { VDEV_ST_NULL, "Port Available"}, 44 | { VDEV_ST_NOTASSIGNED, "Port Initializing"}, 45 | { VDEV_ST_USED, "Port in Use"}, 46 | { VDEV_ST_ERROR, "Port Error"}, 47 | { 0, NULL} 48 | }; 49 | 50 | const char *usbip_status_string(int32_t status) 51 | { 52 | for (int i = 0; portst_strings[i].desc != NULL; i++) 53 | if (portst_strings[i].num == status) 54 | return portst_strings[i].desc; 55 | 56 | return "Unknown Status"; 57 | } 58 | 59 | const char *usbip_speed_string(int num) 60 | { 61 | for (int i = 0; speed_strings[i].speed != NULL; i++) 62 | if (speed_strings[i].num == num) 63 | return speed_strings[i].desc; 64 | 65 | return "Unknown Speed"; 66 | } 67 | 68 | 69 | #define DBG_UDEV_INTEGER(name)\ 70 | dbg("%-20s = %x", to_string(name), (int) udev->name) 71 | 72 | #define DBG_UINF_INTEGER(name)\ 73 | dbg("%-20s = %x", to_string(name), (int) uinf->name) 74 | 75 | void dump_usb_interface(struct usbip_usb_interface *uinf) 76 | { 77 | char buff[100]; 78 | 79 | usbip_names_get_class(buff, sizeof(buff), 80 | uinf->bInterfaceClass, 81 | uinf->bInterfaceSubClass, 82 | uinf->bInterfaceProtocol); 83 | dbg("%-20s = %s", "Interface(C/SC/P)", buff); 84 | } 85 | 86 | void dump_usb_device(struct usbip_usb_device *udev) 87 | { 88 | char buff[100]; 89 | 90 | dbg("%-20s = %s", "path", udev->path); 91 | dbg("%-20s = %s", "busid", udev->busid); 92 | 93 | usbip_names_get_class(buff, sizeof(buff), 94 | udev->bDeviceClass, 95 | udev->bDeviceSubClass, 96 | udev->bDeviceProtocol); 97 | dbg("%-20s = %s", "Device(C/SC/P)", buff); 98 | 99 | DBG_UDEV_INTEGER(bcdDevice); 100 | 101 | usbip_names_get_product(buff, sizeof(buff), 102 | udev->idVendor, 103 | udev->idProduct); 104 | dbg("%-20s = %s", "Vendor/Product", buff); 105 | 106 | DBG_UDEV_INTEGER(bNumConfigurations); 107 | DBG_UDEV_INTEGER(bNumInterfaces); 108 | 109 | dbg("%-20s = %s", "speed", 110 | usbip_speed_string(udev->speed)); 111 | 112 | DBG_UDEV_INTEGER(busnum); 113 | DBG_UDEV_INTEGER(devnum); 114 | } 115 | 116 | 117 | int read_attr_value(struct udev_device *dev, const char *name, 118 | const char *format) 119 | { 120 | const char *attr; 121 | int num = 0; 122 | int ret; 123 | 124 | attr = udev_device_get_sysattr_value(dev, name); 125 | if (!attr) { 126 | err("udev_device_get_sysattr_value failed"); 127 | goto err; 128 | } 129 | 130 | /* The client chooses the device configuration 131 | * when attaching it so right after being bound 132 | * to usbip-host on the server the device will 133 | * have no configuration. 134 | * Therefore, attributes such as bConfigurationValue 135 | * and bNumInterfaces will not exist and sscanf will 136 | * fail. Check for these cases and don't treat them 137 | * as errors. 138 | */ 139 | 140 | ret = sscanf(attr, format, &num); 141 | if (ret < 1) { 142 | if (strcmp(name, "bConfigurationValue") && 143 | strcmp(name, "bNumInterfaces")) { 144 | err("sscanf failed for attribute %s", name); 145 | goto err; 146 | } 147 | } 148 | 149 | err: 150 | 151 | return num; 152 | } 153 | 154 | 155 | int read_attr_speed(struct udev_device *dev) 156 | { 157 | const char *speed; 158 | 159 | speed = udev_device_get_sysattr_value(dev, "speed"); 160 | if (!speed) { 161 | err("udev_device_get_sysattr_value failed"); 162 | goto err; 163 | } 164 | 165 | for (int i = 0; speed_strings[i].speed != NULL; i++) { 166 | if (!strcmp(speed, speed_strings[i].speed)) 167 | return speed_strings[i].num; 168 | } 169 | 170 | err: 171 | 172 | return USB_SPEED_UNKNOWN; 173 | } 174 | 175 | #define READ_ATTR(object, type, dev, name, format) \ 176 | do { \ 177 | (object)->name = (type) read_attr_value(dev, to_string(name), \ 178 | format); \ 179 | } while (0) 180 | 181 | 182 | int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev) 183 | { 184 | uint32_t busnum, devnum; 185 | const char *path, *name; 186 | 187 | READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); 188 | READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); 189 | READ_ATTR(udev, uint8_t, sdev, bDeviceProtocol, "%02x\n"); 190 | 191 | READ_ATTR(udev, uint16_t, sdev, idVendor, "%04x\n"); 192 | READ_ATTR(udev, uint16_t, sdev, idProduct, "%04x\n"); 193 | READ_ATTR(udev, uint16_t, sdev, bcdDevice, "%04x\n"); 194 | 195 | READ_ATTR(udev, uint8_t, sdev, bConfigurationValue, "%02x\n"); 196 | READ_ATTR(udev, uint8_t, sdev, bNumConfigurations, "%02x\n"); 197 | READ_ATTR(udev, uint8_t, sdev, bNumInterfaces, "%02x\n"); 198 | 199 | READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); 200 | udev->speed = read_attr_speed(sdev); 201 | 202 | path = udev_device_get_syspath(sdev); 203 | name = udev_device_get_sysname(sdev); 204 | 205 | strncpy(udev->path, path, SYSFS_PATH_MAX); 206 | strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE); 207 | 208 | sscanf(name, "%u-%u", &busnum, &devnum); 209 | udev->busnum = busnum; 210 | 211 | return 0; 212 | } 213 | 214 | int read_usb_interface(struct usbip_usb_device *udev, int i, 215 | struct usbip_usb_interface *uinf) 216 | { 217 | char busid[SYSFS_BUS_ID_SIZE]; 218 | struct udev_device *sif; 219 | 220 | sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); 221 | 222 | sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); 223 | if (!sif) { 224 | err("udev_device_new_from_subsystem_sysname %s failed", busid); 225 | return -1; 226 | } 227 | 228 | READ_ATTR(uinf, uint8_t, sif, bInterfaceClass, "%02x\n"); 229 | READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); 230 | READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); 231 | 232 | return 0; 233 | } 234 | 235 | int usbip_names_init(char *f) 236 | { 237 | return names_init(f); 238 | } 239 | 240 | void usbip_names_free(void) 241 | { 242 | names_free(); 243 | } 244 | 245 | void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, 246 | uint16_t product) 247 | { 248 | const char *prod, *vend; 249 | 250 | prod = names_product(vendor, product); 251 | if (!prod) 252 | prod = "unknown product"; 253 | 254 | 255 | vend = names_vendor(vendor); 256 | if (!vend) 257 | vend = "unknown vendor"; 258 | 259 | snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product); 260 | } 261 | 262 | void usbip_names_get_class(char *buff, size_t size, uint8_t class, 263 | uint8_t subclass, uint8_t protocol) 264 | { 265 | const char *c, *s, *p; 266 | 267 | if (class == 0 && subclass == 0 && protocol == 0) { 268 | snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol); 269 | return; 270 | } 271 | 272 | p = names_protocol(class, subclass, protocol); 273 | if (!p) 274 | p = "unknown protocol"; 275 | 276 | s = names_subclass(class, subclass); 277 | if (!s) 278 | s = "unknown subclass"; 279 | 280 | c = names_class(class); 281 | if (!c) 282 | c = "unknown class"; 283 | 284 | snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol); 285 | } 286 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | 6. Often, you can also type `make uninstall' to remove the installed 71 | files again. 72 | 73 | Compilers and Options 74 | ===================== 75 | 76 | Some systems require unusual options for compilation or linking that the 77 | `configure' script does not know about. Run `./configure --help' for 78 | details on some of the pertinent environment variables. 79 | 80 | You can give `configure' initial values for configuration parameters 81 | by setting variables in the command line or in the environment. Here 82 | is an example: 83 | 84 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 85 | 86 | *Note Defining Variables::, for more details. 87 | 88 | Compiling For Multiple Architectures 89 | ==================================== 90 | 91 | You can compile the package for more than one kind of computer at the 92 | same time, by placing the object files for each architecture in their 93 | own directory. To do this, you can use GNU `make'. `cd' to the 94 | directory where you want the object files and executables to go and run 95 | the `configure' script. `configure' automatically checks for the 96 | source code in the directory that `configure' is in and in `..'. 97 | 98 | With a non-GNU `make', it is safer to compile the package for one 99 | architecture at a time in the source code directory. After you have 100 | installed the package for one architecture, use `make distclean' before 101 | reconfiguring for another architecture. 102 | 103 | Installation Names 104 | ================== 105 | 106 | By default, `make install' installs the package's commands under 107 | `/usr/local/bin', include files under `/usr/local/include', etc. You 108 | can specify an installation prefix other than `/usr/local' by giving 109 | `configure' the option `--prefix=PREFIX'. 110 | 111 | You can specify separate installation prefixes for 112 | architecture-specific files and architecture-independent files. If you 113 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 114 | PREFIX as the prefix for installing programs and libraries. 115 | Documentation and other data files still use the regular prefix. 116 | 117 | In addition, if you use an unusual directory layout you can give 118 | options like `--bindir=DIR' to specify different values for particular 119 | kinds of files. Run `configure --help' for a list of the directories 120 | you can set and what kinds of files go in them. 121 | 122 | If the package supports it, you can cause programs to be installed 123 | with an extra prefix or suffix on their names by giving `configure' the 124 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 125 | 126 | Optional Features 127 | ================= 128 | 129 | Some packages pay attention to `--enable-FEATURE' options to 130 | `configure', where FEATURE indicates an optional part of the package. 131 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 132 | is something like `gnu-as' or `x' (for the X Window System). The 133 | `README' should mention any `--enable-' and `--with-' options that the 134 | package recognizes. 135 | 136 | For packages that use the X Window System, `configure' can usually 137 | find the X include and library files automatically, but if it doesn't, 138 | you can use the `configure' options `--x-includes=DIR' and 139 | `--x-libraries=DIR' to specify their locations. 140 | 141 | Specifying the System Type 142 | ========================== 143 | 144 | There may be some features `configure' cannot figure out automatically, 145 | but needs to determine by the type of machine the package will run on. 146 | Usually, assuming the package is built to be run on the _same_ 147 | architectures, `configure' can figure that out, but if it prints a 148 | message saying it cannot guess the machine type, give it the 149 | `--build=TYPE' option. TYPE can either be a short name for the system 150 | type, such as `sun4', or a canonical name which has the form: 151 | 152 | CPU-COMPANY-SYSTEM 153 | 154 | where SYSTEM can have one of these forms: 155 | 156 | OS KERNEL-OS 157 | 158 | See the file `config.sub' for the possible values of each field. If 159 | `config.sub' isn't included in this package, then this package doesn't 160 | need to know the machine type. 161 | 162 | If you are _building_ compiler tools for cross-compiling, you should 163 | use the option `--target=TYPE' to select the type of system they will 164 | produce code for. 165 | 166 | If you want to _use_ a cross compiler, that generates code for a 167 | platform different from the build platform, you should specify the 168 | "host" platform (i.e., that on which the generated programs will 169 | eventually be run) with `--host=TYPE'. 170 | 171 | Sharing Defaults 172 | ================ 173 | 174 | If you want to set default values for `configure' scripts to share, you 175 | can create a site shell script called `config.site' that gives default 176 | values for variables like `CC', `cache_file', and `prefix'. 177 | `configure' looks for `PREFIX/share/config.site' if it exists, then 178 | `PREFIX/etc/config.site' if it exists. Or, you can set the 179 | `CONFIG_SITE' environment variable to the location of the site script. 180 | A warning: not all `configure' scripts look for a site script. 181 | 182 | Defining Variables 183 | ================== 184 | 185 | Variables not defined in a site shell script can be set in the 186 | environment passed to `configure'. However, some packages may run 187 | configure again during the build, and the customized values of these 188 | variables may be lost. In order to avoid this problem, you should set 189 | them in the `configure' command line, using `VAR=value'. For example: 190 | 191 | ./configure CC=/usr/local2/bin/gcc 192 | 193 | causes the specified `gcc' to be used as the C compiler (unless it is 194 | overridden in the site shell script). 195 | 196 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 197 | an Autoconf bug. Until the bug is fixed you can use this workaround: 198 | 199 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 200 | 201 | `configure' Invocation 202 | ====================== 203 | 204 | `configure' recognizes the following options to control how it operates. 205 | 206 | `--help' 207 | `-h' 208 | Print a summary of the options to `configure', and exit. 209 | 210 | `--version' 211 | `-V' 212 | Print the version of Autoconf used to generate the `configure' 213 | script, and exit. 214 | 215 | `--cache-file=FILE' 216 | Enable the cache: use and save the results of the tests in FILE, 217 | traditionally `config.cache'. FILE defaults to `/dev/null' to 218 | disable caching. 219 | 220 | `--config-cache' 221 | `-C' 222 | Alias for `--cache-file=config.cache'. 223 | 224 | `--quiet' 225 | `--silent' 226 | `-q' 227 | Do not print messages saying which checks are being made. To 228 | suppress all normal output, redirect it to `/dev/null' (any error 229 | messages will still be shown). 230 | 231 | `--srcdir=DIR' 232 | Look for the package's source code in directory DIR. Usually 233 | `configure' can determine that directory automatically. 234 | 235 | `configure' also accepts some other, not widely useful, options. Run 236 | `configure --help' for more details. 237 | 238 | -------------------------------------------------------------------------------- /libsrc/vhci_driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005-2007 Takahiro Hirofuchi 3 | */ 4 | 5 | #include "usbip_common.h" 6 | #include "vhci_driver.h" 7 | #include 8 | #include 9 | #include 10 | #include "sysfs_utils.h" 11 | 12 | #undef PROGNAME 13 | #define PROGNAME "libusbip" 14 | 15 | struct usbip_vhci_driver *vhci_driver; 16 | struct udev *udev_context; 17 | 18 | static struct usbip_imported_device * 19 | imported_device_init(struct usbip_imported_device *idev, char *busid) 20 | { 21 | struct udev_device *sudev; 22 | 23 | sudev = udev_device_new_from_subsystem_sysname(udev_context, 24 | "usb", busid); 25 | if (!sudev) { 26 | dbg("udev_device_new_from_subsystem_sysname failed: %s", busid); 27 | goto err; 28 | } 29 | read_usb_device(sudev, &idev->udev); 30 | udev_device_unref(sudev); 31 | 32 | return idev; 33 | 34 | err: 35 | return NULL; 36 | } 37 | 38 | 39 | 40 | static int parse_status(const char *value) 41 | { 42 | int ret = 0; 43 | char *c; 44 | 45 | 46 | for (int i = 0; i < vhci_driver->nports; i++) 47 | memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i])); 48 | 49 | 50 | /* skip a header line */ 51 | c = strchr(value, '\n'); 52 | if (!c) 53 | return -1; 54 | c++; 55 | 56 | while (*c != '\0') { 57 | int port, status, speed, devid; 58 | unsigned long socket; 59 | char lbusid[SYSFS_BUS_ID_SIZE]; 60 | 61 | ret = sscanf(c, "%d %d %d %x %lx %31s\n", 62 | &port, &status, &speed, 63 | &devid, &socket, lbusid); 64 | 65 | if (ret < 5) { 66 | dbg("sscanf failed: %d", ret); 67 | BUG(); 68 | } 69 | 70 | dbg("port %d status %d speed %d devid %x", 71 | port, status, speed, devid); 72 | dbg("socket %lx lbusid %s", socket, lbusid); 73 | 74 | 75 | /* if a device is connected, look at it */ 76 | { 77 | struct usbip_imported_device *idev = &vhci_driver->idev[port]; 78 | 79 | idev->port = port; 80 | idev->status = status; 81 | 82 | idev->devid = devid; 83 | 84 | idev->busnum = (devid >> 16); 85 | idev->devnum = (devid & 0x0000ffff); 86 | 87 | if (idev->status != VDEV_ST_NULL 88 | && idev->status != VDEV_ST_NOTASSIGNED) { 89 | idev = imported_device_init(idev, lbusid); 90 | if (!idev) { 91 | dbg("imported_device_init failed"); 92 | return -1; 93 | } 94 | } 95 | } 96 | 97 | 98 | /* go to the next line */ 99 | c = strchr(c, '\n'); 100 | if (!c) 101 | break; 102 | c++; 103 | } 104 | 105 | dbg("exit"); 106 | 107 | return 0; 108 | } 109 | 110 | static int refresh_imported_device_list(void) 111 | { 112 | const char *attr_status; 113 | 114 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, 115 | "status"); 116 | if (!attr_status) { 117 | err("udev_device_get_sysattr_value failed"); 118 | return -1; 119 | } 120 | 121 | return parse_status(attr_status); 122 | } 123 | 124 | static int get_nports(void) 125 | { 126 | char *c; 127 | int nports = 0; 128 | const char *attr_status; 129 | 130 | attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, 131 | "status"); 132 | if (!attr_status) { 133 | err("udev_device_get_sysattr_value failed"); 134 | return -1; 135 | } 136 | 137 | /* skip a header line */ 138 | c = strchr(attr_status, '\n'); 139 | if (!c) 140 | return 0; 141 | c++; 142 | 143 | while (*c != '\0') { 144 | /* go to the next line */ 145 | c = strchr(c, '\n'); 146 | if (!c) 147 | return nports; 148 | c++; 149 | nports += 1; 150 | } 151 | 152 | return nports; 153 | } 154 | 155 | /* 156 | * Read the given port's record. 157 | * 158 | * To avoid buffer overflow we will read the entire line and 159 | * validate each part's size. The initial buffer is padded by 4 to 160 | * accommodate the 2 spaces, 1 newline and an additional character 161 | * which is needed to properly validate the 3rd part without it being 162 | * truncated to an acceptable length. 163 | */ 164 | static int read_record(int rhport, char *host, unsigned long host_len, 165 | char *port, unsigned long port_len, char *busid) 166 | { 167 | int part; 168 | FILE *file; 169 | char path[PATH_MAX+1]; 170 | char *buffer, *start, *end; 171 | char delim[] = {' ', ' ', '\n'}; 172 | int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE}; 173 | size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4; 174 | 175 | buffer = malloc(buffer_len); 176 | if (!buffer) 177 | return -1; 178 | 179 | snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); 180 | 181 | file = fopen(path, "r"); 182 | if (!file) { 183 | err("fopen"); 184 | free(buffer); 185 | return -1; 186 | } 187 | 188 | if (fgets(buffer, buffer_len, file) == NULL) { 189 | err("fgets"); 190 | free(buffer); 191 | fclose(file); 192 | return -1; 193 | } 194 | fclose(file); 195 | 196 | /* validate the length of each of the 3 parts */ 197 | start = buffer; 198 | for (part = 0; part < 3; part++) { 199 | end = strchr(start, delim[part]); 200 | if (end == NULL || (end - start) > max_len[part]) { 201 | free(buffer); 202 | return -1; 203 | } 204 | start = end + 1; 205 | } 206 | 207 | if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) { 208 | err("sscanf"); 209 | free(buffer); 210 | return -1; 211 | } 212 | 213 | free(buffer); 214 | 215 | return 0; 216 | } 217 | 218 | /* ---------------------------------------------------------------------- */ 219 | 220 | int usbip_vhci_driver_open(void) 221 | { 222 | udev_context = udev_new(); 223 | if (!udev_context) { 224 | err("udev_new failed"); 225 | return -1; 226 | } 227 | 228 | vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); 229 | 230 | /* will be freed in usbip_driver_close() */ 231 | vhci_driver->hc_device = 232 | udev_device_new_from_subsystem_sysname(udev_context, 233 | USBIP_VHCI_BUS_TYPE, 234 | USBIP_VHCI_DRV_NAME); 235 | if (!vhci_driver->hc_device) { 236 | err("udev_device_new_from_subsystem_sysname failed"); 237 | goto err; 238 | } 239 | 240 | vhci_driver->nports = get_nports(); 241 | 242 | dbg("available ports: %d", vhci_driver->nports); 243 | 244 | if (refresh_imported_device_list()) 245 | goto err; 246 | 247 | return 0; 248 | 249 | err: 250 | udev_device_unref(vhci_driver->hc_device); 251 | 252 | if (vhci_driver) 253 | free(vhci_driver); 254 | 255 | vhci_driver = NULL; 256 | 257 | udev_unref(udev_context); 258 | 259 | return -1; 260 | } 261 | 262 | 263 | void usbip_vhci_driver_close(void) 264 | { 265 | if (!vhci_driver) 266 | return; 267 | 268 | udev_device_unref(vhci_driver->hc_device); 269 | 270 | free(vhci_driver); 271 | 272 | vhci_driver = NULL; 273 | 274 | udev_unref(udev_context); 275 | } 276 | 277 | 278 | int usbip_vhci_refresh_device_list(void) 279 | { 280 | 281 | if (refresh_imported_device_list()) 282 | goto err; 283 | 284 | return 0; 285 | err: 286 | dbg("failed to refresh device list"); 287 | return -1; 288 | } 289 | 290 | 291 | int usbip_vhci_get_free_port(void) 292 | { 293 | for (int i = 0; i < vhci_driver->nports; i++) { 294 | if (vhci_driver->idev[i].status == VDEV_ST_NULL) 295 | return i; 296 | } 297 | 298 | return -1; 299 | } 300 | 301 | int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, 302 | uint32_t speed) { 303 | char buff[200]; /* what size should be ? */ 304 | char attach_attr_path[SYSFS_PATH_MAX]; 305 | char attr_attach[] = "attach"; 306 | const char *path; 307 | int ret; 308 | 309 | snprintf(buff, sizeof(buff), "%u %d %u %u", 310 | port, sockfd, devid, speed); 311 | dbg("writing: %s", buff); 312 | 313 | path = udev_device_get_syspath(vhci_driver->hc_device); 314 | snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s", 315 | path, attr_attach); 316 | dbg("attach attribute path: %s", attach_attr_path); 317 | 318 | ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff)); 319 | if (ret < 0) { 320 | dbg("write_sysfs_attribute failed"); 321 | return -1; 322 | } 323 | 324 | dbg("attached port: %d", port); 325 | 326 | return 0; 327 | } 328 | 329 | static unsigned long get_devid(uint8_t busnum, uint8_t devnum) 330 | { 331 | return (busnum << 16) | devnum; 332 | } 333 | 334 | /* will be removed */ 335 | int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, 336 | uint8_t devnum, uint32_t speed) 337 | { 338 | int devid = get_devid(busnum, devnum); 339 | 340 | return usbip_vhci_attach_device2(port, sockfd, devid, speed); 341 | } 342 | 343 | int usbip_vhci_detach_device(uint8_t port) 344 | { 345 | char detach_attr_path[SYSFS_PATH_MAX]; 346 | char attr_detach[] = "detach"; 347 | char buff[200]; /* what size should be ? */ 348 | const char *path; 349 | int ret; 350 | 351 | snprintf(buff, sizeof(buff), "%u", port); 352 | dbg("writing: %s", buff); 353 | 354 | path = udev_device_get_syspath(vhci_driver->hc_device); 355 | snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s", 356 | path, attr_detach); 357 | dbg("detach attribute path: %s", detach_attr_path); 358 | 359 | ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff)); 360 | if (ret < 0) { 361 | dbg("write_sysfs_attribute failed"); 362 | return -1; 363 | } 364 | 365 | dbg("detached port: %d", port); 366 | 367 | return 0; 368 | } 369 | 370 | int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) 371 | { 372 | char product_name[100]; 373 | char host[NI_MAXHOST] = "unknown host"; 374 | char serv[NI_MAXSERV] = "unknown port"; 375 | char remote_busid[SYSFS_BUS_ID_SIZE]; 376 | int ret; 377 | int read_record_error = 0; 378 | 379 | if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) 380 | return 0; 381 | 382 | ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv), 383 | remote_busid); 384 | if (ret) { 385 | err("read_record"); 386 | read_record_error = 1; 387 | } 388 | 389 | printf("Port %02d: <%s> at %s\n", idev->port, 390 | usbip_status_string(idev->status), 391 | usbip_speed_string(idev->udev.speed)); 392 | 393 | usbip_names_get_product(product_name, sizeof(product_name), 394 | idev->udev.idVendor, idev->udev.idProduct); 395 | 396 | printf(" %s\n", product_name); 397 | 398 | if (!read_record_error) { 399 | printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid, 400 | host, serv, remote_busid); 401 | printf("%10s -> remote bus/dev %03d/%03d\n", " ", 402 | idev->busnum, idev->devnum); 403 | } else { 404 | printf("%10s -> unknown host, remote port and remote busid\n", 405 | idev->udev.busid); 406 | printf("%10s -> remote bus/dev %03d/%03d\n", " ", 407 | idev->busnum, idev->devnum); 408 | } 409 | 410 | return 0; 411 | } 412 | -------------------------------------------------------------------------------- /src/usbip_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * Copyright (C) 2015-2016 Samsung Electronics 5 | * Igor Kotrasinski 6 | * Krzysztof Opasiak 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | #include "usbip_common.h" 42 | #include "usbip_network.h" 43 | #include "usbip.h" 44 | 45 | static const char usbip_list_usage_string[] = 46 | "usbip list [-p|--parsable] \n" 47 | " -p, --parsable Parsable list format\n" 48 | " -r, --remote= List the exportable USB devices on \n" 49 | " -l, --local List the local USB devices\n"; 50 | 51 | void usbip_list_usage(void) 52 | { 53 | printf("usage: %s", usbip_list_usage_string); 54 | } 55 | 56 | static int get_exported_devices(char *host, int sockfd) 57 | { 58 | char product_name[100]; 59 | char class_name[100]; 60 | struct op_devlist_reply reply; 61 | uint16_t code = OP_REP_DEVLIST; 62 | struct usbip_usb_device udev; 63 | struct usbip_usb_interface uintf; 64 | unsigned int i; 65 | int rc, j; 66 | 67 | rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); 68 | if (rc < 0) { 69 | dbg("usbip_net_send_op_common failed"); 70 | return -1; 71 | } 72 | 73 | rc = usbip_net_recv_op_common(sockfd, &code); 74 | if (rc < 0) { 75 | dbg("usbip_net_recv_op_common failed"); 76 | return -1; 77 | } 78 | 79 | memset(&reply, 0, sizeof(reply)); 80 | rc = usbip_net_recv(sockfd, &reply, sizeof(reply)); 81 | if (rc < 0) { 82 | dbg("usbip_net_recv_op_devlist failed"); 83 | return -1; 84 | } 85 | PACK_OP_DEVLIST_REPLY(0, &reply); 86 | dbg("exportable devices: %d\n", reply.ndev); 87 | 88 | if (reply.ndev == 0) { 89 | info("no exportable devices found on %s", host); 90 | return 0; 91 | } 92 | 93 | printf("Exportable USB devices\n"); 94 | printf("======================\n"); 95 | printf(" - %s\n", host); 96 | 97 | for (i = 0; i < reply.ndev; i++) { 98 | memset(&udev, 0, sizeof(udev)); 99 | rc = usbip_net_recv(sockfd, &udev, sizeof(udev)); 100 | if (rc < 0) { 101 | dbg("usbip_net_recv failed: usbip_usb_device[%d]", i); 102 | return -1; 103 | } 104 | usbip_net_pack_usb_device(0, &udev); 105 | 106 | usbip_names_get_product(product_name, sizeof(product_name), 107 | udev.idVendor, udev.idProduct); 108 | usbip_names_get_class(class_name, sizeof(class_name), 109 | udev.bDeviceClass, udev.bDeviceSubClass, 110 | udev.bDeviceProtocol); 111 | printf("%11s: %s\n", udev.busid, product_name); 112 | printf("%11s: %s\n", "", udev.path); 113 | printf("%11s: %s\n", "", class_name); 114 | 115 | for (j = 0; j < udev.bNumInterfaces; j++) { 116 | rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); 117 | if (rc < 0) { 118 | err("usbip_net_recv failed: usbip_usb_intf[%d]", 119 | j); 120 | 121 | return -1; 122 | } 123 | usbip_net_pack_usb_interface(0, &uintf); 124 | 125 | usbip_names_get_class(class_name, sizeof(class_name), 126 | uintf.bInterfaceClass, 127 | uintf.bInterfaceSubClass, 128 | uintf.bInterfaceProtocol); 129 | printf("%11s: %2d - %s\n", "", j, class_name); 130 | } 131 | 132 | printf("\n"); 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | static int list_exported_devices(char *host) 139 | { 140 | int rc; 141 | int sockfd; 142 | 143 | sockfd = usbip_net_tcp_connect(host, usbip_port_string); 144 | if (sockfd < 0) { 145 | err("could not connect to %s:%s: %s", host, 146 | usbip_port_string, gai_strerror(sockfd)); 147 | return -1; 148 | } 149 | dbg("connected to %s:%s", host, usbip_port_string); 150 | 151 | rc = get_exported_devices(host, sockfd); 152 | if (rc < 0) { 153 | err("failed to get device list from %s", host); 154 | return -1; 155 | } 156 | 157 | close(sockfd); 158 | 159 | return 0; 160 | } 161 | 162 | static void print_device(const char *busid, const char *vendor, 163 | const char *product, bool parsable) 164 | { 165 | if (parsable) 166 | printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); 167 | else 168 | printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); 169 | } 170 | 171 | static void print_product_name(char *product_name, bool parsable) 172 | { 173 | if (!parsable) 174 | printf(" %s\n", product_name); 175 | } 176 | 177 | static int list_devices(bool parsable) 178 | { 179 | struct udev *udev; 180 | struct udev_enumerate *enumerate; 181 | struct udev_list_entry *devices, *dev_list_entry; 182 | struct udev_device *dev; 183 | const char *path; 184 | const char *idVendor; 185 | const char *idProduct; 186 | const char *bConfValue; 187 | const char *bNumIntfs; 188 | const char *busid; 189 | char product_name[128]; 190 | int ret = -1; 191 | 192 | /* Create libudev context. */ 193 | udev = udev_new(); 194 | 195 | /* Create libudev device enumeration. */ 196 | enumerate = udev_enumerate_new(udev); 197 | 198 | /* Take only USB devices that are not hubs and do not have 199 | * the bInterfaceNumber attribute, i.e. are not interfaces. 200 | */ 201 | udev_enumerate_add_match_subsystem(enumerate, "usb"); 202 | udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09"); 203 | udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL); 204 | udev_enumerate_scan_devices(enumerate); 205 | 206 | devices = udev_enumerate_get_list_entry(enumerate); 207 | 208 | /* Show information about each device. */ 209 | udev_list_entry_foreach(dev_list_entry, devices) { 210 | path = udev_list_entry_get_name(dev_list_entry); 211 | dev = udev_device_new_from_syspath(udev, path); 212 | 213 | /* Get device information. */ 214 | idVendor = udev_device_get_sysattr_value(dev, "idVendor"); 215 | idProduct = udev_device_get_sysattr_value(dev, "idProduct"); 216 | bConfValue = udev_device_get_sysattr_value(dev, 217 | "bConfigurationValue"); 218 | bNumIntfs = udev_device_get_sysattr_value(dev, 219 | "bNumInterfaces"); 220 | busid = udev_device_get_sysname(dev); 221 | if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { 222 | err("problem getting device attributes: %s", 223 | strerror(errno)); 224 | goto err_out; 225 | } 226 | 227 | /* Get product name. */ 228 | usbip_names_get_product(product_name, sizeof(product_name), 229 | strtol(idVendor, NULL, 16), 230 | strtol(idProduct, NULL, 16)); 231 | 232 | /* Print information. */ 233 | print_device(busid, idVendor, idProduct, parsable); 234 | print_product_name(product_name, parsable); 235 | 236 | printf("\n"); 237 | 238 | udev_device_unref(dev); 239 | } 240 | 241 | ret = 0; 242 | 243 | err_out: 244 | udev_enumerate_unref(enumerate); 245 | udev_unref(udev); 246 | 247 | return ret; 248 | } 249 | 250 | static int list_gadget_devices(bool parsable) 251 | { 252 | int ret = -1; 253 | struct udev *udev; 254 | struct udev_enumerate *enumerate; 255 | struct udev_list_entry *devices, *dev_list_entry; 256 | struct udev_device *dev; 257 | const char *path; 258 | const char *driver; 259 | 260 | const struct usb_device_descriptor *d_desc; 261 | const char *descriptors; 262 | char product_name[128]; 263 | 264 | uint16_t idVendor; 265 | char idVendor_buf[8]; 266 | uint16_t idProduct; 267 | char idProduct_buf[8]; 268 | const char *busid; 269 | 270 | udev = udev_new(); 271 | enumerate = udev_enumerate_new(udev); 272 | 273 | udev_enumerate_add_match_subsystem(enumerate, "platform"); 274 | 275 | udev_enumerate_scan_devices(enumerate); 276 | devices = udev_enumerate_get_list_entry(enumerate); 277 | 278 | udev_list_entry_foreach(dev_list_entry, devices) { 279 | path = udev_list_entry_get_name(dev_list_entry); 280 | dev = udev_device_new_from_syspath(udev, path); 281 | 282 | driver = udev_device_get_driver(dev); 283 | /* We only have mechanism to enumerate gadgets bound to vudc */ 284 | if (driver == NULL || strcmp(driver, USBIP_DEVICE_DRV_NAME)) 285 | continue; 286 | 287 | /* Get device information. */ 288 | descriptors = udev_device_get_sysattr_value(dev, 289 | VUDC_DEVICE_DESCR_FILE); 290 | 291 | if (!descriptors) { 292 | err("problem getting device attributes: %s", 293 | strerror(errno)); 294 | goto err_out; 295 | } 296 | 297 | d_desc = (const struct usb_device_descriptor *) descriptors; 298 | 299 | idVendor = le16toh(d_desc->idVendor); 300 | sprintf(idVendor_buf, "0x%4x", idVendor); 301 | idProduct = le16toh(d_desc->idProduct); 302 | sprintf(idProduct_buf, "0x%4x", idVendor); 303 | busid = udev_device_get_sysname(dev); 304 | 305 | /* Get product name. */ 306 | usbip_names_get_product(product_name, sizeof(product_name), 307 | le16toh(idVendor), 308 | le16toh(idProduct)); 309 | 310 | /* Print information. */ 311 | print_device(busid, idVendor_buf, idProduct_buf, parsable); 312 | print_product_name(product_name, parsable); 313 | 314 | printf("\n"); 315 | 316 | udev_device_unref(dev); 317 | } 318 | ret = 0; 319 | 320 | err_out: 321 | udev_enumerate_unref(enumerate); 322 | udev_unref(udev); 323 | 324 | return ret; 325 | } 326 | 327 | int usbip_list(int argc, char *argv[]) 328 | { 329 | static const struct option opts[] = { 330 | { "parsable", no_argument, NULL, 'p' }, 331 | { "remote", required_argument, NULL, 'r' }, 332 | { "local", no_argument, NULL, 'l' }, 333 | { "device", no_argument, NULL, 'd' }, 334 | { NULL, 0, NULL, 0 } 335 | }; 336 | 337 | bool parsable = false; 338 | int opt; 339 | int ret = -1; 340 | 341 | if (usbip_names_init(USBIDS_FILE)) 342 | err("failed to open %s", USBIDS_FILE); 343 | 344 | for (;;) { 345 | opt = getopt_long(argc, argv, "pr:ld", opts, NULL); 346 | 347 | if (opt == -1) 348 | break; 349 | 350 | switch (opt) { 351 | case 'p': 352 | parsable = true; 353 | break; 354 | case 'r': 355 | ret = list_exported_devices(optarg); 356 | goto out; 357 | case 'l': 358 | ret = list_devices(parsable); 359 | goto out; 360 | case 'd': 361 | ret = list_gadget_devices(parsable); 362 | goto out; 363 | default: 364 | goto err_out; 365 | } 366 | } 367 | 368 | err_out: 369 | usbip_list_usage(); 370 | out: 371 | usbip_names_free(); 372 | 373 | return ret; 374 | } 375 | -------------------------------------------------------------------------------- /libsrc/names.c: -------------------------------------------------------------------------------- 1 | /* 2 | * names.c -- USB name database manipulation routines 3 | * 4 | * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * Copyright (C) 2005 Takahiro Hirofuchi 25 | * - names_deinit() is added. 26 | * 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "names.h" 41 | #include "usbip_common.h" 42 | 43 | struct vendor { 44 | struct vendor *next; 45 | u_int16_t vendorid; 46 | char name[1]; 47 | }; 48 | 49 | struct product { 50 | struct product *next; 51 | u_int16_t vendorid, productid; 52 | char name[1]; 53 | }; 54 | 55 | struct class { 56 | struct class *next; 57 | u_int8_t classid; 58 | char name[1]; 59 | }; 60 | 61 | struct subclass { 62 | struct subclass *next; 63 | u_int8_t classid, subclassid; 64 | char name[1]; 65 | }; 66 | 67 | struct protocol { 68 | struct protocol *next; 69 | u_int8_t classid, subclassid, protocolid; 70 | char name[1]; 71 | }; 72 | 73 | struct genericstrtable { 74 | struct genericstrtable *next; 75 | unsigned int num; 76 | char name[1]; 77 | }; 78 | 79 | 80 | #define HASH1 0x10 81 | #define HASH2 0x02 82 | #define HASHSZ 16 83 | 84 | static unsigned int hashnum(unsigned int num) 85 | { 86 | unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27; 87 | 88 | for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1) 89 | if (num & mask1) 90 | num ^= mask2; 91 | return num & (HASHSZ-1); 92 | } 93 | 94 | 95 | static struct vendor *vendors[HASHSZ] = { NULL, }; 96 | static struct product *products[HASHSZ] = { NULL, }; 97 | static struct class *classes[HASHSZ] = { NULL, }; 98 | static struct subclass *subclasses[HASHSZ] = { NULL, }; 99 | static struct protocol *protocols[HASHSZ] = { NULL, }; 100 | 101 | const char *names_vendor(u_int16_t vendorid) 102 | { 103 | struct vendor *v; 104 | 105 | v = vendors[hashnum(vendorid)]; 106 | for (; v; v = v->next) 107 | if (v->vendorid == vendorid) 108 | return v->name; 109 | return NULL; 110 | } 111 | 112 | const char *names_product(u_int16_t vendorid, u_int16_t productid) 113 | { 114 | struct product *p; 115 | 116 | p = products[hashnum((vendorid << 16) | productid)]; 117 | for (; p; p = p->next) 118 | if (p->vendorid == vendorid && p->productid == productid) 119 | return p->name; 120 | return NULL; 121 | } 122 | 123 | const char *names_class(u_int8_t classid) 124 | { 125 | struct class *c; 126 | 127 | c = classes[hashnum(classid)]; 128 | for (; c; c = c->next) 129 | if (c->classid == classid) 130 | return c->name; 131 | return NULL; 132 | } 133 | 134 | const char *names_subclass(u_int8_t classid, u_int8_t subclassid) 135 | { 136 | struct subclass *s; 137 | 138 | s = subclasses[hashnum((classid << 8) | subclassid)]; 139 | for (; s; s = s->next) 140 | if (s->classid == classid && s->subclassid == subclassid) 141 | return s->name; 142 | return NULL; 143 | } 144 | 145 | const char *names_protocol(u_int8_t classid, u_int8_t subclassid, 146 | u_int8_t protocolid) 147 | { 148 | struct protocol *p; 149 | 150 | p = protocols[hashnum((classid << 16) | (subclassid << 8) 151 | | protocolid)]; 152 | for (; p; p = p->next) 153 | if (p->classid == classid && p->subclassid == subclassid && 154 | p->protocolid == protocolid) 155 | return p->name; 156 | return NULL; 157 | } 158 | 159 | /* add a cleanup function by takahiro */ 160 | struct pool { 161 | struct pool *next; 162 | void *mem; 163 | }; 164 | 165 | static struct pool *pool_head; 166 | 167 | static void *my_malloc(size_t size) 168 | { 169 | struct pool *p; 170 | 171 | p = calloc(1, sizeof(struct pool)); 172 | if (!p) 173 | return NULL; 174 | 175 | p->mem = calloc(1, size); 176 | if (!p->mem) { 177 | free(p); 178 | return NULL; 179 | } 180 | 181 | p->next = pool_head; 182 | pool_head = p; 183 | 184 | return p->mem; 185 | } 186 | 187 | void names_free(void) 188 | { 189 | struct pool *pool; 190 | 191 | if (!pool_head) 192 | return; 193 | 194 | for (pool = pool_head; pool != NULL; ) { 195 | struct pool *tmp; 196 | 197 | if (pool->mem) 198 | free(pool->mem); 199 | 200 | tmp = pool; 201 | pool = pool->next; 202 | free(tmp); 203 | } 204 | } 205 | 206 | static int new_vendor(const char *name, u_int16_t vendorid) 207 | { 208 | struct vendor *v; 209 | unsigned int h = hashnum(vendorid); 210 | 211 | v = vendors[h]; 212 | for (; v; v = v->next) 213 | if (v->vendorid == vendorid) 214 | return -1; 215 | v = my_malloc(sizeof(struct vendor) + strlen(name)); 216 | if (!v) 217 | return -1; 218 | strcpy(v->name, name); 219 | v->vendorid = vendorid; 220 | v->next = vendors[h]; 221 | vendors[h] = v; 222 | return 0; 223 | } 224 | 225 | static int new_product(const char *name, u_int16_t vendorid, 226 | u_int16_t productid) 227 | { 228 | struct product *p; 229 | unsigned int h = hashnum((vendorid << 16) | productid); 230 | 231 | p = products[h]; 232 | for (; p; p = p->next) 233 | if (p->vendorid == vendorid && p->productid == productid) 234 | return -1; 235 | p = my_malloc(sizeof(struct product) + strlen(name)); 236 | if (!p) 237 | return -1; 238 | strcpy(p->name, name); 239 | p->vendorid = vendorid; 240 | p->productid = productid; 241 | p->next = products[h]; 242 | products[h] = p; 243 | return 0; 244 | } 245 | 246 | static int new_class(const char *name, u_int8_t classid) 247 | { 248 | struct class *c; 249 | unsigned int h = hashnum(classid); 250 | 251 | c = classes[h]; 252 | for (; c; c = c->next) 253 | if (c->classid == classid) 254 | return -1; 255 | c = my_malloc(sizeof(struct class) + strlen(name)); 256 | if (!c) 257 | return -1; 258 | strcpy(c->name, name); 259 | c->classid = classid; 260 | c->next = classes[h]; 261 | classes[h] = c; 262 | return 0; 263 | } 264 | 265 | static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) 266 | { 267 | struct subclass *s; 268 | unsigned int h = hashnum((classid << 8) | subclassid); 269 | 270 | s = subclasses[h]; 271 | for (; s; s = s->next) 272 | if (s->classid == classid && s->subclassid == subclassid) 273 | return -1; 274 | s = my_malloc(sizeof(struct subclass) + strlen(name)); 275 | if (!s) 276 | return -1; 277 | strcpy(s->name, name); 278 | s->classid = classid; 279 | s->subclassid = subclassid; 280 | s->next = subclasses[h]; 281 | subclasses[h] = s; 282 | return 0; 283 | } 284 | 285 | static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, 286 | u_int8_t protocolid) 287 | { 288 | struct protocol *p; 289 | unsigned int h = hashnum((classid << 16) | (subclassid << 8) 290 | | protocolid); 291 | 292 | p = protocols[h]; 293 | for (; p; p = p->next) 294 | if (p->classid == classid && p->subclassid == subclassid 295 | && p->protocolid == protocolid) 296 | return -1; 297 | p = my_malloc(sizeof(struct protocol) + strlen(name)); 298 | if (!p) 299 | return -1; 300 | strcpy(p->name, name); 301 | p->classid = classid; 302 | p->subclassid = subclassid; 303 | p->protocolid = protocolid; 304 | p->next = protocols[h]; 305 | protocols[h] = p; 306 | return 0; 307 | } 308 | 309 | static void parse(FILE *f) 310 | { 311 | char buf[512], *cp; 312 | unsigned int linectr = 0; 313 | int lastvendor = -1; 314 | int lastclass = -1; 315 | int lastsubclass = -1; 316 | int lasthut = -1; 317 | int lastlang = -1; 318 | unsigned int u; 319 | 320 | while (fgets(buf, sizeof(buf), f)) { 321 | linectr++; 322 | /* remove line ends */ 323 | cp = strchr(buf, '\r'); 324 | if (cp) 325 | *cp = 0; 326 | cp = strchr(buf, '\n'); 327 | if (cp) 328 | *cp = 0; 329 | if (buf[0] == '#' || !buf[0]) 330 | continue; 331 | cp = buf; 332 | if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && 333 | buf[3] == 'S' && buf[4] == 'D' && 334 | buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ 335 | buf[7] == ' ') { 336 | continue; 337 | } 338 | if (buf[0] == 'P' && buf[1] == 'H' && 339 | buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { 340 | continue; 341 | } 342 | if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && 343 | buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { 344 | continue; 345 | } 346 | if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { 347 | lasthut = lastclass = lastvendor = lastsubclass = -1; 348 | /* 349 | * set 1 as pseudo-id to indicate that the parser is 350 | * in a `L' section. 351 | */ 352 | lastlang = 1; 353 | continue; 354 | } 355 | if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { 356 | /* class spec */ 357 | cp = buf+2; 358 | while (isspace(*cp)) 359 | cp++; 360 | if (!isxdigit(*cp)) { 361 | err("Invalid class spec at line %u", linectr); 362 | continue; 363 | } 364 | u = strtoul(cp, &cp, 16); 365 | while (isspace(*cp)) 366 | cp++; 367 | if (!*cp) { 368 | err("Invalid class spec at line %u", linectr); 369 | continue; 370 | } 371 | if (new_class(cp, u)) 372 | err("Duplicate class spec at line %u class %04x %s", 373 | linectr, u, cp); 374 | dbg("line %5u class %02x %s", linectr, u, cp); 375 | lasthut = lastlang = lastvendor = lastsubclass = -1; 376 | lastclass = u; 377 | continue; 378 | } 379 | if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { 380 | /* audio terminal type spec */ 381 | continue; 382 | } 383 | if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' 384 | && isspace(buf[3])) { 385 | /* HID Descriptor bCountryCode */ 386 | continue; 387 | } 388 | if (isxdigit(*cp)) { 389 | /* vendor */ 390 | u = strtoul(cp, &cp, 16); 391 | while (isspace(*cp)) 392 | cp++; 393 | if (!*cp) { 394 | err("Invalid vendor spec at line %u", linectr); 395 | continue; 396 | } 397 | if (new_vendor(cp, u)) 398 | err("Duplicate vendor spec at line %u vendor %04x %s", 399 | linectr, u, cp); 400 | dbg("line %5u vendor %04x %s", linectr, u, cp); 401 | lastvendor = u; 402 | lasthut = lastlang = lastclass = lastsubclass = -1; 403 | continue; 404 | } 405 | if (buf[0] == '\t' && isxdigit(buf[1])) { 406 | /* product or subclass spec */ 407 | u = strtoul(buf+1, &cp, 16); 408 | while (isspace(*cp)) 409 | cp++; 410 | if (!*cp) { 411 | err("Invalid product/subclass spec at line %u", 412 | linectr); 413 | continue; 414 | } 415 | if (lastvendor != -1) { 416 | if (new_product(cp, lastvendor, u)) 417 | err("Duplicate product spec at line %u product %04x:%04x %s", 418 | linectr, lastvendor, u, cp); 419 | dbg("line %5u product %04x:%04x %s", linectr, 420 | lastvendor, u, cp); 421 | continue; 422 | } 423 | if (lastclass != -1) { 424 | if (new_subclass(cp, lastclass, u)) 425 | err("Duplicate subclass spec at line %u class %02x:%02x %s", 426 | linectr, lastclass, u, cp); 427 | dbg("line %5u subclass %02x:%02x %s", linectr, 428 | lastclass, u, cp); 429 | lastsubclass = u; 430 | continue; 431 | } 432 | if (lasthut != -1) { 433 | /* do not store hut */ 434 | continue; 435 | } 436 | if (lastlang != -1) { 437 | /* do not store langid */ 438 | continue; 439 | } 440 | err("Product/Subclass spec without prior Vendor/Class spec at line %u", 441 | linectr); 442 | continue; 443 | } 444 | if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { 445 | /* protocol spec */ 446 | u = strtoul(buf+2, &cp, 16); 447 | while (isspace(*cp)) 448 | cp++; 449 | if (!*cp) { 450 | err("Invalid protocol spec at line %u", 451 | linectr); 452 | continue; 453 | } 454 | if (lastclass != -1 && lastsubclass != -1) { 455 | if (new_protocol(cp, lastclass, lastsubclass, 456 | u)) 457 | err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", 458 | linectr, lastclass, lastsubclass, 459 | u, cp); 460 | dbg("line %5u protocol %02x:%02x:%02x %s", 461 | linectr, lastclass, lastsubclass, u, cp); 462 | continue; 463 | } 464 | err("Protocol spec without prior Class and Subclass spec at line %u", 465 | linectr); 466 | continue; 467 | } 468 | if (buf[0] == 'H' && buf[1] == 'I' && 469 | buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { 470 | continue; 471 | } 472 | if (buf[0] == 'H' && buf[1] == 'U' && 473 | buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { 474 | lastlang = lastclass = lastvendor = lastsubclass = -1; 475 | /* 476 | * set 1 as pseudo-id to indicate that the parser is 477 | * in a `HUT' section. 478 | */ 479 | lasthut = 1; 480 | continue; 481 | } 482 | if (buf[0] == 'R' && buf[1] == ' ') 483 | continue; 484 | 485 | if (buf[0] == 'V' && buf[1] == 'T') 486 | continue; 487 | 488 | err("Unknown line at line %u", linectr); 489 | } 490 | } 491 | 492 | 493 | int names_init(char *n) 494 | { 495 | FILE *f; 496 | 497 | f = fopen(n, "r"); 498 | if (!f) 499 | return errno; 500 | 501 | parse(f); 502 | fclose(f); 503 | return 0; 504 | } 505 | -------------------------------------------------------------------------------- /src/usbipd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 matt mooney 3 | * 2005-2007 Takahiro Hirofuchi 4 | * Copyright (C) 2015-2016 Samsung Electronics 5 | * Igor Kotrasinski 6 | * Krzysztof Opasiak 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | 22 | #ifdef HAVE_CONFIG_H 23 | #include "../config.h" 24 | #endif 25 | 26 | #define _GNU_SOURCE 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef HAVE_LIBWRAP 39 | #include 40 | #endif 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include "usbip_host_driver.h" 47 | #include "usbip_host_common.h" 48 | #include "usbip_device_driver.h" 49 | #include "usbip_common.h" 50 | #include "usbip_network.h" 51 | #include "list.h" 52 | 53 | #undef PROGNAME 54 | #define PROGNAME "usbipd" 55 | #define MAXSOCKFD 20 56 | 57 | #define MAIN_LOOP_TIMEOUT 10 58 | 59 | #define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid" 60 | 61 | static const char usbip_version_string[] = PACKAGE_STRING; 62 | 63 | static const char usbipd_help_string[] = 64 | "usage: usbipd [options]\n" 65 | "\n" 66 | " -4, --ipv4\n" 67 | " Bind to IPv4. Default is both.\n" 68 | "\n" 69 | " -6, --ipv6\n" 70 | " Bind to IPv6. Default is both.\n" 71 | "\n" 72 | " -e, --device\n" 73 | " Run in device mode.\n" 74 | " Rather than drive an attached device, create\n" 75 | " a virtual UDC to bind gadgets to.\n" 76 | "\n" 77 | " -D, --daemon\n" 78 | " Run as a daemon process.\n" 79 | "\n" 80 | " -d, --debug\n" 81 | " Print debugging information.\n" 82 | "\n" 83 | " -PFILE, --pid FILE\n" 84 | " Write process id to FILE.\n" 85 | " If no FILE specified, use " DEFAULT_PID_FILE "\n" 86 | "\n" 87 | " -tPORT, --tcp-port PORT\n" 88 | " Listen on TCP/IP port PORT.\n" 89 | "\n" 90 | " -h, --help\n" 91 | " Print this help.\n" 92 | "\n" 93 | " -v, --version\n" 94 | " Show version.\n"; 95 | 96 | static struct usbip_host_driver *driver; 97 | 98 | static void usbipd_help(void) 99 | { 100 | printf("%s\n", usbipd_help_string); 101 | } 102 | 103 | static int recv_request_import(int sockfd) 104 | { 105 | struct op_import_request req; 106 | struct usbip_exported_device *edev; 107 | struct usbip_usb_device pdu_udev; 108 | struct list_head *i; 109 | int found = 0; 110 | int error = 0; 111 | int rc; 112 | 113 | memset(&req, 0, sizeof(req)); 114 | 115 | rc = usbip_net_recv(sockfd, &req, sizeof(req)); 116 | if (rc < 0) { 117 | dbg("usbip_net_recv failed: import request"); 118 | return -1; 119 | } 120 | PACK_OP_IMPORT_REQUEST(0, &req); 121 | 122 | list_for_each(i, &driver->edev_list) { 123 | edev = list_entry(i, struct usbip_exported_device, node); 124 | if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { 125 | info("found requested device: %s", req.busid); 126 | found = 1; 127 | break; 128 | } 129 | } 130 | 131 | if (found) { 132 | /* should set TCP_NODELAY for usbip */ 133 | usbip_net_set_nodelay(sockfd); 134 | 135 | /* export device needs a TCP/IP socket descriptor */ 136 | rc = usbip_export_device(edev, sockfd); 137 | if (rc < 0) 138 | error = 1; 139 | } else { 140 | info("requested device not found: %s", req.busid); 141 | error = 1; 142 | } 143 | 144 | rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT, 145 | (!error ? ST_OK : ST_NA)); 146 | if (rc < 0) { 147 | dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT); 148 | return -1; 149 | } 150 | 151 | if (error) { 152 | dbg("import request busid %s: failed", req.busid); 153 | return -1; 154 | } 155 | 156 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); 157 | usbip_net_pack_usb_device(1, &pdu_udev); 158 | 159 | rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev)); 160 | if (rc < 0) { 161 | dbg("usbip_net_send failed: devinfo"); 162 | return -1; 163 | } 164 | 165 | dbg("import request busid %s: complete", req.busid); 166 | 167 | return 0; 168 | } 169 | 170 | static int send_reply_devlist(int connfd) 171 | { 172 | struct usbip_exported_device *edev; 173 | struct usbip_usb_device pdu_udev; 174 | struct usbip_usb_interface pdu_uinf; 175 | struct op_devlist_reply reply; 176 | struct list_head *j; 177 | int rc, i; 178 | 179 | reply.ndev = 0; 180 | /* number of exported devices */ 181 | list_for_each(j, &driver->edev_list) { 182 | reply.ndev += 1; 183 | } 184 | info("exportable devices: %d", reply.ndev); 185 | 186 | rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK); 187 | if (rc < 0) { 188 | dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST); 189 | return -1; 190 | } 191 | PACK_OP_DEVLIST_REPLY(1, &reply); 192 | 193 | rc = usbip_net_send(connfd, &reply, sizeof(reply)); 194 | if (rc < 0) { 195 | dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST); 196 | return -1; 197 | } 198 | 199 | list_for_each(j, &driver->edev_list) { 200 | edev = list_entry(j, struct usbip_exported_device, node); 201 | dump_usb_device(&edev->udev); 202 | memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); 203 | usbip_net_pack_usb_device(1, &pdu_udev); 204 | 205 | rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev)); 206 | if (rc < 0) { 207 | dbg("usbip_net_send failed: pdu_udev"); 208 | return -1; 209 | } 210 | 211 | for (i = 0; i < edev->udev.bNumInterfaces; i++) { 212 | dump_usb_interface(&edev->uinf[i]); 213 | memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf)); 214 | usbip_net_pack_usb_interface(1, &pdu_uinf); 215 | 216 | rc = usbip_net_send(connfd, &pdu_uinf, 217 | sizeof(pdu_uinf)); 218 | if (rc < 0) { 219 | err("usbip_net_send failed: pdu_uinf"); 220 | return -1; 221 | } 222 | } 223 | } 224 | 225 | return 0; 226 | } 227 | 228 | static int recv_request_devlist(int connfd) 229 | { 230 | struct op_devlist_request req; 231 | int rc; 232 | 233 | memset(&req, 0, sizeof(req)); 234 | 235 | rc = usbip_net_recv(connfd, &req, sizeof(req)); 236 | if (rc < 0) { 237 | dbg("usbip_net_recv failed: devlist request"); 238 | return -1; 239 | } 240 | 241 | rc = send_reply_devlist(connfd); 242 | if (rc < 0) { 243 | dbg("send_reply_devlist failed"); 244 | return -1; 245 | } 246 | 247 | return 0; 248 | } 249 | 250 | static int recv_pdu(int connfd) 251 | { 252 | uint16_t code = OP_UNSPEC; 253 | int ret; 254 | 255 | ret = usbip_net_recv_op_common(connfd, &code); 256 | if (ret < 0) { 257 | dbg("could not receive opcode: %#0x", code); 258 | return -1; 259 | } 260 | 261 | ret = usbip_refresh_device_list(driver); 262 | if (ret < 0) { 263 | dbg("could not refresh device list: %d", ret); 264 | return -1; 265 | } 266 | 267 | info("received request: %#0x(%d)", code, connfd); 268 | switch (code) { 269 | case OP_REQ_DEVLIST: 270 | ret = recv_request_devlist(connfd); 271 | break; 272 | case OP_REQ_IMPORT: 273 | ret = recv_request_import(connfd); 274 | break; 275 | case OP_REQ_DEVINFO: 276 | case OP_REQ_CRYPKEY: 277 | default: 278 | err("received an unknown opcode: %#0x", code); 279 | ret = -1; 280 | } 281 | 282 | if (ret == 0) 283 | info("request %#0x(%d): complete", code, connfd); 284 | else 285 | info("request %#0x(%d): failed", code, connfd); 286 | 287 | return ret; 288 | } 289 | 290 | #ifdef HAVE_LIBWRAP 291 | static int tcpd_auth(int connfd) 292 | { 293 | struct request_info request; 294 | int rc; 295 | 296 | request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0); 297 | fromhost(&request); 298 | rc = hosts_access(&request); 299 | if (rc == 0) 300 | return -1; 301 | 302 | return 0; 303 | } 304 | #endif 305 | 306 | static int do_accept(int listenfd) 307 | { 308 | int connfd; 309 | struct sockaddr_storage ss; 310 | socklen_t len = sizeof(ss); 311 | char host[NI_MAXHOST], port[NI_MAXSERV]; 312 | int rc; 313 | 314 | memset(&ss, 0, sizeof(ss)); 315 | 316 | connfd = accept(listenfd, (struct sockaddr *)&ss, &len); 317 | if (connfd < 0) { 318 | err("failed to accept connection"); 319 | return -1; 320 | } 321 | 322 | rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host), 323 | port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); 324 | if (rc) 325 | err("getnameinfo: %s", gai_strerror(rc)); 326 | 327 | #ifdef HAVE_LIBWRAP 328 | rc = tcpd_auth(connfd); 329 | if (rc < 0) { 330 | info("denied access from %s", host); 331 | close(connfd); 332 | return -1; 333 | } 334 | #endif 335 | info("connection from %s:%s", host, port); 336 | 337 | return connfd; 338 | } 339 | 340 | int process_request(int listenfd) 341 | { 342 | pid_t childpid; 343 | int connfd; 344 | 345 | connfd = do_accept(listenfd); 346 | if (connfd < 0) 347 | return -1; 348 | childpid = fork(); 349 | if (childpid == 0) { 350 | close(listenfd); 351 | recv_pdu(connfd); 352 | exit(0); 353 | } 354 | close(connfd); 355 | return 0; 356 | } 357 | 358 | static void addrinfo_to_text(struct addrinfo *ai, char buf[], 359 | const size_t buf_size) 360 | { 361 | char hbuf[NI_MAXHOST]; 362 | char sbuf[NI_MAXSERV]; 363 | int rc; 364 | 365 | buf[0] = '\0'; 366 | 367 | rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), 368 | sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); 369 | if (rc) 370 | err("getnameinfo: %s", gai_strerror(rc)); 371 | 372 | snprintf(buf, buf_size, "%s:%s", hbuf, sbuf); 373 | } 374 | 375 | static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], 376 | int maxsockfd) 377 | { 378 | struct addrinfo *ai; 379 | int ret, nsockfd = 0; 380 | const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2; 381 | char ai_buf[ai_buf_size]; 382 | 383 | for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) { 384 | int sock; 385 | 386 | addrinfo_to_text(ai, ai_buf, ai_buf_size); 387 | dbg("opening %s", ai_buf); 388 | sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 389 | if (sock < 0) { 390 | err("socket: %s: %d (%s)", 391 | ai_buf, errno, strerror(errno)); 392 | continue; 393 | } 394 | 395 | usbip_net_set_reuseaddr(sock); 396 | usbip_net_set_nodelay(sock); 397 | /* We use seperate sockets for IPv4 and IPv6 398 | * (see do_standalone_mode()) */ 399 | usbip_net_set_v6only(sock); 400 | 401 | if (sock >= FD_SETSIZE) { 402 | err("FD_SETSIZE: %s: sock=%d, max=%d", 403 | ai_buf, sock, FD_SETSIZE); 404 | close(sock); 405 | continue; 406 | } 407 | 408 | ret = bind(sock, ai->ai_addr, ai->ai_addrlen); 409 | if (ret < 0) { 410 | err("bind: %s: %d (%s)", 411 | ai_buf, errno, strerror(errno)); 412 | close(sock); 413 | continue; 414 | } 415 | 416 | ret = listen(sock, SOMAXCONN); 417 | if (ret < 0) { 418 | err("listen: %s: %d (%s)", 419 | ai_buf, errno, strerror(errno)); 420 | close(sock); 421 | continue; 422 | } 423 | 424 | info("listening on %s", ai_buf); 425 | sockfdlist[nsockfd++] = sock; 426 | } 427 | 428 | return nsockfd; 429 | } 430 | 431 | static struct addrinfo *do_getaddrinfo(char *host, int ai_family) 432 | { 433 | struct addrinfo hints, *ai_head; 434 | int rc; 435 | 436 | memset(&hints, 0, sizeof(hints)); 437 | hints.ai_family = ai_family; 438 | hints.ai_socktype = SOCK_STREAM; 439 | hints.ai_flags = AI_PASSIVE; 440 | 441 | rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head); 442 | if (rc) { 443 | err("failed to get a network address %s: %s", usbip_port_string, 444 | gai_strerror(rc)); 445 | return NULL; 446 | } 447 | 448 | return ai_head; 449 | } 450 | 451 | static void signal_handler(int i) 452 | { 453 | dbg("received '%s' signal", strsignal(i)); 454 | } 455 | 456 | static void set_signal(void) 457 | { 458 | struct sigaction act; 459 | 460 | memset(&act, 0, sizeof(act)); 461 | act.sa_handler = signal_handler; 462 | sigemptyset(&act.sa_mask); 463 | sigaction(SIGTERM, &act, NULL); 464 | sigaction(SIGINT, &act, NULL); 465 | act.sa_handler = SIG_IGN; 466 | sigaction(SIGCLD, &act, NULL); 467 | } 468 | 469 | static const char *pid_file; 470 | 471 | static void write_pid_file(void) 472 | { 473 | if (pid_file) { 474 | dbg("creating pid file %s", pid_file); 475 | FILE *fp; 476 | 477 | fp = fopen(pid_file, "w"); 478 | if (!fp) { 479 | err("pid_file: %s: %d (%s)", 480 | pid_file, errno, strerror(errno)); 481 | return; 482 | } 483 | fprintf(fp, "%d\n", getpid()); 484 | fclose(fp); 485 | } 486 | } 487 | 488 | static void remove_pid_file(void) 489 | { 490 | if (pid_file) { 491 | dbg("removing pid file %s", pid_file); 492 | unlink(pid_file); 493 | } 494 | } 495 | 496 | static int do_standalone_mode(int daemonize, int ipv4, int ipv6) 497 | { 498 | struct addrinfo *ai_head; 499 | int sockfdlist[MAXSOCKFD]; 500 | int nsockfd, family; 501 | int i, terminate; 502 | struct pollfd *fds; 503 | struct timespec timeout; 504 | sigset_t sigmask; 505 | 506 | if (usbip_driver_open(driver)) 507 | return -1; 508 | 509 | if (daemonize) { 510 | if (daemon(0, 0) < 0) { 511 | err("daemonizing failed: %s", strerror(errno)); 512 | usbip_driver_close(driver); 513 | return -1; 514 | } 515 | umask(0); 516 | usbip_use_syslog = 1; 517 | } 518 | set_signal(); 519 | write_pid_file(); 520 | 521 | info("starting " PROGNAME " (%s)", usbip_version_string); 522 | 523 | /* 524 | * To suppress warnings on systems with bindv6only disabled 525 | * (default), we use seperate sockets for IPv6 and IPv4 and set 526 | * IPV6_V6ONLY on the IPv6 sockets. 527 | */ 528 | if (ipv4 && ipv6) 529 | family = AF_UNSPEC; 530 | else if (ipv4) 531 | family = AF_INET; 532 | else 533 | family = AF_INET6; 534 | 535 | ai_head = do_getaddrinfo(NULL, family); 536 | if (!ai_head) { 537 | usbip_driver_close(driver); 538 | return -1; 539 | } 540 | nsockfd = listen_all_addrinfo(ai_head, sockfdlist, 541 | sizeof(sockfdlist) / sizeof(*sockfdlist)); 542 | freeaddrinfo(ai_head); 543 | if (nsockfd <= 0) { 544 | err("failed to open a listening socket"); 545 | usbip_driver_close(driver); 546 | return -1; 547 | } 548 | 549 | dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); 550 | 551 | fds = calloc(nsockfd, sizeof(struct pollfd)); 552 | for (i = 0; i < nsockfd; i++) { 553 | fds[i].fd = sockfdlist[i]; 554 | fds[i].events = POLLIN; 555 | } 556 | timeout.tv_sec = MAIN_LOOP_TIMEOUT; 557 | timeout.tv_nsec = 0; 558 | 559 | sigfillset(&sigmask); 560 | sigdelset(&sigmask, SIGTERM); 561 | sigdelset(&sigmask, SIGINT); 562 | 563 | terminate = 0; 564 | while (!terminate) { 565 | int r; 566 | 567 | r = ppoll(fds, nsockfd, &timeout, &sigmask); 568 | if (r < 0) { 569 | dbg("%s", strerror(errno)); 570 | terminate = 1; 571 | } else if (r) { 572 | for (i = 0; i < nsockfd; i++) { 573 | if (fds[i].revents & POLLIN) { 574 | dbg("read event on fd[%d]=%d", 575 | i, sockfdlist[i]); 576 | process_request(sockfdlist[i]); 577 | } 578 | } 579 | } else { 580 | dbg("heartbeat timeout on ppoll()"); 581 | } 582 | } 583 | 584 | info("shutting down " PROGNAME); 585 | free(fds); 586 | usbip_driver_close(driver); 587 | 588 | return 0; 589 | } 590 | 591 | int main(int argc, char *argv[]) 592 | { 593 | static const struct option longopts[] = { 594 | { "ipv4", no_argument, NULL, '4' }, 595 | { "ipv6", no_argument, NULL, '6' }, 596 | { "daemon", no_argument, NULL, 'D' }, 597 | { "daemon", no_argument, NULL, 'D' }, 598 | { "debug", no_argument, NULL, 'd' }, 599 | { "device", no_argument, NULL, 'e' }, 600 | { "pid", optional_argument, NULL, 'P' }, 601 | { "tcp-port", required_argument, NULL, 't' }, 602 | { "help", no_argument, NULL, 'h' }, 603 | { "version", no_argument, NULL, 'v' }, 604 | { NULL, 0, NULL, 0 } 605 | }; 606 | 607 | enum { 608 | cmd_standalone_mode = 1, 609 | cmd_help, 610 | cmd_version 611 | } cmd; 612 | 613 | int daemonize = 0; 614 | int ipv4 = 0, ipv6 = 0; 615 | int opt, rc = -1; 616 | 617 | pid_file = NULL; 618 | 619 | usbip_use_stderr = 1; 620 | usbip_use_syslog = 0; 621 | 622 | if (geteuid() != 0) 623 | err("not running as root?"); 624 | 625 | cmd = cmd_standalone_mode; 626 | driver = &host_driver; 627 | for (;;) { 628 | opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL); 629 | 630 | if (opt == -1) 631 | break; 632 | 633 | switch (opt) { 634 | case '4': 635 | ipv4 = 1; 636 | break; 637 | case '6': 638 | ipv6 = 1; 639 | break; 640 | case 'D': 641 | daemonize = 1; 642 | break; 643 | case 'd': 644 | usbip_use_debug = 1; 645 | break; 646 | case 'h': 647 | cmd = cmd_help; 648 | break; 649 | case 'P': 650 | pid_file = optarg ? optarg : DEFAULT_PID_FILE; 651 | break; 652 | case 't': 653 | usbip_setup_port_number(optarg); 654 | break; 655 | case 'v': 656 | cmd = cmd_version; 657 | break; 658 | case 'e': 659 | driver = &device_driver; 660 | break; 661 | case '?': 662 | usbipd_help(); 663 | default: 664 | goto err_out; 665 | } 666 | } 667 | 668 | if (!ipv4 && !ipv6) 669 | ipv4 = ipv6 = 1; 670 | 671 | switch (cmd) { 672 | case cmd_standalone_mode: 673 | rc = do_standalone_mode(daemonize, ipv4, ipv6); 674 | remove_pid_file(); 675 | break; 676 | case cmd_version: 677 | printf(PROGNAME " (%s)\n", usbip_version_string); 678 | rc = 0; 679 | break; 680 | case cmd_help: 681 | usbipd_help(); 682 | rc = 0; 683 | break; 684 | default: 685 | usbipd_help(); 686 | goto err_out; 687 | } 688 | 689 | err_out: 690 | return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE); 691 | } 692 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | --------------------------------------------------------------------------------