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