⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmeth.c

📁 LINUX网络代码详解,好东西!不能错过哟!
💻 C
字号:
/************************************************************************
	虚拟多网卡驱动程序.原理:
	接收的原理:
	1.通过dev_add_pack注册一个原始以太网接收接口模拟接收报文,所以被绑定的网卡要打开侦听模式;
	2.在本程序里面使用一个模拟网卡的数组,最多可以模拟1024个网卡;
	3.根据报文的目的MAC地址,使用HASH算法计算该报文是所模拟的哪个网卡的报文;
	4.通过netif_rx()函数将报文加入到接受队列中.
	发送的原理:
	1.在实现hard_start_xmit函数时,将保文直接通过被绑定的网卡的hard_start_xmit函数发送出去.

	HASH算法的原理:
	HASH = 将报文目的MAC的低10位.HASH值相同的网卡链成单向链表.
	
    This program is free software; you can redistribute it and/or
 	modify it under the terms of the GNU General Public License
 	as published by the Free Software Foundation; either version
 	2 of the License, or (at your option) any later version.
	
	作者:陈国强, douspring@263.net 
**************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "vmeth.h"

struct net_local{
	struct net_device_stats stats;
	unsigned short usIndex;
};

VMETH_HASH_ITEM_S *gstHashTable[VMETH_HASHTABLE_LEN];
struct net_device gstDevTable[VMETH_HASHTABLE_LEN];
struct net_device *gpstHostDev = NULL;
static int card_num = 1;
static char *host_dev = VMETH_DEF_BOUND_ETH;
static int base_mac[6]= DEF_BASEMAC;
/*static char base_mac[32]= DEF_BASEMAC_STR;*/
static MAC_S stDefBaseMac = DEF_BASEMAC;
static char gszStrMac[64];

rwlock_t HashLock = RW_LOCK_UNLOCKED;

int debug = 0;

/*functions defined in this file*/
static int __init VMETH_Probe(struct net_device *dev);
static int VMETH_Open	(struct net_device *dev);
static int VMETH_StartXmit(struct sk_buff *skb, struct net_device *dev);
static void VMETH_Timeout	(struct net_device *dev);
static int VMETH_Close	(struct net_device *dev);
static struct net_device_stats *VMETH_GetStats(struct net_device *dev);
int	 VMETH_SetMacAddress(struct net_device *dev,void *addr);
char *MacToStr(const unsigned char *mac,	char *szStr);


/*
	get mac address from a integer array;
	return -1, if failed;
	return 0 if success, and put mac to output parameter 'szMac'
*/
int VMETH_GetMacFromIntArray(const int *pArr, char *pstMac)
{
	int i;

	for(i=0; i<6; i++)
	{
		if(pArr[i] > 0xFF || pArr[i] < 0){
			return -1;
		}
		pstMac[i] = (unsigned char)pArr[i];
	}
	return 0;
}

char *MacToStr(const unsigned char *mac,	char *szStr)
{
	if(mac){
		sprintf(szStr,"%02x:%02x:%02x:%02x:%02x:%02x",
				(unsigned char)mac[0],
				(unsigned char)mac[1],
				(unsigned char)mac[2],
				(unsigned char)mac[3],
				(unsigned char)mac[4],
				(unsigned char)mac[5]);
	}else{
		strcpy(szStr,"00:00:00:00:00:00");
	}
	return szStr;		
}

static int __init VMETH_Probe(struct net_device *dev)
{
	SET_MODULE_OWNER(dev);
	/*setup phy parameter*/
	dev->base_addr = VMETH_IO;
	dev->irq = VMETH_IRQ;

	dev->open = &VMETH_Open;
	dev->hard_start_xmit = &VMETH_StartXmit;
	dev->tx_timeout = &VMETH_Timeout;
	dev->watchdog_timeo = HZ;
	dev->stop = &VMETH_Close;
	dev->get_stats = &VMETH_GetStats;
	dev->do_ioctl = NULL;

	/*
	 *	Setup the generic properties
	 */
	ether_setup(dev);
	/*replace ether_setup's setting*/
	dev->set_mac_address = &VMETH_SetMacAddress;
	
	printk("The %d vmeth is setup success, name=%s\n",((struct net_local *)dev->priv)->usIndex,dev->name);
	return 0;
}
static int VMETH_Open	(struct net_device *dev)
{
	netif_start_queue(dev);
	printk("The %s vmeth is open success\n",dev->name);
	return 0;
}
static int VMETH_StartXmit(struct sk_buff *skb, struct net_device *dev)
{
	struct net_local *pstNetLocal = (struct net_local *)dev->priv;

	skb->dev = gpstHostDev;
	netif_stop_queue(dev);
	if(dev_queue_xmit(skb)){
		pstNetLocal->stats.tx_errors++;
	}else{
		pstNetLocal->stats.tx_packets++;
		pstNetLocal->stats.tx_bytes += skb->len;
	}
	netif_start_queue(dev);
	return 0;
}

