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 = &eth_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 }

   接收的过程为此的逆过程,大家可以自行分析。