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");