/* Sysfs entry to shutdown a virtual connection */ static int vhci_port_disconnect(__u32 rhport) { struct vhci_device *vdev; usbip_dbg_vhci_sysfs("enter\n"); /* lock */ spin_lock(&the_controller->lock); vdev = port_to_vdev(rhport); spin_lock(&vdev->ud.lock); if (vdev->ud.status == VDEV_ST_NULL) { pr_err("not connected %d\n", vdev->ud.status); /* unlock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); return -EINVAL; } /* unlock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); return 0; }
static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *out) { char *s = out; int i = 0; if (!the_controller || !out) { if(!the_controller) err("'the_controller' is undefined"); if(!out) err("'out' is undefined"); //BUG(); return -1; } spin_lock(&the_controller->lock); /* * output example: * prt sta bus dev socket local_busid * 000 004 000 000 c5a7bb80 1-2.3 * 001 004 000 000 d8cee980 2-3.4 * * IP address can be retrieved from a socket pointer address by looking * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a * port number and its peer IP address. */ out += sprintf(out, "prt sta spd bus dev socket local_busid\n"); for (i=0; i < VHCI_NPORTS; i++) { struct vhci_device *vdev = port_to_vdev(i); spin_lock(&vdev->ud.lock); out += sprintf(out, "%03u %03u ", i, vdev->ud.status); if (vdev->ud.status == VDEV_ST_USED) { out += sprintf(out, "%03u %03u %03u ", vdev->speed, vdev->busnum, vdev->devnum); out += sprintf(out, "%16p ", vdev->ud.tcp_socket); out += sprintf(out, "%s", vdev->udev->dev.bus_id); } else out += sprintf(out, "000 000 000 0000000000000000 0-0"); out += sprintf(out, "\n"); spin_unlock(&vdev->ud.lock); } spin_unlock(&the_controller->lock); return out - s ; }
/* FIXME: ipv4 only code */ static int print_client_ip(struct device *dev, struct device_attribute *attr, char *out) { int i; int ret; int size; __u32 ip; char *s = out; if (!the_controller || !out) BUG(); spin_lock(&the_controller->lock); for (i=0; i < VHCI_NPORTS; i++) { struct socket *sock; struct sockaddr_in inaddr; struct vhci_device *vdev = port_to_vdev(i); spin_lock(&vdev->ud.lock); if( vdev->ud.status != VDEV_ST_USED ) { out += snprintf(out, 15, "%d -\n", i ); spin_unlock(&vdev->ud.lock); continue; } sock = vdev->ud.tcp_socket; size = sizeof(struct sockaddr); ret = sock->ops->getname(sock, (struct sockaddr *)&inaddr, &size, 0); if( ! ret ) { spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); return -ENODEV; } ip = ntohl(inaddr.sin_addr.s_addr); out += snprintf( out, 15, "%d %u\n", i, ip ); spin_unlock(&vdev->ud.lock); } spin_unlock(&the_controller->lock); return out-s; }
/* * To start a new USB/IP attachment, a userland program needs to setup a TCP * connection and then write its socket descriptor with remote device * information into this sysfs file. * * A remote device is virtually attached to the root-hub port of @rhport with * @speed. @devid is embedded into a request to specify the remote device in a * server host. * * write() returns 0 on success, else negative errno. */ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vhci_device *vdev; struct socket *socket; int sockfd = 0; __u32 rhport = 0, devid = 0, speed = 0; /* * @rhport: port number of vhci_hcd * @sockfd: socket descriptor of an established TCP connection * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed); usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", rhport, sockfd, devid, speed); /* check received parameters */ if (valid_args(rhport, speed) < 0) return -EINVAL; /* check sockfd */ socket = sockfd_to_socket(sockfd); if (!socket) return -EINVAL; /* now need lock until setting vdev status as used */ /* begin a lock */ spin_lock(&the_controller->lock); vdev = port_to_vdev(rhport); spin_lock(&vdev->ud.lock); if (vdev->ud.status != VDEV_ST_NULL) { /* end of the lock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); usbip_uerr("port %d already used\n", rhport); return -EINVAL; } usbip_uinfo("rhport(%u) sockfd(%d) devid(%u) speed(%u)\n", rhport, sockfd, devid, speed); vdev->devid = devid; vdev->speed = speed; vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; wake_up_process(vdev->ud.tcp_rx); wake_up_process(vdev->ud.tcp_tx); spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); /* end the lock */ rh_port_connect(rhport, speed); return count; }
/* * To start a new USB/IP attachment, a userland program needs to setup a TCP * connection and then write its socket descriptor with remote device * information into this sysfs file. * * A remote device is virtually attached to the root-hub port of @rhport with * @speed. @busnum and @devnum are used to convert URBs between a client host * and a server host. * * write() returns 0 on success, else negative errno. */ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vhci_device *vdev; struct socket *socket; int sockfd = 0; __u32 rhport=0, busnum=0, devnum=0, speed=0; /* * @rhport: port number of vhci_hcd * @sockfd: socket descriptor of an established TCP connection * @busnum: usb bus number in a remote host * @devnum: usb device number in a remote host * @speed: usb device speed in a remote host */ sscanf(buf, "%u %u %u %u %u", &rhport, &sockfd, &busnum, &devnum, &speed); dbg_vhci_sysfs("rhport(%u) sockfd(%u) busnum(%u) devnum(%u) speed(%u)\n", rhport, sockfd, busnum, devnum, speed); /* check received parameters */ if (valid_args(rhport, busnum, devnum, speed) < 0) return -EINVAL; /* check sockfd */ socket = sockfd_to_socket(sockfd); if (!socket) return -EINVAL; #if 0 setnodelay(socket); #endif /* now need lock until setting vdev status as used */ /* begin a lock */ spin_lock(&the_controller->lock); vdev = port_to_vdev(rhport); spin_lock(&vdev->ud.lock); if (vdev->ud.status != VDEV_ST_NULL) { /* end of the lock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); uerr("port %d already used\n", rhport); return -EINVAL; } uinfo("rhport(%u) sockfd(%d) busnum(%u) devnum(%u) speed(%u)\n", rhport, sockfd, busnum, devnum, speed); vdev->busnum = busnum; vdev->devnum = devnum; vdev->speed = speed; vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); /* end the lock */ /* * this function will sleep, so should be out of the lock. but, it's ok * because we already marked vdev as being used. really? */ usbip_start_threads(&vdev->ud); rh_port_connect(rhport, speed); return count; }
/* * To start a new USB/IP attachment, a userland program needs to setup a TCP * connection and then write its socket descriptor with remote device * information into this sysfs file. * * A remote device is virtually attached to the root-hub port of @rhport with * @speed. @devid is embedded into a request to specify the remote device in a * server host. * * write() returns 0 on success, else negative errno. */ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vhci_device *vdev; struct socket *socket; int sockfd = 0; __u32 rhport = 0, devid = 0, speed = 0; int err; /* * @rhport: port number of vhci_hcd * @sockfd: socket descriptor of an established TCP connection * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) return -EINVAL; usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", rhport, sockfd, devid, speed); /* check received parameters */ if (valid_args(rhport, speed) < 0) return -EINVAL; /* Extract socket from fd. */ socket = sockfd_lookup(sockfd, &err); if (!socket) return -EINVAL; /* now need lock until setting vdev status as used */ /* begin a lock */ spin_lock(&the_controller->lock); vdev = port_to_vdev(rhport); spin_lock(&vdev->ud.lock); if (vdev->ud.status != VDEV_ST_NULL) { /* end of the lock */ spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); sockfd_put(socket); dev_err(dev, "port %d already used\n", rhport); return -EINVAL; } dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n", rhport, sockfd, devid, speed, usb_speed_string(speed)); vdev->devid = devid; vdev->speed = speed; vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); /* end the lock */ vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); rh_port_connect(rhport, speed); return count; }