linux kernel X-tranx-Y : Ethernet-to-Gadget
来源:互联网 发布:网络切换器设置 编辑:程序博客网 时间:2024/04/27 16:42
今天我们来看看linux kernel driver中的glue:u_ether.c这个文件把以太网卡设备转换成了USB gadget设备,目的是实现TCP/IP Over USB。该文件实现的功能框图如下:
+-------------+--------------------------+
| | |
| | ethernet device |
| | |
| u_ether.c+---------------------------+
| | |
| | gadget device |
| | |
+-------------+--------------------------+
我们先来看一下struct eth_dev这个结构:
struct eth_dev {
52 /* lock is held while accessing port_usb
53 * or updating its backlink port_usb->ioport
54 */
55 spinlock_t lock;
56 struct gether *port_usb;
57
58 struct net_device *net;
59 struct usb_gadget *gadget;
60
61 spinlock_t req_lock; /* guard {rx,tx}_reqs */
62 struct list_head tx_reqs, rx_reqs;
63 atomic_t tx_qlen;
64
65 struct sk_buff_head rx_frames;
66
67 unsigned header_len;
//以下两个成员相当重要,调了gadget层的收发,主要是添加或删除包头。
68 struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
69 int (*unwrap)(struct gether *,
70 struct sk_buff *skb,
71 struct sk_buff_head *list);
72
73 struct work_struct work;
74
75 unsigned long todo;
76 #define WORK_RX_MEMORY 0
77
78 bool zlp;
79 u8 host_mac[ETH_ALEN];
80 };
在这个结构中,我们可以看到两个很重要的成员:struct net_device *net;和 struct usb_gadget *gadget;由此可知,这个结构是两个设备的枢纽,它是胶水层的主要结构。
这个结构何时被创建呢? 以下成员函数实现创建和初始化任务:
747 /**
748 * gether_setup_name - initialize one ethernet-over-usb link
749 * @g: gadget to associated with these links
750 * @ethaddr: NULL, or a buffer in which the ethernet address of the
751 * host side of the link is recorded
752 * @netname: name for network device (for example, "usb")
753 * Context: may sleep
754 *
755 * This sets up the single network link that may be exported by a
756 * gadget driver using this framework. The link layer addresses are
757 * set up using module parameters.
758 *
759 * Returns negative errno, or zero on success
760 */
//这个成员往往由gadget来调用,创建一个网络设备(以太网卡)
761 int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
762 const char *netname)
763 {
764 struct eth_dev *dev;
765 struct net_device *net;
766 int status;
767
768 if (the_dev)
769 return -EBUSY;
770
771 net = alloc_etherdev(sizeof *dev); //为胶水结构开辟内存
772 if (!net)
773 return -ENOMEM;
774
775 dev = netdev_priv(net);
776 spin_lock_init(&dev->lock);
777 spin_lock_init(&dev->req_lock);
778 INIT_WORK(&dev->work, eth_work);
779 INIT_LIST_HEAD(&dev->tx_reqs);
780 INIT_LIST_HEAD(&dev->rx_reqs);
781
782 skb_queue_head_init(&dev->rx_frames);
783
784 /* network device setup */
785 dev->net = net; //拉红线:net device
786 snprintf(net->name, sizeof(net->name), "%s%%d", netname);
787
788 if (get_ether_addr(dev_addr, net->dev_addr))
789 dev_warn(&g->dev,
790 "using random %s ethernet address\n", "self");
791 if (get_ether_addr(host_addr, dev->host_mac))
792 dev_warn(&g->dev,
793 "using random %s ethernet address\n", "host");
794
795 if (ethaddr)
796 memcpy(ethaddr, dev->host_mac, ETH_ALEN);
797
798 net->netdev_ops = ð_netdev_ops;
799
800 SET_ETHTOOL_OPS(net, &ops);
801
802 dev->gadget = g; //拉红线:gadget device
803 SET_NETDEV_DEV(net, &g->dev);
804 SET_NETDEV_DEVTYPE(net, &gadget_type);
805
806 status = register_netdev(net); //注册网络设备,为IP over USB搭桥
807 if (status < 0) {
808 dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
809 free_netdev(net);
810 } else {
811 INFO(dev, "MAC %pM\n", net->dev_addr);
812 INFO(dev, "HOST MAC %pM\n", dev->host_mac);
813
814 the_dev = dev;
815
816 /* two kinds of host-initiated state changes:
817 * - iff DATA transfer is active, carrier is "on"
818 * - tx queueing enabled if open *and* carrier is "on"
819 */
820 netif_carrier_off(net);
821 }
822
823 return status;
824 }
接下来,我们一起来看看IP层到网络设备层的写流程,忽略了协议接口层、网络设备抽象层、直接跳到网络设备实例层:
734 static const struct net_device_ops eth_netdev_ops = {
735 .ndo_open = eth_open,
736 .ndo_stop = eth_stop,
737 .ndo_start_xmit = eth_start_xmit,
738 .ndo_change_mtu = ueth_change_mtu,
739 .ndo_set_mac_address = eth_mac_addr,
740 .ndo_validate_addr = eth_validate_addr,
741 };
484 static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
485 struct net_device *net)
486 {
487 struct eth_dev *dev = netdev_priv(net);
488 int length = skb->len;
489 int retval;
490 struct usb_request *req = NULL;
491 unsigned long flags;
492 struct usb_ep *in;
493 u16 cdc_filter;
494
495 spin_lock_irqsave(&dev->lock, flags);
496 if (dev->port_usb) {
497 in = dev->port_usb->in_ep;
498 cdc_filter = dev->port_usb->cdc_filter;
499 } else {
500 in = NULL;
501 cdc_filter = 0;
502 }
503 spin_unlock_irqrestore(&dev->lock, flags);
504
505 if (!in) {
506 dev_kfree_skb_any(skb);
507 return NETDEV_TX_OK;
508 }
509
510 /* apply outgoing CDC or RNDIS filters */
511 if (!is_promisc(cdc_filter)) {
512 u8 *dest = skb->data;
513
514 if (is_multicast_ether_addr(dest)) {
515 u16 type;
516
517 /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
518 * SET_ETHERNET_MULTICAST_FILTERS requests
519 */
520 if (is_broadcast_ether_addr(dest))
521 type = USB_CDC_PACKET_TYPE_BROADCAST;
522 else
523 type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
524 if (!(cdc_filter & type)) {
525 dev_kfree_skb_any(skb);
526 return NETDEV_TX_OK;
527 }
528 }
529 /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
530 }
531
532 spin_lock_irqsave(&dev->req_lock, flags);
533 /*
534 * this freelist can be empty if an interrupt triggered disconnect()
535 * and reconfigured the gadget (shutting down this queue) after the
536 * network stack decided to xmit but before we got the spinlock.
537 */
538 if (list_empty(&dev->tx_reqs)) {
539 spin_unlock_irqrestore(&dev->req_lock, flags);
540 return NETDEV_TX_BUSY;
541 }
542
543 req = container_of(dev->tx_reqs.next, struct usb_request, list);
544 list_del(&req->list);
545
546 /* temporarily stop TX queue when the freelist empties */
547 if (list_empty(&dev->tx_reqs))
548 netif_stop_queue(net);
549 spin_unlock_irqrestore(&dev->req_lock, flags);
550
551 /* no buffer copies needed, unless the network stack did it
552 * or the hardware can't use skb buffers.
553 * or there's not enough space for extra headers we need
554 */
//若gadget功能层需要,则添加包头
555 if (dev->wrap) {
556 unsigned long flags;
557
558 spin_lock_irqsave(&dev->lock, flags);
559 if (dev->port_usb)
560 skb = dev->wrap(dev->port_usb, skb); //
561 spin_unlock_irqrestore(&dev->lock, flags);
562 if (!skb)
563 goto drop;
564
565 length = skb->len;
566 }
//没有gadget功能层包头的需要就直接发生skb,有需求的话已经在上面的if中添加
567 req->buf = skb->data;
568 req->context = skb;
569 req->complete = tx_complete;
570
571 /* NCM requires no zlp if transfer is dwNtbInMaxSize */
572 if (dev->port_usb->is_fixed &&
573 length == dev->port_usb->fixed_in_len &&
574 (length % in->maxpacket) == 0)
575 req->zero = 0;
576 else
577 req->zero = 1;
578
579 /* use zlp framing on tx for strict CDC-Ether conformance,
580 * though any robust network rx path ignores extra padding.
581 * and some hardware doesn't like to write zlps.
582 */
583 if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
584 length++;
585
586 req->length = length;
587
588 /* throttle high/super speed IRQ rate back slightly */
589 if (gadget_is_dualspeed(dev->gadget))
590 req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
591 dev->gadget->speed == USB_SPEED_SUPER)
592 ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
593 : 0;
594
//最终在usb 端点发送,完成实际的发送任务的承担。也体现了ether over usb。
595 retval = usb_ep_queue(in, req, GFP_ATOMIC);
596 switch (retval) {
597 default:
598 DBG(dev, "tx queue err %d\n", retval);
599 break;
600 case 0:
601 net->trans_start = jiffies;
602 atomic_inc(&dev->tx_qlen);
603 }
604
605 if (retval) {
606 dev_kfree_skb_any(skb);
607 drop:
608 dev->net->stats.tx_dropped++;
609 spin_lock_irqsave(&dev->req_lock, flags);
610 if (list_empty(&dev->tx_reqs))
611 netif_start_queue(net);
612 list_add(&req->list, &dev->tx_reqs);
613 spin_unlock_irqrestore(&dev->req_lock, flags);
614 }
615 return NETDEV_TX_OK;
616 }
接收的过程为此的逆过程,大家可以自行分析。
- linux kernel X-tranx-Y : Ethernet-to-Gadget
- linux kernel X-tranx-Y : TTY to gadget
- linux kernel X-tranx-Y : TTY to sdio
- usb to ethernet adapter (moshi) work in linux kernel
- Kernel Panic on VFS: Unable to mount root fs on unknown-block(x,y) (转)
- Linux-USB Gadget : Part 2: USB Gadget API for Linux (From Linux kernel 2.6.25.10)
- Linux gadget USB设备端驱动程序(kernel 2.6.28)
- marvell pxa2128 uboot/linux kernel fast ethernet development documentary
- Linux内核升级 (2.4 to 2.6 OR 2.6.x to 2.6.y)
- rndis ethernet gadget 驱动 安装方法
- rndis ethernet gadget 驱动 安装方法
- Use Y method to solve Problem X
- Convert from type X to type Y
- How to Upgrade Linux Kernel to Stable 3.18.4 on CentOS 7.x
- 七、android-kernel gadget框架
- android-kernel usb gadget框架
- My contribution to linux kernel
- (x&y)+((x^y)>>1)
- Mac如何通过Xcode安装GCC编译器 How to install gcc on mac with xcode
- 我的Android进阶之旅------>Android DatePicker和TimePicker案例
- 人生的五件大事
- 思想道德与法律基础
- 谈组件化、平台化、自动化
- linux kernel X-tranx-Y : Ethernet-to-Gadget
- 解决PowerDesigner里允许字段重名约束的设置问题-爽!
- 程序人生--2008年(48)
- java 十进制 二进制 十六进制 转换
- udig工具的升级,地图配置保存
- 关于android 如何安装 assets文件下的apk
- 云计算网络技术
- 黑马程序员——方法重载、ref和out修饰的参数
- 2013 CSDN & 西南大学 高校俱乐部 春季巡讲