This patch is the new application(vhci)-side daemon specific code. The daemons are consisting three files. usbip.c : common code. usbip_dev.c: device(stub)-side specific code. usbip_app.c: application(vhci)-side specific code - this patch. Here, device-side daemon is EXISTING-1 and application-side daemon is NEW-1 in figure below. EXISTING) - invites devices from application(vhci)-side +------+ +------------------+ device--+ STUB | | application/VHCI | +------+ +------------------+ 1) usbipd ... start daemon = = = 2) usbip list --local 3) usbip bind <--- list bound devices --- 4) usbip list --remote <--- import a device ------ 5) usbip attach = = = X disconnected 6) usbip detach 7) usbip unbind NEW) - dedicates devices from device(stb)-side +------+ +------------------+ device--+ STUB | | application/VHCI | +------+ +------------------+ 1) usbipa ... start daemon = = = 2) usbip list --local 3) usbip connect --- export a device ------> = = = 4) usbip disconnect --- un-export a device ---> Signed-off-by: Nobuo Iwata <nobuo.iwata@xxxxxxxxxxxxxxx> --- tools/usb/usbip/libsrc/vhci_driver.c | 19 +++ tools/usb/usbip/libsrc/vhci_driver.h | 1 + tools/usb/usbip/src/Makefile.am | 7 +- tools/usb/usbip/src/usbipd.c | 12 +- tools/usb/usbip/src/usbipd_app.c | 242 +++++++++++++++++++++++++++ 5 files changed, 279 insertions(+), 2 deletions(-) diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c index d2221c5..3fe92ff 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.c +++ b/tools/usb/usbip/libsrc/vhci_driver.c @@ -314,6 +314,25 @@ int usbip_vhci_get_free_port(void) return -1; } +struct usbip_imported_device *usbip_vhci_find_device(char *host, char *busid) +{ + int ret; + char rhost[NI_MAXHOST] = "unknown host"; + char rserv[NI_MAXSERV] = "unknown port"; + char rbusid[SYSFS_BUS_ID_SIZE]; + + for (int i = 0; i < vhci_driver->nports; i++) { + ret = read_record(vhci_driver->idev[i].port, rhost, NI_MAXHOST, + rserv, NI_MAXSERV, rbusid); + if (!ret && + !strncmp(host, rhost, NI_MAXHOST) && + !strncmp(busid, rbusid, SYSFS_BUS_ID_SIZE)) { + return vhci_driver->idev + i; + } + } + return NULL; +} + int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, uint32_t speed) { char buff[200]; /* what size should be ? */ diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h index f955ada..acb427d 100644 --- a/tools/usb/usbip/libsrc/vhci_driver.h +++ b/tools/usb/usbip/libsrc/vhci_driver.h @@ -46,6 +46,7 @@ int usbip_vhci_refresh_device_list(void); int usbip_vhci_get_free_port(void); +struct usbip_imported_device *usbip_vhci_find_device(char *host, char *busid); int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, uint32_t speed); diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am index 1aa5156..8fdebce 100644 --- a/tools/usb/usbip/src/Makefile.am +++ b/tools/usb/usbip/src/Makefile.am @@ -2,11 +2,16 @@ AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' AM_CFLAGS = @EXTRA_CFLAGS@ LDADD = $(top_builddir)/libsrc/libusbip.la -sbin_PROGRAMS := usbip usbipd +sbin_PROGRAMS := usbip usbipd usbipa usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \ usbip_attach.c usbip_detach.c usbip_list.c \ usbip_bind.c usbip_unbind.c usbip_port.c \ usbip_connect.c usbip_disconnect.c +usbip_CFLAGS := $(AM_CFLAGS) usbipd_SOURCES := usbip_network.h usbipd.c usbipd_dev.c usbip_network.c +usbipd_CFLAGS := $(AM_CFLAGS) + +usbipa_SOURCES := usbip_network.h usbipd.c usbipd_app.c usbip_network.c +usbipa_CFLAGS := $(AM_CFLAGS) -DUSBIP_DAEMON_APP diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index bc4775f..8fe89d9 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c @@ -64,11 +64,13 @@ static const char usbipd_help_string[] = " -6, --ipv6\n" " Bind to IPv6. Default is both.\n" "\n" +#ifndef USBIP_DAEMON_APP " -e, --device\n" " Run in device mode.\n" " Rather than drive an attached device, create\n" " a virtual UDC to bind gadgets to.\n" "\n" +#endif " -D, --daemon\n" " Run as a daemon process.\n" "\n" @@ -397,7 +399,9 @@ int main(int argc, char *argv[]) { "ipv6", no_argument, NULL, '6' }, { "daemon", no_argument, NULL, 'D' }, { "debug", no_argument, NULL, 'd' }, +#ifndef USBIP_DAEMON_APP { "device", no_argument, NULL, 'e' }, +#endif { "pid", optional_argument, NULL, 'P' }, { "tcp-port", required_argument, NULL, 't' }, { "help", no_argument, NULL, 'h' }, @@ -426,7 +430,11 @@ int main(int argc, char *argv[]) cmd = cmd_standalone_mode; usbip_init_driver(); for (;;) { - opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL); + opt = getopt_long(argc, argv, "46Dd" +#ifndef USBIP_DAEMON_APP + "e" +#endif + "P::t:hv", longopts, NULL); if (opt == -1) break; @@ -456,9 +464,11 @@ int main(int argc, char *argv[]) case 'v': cmd = cmd_version; break; +#ifndef USBIP_DAEMON_APP case 'e': usbip_update_driver(); break; +#endif case '?': usbipd_help(); default: diff --git a/tools/usb/usbip/src/usbipd_app.c b/tools/usb/usbip/src/usbipd_app.c new file mode 100644 index 0000000..41f42f1 --- /dev/null +++ b/tools/usb/usbip/src/usbipd_app.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2015 Nobuo Iwata + * 2011 matt mooney <mfm@xxxxxxxxxxxxx> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + +#define _GNU_SOURCE +#include <errno.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> + +#include "vhci_driver.h" +#include "usbip_common.h" +#include "usbip_network.h" + +char *usbip_progname = "usbipa"; +char *usbip_default_pid_file = "/var/run/usbipa"; + +void usbip_init_driver(void) +{ +} + +int usbip_open_driver(void) +{ + if (usbip_vhci_driver_open()) { + err("please load " USBIP_CORE_MOD_NAME ".ko and " + USBIP_VHCI_DRV_NAME ".ko!"); + return -1; + } + return 0; +} + +void usbip_close_driver(void) +{ + usbip_vhci_driver_close(); +} + +static int import_device(int sockfd, struct usbip_usb_device *udev) +{ + int rc; + int port; + + dbg("Sockfd:%d", sockfd); + port = usbip_vhci_get_free_port(); + if (port < 0) { + err("no free port"); + return -1; + } + + dump_usb_device(udev); + rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, + udev->devnum, udev->speed); + if (rc < 0) { + err("import device"); + return -1; + } + + return port; +} + +static int recv_request_export(int sockfd, char *host, char *port) +{ + struct op_export_request req; + struct op_export_reply reply; + int rhport = 0; + int error = 0; + int rc; + + memset(&req, 0, sizeof(req)); + memset(&reply, 0, sizeof(reply)); + + rc = usbip_net_recv(sockfd, &req, sizeof(req)); + if (rc < 0) { + dbg("usbip_net_recv failed: export request"); + return -1; + } + PACK_OP_EXPORT_REQUEST(0, &req); + + rhport = import_device(sockfd, &req.udev); + if (rhport < 0) { + dbg("export request busid %s: failed", req.udev.busid); + error = 1; + } + + rc = usbip_net_send_op_common(sockfd, OP_REP_EXPORT, + (!error ? ST_OK : ST_NA)); + if (rc < 0) { + dbg("usbip_net_send_op_common failed: %#0x", OP_REP_EXPORT); + return -1; + } + + if (!error) + reply.returncode = 0; + else + reply.returncode = -1; + + PACK_OP_EXPORT_REPLY(0, &rep); + + rc = usbip_net_send(sockfd, &reply, sizeof(reply)); + if (rc < 0) { + dbg("usbip_net_send failed: export reply"); + return -1; + } + + rc = usbip_vhci_create_record(host, port, req.udev.busid, rhport); + if (rc < 0) { + err("record connection"); + return -1; + } + + dbg("export request busid %s: complete", req.udev.busid); + + return 0; +} + +static int unimport_device(char *host, struct usbip_usb_device *udev) +{ + int rc; + struct usbip_imported_device *idev; + + idev = usbip_vhci_find_device(host, udev->busid); + if (idev == NULL) { + err("no imported port %s %s", host, udev->busid); + return -1; + } + + rc = usbip_vhci_detach_device(idev->port); + if (rc < 0) { + err("no imported port %d %s %s", idev->port, host, udev->busid); + return -1; + } + return idev->port; +} + +static int recv_request_unexport(int sockfd, char *host) +{ + struct op_unexport_request req; + struct op_unexport_reply reply; + int rhport = 0; + int error = 0; + int rc; + + memset(&req, 0, sizeof(req)); + memset(&reply, 0, sizeof(reply)); + + rc = usbip_net_recv(sockfd, &req, sizeof(req)); + if (rc < 0) { + dbg("usbip_net_recv failed: unexport request"); + return -1; + } + PACK_OP_UNEXPORT_REQUEST(0, &req); + + rhport = unimport_device(host, &req.udev); + if (rhport < 0) + error = 1; + + rc = usbip_net_send_op_common(sockfd, OP_REP_UNEXPORT, + (!error ? ST_OK : ST_NA)); + if (rc < 0) { + dbg("usbip_net_send_op_common failed: %#0x", OP_REP_UNEXPORT); + return -1; + } + + if (!error) { + reply.returncode = 0; + } else { + reply.returncode = -1; + dbg("unexport request busid %s: failed", req.udev.busid); + return -1; + } + PACK_OP_UNEXPORT_REPLY(0, &rep); + + rc = usbip_net_send(sockfd, &reply, sizeof(reply)); + if (rc < 0) { + dbg("usbip_net_send failed: unexport reply"); + return -1; + } + + usbip_vhci_delete_record(rhport); + + dbg("unexport request busid %s: complete", req.udev.busid); + + return 0; +} + +int usbip_recv_pdu(int connfd, char *host, char *port) +{ + uint16_t code = OP_UNSPEC; + int ret; + + ret = usbip_net_recv_op_common(connfd, &code); + if (ret < 0) { + dbg("could not receive opcode: %#0x", code); + return -1; + } + + ret = usbip_vhci_refresh_device_list(); + if (ret < 0) { + dbg("could not refresh device list: %d", ret); + return -1; + } + + info("received request: %#0x(%d)", code, connfd); + switch (code) { + case OP_REQ_EXPORT: + ret = recv_request_export(connfd, host, port); + break; + case OP_REQ_UNEXPORT: + ret = recv_request_unexport(connfd, host); + break; + default: + err("received an unknown opcode: %#0x", code); + ret = -1; + } + + if (ret == 0) + info("request %#0x(%s:%s): complete", code, host, port); + else + info("request %#0x(%s:%s): failed", code, host, port); + + return ret; +} -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html