博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 网卡驱动相关——03
阅读量:5130 次
发布时间:2019-06-13

本文共 6555 字,大约阅读时间需要 21 分钟。

  紧接上一篇,这里简要介绍net_device 结构和网卡驱动框架。  
  struct net_device  是一个比sk_buff 更复杂的结构,里面包含了与TCP/IP协议栈通信的接口函数,但是自从2.6.31 之后的内核中这些接口函数就被封装在了 stuct net_device_ops 结构中,在net_device 结构中以 netdev_ops 成员的形式出现。
我们就来看如何使用该结构:
1. 在初始化幻术中驱动需要分配一个net_device 结构,可以使用alloc_netdev()函数,也可以使用一个更常用的函数 alloc_etherdev() 函数来实现。这个函数在创建net_device 结构的同时也为驱动自定义的 私有数据结构分配了空间。
一般这样使用:
  struct net_device  *netdev;
  struct priv_struct *mycard_priv;
  netdev   = alloc_etherdev(sizeof(struct priv_struct));
  mycard_priv = netdev->priv; 
2. 使用register_netdev() 函数来注册net_device结构中的接口函数,并将其中的组成员进行赋值
3. 读取MAC地址,配置局域网唤醒机制。
 
现在我们来看看网卡驱动框架:(来源于Essential Linux Device Drivers,稍作改动)
#include 
#include
#include
#include
struct net_device_stats mycard_stats; /* Statistics *//* Fill ethtool_ops methods from a suitable place in the driver */struct ethtool_ops mycard_ethtool_ops = { /* ... */ .get_eeprom = mycard_get_eeprom, /* Dump EEPROM contents */ /* ... */};/* Initialize/probe the card. For PCI cards, this is invoked from (or is itself) the probe() method. In that case, the function is declared as: static struct net_device *init_mycard(struct pci_dev *pdev, const struct pci_device_id *id)*/static struct net_device *init_mycard(){ struct net_device *netdev; struct priv_struct mycard_priv; /* ... */ netdev = alloc_etherdev(sizeof(struct priv_struct)); /* Common methods */ netdev->netdev_ops = &my_netdev_ops; dev->ethtool_ops = &my_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; netif_napi_add(dev, &tp->napi, my_poll, 64); /* Register the interface */ register_netdev(netdev); /* ... */ /* Get MAC address from attached EEPROM */ /* ... */ /* Download microcode if needed */ /* ... */}/* The interrupt handler */static irqreturn_tmycard_interrupt(int irq, void *dev_id){ struct net_device *netdev = dev_id; struct sk_buff *skb; unsigned int length; /* ... */ if (receive_interrupt) { /* We were interrupted due to packet reception. At this point, the NIC has already DMA'ed received data to an sk_buff that was pre-allocated and mapped during device open. Obtain the address of the sk_buff depending on your data structure design and assign it to 'skb'. 'length' is similarly obtained from the NIC by reading the descriptor used to DMA data from the card. Now, skb->data contains the receive data. */ /* ... */ /* For PCI cards, perform a pci_unmap_single() on the received buffer in order to allow the CPU to access it */ /* ... */ /* Allow the data go to the tail of the packet by moving skb->tail down by length bytes and increasing skb->len correspondingly */ skb_put(skb, length) /* Pass the packet to the TCP/IP stack */#if !defined (USE_NAPI) /* Do it the old way */ netif_rx(skb);#else /* Do it the NAPI way */ if (napi_schedule_prep(&priv->napi))) { /* Disable NIC interrupt. Implementation not shown. */ disable_nic_interrupt(); /* Post the packet to the protocol layer and add the device to the poll list */ __napi_schedule(&priv->napi); }#endif } else if (tx_complete_interrupt) { /* Transmit Complete Interrupt */ /* ... */ /* Unmap and free transmit resources such as DMA descriptors and buffers. Free sk_buffs or reclaim them into a free pool */ /* ... */}}/* Driver open */static intmycard_open(struct net_device *netdev){ /* ... */ /* Request irq */ request_irq(irq, mycard_interrupt, IRQF_SHARED, netdev->name, dev); /* Fill transmit and receive rings */ /* See the section, "Buffer Management and Concurrency Control" */ /* ... */ /* Provide free descriptor addresses to the card */ /* ... */ /* Convey your readiness to accept data from the networking stack */ netif_start_queue(netdev); /* ... */}/* Driver close */static intmycard_close(struct net_device *netdev){ /* ... */ /* Ask the networking stack to stop sending down data */ netif_stop_queue(netdev); /* ... */}/* Called when the device is unplugged or when the module is released. For PCI cards, this is invoked from (or is itself) the remove() method. In that case, the function is declared as: static void __devexit mycard_remove(struct pci_dev *pdev)*/static void __devexitmycard_remove(){ struct net_device *netdev; /* ... */ /* For a PCI card, obtain the associated netdev as follows, assuming that the probe() method performed a corresponding pci_set_drvdata(pdev, netdev) after allocating the netdev */ netdev = pci_get_drvdata(pdev); /* unregister_netdev(netdev); /* Reverse of register_netdev() */ /* ... */ free_netdev(netdev); /* Reverse of alloc_netdev() */ /* ... */}/* Suspend method. For PCI devices, this is part of the pci_driver structure discussed in Chapter 10 */static intmycard_suspend(struct pci_dev *pdev, pm_message_t state){ /* ... */ netif_device_detach(netdev); /* ... */}/* Resume method. For PCI devices, this is part of the pci_driver structure discussed in Chapter 10 */static intmycard_resume(struct pci_dev *pdev){ /* ... */ netif_device_attach(netdev); /* ... */}/* Get statistics */static struct net_device_stats *mycard_get_stats(struct net_device *netdev){ /* House keeping */ /* ... */ return(&mycard_stats);}/* Dump EEPROM contents. This is an ethtool_ops operation */static intmycard_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, uint8_t *bytes){ /* Read data from the accompanying EEPROM */ /* ... */}/* Poll method */static intmycard_poll(struct net_device *netdev, int *budget){ /* Post packets to the protocol layer using netif_receive_skb() */ /* ... */ if (no_more_ingress_packets()){ /* Remove the device from the polled list */ __napi_complete(netdev); /* Fall back to interrupt mode. Implementation not shown */ enable_nic_interrupt(); return 0; }}/* Transmit method */static intmycard_xmit_frame(struct sk_buff *skb, struct net_device *netdev){ /* DMA the transmit packet from the associated sk_buff to card memory */ /* ... */ /* Manage buffers */ /* ... */}
   需要注意的是,网卡驱动使用了new api 机制,硬件对接收到的包是进行中断来通知驱动处理还是通过轮询的方式来处理,该机制进行了简单的判断。接收到的数据与协议栈进行通信才是核心部分,主要工作都在接收函数,需要将接收到的数据存放到sk_buff 结构中,然后对其进行调整填充等操作,然后直接将数据送往上一层。
注意:网卡是一个数据链路层设备 !网卡驱动需要将接收到的数据送往网络层,将要发送的数据送到物理层,当然这个动作都由硬件来完成。
 

转载于:https://www.cnblogs.com/zhuyp1015/archive/2012/08/04/2623385.html

你可能感兴趣的文章
企业级应用与互联网应用的区别
查看>>
steelray project viewer
查看>>
itext jsp页面打印
查看>>
HTTP之报文
查看>>
Perl正则表达式匹配
查看>>
Git
查看>>
DB Change
查看>>
nginx --rhel6.5
查看>>
Eclipse Python插件 PyDev
查看>>
selenium+python3模拟键盘实现粘贴、复制
查看>>
第一篇博客
查看>>
typeof与instanceof的区别
查看>>
网站搭建(一)
查看>>
SDWebImage源码解读之SDWebImageDownloaderOperation
查看>>
elastaticsearch
查看>>
postgreSQL 简单命令操作
查看>>
Spring JDBCTemplate
查看>>
Radon变换——MATLAB
查看>>
第五章笔记
查看>>
Iroha and a Grid AtCoder - 1974(思维水题)
查看>>