模块的用途
这个模块的作用是将网络层的数据转换成usb可用的样子发送出去。同时,将收到的外部网络数据接收并传递到设备内部的网络层。
抽象点: 中间人的角色,跟以太网卡功能类似,只不过这个人事多,要转换一轮。
区别与以太网
USB中没有专门的接收发送数据的软中断。以太网有。
USB转以太网主要是通过轮询的方式,来负责数据的传递。
工作流程
参考这个链接就好了,这里不再赘述了。
https://blog.csdn.net/zh98jm/article/details/6339320
主要讲讲这个usbnet_bh函数
// tasklet (work deferred from completions, in_irq) or timer
static void usbnet_bh (unsigned long param)
{
struct usbnet *dev = (struct usbnet *) param;
struct sk_buff *skb;
struct skb_data *entry;
// dev->done 这个需要了解usb core 去理解这个done队列事什么? usb接收完全的数据放入这个队列吗?
while ((skb = skb_dequeue (&dev->done))) {
entry = (struct skb_data *) skb->cb; //私人定制cb存放自己想要东的数据,和usb core有关
switch (entry->state) {
case rx_done:
entry->state = rx_cleanup;
//将usb驱动中的数据拷贝到dev->done队列尾部,或者交给上网络协议栈
rx_process (dev, skb);
continue;
case tx_done:
case rx_cleanup:
usb_free_urb (entry->urb);
dev_kfree_skb (skb);
continue;
default:
netdev_dbg(dev->net, "bogus skb state %d\n", entry->state);
}
}
/* restart RX again after disabling due to high error rate */
clear_bit(EVENT_RX_KILL, &dev->flags);
/* waiting for all pending urbs to complete?
* only then can we forgo submitting anew
*/
if (waitqueue_active(&dev->wait)) {
if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
wake_up_all(&dev->wait);
// or are we maybe short a few urbs?
} else if (netif_running (dev->net) &&
netif_device_present (dev->net) &&
netif_carrier_ok(dev->net) &&
!timer_pending (&dev->delay) &&
!test_bit (EVENT_RX_HALT, &dev->flags)) {
int temp = dev->rxq.qlen;
if (temp < RX_QLEN(dev)) {
if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK)
return;
if (temp != dev->rxq.qlen)
netif_dbg(dev, link, dev->net,
"rxqlen %d --> %d\n",
temp, dev->rxq.qlen);
if (dev->rxq.qlen < RX_QLEN(dev))
tasklet_schedule (&dev->bh);
}
if (dev->txq.qlen < TX_QLEN (dev))
{
#ifdef USBNET_PPA_DP
if(dev->usbnet_ppadp_on && dev->usbnet_ppadp_ifid>=0 && ppa_hook_directpath_rx_restart_fn)
ppa_hook_directpath_rx_restart_fn(dev->usbnet_ppadp_ifid,0);
#endif
netif_wake_queue (dev->net);
}
}
}
static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
{
if (dev->driver_info->rx_fixup &&
!dev->driver_info->rx_fixup (dev, skb)) {
/* With RX_ASSEMBLE, rx_fixup() must update counters */
if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE))
dev->net->stats.rx_errors++;
goto done;
}
// else network stack removes extra byte if we forced a short packet
/* all data was already cloned from skb inside the driver */
if (dev->driver_info->flags & FLAG_MULTI_PACKET)
goto done;
if (skb->len < ETH_HLEN) {
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
} else {
//将数据报文交给网络层协议栈,数据报文处理结束
usbnet_skb_return(dev, skb);
return;
}
//将skb数据加入到done队列
done:
skb_queue_tail(&dev->done, skb);
}
//数据接收完的回调函数
static void rx_complete (struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
struct skb_data *entry = (struct skb_data *) skb->cb;
struct usbnet *dev = entry->dev;
int urb_status = urb->status;
enum skb_state state;
#if 1
if(urb->actual_length > dev->rx_urb_size)
{
// devdbg (dev, "found larger packet size (%d) more than %d",urb->actual_length, (int)(dev->rx_urb_size));
dev->net->stats.rx_errors++;
skb_put (skb, dev->rx_urb_size);
goto block;
}
#endif
skb_put (skb, urb->actual_length);
state = rx_done;
entry->urb = NULL;
#ifdef USBNET_PPA_DP
register_ppadp(dev->net);
#endif
switch (urb_status) {
/* success */
case 0:
break;
/* stalls need manual reset. this is rare ... except that
* when going through USB 2.0 TTs, unplug appears this way.
* we avoid the highspeed version of the ETIMEDOUT/EILSEQ
* storm, recovering as needed.
*/
case -EPIPE:
dev->net->stats.rx_errors++;
usbnet_defer_kevent (dev, EVENT_RX_HALT);
// FALLTHROUGH
/* software-driven interface shutdown */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware gone */
netif_dbg(dev, ifdown, dev->net,
"rx shutdown, code %d\n", urb_status);
goto block;
/* we get controller i/o faults during khubd disconnect() delays.
* throttle down resubmits, to avoid log floods; just temporarily,
* so we still recover when the fault isn't a khubd delay.
*/
case -EPROTO:
case -ETIME:
case -EILSEQ:
dev->net->stats.rx_errors++;
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
netif_dbg(dev, link, dev->net,
"rx throttle %d\n", urb_status);
}
block:
state = rx_cleanup;
entry->urb = urb;
urb = NULL;
break;
/* data overrun ... flush fifo? */
case -EOVERFLOW:
dev->net->stats.rx_over_errors++;
// FALLTHROUGH
default:
state = rx_cleanup;
dev->net->stats.rx_errors++;
netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status);
break;
}
//数据报文错误过多的花就进行重启? EVENT_RX_KILL
/* stop rx if packet error rate is high */
if (++dev->pkt_cnt > 30) {
dev->pkt_cnt = 0;
dev->pkt_err = 0;
} else {
if (state == rx_cleanup)
dev->pkt_err++;
if (dev->pkt_err > 20)
set_bit(EVENT_RX_KILL, &dev->flags);
}
继续执行将数据从rxq队列取出,放到done队列,调用tasklet_schedule出发usbnet_bh
state = defer_bh(dev, skb, &dev->rxq, state);
if (urb) {
if (netif_running (dev->net) &&
!test_bit (EVENT_RX_HALT, &dev->flags) &&
state != unlink_start) {
rx_submit (dev, urb, GFP_ATOMIC);
usb_mark_last_busy(dev->udev);
return;
}
usb_free_urb (urb);
}
netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n");
}
urb received callback function rx_complete
rx_complete -> defer_bh ( move skb from rxq to done queue list) -> usbnet_bh -> rx_process --> netif_rx() / reappend to done queue