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

📄 vlan.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		return -EOPNOTSUPP;	}	/* The real device must be up and operating in order to	 * assosciate a VLAN device with it.	 */	if (!(real_dev->flags & IFF_UP))		return -ENETDOWN;	if (__find_vlan_dev(real_dev, vlan_id) != NULL) {		/* was already registered. */		printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);		return -EEXIST;	}	return 0;}int register_vlan_dev(struct net_device *dev){	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);	struct net_device *real_dev = vlan->real_dev;	unsigned short vlan_id = vlan->vlan_id;	struct vlan_group *grp, *ngrp = NULL;	int err;	grp = __vlan_find_group(real_dev->ifindex);	if (!grp) {		ngrp = grp = vlan_group_alloc(real_dev->ifindex);		if (!grp)			return -ENOBUFS;	}	err = register_netdevice(dev);	if (err < 0)		goto out_free_group;	/* Account for reference in struct vlan_dev_info */	dev_hold(real_dev);	vlan_transfer_operstate(real_dev, dev);	linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */	/* So, got the sucker initialized, now lets place	 * it into our local structure.	 */	vlan_group_set_device(grp, vlan_id, dev);	if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)		real_dev->vlan_rx_register(real_dev, ngrp);	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)		real_dev->vlan_rx_add_vid(real_dev, vlan_id);	if (vlan_proc_add_dev(dev) < 0)		printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",		       dev->name);	return 0;out_free_group:	if (ngrp)		vlan_group_free(ngrp);	return err;}/*  Attach a VLAN device to a mac address (ie Ethernet Card). *  Returns 0 if the device was created or a negative error code otherwise. */static int register_vlan_device(struct net_device *real_dev,				unsigned short VLAN_ID){	struct net_device *new_dev;	char name[IFNAMSIZ];	int err;#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)		return -ERANGE;	err = vlan_check_real_dev(real_dev, VLAN_ID);	if (err < 0)		return err;	/* Gotta set up the fields for the device. */#ifdef VLAN_DEBUG	printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n",	       vlan_name_type);#endif	switch (vlan_name_type) {	case VLAN_NAME_TYPE_RAW_PLUS_VID:		/* name will look like:	 eth1.0005 */		snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID);		break;	case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:		/* Put our vlan.VID in the name.		 * Name will look like:	 vlan5		 */		snprintf(name, IFNAMSIZ, "vlan%i", VLAN_ID);		break;	case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD:		/* Put our vlan.VID in the name.		 * Name will look like:	 eth0.5		 */		snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, VLAN_ID);		break;	case VLAN_NAME_TYPE_PLUS_VID:		/* Put our vlan.VID in the name.		 * Name will look like:	 vlan0005		 */	default:		snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID);	}	new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,			       vlan_setup);	if (new_dev == NULL)		return -ENOBUFS;	/* need 4 bytes for extra VLAN header info,	 * hope the underlying device can handle it.	 */	new_dev->mtu = real_dev->mtu;#ifdef VLAN_DEBUG	printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);	VLAN_MEM_DBG("new_dev->priv malloc, addr: %p  size: %i\n",		     new_dev->priv,		     sizeof(struct vlan_dev_info));#endif	VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */	VLAN_DEV_INFO(new_dev)->real_dev = real_dev;	VLAN_DEV_INFO(new_dev)->dent = NULL;	VLAN_DEV_INFO(new_dev)->flags = VLAN_FLAG_REORDER_HDR;	new_dev->rtnl_link_ops = &vlan_link_ops;	err = register_vlan_dev(new_dev);	if (err < 0)		goto out_free_newdev;#ifdef VLAN_DEBUG	printk(VLAN_DBG "Allocated new device successfully, returning.\n");#endif	return 0;out_free_newdev:	free_netdev(new_dev);	return err;}static void vlan_sync_address(struct net_device *dev,			      struct net_device *vlandev){	struct vlan_dev_info *vlan = VLAN_DEV_INFO(vlandev);	/* May be called without an actual change */	if (!compare_ether_addr(vlan->real_dev_addr, dev->dev_addr))		return;	/* vlan address was different from the old address and is equal to	 * the new address */	if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&	    !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))		dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN);	/* vlan address was equal to the old address and is different from	 * the new address */	if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&	    compare_ether_addr(vlandev->dev_addr, dev->dev_addr))		dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN);	memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);}static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr){	struct net_device *dev = ptr;	struct vlan_group *grp = __vlan_find_group(dev->ifindex);	int i, flgs;	struct net_device *vlandev;	if (dev->nd_net != &init_net)		return NOTIFY_DONE;	if (!grp)		goto out;	/* It is OK that we do not hold the group lock right now,	 * as we run under the RTNL lock.	 */	switch (event) {	case NETDEV_CHANGE:		/* Propagate real device state to vlan devices */		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {			vlandev = vlan_group_get_device(grp, i);			if (!vlandev)				continue;			vlan_transfer_operstate(dev, vlandev);		}		break;	case NETDEV_CHANGEADDR:		/* Adjust unicast filters on underlying device */		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {			vlandev = vlan_group_get_device(grp, i);			if (!vlandev)				continue;			flgs = vlandev->flags;			if (!(flgs & IFF_UP))				continue;			vlan_sync_address(dev, vlandev);		}		break;	case NETDEV_DOWN:		/* Put all VLANs for this dev in the down state too.  */		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {			vlandev = vlan_group_get_device(grp, i);			if (!vlandev)				continue;			flgs = vlandev->flags;			if (!(flgs & IFF_UP))				continue;			dev_change_flags(vlandev, flgs & ~IFF_UP);		}		break;	case NETDEV_UP:		/* Put all VLANs for this dev in the up state too.  */		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {			vlandev = vlan_group_get_device(grp, i);			if (!vlandev)				continue;			flgs = vlandev->flags;			if (flgs & IFF_UP)				continue;			dev_change_flags(vlandev, flgs | IFF_UP);		}		break;	case NETDEV_UNREGISTER:		/* Delete all VLANs for this dev. */		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {			int ret;			vlandev = vlan_group_get_device(grp, i);			if (!vlandev)				continue;			ret = unregister_vlan_dev(dev,						  VLAN_DEV_INFO(vlandev)->vlan_id);			unregister_netdevice(vlandev);			/* Group was destroyed? */			if (ret == 1)				break;		}		break;	}out:	return NOTIFY_DONE;}/* *	VLAN IOCTL handler. *	o execute requested action or pass command to the device driver *   arg is really a struct vlan_ioctl_args __user *. */static int vlan_ioctl_handler(struct net *net, void __user *arg){	int err;	unsigned short vid = 0;	struct vlan_ioctl_args args;	struct net_device *dev = NULL;	if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args)))		return -EFAULT;	/* Null terminate this sucker, just in case. */	args.device1[23] = 0;	args.u.device2[23] = 0;#ifdef VLAN_DEBUG	printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);#endif	rtnl_lock();	switch (args.cmd) {	case SET_VLAN_INGRESS_PRIORITY_CMD:	case SET_VLAN_EGRESS_PRIORITY_CMD:	case SET_VLAN_FLAG_CMD:	case ADD_VLAN_CMD:	case DEL_VLAN_CMD:	case GET_VLAN_REALDEV_NAME_CMD:	case GET_VLAN_VID_CMD:		err = -ENODEV;		dev = __dev_get_by_name(&init_net, args.device1);		if (!dev)			goto out;		err = -EINVAL;		if (args.cmd != ADD_VLAN_CMD &&		    !(dev->priv_flags & IFF_802_1Q_VLAN))			goto out;	}	switch (args.cmd) {	case SET_VLAN_INGRESS_PRIORITY_CMD:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		vlan_dev_set_ingress_priority(dev,					      args.u.skb_priority,					      args.vlan_qos);		err = 0;		break;	case SET_VLAN_EGRESS_PRIORITY_CMD:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		err = vlan_dev_set_egress_priority(dev,						   args.u.skb_priority,						   args.vlan_qos);		break;	case SET_VLAN_FLAG_CMD:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		err = vlan_dev_set_vlan_flag(dev,					     args.u.flag,					     args.vlan_qos);		break;	case SET_VLAN_NAME_TYPE_CMD:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		if ((args.u.name_type >= 0) &&		    (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {			vlan_name_type = args.u.name_type;			err = 0;		} else {			err = -EINVAL;		}		break;	case ADD_VLAN_CMD:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		err = register_vlan_device(dev, args.u.VID);		break;	case DEL_VLAN_CMD:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		err = unregister_vlan_device(dev);		break;	case GET_VLAN_INGRESS_PRIORITY_CMD:		/* TODO:  Implement		   err = vlan_dev_get_ingress_priority(args);		   if (copy_to_user((void*)arg, &args,			sizeof(struct vlan_ioctl_args))) {			err = -EFAULT;		   }		*/		err = -EINVAL;		break;	case GET_VLAN_EGRESS_PRIORITY_CMD:		/* TODO:  Implement		   err = vlan_dev_get_egress_priority(args.device1, &(args.args);		   if (copy_to_user((void*)arg, &args,			sizeof(struct vlan_ioctl_args))) {			err = -EFAULT;		   }		*/		err = -EINVAL;		break;	case GET_VLAN_REALDEV_NAME_CMD:		err = 0;		vlan_dev_get_realdev_name(dev, args.u.device2);		if (copy_to_user(arg, &args,				 sizeof(struct vlan_ioctl_args))) {			err = -EFAULT;		}		break;	case GET_VLAN_VID_CMD:		err = 0;		vlan_dev_get_vid(dev, &vid);		args.u.VID = vid;		if (copy_to_user(arg, &args,				 sizeof(struct vlan_ioctl_args))) {		      err = -EFAULT;		}		break;	default:		/* pass on to underlying device instead?? */		printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",			__FUNCTION__, args.cmd);		err = -EINVAL;		break;	}out:	rtnl_unlock();	return err;}MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);

⌨️ 快捷键说明

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