嵌入式Linux驅動學習之路(二十五)虛擬網卡驅動程序


一、協議棧層次對比

設備無關層到驅動層的體系結構

 

1)、網絡協議接口層向網絡層協議提供提供統一的數據包收發接口,不論上層協議為ARP還是IP,都通過dev_queue_xmit()函數發送數據,並通過netif_rx()函數接受數據。這一層的存在使得上層協議獨立於具體的設備。
2)、網絡設備接口層向協議接口層提供統一的用於描述具體網絡設備屬性和操作的結構體net_device,該結構體是設備驅動功能層中各函數的容器。實際上,網絡設備接口層從宏觀上規划了具體操作硬件的設備驅動功能層的結構。
3)、設備驅動功能層各函數是網絡設備接口層net_device數據結構的具體成員,是驅使網絡設備硬件完成相應動作的程序,他通過hard_start_xmit()函數啟動發送操作,並通過網絡設備上的中斷觸發接受操作。
4)、網絡設備與媒介層是完成數據包發送和接受的物理實體,包括網絡適配器和具體的傳輸媒介,網絡適配器被驅動功能層中的函數物理上驅動。對於Linux系統而言,網絡設備和媒介都可以是虛擬的。

網絡協議接口層:主要進行數據包的收發。

 驅動程序代碼:

/*************************************************************************
    > File Name: s3c_virnet.c
    > Author: 
    > Mail: 
    > Created Time: 2016年11月09日 星期三 13時27分51秒
 ************************************************************************/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/ip.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>

static struct net_device *vnet_dev;


static void virnet_tx_packet(struct sk_buff *skb, struct net_device *dev)
{
    unsigned char *type;
    struct iphdr *ih;
    __be32 *saddr, *daddr, tmp;
    unsigned char tmp_dev_addr[ETH_ALEN];
    struct ethhdr *ethhdr;

    struct sk_buff *rx_skb;

    /* 對調MAC地址 */
    ethhdr = (struct ethhdr *)skb->data;
    memcpy(tmp_dev_addr,ethhdr->h_dest,ETH_ALEN);
    memcpy(ethhdr->h_dest,ethhdr->h_source,ETH_ALEN);
    memcpy(ethhdr->h_source,tmp_dev_addr,ETH_ALEN);

    /*  */
    ih = (struct iphdr *)(skb->data+sizeof(struct ethhdr));
    saddr = &ih->saddr;
    daddr = &ih->daddr;

    tmp = *saddr;
    *saddr = *daddr;
    *daddr = tmp;

    type = skb->data + sizeof(struct ethhdr)+sizeof(struct iphdr);

    *type = 0;

    ih->check = 0;
    ih->check = ip_fast_csum((unsigned char*)ih,ih->ihl);

    rx_skb = dev_alloc_skb(skb->len + 2);
    skb_reserve(rx_skb,2);
    memcpy(skb_put(rx_skb,skb->len),skb->data,skb->len);

    rx_skb->dev = dev;
    rx_skb->protocol = eth_type_trans(rx_skb,dev);
    rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
    dev->stats.rx_bytes += skb->len;
    dev->stats.rx_packets++;
    netif_rx(rx_skb);

}
static int virnet_send_packet(struct sk_buff *skb, struct net_device *dev)
{
    dev->stats.tx_packets++;
    dev->stats.tx_bytes += skb->len;
    
    netif_stop_queue(dev);  //停止該網卡的隊列
                             /*把skb的數據寫入網卡*/
    //dev_kfree_skb(skb);     //釋放skb
    netif_wake_queue(dev);   //數據發送成功后喚醒隊列
    /* 構造出一個假的sk_buff */
    
    virnet_tx_packet(skb,dev);
    

    return 0;
}


static int s3c_virnet_init(void)
{
    
    /* 分配一個net_device結構體 */
    vnet_dev = alloc_netdev(0, "vnet%d", ether_setup);
    
    /* 設置 */
    vnet_dev->hard_start_xmit = virnet_send_packet;
    
    /* MAC地址設置 */
    vnet_dev->dev_addr[0] = 0x07;
    vnet_dev->dev_addr[1] = 0x05;
    vnet_dev->dev_addr[2] = 0x06;
    vnet_dev->dev_addr[3] = 0x07;
    vnet_dev->dev_addr[4] = 0x08;
    vnet_dev->dev_addr[5] = 0x09;

    /* 添加下面的配置后才能ping通 */ 
    vnet_dev->flags |= IFF_NOARP;
    vnet_dev->features |= NETIF_F_NO_CSUM;
    
    /* 注冊 */
    register_netdev(vnet_dev); 
    
    return 0;
}

static void s3c_virnet_exit(void)
{
    unregister_netdev(vnet_dev);

    free_netdev(vnet_dev);
}

module_init(s3c_virnet_init);
module_exit(s3c_virnet_exit);
MODULE_LICENSE("GPL");

 

 

sd


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM