本文分析基于Linux Kernel 1.2.13

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870

更多请查看专栏,地址http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

注:标题中的”(上)“,”(下)“表示分析过程基于数据包的传递方向:”(上)“表示分析是从底层向上分析、”(下)“表示分析是从上向下分析。

在博文Linux内核--网络栈实现分析(三)--驱动程序层(链路层)(上)中对网络设备结构,网络设备初始化等函数有了初步认识,并列出了设备的发送和接收函数。

设备接口层会调用函数设备驱动层ei_start_xmit()函数发送数据,这里没有详细分析。

  1. static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
  2. {
  3. int e8390_base = dev->base_addr;
  4. struct ei_device *ei_local = (struct ei_device *) dev->priv;//取出网卡设备的私有数据,和具体的网卡型号有关,在ethdev_init()函数中已经分配空间
  5. int length, send_length;
  6. unsigned long flags;
  7. /*
  8. *  We normally shouldn't be called if dev->tbusy is set, but the
  9. *  existing code does anyway. If it has been too long since the
  10. *  last Tx, we assume the board has died and kick it.
  11. */
  12. if (dev->tbusy) {    /* Do timeouts, just like the 8003 driver. */
  13. ........................................
  14. ........................................
  15. }
  16. /* Sending a NULL skb means some higher layer thinks we've missed an
  17. tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
  18. itself. */
  19. if (skb == NULL) {//该条件似乎不会发生,这用于处理内核中的BUG
  20. dev_tint(dev);//发送设备中的所有缓存的数据包
  21. return 0;
  22. }
  23. length = skb->len;
  24. if (skb->len <= 0)
  25. return 0;
  26. save_flags(flags);
  27. cli();
  28. /* Block a timer-based transmit from overlapping. */
  29. if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {
  30. printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",
  31. dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,
  32. ei_local->tx2, ei_local->lasttx);
  33. restore_flags(flags);
  34. return 1;
  35. }
  36. /* Mask interrupts from the ethercard. */
  37. outb(0x00, e8390_base + EN0_IMR);
  38. ei_local->irqlock = 1;
  39. restore_flags(flags);
  40. send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
  41. if (ei_local->pingpong) {
  42. int output_page;
  43. if (ei_local->tx1 == 0) {
  44. output_page = ei_local->tx_start_page;
  45. ei_local->tx1 = send_length;
  46. if (ei_debug  &&  ei_local->tx2 > 0)
  47. printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
  48. dev->name, ei_local->tx2, ei_local->lasttx,
  49. ei_local->txing);
  50. } else if (ei_local->tx2 == 0) {
  51. output_page = ei_local->tx_start_page + 6;
  52. ei_local->tx2 = send_length;
  53. if (ei_debug  &&  ei_local->tx1 > 0)
  54. printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
  55. dev->name, ei_local->tx1, ei_local->lasttx,
  56. ei_local->txing);
  57. } else {    /* We should never get here. */
  58. if (ei_debug)
  59. printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",
  60. dev->name, dev->interrupt, ei_local->tx1,
  61. ei_local->tx2, ei_local->lasttx);
  62. ei_local->irqlock = 0;
  63. dev->tbusy = 1;
  64. outb_p(ENISR_ALL, e8390_base + EN0_IMR);
  65. return 1;
  66. }
  67. ei_block_output(dev, length, skb->data, output_page);
  68. if (! ei_local->txing) {
  69. ei_local->txing = 1;
  70. NS8390_trigger_send(dev, send_length, output_page);
  71. dev->trans_start = jiffies;
  72. if (output_page == ei_local->tx_start_page)
  73. ei_local->tx1 = -1, ei_local->lasttx = -1;
  74. else
  75. ei_local->tx2 = -1, ei_local->lasttx = -2;
  76. } else
  77. ei_local->txqueue++;
  78. dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);
  79. } else {  /* No pingpong, just a single Tx buffer. */
  80. ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
  81. ei_local->txing = 1;
  82. NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
  83. dev->trans_start = jiffies;
  84. dev->tbusy = 1;
  85. }
  86. /* Turn 8390 interrupts back on. */
  87. ei_local->irqlock = 0;
  88. outb_p(ENISR_ALL, e8390_base + EN0_IMR);
  89. dev_kfree_skb (skb, FREE_WRITE);
  90. return 0;

其中的dev_tint()函数是将设备的所有缓存队列中的数据全部调用dev_queue_xmit()发送全部数据包。

  1. /*
  2. *  This routine is called when an device driver (i.e. an
  3. *  interface) is ready to transmit a packet.
  4. */
  5. //该函数功能:遍历设备的缓冲队列,对所有的数据包调用dev_queue_xmit()函数发送数据
  6. void dev_tint(struct device *dev)
  7. {
  8. int i;
  9. struct sk_buff *skb;
  10. unsigned long flags;
  11. save_flags(flags);
  12. /*
  13. *  Work the queues in priority order
  14. */
  15. for(i = 0;i < DEV_NUMBUFFS; i++)
  16. {
  17. /*
  18. *  Pull packets from the queue
  19. */
  20. cli();
  21. while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
  22. {
  23. /*
  24. *  Stop anyone freeing the buffer while we retransmit it
  25. */
  26. skb_device_lock(skb);
  27. restore_flags(flags);
  28. /*
  29. *  Feed them to the output stage and if it fails
  30. *  indicate they re-queue at the front.
  31. */
  32. dev_queue_xmit(skb,dev,-i - 1);//注意优先级的计算方式,在函数dev_queue_xmit()中优先级若<0则计算pri=-pri-1=-(-i-1)-1=i,
  33. //这样做的目的就是为了得到正确的where值,函数(dev_queue_xmit())中
  34. /*
  35. *  If we can take no more then stop here.
  36. */
  37. if (dev->tbusy)
  38. return;
  39. cli();
  40. }
  41. }
  42. restore_flags(flags);
  43. }

驱动层严格的说不属于内核网络栈的内容,和硬件关系密切,何况这种网卡硬件设备可能已经不用了,这里就没有详细分析,如果对网卡驱动有兴趣可以看一下之前的分析的ARM-Linux下的DM9000网卡驱动的分析,链接如下:

    1. ARM-Linux驱动--DM9000网卡驱动分析(一)
    2. ARM-Linux驱动--DM9000网卡驱动分析(二)
    3. ARM-Linux驱动--DM9000网卡驱动分析(三)
    4. ARM-Linux驱动--DM9000网卡驱动分析(四)

Linux内核--网络栈实现分析(十一)--驱动程序层(下)的更多相关文章

  1. Linux内核--网络栈实现分析(七)--数据包的传递过程(下)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7545855 更多请查看专栏,地 ...

  2. Linux内核--网络栈实现分析(二)--数据包的传递过程--转

    转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的”(上 ...

  3. Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260 更多请看专栏,地址 ...

  4. Linux内核--网络栈实现分析(一)--网络栈初始化

    本文分析基于内核Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7488828 更多请看专栏, ...

  5. Linux内核--网络栈实现分析(一)--网络栈初始化--转

    转载地址 http://blog.csdn.net/yming0221/article/details/7488828 作者:闫明 本文分析基于内核Linux Kernel 1.2.13 以后的系列博 ...

  6. Linux内核--网络栈实现分析(六)--应用层获取数据包(上)

    本文分析基于内核Linux 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7541907 更多请看专栏,地址http: ...

  7. Linux内核--网络栈实现分析(四)--网络层之IP协议(上)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7514017 更多请看专栏,地址 ...

  8. Linux内核--网络栈实现分析(二)--数据包的传递过程(上)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7492423 更多请看专栏,地址 ...

  9. Linux内核--网络栈实现分析(十)--网络层之IP协议(下)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7552455 更多请查看专栏,地 ...

随机推荐

  1. FileReader对象

    在一些项目中,经常会遇到图片上传的情况,为了提高用户体验,一般会要求选择图片后 能预览一下图片. 以前的做法是 通过 ajax上传图片后,然后再显示出来,这样会产生大量的无用的图片文件,在HTML5的 ...

  2. 构造 & 析构 & 匿名对象‍

    ‍以前仅知道创建对象,但对匿名对象的了解基本为0. 通过阅读google chromium源代码 中关于 log 的使用,查阅相关资料,了解了一下匿名对象,予以记录. 什么是匿名对象‍ 匿名对象可以理 ...

  3. [转载]Docker的安装配置及使用详解

    简介    官网:http://www.docker.com/,点击get started进入下载,目前三个系统的docker容器都有,Windows版需要win10系统,我的是win7系统一开始用的 ...

  4. 【如何快速的开发一个完整的iOS直播app】(原理篇)

    原文转自:袁峥Seemygo    感谢分享.自我学习 目录 [如何快速的开发一个完整的iOS直播app](原理篇) [如何快速的开发一个完整的iOS直播app](播放篇) [如何快速的开发一个完整的 ...

  5. 使用 xsd.exe 命令工具将 xsd 架构生成 类(CS) 文件

    vs自带命令行工具 命令:xsd  xml文件路径 C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC>xsd d:Scheme.xml ...

  6. Linux内核完全注释阅读笔记1:O(1)时间复杂度查找timeout定时器

    前言 一直有Linux kernel情节,之前也一直在看Linux kernel相关的书和代码,但是每次到最后又由于兴趣转变而荒废了.这次终于静下心来想把Linux内核相关的代码好好看看,算是对自己的 ...

  7. MySQL 5.6 & 5.7最优配置模板

    摘自:http://mp.weixin.qq.com/s?__biz=MjM5MjIxNDA4NA==&mid=207854835&idx=1&sn=c998031ae6816 ...

  8. maven下读取资源文件的问题(转)

    原文链接:http://shenchao.me/2016/04/20/maven%E4%B8%8B%E8%AF%BB%E5%8F%96%E8%B5%84%E6%BA%90%E6%96%87%E4%BB ...

  9. Android安全之Https中间人攻击漏洞

    Android安全之Https中间人攻击漏洞 0X01 概述   HTTPS,是一种网络安全传输协议,利用SSL/TLS来对数据包进行加密,以提供对网络服务器的身份认证,保护交换数据的隐私与完整性. ...

  10. IIS 7 Web服务器上部署ASP.NET网站(转)

    IIS 7 Web服务器上部署ASP.NET网站小记 摘自:http://swanmsg.blog.sohu.com/162111073.html 网上查找了很久关于iis7配置asp.net配置问题 ...