c73b355cf140694996ccb6f0131bc72954e3d325
[pandora-kernel.git] / drivers / staging / usbip / userspace / src / usbip.c
1 /*
2  *
3  * Copyright (C) 2005-2007 Takahiro Hirofuchi
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "../config.h"
8 #endif
9
10 #include "usbip.h"
11 #include "usbip_network.h"
12 #include <ctype.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <stdlib.h>
16 #include <fcntl.h>
17 #include <glib.h>
18
19 static const char version[] = PACKAGE_STRING;
20
21
22 /* /sys/devices/platform/vhci_hcd/usb6/6-1/6-1:1.1  -> 1 */
23 static int get_interface_number(char *path)
24 {
25         char *c;
26
27         c = strstr(path, vhci_driver->hc_device->bus_id);
28         if (!c)
29                 return -1;      /* hc exist? */
30         c++;
31         /* -> usb6/6-1/6-1:1.1 */
32
33         c = strchr(c, '/');
34         if (!c)
35                 return -1;      /* hc exist? */
36         c++;
37         /* -> 6-1/6-1:1.1 */
38
39         c = strchr(c, '/');
40         if (!c)
41                 return -1;      /* no interface path */
42         c++;
43         /* -> 6-1:1.1 */
44
45         c = strchr(c, ':');
46         if (!c)
47                 return -1;      /* no configuration? */
48         c++;
49         /* -> 1.1 */
50
51         c = strchr(c, '.');
52         if (!c)
53                 return -1;      /* no interface? */
54         c++;
55         /* -> 1 */
56
57
58         return atoi(c);
59 }
60
61
62 static struct sysfs_device *open_usb_interface(struct usb_device *udev, int i)
63 {
64         struct sysfs_device *suinf;
65         char busid[SYSFS_BUS_ID_SIZE];
66
67         snprintf(busid, SYSFS_BUS_ID_SIZE, "%s:%d.%d",
68                         udev->busid, udev->bConfigurationValue, i);
69
70         suinf = sysfs_open_device("usb", busid);
71         if (!suinf)
72                 err("sysfs_open_device %s", busid);
73
74         return suinf;
75 }
76
77
78 #define MAX_BUFF 100
79 static int record_connection(char *host, char *port, char *busid, int rhport)
80 {
81         int fd;
82         char path[PATH_MAX+1];
83         char buff[MAX_BUFF+1];
84         int ret;
85
86         mkdir(VHCI_STATE_PATH, 0700);
87
88         snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
89
90         fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
91         if (fd < 0)
92                 return -1;
93
94         snprintf(buff, MAX_BUFF, "%s %s %s\n",
95                         host, port, busid);
96
97         ret = write(fd, buff, strlen(buff));
98         if (ret != (ssize_t) strlen(buff)) {
99                 close(fd);
100                 return -1;
101         }
102
103         close(fd);
104
105         return 0;
106 }
107
108 static int read_record(int rhport, char *host, char *port, char *busid)
109 {
110         FILE *file;
111         char path[PATH_MAX+1];
112
113         snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
114
115         file = fopen(path, "r");
116         if (!file) {
117                 err("fopen");
118                 return -1;
119         }
120
121         if (fscanf(file, "%s %s %s\n", host, port, busid) != 3) {
122                 err("fscanf");
123                 fclose(file);
124                 return -1;
125         }
126
127         fclose(file);
128
129         return 0;
130 }
131
132
133 int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
134 {
135         char product_name[100];
136         char host[NI_MAXHOST] = "unknown host";
137         char serv[NI_MAXSERV] = "unknown port";
138         char remote_busid[SYSFS_BUS_ID_SIZE];
139         int ret;
140
141         if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) {
142                 info("Port %02d: <%s>", idev->port, usbip_status_string(idev->status));
143                 return 0;
144         }
145
146         ret = read_record(idev->port, host, serv, remote_busid);
147         if (ret) {
148                 err("read_record");
149                 return -1;
150         }
151
152         info("Port %02d: <%s> at %s", idev->port,
153                         usbip_status_string(idev->status), usbip_speed_string(idev->udev.speed));
154
155         usbip_names_get_product(product_name, sizeof(product_name),
156                         idev->udev.idVendor, idev->udev.idProduct);
157
158         info("       %s",  product_name);
159
160         info("%10s -> usbip://%s:%s/%s  (remote devid %08x (bus/dev %03d/%03d))",
161                         idev->udev.busid, host, serv, remote_busid,
162                         idev->devid,
163                         idev->busnum, idev->devnum);
164
165         for (int i=0; i < idev->udev.bNumInterfaces; i++) {
166                 /* show interface information */
167                 struct sysfs_device *suinf;
168
169                 suinf = open_usb_interface(&idev->udev, i);
170                 if (!suinf)
171                         continue;
172
173                 info("       %6s used by %-17s", suinf->bus_id, suinf->driver_name);
174                 sysfs_close_device(suinf);
175
176                 /* show class device information */
177                 struct usbip_class_device *cdev;
178
179                 dlist_for_each_data(idev->cdev_list, cdev,
180                                     struct usbip_class_device) {
181                         int ifnum = get_interface_number(cdev->dev_path);
182                         if (ifnum == i) {
183                                 info("           %s", cdev->class_path);
184                         }
185                 }
186         }
187
188         return 0;
189 }
190
191
192
193
194 static int query_exported_devices(int sockfd)
195 {
196         int ret;
197         struct op_devlist_reply rep;
198         uint16_t code = OP_REP_DEVLIST;
199
200         bzero(&rep, sizeof(rep));
201
202         ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
203         if (ret < 0) {
204                 err("send op_common");
205                 return -1;
206         }
207
208         ret = usbip_recv_op_common(sockfd, &code);
209         if (ret < 0) {
210                 err("recv op_common");
211                 return -1;
212         }
213
214         ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
215         if (ret < 0) {
216                 err("recv op_devlist");
217                 return -1;
218         }
219
220         PACK_OP_DEVLIST_REPLY(0, &rep);
221         dbg("exportable %d devices", rep.ndev);
222
223         for (unsigned int i=0; i < rep.ndev; i++) {
224                 char product_name[100];
225                 char class_name[100];
226                 struct usb_device udev;
227
228                 bzero(&udev, sizeof(udev));
229
230                 ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
231                 if (ret < 0) {
232                         err("recv usb_device[%d]", i);
233                         return -1;
234                 }
235                 pack_usb_device(0, &udev);
236
237                 usbip_names_get_product(product_name, sizeof(product_name),
238                                 udev.idVendor, udev.idProduct);
239                 usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass,
240                                 udev.bDeviceSubClass, udev.bDeviceProtocol);
241
242                 info("%8s: %s", udev.busid, product_name);
243                 info("%8s: %s", " ", udev.path);
244                 info("%8s: %s", " ", class_name);
245
246                 for (int j=0; j < udev.bNumInterfaces; j++) {
247                         struct usb_interface uinf;
248
249                         ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
250                         if (ret < 0) {
251                                 err("recv usb_interface[%d]", j);
252                                 return -1;
253                         }
254
255                         pack_usb_interface(0, &uinf);
256                         usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
257                                         uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
258
259                         info("%8s: %2d - %s", " ", j, class_name);
260                 }
261
262                 info(" ");
263         }
264
265         return rep.ndev;
266 }
267
268 static int import_device(int sockfd, struct usb_device *udev)
269 {
270         int ret;
271         int port;
272
273         ret = usbip_vhci_driver_open();
274         if (ret < 0) {
275                 err("open vhci_driver");
276                 return -1;
277         }
278
279         port = usbip_vhci_get_free_port();
280         if (port < 0) {
281                 err("no free port");
282                 usbip_vhci_driver_close();
283                 return -1;
284         }
285
286         ret = usbip_vhci_attach_device(port, sockfd, udev->busnum,
287                         udev->devnum, udev->speed);
288         if (ret < 0) {
289                 err("import device");
290                 usbip_vhci_driver_close();
291                 return -1;
292         }
293
294         usbip_vhci_driver_close();
295
296         return port;
297 }
298
299
300 static int query_import_device(int sockfd, char *busid)
301 {
302         int ret;
303         struct op_import_request request;
304         struct op_import_reply   reply;
305         uint16_t code = OP_REP_IMPORT;
306
307         bzero(&request, sizeof(request));
308         bzero(&reply, sizeof(reply));
309
310
311         /* send a request */
312         ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0);
313         if (ret < 0) {
314                 err("send op_common");
315                 return -1;
316         }
317
318         strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
319
320         PACK_OP_IMPORT_REQUEST(0, &request);
321
322         ret = usbip_send(sockfd, (void *) &request, sizeof(request));
323         if (ret < 0) {
324                 err("send op_import_request");
325                 return -1;
326         }
327
328
329         /* recieve a reply */
330         ret = usbip_recv_op_common(sockfd, &code);
331         if (ret < 0) {
332                 err("recv op_common");
333                 return -1;
334         }
335
336         ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply));
337         if (ret < 0) {
338                 err("recv op_import_reply");
339                 return -1;
340         }
341
342         PACK_OP_IMPORT_REPLY(0, &reply);
343
344
345         /* check the reply */
346         if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
347                 err("recv different busid %s", reply.udev.busid);
348                 return -1;
349         }
350
351
352         /* import a device */
353         return import_device(sockfd, &reply.udev);
354 }
355
356 static int attach_device(char *host, char *busid)
357 {
358         int sockfd;
359         int ret;
360         int rhport;
361
362         sockfd = tcp_connect(host, USBIP_PORT_STRING);
363         if (sockfd < 0) {
364                 err("tcp connect");
365                 return -1;
366         }
367
368         rhport = query_import_device(sockfd, busid);
369         if (rhport < 0) {
370                 err("query");
371                 return -1;
372         }
373
374         close(sockfd);
375
376         ret = record_connection(host, USBIP_PORT_STRING,
377                         busid, rhport);
378         if (ret < 0) {
379                 err("record connection");
380                 return -1;
381         }
382
383         return 0;
384 }
385
386 static int detach_port(char *port)
387 {
388         int ret;
389         uint8_t portnum;
390
391         for (unsigned int i=0; i < strlen(port); i++)
392                 if (!isdigit(port[i])) {
393                         err("invalid port %s", port);
394                         return -1;
395                 }
396
397         /* check max port */
398
399         portnum = atoi(port);
400
401         ret = usbip_vhci_driver_open();
402         if (ret < 0) {
403                 err("open vhci_driver");
404                 return -1;
405         }
406
407         ret = usbip_vhci_detach_device(portnum);
408         if (ret < 0)
409                 return -1;
410
411         usbip_vhci_driver_close();
412
413         return ret;
414 }
415
416 static int show_exported_devices(char *host)
417 {
418         int ret;
419         int sockfd;
420
421         sockfd = tcp_connect(host, USBIP_PORT_STRING);
422         if (sockfd < 0) {
423                 err("- %s failed", host);
424                 return -1;
425         }
426
427         info("- %s", host);
428
429         ret = query_exported_devices(sockfd);
430         if (ret < 0) {
431                 err("query");
432                 return -1;
433         }
434
435         close(sockfd);
436         return 0;
437 }
438
439 static int attach_exported_devices(char *host, int sockfd)
440 {
441         int ret;
442         struct op_devlist_reply rep;
443         uint16_t code = OP_REP_DEVLIST;
444
445         bzero(&rep, sizeof(rep));
446
447         ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
448         if(ret < 0) {
449                 err("send op_common");
450                 return -1;
451         }
452
453         ret = usbip_recv_op_common(sockfd, &code);
454         if(ret < 0) {
455                 err("recv op_common");
456                 return -1;
457         }
458
459         ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
460         if(ret < 0) {
461                 err("recv op_devlist");
462                 return -1;
463         }
464
465         PACK_OP_DEVLIST_REPLY(0, &rep);
466         dbg("exportable %d devices", rep.ndev);
467
468         for(unsigned int i=0; i < rep.ndev; i++) {
469                 char product_name[100];
470                 char class_name[100];
471                 struct usb_device udev;
472
473                 bzero(&udev, sizeof(udev));
474
475                 ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
476                 if(ret < 0) {
477                         err("recv usb_device[%d]", i);
478                         return -1;
479                 }
480                 pack_usb_device(0, &udev);
481
482                 usbip_names_get_product(product_name, sizeof(product_name),
483                                 udev.idVendor, udev.idProduct);
484                 usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass,
485                                 udev.bDeviceSubClass, udev.bDeviceProtocol);
486
487                 dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name);
488
489                 for (int j=0; j < udev.bNumInterfaces; j++) {
490                         struct usb_interface uinf;
491
492                         ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
493                         if (ret < 0) {
494                                 err("recv usb_interface[%d]", j);
495                                 return -1;
496                         }
497
498                         pack_usb_interface(0, &uinf);
499                         usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
500                                         uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
501
502                         dbg("interface %2d - %s", j, class_name);
503                 }
504
505                 attach_device(host, udev.busid);
506         }
507
508         return rep.ndev;
509 }
510
511 static int attach_devices_all(char *host)
512 {
513         int ret;
514         int sockfd;
515
516         sockfd = tcp_connect(host, USBIP_PORT_STRING);
517         if(sockfd < 0) {
518                 err("- %s failed", host);
519                 return -1;
520         }
521
522         info("- %s", host);
523
524         ret = attach_exported_devices(host, sockfd);
525         if(ret < 0) {
526                 err("query");
527                 return -1;
528         }
529
530         close(sockfd);
531         return 0;
532 }
533
534
535 const char help_message[] = "\
536 Usage: usbip [options]                          \n\
537         -a, --attach [host] [bus_id]            \n\
538                 Attach a remote USB device.     \n\
539                                                 \n\
540         -x, --attachall [host]          \n\
541                 Attach all remote USB devices on the specific host.     \n\
542                                                 \n\
543         -d, --detach [ports]                    \n\
544                 Detach an imported USB device.  \n\
545                                                 \n\
546         -l, --list [hosts]                      \n\
547                 List exported USB devices.      \n\
548                                                 \n\
549         -p, --port                              \n\
550                 List virtual USB port status.   \n\
551                                                 \n\
552         -D, --debug                             \n\
553                 Print debugging information.    \n\
554                                                 \n\
555         -v, --version                           \n\
556                 Show version.                   \n\
557                                                 \n\
558         -h, --help                              \n\
559                 Print this help.                \n";
560
561 static void show_help(void)
562 {
563         printf("%s", help_message);
564 }
565
566 static int show_port_status(void)
567 {
568         int ret;
569         struct usbip_imported_device *idev;
570
571         ret = usbip_vhci_driver_open();
572         if (ret < 0)
573                 return ret;
574
575         for (int i = 0; i < vhci_driver->nports; i++) {
576                 idev = &vhci_driver->idev[i];
577
578                 if (usbip_vhci_imported_device_dump(idev) < 0)
579                         ret = -1;
580         }
581
582         usbip_vhci_driver_close();
583
584         return ret;
585 }
586
587 #define _GNU_SOURCE
588 #include <getopt.h>
589 static const struct option longopts[] = {
590         {"attach",      no_argument,    NULL, 'a'},
591         {"attachall",   no_argument,    NULL, 'x'},
592         {"detach",      no_argument,    NULL, 'd'},
593         {"port",        no_argument,    NULL, 'p'},
594         {"list",        no_argument,    NULL, 'l'},
595         {"version",     no_argument,    NULL, 'v'},
596         {"help",        no_argument,    NULL, 'h'},
597         {"debug",       no_argument,    NULL, 'D'},
598         {"syslog",      no_argument,    NULL, 'S'},
599         {NULL,          0,              NULL,  0}
600 };
601
602 int main(int argc, char *argv[])
603 {
604         int ret;
605
606         enum {
607                 cmd_attach = 1,
608                 cmd_attachall,
609                 cmd_detach,
610                 cmd_port,
611                 cmd_list,
612                 cmd_help,
613                 cmd_version
614         } cmd = 0;
615
616         usbip_use_stderr = 1;
617
618         if (geteuid() != 0)
619                 g_warning("running non-root?");
620
621         ret = usbip_names_init(USBIDS_FILE);
622         if (ret)
623                 notice("failed to open %s", USBIDS_FILE);
624
625         for (;;) {
626                 int c;
627                 int index = 0;
628
629                 c = getopt_long(argc, argv, "adplvhDSx", longopts, &index);
630
631                 if (c == -1)
632                         break;
633
634                 switch(c) {
635                         case 'a':
636                                 if (!cmd)
637                                         cmd = cmd_attach;
638                                 else
639                                         cmd = cmd_help;
640                                 break;
641                         case 'd':
642                                 if (!cmd)
643                                         cmd = cmd_detach;
644                                 else
645                                         cmd = cmd_help;
646                                 break;
647                         case 'p':
648                                 if (!cmd)
649                                         cmd = cmd_port;
650                                 else cmd = cmd_help;
651                                 break;
652                         case 'l':
653                                 if (!cmd)
654                                         cmd = cmd_list;
655                                 else
656                                         cmd = cmd_help;
657                                 break;
658                         case 'v':
659                                 if (!cmd)
660                                         cmd = cmd_version;
661                                 else
662                                         cmd = cmd_help;
663                                 break;
664                         case 'x':
665                                 if(!cmd)
666                                         cmd = cmd_attachall;
667                                 else
668                                         cmd = cmd_help;
669                                 break;
670                         case 'h':
671                                 cmd = cmd_help;
672                                 break;
673                         case 'D':
674                                 usbip_use_debug = 1;
675                                 break;
676                         case 'S':
677                                 usbip_use_syslog = 1;
678                                 break;
679                         case '?':
680                                 break;
681
682                         default:
683                                 err("getopt");
684                 }
685         }
686
687         ret = 0;
688         switch(cmd) {
689                 case cmd_attach:
690                         if (optind == argc - 2)
691                                 ret = attach_device(argv[optind], argv[optind+1]);
692                         else
693                                 show_help();
694                         break;
695                 case cmd_detach:
696                         while (optind < argc)
697                                 ret = detach_port(argv[optind++]);
698                         break;
699                 case cmd_port:
700                         ret = show_port_status();
701                         break;
702                 case cmd_list:
703                         while (optind < argc)
704                                 ret = show_exported_devices(argv[optind++]);
705                         break;
706                 case cmd_attachall:
707                         while(optind < argc)
708                                 ret = attach_devices_all(argv[optind++]);
709                         break;
710                 case cmd_version:
711                         printf("%s\n", version);
712                         break;
713                 case cmd_help:
714                         show_help();
715                         break;
716                 default:
717                         show_help();
718         }
719
720
721         usbip_names_free();
722
723         exit((ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
724 }