/* * $Id: usbip_common.c 66 2008-04-20 13:19:42Z hirofuchi $ * * Copyright (C) 2003-2008 Takahiro Hirofuchi * * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* 提供的外部接口 usbip_debug_flag 调式的flag,用来决定输入哪些调式信息 usbip_debug 用于修改和打印usbip_debug_flag值 usbip_dump_urb 用户打印urb的内容 usbip_dump_header用于打印usbip_header内容 usbip_start_threads 开启 usbip_device 的接收和发送线程 usbip_stop_threads 停止 usbip_device 的接收和发送线程 usbip_task_init 初始化usbip_task结构体 usbip_xmit 接收和发送TCP包 sockfd_to_socket 将sockfd获得对应的socket对象 usbip_pack_pdu 对pdu和urb进行解压包,即urb和pdu字段之间的相互赋值 usbip_header_correct_endian usbip_header 在网络编码和主机编码之间的转换 usbip_alloc_iso_desc_pdu pdu中的iso的处理,完成urb和pdu之间对iso_desc的信息相互赋值 usbip_recv_iso 接收urb包中的iso_frame_desc数据 usbip_recv_xbuff 接收urb包中的缓存取数据,接收urb->transfer_buffer */ #include <linux/kernel.h> #include <linux/file.h> #include <linux/tcp.h> #include <linux/in.h> #include "usbip_common.h" /* version information */ #define DRIVER_VERSION "$Id: usbip_common.c 66 2008-04-20 13:19:42Z hirofuchi $" #define DRIVER_AUTHOR "Takahiro Hirofuchi <hirofuchi _at_ users.sourceforge.net>" #define DRIVER_DESC "usbip common driver" /*-------------------------------------------------------------------------*/ /* debug routines */ #ifdef CONFIG_USB_DEBUG unsigned long usbip_debug_flag = 0xffffffff; #else unsigned long usbip_debug_flag = 0; #endif EXPORT_SYMBOL(usbip_debug_flag); /* FIXME */ struct device_attribute dev_attr_usbip_debug; EXPORT_SYMBOL(dev_attr_usbip_debug); static ssize_t show_flag(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%lx\n", usbip_debug_flag); } static ssize_t store_flag(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long flag; sscanf(buf, "%lx", &flag); usbip_debug_flag = flag; return count; } DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag); static void usbip_dump_buffer(char *buff, int bufflen) { } static void usbip_dump_pipe(unsigned int p) { } static void usbip_dump_usb_device(struct usb_device *dev) { } static void usbip_dump_request_type(__u8 rt) { } static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd) { } void usbip_dump_urb (struct urb *purb) { } EXPORT_SYMBOL(usbip_dump_urb); void usbip_dump_header(struct usbip_header *pdu) { } EXPORT_SYMBOL(usbip_dump_header); /*-------------------------------------------------------------------------*/ /* thread routines */ //param为usbip_task //将进程后台化,允许信号SIGKILL,将当前进程赋予ut->thread,执行 //usbip_task中loop函数,并complete(ut->thread_done),通知ut已经完成启动 //等待loop函数因返回结束,complete_and_exit(ut->thread_done) int usbip_thread(void *param) { struct usbip_task *ut = (struct usbip_task *) param; if (!ut) return -EINVAL; lock_kernel();//禁止内核的调度 daemonize(ut->name);//进程后台化 allow_signal(SIGKILL);//允许SIGKILL信号的捕捉 ut->thread = current;//对ut->thread进行复制,保存当前进行 unlock_kernel();//解禁内核的调度 /* srv.rb must wait for rx_thread starting */ complete(&ut->thread_done);//通知执行完成 /* start of while loop */ ut->loop_ops(ut); /* end of loop */ ut->thread = NULL; complete_and_exit(&ut->thread_done, 0);//通知usbip_stop_threads中对应的tcp_rx和tcp_tx } //参数usbip_device //启动ud->tcp_rx和ur-tcp_tx这两个接收和发送独立线程,并等待usbip_thread的complete信号 void usbip_start_threads(struct usbip_device *ud) { /* * threads are invoked per one device (per one connection). */ kernel_thread((int(*)(void *))usbip_thread, (void *)&ud->tcp_rx, 0); kernel_thread((int(*)(void *))usbip_thread, (void *)&ud->tcp_tx, 0); /* confirm threads are starting */ wait_for_completion(&ud->tcp_rx.thread_done); wait_for_completion(&ud->tcp_tx.thread_done); } EXPORT_SYMBOL(usbip_start_threads); //参数usbip_device //停止接收和发送两个线程 void usbip_stop_threads(struct usbip_device *ud) { /* kill threads related to this sdev, if v.c. exists */ if (ud->tcp_rx.thread != NULL) { send_sig(SIGKILL, ud->tcp_rx.thread, 1); wait_for_completion(&ud->tcp_rx.thread_done); udbg("rx_thread for ud %p has finished\n", ud); } if (ud->tcp_tx.thread != NULL) { //在usbip_thread中支持allow_signal(SIGKILL)信号 //发送SIGKILL中后,[vhci|stub]_rx_loop中的signal_pending捕获到信号,然后退出循环 send_sig(SIGKILL, ud->tcp_tx.thread, 1); wait_for_completion(&ud->tcp_tx.thread_done);//与usbip_thread中的最后一行complete_and_exit对应 udbg("tx_thread for ud %p has finished\n", ud); } } EXPORT_SYMBOL(usbip_stop_threads); //初始化usbip_task相关属性 void usbip_task_init(struct usbip_task *ut, char *name, void (*loop_ops)(struct usbip_task *)) { ut->thread = NULL; init_completion(&ut->thread_done); ut->name = name; ut->loop_ops = loop_ops; } EXPORT_SYMBOL(usbip_task_init); /*-------------------------------------------------------------------------*/ /* socket routines */ //接收和发送buf,接收和发送通过msg_flags来判断方向 /* Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */ int usbip_xmit(int send, struct socket *sock, char *buf, int size, int msg_flags) { int result; struct msghdr msg; struct kvec iov; int total = 0; /* for blocks of if (dbg_flag_xmit) */ char *bp = buf; int osize= size; dbg_xmit("enter\n"); if (!sock || !buf || !size) { uerr("usbip_xmit: invalid arg, sock %p buff %p size %d\n", sock, buf, size); return -EINVAL; } if (dbg_flag_xmit) { if (send) { if (!in_interrupt()) printk(KERN_DEBUG "%-10s:", current->comm); else printk(KERN_DEBUG "interupt :"); printk("usbip_xmit: sending... , sock %p, buf %p, size %d, msg_flags %d\n", sock, buf, size, msg_flags); usbip_dump_buffer(buf, size); } } do { sock->sk->sk_allocation = GFP_NOIO; iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_namelen = 0; msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (send) result = kernel_sendmsg(sock, &msg, &iov, 1, size); else result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL); if (result <= 0) { udbg("usbip_xmit: %s sock %p buf %p size %u ret %d total %d\n", send ? "send" : "receive", sock, buf, size, result, total); goto err; } size -= result; buf += result; total += result; } while (size > 0); if (dbg_flag_xmit) { if (!send) { if (!in_interrupt()) printk(KERN_DEBUG "%-10s:", current->comm); else printk(KERN_DEBUG "interupt :"); printk("usbip_xmit: receiving....\n"); usbip_dump_buffer(bp, osize); printk("usbip_xmit: received, osize %d ret %d size %d total %d\n", osize, result, size, total); } if (send) { printk("usbip_xmit: send, total %d\n", total); } } return total; err: return result; } EXPORT_SYMBOL(usbip_xmit); //以下四个函数,现在已经移到用户空间程序处理 /* now a usrland utility should set options. */ #if 0 int setquickack(struct socket *socket) { mm_segment_t oldfs; int val = 1; int ret; oldfs = get_fs(); set_fs(get_ds()); ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_QUICKACK, (char __user *) &val, sizeof(ret)); set_fs(oldfs); return ret; } int setnodelay(struct socket *socket) { mm_segment_t oldfs; int val = 1; int ret; oldfs = get_fs(); set_fs(get_ds()); ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_NODELAY, (char __user *) &val, sizeof(ret)); set_fs(oldfs); return ret; } int setkeepalive(struct socket *socket) { mm_segment_t oldfs; int val = 1; int ret; oldfs = get_fs(); set_fs(get_ds()); ret = socket->ops->setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char __user *) &val, sizeof(ret)); set_fs(oldfs); return ret; } void setreuse(struct socket *socket) { socket->sk->sk_reuse = 1; } #endif //参数 uint sockfd //根据sockfd,获取file对象,然后根据file对象,获取inode,调用SOCKET_I(inode)返回socke对象 struct socket *sockfd_to_socket(unsigned int sockfd) { struct socket *socket; struct file *file; struct inode *inode; file = fget(sockfd); if (!file) { uerr("invalid sockfd\n"); return NULL; } //获取file的inode值 inode = file->f_dentry->d_inode; if (!inode || !S_ISSOCK(inode->i_mode)) return NULL; //根据inode值获取socket对象 socket = SOCKET_I(inode); return socket; } EXPORT_SYMBOL(sockfd_to_socket); /*-------------------------------------------------------------------------*/ /* pdu routines */ //去除flags中本驱动不支持的标签,主要去除URB_NO_TRANSFER_DMA_MAP、URB_NO_SETUP_DMA_MAP /* there may be more cases to tweak the flags. */ static unsigned int tweak_transfer_flags(unsigned int flags) { if (flags & URB_NO_TRANSFER_DMA_MAP) /* * vhci_hcd does not provide DMA-mapped I/O. The upper * driver does not need to set this flag. The remote * usbip.ko does not still perform DMA-mapped I/O for * DMA-caplable host controllers. So, clear this flag. */ flags &= ~URB_NO_TRANSFER_DMA_MAP; if (flags & URB_NO_SETUP_DMA_MAP) flags &= ~URB_NO_SETUP_DMA_MAP; return flags; } //针对cmd命令,根据pack确定打包方向,将urb和pdu中的信息进行同步,完成相互复制 static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb, int pack) { struct usbip_header_cmd_submit *spdu = &pdu->u.cmd_submit; /* * Some members are not still implemented in usbip. I hope this issue * will be discussed when usbip is ported to other operating systems. */ if (pack) { /* vhci_tx.c */ spdu->transfer_flags = tweak_transfer_flags(urb->transfer_flags); spdu->transfer_buffer_length = urb->transfer_buffer_length; spdu->start_frame = urb->start_frame; spdu->number_of_packets = urb->number_of_packets; spdu->interval = urb->interval; } else { /* stub_rx.c */ urb->transfer_flags = spdu->transfer_flags; urb->transfer_buffer_length = spdu->transfer_buffer_length; urb->start_frame = spdu->start_frame; urb->number_of_packets = spdu->number_of_packets; urb->interval = spdu->interval; } } //针对ret命令,根据pack确定打包方向,将urb和pdu中的信息进行同步,完成相互复制 static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb, int pack) { struct usbip_header_ret_submit *rpdu = &pdu->u.ret_submit; if (pack) { /* stub_tx.c */ rpdu->status = urb->status; rpdu->actual_length = urb->actual_length; rpdu->start_frame = urb->start_frame; rpdu->error_count = urb->error_count; } else { /* vhci_rx.c */ urb->status = rpdu->status; urb->actual_length = rpdu->actual_length; urb->start_frame = rpdu->start_frame; urb->error_count = rpdu->error_count; } } //根据cmd命令类型和pack打包方向,对pdu和urb进行打包赋值 //调用usbip_pack_cmd_submit和usbip_pack_ret_submit void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, int pack) { switch(cmd) { case USBIP_CMD_SUBMIT: usbip_pack_cmd_submit(pdu, urb, pack); break; case USBIP_RET_SUBMIT: usbip_pack_ret_submit(pdu, urb, pack); break; default: err("unknown command"); /* NOTREACHED */ //BUG(); } } EXPORT_SYMBOL(usbip_pack_pdu); //大小端编码问题,send代码转换方向 static void correct_endian_basic(struct usbip_header_basic *base, int send) { if (send) { base->command = cpu_to_be32(base->command); base->seqnum = cpu_to_be32(base->seqnum); base->devid = cpu_to_be32(base->devid); base->direction = cpu_to_be32(base->direction); base->ep = cpu_to_be32(base->ep); } else { base->command = be32_to_cpu(base->command); base->seqnum = be32_to_cpu(base->seqnum); base->devid = be32_to_cpu(base->devid); base->direction = be32_to_cpu(base->direction); base->ep = be32_to_cpu(base->ep); } } static void correct_endian_cmd_submit(struct usbip_header_cmd_submit *pdu, int send) { if (send) { pdu->transfer_flags = cpu_to_be32(pdu->transfer_flags); cpu_to_be32s(&pdu->transfer_buffer_length); cpu_to_be32s(&pdu->start_frame); cpu_to_be32s(&pdu->number_of_packets); cpu_to_be32s(&pdu->interval); } else { pdu->transfer_flags = be32_to_cpu(pdu->transfer_flags); be32_to_cpus(&pdu->transfer_buffer_length); be32_to_cpus(&pdu->start_frame); be32_to_cpus(&pdu->number_of_packets); be32_to_cpus(&pdu->interval); } } static void correct_endian_ret_submit(struct usbip_header_ret_submit *pdu, int send) { if (send) { cpu_to_be32s(&pdu->status); cpu_to_be32s(&pdu->actual_length); cpu_to_be32s(&pdu->start_frame); cpu_to_be32s(&pdu->error_count); } else { be32_to_cpus(&pdu->status); be32_to_cpus(&pdu->actual_length); be32_to_cpus(&pdu->start_frame); be32_to_cpus(&pdu->error_count); } } static void correct_endian_cmd_unlink(struct usbip_header_cmd_unlink *pdu, int send) { if (send) pdu->seqnum = cpu_to_be32(pdu->seqnum); else pdu->seqnum = be32_to_cpu(pdu->seqnum); } static void correct_endian_ret_unlink(struct usbip_header_ret_unlink *pdu, int send) { if (send) cpu_to_be32s(&pdu->status); else be32_to_cpus(&pdu->status); } //对接收到的pdu进行大小端调正,send代码接收还是发送 //函数根据pdu->base.command来分别对四种pdu包进行解析 void usbip_header_correct_endian(struct usbip_header *pdu, int send) { __u32 cmd = 0; if (send) cmd = pdu->base.command; correct_endian_basic(&pdu->base, send); if (!send) cmd = pdu->base.command; switch (cmd) { case USBIP_CMD_SUBMIT: correct_endian_cmd_submit(&pdu->u.cmd_submit, send); break; case USBIP_RET_SUBMIT: correct_endian_ret_submit(&pdu->u.ret_submit, send); break; case USBIP_CMD_UNLINK: correct_endian_cmd_unlink(&pdu->u.cmd_unlink, send); break; case USBIP_RET_UNLINK: correct_endian_ret_unlink(&pdu->u.ret_unlink, send); break; default: /* NOTREACHED */ err("unknown command in pdu header: %d", cmd); //BUG(); } } EXPORT_SYMBOL(usbip_header_correct_endian); //根据send判断方向,来调整iso字段的大小端 static void usbip_iso_pakcet_correct_endian(struct usbip_iso_packet_descriptor *iso, int send) { /* does not need all members. but copy all simply. */ if (send) { iso->offset = cpu_to_be32(iso->offset); iso->length = cpu_to_be32(iso->length); iso->status = cpu_to_be32(iso->status); iso->actual_length = cpu_to_be32(iso->actual_length); } else { iso->offset = be32_to_cpu(iso->offset); iso->length = be32_to_cpu(iso->length); iso->status = be32_to_cpu(iso->status); iso->actual_length = be32_to_cpu(iso->actual_length); } } //根据pack判断方向,将iso和uiso的属性字段进行相互赋值 static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso, struct usb_iso_packet_descriptor *uiso, int pack) { if (pack) { iso->offset = uiso->offset; iso->length = uiso->length; iso->status = uiso->status; iso->actual_length = uiso->actual_length; } else { uiso->offset = iso->offset; uiso->length = iso->length; uiso->status = iso->status; uiso->actual_length = iso->actual_length; } } //分配urb->number_of_packets个usbip_iso_packet_descriptor描述结构体 //并将urb->iso_frame_desc[0----np-1]个usb_iso_packet_descriptor写入到buff中 //将bufff返回 /* must free buffer */ void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen) { void *buff; struct usbip_iso_packet_descriptor *iso; int np = urb->number_of_packets; ssize_t size = np * sizeof(*iso); int i; buff = kzalloc(size, GFP_KERNEL); if (!buff) return NULL; for (i = 0; i < np; i++) { iso = buff + (i * sizeof(*iso)); //对每一个usbip_iso_packet_descriptor包进行处理,保存到iso中,并调整大小端 usbip_pack_iso(iso, &urb->iso_frame_desc[i], 1); usbip_iso_pakcet_correct_endian(iso, 1); } *bufflen = size; return buff; } EXPORT_SYMBOL(usbip_alloc_iso_desc_pdu); //接收urb->number_of_packets个包,并以此对这些包进行大小端转换 /* 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; if (!usb_pipeisoc(urb->pipe)) return 0; /* my Bluetooth dongle gets ISO URBs which are np = 0 */ if (np == 0) { //uinfo("iso np == 0\n"); //usbip_dump_urb(urb); return 0; } buff = kzalloc(size, GFP_KERNEL); if (!buff) return -ENOMEM; ret = usbip_xmit(0, ud->tcp_socket, buff, size, 0); if (ret != size) { uerr("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; } for (i = 0; i < np; i++) { iso = buff + (i * sizeof(*iso)); usbip_iso_pakcet_correct_endian(iso, 0); usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); } kfree(buff); return ret; } EXPORT_SYMBOL(usbip_recv_iso); //根据ud->side来判断urb->pipe的类型是否正确和获取接收大小,然后接收数据 //将接收的数据保存到urb->transfer_buffer /* 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) { /* stub_rx.c */ /* the direction of urb must be OUT. */ if (usb_pipein(urb->pipe)) return 0; size = urb->transfer_buffer_length; } else { /* vhci_rx.c */ /* 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; //从接收ud->tcp_socket接收size大小的字节,保存到urb->transfer_buffer ret = usbip_xmit(0, ud->tcp_socket, (char *) urb->transfer_buffer, size, 0); if (ret != size) { uerr("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; } EXPORT_SYMBOL(usbip_recv_xbuff); /*-------------------------------------------------------------------------*/ static int __init usbip_common_init(void) { info(DRIVER_DESC "" DRIVER_VERSION); return 0; } static void __exit usbip_common_exit(void) { return; } module_init(usbip_common_init); module_exit(usbip_common_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL");