Linux-libre 3.0.60-gnu1
[librecmc/linux-libre.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 class_device *cdev;
178
179                 dlist_for_each_data(idev->cdev_list, cdev, struct class_device) {
180                         int ifnum = get_interface_number(cdev->devpath);
181                         if (ifnum == i) {
182                                 info("           %s", cdev->clspath);
183                         }
184                 }
185         }
186
187         return 0;
188 }
189
190
191
192
193 static int query_exported_devices(int sockfd)
194 {
195         int ret;
196         struct op_devlist_reply rep;
197         uint16_t code = OP_REP_DEVLIST;
198
199         bzero(&rep, sizeof(rep));
200
201         ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
202         if (ret < 0) {
203                 err("send op_common");
204                 return -1;
205         }
206
207         ret = usbip_recv_op_common(sockfd, &code);
208         if (ret < 0) {
209                 err("recv op_common");
210                 return -1;
211         }
212
213         ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
214         if (ret < 0) {
215                 err("recv op_devlist");
216                 return -1;
217         }
218
219         PACK_OP_DEVLIST_REPLY(0, &rep);
220         dbg("exportable %d devices", rep.ndev);
221
222         for (unsigned int i=0; i < rep.ndev; i++) {
223                 char product_name[100];
224                 char class_name[100];
225                 struct usb_device udev;
226
227                 bzero(&udev, sizeof(udev));
228
229                 ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
230                 if (ret < 0) {
231                         err("recv usb_device[%d]", i);
232                         return -1;
233                 }
234                 pack_usb_device(0, &udev);
235
236                 usbip_names_get_product(product_name, sizeof(product_name),
237                                 udev.idVendor, udev.idProduct);
238                 usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass,
239                                 udev.bDeviceSubClass, udev.bDeviceProtocol);
240
241                 info("%8s: %s", udev.busid, product_name);
242                 info("%8s: %s", " ", udev.path);
243                 info("%8s: %s", " ", class_name);
244
245                 for (int j=0; j < udev.bNumInterfaces; j++) {
246                         struct usb_interface uinf;
247
248                         ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
249                         if (ret < 0) {
250                                 err("recv usb_interface[%d]", j);
251                                 return -1;
252                         }
253
254                         pack_usb_interface(0, &uinf);
255                         usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
256                                         uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
257
258                         info("%8s: %2d - %s", " ", j, class_name);
259                 }
260
261                 info(" ");
262         }
263
264         return rep.ndev;
265 }
266
267 static int import_device(int sockfd, struct usb_device *udev)
268 {
269         int ret;
270         int port;
271
272         ret = usbip_vhci_driver_open();
273         if (ret < 0) {
274                 err("open vhci_driver");
275                 return -1;
276         }
277
278         port = usbip_vhci_get_free_port();
279         if (port < 0) {
280                 err("no free port");
281                 usbip_vhci_driver_close();
282                 return -1;
283         }
284
285         ret = usbip_vhci_attach_device(port, sockfd, udev->busnum,
286                         udev->devnum, udev->speed);
287         if (ret < 0) {
288                 err("import device");
289                 usbip_vhci_driver_close();
290                 return -1;
291         }
292
293         usbip_vhci_driver_close();
294
295         return port;
296 }
297
298
299 static int query_import_device(int sockfd, char *busid)
300 {
301         int ret;
302         struct op_import_request request;
303         struct op_import_reply   reply;
304         uint16_t code = OP_REP_IMPORT;
305
306         bzero(&request, sizeof(request));
307         bzero(&reply, sizeof(reply));
308
309
310         /* send a request */
311         ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0);
312         if (ret < 0) {
313                 err("send op_common");
314                 return -1;
315         }
316
317         strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
318
319         PACK_OP_IMPORT_REQUEST(0, &request);
320
321         ret = usbip_send(sockfd, (void *) &request, sizeof(request));
322         if (ret < 0) {
323                 err("send op_import_request");
324                 return -1;
325         }
326
327
328         /* recieve a reply */
329         ret = usbip_recv_op_common(sockfd, &code);
330         if (ret < 0) {
331                 err("recv op_common");
332                 return -1;
333         }
334
335         ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply));
336         if (ret < 0) {
337                 err("recv op_import_reply");
338                 return -1;
339         }
340
341         PACK_OP_IMPORT_REPLY(0, &reply);
342
343
344         /* check the reply */
345         if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
346                 err("recv different busid %s", reply.udev.busid);
347                 return -1;
348         }
349
350
351         /* import a device */
352         return import_device(sockfd, &reply.udev);
353 }
354
355 static int attach_device(char *host, char *busid)
356 {
357         int sockfd;
358         int ret;
359         int rhport;
360
361         sockfd = tcp_connect(host, USBIP_PORT_STRING);
362         if (sockfd < 0) {
363                 err("tcp connect");
364                 return -1;
365         }
366
367         rhport = query_import_device(sockfd, busid);
368         if (rhport < 0) {
369                 err("query");
370                 return -1;
371         }
372
373         close(sockfd);
374
375         ret = record_connection(host, USBIP_PORT_STRING,
376                         busid, rhport);
377         if (ret < 0) {
378                 err("record connection");
379                 return -1;
380         }
381
382         return 0;
383 }
384
385 static int detach_port(char *port)
386 {
387         int ret;
388         uint8_t portnum;
389
390         for (unsigned int i=0; i < strlen(port); i++)
391                 if (!isdigit(port[i])) {
392                         err("invalid port %s", port);
393                         return -1;
394                 }
395
396         /* check max port */
397
398         portnum = atoi(port);
399
400         ret = usbip_vhci_driver_open();
401         if (ret < 0) {
402                 err("open vhci_driver");
403                 return -1;
404         }
405
406         ret = usbip_vhci_detach_device(portnum);
407         if (ret < 0)
408                 return -1;
409
410         usbip_vhci_driver_close();
411
412         return ret;
413 }
414
415 static int show_exported_devices(char *host)
416 {
417         int ret;
418         int sockfd;
419
420         sockfd = tcp_connect(host, USBIP_PORT_STRING);
421         if (sockfd < 0) {
422                 err("- %s failed", host);
423                 return -1;
424         }
425
426         info("- %s", host);
427
428         ret = query_exported_devices(sockfd);
429         if (ret < 0) {
430                 err("query");
431                 return -1;
432         }
433
434         close(sockfd);
435         return 0;
436 }
437
438 static int attach_exported_devices(char *host, int sockfd)
439 {
440         int ret;
441         struct op_devlist_reply rep;
442         uint16_t code = OP_REP_DEVLIST;
443
444         bzero(&rep, sizeof(rep));
445
446         ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
447         if(ret < 0) {
448                 err("send op_common");
449                 return -1;
450         }
451
452         ret = usbip_recv_op_common(sockfd, &code);
453         if(ret < 0) {
454                 err("recv op_common");
455                 return -1;
456         }
457
458         ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep));
459         if(ret < 0) {
460                 err("recv op_devlist");
461                 return -1;
462         }
463
464         PACK_OP_DEVLIST_REPLY(0, &rep);
465         dbg("exportable %d devices", rep.ndev);
466
467         for(unsigned int i=0; i < rep.ndev; i++) {
468                 char product_name[100];
469                 char class_name[100];
470                 struct usb_device udev;
471
472                 bzero(&udev, sizeof(udev));
473
474                 ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev));
475                 if(ret < 0) {
476                         err("recv usb_device[%d]", i);
477                         return -1;
478                 }
479                 pack_usb_device(0, &udev);
480
481                 usbip_names_get_product(product_name, sizeof(product_name),
482                                 udev.idVendor, udev.idProduct);
483                 usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass,
484                                 udev.bDeviceSubClass, udev.bDeviceProtocol);
485
486                 dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name);
487
488                 for (int j=0; j < udev.bNumInterfaces; j++) {
489                         struct usb_interface uinf;
490
491                         ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf));
492                         if (ret < 0) {
493                                 err("recv usb_interface[%d]", j);
494                                 return -1;
495                         }
496
497                         pack_usb_interface(0, &uinf);
498                         usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass,
499                                         uinf.bInterfaceSubClass, uinf.bInterfaceProtocol);
500
501                         dbg("interface %2d - %s", j, class_name);
502                 }
503
504                 attach_device(host, udev.busid);
505         }
506
507         return rep.ndev;
508 }
509
510 static int attach_devices_all(char *host)
511 {
512         int ret;
513         int sockfd;
514
515         sockfd = tcp_connect(host, USBIP_PORT_STRING);
516         if(sockfd < 0) {
517                 err("- %s failed", host);
518                 return -1;
519         }
520
521         info("- %s", host);
522
523         ret = attach_exported_devices(host, sockfd);
524         if(ret < 0) {
525                 err("query");
526                 return -1;
527         }
528
529         close(sockfd);
530         return 0;
531 }
532
533
534 const char help_message[] = "\
535 Usage: usbip [options]                          \n\
536         -a, --attach [host] [bus_id]            \n\
537                 Attach a remote USB device.     \n\
538                                                 \n\
539         -x, --attachall [host]          \n\
540                 Attach all remote USB devices on the specific host.     \n\
541                                                 \n\
542         -d, --detach [ports]                    \n\
543                 Detach an imported USB device.  \n\
544                                                 \n\
545         -l, --list [hosts]                      \n\
546                 List exported USB devices.      \n\
547                                                 \n\
548         -p, --port                              \n\
549                 List virtual USB port status.   \n\
550                                                 \n\
551         -D, --debug                             \n\
552                 Print debugging information.    \n\
553                                                 \n\
554         -v, --version                           \n\
555                 Show version.                   \n\
556                                                 \n\
557         -h, --help                              \n\
558                 Print this help.                \n";
559
560 static void show_help(void)
561 {
562         printf("%s", help_message);
563 }
564
565 static int show_port_status(void)
566 {
567         int ret;
568         struct usbip_imported_device *idev;
569
570         ret = usbip_vhci_driver_open();
571         if (ret < 0)
572                 return ret;
573
574         for (int i = 0; i < vhci_driver->nports; i++) {
575                 idev = &vhci_driver->idev[i];
576
577                 if (usbip_vhci_imported_device_dump(idev) < 0)
578                         ret = -1;
579         }
580
581         usbip_vhci_driver_close();
582
583         return ret;
584 }
585
586 #define _GNU_SOURCE
587 #include <getopt.h>
588 static const struct option longopts[] = {
589         {"attach",      no_argument,    NULL, 'a'},
590         {"attachall",   no_argument,    NULL, 'x'},
591         {"detach",      no_argument,    NULL, 'd'},
592         {"port",        no_argument,    NULL, 'p'},
593         {"list",        no_argument,    NULL, 'l'},
594         {"version",     no_argument,    NULL, 'v'},
595         {"help",        no_argument,    NULL, 'h'},
596         {"debug",       no_argument,    NULL, 'D'},
597         {"syslog",      no_argument,    NULL, 'S'},
598         {NULL,          0,              NULL,  0}
599 };
600
601 int main(int argc, char *argv[])
602 {
603         int ret;
604
605         enum {
606                 cmd_attach = 1,
607                 cmd_attachall,
608                 cmd_detach,
609                 cmd_port,
610                 cmd_list,
611                 cmd_help,
612                 cmd_version
613         } cmd = 0;
614
615         usbip_use_stderr = 1;
616
617         if (geteuid() != 0)
618                 g_warning("running non-root?");
619
620         ret = usbip_names_init(USBIDS_FILE);
621         if (ret)
622                 notice("failed to open %s", USBIDS_FILE);
623
624         for (;;) {
625                 int c;
626                 int index = 0;
627
628                 c = getopt_long(argc, argv, "adplvhDSx", longopts, &index);
629
630                 if (c == -1)
631                         break;
632
633                 switch(c) {
634                         case 'a':
635                                 if (!cmd)
636                                         cmd = cmd_attach;
637                                 else
638                                         cmd = cmd_help;
639                                 break;
640                         case 'd':
641                                 if (!cmd)
642                                         cmd = cmd_detach;
643                                 else
644                                         cmd = cmd_help;
645                                 break;
646                         case 'p':
647                                 if (!cmd)
648                                         cmd = cmd_port;
649                                 else cmd = cmd_help;
650                                 break;
651                         case 'l':
652                                 if (!cmd)
653                                         cmd = cmd_list;
654                                 else
655                                         cmd = cmd_help;
656                                 break;
657                         case 'v':
658                                 if (!cmd)
659                                         cmd = cmd_version;
660                                 else
661                                         cmd = cmd_help;
662                                 break;
663                         case 'x':
664                                 if(!cmd)
665                                         cmd = cmd_attachall;
666                                 else
667                                         cmd = cmd_help;
668                                 break;
669                         case 'h':
670                                 cmd = cmd_help;
671                                 break;
672                         case 'D':
673                                 usbip_use_debug = 1;
674                                 break;
675                         case 'S':
676                                 usbip_use_syslog = 1;
677                                 break;
678                         case '?':
679                                 break;
680
681                         default:
682                                 err("getopt");
683                 }
684         }
685
686         ret = 0;
687         switch(cmd) {
688                 case cmd_attach:
689                         if (optind == argc - 2)
690                                 ret = attach_device(argv[optind], argv[optind+1]);
691                         else
692                                 show_help();
693                         break;
694                 case cmd_detach:
695                         while (optind < argc)
696                                 ret = detach_port(argv[optind++]);
697                         break;
698                 case cmd_port:
699                         ret = show_port_status();
700                         break;
701                 case cmd_list:
702                         while (optind < argc)
703                                 ret = show_exported_devices(argv[optind++]);
704                         break;
705                 case cmd_attachall:
706                         while(optind < argc)
707                                 ret = attach_devices_all(argv[optind++]);
708                         break;
709                 case cmd_version:
710                         printf("%s\n", version);
711                         break;
712                 case cmd_help:
713                         show_help();
714                         break;
715                 default:
716                         show_help();
717         }
718
719
720         usbip_names_free();
721
722         exit((ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE);
723 }