usbip_attach.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
  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 <http://www.gnu.org/licenses/>.
  17. */
  18. #include <sys/stat.h>
  19. #include <limits.h>
  20. #include <stdint.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <fcntl.h>
  24. #include <getopt.h>
  25. #include <unistd.h>
  26. #include <errno.h>
  27. #include "vhci_driver.h"
  28. #include "usbip_common.h"
  29. #include "usbip_network.h"
  30. #include "usbip.h"
  31. static const char usbip_attach_usage_string[] =
  32. "usbip attach <args>\n"
  33. " -r, --remote=<host> The machine with exported USB devices\n"
  34. " -b, --busid=<busid> Busid of the device on <host>\n";
  35. void usbip_attach_usage(void)
  36. {
  37. printf("usage: %s", usbip_attach_usage_string);
  38. }
  39. #define MAX_BUFF 100
  40. static int record_connection(char *host, char *port, char *busid, int rhport)
  41. {
  42. int fd;
  43. char path[PATH_MAX+1];
  44. char buff[MAX_BUFF+1];
  45. int ret;
  46. ret = mkdir(VHCI_STATE_PATH, 0700);
  47. if (ret < 0) {
  48. /* if VHCI_STATE_PATH exists, then it better be a directory */
  49. if (errno == EEXIST) {
  50. struct stat s;
  51. ret = stat(VHCI_STATE_PATH, &s);
  52. if (ret < 0)
  53. return -1;
  54. if (!(s.st_mode & S_IFDIR))
  55. return -1;
  56. } else
  57. return -1;
  58. }
  59. snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
  60. fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
  61. if (fd < 0)
  62. return -1;
  63. snprintf(buff, MAX_BUFF, "%s %s %s\n",
  64. host, port, busid);
  65. ret = write(fd, buff, strlen(buff));
  66. if (ret != (ssize_t) strlen(buff)) {
  67. close(fd);
  68. return -1;
  69. }
  70. close(fd);
  71. return 0;
  72. }
  73. static int import_device(int sockfd, struct usbip_usb_device *udev)
  74. {
  75. int rc;
  76. int port;
  77. rc = usbip_vhci_driver_open();
  78. if (rc < 0) {
  79. err("open vhci_driver");
  80. return -1;
  81. }
  82. port = usbip_vhci_get_free_port();
  83. if (port < 0) {
  84. err("no free port");
  85. usbip_vhci_driver_close();
  86. return -1;
  87. }
  88. rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
  89. udev->devnum, udev->speed);
  90. if (rc < 0) {
  91. err("import device");
  92. usbip_vhci_driver_close();
  93. return -1;
  94. }
  95. usbip_vhci_driver_close();
  96. return port;
  97. }
  98. static int query_import_device(int sockfd, char *busid)
  99. {
  100. int rc;
  101. struct op_import_request request;
  102. struct op_import_reply reply;
  103. uint16_t code = OP_REP_IMPORT;
  104. memset(&request, 0, sizeof(request));
  105. memset(&reply, 0, sizeof(reply));
  106. /* send a request */
  107. rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
  108. if (rc < 0) {
  109. err("send op_common");
  110. return -1;
  111. }
  112. strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
  113. PACK_OP_IMPORT_REQUEST(0, &request);
  114. rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
  115. if (rc < 0) {
  116. err("send op_import_request");
  117. return -1;
  118. }
  119. /* receive a reply */
  120. rc = usbip_net_recv_op_common(sockfd, &code);
  121. if (rc < 0) {
  122. err("recv op_common");
  123. return -1;
  124. }
  125. rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
  126. if (rc < 0) {
  127. err("recv op_import_reply");
  128. return -1;
  129. }
  130. PACK_OP_IMPORT_REPLY(0, &reply);
  131. /* check the reply */
  132. if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
  133. err("recv different busid %s", reply.udev.busid);
  134. return -1;
  135. }
  136. /* import a device */
  137. return import_device(sockfd, &reply.udev);
  138. }
  139. static int attach_device(char *host, char *busid)
  140. {
  141. int sockfd;
  142. int rc;
  143. int rhport;
  144. sockfd = usbip_net_tcp_connect(host, usbip_port_string);
  145. if (sockfd < 0) {
  146. err("tcp connect");
  147. return -1;
  148. }
  149. rhport = query_import_device(sockfd, busid);
  150. if (rhport < 0) {
  151. err("query");
  152. return -1;
  153. }
  154. close(sockfd);
  155. rc = record_connection(host, usbip_port_string, busid, rhport);
  156. if (rc < 0) {
  157. err("record connection");
  158. return -1;
  159. }
  160. return 0;
  161. }
  162. int usbip_attach(int argc, char *argv[])
  163. {
  164. static const struct option opts[] = {
  165. { "remote", required_argument, NULL, 'r' },
  166. { "busid", required_argument, NULL, 'b' },
  167. { NULL, 0, NULL, 0 }
  168. };
  169. char *host = NULL;
  170. char *busid = NULL;
  171. int opt;
  172. int ret = -1;
  173. for (;;) {
  174. opt = getopt_long(argc, argv, "r:b:", opts, NULL);
  175. if (opt == -1)
  176. break;
  177. switch (opt) {
  178. case 'r':
  179. host = optarg;
  180. break;
  181. case 'b':
  182. busid = optarg;
  183. break;
  184. default:
  185. goto err_out;
  186. }
  187. }
  188. if (!host || !busid)
  189. goto err_out;
  190. ret = attach_device(host, busid);
  191. goto out;
  192. err_out:
  193. usbip_attach_usage();
  194. out:
  195. return ret;
  196. }