static int attach_exported_devices(char *host, int sockfd) { int ret; struct op_devlist_reply rep; uint16_t code = OP_REP_DEVLIST; bzero(&rep, sizeof(rep)); ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if(ret < 0) { err("send op_common"); return -1; } ret = usbip_recv_op_common(sockfd, &code); if(ret < 0) { err("recv op_common"); return -1; } ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); if(ret < 0) { err("recv op_devlist"); return -1; } PACK_OP_DEVLIST_REPLY(0, &rep); dbg("exportable %d devices", rep.ndev); for(unsigned int i=0; i < rep.ndev; i++) { char product_name[100]; char class_name[100]; struct usb_device udev; bzero(&udev, sizeof(udev)); ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); if(ret < 0) { err("recv usb_device[%d]", i); return -1; } pack_usb_device(0, &udev); usbip_names_get_product(product_name, sizeof(product_name), udev.idVendor, udev.idProduct); usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, udev.bDeviceSubClass, udev.bDeviceProtocol); dbg("Attaching usb port %s from host %s on usbip, with deviceid: %s", udev.busid, host, product_name); attach_device(host, udev.busid); } return rep.ndev; }
/* some members of urb must be substituted before. */ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) { void *buff; struct usbip_iso_packet_descriptor *iso; int np = urb->number_of_packets; int size = np * sizeof(*iso); int i; int ret; int total_length = 0; if (!usb_pipeisoc(urb->pipe)) return 0; /* my Bluetooth dongle gets ISO URBs which are np = 0 */ if (np == 0) return 0; buff = kzalloc(size, GFP_KERNEL); if (!buff) return -ENOMEM; ret = usbip_recv(ud->tcp_socket, buff, size); if (ret != size) { dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n", ret); kfree(buff); if (ud->side == USBIP_STUB) usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); else usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return -EPIPE; } iso = (struct usbip_iso_packet_descriptor *) buff; for (i = 0; i < np; i++) { usbip_iso_packet_correct_endian(&iso[i], 0); usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); total_length += urb->iso_frame_desc[i].actual_length; } kfree(buff); if (total_length != urb->actual_length) { dev_err(&urb->dev->dev, "total length of iso packets %d not equal to actual " "length of buffer %d\n", total_length, urb->actual_length); if (ud->side == USBIP_STUB) usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); else usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return -EPIPE; } return ret; }
static int query_import_device(int sockfd, char *busid) { int ret; struct op_import_request request; struct op_import_reply reply; uint16_t code = OP_REP_IMPORT; bzero(&request, sizeof(request)); bzero(&reply, sizeof(reply)); /* send a request */ ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0); if (ret < 0) { err("send op_common"); return -1; } strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1); PACK_OP_IMPORT_REQUEST(0, &request); ret = usbip_send(sockfd, (void *) &request, sizeof(request)); if (ret < 0) { err("send op_import_request"); return -1; } /* recieve a reply */ ret = usbip_recv_op_common(sockfd, &code); if (ret < 0) { err("recv op_common"); return -1; } ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply)); if (ret < 0) { err("recv op_import_reply"); return -1; } PACK_OP_IMPORT_REPLY(0, &reply); /* check the reply */ if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) { err("recv different busid %s", reply.udev.busid); return -1; } /* import a device */ return import_device(sockfd, &reply.udev); }
static int query_import_device(int sockfd, char *busid, struct usb_interface *uinf0, HANDLE * fd) { int ret; struct op_import_request request; struct op_import_reply reply; uint16_t code = OP_REP_IMPORT; memset(&request, 0, sizeof(request)); memset(&reply, 0, sizeof(reply)); /* send a request */ ret = usbip_send_op_common(sockfd, OP_REQ_IMPORT, 0); if (ret < 0) { err("send op_common"); return -1; } strncpy(request.busid, busid, sizeof(request.busid)); request.busid[sizeof(request.busid)-1]=0; PACK_OP_IMPORT_REQUEST(0, &request); ret = usbip_send(sockfd, (void *) &request, sizeof(request)); if (ret < 0) { err("send op_import_request"); return -1; } /* recieve a reply */ ret = usbip_recv_op_common(sockfd, &code); if (ret < 0) { err("recv op_common"); return -1; } ret = usbip_recv(sockfd, (void *) &reply, sizeof(reply)); if (ret < 0) { err("recv op_import_reply"); return -1; } PACK_OP_IMPORT_REPLY(0, &reply); /* check the reply */ if (strncmp(reply.udev.busid, busid, sizeof(reply.udev.busid))) { err("recv different busid %s", reply.udev.busid); return -1; } /* import a device */ return import_device(sockfd, &reply.udev, uinf0, fd); }
/* some members of urb must be substituted before. */ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) { int ret; int size; if (ud->side == USBIP_STUB) { /* the direction of urb must be OUT. */ if (usb_pipein(urb->pipe)) return 0; size = urb->transfer_buffer_length; } else { /* the direction of urb must be IN. */ if (usb_pipeout(urb->pipe)) return 0; size = urb->actual_length; } /* no need to recv xbuff */ if (!(size > 0)) return 0; if (size > urb->transfer_buffer_length) { /* should not happen, probably malicious packet */ if (ud->side == USBIP_STUB) { usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); return 0; } else { usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return -EPIPE; } } ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); if (ret != size) { dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); if (ud->side == USBIP_STUB) { usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); } else { usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return -EPIPE; } } return ret; }
int usbip_recv_op_common(int sockfd, uint16_t *code) { int ret; struct op_common op_common; bzero(&op_common, sizeof(op_common)); ret = usbip_recv(sockfd, (void *) &op_common, sizeof(op_common)); if (ret < 0) { err("recv op_common, %d", ret); goto err; } PACK_OP_COMMON(0, &op_common); if (op_common.version != USBIP_VERSION) { err("version mismatch, %d %d", op_common.version, USBIP_VERSION); goto err; } switch(*code) { case OP_UNSPEC: break; default: if (op_common.code != *code) { info("unexpected pdu %d for %d", op_common.code, *code); goto err; } } if (op_common.status != ST_OK) { info("request failed at peer, %d", op_common.status); goto err; } *code = op_common.code; return 0; err: return -1; }
static int recv_request_devlist(int sockfd) { int ret; struct op_devlist_request req; bzero(&req, sizeof(req)); ret = usbip_recv(sockfd, (void *) &req, sizeof(req)); if (ret < 0) { err("recv devlist request"); return -1; } ret = send_reply_devlist(sockfd); if (ret < 0) { err("send devlist reply"); return -1; } return 0; }
int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) { int ret; int size; if (ud->side == USBIP_STUB) { if (usb_pipein(urb->pipe)) return 0; size = urb->transfer_buffer_length; } else { if (usb_pipeout(urb->pipe)) return 0; size = urb->actual_length; } if (!(size > 0)) return 0; ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size); if (ret != size) { dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret); if (ud->side == USBIP_STUB) { usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); } else { usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return -EPIPE; } } return ret; }
static int query_exported_devices(int sockfd) { int ret; struct op_devlist_reply rep; uint16_t code = OP_REP_DEVLIST; bzero(&rep, sizeof(rep)); ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if (ret < 0) { err("send op_common"); return -1; } ret = usbip_recv_op_common(sockfd, &code); if (ret < 0) { err("recv op_common"); return -1; } ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); if (ret < 0) { err("recv op_devlist"); return -1; } PACK_OP_DEVLIST_REPLY(0, &rep); dbg("exportable %d devices", rep.ndev); for (unsigned int i=0; i < rep.ndev; i++) { char product_name[100]; char class_name[100]; struct usb_device udev; bzero(&udev, sizeof(udev)); ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); if (ret < 0) { err("recv usb_device[%d]", i); return -1; } pack_usb_device(0, &udev); usbip_names_get_product(product_name, sizeof(product_name), udev.idVendor, udev.idProduct); usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, udev.bDeviceSubClass, udev.bDeviceProtocol); info("%8s: %s", udev.busid, product_name); info("%8s: %s", " ", udev.path); info("%8s: %s", " ", class_name); for (int j=0; j < udev.bNumInterfaces; j++) { struct usb_interface uinf; ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf)); if (ret < 0) { err("recv usb_interface[%d]", j); return -1; } pack_usb_interface(0, &uinf); usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass, uinf.bInterfaceSubClass, uinf.bInterfaceProtocol); info("%8s: %2d - %s", " ", j, class_name); } info(" "); } return rep.ndev; }
static int query_interface0(SOCKET sockfd, char * busid, struct usb_interface * uinf0) { int ret; struct op_devlist_reply rep; uint16_t code = OP_REP_DEVLIST; uint32_t i,j; char product_name[100]; char class_name[100]; struct usb_device udev; struct usb_interface uinf; int found=0; memset(&rep, 0, sizeof(rep)); ret = usbip_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if (ret < 0) { err("send op_common"); return -1; } ret = usbip_recv_op_common(sockfd, &code); if (ret < 0) { err("recv op_common"); return -1; } ret = usbip_recv(sockfd, (void *) &rep, sizeof(rep)); if (ret < 0) { err("recv op_devlist"); return -1; } PACK_OP_DEVLIST_REPLY(0, &rep); dbg("exportable %d devices", rep.ndev); for (i=0; i < rep.ndev; i++) { memset(&udev, 0, sizeof(udev)); ret = usbip_recv(sockfd, (void *) &udev, sizeof(udev)); if (ret < 0) { err("recv usb_device[%d]", i); return -1; } pack_usb_device(0, &udev); usbip_names_get_product(product_name, sizeof(product_name), udev.idVendor, udev.idProduct); usbip_names_get_class(class_name, sizeof(class_name), udev.bDeviceClass, udev.bDeviceSubClass, udev.bDeviceProtocol); dbg("%8s: %s", udev.busid, product_name); dbg("%8s: %s", " ", udev.path); dbg("%8s: %s", " ", class_name); for (j=0; j < udev.bNumInterfaces; j++) { ret = usbip_recv(sockfd, (void *) &uinf, sizeof(uinf)); if (ret < 0) { err("recv usb_interface[%d]", j); return -1; } pack_usb_interface(0, &uinf); if(!strcmp(udev.busid, busid)&&j==0){ memcpy(uinf0, &uinf, sizeof(uinf)); found=1; } usbip_names_get_class(class_name, sizeof(class_name), uinf.bInterfaceClass, uinf.bInterfaceSubClass, uinf.bInterfaceProtocol); dbg("%8s: %2d - %s", " ", j, class_name); } dbg(" "); } if(found) return 0; return -1; }
int write_to_dev(char * buf, int buf_len, int len, SOCKET sockfd, HANDLE devfd, OVERLAPPED *ov) { int ret; unsigned long out=0, in_len, iso_len; struct usbip_header * u = (struct usbip_header *)buf; if(len!=sizeof(*u)){ err("read from sock ret %d not equal a usbip_header", len); #ifdef DEBUG usbip_dump_buffer(buf,len); #endif return -1; } if(usbip_header_correct_endian(u, 0)<0) return -1; dbg_file("recv seq %d\n", u->base.seqnum); if ((u->base.seqnum%100)==0) fprintf(stderr,"Receive sequence: %d\r", u->base.seqnum); #ifdef DEBUG usbip_dump_header(u); #endif if(check_out(htonl(u->base.seqnum))) in_len=0; else in_len=u->u.ret_submit.actual_length; iso_len = u->u.ret_submit.number_of_packets * sizeof(struct usbip_iso_packet_descriptor); if(in_len==0&&iso_len==0){ ret=WriteFile(devfd, (char *)u, sizeof(*u), &out, ov); if(!ret||out!=sizeof(*u)){ err("last error:%ld",GetLastError()); err("out:%ld ret:%d",out,ret); err("write dev failed"); return -1; } return 0; } len = sizeof(*u) + in_len + iso_len; if(len>buf_len){ err("too big len %d %ld %ld", len, in_len,iso_len); return -1; } ret=usbip_recv(sockfd, buf+sizeof(*u), in_len+iso_len); if(ret != in_len + iso_len){ err("recv from sock failed %d %ld", ret, in_len + iso_len); return -1; } if(iso_len) fix_iso_desc_endian(sock_read_buf+sizeof(*u)+in_len, u->u.ret_submit.number_of_packets); ret=WriteFile(devfd, buf, len, &out, ov); if(!ret||out!=len){ err("last error:%ld\n",GetLastError()); err("out:%ld ret:%d len:%d\n",out,ret,len); err("write dev failed"); return -1; } return 0; }
static int recv_request_import(int sockfd) { int ret; struct op_import_request req; struct op_common reply; struct usbip_exported_device *edev; int found = 0; int error = 0; bzero(&req, sizeof(req)); bzero(&reply, sizeof(reply)); ret = usbip_recv(sockfd, (void *) &req, sizeof(req)); if (ret < 0) { err("recv import request"); return -1; } PACK_OP_IMPORT_REQUEST(0, &req); dlist_for_each_data(stub_driver->edev_list, edev, struct usbip_exported_device) { if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { dbg("found requested device %s", req.busid); found = 1; break; } } if (found) { /* should set TCP_NODELAY for usbip */ usbip_set_nodelay(sockfd); /* export_device needs a TCP/IP socket descriptor */ ret = usbip_stub_export_device(edev, sockfd); if (ret < 0) error = 1; } else { info("not found requested device %s", req.busid); error = 1; } ret = usbip_send_op_common(sockfd, OP_REP_IMPORT, (!error ? ST_OK : ST_NA)); if (ret < 0) { err("send import reply"); return -1; } if (!error) { struct usb_device pdu_udev; memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); pack_usb_device(1, &pdu_udev); ret = usbip_send(sockfd, (void *) &pdu_udev, sizeof(pdu_udev)); if (ret < 0) { err("send devinfo"); return -1; } } return 0; }