static void VMETH_Timeout	(struct net_device *dev)
{
	return ;
}

static int VMETH_Close	(struct net_device *dev)
{
	netif_stop_queue(dev);
	printk("The %s vmeth is close success\n",dev->name);
	return 0;
}
static struct net_device_stats *VMETH_GetStats(struct net_device *dev)
{
	struct net_local *pstNetLocal  = (struct net_local *)dev->priv;
	return &(pstNetLocal->stats);
}
int	 VMETH_SetMacAddress(struct net_device *dev,void *p)
{
	struct sockaddr *addr=p;
	struct net_local *pstNetLocal  = (struct net_local *)dev->priv;
	
	if (netif_running(dev)){
		return -EBUSY;
	}	
	if(VMETH_DelItemFromHashTable(dev->dev_addr) != 0){
		return -1;
	}
	if(VMETH_InsertItemToHashTable(pstNetLocal->usIndex, addr->sa_data) != 0){
		return -1;
	}
	/*
	if(VMETH_HashTableReplaceItem(dev->dev_addr,addr->sa_data,pstNetLocal->usIndex) ){
		printk("Hash Table error,not found old mac index\n");
		return -1;
	}*/
	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
	return 0;
}

int VMETH_Rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
	struct net_device *pstMyDev = NULL;
	struct ethhdr  *pstEthHeader = NULL;
	struct net_local *pstNetLocal = NULL;
	unsigned short usIndex = VMETH_INVALID_INDEX;

	/*is our sended packet, or not from bound device*/
	if((dev >= &gstDevTable[0] && dev <= &gstDevTable[VMETH_MAX_VM-1]) || (dev != gpstHostDev)){
#ifdef VMETH_DEBUG
		if(debug > 0){
			printk("vmeth droped a packet because it is myselft or bound dev's \n");
		}
#endif
		goto droped;
	}
	if(skb->pkt_type == PACKET_HOST){
	#ifdef VMETH_DEBUG
		if(debug > 0){
			printk("vmeth droped a packet because pkt_type is PACKET_HOST\n");
		}
	#endif
		goto droped;
	}
	if((skb = skb_share_check(skb,GFP_ATOMIC)) == NULL){
		goto droped;
	}
	pstEthHeader = skb->mac.ethernet;
	if(skb->pkt_type == PACKET_OTHERHOST){

	    usIndex = VMETH_GetIndexFromHashTable(pstEthHeader->h_dest);
		/*search dev failed*/
    	if(usIndex >=  VMETH_HASHTABLE_LEN){
			printk("vmeth droped a packet because not found device\n");
			goto droped; /*not support promisc mode*/
    	}
    	pstMyDev = &gstDevTable[usIndex];
    	/*device not opened*/
    	if(netif_queue_stopped(pstMyDev)){
	    	printk("vmeth droped a packet because device not opened\n");
			goto droped;
    	}
    	pstNetLocal = (struct net_local *)pstMyDev->priv;
    	skb->pkt_type = PACKET_HOST;
#ifdef VMETH_DEBUG
		if(debug > 0){
	    	printk("vmeth receive packet index=%d, dev=%s,pkt_dest_mac=%s\n",usIndex,
				pstMyDev->name,MacToStr(pstEthHeader->h_dest,gszStrMac));
		}
#endif
		skb->dev = pstMyDev;
		netif_rx(skb);/*send packet to upper link*/

		pstMyDev->last_rx = jiffies;
		pstNetLocal->stats.rx_packets +=1;
		pstNetLocal->stats.rx_bytes += skb->len;
		return 0;
	}
{
		/*multicast or promisc*/
		unsigned short i = 0;
		struct sk_buff *nskb = NULL;
		for(i = 0; i< VMETH_MAX_VM;i++){
			pstMyDev = &gstDevTable[i];
			/*device is open, and in promisc/multicast state,or packet is a broacast pakcet*/
			if((netif_queue_stopped(pstMyDev) == 0) &&
				   ((pstMyDev->flags & IFF_ALLMULTI) || 
						MAC_CMP(pstEthHeader->h_dest,pstMyDev->broadcast) ==0)){
				if( (nskb = skb_clone(skb,GFP_ATOMIC)) == NULL){
					printk("vmeth out mem\n");
					continue;
				}
				pstNetLocal = (struct net_local *)pstMyDev->priv;
				nskb->dev = pstMyDev;
				netif_rx(nskb);	/*send packet to upper link*/
				pstMyDev->last_rx = jiffies;
				pstNetLocal->stats.rx_packets +=1;
				pstNetLocal->stats.rx_bytes += nskb->len;
			}
		}
}
	kfree_skb(skb);
	return 0;
droped:
	kfree_skb(skb);
	return NET_RX_DROP;
}


#ifdef MODULE

