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

📄 vlan.c

📁 linux 内核源代码
💻 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 <net/net_namespace.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(struct net *net, 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)		goto err1;	err = vlan_netlink_init();	if (err < 0)		goto err2;	vlan_ioctl_set(vlan_ioctl_handler);	return 0;err2:	unregister_netdevice_notifier(&vlan_notifier_block);err1:	vlan_proc_cleanup();	dev_remove_pack(&vlan_packet_type);	return err;}/* *     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);	vlan_netlink_fini();	/* Un-register us from receiving netdevice events */	unregister_netdevice_notifier(&vlan_notifier_block);	dev_remove_pack(&vlan_packet_type);	/* 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 vlan_group_get_device(grp, VID);	return NULL;}static void vlan_group_free(struct vlan_group *grp){	int i;	for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)		kfree(grp->vlan_devices_arrays[i]);	kfree(grp);}static struct vlan_group *vlan_group_alloc(int ifindex){	struct vlan_group *grp;	unsigned int size;	unsigned int i;	grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);	if (!grp)		return NULL;	size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;	for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {		grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL);		if (!grp->vlan_devices_arrays[i])			goto err;	}	grp->real_dev_ifindex = ifindex;	hlist_add_head_rcu(&grp->hlist,			   &vlan_group_hash[vlan_grp_hashfn(ifindex)]);	return grp;err:	vlan_group_free(grp);	return NULL;}static void vlan_rcu_free(struct rcu_head *rcu){	vlan_group_free(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 = vlan_group_get_device(grp, 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_FILTER)				real_dev->vlan_rx_kill_vid(real_dev, vlan_id);			vlan_group_set_device(grp, 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 (vlan_group_get_device(grp, 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;}int unregister_vlan_device(struct net_device *dev){	int ret;	ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,				  VLAN_DEV_INFO(dev)->vlan_id);	unregister_netdevice(dev);	if (ret == 1)		ret = 0;	return ret;}/* * 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;static const struct header_ops vlan_header_ops = {	.create	 = vlan_dev_hard_header,	.rebuild = vlan_dev_rebuild_header,	.parse	 = eth_header_parse,};static int vlan_dev_init(struct net_device *dev){	struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;	int subclass = 0;	/* IFF_BROADCAST|IFF_MULTICAST; ??? */	dev->flags  = real_dev->flags & ~IFF_UP;	dev->iflink = real_dev->ifindex;	dev->state  = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |					  (1<<__LINK_STATE_DORMANT))) |		      (1<<__LINK_STATE_PRESENT);	/* ipv6 shared card related stuff */	dev->dev_id = real_dev->dev_id;	if (is_zero_ether_addr(dev->dev_addr))		memcpy(dev->dev_addr, real_dev->dev_addr, dev->addr_len);	if (is_zero_ether_addr(dev->broadcast))		memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);	if (real_dev->features & NETIF_F_HW_VLAN_TX) {		dev->header_ops      = real_dev->header_ops;		dev->hard_header_len = real_dev->hard_header_len;		dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;	} else {		dev->header_ops      = &vlan_header_ops;		dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;		dev->hard_start_xmit = vlan_dev_hard_start_xmit;	}	if (real_dev->priv_flags & IFF_802_1Q_VLAN)		subclass = 1;	lockdep_set_class_and_subclass(&dev->_xmit_lock,				&vlan_netdev_xmit_lock_key, subclass);	return 0;}void vlan_setup(struct net_device *new_dev){	ether_setup(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->init = vlan_dev_init;	new_dev->open = vlan_dev_open;	new_dev->stop = vlan_dev_stop;	new_dev->set_mac_address = vlan_set_mac_address;	new_dev->set_multicast_list = vlan_dev_set_multicast_list;	new_dev->change_rx_flags = vlan_change_rx_flags;	new_dev->destructor = free_netdev;	new_dev->do_ioctl = vlan_dev_ioctl;	memset(new_dev->broadcast, 0, ETH_ALEN);}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);	}}int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id){	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {		printk(VLAN_DBG "%s: VLANs not supported on %s.\n",			__FUNCTION__, real_dev->name);		return -EOPNOTSUPP;	}	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&	    !real_dev->vlan_rx_register) {		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",			__FUNCTION__, real_dev->name);		return -EOPNOTSUPP;	}	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&	    (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) {		printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",			__FUNCTION__, real_dev->name);

⌨️ 快捷键说明

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