vhci_sysfs.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright (C) 2003-2008 Takahiro Hirofuchi
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #include <linux/kthread.h>
  20. #include <linux/file.h>
  21. #include <linux/net.h>
  22. #include "usbip_common.h"
  23. #include "vhci.h"
  24. /* TODO: refine locking ?*/
  25. /* Sysfs entry to show port status */
  26. static ssize_t status_show(struct device *dev, struct device_attribute *attr,
  27. char *out)
  28. {
  29. char *s = out;
  30. int i = 0;
  31. unsigned long flags;
  32. BUG_ON(!the_controller || !out);
  33. spin_lock_irqsave(&the_controller->lock, flags);
  34. /*
  35. * output example:
  36. * prt sta spd dev socket local_busid
  37. * 000 004 000 000 c5a7bb80 1-2.3
  38. * 001 004 000 000 d8cee980 2-3.4
  39. *
  40. * IP address can be retrieved from a socket pointer address by looking
  41. * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
  42. * port number and its peer IP address.
  43. */
  44. out += sprintf(out,
  45. "prt sta spd bus dev socket local_busid\n");
  46. for (i = 0; i < VHCI_NPORTS; i++) {
  47. struct vhci_device *vdev = port_to_vdev(i);
  48. spin_lock(&vdev->ud.lock);
  49. out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
  50. if (vdev->ud.status == VDEV_ST_USED) {
  51. out += sprintf(out, "%03u %08x ",
  52. vdev->speed, vdev->devid);
  53. out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
  54. out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
  55. } else {
  56. out += sprintf(out, "000 000 000 0000000000000000 0-0");
  57. }
  58. out += sprintf(out, "\n");
  59. spin_unlock(&vdev->ud.lock);
  60. }
  61. spin_unlock_irqrestore(&the_controller->lock, flags);
  62. return out - s;
  63. }
  64. static DEVICE_ATTR_RO(status);
  65. /* Sysfs entry to shutdown a virtual connection */
  66. static int vhci_port_disconnect(__u32 rhport)
  67. {
  68. struct vhci_device *vdev;
  69. unsigned long flags;
  70. usbip_dbg_vhci_sysfs("enter\n");
  71. /* lock */
  72. spin_lock_irqsave(&the_controller->lock, flags);
  73. vdev = port_to_vdev(rhport);
  74. spin_lock(&vdev->ud.lock);
  75. if (vdev->ud.status == VDEV_ST_NULL) {
  76. pr_err("not connected %d\n", vdev->ud.status);
  77. /* unlock */
  78. spin_unlock(&vdev->ud.lock);
  79. spin_unlock_irqrestore(&the_controller->lock, flags);
  80. return -EINVAL;
  81. }
  82. /* unlock */
  83. spin_unlock(&vdev->ud.lock);
  84. spin_unlock_irqrestore(&the_controller->lock, flags);
  85. usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
  86. return 0;
  87. }
  88. static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
  89. const char *buf, size_t count)
  90. {
  91. int err;
  92. __u32 rhport = 0;
  93. if (sscanf(buf, "%u", &rhport) != 1)
  94. return -EINVAL;
  95. /* check rhport */
  96. if (rhport >= VHCI_NPORTS) {
  97. dev_err(dev, "invalid port %u\n", rhport);
  98. return -EINVAL;
  99. }
  100. err = vhci_port_disconnect(rhport);
  101. if (err < 0)
  102. return -EINVAL;
  103. usbip_dbg_vhci_sysfs("Leave\n");
  104. return count;
  105. }
  106. static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
  107. /* Sysfs entry to establish a virtual connection */
  108. static int valid_args(__u32 rhport, enum usb_device_speed speed)
  109. {
  110. /* check rhport */
  111. if (rhport >= VHCI_NPORTS) {
  112. pr_err("port %u\n", rhport);
  113. return -EINVAL;
  114. }
  115. /* check speed */
  116. switch (speed) {
  117. case USB_SPEED_LOW:
  118. case USB_SPEED_FULL:
  119. case USB_SPEED_HIGH:
  120. case USB_SPEED_WIRELESS:
  121. break;
  122. default:
  123. pr_err("Failed attach request for unsupported USB speed: %s\n",
  124. usb_speed_string(speed));
  125. return -EINVAL;
  126. }
  127. return 0;
  128. }
  129. /*
  130. * To start a new USB/IP attachment, a userland program needs to setup a TCP
  131. * connection and then write its socket descriptor with remote device
  132. * information into this sysfs file.
  133. *
  134. * A remote device is virtually attached to the root-hub port of @rhport with
  135. * @speed. @devid is embedded into a request to specify the remote device in a
  136. * server host.
  137. *
  138. * write() returns 0 on success, else negative errno.
  139. */
  140. static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
  141. const char *buf, size_t count)
  142. {
  143. struct vhci_device *vdev;
  144. struct socket *socket;
  145. int sockfd = 0;
  146. __u32 rhport = 0, devid = 0, speed = 0;
  147. int err;
  148. unsigned long flags;
  149. /*
  150. * @rhport: port number of vhci_hcd
  151. * @sockfd: socket descriptor of an established TCP connection
  152. * @devid: unique device identifier in a remote host
  153. * @speed: usb device speed in a remote host
  154. */
  155. if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4)
  156. return -EINVAL;
  157. usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
  158. rhport, sockfd, devid, speed);
  159. /* check received parameters */
  160. if (valid_args(rhport, speed) < 0)
  161. return -EINVAL;
  162. /* Extract socket from fd. */
  163. socket = sockfd_lookup(sockfd, &err);
  164. if (!socket)
  165. return -EINVAL;
  166. /* now need lock until setting vdev status as used */
  167. /* begin a lock */
  168. spin_lock_irqsave(&the_controller->lock, flags);
  169. vdev = port_to_vdev(rhport);
  170. spin_lock(&vdev->ud.lock);
  171. if (vdev->ud.status != VDEV_ST_NULL) {
  172. /* end of the lock */
  173. spin_unlock(&vdev->ud.lock);
  174. spin_unlock_irqrestore(&the_controller->lock, flags);
  175. sockfd_put(socket);
  176. dev_err(dev, "port %d already used\n", rhport);
  177. return -EINVAL;
  178. }
  179. dev_info(dev,
  180. "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n",
  181. rhport, sockfd, devid, speed, usb_speed_string(speed));
  182. vdev->devid = devid;
  183. vdev->speed = speed;
  184. vdev->ud.tcp_socket = socket;
  185. vdev->ud.status = VDEV_ST_NOTASSIGNED;
  186. spin_unlock(&vdev->ud.lock);
  187. spin_unlock_irqrestore(&the_controller->lock, flags);
  188. /* end the lock */
  189. vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
  190. vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
  191. rh_port_connect(rhport, speed);
  192. return count;
  193. }
  194. static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
  195. static struct attribute *dev_attrs[] = {
  196. &dev_attr_status.attr,
  197. &dev_attr_detach.attr,
  198. &dev_attr_attach.attr,
  199. &dev_attr_usbip_debug.attr,
  200. NULL,
  201. };
  202. const struct attribute_group dev_attr_group = {
  203. .attrs = dev_attrs,
  204. };