MODULE_AUTHOR("Chen Guoqiang, douspring@263.net");
MODULE_DESCRIPTION("A simulated mutiple ethernet device driver based on a real ethernet device,version 1.0 2003/01/06");
MODULE_LICENSE("GPL");
MODULE_PARM(card_num, "i");
MODULE_PARM(host_dev, "s");
MODULE_PARM(base_mac, "6i");
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(card_num, "How much virtual device");
MODULE_PARM_DESC(host_dev, "Virtual devices is based on which device");
MODULE_PARM_DESC(base_mac, "Virtual devices is based on which mac address");
MODULE_PARM_DESC(debug, "debug switch, 0:close, >0 open");
/**
 * init_module:
 *
 * When the driver is loaded as a module this function is called. We fake up
 * a device structure with the base I/O and interrupt set as if it was being
 * called from Space.c. This minimises the extra code that would otherwise
 * be required.
 *
 * Returns 0 for success or -EIO if a card is not found. Returning an error
 * here also causes the module to be unloaded
 */
 static struct packet_type vmeth_packet_type = {
	type:	__constant_htons(ETH_P_ALL),
	func:	VMETH_Rcv,
	data:	(void*) 1, /* understand shared skbs */
};

static int VMETH_Setup()
{
	unsigned short i = 0;
	struct net_device *pstDev = NULL;
	struct net_local *pstNetLocal = NULL;
	MAC_S Mac,BaseMac;

	if(card_num >= VMETH_MAX_VM){
		card_num = VMETH_MAX_VM;
		printk("Too large vmeths, cut to %d\n",card_num);
	}
	if(card_num <=0){
		card_num = 1;
		printk("Too small vmeths, cut to %d\n",card_num);
	}
	if(card_num >= 100){
		printk("By default,linux kernel do not support eth device more than 100, you should modify kernel\n");
		printk("Your setting may be dump the kernel\n");
	}
	/*Setup mac address hash table*/
	VMETH_InitHashTable();
	if(VMETH_GetMacFromIntArray(base_mac,BaseMac) != 0){
		printk("Invalid base mac, use default\n");
		MAC_CPY(BaseMac,stDefBaseMac);
	}
	MAC_CPY(Mac,BaseMac);
	for(i = 0; i< VMETH_MAX_VM;i++){
		netif_stop_queue(&gstDevTable[i]);
		gstDevTable[i].priv = NULL;
	}
	
	for(i = 0; i < card_num; i++){
		if(i >= 0xFF){
			Mac[4] = (unsigned char)((i+1)>>8);
		}
		Mac[5] =(unsigned char)((i+1) & 0xFF);
		printk("vmeth %d mac %s\n",i,MacToStr(Mac,gszStrMac));

		if(VMETH_InsertItemToHashTable(i,Mac) != 0){
			printk("Init %d vmeth failed ,maybe mallo failed\n",i);
			MAC_CPY(pstDev->dev_addr,Mac);
			netif_stop_queue(pstDev);
			continue; /*do not register*/
		}
		pstDev = &gstDevTable[i];
		if((pstDev->priv = kmalloc(sizeof(struct net_local),GFP_KERNEL)) == NULL){
			printk("vmeth out of mem, index =%d\n",i);
			continue;
		}
		memset(pstDev->priv,0,sizeof(struct net_local));
		pstNetLocal = (struct net_local *)pstDev->priv;
		pstNetLocal->usIndex = i;
		MAC_CPY(pstDev->dev_addr,Mac);
		pstDev->init = &VMETH_Probe;
		if (register_netdev(pstDev) != 0){
			printk("Init %d vmeth failed ,register failed\n",i);
			pstDev->state = __LINK_STATE_NOCARRIER;
		}
	}
	return 0;
}

static int __init VMETH_InitModule(void)
{
	if((gpstHostDev = dev_get_by_name(host_dev)) == NULL){
		return -1;
	}
	VMETH_Setup();
	/*avoid boud dev to be deleted*/
	dev_hold(gpstHostDev);
	vmeth_packet_type.dev = gpstHostDev;
	dev_add_pack(&vmeth_packet_type);
	return 0;
}

/**
 * cleanup_module:
 * 
 * The module is being unloaded. We unhook our network device from the system
 * and then free up the resources we took when the card was found.
 */
 
static void __exit VMETH_CleanupModule(void)
{
	int i;

	dev_remove_pack(&vmeth_packet_type);
	for(i=0;i<VMETH_MAX_VM;i++)
	{
		if(gstDevTable[i].priv != NULL){
			unregister_netdev(&gstDevTable[i]);
			kfree(gstDevTable[i].priv);
			gstDevTable[i].priv = NULL;
		}
	}	
	dev_put(gpstHostDev);
	VMETH_DestroyHashTable();
	return;
}

module_init(VMETH_InitModule);
module_exit(VMETH_CleanupModule);
#endif /* MODULE */

/*
 * Local variables:
 *  compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer  -m486 -c -o 3c501.o 3c501.c"
 *  kept-new-versions: 5
 * End:
 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -