Linux下的网络设备驱动(二)

发表于:2013-2-20 10:08

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:weiqing1981127    来源:51Testing软件测试网采编

  我们知道数据包的接收是通过中断来实现的,下面再分析一下数据的发送,当协议层已经封装好上层协议数据的skb_buffer后,将调用前面提到的dm9000_start_xmit函数把数据发送出去,下面我们看看这个dm9000_start_xmit函数的实现

static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
       unsigned long flags;
       board_info_t *db = netdev_priv(dev); //获取私有数据
       dm9000_dbg(db, 3, "%s:\n", __func__);
       if (db->tx_pkt_cnt > 1)     //网卡忙
              return NETDEV_TX_BUSY;
       spin_lock_irqsave(&db->lock, flags);   //关闭中断,获取锁
       writeb(DM9000_MWCMD, db->io_addr); //读数据命令
       (db->outblk)(db->io_data, skb->data, skb->len);  //把数据发送出去
       dev->stats.tx_bytes += skb->len;   //统计发送字节数
       db->tx_pkt_cnt++; //正在发送中的数据计数加1
       if (db->tx_pkt_cnt == 1) {
              dm9000_send_packet(dev, skb->ip_summed, skb->len);
       } else {
              db->queue_pkt_len = skb->len;
              db->queue_ip_summed = skb->ip_summed;
              netif_stop_queue(dev);  //网卡停止接收数据
       }
       spin_unlock_irqrestore(&db->lock, flags); //释放锁
       dev_kfree_skb(skb);   //释放内存空间
       return NETDEV_TX_OK;
}

  首先需要说明的是上述函数实现中调用spin_lock_irqsave(&db->lock, flags)来获取一个自旋锁,当重发后释放该自旋锁,以避免与协议栈调用发送函数产生竞态。

  另外,当软件完成指示硬件发送数据包后该函数返回,但此时硬件传送可能还没完成,因此驱动需要告知协议栈不要再起的发送,即调用netif_stop_queue函数,直至硬件准备好接收新的数据。当数据发送完,会触发中断,仍然调用前面的中断处理函数,然后执行dm9000_tx_done(dev, db),跟踪下dm9000_tx_done的实现吧

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
       int tx_status = ior(db, DM9000_NSR);
       if (tx_status & (NSR_TX2END | NSR_TX1END)) {
              db->tx_pkt_cnt--;
              dev->stats.tx_packets++;
              if (netif_msg_tx_done(db))
                     dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
              if (db->tx_pkt_cnt > 0)
                     dm9000_send_packet(dev, db->queue_ip_summed,
                                      db->queue_pkt_len);
              netif_wake_queue(dev); //告知协议栈可以再次发送数据
       }
}

  需要补充的是如果在其他地方需要停止数据包的传送,可以使用netif_tx_disable函数。

  四、网络设备驱动测试

  网络设备没有字符设备里的open、close等函数,而是靠IP地址选择路由,Linux网络系统的路由选择会自动查找匹配合适的驱动,这是网络驱动和其他两种驱动的主要区别。

  下面给出三种测试网络驱动是否正常的方法

  其一,使用ifconfig进行IP地址的设置。

  其二,为了让用户获取网络统计的数据,驱动一般有一个net_device_stats结构体,并提供get_stats函数接收它,比如要从eth0接口得到接收的数据包数,可以查看/sys/class/net/eth0/statistics,其中rx_packet表示受到的报文数目,rx_byte表示收到的字节总数。

  其三,应用程序使用标准的socket、bind、send等操作。

相关链接:

Linux下的网络设备驱动(一)
44/4<1234
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号