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

📄 vlan.c

📁 linux 下对8021q协议的配置和实现的增强
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		802.1Q VLAN *		Ethernet-type device handling. * * Authors:	Ben Greear <greearb@candelatech.com> *              Please send support related email to: vlan@scry.wanfear.com *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html *  * Fixes: *              Fix for packet capture - Nick Eggleston <nick@dccinc.com>; *		Add HW acceleration hooks - David S. Miller <davem@redhat.com>; *		Correct all the locking - David S. Miller <davem@redhat.com>; *		Use hash table for VLAN groups - David S. Miller <davem@redhat.com> * *		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. */#include <asm/uaccess.h> /* for copy_from_user */#include <linux/capability.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <net/datalink.h>#include <linux/mm.h>#include <linux/in.h>#include <linux/init.h>#include <net/p8022.h>#include <net/arp.h>#include <linux/rtnetlink.h>#include <linux/notifier.h>#include <linux/if_vlan.h>#include "vlan.h"#include "vlanproc.h"#define DRV_VERSION "1.8"/* Global VLAN variables *//* Our listing of VLAN group(s) */static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];#define vlan_grp_hashfn(IDX)	((((IDX) >> VLAN_GRP_HASH_SHIFT) ^ (IDX)) & VLAN_GRP_HASH_MASK)static char vlan_fullname[] = "802.1Q VLAN Support";static char vlan_version[] = DRV_VERSION;static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";static int vlan_device_event(struct notifier_block *, unsigned long, void *);static int vlan_ioctl_handler(void __user *);static int unregister_vlan_dev(struct net_device *, unsigned short );static struct notifier_block vlan_notifier_block = {	.notifier_call = vlan_device_event,};/* These may be changed at run-time through IOCTLs *//* Determines interface naming scheme. */unsigned short vlan_name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;static struct packet_type vlan_packet_type = {	.type = __constant_htons(ETH_P_8021Q),	.func = vlan_skb_recv, /* VLAN receive method */};/* End of global variables definitions. *//* * Function vlan_proto_init (pro) * *    Initialize VLAN protocol layer,  * */static int __init vlan_proto_init(void){	int err;	printk(VLAN_INF "%s v%s %s\n",	       vlan_fullname, vlan_version, vlan_copyright);	printk(VLAN_INF "All bugs added by %s\n",	       vlan_buggyright);	/* proc file system initialization */	err = vlan_proc_init();	if (err < 0) {		printk(KERN_ERR 		       "%s %s: can't create entry in proc filesystem!\n",		       __FUNCTION__, VLAN_NAME);		return err;	}	dev_add_pack(&vlan_packet_type);	/* Register us to receive netdevice events */	err = register_netdevice_notifier(&vlan_notifier_block);	if (err < 0) {		dev_remove_pack(&vlan_packet_type);		vlan_proc_cleanup();		return err;	}	vlan_ioctl_set(vlan_ioctl_handler);	return 0;}/* Cleanup all vlan devices  * Note: devices that have been registered that but not * brought up will exist but have no module ref count. */static void __exit vlan_cleanup_devices(void){	struct net_device *dev, *nxt;	rtnl_lock();	for (dev = dev_base; dev; dev = nxt) {		nxt = dev->next;		if (dev->priv_flags & IFF_802_1Q_VLAN) {			unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,					    VLAN_DEV_INFO(dev)->vlan_id);			unregister_netdevice(dev);		}	}	rtnl_unlock();}/* *     Module 'remove' entry point. *     o delete /proc/net/router directory and static entries. */ static void __exit vlan_cleanup_module(void){	int i;	vlan_ioctl_set(NULL);	/* Un-register us from receiving netdevice events */	unregister_netdevice_notifier(&vlan_notifier_block);	dev_remove_pack(&vlan_packet_type);	vlan_cleanup_devices();	/* This table must be empty if there are no module	 * references left.	 */	for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) {		BUG_ON(!hlist_empty(&vlan_group_hash[i]));	}	vlan_proc_cleanup();	synchronize_net();}module_init(vlan_proto_init);module_exit(vlan_cleanup_module);/* Must be invoked with RCU read lock (no preempt) */static struct vlan_group *__vlan_find_group(int real_dev_ifindex){	struct vlan_group *grp;	struct hlist_node *n;	int hash = vlan_grp_hashfn(real_dev_ifindex);	hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) {		if (grp->real_dev_ifindex == real_dev_ifindex)			return grp;	}	return NULL;}/*  Find the protocol handler.  Assumes VID < VLAN_VID_MASK. * * Must be invoked with RCU read lock (no preempt) */struct net_device *__find_vlan_dev(struct net_device *real_dev,				   unsigned short VID){	struct vlan_group *grp = __vlan_find_group(real_dev->ifindex);	if (grp)                return grp->vlan_devices[VID];	return NULL;}static void vlan_rcu_free(struct rcu_head *rcu){	kfree(container_of(rcu, struct vlan_group, rcu));}/* This returns 0 if everything went fine. * It will return 1 if the group was killed as a result. * A negative return indicates failure. * * The RTNL lock must be held. */static int unregister_vlan_dev(struct net_device *real_dev,			       unsigned short vlan_id){	struct net_device *dev = NULL;	int real_dev_ifindex = real_dev->ifindex;	struct vlan_group *grp;	int i, ret;#ifdef VLAN_DEBUG	printk(VLAN_DBG "%s: VID: %i\n", __FUNCTION__, vlan_id);#endif	/* sanity check */	if (vlan_id >= VLAN_VID_MASK)		return -EINVAL;	ASSERT_RTNL();	grp = __vlan_find_group(real_dev_ifindex);	ret = 0;	if (grp) {		dev = grp->vlan_devices[vlan_id];		if (dev) {			/* Remove proc entry */			vlan_proc_rem_dev(dev);			/* Take it out of our own structures, but be sure to			 * interlock with HW accelerating devices or SW vlan			 * input packet processing.			 */			if (real_dev->features &			    (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER)) {				real_dev->vlan_rx_kill_vid(real_dev, vlan_id);			}			grp->vlan_devices[vlan_id] = NULL;			synchronize_net();			/* Caller unregisters (and if necessary, puts)			 * VLAN device, but we get rid of the reference to			 * real_dev here.			 */			dev_put(real_dev);			/* If the group is now empty, kill off the			 * group.			 */			for (i = 0; i < VLAN_VID_MASK; i++)				if (grp->vlan_devices[i])					break;			if (i == VLAN_VID_MASK) {				if (real_dev->features & NETIF_F_HW_VLAN_RX)					real_dev->vlan_rx_register(real_dev, NULL);				hlist_del_rcu(&grp->hlist);				/* Free the group, after all cpu's are done. */				call_rcu(&grp->rcu, vlan_rcu_free);				grp = NULL;				ret = 1;			}		}	}        return ret;}static int unregister_vlan_device(const char *vlan_IF_name){	struct net_device *dev = NULL;	int ret;	dev = dev_get_by_name(vlan_IF_name);	ret = -EINVAL;	if (dev) {		if (dev->priv_flags & IFF_802_1Q_VLAN) {			rtnl_lock();			ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,						  VLAN_DEV_INFO(dev)->vlan_id);			dev_put(dev);			unregister_netdevice(dev);			rtnl_unlock();			if (ret == 1)				ret = 0;		} else {			printk(VLAN_ERR 			       "%s: ERROR:	Tried to remove a non-vlan device "			       "with VLAN code, name: %s  priv_flags: %hX\n",			       __FUNCTION__, dev->name, dev->priv_flags);			dev_put(dev);			ret = -EPERM;		}	} else {#ifdef VLAN_DEBUG		printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__);#endif		ret = -EINVAL;	}	return ret;}static void vlan_setup(struct net_device *new_dev){	SET_MODULE_OWNER(new_dev);	    	/* new_dev->ifindex = 0;  it will be set when added to	 * the global list.	 * iflink is set as well.	 */	new_dev->get_stats = vlan_dev_get_stats;	/* Make this thing known as a VLAN device */	new_dev->priv_flags |= IFF_802_1Q_VLAN;					/* Set us up to have no queue, as the underlying Hardware device	 * can do all the queueing we could want.	 */	new_dev->tx_queue_len = 0;	/* set up method calls */	new_dev->change_mtu = vlan_dev_change_mtu;	new_dev->open = vlan_dev_open;	new_dev->stop = vlan_dev_stop;	new_dev->set_mac_address = vlan_dev_set_mac_address;	new_dev->set_multicast_list = vlan_dev_set_multicast_list;	new_dev->destructor = free_netdev;	new_dev->do_ioctl = vlan_dev_ioctl;}static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev){	/* Have to respect userspace enforced dormant state	 * of real device, also must allow supplicant running	 * on VLAN device	 */	if (dev->operstate == IF_OPER_DORMANT)		netif_dormant_on(vlandev);	else		netif_dormant_off(vlandev);	if (netif_carrier_ok(dev)) {		if (!netif_carrier_ok(vlandev))			netif_carrier_on(vlandev);	} else {		if (netif_carrier_ok(vlandev))			netif_carrier_off(vlandev);	}}/* * vlan network devices have devices nesting below it, and are a special * "super class" of normal network devices; split their locks off into a * separate class since they always nest. */static struct lock_class_key vlan_netdev_xmit_lock_key;/*  Attach a VLAN device to a mac address (ie Ethernet Card). *  Returns the device that was created, or NULL if there was *  an error of some kind. */static struct net_device *register_vlan_device(const char *eth_IF_name,					       unsigned short VLAN_ID){	struct vlan_group *grp;	struct net_device *new_dev;	struct net_device *real_dev; /* the ethernet device */	char name[IFNAMSIZ];#ifdef VLAN_DEBUG	printk(VLAN_DBG "%s: if_name -:%s:-	vid: %i\n",		__FUNCTION__, eth_IF_name, VLAN_ID);#endif	if (VLAN_ID >= VLAN_VID_MASK)		goto out_ret_null;	/* find the device relating to eth_IF_name. */	real_dev = dev_get_by_name(eth_IF_name);	if (!real_dev)		goto out_ret_null;	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {		printk(VLAN_DBG "%s: VLANs not supported on %s.\n",			__FUNCTION__, real_dev->name);		goto out_put_dev;	}	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&	    (real_dev->vlan_rx_register == NULL ||	     real_dev->vlan_rx_kill_vid == NULL)) {

⌨️ 快捷键说明

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