aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q
diff options
context:
space:
mode:
Diffstat (limited to 'net/8021q')
-rw-r--r--net/8021q/Kconfig11
-rw-r--r--net/8021q/Makefile1
-rw-r--r--net/8021q/vlan.c42
-rw-r--r--net/8021q/vlan.h16
-rw-r--r--net/8021q/vlan_core.c25
-rw-r--r--net/8021q/vlan_dev.c20
-rw-r--r--net/8021q/vlan_mvrp.c72
-rw-r--r--net/8021q/vlan_netlink.c2
-rw-r--r--net/8021q/vlanproc.c2
9 files changed, 161 insertions, 30 deletions
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
index fa073a54963e..8f7517df41a5 100644
--- a/net/8021q/Kconfig
+++ b/net/8021q/Kconfig
@@ -27,3 +27,14 @@ config VLAN_8021Q_GVRP
27 automatic propagation of registered VLANs to switches. 27 automatic propagation of registered VLANs to switches.
28 28
29 If unsure, say N. 29 If unsure, say N.
30
31config VLAN_8021Q_MVRP
32 bool "MVRP (Multiple VLAN Registration Protocol) support"
33 depends on VLAN_8021Q
34 select MRP
35 help
36 Select this to enable MVRP end-system support. MVRP is used for
37 automatic propagation of registered VLANs to switches; it
38 supersedes GVRP and is not backwards-compatible.
39
40 If unsure, say N.
diff --git a/net/8021q/Makefile b/net/8021q/Makefile
index 9f4f174ead1c..7bc8db08d7ef 100644
--- a/net/8021q/Makefile
+++ b/net/8021q/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_VLAN_8021Q) += 8021q.o
6 6
78021q-y := vlan.o vlan_dev.o vlan_netlink.o 78021q-y := vlan.o vlan_dev.o vlan_netlink.o
88021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o 88021q-$(CONFIG_VLAN_8021Q_GVRP) += vlan_gvrp.o
98021q-$(CONFIG_VLAN_8021Q_MVRP) += vlan_mvrp.o
98021q-$(CONFIG_PROC_FS) += vlanproc.o 108021q-$(CONFIG_PROC_FS) += vlanproc.o
10 11
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index a292e8050ef2..a18714469bf7 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -95,6 +95,8 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
95 95
96 grp->nr_vlan_devs--; 96 grp->nr_vlan_devs--;
97 97
98 if (vlan->flags & VLAN_FLAG_MVRP)
99 vlan_mvrp_request_leave(dev);
98 if (vlan->flags & VLAN_FLAG_GVRP) 100 if (vlan->flags & VLAN_FLAG_GVRP)
99 vlan_gvrp_request_leave(dev); 101 vlan_gvrp_request_leave(dev);
100 102
@@ -105,8 +107,12 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
105 */ 107 */
106 unregister_netdevice_queue(dev, head); 108 unregister_netdevice_queue(dev, head);
107 109
108 if (grp->nr_vlan_devs == 0) 110 netdev_upper_dev_unlink(real_dev, dev);
111
112 if (grp->nr_vlan_devs == 0) {
113 vlan_mvrp_uninit_applicant(real_dev);
109 vlan_gvrp_uninit_applicant(real_dev); 114 vlan_gvrp_uninit_applicant(real_dev);
115 }
110 116
111 /* Get rid of the vlan's reference to real_dev */ 117 /* Get rid of the vlan's reference to real_dev */
112 dev_put(real_dev); 118 dev_put(real_dev);
@@ -115,19 +121,12 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
115int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) 121int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
116{ 122{
117 const char *name = real_dev->name; 123 const char *name = real_dev->name;
118 const struct net_device_ops *ops = real_dev->netdev_ops;
119 124
120 if (real_dev->features & NETIF_F_VLAN_CHALLENGED) { 125 if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
121 pr_info("VLANs not supported on %s\n", name); 126 pr_info("VLANs not supported on %s\n", name);
122 return -EOPNOTSUPP; 127 return -EOPNOTSUPP;
123 } 128 }
124 129
125 if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
126 (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) {
127 pr_info("Device %s has buggy VLAN hw accel\n", name);
128 return -EOPNOTSUPP;
129 }
130
131 if (vlan_find_dev(real_dev, vlan_id) != NULL) 130 if (vlan_find_dev(real_dev, vlan_id) != NULL)
132 return -EEXIST; 131 return -EEXIST;
133 132
@@ -156,15 +155,22 @@ int register_vlan_dev(struct net_device *dev)
156 err = vlan_gvrp_init_applicant(real_dev); 155 err = vlan_gvrp_init_applicant(real_dev);
157 if (err < 0) 156 if (err < 0)
158 goto out_vid_del; 157 goto out_vid_del;
158 err = vlan_mvrp_init_applicant(real_dev);
159 if (err < 0)
160 goto out_uninit_gvrp;
159 } 161 }
160 162
161 err = vlan_group_prealloc_vid(grp, vlan_id); 163 err = vlan_group_prealloc_vid(grp, vlan_id);
162 if (err < 0) 164 if (err < 0)
163 goto out_uninit_applicant; 165 goto out_uninit_mvrp;
166
167 err = netdev_upper_dev_link(real_dev, dev);
168 if (err)
169 goto out_uninit_mvrp;
164 170
165 err = register_netdevice(dev); 171 err = register_netdevice(dev);
166 if (err < 0) 172 if (err < 0)
167 goto out_uninit_applicant; 173 goto out_upper_dev_unlink;
168 174
169 /* Account for reference in struct vlan_dev_priv */ 175 /* Account for reference in struct vlan_dev_priv */
170 dev_hold(real_dev); 176 dev_hold(real_dev);
@@ -180,7 +186,12 @@ int register_vlan_dev(struct net_device *dev)
180 186
181 return 0; 187 return 0;
182 188
183out_uninit_applicant: 189out_upper_dev_unlink:
190 netdev_upper_dev_unlink(real_dev, dev);
191out_uninit_mvrp:
192 if (grp->nr_vlan_devs == 0)
193 vlan_mvrp_uninit_applicant(real_dev);
194out_uninit_gvrp:
184 if (grp->nr_vlan_devs == 0) 195 if (grp->nr_vlan_devs == 0)
185 vlan_gvrp_uninit_applicant(real_dev); 196 vlan_gvrp_uninit_applicant(real_dev);
186out_vid_del: 197out_vid_del:
@@ -654,13 +665,19 @@ static int __init vlan_proto_init(void)
654 if (err < 0) 665 if (err < 0)
655 goto err3; 666 goto err3;
656 667
657 err = vlan_netlink_init(); 668 err = vlan_mvrp_init();
658 if (err < 0) 669 if (err < 0)
659 goto err4; 670 goto err4;
660 671
672 err = vlan_netlink_init();
673 if (err < 0)
674 goto err5;
675
661 vlan_ioctl_set(vlan_ioctl_handler); 676 vlan_ioctl_set(vlan_ioctl_handler);
662 return 0; 677 return 0;
663 678
679err5:
680 vlan_mvrp_uninit();
664err4: 681err4:
665 vlan_gvrp_uninit(); 682 vlan_gvrp_uninit();
666err3: 683err3:
@@ -681,6 +698,7 @@ static void __exit vlan_cleanup_module(void)
681 unregister_pernet_subsys(&vlan_net_ops); 698 unregister_pernet_subsys(&vlan_net_ops);
682 rcu_barrier(); /* Wait for completion of call_rcu()'s */ 699 rcu_barrier(); /* Wait for completion of call_rcu()'s */
683 700
701 vlan_mvrp_uninit();
684 vlan_gvrp_uninit(); 702 vlan_gvrp_uninit();
685} 703}
686 704
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index a4886d94c40c..670f1e8cfc0f 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -171,6 +171,22 @@ static inline int vlan_gvrp_init(void) { return 0; }
171static inline void vlan_gvrp_uninit(void) {} 171static inline void vlan_gvrp_uninit(void) {}
172#endif 172#endif
173 173
174#ifdef CONFIG_VLAN_8021Q_MVRP
175extern int vlan_mvrp_request_join(const struct net_device *dev);
176extern void vlan_mvrp_request_leave(const struct net_device *dev);
177extern int vlan_mvrp_init_applicant(struct net_device *dev);
178extern void vlan_mvrp_uninit_applicant(struct net_device *dev);
179extern int vlan_mvrp_init(void);
180extern void vlan_mvrp_uninit(void);
181#else
182static inline int vlan_mvrp_request_join(const struct net_device *dev) { return 0; }
183static inline void vlan_mvrp_request_leave(const struct net_device *dev) {}
184static inline int vlan_mvrp_init_applicant(struct net_device *dev) { return 0; }
185static inline void vlan_mvrp_uninit_applicant(struct net_device *dev) {}
186static inline int vlan_mvrp_init(void) { return 0; }
187static inline void vlan_mvrp_uninit(void) {}
188#endif
189
174extern const char vlan_fullname[]; 190extern const char vlan_fullname[];
175extern const char vlan_version[]; 191extern const char vlan_version[];
176extern int vlan_netlink_init(void); 192extern int vlan_netlink_init(void);
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 65e06abe023f..f3b6f515eba6 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -60,21 +60,25 @@ bool vlan_do_receive(struct sk_buff **skbp)
60 return true; 60 return true;
61} 61}
62 62
63/* Must be invoked with rcu_read_lock or with RTNL. */ 63/* Must be invoked with rcu_read_lock. */
64struct net_device *__vlan_find_dev_deep(struct net_device *real_dev, 64struct net_device *__vlan_find_dev_deep(struct net_device *dev,
65 u16 vlan_id) 65 u16 vlan_id)
66{ 66{
67 struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info); 67 struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info);
68 68
69 if (vlan_info) { 69 if (vlan_info) {
70 return vlan_group_get_device(&vlan_info->grp, vlan_id); 70 return vlan_group_get_device(&vlan_info->grp, vlan_id);
71 } else { 71 } else {
72 /* 72 /*
73 * Bonding slaves do not have grp assigned to themselves. 73 * Lower devices of master uppers (bonding, team) do not have
74 * Grp is assigned to bonding master instead. 74 * grp assigned to themselves. Grp is assigned to upper device
75 * instead.
75 */ 76 */
76 if (netif_is_bond_slave(real_dev)) 77 struct net_device *upper_dev;
77 return __vlan_find_dev_deep(real_dev->master, vlan_id); 78
79 upper_dev = netdev_master_upper_dev_get_rcu(dev);
80 if (upper_dev)
81 return __vlan_find_dev_deep(upper_dev, vlan_id);
78 } 82 }
79 83
80 return NULL; 84 return NULL;
@@ -140,6 +144,7 @@ err_free:
140 kfree_skb(skb); 144 kfree_skb(skb);
141 return NULL; 145 return NULL;
142} 146}
147EXPORT_SYMBOL(vlan_untag);
143 148
144 149
145/* 150/*
@@ -220,8 +225,7 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid,
220 if (!vid_info) 225 if (!vid_info)
221 return -ENOMEM; 226 return -ENOMEM;
222 227
223 if ((dev->features & NETIF_F_HW_VLAN_FILTER) && 228 if (dev->features & NETIF_F_HW_VLAN_FILTER) {
224 ops->ndo_vlan_rx_add_vid) {
225 err = ops->ndo_vlan_rx_add_vid(dev, vid); 229 err = ops->ndo_vlan_rx_add_vid(dev, vid);
226 if (err) { 230 if (err) {
227 kfree(vid_info); 231 kfree(vid_info);
@@ -278,8 +282,7 @@ static void __vlan_vid_del(struct vlan_info *vlan_info,
278 unsigned short vid = vid_info->vid; 282 unsigned short vid = vid_info->vid;
279 int err; 283 int err;
280 284
281 if ((dev->features & NETIF_F_HW_VLAN_FILTER) && 285 if (dev->features & NETIF_F_HW_VLAN_FILTER) {
282 ops->ndo_vlan_rx_kill_vid) {
283 err = ops->ndo_vlan_rx_kill_vid(dev, vid); 286 err = ops->ndo_vlan_rx_kill_vid(dev, vid);
284 if (err) { 287 if (err) {
285 pr_warn("failed to kill vid %d for device %s\n", 288 pr_warn("failed to kill vid %d for device %s\n",
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 4a6d31a082b9..19cf81bf9f69 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -261,7 +261,7 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
261 u32 old_flags = vlan->flags; 261 u32 old_flags = vlan->flags;
262 262
263 if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | 263 if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
264 VLAN_FLAG_LOOSE_BINDING)) 264 VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
265 return -EINVAL; 265 return -EINVAL;
266 266
267 vlan->flags = (old_flags & ~mask) | (flags & mask); 267 vlan->flags = (old_flags & ~mask) | (flags & mask);
@@ -272,6 +272,13 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
272 else 272 else
273 vlan_gvrp_request_leave(dev); 273 vlan_gvrp_request_leave(dev);
274 } 274 }
275
276 if (netif_running(dev) && (vlan->flags ^ old_flags) & VLAN_FLAG_MVRP) {
277 if (vlan->flags & VLAN_FLAG_MVRP)
278 vlan_mvrp_request_join(dev);
279 else
280 vlan_mvrp_request_leave(dev);
281 }
275 return 0; 282 return 0;
276} 283}
277 284
@@ -312,6 +319,9 @@ static int vlan_dev_open(struct net_device *dev)
312 if (vlan->flags & VLAN_FLAG_GVRP) 319 if (vlan->flags & VLAN_FLAG_GVRP)
313 vlan_gvrp_request_join(dev); 320 vlan_gvrp_request_join(dev);
314 321
322 if (vlan->flags & VLAN_FLAG_MVRP)
323 vlan_mvrp_request_join(dev);
324
315 if (netif_carrier_ok(real_dev)) 325 if (netif_carrier_ok(real_dev))
316 netif_carrier_on(dev); 326 netif_carrier_on(dev);
317 return 0; 327 return 0;
@@ -640,9 +650,9 @@ static int vlan_ethtool_get_settings(struct net_device *dev,
640static void vlan_ethtool_get_drvinfo(struct net_device *dev, 650static void vlan_ethtool_get_drvinfo(struct net_device *dev,
641 struct ethtool_drvinfo *info) 651 struct ethtool_drvinfo *info)
642{ 652{
643 strcpy(info->driver, vlan_fullname); 653 strlcpy(info->driver, vlan_fullname, sizeof(info->driver));
644 strcpy(info->version, vlan_version); 654 strlcpy(info->version, vlan_version, sizeof(info->version));
645 strcpy(info->fw_version, "N/A"); 655 strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
646} 656}
647 657
648static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 658static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
@@ -723,7 +733,7 @@ static void vlan_dev_netpoll_cleanup(struct net_device *dev)
723 733
724 vlan->netpoll = NULL; 734 vlan->netpoll = NULL;
725 735
726 __netpoll_free_rcu(netpoll); 736 __netpoll_free_async(netpoll);
727} 737}
728#endif /* CONFIG_NET_POLL_CONTROLLER */ 738#endif /* CONFIG_NET_POLL_CONTROLLER */
729 739
diff --git a/net/8021q/vlan_mvrp.c b/net/8021q/vlan_mvrp.c
new file mode 100644
index 000000000000..d9ec1d5964aa
--- /dev/null
+++ b/net/8021q/vlan_mvrp.c
@@ -0,0 +1,72 @@
1/*
2 * IEEE 802.1Q Multiple VLAN Registration Protocol (MVRP)
3 *
4 * Copyright (c) 2012 Massachusetts Institute of Technology
5 *
6 * Adapted from code in net/8021q/vlan_gvrp.c
7 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 */
13#include <linux/types.h>
14#include <linux/if_ether.h>
15#include <linux/if_vlan.h>
16#include <net/mrp.h>
17#include "vlan.h"
18
19#define MRP_MVRP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21 }
20
21enum mvrp_attributes {
22 MVRP_ATTR_INVALID,
23 MVRP_ATTR_VID,
24 __MVRP_ATTR_MAX
25};
26#define MVRP_ATTR_MAX (__MVRP_ATTR_MAX - 1)
27
28static struct mrp_application vlan_mrp_app __read_mostly = {
29 .type = MRP_APPLICATION_MVRP,
30 .maxattr = MVRP_ATTR_MAX,
31 .pkttype.type = htons(ETH_P_MVRP),
32 .group_address = MRP_MVRP_ADDRESS,
33 .version = 0,
34};
35
36int vlan_mvrp_request_join(const struct net_device *dev)
37{
38 const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
39 __be16 vlan_id = htons(vlan->vlan_id);
40
41 return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
42 &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
43}
44
45void vlan_mvrp_request_leave(const struct net_device *dev)
46{
47 const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
48 __be16 vlan_id = htons(vlan->vlan_id);
49
50 mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
51 &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
52}
53
54int vlan_mvrp_init_applicant(struct net_device *dev)
55{
56 return mrp_init_applicant(dev, &vlan_mrp_app);
57}
58
59void vlan_mvrp_uninit_applicant(struct net_device *dev)
60{
61 mrp_uninit_applicant(dev, &vlan_mrp_app);
62}
63
64int __init vlan_mvrp_init(void)
65{
66 return mrp_register_application(&vlan_mrp_app);
67}
68
69void vlan_mvrp_uninit(void)
70{
71 mrp_unregister_application(&vlan_mrp_app);
72}
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 708c80ea1874..1789658b7cd7 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -62,7 +62,7 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
62 flags = nla_data(data[IFLA_VLAN_FLAGS]); 62 flags = nla_data(data[IFLA_VLAN_FLAGS]);
63 if ((flags->flags & flags->mask) & 63 if ((flags->flags & flags->mask) &
64 ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP | 64 ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
65 VLAN_FLAG_LOOSE_BINDING)) 65 VLAN_FLAG_LOOSE_BINDING | VLAN_FLAG_MVRP))
66 return -EINVAL; 66 return -EINVAL;
67 } 67 }
68 68
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index 4de77ea5fa37..dc526ec965e4 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -131,7 +131,7 @@ void vlan_proc_cleanup(struct net *net)
131 remove_proc_entry(name_conf, vn->proc_vlan_dir); 131 remove_proc_entry(name_conf, vn->proc_vlan_dir);
132 132
133 if (vn->proc_vlan_dir) 133 if (vn->proc_vlan_dir)
134 proc_net_remove(net, name_root); 134 remove_proc_entry(name_root, net->proc_net);
135 135
136 /* Dynamically added entries should be cleaned up as their vlan_device 136 /* Dynamically added entries should be cleaned up as their vlan_device
137 * is removed, so we should not have to take care of it here... 137 * is removed, so we should not have to take care of it here...