Understanding Linux Network Driver Devices (Part 8)

2.5 Virtual Network Card Driver

#include <linux/init.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/ip.h>#include <linux/in.h>#include <linux/etherdevice.h>#include <linux/types.h>/*Experiment Description: * The reception and transmission of its data are aimed at user space. * This experiment adds the setting of the MAC address and the counting of sent packets compared to the program in the net2 folder; * Experiment Steps: *(1) ifconfig, check the current network card information; *(2) sudo ifconfig vent0 3.3.3.3 set the IP of the virtual network card; *(3) ifconfig check the current MAC address of the virtual network card and the number and length of sent and received packets; *(4) PING 3.3.3.5 data transmission; *(5) ctrl + c to stop sending; ifconfig check the current data transmission and reception status of the virtual network card; *(6) sudo rmmod mynet, unload the module; at this time, check the kernel print information, call stop; */#define ETH_ADDR_LEN 6#define NAME "vnet0"struct net_device *mynet;int count = 0;int mynet_open(struct net_device *dev){    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);    return 0;}int mynet_stop(struct net_device *dev){    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);    return 0;}int rx_packet(struct sk_buff*skb,struct net_device *dev){    struct ethhdr *ethhdr;    struct iphdr *iphdr;    __be32 temp_ip;    unsigned char temp_mac[ETH_ADDR_LEN];    unsigned char *type;    struct sk_buff *rx_skb;    ethhdr = (struct ethhdr *)skb->data;    memcpy(temp_mac,ethhdr->h_dest,ETH_ADDR_LEN);    memcpy(ethhdr->h_dest,ethhdr->h_source,ETH_ADDR_LEN);    memcpy(ethhdr->h_source,temp_mac,ETH_ADDR_LEN);    iphdr = (struct iphdr *)(skb->data + sizeof(struct ethhdr));    temp_ip = iphdr->daddr;    iphdr->daddr = iphdr->saddr;    iphdr->saddr = temp_ip;    iphdr->check = 0;    iphdr->check = ip_fast_csum(iphdr,iphdr->ihl);    type = skb->data +sizeof(*ethhdr)+sizeof(*iphdr);    *type = 0;  // 0x80 ping 0x00 reply    rx_skb  = dev_alloc_skb(skb->len + 2);    skb_reserve(rx_skb,2);//align to 16B boundary of ip    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;    //update statistics    dev->stats.rx_packets++;    dev->stats.rx_bytes += skb->len;    //submit sk_buff    netif_rx(rx_skb);    return 0;}netdev_tx_t mynet_start_xmint(struct sk_buff *skb,                       struct net_device *dev){    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);    netif_stop_queue(dev);    rx_packet(skb,dev);    dev_kfree_skb(skb);    netif_wake_queue(dev);    //struct net_device_stats stats;    count++;    dev->stats.tx_packets ++;    dev->stats.tx_bytes = skb->len;    return NETDEV_TX_OK;}struct net_device_ops nfops = {    .ndo_open = mynet_open,    .ndo_stop = mynet_stop,    .ndo_start_xmit = mynet_start_xmint,};static int __init mynet_init(void){    mynet = alloc_netdev_mqs(0, NAME, NET_NAME_UNKNOWN,                ether_setup, 1, 1);    //mynet = alloc_netdev(0,NAME,ether_setup);    if(mynet == NULL){        printk("alloc net error\n");        return -ENOMEM;    }    mynet->netdev_ops = &nfops;    mynet->dev_addr[0] = 00;    mynet->dev_addr[1] = 01;    mynet->dev_addr[2] = 02;    mynet->dev_addr[3] = 03;    mynet->dev_addr[4] = 04;    mynet->dev_addr[5] = 05;    mynet->flags |= IFF_NOARP;    //mynet->features |= NETIF_F_V6_CSUM;    mynet->features |= NETIF_F_IP_CSUM;    register_netdev(mynet);    return 0;}static void __exit mynet_exit(void){    unregister_netdev(mynet);    free_netdev(mynet);}module_init(mynet_init);module_exit(mynet_exit);MODULE_LICENSE("GPL");

Leave a Comment