18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 48c2ecf20Sopenharmony_ci * 2005-2007 Takahiro Hirofuchi 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <ctype.h> 88c2ecf20Sopenharmony_ci#include <limits.h> 98c2ecf20Sopenharmony_ci#include <stdint.h> 108c2ecf20Sopenharmony_ci#include <stdio.h> 118c2ecf20Sopenharmony_ci#include <stdlib.h> 128c2ecf20Sopenharmony_ci#include <string.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <getopt.h> 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "vhci_driver.h" 188c2ecf20Sopenharmony_ci#include "usbip_common.h" 198c2ecf20Sopenharmony_ci#include "usbip_network.h" 208c2ecf20Sopenharmony_ci#include "usbip.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic const char usbip_detach_usage_string[] = 238c2ecf20Sopenharmony_ci "usbip detach <args>\n" 248c2ecf20Sopenharmony_ci " -p, --port=<port> " USBIP_VHCI_DRV_NAME 258c2ecf20Sopenharmony_ci " port the device is on\n"; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_civoid usbip_detach_usage(void) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci printf("usage: %s", usbip_detach_usage_string); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int detach_port(char *port) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci int ret = 0; 358c2ecf20Sopenharmony_ci uint8_t portnum; 368c2ecf20Sopenharmony_ci char path[PATH_MAX+1]; 378c2ecf20Sopenharmony_ci int i; 388c2ecf20Sopenharmony_ci struct usbip_imported_device *idev; 398c2ecf20Sopenharmony_ci int found = 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci unsigned int port_len = strlen(port); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci for (unsigned int i = 0; i < port_len; i++) 448c2ecf20Sopenharmony_ci if (!isdigit(port[i])) { 458c2ecf20Sopenharmony_ci err("invalid port %s", port); 468c2ecf20Sopenharmony_ci return -1; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci portnum = atoi(port); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci ret = usbip_vhci_driver_open(); 528c2ecf20Sopenharmony_ci if (ret < 0) { 538c2ecf20Sopenharmony_ci err("open vhci_driver"); 548c2ecf20Sopenharmony_ci return -1; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* check for invalid port */ 588c2ecf20Sopenharmony_ci for (i = 0; i < vhci_driver->nports; i++) { 598c2ecf20Sopenharmony_ci idev = &vhci_driver->idev[i]; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (idev->port == portnum) { 628c2ecf20Sopenharmony_ci found = 1; 638c2ecf20Sopenharmony_ci if (idev->status != VDEV_ST_NULL) 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci info("Port %d is already detached!\n", idev->port); 668c2ecf20Sopenharmony_ci goto call_driver_close; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!found) { 718c2ecf20Sopenharmony_ci err("Invalid port %s > maxports %d", 728c2ecf20Sopenharmony_ci port, vhci_driver->nports); 738c2ecf20Sopenharmony_ci goto call_driver_close; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* remove the port state file */ 778c2ecf20Sopenharmony_ci snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci remove(path); 808c2ecf20Sopenharmony_ci rmdir(VHCI_STATE_PATH); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = usbip_vhci_detach_device(portnum); 838c2ecf20Sopenharmony_ci if (ret < 0) { 848c2ecf20Sopenharmony_ci ret = -1; 858c2ecf20Sopenharmony_ci err("Port %d detach request failed!\n", portnum); 868c2ecf20Sopenharmony_ci goto call_driver_close; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci info("Port %d is now detached!\n", portnum); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cicall_driver_close: 918c2ecf20Sopenharmony_ci usbip_vhci_driver_close(); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return ret; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint usbip_detach(int argc, char *argv[]) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci static const struct option opts[] = { 998c2ecf20Sopenharmony_ci { "port", required_argument, NULL, 'p' }, 1008c2ecf20Sopenharmony_ci { NULL, 0, NULL, 0 } 1018c2ecf20Sopenharmony_ci }; 1028c2ecf20Sopenharmony_ci int opt; 1038c2ecf20Sopenharmony_ci int ret = -1; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci for (;;) { 1068c2ecf20Sopenharmony_ci opt = getopt_long(argc, argv, "p:", opts, NULL); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (opt == -1) 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci switch (opt) { 1128c2ecf20Sopenharmony_ci case 'p': 1138c2ecf20Sopenharmony_ci ret = detach_port(optarg); 1148c2ecf20Sopenharmony_ci goto out; 1158c2ecf20Sopenharmony_ci default: 1168c2ecf20Sopenharmony_ci goto err_out; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cierr_out: 1218c2ecf20Sopenharmony_ci usbip_detach_usage(); 1228c2ecf20Sopenharmony_ciout: 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci} 125