blob: c287ccc78fde811c26a2bea60ade1fe2c39c507f [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:
Shuah Khance601a02017-12-07 14:16:49 -070052 * port sta spd dev sockfd local_busid
53 * 0000 004 000 00000000 000003 1-2.3
54 * 0001 004 000 00000000 000004 2-3.4
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060055 *
Shuah Khance601a02017-12-07 14:16:49 -070056 * Output includes socket fd instead of socket pointer address to
57 * avoid leaking kernel memory address in:
58 * /sys/devices/platform/vhci_hcd.0/status and in debug output.
59 * The socket pointer address is not used at the moment and it was
60 * made visible as a convenient way to find IP address from socket
61 * pointer address by looking up /proc/net/{tcp,tcp6}. As this opens
62 * a security hole, the change is made to use sockfd instead.
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060063 */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090064 for (i = 0; i < VHCI_HC_PORTS; i++) {
65 struct vhci_device *vdev = &vhci->vdev[i];
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060066
67 spin_lock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090068 out += sprintf(out, "%04u %03u ",
69 (pdev_nr * VHCI_HC_PORTS) + i,
70 vdev->ud.status);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060071
72 if (vdev->ud.status == VDEV_ST_USED) {
73 out += sprintf(out, "%03u %08x ",
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090074 vdev->speed, vdev->devid);
Shuah Khance601a02017-12-07 14:16:49 -070075 out += sprintf(out, "%06u %s",
76 vdev->ud.sockfd,
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090077 dev_name(&vdev->udev->dev));
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060078
matt mooneybd608f62011-05-06 03:47:52 -070079 } else {
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090080 out += sprintf(out, "000 00000000 ");
Shuah Khance601a02017-12-07 14:16:49 -070081 out += sprintf(out, "000000 0-0");
matt mooneybd608f62011-05-06 03:47:52 -070082 }
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060083
84 out += sprintf(out, "\n");
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060085 spin_unlock(&vdev->ud.lock);
86 }
87
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090088 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -060089
90 return out - s;
91}
Nobuo Iwata0775a9c2016-06-13 11:33:40 +090092
93static ssize_t status_show_not_ready(int pdev_nr, char *out)
94{
95 char *s = out;
96 int i = 0;
97
98 for (i = 0; i < VHCI_HC_PORTS; i++) {
99 out += sprintf(out, "%04u %03u ",
100 (pdev_nr * VHCI_HC_PORTS) + i,
101 VDEV_ST_NOTASSIGNED);
102 out += sprintf(out, "000 00000000 0000000000000000 0-0");
103 out += sprintf(out, "\n");
104 }
105 return out - s;
106}
107
108static int status_name_to_id(const char *name)
109{
110 char *c;
111 long val;
112 int ret;
113
114 c = strchr(name, '.');
115 if (c == NULL)
116 return 0;
117
118 ret = kstrtol(c+1, 10, &val);
119 if (ret < 0)
120 return ret;
121
122 return val;
123}
124
125static ssize_t status_show(struct device *dev,
126 struct device_attribute *attr, char *out)
127{
128 char *s = out;
129 int pdev_nr;
130
131 out += sprintf(out,
Shuah Khance601a02017-12-07 14:16:49 -0700132 "port sta spd dev sockfd local_busid\n");
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900133
134 pdev_nr = status_name_to_id(attr->attr.name);
135 if (pdev_nr < 0)
136 out += status_show_not_ready(pdev_nr, out);
137 else
138 out += status_show_vhci(pdev_nr, out);
139
140 return out - s;
141}
142
143static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
144 char *out)
145{
146 char *s = out;
147
148 out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
149 return out - s;
150}
151static DEVICE_ATTR_RO(nports);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600152
153/* Sysfs entry to shutdown a virtual connection */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900154static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600155{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900156 struct vhci_device *vdev = &vhci->vdev[rhport];
Andrew Goodbody21619792016-02-02 17:36:39 +0000157 unsigned long flags;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600158
Brian G. Merrellb8868e42009-07-21 00:46:13 -0600159 usbip_dbg_vhci_sysfs("enter\n");
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600160
161 /* lock */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900162 spin_lock_irqsave(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600163 spin_lock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900164
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600165 if (vdev->ud.status == VDEV_ST_NULL) {
matt mooney1a4b6f62011-05-19 16:47:32 -0700166 pr_err("not connected %d\n", vdev->ud.status);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600167
168 /* unlock */
169 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900170 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600171
172 return -EINVAL;
173 }
174
175 /* unlock */
176 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900177 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600178
179 usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
180
181 return 0;
182}
183
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900184static int valid_port(__u32 pdev_nr, __u32 rhport)
185{
186 if (pdev_nr >= vhci_num_controllers) {
187 pr_err("pdev %u\n", pdev_nr);
188 return 0;
189 }
190 if (rhport >= VHCI_HC_PORTS) {
191 pr_err("rhport %u\n", rhport);
192 return 0;
193 }
194 return 1;
195}
196
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600197static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
198 const char *buf, size_t count)
199{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900200 __u32 port = 0, pdev_nr = 0, rhport = 0;
201 struct usb_hcd *hcd;
202 int ret;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600203
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900204 if (kstrtoint(buf, 10, &port) < 0)
John de la Garza88fa1eb2014-03-06 10:36:34 -0800205 return -EINVAL;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600206
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900207 pdev_nr = port_to_pdev_nr(port);
208 rhport = port_to_rhport(port);
209
210 if (!valid_port(pdev_nr, rhport))
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600211 return -EINVAL;
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900212
213 hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
214 if (hcd == NULL) {
215 dev_err(dev, "port is not ready %u\n", port);
216 return -EAGAIN;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600217 }
218
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900219 ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport);
220 if (ret < 0)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600221 return -EINVAL;
222
Brian G. Merrellb8868e42009-07-21 00:46:13 -0600223 usbip_dbg_vhci_sysfs("Leave\n");
matt mooneybd608f62011-05-06 03:47:52 -0700224
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600225 return count;
226}
227static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
228
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900229static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed)
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600230{
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900231 if (!valid_port(pdev_nr, rhport)) {
232 return 0;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600233 }
234
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600235 switch (speed) {
236 case USB_SPEED_LOW:
237 case USB_SPEED_FULL:
238 case USB_SPEED_HIGH:
Greg Kroah-Hartman551cdbb2010-01-14 11:08:04 -0800239 case USB_SPEED_WIRELESS:
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600240 break;
241 default:
Shuah Khan8360fb02014-01-22 09:38:14 -0700242 pr_err("Failed attach request for unsupported USB speed: %s\n",
243 usb_speed_string(speed));
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900244 return 0;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600245 }
246
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900247 return 1;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600248}
249
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900250/* Sysfs entry to establish a virtual connection */
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600251/*
252 * To start a new USB/IP attachment, a userland program needs to setup a TCP
253 * connection and then write its socket descriptor with remote device
254 * information into this sysfs file.
255 *
256 * A remote device is virtually attached to the root-hub port of @rhport with
257 * @speed. @devid is embedded into a request to specify the remote device in a
258 * server host.
259 *
260 * write() returns 0 on success, else negative errno.
261 */
262static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
263 const char *buf, size_t count)
264{
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600265 struct socket *socket;
266 int sockfd = 0;
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900267 __u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
268 struct usb_hcd *hcd;
269 struct vhci_hcd *vhci;
270 struct vhci_device *vdev;
Al Viro964ea962014-03-05 20:33:08 -0500271 int err;
Andrew Goodbody21619792016-02-02 17:36:39 +0000272 unsigned long flags;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600273
274 /*
275 * @rhport: port number of vhci_hcd
276 * @sockfd: socket descriptor of an established TCP connection
277 * @devid: unique device identifier in a remote host
278 * @speed: usb device speed in a remote host
279 */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900280 if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4)
John de la Garza88fa1eb2014-03-06 10:36:34 -0800281 return -EINVAL;
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900282 pdev_nr = port_to_pdev_nr(port);
283 rhport = port_to_rhport(port);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600284
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900285 usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n",
286 port, pdev_nr, rhport);
287 usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n",
288 sockfd, devid, speed);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600289
290 /* check received parameters */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900291 if (!valid_args(pdev_nr, rhport, speed))
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600292 return -EINVAL;
293
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900294 hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr));
295 if (hcd == NULL) {
296 dev_err(dev, "port %d is not ready\n", port);
297 return -EAGAIN;
298 }
299 vhci = hcd_to_vhci(hcd);
300 vdev = &vhci->vdev[rhport];
301
Bernard Blackham3d0a2a22012-10-22 06:45:00 +1100302 /* Extract socket from fd. */
Al Viro964ea962014-03-05 20:33:08 -0500303 socket = sockfd_lookup(sockfd, &err);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600304 if (!socket)
Márton Németha6d81814a2011-05-27 06:18:48 +0200305 return -EINVAL;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600306
307 /* now need lock until setting vdev status as used */
308
309 /* begin a lock */
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900310 spin_lock_irqsave(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600311 spin_lock(&vdev->ud.lock);
312
313 if (vdev->ud.status != VDEV_ST_NULL) {
314 /* end of the lock */
315 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900316 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600317
Al Viro964ea962014-03-05 20:33:08 -0500318 sockfd_put(socket);
Bernard Blackham3d0a2a22012-10-22 06:45:00 +1100319
matt mooney1a4b6f62011-05-19 16:47:32 -0700320 dev_err(dev, "port %d already used\n", rhport);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600321 return -EINVAL;
322 }
323
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900324 dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n",
325 pdev_nr, rhport, sockfd);
326 dev_info(dev, "devid(%u) speed(%u) speed_str(%s)\n",
327 devid, speed, usb_speed_string(speed));
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600328
329 vdev->devid = devid;
330 vdev->speed = speed;
Shuah Khance601a02017-12-07 14:16:49 -0700331 vdev->ud.sockfd = sockfd;
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600332 vdev->ud.tcp_socket = socket;
333 vdev->ud.status = VDEV_ST_NOTASSIGNED;
334
335 spin_unlock(&vdev->ud.lock);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900336 spin_unlock_irqrestore(&vhci->lock, flags);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600337 /* end the lock */
338
Oleg Nesterovba46ce32012-03-13 19:07:18 +0100339 vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
340 vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
Max Vozelerd1b2e952011-04-18 21:44:10 +0200341
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900342 rh_port_connect(vdev, speed);
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600343
344 return count;
345}
346static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
347
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900348#define MAX_STATUS_NAME 16
349
350struct status_attr {
351 struct device_attribute attr;
352 char name[MAX_STATUS_NAME+1];
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600353};
354
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900355static struct status_attr *status_attrs;
356
357static void set_status_attr(int id)
358{
359 struct status_attr *status;
360
361 status = status_attrs + id;
362 if (id == 0)
363 strcpy(status->name, "status");
364 else
365 snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id);
366 status->attr.attr.name = status->name;
367 status->attr.attr.mode = S_IRUGO;
368 status->attr.show = status_show;
Shuah Khan87ac2972016-12-05 12:56:38 -0700369 sysfs_attr_init(&status->attr.attr);
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900370}
371
372static int init_status_attrs(void)
373{
374 int id;
375
376 status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr),
377 GFP_KERNEL);
378 if (status_attrs == NULL)
379 return -ENOMEM;
380
381 for (id = 0; id < vhci_num_controllers; id++)
382 set_status_attr(id);
383
384 return 0;
385}
386
387static void finish_status_attrs(void)
388{
389 kfree(status_attrs);
390}
391
392struct attribute_group vhci_attr_group = {
393 .attrs = NULL,
Takahiro Hirofuchi04679b32008-07-09 14:56:51 -0600394};
Nobuo Iwata0775a9c2016-06-13 11:33:40 +0900395
396int vhci_init_attr_group(void)
397{
398 struct attribute **attrs;
399 int ret, i;
400
401 attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *),
402 GFP_KERNEL);
403 if (attrs == NULL)
404 return -ENOMEM;
405
406 ret = init_status_attrs();
407 if (ret) {
408 kfree(attrs);
409 return ret;
410 }
411 *attrs = &dev_attr_nports.attr;
412 *(attrs + 1) = &dev_attr_detach.attr;
413 *(attrs + 2) = &dev_attr_attach.attr;
414 *(attrs + 3) = &dev_attr_usbip_debug.attr;
415 for (i = 0; i < vhci_num_controllers; i++)
416 *(attrs + i + 4) = &((status_attrs + i)->attr.attr);
417 vhci_attr_group.attrs = attrs;
418 return 0;
419}
420
421void vhci_finish_attr_group(void)
422{
423 finish_status_attrs();
424 kfree(vhci_attr_group.attrs);
425}