blob: c404017c1b5ae26aa1df115c0ac1652284ed21b4 [file] [log] [blame]
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -06001/*
2 * Copyright (C) 2003-2008 Takahiro Hirofuchi
Nobuo Iwata0775a9c2016-06-13 11:33:40 +09003 * Copyright (C) 2015-2016 Nobuo Iwata
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -06004 *
5 * This 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 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, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
matt mooney7aaacb42011-05-11 22:33:43 -070021#include <linux/kthread.h>
Bernard Blackham3d0a2a22012-10-22 06:45:00 +110022#include <linux/file.h>
matt mooney7aaacb42011-05-11 22:33:43 -070023#include <linux/net.h>
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090024#include <linux/platform_device.h>
25#include <linux/slab.h>
matt mooney7aaacb42011-05-11 22:33:43 -070026
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060027#include "usbip_common.h"
28#include "vhci.h"
29
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060030/* TODO: refine locking ?*/
31
32/* Sysfs entry to show port status */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090033static ssize_t status_show_vhci(int pdev_nr, char *out)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060034{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090035 struct platform_device *pdev = *(vhci_pdevs + pdev_nr);
36 struct vhci_hcd *vhci;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060037 char *s = out;
38 int i = 0;
Andrew Goodbody21619792016-02-02 17:36:39 +000039 unsigned long flags;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060040
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090041 if (!pdev || !out) {
42 usbip_dbg_vhci_sysfs("show status error\n");
43 return 0;
44 }
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060045
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090046 vhci = hcd_to_vhci(platform_get_drvdata(pdev));
47
48 spin_lock_irqsave(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060049
50 /*
51 * output example:
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090052 * port sta spd dev socket local_busid
53 * 0000 004 000 00000000 c5a7bb80 1-2.3
54 * 0001 004 000 00000000 d8cee980 2-3.4
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060055 *
56 * IP address can be retrieved from a socket pointer address by looking
57 * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
58 * port number and its peer IP address.
59 */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090060 for (i = 0; i < VHCI_HC_PORTS; i++) {
61 struct vhci_device *vdev = &vhci->vdev[i];
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060062
63 spin_lock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090064 out += sprintf(out, "%04u %03u ",
65 (pdev_nr * VHCI_HC_PORTS) + i,
66 vdev->ud.status);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060067
68 if (vdev->ud.status == VDEV_ST_USED) {
69 out += sprintf(out, "%03u %08x ",
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090070 vdev->speed, vdev->devid);
71 out += sprintf(out, "%16p %s",
72 vdev->ud.tcp_socket,
73 dev_name(&vdev->udev->dev));
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060074
matt mooneybd608f62011-05-06 03:47:52 -070075 } else {
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090076 out += sprintf(out, "000 00000000 ");
77 out += sprintf(out, "0000000000000000 0-0");
matt mooneybd608f62011-05-06 03:47:52 -070078 }
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060079
80 out += sprintf(out, "\n");
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060081 spin_unlock(&vdev->ud.lock);
82 }
83
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090084 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060085
86 return out - s;
87}
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090088
89static ssize_t status_show_not_ready(int pdev_nr, char *out)
90{
91 char *s = out;
92 int i = 0;
93
94 for (i = 0; i < VHCI_HC_PORTS; i++) {
95 out += sprintf(out, "%04u %03u ",
96 (pdev_nr * VHCI_HC_PORTS) + i,
97 VDEV_ST_NOTASSIGNED);
98 out += sprintf(out, "000 00000000 0000000000000000 0-0");
99 out += sprintf(out, "\n");
100 }
101 return out - s;
102}
103
104static int status_name_to_id(const char *name)
105{
106 char *c;
107 long val;
108 int ret;
109
110 c = strchr(name, '.');
111 if (c == NULL)
112 return 0;
113
114 ret = kstrtol(c+1, 10, &val);
115 if (ret < 0)
116 return ret;
117
118 return val;
119}
120
121static ssize_t status_show(struct device *dev,
122 struct device_attribute *attr, char *out)
123{
124 char *s = out;
125 int pdev_nr;
126
127 out += sprintf(out,
128 "port sta spd dev socket local_busid\n");
129
130 pdev_nr = status_name_to_id(attr->attr.name);
131 if (pdev_nr < 0)
132 out += status_show_not_ready(pdev_nr, out);
133 else
134 out += status_show_vhci(pdev_nr, out);
135
136 return out - s;
137}
138
139static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
140 char *out)
141{
142 char *s = out;
143
144 out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
145 return out - s;
146}
147static DEVICE_ATTR_RO(nports);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600148
149/* Sysfs entry to shutdown a virtual connection */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900150static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600151{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900152 struct vhci_device *vdev = &vhci->vdev[rhport];
Andrew Goodbody21619792016-02-02 17:36:39 +0000153 unsigned long flags;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600154
Brian G. Merrellb8868e42009-07-21 00:46:13 -0600155 usbip_dbg_vhci_sysfs("enter\n");
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600156
157 /* lock */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900158 spin_lock_irqsave(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600159 spin_lock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900160
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600161 if (vdev->ud.status == VDEV_ST_NULL) {
matt mooney1a4b6f62011-05-19 16:47:32 -0700162 pr_err("not connected %d\n", vdev->ud.status);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600163
164 /* unlock */
165 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900166 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600167
168 return -EINVAL;
169 }
170
171 /* unlock */
172 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900173 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600174
175 usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
176
177 return 0;
178}
179
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900180static int valid_port(__u32 pdev_nr, __u32 rhport)
181{
182 if (pdev_nr >= vhci_num_controllers) {
183 pr_err("pdev %u\n", pdev_nr);
184 return 0;
185 }
186 if (rhport >= VHCI_HC_PORTS) {
187 pr_err("rhport %u\n", rhport);
188 return 0;
189 }
190 return 1;
191}
192
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600193static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
194 const char *buf, size_t count)
195{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900196 __u32 port = 0, pdev_nr = 0, rhport = 0;
197 struct usb_hcd *hcd;
198 int ret;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600199
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900200 if (kstrtoint(buf, 10, &port) < 0)
John de la Garza88fa1eb2014-03-06 10:36:34 -0800201 return -EINVAL;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600202
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900203 pdev_nr = port_to_pdev_nr(port);
204 rhport = port_to_rhport(port);
205
206 if (!valid_port(pdev_nr, rhport))
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600207 return -EINVAL;
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900208
209 hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
210 if (hcd == NULL) {
211 dev_err(dev, "port is not ready %u\n", port);
212 return -EAGAIN;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600213 }
214
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900215 ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport);
216 if (ret < 0)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600217 return -EINVAL;
218
Brian G. Merrellb8868e42009-07-21 00:46:13 -0600219 usbip_dbg_vhci_sysfs("Leave\n");
matt mooneybd608f62011-05-06 03:47:52 -0700220
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600221 return count;
222}
223static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
224
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900225static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600226{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900227 if (!valid_port(pdev_nr, rhport)) {
228 return 0;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600229 }
230
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600231 switch (speed) {
232 case USB_SPEED_LOW:
233 case USB_SPEED_FULL:
234 case USB_SPEED_HIGH:
Greg Kroah-Hartman551cdbb2010-01-14 11:08:04 -0800235 case USB_SPEED_WIRELESS:
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600236 break;
237 default:
Shuah Khan8360fb02014-01-22 09:38:14 -0700238 pr_err("Failed attach request for unsupported USB speed: %s\n",
239 usb_speed_string(speed));
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900240 return 0;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600241 }
242
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900243 return 1;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600244}
245
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900246/* Sysfs entry to establish a virtual connection */
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600247/*
248 * To start a new USB/IP attachment, a userland program needs to setup a TCP
249 * connection and then write its socket descriptor with remote device
250 * information into this sysfs file.
251 *
252 * A remote device is virtually attached to the root-hub port of @rhport with
253 * @speed. @devid is embedded into a request to specify the remote device in a
254 * server host.
255 *
256 * write() returns 0 on success, else negative errno.
257 */
258static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
259 const char *buf, size_t count)
260{
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600261 struct socket *socket;
262 int sockfd = 0;
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900263 __u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
264 struct usb_hcd *hcd;
265 struct vhci_hcd *vhci;
266 struct vhci_device *vdev;
Al Viro964ea962014-03-05 20:33:08 -0500267 int err;
Andrew Goodbody21619792016-02-02 17:36:39 +0000268 unsigned long flags;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600269
270 /*
271 * @rhport: port number of vhci_hcd
272 * @sockfd: socket descriptor of an established TCP connection
273 * @devid: unique device identifier in a remote host
274 * @speed: usb device speed in a remote host
275 */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900276 if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4)
John de la Garza88fa1eb2014-03-06 10:36:34 -0800277 return -EINVAL;
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900278 pdev_nr = port_to_pdev_nr(port);
279 rhport = port_to_rhport(port);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600280
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900281 usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n",
282 port, pdev_nr, rhport);
283 usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n",
284 sockfd, devid, speed);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600285
286 /* check received parameters */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900287 if (!valid_args(pdev_nr, rhport, speed))
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600288 return -EINVAL;
289
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900290 hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
291 if (hcd == NULL) {
292 dev_err(dev, "port %d is not ready\n", port);
293 return -EAGAIN;
294 }
295 vhci = hcd_to_vhci(hcd);
296 vdev = &vhci->vdev[rhport];
297
Bernard Blackham3d0a2a22012-10-22 06:45:00 +1100298 /* Extract socket from fd. */
Al Viro964ea962014-03-05 20:33:08 -0500299 socket = sockfd_lookup(sockfd, &err);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600300 if (!socket)
Márton Németha6d81814a2011-05-27 06:18:48 +0200301 return -EINVAL;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600302
303 /* now need lock until setting vdev status as used */
304
305 /* begin a lock */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900306 spin_lock_irqsave(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600307 spin_lock(&vdev->ud.lock);
308
309 if (vdev->ud.status != VDEV_ST_NULL) {
310 /* end of the lock */
311 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900312 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600313
Al Viro964ea962014-03-05 20:33:08 -0500314 sockfd_put(socket);
Bernard Blackham3d0a2a22012-10-22 06:45:00 +1100315
matt mooney1a4b6f62011-05-19 16:47:32 -0700316 dev_err(dev, "port %d already used\n", rhport);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600317 return -EINVAL;
318 }
319
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900320 dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n",
321 pdev_nr, rhport, sockfd);
322 dev_info(dev, "devid(%u) speed(%u) speed_str(%s)\n",
323 devid, speed, usb_speed_string(speed));
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600324
325 vdev->devid = devid;
326 vdev->speed = speed;
327 vdev->ud.tcp_socket = socket;
328 vdev->ud.status = VDEV_ST_NOTASSIGNED;
329
330 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900331 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600332 /* end the lock */
333
Oleg Nesterovba46ce32012-03-13 19:07:18 +0100334 vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
335 vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
Max Vozelerd1b2e952011-04-18 21:44:10 +0200336
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900337 rh_port_connect(vdev, speed);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600338
339 return count;
340}
341static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
342
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900343#define MAX_STATUS_NAME 16
344
345struct status_attr {
346 struct device_attribute attr;
347 char name[MAX_STATUS_NAME+1];
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600348};
349
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900350static struct status_attr *status_attrs;
351
352static void set_status_attr(int id)
353{
354 struct status_attr *status;
355
356 status = status_attrs + id;
357 if (id == 0)
358 strcpy(status->name, "status");
359 else
360 snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id);
361 status->attr.attr.name = status->name;
362 status->attr.attr.mode = S_IRUGO;
363 status->attr.show = status_show;
364}
365
366static int init_status_attrs(void)
367{
368 int id;
369
370 status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr),
371 GFP_KERNEL);
372 if (status_attrs == NULL)
373 return -ENOMEM;
374
375 for (id = 0; id < vhci_num_controllers; id++)
376 set_status_attr(id);
377
378 return 0;
379}
380
381static void finish_status_attrs(void)
382{
383 kfree(status_attrs);
384}
385
386struct attribute_group vhci_attr_group = {
387 .attrs = NULL,
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600388};
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900389
390int vhci_init_attr_group(void)
391{
392 struct attribute **attrs;
393 int ret, i;
394
395 attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *),
396 GFP_KERNEL);
397 if (attrs == NULL)
398 return -ENOMEM;
399
400 ret = init_status_attrs();
401 if (ret) {
402 kfree(attrs);
403 return ret;
404 }
405 *attrs = &dev_attr_nports.attr;
406 *(attrs + 1) = &dev_attr_detach.attr;
407 *(attrs + 2) = &dev_attr_attach.attr;
408 *(attrs + 3) = &dev_attr_usbip_debug.attr;
409 for (i = 0; i < vhci_num_controllers; i++)
410 *(attrs + i + 4) = &((status_attrs + i)->attr.attr);
411 vhci_attr_group.attrs = attrs;
412 return 0;
413}
414
415void vhci_finish_attr_group(void)
416{
417 finish_status_attrs();
418 kfree(vhci_attr_group.attrs);
419}