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 20 #include <linux/kthread.h> 21 #include <linux/file.h> 22 #include <linux/net.h> 23 24 #include "usbip_common.h" 25 #include "vhci.h" 26 27 /* TODO: refine locking ?*/ 28 29 /* Sysfs entry to show port status */ 30 static ssize_t status_show(struct device *dev, struct device_attribute *attr, 31 char *out) 32 { 33 char *s = out; 34 int i = 0; 35 unsigned long flags; 36 37 BUG_ON(!the_controller || !out); 38 39 spin_lock_irqsave(&the_controller->lock, flags); 40 41 /* 42 * output example: 43 * prt sta spd dev socket local_busid 44 * 000 004 000 000 c5a7bb80 1-2.3 45 * 001 004 000 000 d8cee980 2-3.4 46 * 47 * IP address can be retrieved from a socket pointer address by looking 48 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a 49 * port number and its peer IP address. 50 */ 51 out += sprintf(out, 52 "prt sta spd bus dev socket local_busid\n"); 53 54 for (i = 0; i < VHCI_NPORTS; i++) { 55 struct vhci_device *vdev = port_to_vdev(i); 56 57 spin_lock(&vdev->ud.lock); 58 out += sprintf(out, "%03u %03u ", i, vdev->ud.status); 59 60 if (vdev->ud.status == VDEV_ST_USED) { 61 out += sprintf(out, "%03u %08x ", 62 vdev->speed, vdev->devid); 63 out += sprintf(out, "%16p ", vdev->ud.tcp_socket); 64 out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); 65 66 } else { 67 out += sprintf(out, "000 000 000 0000000000000000 0-0"); 68 } 69 70 out += sprintf(out, "\n"); 71 spin_unlock(&vdev->ud.lock); 72 } 73 74 spin_unlock_irqrestore(&the_controller->lock, flags); 75 76 return out - s; 77 } 78 static DEVICE_ATTR_RO(status); 79 80 /* Sysfs entry to shutdown a virtual connection */ 81 static int vhci_port_disconnect(__u32 rhport) 82 { 83 struct vhci_device *vdev; 84 unsigned long flags; 85 86 usbip_dbg_vhci_sysfs("enter\n"); 87 88 /* lock */ 89 spin_lock_irqsave(&the_controller->lock, flags); 90 91 vdev = port_to_vdev(rhport); 92 93 spin_lock(&vdev->ud.lock); 94 if (vdev->ud.status == VDEV_ST_NULL) { 95 pr_err("not connected %d\n", vdev->ud.status); 96 97 /* unlock */ 98 spin_unlock(&vdev->ud.lock); 99 spin_unlock_irqrestore(&the_controller->lock, flags); 100 101 return -EINVAL; 102 } 103 104 /* unlock */ 105 spin_unlock(&vdev->ud.lock); 106 spin_unlock_irqrestore(&the_controller->lock, flags); 107 108 usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); 109 110 return 0; 111 } 112 113 static ssize_t store_detach(struct device *dev, struct device_attribute *attr, 114 const char *buf, size_t count) 115 { 116 int err; 117 __u32 rhport = 0; 118 119 if (sscanf(buf, "%u", &rhport) != 1) 120 return -EINVAL; 121 122 /* check rhport */ 123 if (rhport >= VHCI_NPORTS) { 124 dev_err(dev, "invalid port %u\n", rhport); 125 return -EINVAL; 126 } 127 128 err = vhci_port_disconnect(rhport); 129 if (err < 0) 130 return -EINVAL; 131 132 usbip_dbg_vhci_sysfs("Leave\n"); 133 134 return count; 135 } 136 static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); 137 138 /* Sysfs entry to establish a virtual connection */ 139 static int valid_args(__u32 rhport, enum usb_device_speed speed) 140 { 141 /* check rhport */ 142 if (rhport >= VHCI_NPORTS) { 143 pr_err("port %u\n", rhport); 144 return -EINVAL; 145 } 146 147 /* check speed */ 148 switch (speed) { 149 case USB_SPEED_LOW: 150 case USB_SPEED_FULL: 151 case USB_SPEED_HIGH: 152 case USB_SPEED_WIRELESS: 153 break; 154 default: 155 pr_err("Failed attach request for unsupported USB speed: %s\n", 156 usb_speed_string(speed)); 157 return -EINVAL; 158 } 159 160 return 0; 161 } 162 163 /* 164 * To start a new USB/IP attachment, a userland program needs to setup a TCP 165 * connection and then write its socket descriptor with remote device 166 * information into this sysfs file. 167 * 168 * A remote device is virtually attached to the root-hub port of @rhport with 169 * @speed. @devid is embedded into a request to specify the remote device in a 170 * server host. 171 * 172 * write() returns 0 on success, else negative errno. 173 */ 174 static ssize_t store_attach(struct device *dev, struct device_attribute *attr, 175 const char *buf, size_t count) 176 { 177 struct vhci_device *vdev; 178 struct socket *socket; 179 int sockfd = 0; 180 __u32 rhport = 0, devid = 0, speed = 0; 181 int err; 182 unsigned long flags; 183 184 /* 185 * @rhport: port number of vhci_hcd 186 * @sockfd: socket descriptor of an established TCP connection 187 * @devid: unique device identifier in a remote host 188 * @speed: usb device speed in a remote host 189 */ 190 if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) 191 return -EINVAL; 192 193 usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", 194 rhport, sockfd, devid, speed); 195 196 /* check received parameters */ 197 if (valid_args(rhport, speed) < 0) 198 return -EINVAL; 199 200 /* Extract socket from fd. */ 201 socket = sockfd_lookup(sockfd, &err); 202 if (!socket) 203 return -EINVAL; 204 205 /* now need lock until setting vdev status as used */ 206 207 /* begin a lock */ 208 spin_lock_irqsave(&the_controller->lock, flags); 209 vdev = port_to_vdev(rhport); 210 spin_lock(&vdev->ud.lock); 211 212 if (vdev->ud.status != VDEV_ST_NULL) { 213 /* end of the lock */ 214 spin_unlock(&vdev->ud.lock); 215 spin_unlock_irqrestore(&the_controller->lock, flags); 216 217 sockfd_put(socket); 218 219 dev_err(dev, "port %d already used\n", rhport); 220 return -EINVAL; 221 } 222 223 dev_info(dev, 224 "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n", 225 rhport, sockfd, devid, speed, usb_speed_string(speed)); 226 227 vdev->devid = devid; 228 vdev->speed = speed; 229 vdev->ud.tcp_socket = socket; 230 vdev->ud.status = VDEV_ST_NOTASSIGNED; 231 232 spin_unlock(&vdev->ud.lock); 233 spin_unlock_irqrestore(&the_controller->lock, flags); 234 /* end the lock */ 235 236 vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); 237 vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); 238 239 rh_port_connect(rhport, speed); 240 241 return count; 242 } 243 static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach); 244 245 static struct attribute *dev_attrs[] = { 246 &dev_attr_status.attr, 247 &dev_attr_detach.attr, 248 &dev_attr_attach.attr, 249 &dev_attr_usbip_debug.attr, 250 NULL, 251 }; 252 253 const struct attribute_group dev_attr_group = { 254 .attrs = dev_attrs, 255 }; 256