xref: /openbmc/linux/net/8021q/vlan.c (revision 198a291ce3a9103f4738600e3cf5416b66e009d9)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * INET		802.1Q VLAN
31da177e4SLinus Torvalds  *		Ethernet-type device handling.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Authors:	Ben Greear <greearb@candelatech.com>
61da177e4SLinus Torvalds  *              Please send support related email to: vlan@scry.wanfear.com
71da177e4SLinus Torvalds  *              VLAN Home Page: http://www.candelatech.com/~greear/vlan.html
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Fixes:
101da177e4SLinus Torvalds  *              Fix for packet capture - Nick Eggleston <nick@dccinc.com>;
111da177e4SLinus Torvalds  *		Add HW acceleration hooks - David S. Miller <davem@redhat.com>;
121da177e4SLinus Torvalds  *		Correct all the locking - David S. Miller <davem@redhat.com>;
131da177e4SLinus Torvalds  *		Use hash table for VLAN groups - David S. Miller <davem@redhat.com>
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  *		This program is free software; you can redistribute it and/or
161da177e4SLinus Torvalds  *		modify it under the terms of the GNU General Public License
171da177e4SLinus Torvalds  *		as published by the Free Software Foundation; either version
181da177e4SLinus Torvalds  *		2 of the License, or (at your option) any later version.
191da177e4SLinus Torvalds  */
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #include <asm/uaccess.h> /* for copy_from_user */
224fc268d2SRandy Dunlap #include <linux/capability.h>
231da177e4SLinus Torvalds #include <linux/module.h>
241da177e4SLinus Torvalds #include <linux/netdevice.h>
251da177e4SLinus Torvalds #include <linux/skbuff.h>
261da177e4SLinus Torvalds #include <net/datalink.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/in.h>
291da177e4SLinus Torvalds #include <linux/init.h>
301da177e4SLinus Torvalds #include <net/p8022.h>
311da177e4SLinus Torvalds #include <net/arp.h>
321da177e4SLinus Torvalds #include <linux/rtnetlink.h>
331da177e4SLinus Torvalds #include <linux/notifier.h>
34e9dc8653SEric W. Biederman #include <net/net_namespace.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include <linux/if_vlan.h>
371da177e4SLinus Torvalds #include "vlan.h"
381da177e4SLinus Torvalds #include "vlanproc.h"
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds #define DRV_VERSION "1.8"
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds /* Global VLAN variables */
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds /* Our listing of VLAN group(s) */
451da177e4SLinus Torvalds static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE];
461da177e4SLinus Torvalds #define vlan_grp_hashfn(IDX)	((((IDX) >> VLAN_GRP_HASH_SHIFT) ^ (IDX)) & VLAN_GRP_HASH_MASK)
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds static char vlan_fullname[] = "802.1Q VLAN Support";
491da177e4SLinus Torvalds static char vlan_version[] = DRV_VERSION;
501da177e4SLinus Torvalds static char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
511da177e4SLinus Torvalds static char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds static int vlan_device_event(struct notifier_block *, unsigned long, void *);
54881d966bSEric W. Biederman static int vlan_ioctl_handler(struct net *net, void __user *);
551da177e4SLinus Torvalds static int unregister_vlan_dev(struct net_device *, unsigned short );
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds static struct notifier_block vlan_notifier_block = {
581da177e4SLinus Torvalds 	.notifier_call = vlan_device_event,
591da177e4SLinus Torvalds };
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /* These may be changed at run-time through IOCTLs */
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /* Determines interface naming scheme. */
641da177e4SLinus Torvalds unsigned short vlan_name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds static struct packet_type vlan_packet_type = {
671da177e4SLinus Torvalds 	.type = __constant_htons(ETH_P_8021Q),
681da177e4SLinus Torvalds 	.func = vlan_skb_recv, /* VLAN receive method */
691da177e4SLinus Torvalds };
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /* End of global variables definitions. */
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds /*
741da177e4SLinus Torvalds  * Function vlan_proto_init (pro)
751da177e4SLinus Torvalds  *
761da177e4SLinus Torvalds  *    Initialize VLAN protocol layer,
771da177e4SLinus Torvalds  *
781da177e4SLinus Torvalds  */
791da177e4SLinus Torvalds static int __init vlan_proto_init(void)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	int err;
821da177e4SLinus Torvalds 
8340f98e1aSPatrick McHardy 	pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright);
8440f98e1aSPatrick McHardy 	pr_info("All bugs added by %s\n", vlan_buggyright);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	/* proc file system initialization */
871da177e4SLinus Torvalds 	err = vlan_proc_init();
881da177e4SLinus Torvalds 	if (err < 0) {
8940f98e1aSPatrick McHardy 		pr_err("%s: can't create entry in proc filesystem!\n",
90b7a4a836SPatrick McHardy 		       __FUNCTION__);
911da177e4SLinus Torvalds 		return err;
921da177e4SLinus Torvalds 	}
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	dev_add_pack(&vlan_packet_type);
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	/* Register us to receive netdevice events */
971da177e4SLinus Torvalds 	err = register_netdevice_notifier(&vlan_notifier_block);
9807b5b17eSPatrick McHardy 	if (err < 0)
9907b5b17eSPatrick McHardy 		goto err1;
10007b5b17eSPatrick McHardy 
10107b5b17eSPatrick McHardy 	err = vlan_netlink_init();
10207b5b17eSPatrick McHardy 	if (err < 0)
10307b5b17eSPatrick McHardy 		goto err2;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	vlan_ioctl_set(vlan_ioctl_handler);
1061da177e4SLinus Torvalds 	return 0;
10707b5b17eSPatrick McHardy 
10807b5b17eSPatrick McHardy err2:
10907b5b17eSPatrick McHardy 	unregister_netdevice_notifier(&vlan_notifier_block);
11007b5b17eSPatrick McHardy err1:
11107b5b17eSPatrick McHardy 	vlan_proc_cleanup();
11207b5b17eSPatrick McHardy 	dev_remove_pack(&vlan_packet_type);
11307b5b17eSPatrick McHardy 	return err;
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds /*
1171da177e4SLinus Torvalds  *     Module 'remove' entry point.
1181da177e4SLinus Torvalds  *     o delete /proc/net/router directory and static entries.
1191da177e4SLinus Torvalds  */
1201da177e4SLinus Torvalds static void __exit vlan_cleanup_module(void)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	int i;
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	vlan_ioctl_set(NULL);
1253f03e387SPavel Emelyanov 	vlan_netlink_fini();
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	/* Un-register us from receiving netdevice events */
1281da177e4SLinus Torvalds 	unregister_netdevice_notifier(&vlan_notifier_block);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	dev_remove_pack(&vlan_packet_type);
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	/* This table must be empty if there are no module
1331da177e4SLinus Torvalds 	 * references left.
1341da177e4SLinus Torvalds 	 */
1351da177e4SLinus Torvalds 	for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) {
1361da177e4SLinus Torvalds 		BUG_ON(!hlist_empty(&vlan_group_hash[i]));
1371da177e4SLinus Torvalds 	}
1381da177e4SLinus Torvalds 	vlan_proc_cleanup();
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	synchronize_net();
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds module_init(vlan_proto_init);
1441da177e4SLinus Torvalds module_exit(vlan_cleanup_module);
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /* Must be invoked with RCU read lock (no preempt) */
1471da177e4SLinus Torvalds static struct vlan_group *__vlan_find_group(int real_dev_ifindex)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	struct vlan_group *grp;
1501da177e4SLinus Torvalds 	struct hlist_node *n;
1511da177e4SLinus Torvalds 	int hash = vlan_grp_hashfn(real_dev_ifindex);
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) {
1541da177e4SLinus Torvalds 		if (grp->real_dev_ifindex == real_dev_ifindex)
1551da177e4SLinus Torvalds 			return grp;
1561da177e4SLinus Torvalds 	}
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 	return NULL;
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds /*  Find the protocol handler.  Assumes VID < VLAN_VID_MASK.
1621da177e4SLinus Torvalds  *
1631da177e4SLinus Torvalds  * Must be invoked with RCU read lock (no preempt)
1641da177e4SLinus Torvalds  */
1651da177e4SLinus Torvalds struct net_device *__find_vlan_dev(struct net_device *real_dev,
1661da177e4SLinus Torvalds 				   unsigned short VID)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds 	struct vlan_group *grp = __vlan_find_group(real_dev->ifindex);
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 	if (grp)
1715c15bdecSDan Aloni 		return vlan_group_get_device(grp, VID);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	return NULL;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
1765c15bdecSDan Aloni static void vlan_group_free(struct vlan_group *grp)
1775c15bdecSDan Aloni {
1785c15bdecSDan Aloni 	int i;
1795c15bdecSDan Aloni 
1805c15bdecSDan Aloni 	for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
1815c15bdecSDan Aloni 		kfree(grp->vlan_devices_arrays[i]);
1825c15bdecSDan Aloni 	kfree(grp);
1835c15bdecSDan Aloni }
1845c15bdecSDan Aloni 
18542429aaeSPatrick McHardy static struct vlan_group *vlan_group_alloc(int ifindex)
18642429aaeSPatrick McHardy {
18742429aaeSPatrick McHardy 	struct vlan_group *grp;
18842429aaeSPatrick McHardy 	unsigned int size;
18942429aaeSPatrick McHardy 	unsigned int i;
19042429aaeSPatrick McHardy 
19142429aaeSPatrick McHardy 	grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
19242429aaeSPatrick McHardy 	if (!grp)
19342429aaeSPatrick McHardy 		return NULL;
19442429aaeSPatrick McHardy 
19542429aaeSPatrick McHardy 	size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
19642429aaeSPatrick McHardy 
19742429aaeSPatrick McHardy 	for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
19842429aaeSPatrick McHardy 		grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL);
19942429aaeSPatrick McHardy 		if (!grp->vlan_devices_arrays[i])
20042429aaeSPatrick McHardy 			goto err;
20142429aaeSPatrick McHardy 	}
20242429aaeSPatrick McHardy 
20342429aaeSPatrick McHardy 	grp->real_dev_ifindex = ifindex;
20442429aaeSPatrick McHardy 	hlist_add_head_rcu(&grp->hlist,
20542429aaeSPatrick McHardy 			   &vlan_group_hash[vlan_grp_hashfn(ifindex)]);
20642429aaeSPatrick McHardy 	return grp;
20742429aaeSPatrick McHardy 
20842429aaeSPatrick McHardy err:
20942429aaeSPatrick McHardy 	vlan_group_free(grp);
21042429aaeSPatrick McHardy 	return NULL;
21142429aaeSPatrick McHardy }
21242429aaeSPatrick McHardy 
2131da177e4SLinus Torvalds static void vlan_rcu_free(struct rcu_head *rcu)
2141da177e4SLinus Torvalds {
2155c15bdecSDan Aloni 	vlan_group_free(container_of(rcu, struct vlan_group, rcu));
2161da177e4SLinus Torvalds }
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds /* This returns 0 if everything went fine.
2201da177e4SLinus Torvalds  * It will return 1 if the group was killed as a result.
2211da177e4SLinus Torvalds  * A negative return indicates failure.
2221da177e4SLinus Torvalds  *
2231da177e4SLinus Torvalds  * The RTNL lock must be held.
2241da177e4SLinus Torvalds  */
2251da177e4SLinus Torvalds static int unregister_vlan_dev(struct net_device *real_dev,
2261da177e4SLinus Torvalds 			       unsigned short vlan_id)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	struct net_device *dev = NULL;
2291da177e4SLinus Torvalds 	int real_dev_ifindex = real_dev->ifindex;
2301da177e4SLinus Torvalds 	struct vlan_group *grp;
2311da177e4SLinus Torvalds 	int i, ret;
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	/* sanity check */
2341da177e4SLinus Torvalds 	if (vlan_id >= VLAN_VID_MASK)
2351da177e4SLinus Torvalds 		return -EINVAL;
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds 	ASSERT_RTNL();
2381da177e4SLinus Torvalds 	grp = __vlan_find_group(real_dev_ifindex);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	ret = 0;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	if (grp) {
2435c15bdecSDan Aloni 		dev = vlan_group_get_device(grp, vlan_id);
2441da177e4SLinus Torvalds 		if (dev) {
2451da177e4SLinus Torvalds 			/* Remove proc entry */
2461da177e4SLinus Torvalds 			vlan_proc_rem_dev(dev);
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 			/* Take it out of our own structures, but be sure to
2491da177e4SLinus Torvalds 			 * interlock with HW accelerating devices or SW vlan
2501da177e4SLinus Torvalds 			 * input packet processing.
2511da177e4SLinus Torvalds 			 */
252d2d1acdbSStephen Hemminger 			if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
2531da177e4SLinus Torvalds 				real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
2541da177e4SLinus Torvalds 
2555c15bdecSDan Aloni 			vlan_group_set_device(grp, vlan_id, NULL);
2561da177e4SLinus Torvalds 			synchronize_net();
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 			/* Caller unregisters (and if necessary, puts)
2601da177e4SLinus Torvalds 			 * VLAN device, but we get rid of the reference to
2611da177e4SLinus Torvalds 			 * real_dev here.
2621da177e4SLinus Torvalds 			 */
2631da177e4SLinus Torvalds 			dev_put(real_dev);
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 			/* If the group is now empty, kill off the
2661da177e4SLinus Torvalds 			 * group.
2671da177e4SLinus Torvalds 			 */
2681da177e4SLinus Torvalds 			for (i = 0; i < VLAN_VID_MASK; i++)
2695c15bdecSDan Aloni 				if (vlan_group_get_device(grp, i))
2701da177e4SLinus Torvalds 					break;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 			if (i == VLAN_VID_MASK) {
2731da177e4SLinus Torvalds 				if (real_dev->features & NETIF_F_HW_VLAN_RX)
2741da177e4SLinus Torvalds 					real_dev->vlan_rx_register(real_dev, NULL);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 				hlist_del_rcu(&grp->hlist);
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 				/* Free the group, after all cpu's are done. */
2791da177e4SLinus Torvalds 				call_rcu(&grp->rcu, vlan_rcu_free);
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 				grp = NULL;
2821da177e4SLinus Torvalds 				ret = 1;
2831da177e4SLinus Torvalds 			}
2841da177e4SLinus Torvalds 		}
2851da177e4SLinus Torvalds 	}
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	return ret;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
29007b5b17eSPatrick McHardy int unregister_vlan_device(struct net_device *dev)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	int ret;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
2951da177e4SLinus Torvalds 				  VLAN_DEV_INFO(dev)->vlan_id);
2961da177e4SLinus Torvalds 	unregister_netdevice(dev);
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds 	if (ret == 1)
2991da177e4SLinus Torvalds 		ret = 0;
3001da177e4SLinus Torvalds 	return ret;
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds 
303ddd7bf9fSStefan Rompf static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
304ddd7bf9fSStefan Rompf {
305ddd7bf9fSStefan Rompf 	/* Have to respect userspace enforced dormant state
306ddd7bf9fSStefan Rompf 	 * of real device, also must allow supplicant running
307ddd7bf9fSStefan Rompf 	 * on VLAN device
308ddd7bf9fSStefan Rompf 	 */
309ddd7bf9fSStefan Rompf 	if (dev->operstate == IF_OPER_DORMANT)
310ddd7bf9fSStefan Rompf 		netif_dormant_on(vlandev);
311ddd7bf9fSStefan Rompf 	else
312ddd7bf9fSStefan Rompf 		netif_dormant_off(vlandev);
313ddd7bf9fSStefan Rompf 
314ddd7bf9fSStefan Rompf 	if (netif_carrier_ok(dev)) {
315ddd7bf9fSStefan Rompf 		if (!netif_carrier_ok(vlandev))
316ddd7bf9fSStefan Rompf 			netif_carrier_on(vlandev);
317ddd7bf9fSStefan Rompf 	} else {
318ddd7bf9fSStefan Rompf 		if (netif_carrier_ok(vlandev))
319ddd7bf9fSStefan Rompf 			netif_carrier_off(vlandev);
320ddd7bf9fSStefan Rompf 	}
321ddd7bf9fSStefan Rompf }
322ddd7bf9fSStefan Rompf 
32307b5b17eSPatrick McHardy int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id)
324c1d3ee99SPatrick McHardy {
32540f98e1aSPatrick McHardy 	char *name = real_dev->name;
32640f98e1aSPatrick McHardy 
327c1d3ee99SPatrick McHardy 	if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
32840f98e1aSPatrick McHardy 		pr_info("8021q: VLANs not supported on %s\n", name);
329c1d3ee99SPatrick McHardy 		return -EOPNOTSUPP;
330c1d3ee99SPatrick McHardy 	}
331c1d3ee99SPatrick McHardy 
332c1d3ee99SPatrick McHardy 	if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
333c1d3ee99SPatrick McHardy 	    !real_dev->vlan_rx_register) {
33440f98e1aSPatrick McHardy 		pr_info("8021q: device %s has buggy VLAN hw accel\n", name);
335c1d3ee99SPatrick McHardy 		return -EOPNOTSUPP;
336c1d3ee99SPatrick McHardy 	}
337c1d3ee99SPatrick McHardy 
338c1d3ee99SPatrick McHardy 	if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
339c1d3ee99SPatrick McHardy 	    (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) {
34040f98e1aSPatrick McHardy 		pr_info("8021q: Device %s has buggy VLAN hw accel\n", name);
341c1d3ee99SPatrick McHardy 		return -EOPNOTSUPP;
342c1d3ee99SPatrick McHardy 	}
343c1d3ee99SPatrick McHardy 
344c1d3ee99SPatrick McHardy 	/* The real device must be up and operating in order to
345c1d3ee99SPatrick McHardy 	 * assosciate a VLAN device with it.
346c1d3ee99SPatrick McHardy 	 */
347c1d3ee99SPatrick McHardy 	if (!(real_dev->flags & IFF_UP))
348c1d3ee99SPatrick McHardy 		return -ENETDOWN;
349c1d3ee99SPatrick McHardy 
35040f98e1aSPatrick McHardy 	if (__find_vlan_dev(real_dev, vlan_id) != NULL)
351c1d3ee99SPatrick McHardy 		return -EEXIST;
352c1d3ee99SPatrick McHardy 
353c1d3ee99SPatrick McHardy 	return 0;
354c1d3ee99SPatrick McHardy }
355c1d3ee99SPatrick McHardy 
35607b5b17eSPatrick McHardy int register_vlan_dev(struct net_device *dev)
357e89fe42cSPatrick McHardy {
358e89fe42cSPatrick McHardy 	struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
359e89fe42cSPatrick McHardy 	struct net_device *real_dev = vlan->real_dev;
360e89fe42cSPatrick McHardy 	unsigned short vlan_id = vlan->vlan_id;
361e89fe42cSPatrick McHardy 	struct vlan_group *grp, *ngrp = NULL;
362e89fe42cSPatrick McHardy 	int err;
363e89fe42cSPatrick McHardy 
364e89fe42cSPatrick McHardy 	grp = __vlan_find_group(real_dev->ifindex);
365e89fe42cSPatrick McHardy 	if (!grp) {
366e89fe42cSPatrick McHardy 		ngrp = grp = vlan_group_alloc(real_dev->ifindex);
367e89fe42cSPatrick McHardy 		if (!grp)
368e89fe42cSPatrick McHardy 			return -ENOBUFS;
369e89fe42cSPatrick McHardy 	}
370e89fe42cSPatrick McHardy 
371e89fe42cSPatrick McHardy 	err = register_netdevice(dev);
372e89fe42cSPatrick McHardy 	if (err < 0)
373e89fe42cSPatrick McHardy 		goto out_free_group;
374e89fe42cSPatrick McHardy 
375e89fe42cSPatrick McHardy 	/* Account for reference in struct vlan_dev_info */
376e89fe42cSPatrick McHardy 	dev_hold(real_dev);
377e89fe42cSPatrick McHardy 
378e89fe42cSPatrick McHardy 	vlan_transfer_operstate(real_dev, dev);
379e89fe42cSPatrick McHardy 	linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
380e89fe42cSPatrick McHardy 
381e89fe42cSPatrick McHardy 	/* So, got the sucker initialized, now lets place
382e89fe42cSPatrick McHardy 	 * it into our local structure.
383e89fe42cSPatrick McHardy 	 */
384e89fe42cSPatrick McHardy 	vlan_group_set_device(grp, vlan_id, dev);
385e89fe42cSPatrick McHardy 	if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
386e89fe42cSPatrick McHardy 		real_dev->vlan_rx_register(real_dev, ngrp);
387e89fe42cSPatrick McHardy 	if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
388e89fe42cSPatrick McHardy 		real_dev->vlan_rx_add_vid(real_dev, vlan_id);
389e89fe42cSPatrick McHardy 
390e89fe42cSPatrick McHardy 	if (vlan_proc_add_dev(dev) < 0)
39140f98e1aSPatrick McHardy 		pr_warning("8021q: failed to add proc entry for %s\n",
392e89fe42cSPatrick McHardy 			   dev->name);
393e89fe42cSPatrick McHardy 	return 0;
394e89fe42cSPatrick McHardy 
395e89fe42cSPatrick McHardy out_free_group:
396e89fe42cSPatrick McHardy 	if (ngrp)
397e89fe42cSPatrick McHardy 		vlan_group_free(ngrp);
398e89fe42cSPatrick McHardy 	return err;
399e89fe42cSPatrick McHardy }
400e89fe42cSPatrick McHardy 
4011da177e4SLinus Torvalds /*  Attach a VLAN device to a mac address (ie Ethernet Card).
4022ae0bf69SPatrick McHardy  *  Returns 0 if the device was created or a negative error code otherwise.
4031da177e4SLinus Torvalds  */
4042ae0bf69SPatrick McHardy static int register_vlan_device(struct net_device *real_dev,
4051da177e4SLinus Torvalds 				unsigned short VLAN_ID)
4061da177e4SLinus Torvalds {
4071da177e4SLinus Torvalds 	struct net_device *new_dev;
4081da177e4SLinus Torvalds 	char name[IFNAMSIZ];
4092ae0bf69SPatrick McHardy 	int err;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	if (VLAN_ID >= VLAN_VID_MASK)
4122ae0bf69SPatrick McHardy 		return -ERANGE;
4131da177e4SLinus Torvalds 
4142ae0bf69SPatrick McHardy 	err = vlan_check_real_dev(real_dev, VLAN_ID);
4152ae0bf69SPatrick McHardy 	if (err < 0)
4162ae0bf69SPatrick McHardy 		return err;
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	/* Gotta set up the fields for the device. */
4191da177e4SLinus Torvalds 	switch (vlan_name_type) {
4201da177e4SLinus Torvalds 	case VLAN_NAME_TYPE_RAW_PLUS_VID:
4211da177e4SLinus Torvalds 		/* name will look like:	 eth1.0005 */
4221da177e4SLinus Torvalds 		snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID);
4231da177e4SLinus Torvalds 		break;
4241da177e4SLinus Torvalds 	case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:
4251da177e4SLinus Torvalds 		/* Put our vlan.VID in the name.
4261da177e4SLinus Torvalds 		 * Name will look like:	 vlan5
4271da177e4SLinus Torvalds 		 */
4281da177e4SLinus Torvalds 		snprintf(name, IFNAMSIZ, "vlan%i", VLAN_ID);
4291da177e4SLinus Torvalds 		break;
4301da177e4SLinus Torvalds 	case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD:
4311da177e4SLinus Torvalds 		/* Put our vlan.VID in the name.
4321da177e4SLinus Torvalds 		 * Name will look like:	 eth0.5
4331da177e4SLinus Torvalds 		 */
4341da177e4SLinus Torvalds 		snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, VLAN_ID);
4351da177e4SLinus Torvalds 		break;
4361da177e4SLinus Torvalds 	case VLAN_NAME_TYPE_PLUS_VID:
4371da177e4SLinus Torvalds 		/* Put our vlan.VID in the name.
4381da177e4SLinus Torvalds 		 * Name will look like:	 vlan0005
4391da177e4SLinus Torvalds 		 */
4401da177e4SLinus Torvalds 	default:
4411da177e4SLinus Torvalds 		snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID);
4423ff50b79SStephen Hemminger 	}
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
4451da177e4SLinus Torvalds 			       vlan_setup);
4465dd8d1e9SArjan van de Ven 
4471da177e4SLinus Torvalds 	if (new_dev == NULL)
4482ae0bf69SPatrick McHardy 		return -ENOBUFS;
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 	/* need 4 bytes for extra VLAN header info,
4511da177e4SLinus Torvalds 	 * hope the underlying device can handle it.
4521da177e4SLinus Torvalds 	 */
4531da177e4SLinus Torvalds 	new_dev->mtu = real_dev->mtu;
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
4561da177e4SLinus Torvalds 	VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
4571da177e4SLinus Torvalds 	VLAN_DEV_INFO(new_dev)->dent = NULL;
458a4bf3af4SPatrick McHardy 	VLAN_DEV_INFO(new_dev)->flags = VLAN_FLAG_REORDER_HDR;
4591da177e4SLinus Torvalds 
46007b5b17eSPatrick McHardy 	new_dev->rtnl_link_ops = &vlan_link_ops;
4612ae0bf69SPatrick McHardy 	err = register_vlan_dev(new_dev);
4622ae0bf69SPatrick McHardy 	if (err < 0)
46342429aaeSPatrick McHardy 		goto out_free_newdev;
4641da177e4SLinus Torvalds 
4652ae0bf69SPatrick McHardy 	return 0;
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds out_free_newdev:
4681da177e4SLinus Torvalds 	free_netdev(new_dev);
4692ae0bf69SPatrick McHardy 	return err;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds 
4728c979c26SPatrick McHardy static void vlan_sync_address(struct net_device *dev,
4738c979c26SPatrick McHardy 			      struct net_device *vlandev)
4748c979c26SPatrick McHardy {
4758c979c26SPatrick McHardy 	struct vlan_dev_info *vlan = VLAN_DEV_INFO(vlandev);
4768c979c26SPatrick McHardy 
4778c979c26SPatrick McHardy 	/* May be called without an actual change */
4788c979c26SPatrick McHardy 	if (!compare_ether_addr(vlan->real_dev_addr, dev->dev_addr))
4798c979c26SPatrick McHardy 		return;
4808c979c26SPatrick McHardy 
4818c979c26SPatrick McHardy 	/* vlan address was different from the old address and is equal to
4828c979c26SPatrick McHardy 	 * the new address */
4838c979c26SPatrick McHardy 	if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
4848c979c26SPatrick McHardy 	    !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
4858c979c26SPatrick McHardy 		dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN);
4868c979c26SPatrick McHardy 
4878c979c26SPatrick McHardy 	/* vlan address was equal to the old address and is different from
4888c979c26SPatrick McHardy 	 * the new address */
4898c979c26SPatrick McHardy 	if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
4908c979c26SPatrick McHardy 	    compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
4918c979c26SPatrick McHardy 		dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN);
4928c979c26SPatrick McHardy 
4938c979c26SPatrick McHardy 	memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
4948c979c26SPatrick McHardy }
4958c979c26SPatrick McHardy 
4961da177e4SLinus Torvalds static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
4971da177e4SLinus Torvalds {
4981da177e4SLinus Torvalds 	struct net_device *dev = ptr;
4991da177e4SLinus Torvalds 	struct vlan_group *grp = __vlan_find_group(dev->ifindex);
5001da177e4SLinus Torvalds 	int i, flgs;
5011da177e4SLinus Torvalds 	struct net_device *vlandev;
5021da177e4SLinus Torvalds 
503e9dc8653SEric W. Biederman 	if (dev->nd_net != &init_net)
504e9dc8653SEric W. Biederman 		return NOTIFY_DONE;
505e9dc8653SEric W. Biederman 
5061da177e4SLinus Torvalds 	if (!grp)
5071da177e4SLinus Torvalds 		goto out;
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds 	/* It is OK that we do not hold the group lock right now,
5101da177e4SLinus Torvalds 	 * as we run under the RTNL lock.
5111da177e4SLinus Torvalds 	 */
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	switch (event) {
5141da177e4SLinus Torvalds 	case NETDEV_CHANGE:
5151da177e4SLinus Torvalds 		/* Propagate real device state to vlan devices */
5161da177e4SLinus Torvalds 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
5175c15bdecSDan Aloni 			vlandev = vlan_group_get_device(grp, i);
5181da177e4SLinus Torvalds 			if (!vlandev)
5191da177e4SLinus Torvalds 				continue;
5201da177e4SLinus Torvalds 
521ddd7bf9fSStefan Rompf 			vlan_transfer_operstate(dev, vlandev);
5221da177e4SLinus Torvalds 		}
5231da177e4SLinus Torvalds 		break;
5241da177e4SLinus Torvalds 
5258c979c26SPatrick McHardy 	case NETDEV_CHANGEADDR:
5268c979c26SPatrick McHardy 		/* Adjust unicast filters on underlying device */
5278c979c26SPatrick McHardy 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
5288c979c26SPatrick McHardy 			vlandev = vlan_group_get_device(grp, i);
5298c979c26SPatrick McHardy 			if (!vlandev)
5308c979c26SPatrick McHardy 				continue;
5318c979c26SPatrick McHardy 
532d932e04aSPatrick McHardy 			flgs = vlandev->flags;
533d932e04aSPatrick McHardy 			if (!(flgs & IFF_UP))
534d932e04aSPatrick McHardy 				continue;
535d932e04aSPatrick McHardy 
5368c979c26SPatrick McHardy 			vlan_sync_address(dev, vlandev);
5378c979c26SPatrick McHardy 		}
5388c979c26SPatrick McHardy 		break;
5398c979c26SPatrick McHardy 
5401da177e4SLinus Torvalds 	case NETDEV_DOWN:
5411da177e4SLinus Torvalds 		/* Put all VLANs for this dev in the down state too.  */
5421da177e4SLinus Torvalds 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
5435c15bdecSDan Aloni 			vlandev = vlan_group_get_device(grp, i);
5441da177e4SLinus Torvalds 			if (!vlandev)
5451da177e4SLinus Torvalds 				continue;
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds 			flgs = vlandev->flags;
5481da177e4SLinus Torvalds 			if (!(flgs & IFF_UP))
5491da177e4SLinus Torvalds 				continue;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 			dev_change_flags(vlandev, flgs & ~IFF_UP);
5521da177e4SLinus Torvalds 		}
5531da177e4SLinus Torvalds 		break;
5541da177e4SLinus Torvalds 
5551da177e4SLinus Torvalds 	case NETDEV_UP:
5561da177e4SLinus Torvalds 		/* Put all VLANs for this dev in the up state too.  */
5571da177e4SLinus Torvalds 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
5585c15bdecSDan Aloni 			vlandev = vlan_group_get_device(grp, i);
5591da177e4SLinus Torvalds 			if (!vlandev)
5601da177e4SLinus Torvalds 				continue;
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 			flgs = vlandev->flags;
5631da177e4SLinus Torvalds 			if (flgs & IFF_UP)
5641da177e4SLinus Torvalds 				continue;
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 			dev_change_flags(vlandev, flgs | IFF_UP);
5671da177e4SLinus Torvalds 		}
5681da177e4SLinus Torvalds 		break;
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds 	case NETDEV_UNREGISTER:
5711da177e4SLinus Torvalds 		/* Delete all VLANs for this dev. */
5721da177e4SLinus Torvalds 		for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
5731da177e4SLinus Torvalds 			int ret;
5741da177e4SLinus Torvalds 
5755c15bdecSDan Aloni 			vlandev = vlan_group_get_device(grp, i);
5761da177e4SLinus Torvalds 			if (!vlandev)
5771da177e4SLinus Torvalds 				continue;
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds 			ret = unregister_vlan_dev(dev,
5801da177e4SLinus Torvalds 						  VLAN_DEV_INFO(vlandev)->vlan_id);
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 			unregister_netdevice(vlandev);
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 			/* Group was destroyed? */
5851da177e4SLinus Torvalds 			if (ret == 1)
5861da177e4SLinus Torvalds 				break;
5871da177e4SLinus Torvalds 		}
5881da177e4SLinus Torvalds 		break;
5893ff50b79SStephen Hemminger 	}
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds out:
5921da177e4SLinus Torvalds 	return NOTIFY_DONE;
5931da177e4SLinus Torvalds }
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds /*
5961da177e4SLinus Torvalds  *	VLAN IOCTL handler.
5971da177e4SLinus Torvalds  *	o execute requested action or pass command to the device driver
5981da177e4SLinus Torvalds  *   arg is really a struct vlan_ioctl_args __user *.
5991da177e4SLinus Torvalds  */
600881d966bSEric W. Biederman static int vlan_ioctl_handler(struct net *net, void __user *arg)
6011da177e4SLinus Torvalds {
602c17d8874SPatrick McHardy 	int err;
6031da177e4SLinus Torvalds 	unsigned short vid = 0;
6041da177e4SLinus Torvalds 	struct vlan_ioctl_args args;
605c17d8874SPatrick McHardy 	struct net_device *dev = NULL;
6061da177e4SLinus Torvalds 
6071da177e4SLinus Torvalds 	if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args)))
6081da177e4SLinus Torvalds 		return -EFAULT;
6091da177e4SLinus Torvalds 
6101da177e4SLinus Torvalds 	/* Null terminate this sucker, just in case. */
6111da177e4SLinus Torvalds 	args.device1[23] = 0;
6121da177e4SLinus Torvalds 	args.u.device2[23] = 0;
6131da177e4SLinus Torvalds 
614c17d8874SPatrick McHardy 	rtnl_lock();
615c17d8874SPatrick McHardy 
6161da177e4SLinus Torvalds 	switch (args.cmd) {
6171da177e4SLinus Torvalds 	case SET_VLAN_INGRESS_PRIORITY_CMD:
618c17d8874SPatrick McHardy 	case SET_VLAN_EGRESS_PRIORITY_CMD:
619c17d8874SPatrick McHardy 	case SET_VLAN_FLAG_CMD:
620c17d8874SPatrick McHardy 	case ADD_VLAN_CMD:
621c17d8874SPatrick McHardy 	case DEL_VLAN_CMD:
622c17d8874SPatrick McHardy 	case GET_VLAN_REALDEV_NAME_CMD:
623c17d8874SPatrick McHardy 	case GET_VLAN_VID_CMD:
624c17d8874SPatrick McHardy 		err = -ENODEV;
625881d966bSEric W. Biederman 		dev = __dev_get_by_name(&init_net, args.device1);
626c17d8874SPatrick McHardy 		if (!dev)
627c17d8874SPatrick McHardy 			goto out;
628c17d8874SPatrick McHardy 
629c17d8874SPatrick McHardy 		err = -EINVAL;
630c17d8874SPatrick McHardy 		if (args.cmd != ADD_VLAN_CMD &&
631c17d8874SPatrick McHardy 		    !(dev->priv_flags & IFF_802_1Q_VLAN))
632c17d8874SPatrick McHardy 			goto out;
633c17d8874SPatrick McHardy 	}
634c17d8874SPatrick McHardy 
635c17d8874SPatrick McHardy 	switch (args.cmd) {
636c17d8874SPatrick McHardy 	case SET_VLAN_INGRESS_PRIORITY_CMD:
637c17d8874SPatrick McHardy 		err = -EPERM;
6381da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
639c17d8874SPatrick McHardy 			break;
640c17d8874SPatrick McHardy 		vlan_dev_set_ingress_priority(dev,
6411da177e4SLinus Torvalds 					      args.u.skb_priority,
6421da177e4SLinus Torvalds 					      args.vlan_qos);
643fffe470aSPatrick McHardy 		err = 0;
6441da177e4SLinus Torvalds 		break;
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	case SET_VLAN_EGRESS_PRIORITY_CMD:
647c17d8874SPatrick McHardy 		err = -EPERM;
6481da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
649c17d8874SPatrick McHardy 			break;
650c17d8874SPatrick McHardy 		err = vlan_dev_set_egress_priority(dev,
6511da177e4SLinus Torvalds 						   args.u.skb_priority,
6521da177e4SLinus Torvalds 						   args.vlan_qos);
6531da177e4SLinus Torvalds 		break;
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 	case SET_VLAN_FLAG_CMD:
656c17d8874SPatrick McHardy 		err = -EPERM;
6571da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
658c17d8874SPatrick McHardy 			break;
659c17d8874SPatrick McHardy 		err = vlan_dev_set_vlan_flag(dev,
6601da177e4SLinus Torvalds 					     args.u.flag,
6611da177e4SLinus Torvalds 					     args.vlan_qos);
6621da177e4SLinus Torvalds 		break;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	case SET_VLAN_NAME_TYPE_CMD:
665c17d8874SPatrick McHardy 		err = -EPERM;
6661da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
667e35de026SPavel Emelyanov 			break;
668c17d8874SPatrick McHardy 		if ((args.u.name_type >= 0) &&
669c17d8874SPatrick McHardy 		    (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
6701da177e4SLinus Torvalds 			vlan_name_type = args.u.name_type;
6711da177e4SLinus Torvalds 			err = 0;
6721da177e4SLinus Torvalds 		} else {
6731da177e4SLinus Torvalds 			err = -EINVAL;
6741da177e4SLinus Torvalds 		}
6751da177e4SLinus Torvalds 		break;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	case ADD_VLAN_CMD:
678c17d8874SPatrick McHardy 		err = -EPERM;
6791da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
680c17d8874SPatrick McHardy 			break;
6812ae0bf69SPatrick McHardy 		err = register_vlan_device(dev, args.u.VID);
6821da177e4SLinus Torvalds 		break;
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds 	case DEL_VLAN_CMD:
685c17d8874SPatrick McHardy 		err = -EPERM;
6861da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN))
687c17d8874SPatrick McHardy 			break;
688c17d8874SPatrick McHardy 		err = unregister_vlan_device(dev);
6891da177e4SLinus Torvalds 		break;
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	case GET_VLAN_REALDEV_NAME_CMD:
6923f5f4346SAndrew Morton 		err = 0;
693c17d8874SPatrick McHardy 		vlan_dev_get_realdev_name(dev, args.u.device2);
6941da177e4SLinus Torvalds 		if (copy_to_user(arg, &args,
6951da177e4SLinus Torvalds 				 sizeof(struct vlan_ioctl_args))) {
6961da177e4SLinus Torvalds 			err = -EFAULT;
6971da177e4SLinus Torvalds 		}
6981da177e4SLinus Torvalds 		break;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	case GET_VLAN_VID_CMD:
7013f5f4346SAndrew Morton 		err = 0;
702c17d8874SPatrick McHardy 		vlan_dev_get_vid(dev, &vid);
7031da177e4SLinus Torvalds 		args.u.VID = vid;
7041da177e4SLinus Torvalds 		if (copy_to_user(arg, &args,
7051da177e4SLinus Torvalds 				 sizeof(struct vlan_ioctl_args))) {
7061da177e4SLinus Torvalds 		      err = -EFAULT;
7071da177e4SLinus Torvalds 		}
7081da177e4SLinus Torvalds 		break;
7091da177e4SLinus Torvalds 
7101da177e4SLinus Torvalds 	default:
711*198a291cSPatrick McHardy 		err = -EOPNOTSUPP;
712c17d8874SPatrick McHardy 		break;
7133ff50b79SStephen Hemminger 	}
7147eb1b3d3SMika Kukkonen out:
715c17d8874SPatrick McHardy 	rtnl_unlock();
7161da177e4SLinus Torvalds 	return err;
7171da177e4SLinus Torvalds }
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds MODULE_LICENSE("GPL");
7201da177e4SLinus Torvalds MODULE_VERSION(DRV_VERSION);
721