Blame view
net/8021q/vlan.c
18.7 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 |
/* * INET 802.1Q VLAN * Ethernet-type device handling. * * Authors: Ben Greear <greearb@candelatech.com> |
ad712087f [VLAN]: Update li... |
6 |
* Please send support related email to: netdev@vger.kernel.org |
1da177e4c Linux-2.6.12-rc2 |
7 |
* VLAN Home Page: http://www.candelatech.com/~greear/vlan.html |
122952fc2 [NET] 8021Q: Fix ... |
8 |
* |
1da177e4c Linux-2.6.12-rc2 |
9 10 11 12 13 14 15 16 17 18 19 |
* 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. */ |
afab2d299 net: 8021q: Add p... |
20 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
4fc268d24 [PATCH] capable/c... |
21 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 24 |
#include <linux/module.h> #include <linux/netdevice.h> #include <linux/skbuff.h> |
5a0e3ad6a include cleanup: ... |
25 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
26 |
#include <linux/init.h> |
82524746c rcu: split list.h... |
27 |
#include <linux/rculist.h> |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 |
#include <net/p8022.h> #include <net/arp.h> #include <linux/rtnetlink.h> #include <linux/notifier.h> |
61362766d vlan: remove unne... |
32 |
#include <net/rtnetlink.h> |
e9dc86534 [NET]: Make devic... |
33 |
#include <net/net_namespace.h> |
d9ed0f0e2 [VLAN]: Introduce... |
34 |
#include <net/netns/generic.h> |
61362766d vlan: remove unne... |
35 |
#include <asm/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
36 37 38 39 40 41 42 43 |
#include <linux/if_vlan.h> #include "vlan.h" #include "vlanproc.h" #define DRV_VERSION "1.8" /* Global VLAN variables */ |
f99189b18 netns: net_identi... |
44 |
int vlan_net_id __read_mostly; |
d9ed0f0e2 [VLAN]: Introduce... |
45 |
|
b30200616 vlan: propogate e... |
46 47 |
const char vlan_fullname[] = "802.1Q VLAN Support"; const char vlan_version[] = DRV_VERSION; |
1da177e4c Linux-2.6.12-rc2 |
48 |
|
1da177e4c Linux-2.6.12-rc2 |
49 |
/* End of global variables definitions. */ |
1fd9b1fc3 net: vlan: prepar... |
50 51 |
static int vlan_group_prealloc_vid(struct vlan_group *vg, __be16 vlan_proto, u16 vlan_id) |
67727184f [VLAN]: Reduce me... |
52 53 |
{ struct net_device **array; |
1fd9b1fc3 net: vlan: prepar... |
54 |
unsigned int pidx, vidx; |
67727184f [VLAN]: Reduce me... |
55 56 57 |
unsigned int size; ASSERT_RTNL(); |
1fd9b1fc3 net: vlan: prepar... |
58 59 60 |
pidx = vlan_proto_idx(vlan_proto); vidx = vlan_id / VLAN_GROUP_ARRAY_PART_LEN; array = vg->vlan_devices_arrays[pidx][vidx]; |
67727184f [VLAN]: Reduce me... |
61 62 63 64 65 66 67 |
if (array != NULL) return 0; size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN; array = kzalloc(size, GFP_KERNEL); if (array == NULL) return -ENOBUFS; |
1fd9b1fc3 net: vlan: prepar... |
68 |
vg->vlan_devices_arrays[pidx][vidx] = array; |
67727184f [VLAN]: Reduce me... |
69 |
return 0; |
42429aaee [VLAN]: Move vlan... |
70 |
} |
23289a37e net: add a list_h... |
71 |
void unregister_vlan_dev(struct net_device *dev, struct list_head *head) |
1da177e4c Linux-2.6.12-rc2 |
72 |
{ |
7da82c06d vlan: rename vlan... |
73 |
struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
af3015170 [VLAN]: Simplify ... |
74 |
struct net_device *real_dev = vlan->real_dev; |
5b9ea6e02 vlan: introduce v... |
75 |
struct vlan_info *vlan_info; |
1da177e4c Linux-2.6.12-rc2 |
76 |
struct vlan_group *grp; |
9bb8582ef vlan: TCI related... |
77 |
u16 vlan_id = vlan->vlan_id; |
1da177e4c Linux-2.6.12-rc2 |
78 79 |
ASSERT_RTNL(); |
acc5efbcd [VLAN]: Clean up ... |
80 |
|
5b9ea6e02 vlan: introduce v... |
81 82 83 84 |
vlan_info = rtnl_dereference(real_dev->vlan_info); BUG_ON(!vlan_info); grp = &vlan_info->grp; |
acc5efbcd [VLAN]: Clean up ... |
85 |
|
5b9ea6e02 vlan: introduce v... |
86 |
grp->nr_vlan_devs--; |
acc5efbcd [VLAN]: Clean up ... |
87 |
|
86fbe9bb5 net/8021q: Implem... |
88 89 |
if (vlan->flags & VLAN_FLAG_MVRP) vlan_mvrp_request_leave(dev); |
55aee10de vlan: fix GVRP at... |
90 91 |
if (vlan->flags & VLAN_FLAG_GVRP) vlan_gvrp_request_leave(dev); |
1fd9b1fc3 net: vlan: prepar... |
92 |
vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL); |
47701a36a vlan: unlink the ... |
93 94 |
netdev_upper_dev_unlink(real_dev, dev); |
48752e1b1 vlan: remove one ... |
95 96 97 98 |
/* Because unregister_netdevice_queue() makes sure at least one rcu * grace period is respected before device freeing, * we dont need to call synchronize_net() here. */ |
23289a37e net: add a list_h... |
99 |
unregister_netdevice_queue(dev, head); |
ce305002e vlan: Move device... |
100 |
|
86fbe9bb5 net/8021q: Implem... |
101 102 |
if (grp->nr_vlan_devs == 0) { vlan_mvrp_uninit_applicant(real_dev); |
70c03b49b vlan: Add GVRP su... |
103 |
vlan_gvrp_uninit_applicant(real_dev); |
86fbe9bb5 net/8021q: Implem... |
104 |
} |
70c03b49b vlan: Add GVRP su... |
105 |
|
4a7df340e 8021q: fix a pote... |
106 107 108 109 110 |
/* Take it out of our own structures, but be sure to interlock with * HW accelerating devices or SW vlan input packet processing if * VLAN is not 0 (leave it there for 802.1p). */ if (vlan_id) |
1fd9b1fc3 net: vlan: prepar... |
111 |
vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); |
4a7df340e 8021q: fix a pote... |
112 |
|
af3015170 [VLAN]: Simplify ... |
113 114 |
/* Get rid of the vlan's reference to real_dev */ dev_put(real_dev); |
1da177e4c Linux-2.6.12-rc2 |
115 |
} |
1fd9b1fc3 net: vlan: prepar... |
116 117 |
int vlan_check_real_dev(struct net_device *real_dev, __be16 protocol, u16 vlan_id) |
1da177e4c Linux-2.6.12-rc2 |
118 |
{ |
656299f70 vlan: convert to ... |
119 |
const char *name = real_dev->name; |
40f98e1af [VLAN]: Clean up ... |
120 |
|
1da177e4c Linux-2.6.12-rc2 |
121 |
if (real_dev->features & NETIF_F_VLAN_CHALLENGED) { |
afab2d299 net: 8021q: Add p... |
122 123 |
pr_info("VLANs not supported on %s ", name); |
c1d3ee992 [VLAN]: Split up ... |
124 |
return -EOPNOTSUPP; |
1da177e4c Linux-2.6.12-rc2 |
125 |
} |
1fd9b1fc3 net: vlan: prepar... |
126 |
if (vlan_find_dev(real_dev, protocol, vlan_id) != NULL) |
c1d3ee992 [VLAN]: Split up ... |
127 |
return -EEXIST; |
1da177e4c Linux-2.6.12-rc2 |
128 |
|
c1d3ee992 [VLAN]: Split up ... |
129 130 |
return 0; } |
07b5b17e1 [VLAN]: Use rtnl_... |
131 |
int register_vlan_dev(struct net_device *dev) |
e89fe42cd [VLAN]: Move devi... |
132 |
{ |
7da82c06d vlan: rename vlan... |
133 |
struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
e89fe42cd [VLAN]: Move devi... |
134 |
struct net_device *real_dev = vlan->real_dev; |
9bb8582ef vlan: TCI related... |
135 |
u16 vlan_id = vlan->vlan_id; |
5b9ea6e02 vlan: introduce v... |
136 137 |
struct vlan_info *vlan_info; struct vlan_group *grp; |
e89fe42cd [VLAN]: Move devi... |
138 |
int err; |
1fd9b1fc3 net: vlan: prepar... |
139 |
err = vlan_vid_add(real_dev, vlan->vlan_proto, vlan_id); |
5b9ea6e02 vlan: introduce v... |
140 141 142 143 144 145 146 147 148 |
if (err) return err; vlan_info = rtnl_dereference(real_dev->vlan_info); /* vlan_info should be there now. vlan_vid_add took care of it */ BUG_ON(!vlan_info); grp = &vlan_info->grp; if (grp->nr_vlan_devs == 0) { |
70c03b49b vlan: Add GVRP su... |
149 150 |
err = vlan_gvrp_init_applicant(real_dev); if (err < 0) |
5b9ea6e02 vlan: introduce v... |
151 |
goto out_vid_del; |
86fbe9bb5 net/8021q: Implem... |
152 153 154 |
err = vlan_mvrp_init_applicant(real_dev); if (err < 0) goto out_uninit_gvrp; |
e89fe42cd [VLAN]: Move devi... |
155 |
} |
1fd9b1fc3 net: vlan: prepar... |
156 |
err = vlan_group_prealloc_vid(grp, vlan->vlan_proto, vlan_id); |
67727184f [VLAN]: Reduce me... |
157 |
if (err < 0) |
86fbe9bb5 net/8021q: Implem... |
158 |
goto out_uninit_mvrp; |
67727184f [VLAN]: Reduce me... |
159 |
|
952fcfd08 net: remove type_... |
160 |
vlan->nest_level = dev_get_nest_level(real_dev) + 1; |
e89fe42cd [VLAN]: Move devi... |
161 162 |
err = register_netdevice(dev); if (err < 0) |
5df27e6cb vlan: link the up... |
163 164 165 166 167 |
goto out_uninit_mvrp; err = netdev_upper_dev_link(real_dev, dev); if (err) goto out_unregister_netdev; |
e89fe42cd [VLAN]: Move devi... |
168 |
|
7da82c06d vlan: rename vlan... |
169 |
/* Account for reference in struct vlan_dev_priv */ |
e89fe42cd [VLAN]: Move devi... |
170 |
dev_hold(real_dev); |
fc4a74896 netdevice: provid... |
171 |
netif_stacked_transfer_operstate(real_dev, dev); |
e89fe42cd [VLAN]: Move devi... |
172 173 174 175 176 |
linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */ /* So, got the sucker initialized, now lets place * it into our local structure. */ |
1fd9b1fc3 net: vlan: prepar... |
177 |
vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, dev); |
5b9ea6e02 vlan: introduce v... |
178 |
grp->nr_vlan_devs++; |
e89fe42cd [VLAN]: Move devi... |
179 |
|
e89fe42cd [VLAN]: Move devi... |
180 |
return 0; |
5df27e6cb vlan: link the up... |
181 182 |
out_unregister_netdev: unregister_netdevice(dev); |
86fbe9bb5 net/8021q: Implem... |
183 184 185 186 |
out_uninit_mvrp: if (grp->nr_vlan_devs == 0) vlan_mvrp_uninit_applicant(real_dev); out_uninit_gvrp: |
5b9ea6e02 vlan: introduce v... |
187 |
if (grp->nr_vlan_devs == 0) |
70c03b49b vlan: Add GVRP su... |
188 |
vlan_gvrp_uninit_applicant(real_dev); |
5b9ea6e02 vlan: introduce v... |
189 |
out_vid_del: |
1fd9b1fc3 net: vlan: prepar... |
190 |
vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); |
e89fe42cd [VLAN]: Move devi... |
191 192 |
return err; } |
c1d3ee992 [VLAN]: Split up ... |
193 |
/* Attach a VLAN device to a mac address (ie Ethernet Card). |
2ae0bf69b [VLAN]: Return pr... |
194 |
* Returns 0 if the device was created or a negative error code otherwise. |
c1d3ee992 [VLAN]: Split up ... |
195 |
*/ |
9bb8582ef vlan: TCI related... |
196 |
static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) |
c1d3ee992 [VLAN]: Split up ... |
197 |
{ |
c1d3ee992 [VLAN]: Split up ... |
198 |
struct net_device *new_dev; |
0c0667a85 vlan: cleanup the... |
199 |
struct vlan_dev_priv *vlan; |
7a17a2f79 [VLAN]: Make the ... |
200 201 |
struct net *net = dev_net(real_dev); struct vlan_net *vn = net_generic(net, vlan_net_id); |
c1d3ee992 [VLAN]: Split up ... |
202 |
char name[IFNAMSIZ]; |
2ae0bf69b [VLAN]: Return pr... |
203 |
int err; |
c1d3ee992 [VLAN]: Split up ... |
204 |
|
9bb8582ef vlan: TCI related... |
205 |
if (vlan_id >= VLAN_VID_MASK) |
2ae0bf69b [VLAN]: Return pr... |
206 |
return -ERANGE; |
c1d3ee992 [VLAN]: Split up ... |
207 |
|
1fd9b1fc3 net: vlan: prepar... |
208 |
err = vlan_check_real_dev(real_dev, htons(ETH_P_8021Q), vlan_id); |
2ae0bf69b [VLAN]: Return pr... |
209 210 |
if (err < 0) return err; |
c1d3ee992 [VLAN]: Split up ... |
211 |
|
1da177e4c Linux-2.6.12-rc2 |
212 |
/* Gotta set up the fields for the device. */ |
7a17a2f79 [VLAN]: Make the ... |
213 |
switch (vn->name_type) { |
1da177e4c Linux-2.6.12-rc2 |
214 215 |
case VLAN_NAME_TYPE_RAW_PLUS_VID: /* name will look like: eth1.0005 */ |
9bb8582ef vlan: TCI related... |
216 |
snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, vlan_id); |
1da177e4c Linux-2.6.12-rc2 |
217 218 219 220 221 |
break; case VLAN_NAME_TYPE_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: vlan5 */ |
9bb8582ef vlan: TCI related... |
222 |
snprintf(name, IFNAMSIZ, "vlan%i", vlan_id); |
1da177e4c Linux-2.6.12-rc2 |
223 224 225 226 227 |
break; case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: eth0.5 */ |
9bb8582ef vlan: TCI related... |
228 |
snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, vlan_id); |
1da177e4c Linux-2.6.12-rc2 |
229 230 231 232 233 234 |
break; case VLAN_NAME_TYPE_PLUS_VID: /* Put our vlan.VID in the name. * Name will look like: vlan0005 */ default: |
9bb8582ef vlan: TCI related... |
235 |
snprintf(name, IFNAMSIZ, "vlan%.4i", vlan_id); |
3ff50b799 [NET]: cleanup ex... |
236 |
} |
122952fc2 [NET] 8021Q: Fix ... |
237 |
|
c835a6773 net: set name_ass... |
238 239 |
new_dev = alloc_netdev(sizeof(struct vlan_dev_priv), name, NET_NAME_UNKNOWN, vlan_setup); |
5dd8d1e9e [PATCH] lockdep: ... |
240 |
|
1da177e4c Linux-2.6.12-rc2 |
241 |
if (new_dev == NULL) |
2ae0bf69b [VLAN]: Return pr... |
242 |
return -ENOBUFS; |
1da177e4c Linux-2.6.12-rc2 |
243 |
|
65d292a2e [VLAN]: Allow vla... |
244 |
dev_net_set(new_dev, net); |
1da177e4c Linux-2.6.12-rc2 |
245 246 247 248 |
/* need 4 bytes for extra VLAN header info, * hope the underlying device can handle it. */ new_dev->mtu = real_dev->mtu; |
0c0667a85 vlan: cleanup the... |
249 250 251 252 253 254 |
vlan = vlan_dev_priv(new_dev); vlan->vlan_proto = htons(ETH_P_8021Q); vlan->vlan_id = vlan_id; vlan->real_dev = real_dev; vlan->dent = NULL; vlan->flags = VLAN_FLAG_REORDER_HDR; |
1da177e4c Linux-2.6.12-rc2 |
255 |
|
07b5b17e1 [VLAN]: Use rtnl_... |
256 |
new_dev->rtnl_link_ops = &vlan_link_ops; |
2ae0bf69b [VLAN]: Return pr... |
257 258 |
err = register_vlan_dev(new_dev); if (err < 0) |
e89fe42cd [VLAN]: Move devi... |
259 |
goto out_free_newdev; |
1da177e4c Linux-2.6.12-rc2 |
260 |
|
2ae0bf69b [VLAN]: Return pr... |
261 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
262 |
|
1da177e4c Linux-2.6.12-rc2 |
263 264 |
out_free_newdev: free_netdev(new_dev); |
2ae0bf69b [VLAN]: Return pr... |
265 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
266 |
} |
8c979c26a [VLAN]: Fix MAC a... |
267 268 269 |
static void vlan_sync_address(struct net_device *dev, struct net_device *vlandev) { |
7da82c06d vlan: rename vlan... |
270 |
struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); |
8c979c26a [VLAN]: Fix MAC a... |
271 272 |
/* May be called without an actual change */ |
53a2b3a18 8021q: Convert co... |
273 |
if (ether_addr_equal(vlan->real_dev_addr, dev->dev_addr)) |
8c979c26a [VLAN]: Fix MAC a... |
274 |
return; |
308453aa9 vlan: Propagate M... |
275 276 277 |
/* vlan continues to inherit address of lower device */ if (vlan_dev_inherit_address(vlandev, dev)) goto out; |
8c979c26a [VLAN]: Fix MAC a... |
278 279 |
/* vlan address was different from the old address and is equal to * the new address */ |
53a2b3a18 8021q: Convert co... |
280 281 |
if (!ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) && ether_addr_equal(vlandev->dev_addr, dev->dev_addr)) |
a748ee242 net: move address... |
282 |
dev_uc_del(dev, vlandev->dev_addr); |
8c979c26a [VLAN]: Fix MAC a... |
283 284 285 |
/* vlan address was equal to the old address and is different from * the new address */ |
53a2b3a18 8021q: Convert co... |
286 287 |
if (ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) && !ether_addr_equal(vlandev->dev_addr, dev->dev_addr)) |
a748ee242 net: move address... |
288 |
dev_uc_add(dev, vlandev->dev_addr); |
8c979c26a [VLAN]: Fix MAC a... |
289 |
|
308453aa9 vlan: Propagate M... |
290 |
out: |
07fc67bef 8021q: Use ether_... |
291 |
ether_addr_copy(vlan->real_dev_addr, dev->dev_addr); |
8c979c26a [VLAN]: Fix MAC a... |
292 |
} |
5fb135705 [VLAN]: Propagate... |
293 294 295 |
static void vlan_transfer_features(struct net_device *dev, struct net_device *vlandev) { |
fc0d48b8f vlan: Set hard_he... |
296 |
struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); |
1ae4be22f vlan: vlan device... |
297 |
vlandev->gso_max_size = dev->gso_max_size; |
f6773c5e9 vlan: propagate g... |
298 |
vlandev->gso_max_segs = dev->gso_max_segs; |
029f5fc31 8021q: set hard_h... |
299 |
|
fc0d48b8f vlan: Set hard_he... |
300 |
if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto)) |
029f5fc31 8021q: set hard_h... |
301 302 303 |
vlandev->hard_header_len = dev->hard_header_len; else vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN; |
f4d5392e5 vlan: use IS_ENAB... |
304 |
#if IS_ENABLED(CONFIG_FCOE) |
b85daa532 vlan: adds fcoe o... |
305 306 |
vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; #endif |
8a0427bb6 vlan: convert VLA... |
307 308 |
netdev_update_features(vlandev); |
5fb135705 [VLAN]: Propagate... |
309 |
} |
9c5ff24f9 vlan: fail early ... |
310 |
static int __vlan_device_event(struct net_device *dev, unsigned long event) |
802fb176d [VLAN]: Proc entr... |
311 |
{ |
9c5ff24f9 vlan: fail early ... |
312 |
int err = 0; |
802fb176d [VLAN]: Proc entr... |
313 314 315 |
switch (event) { case NETDEV_CHANGENAME: vlan_proc_rem_dev(dev); |
9c5ff24f9 vlan: fail early ... |
316 |
err = vlan_proc_add_dev(dev); |
802fb176d [VLAN]: Proc entr... |
317 |
break; |
30688a9a3 [VLAN]: Handle vl... |
318 |
case NETDEV_REGISTER: |
9c5ff24f9 vlan: fail early ... |
319 |
err = vlan_proc_add_dev(dev); |
30688a9a3 [VLAN]: Handle vl... |
320 321 322 323 |
break; case NETDEV_UNREGISTER: vlan_proc_rem_dev(dev); break; |
802fb176d [VLAN]: Proc entr... |
324 |
} |
9c5ff24f9 vlan: fail early ... |
325 326 |
return err; |
802fb176d [VLAN]: Proc entr... |
327 |
} |
2029cc2c8 [VLAN]: checkpatc... |
328 329 |
static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) |
1da177e4c Linux-2.6.12-rc2 |
330 |
{ |
351638e7d net: pass info st... |
331 |
struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
802fb176d [VLAN]: Proc entr... |
332 |
struct vlan_group *grp; |
5b9ea6e02 vlan: introduce v... |
333 |
struct vlan_info *vlan_info; |
1da177e4c Linux-2.6.12-rc2 |
334 335 |
int i, flgs; struct net_device *vlandev; |
7da82c06d vlan: rename vlan... |
336 |
struct vlan_dev_priv *vlan; |
1fd9b1fc3 net: vlan: prepar... |
337 |
bool last = false; |
29906f6a4 vlan: cleanup mul... |
338 |
LIST_HEAD(list); |
1da177e4c Linux-2.6.12-rc2 |
339 |
|
9c5ff24f9 vlan: fail early ... |
340 341 342 343 344 345 |
if (is_vlan_dev(dev)) { int err = __vlan_device_event(dev, event); if (err) return notifier_from_errno(err); } |
802fb176d [VLAN]: Proc entr... |
346 |
|
ad1afb003 vlan_dev: VLAN 0 ... |
347 |
if ((event == NETDEV_UP) && |
f646968f8 net: vlan: rename... |
348 |
(dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { |
afab2d299 net: 8021q: Add p... |
349 350 |
pr_info("adding VLAN 0 to HW filter on device %s ", |
ad1afb003 vlan_dev: VLAN 0 ... |
351 |
dev->name); |
80d5c3689 net: vlan: prepar... |
352 |
vlan_vid_add(dev, htons(ETH_P_8021Q), 0); |
ad1afb003 vlan_dev: VLAN 0 ... |
353 |
} |
5b9ea6e02 vlan: introduce v... |
354 355 |
vlan_info = rtnl_dereference(dev->vlan_info); if (!vlan_info) |
1da177e4c Linux-2.6.12-rc2 |
356 |
goto out; |
5b9ea6e02 vlan: introduce v... |
357 |
grp = &vlan_info->grp; |
1da177e4c Linux-2.6.12-rc2 |
358 359 360 361 362 363 364 365 |
/* 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 */ |
1fd9b1fc3 net: vlan: prepar... |
366 |
vlan_group_for_each_dev(grp, i, vlandev) |
fc4a74896 netdevice: provid... |
367 |
netif_stacked_transfer_operstate(dev, vlandev); |
1da177e4c Linux-2.6.12-rc2 |
368 |
break; |
8c979c26a [VLAN]: Fix MAC a... |
369 370 |
case NETDEV_CHANGEADDR: /* Adjust unicast filters on underlying device */ |
1fd9b1fc3 net: vlan: prepar... |
371 |
vlan_group_for_each_dev(grp, i, vlandev) { |
d932e04a5 [VLAN]: Don't syn... |
372 373 374 |
flgs = vlandev->flags; if (!(flgs & IFF_UP)) continue; |
8c979c26a [VLAN]: Fix MAC a... |
375 376 |
vlan_sync_address(dev, vlandev); } |
2e477c9bd vlan: Propagate p... |
377 378 379 |
break; case NETDEV_CHANGEMTU: |
1fd9b1fc3 net: vlan: prepar... |
380 |
vlan_group_for_each_dev(grp, i, vlandev) { |
2e477c9bd vlan: Propagate p... |
381 382 383 384 385 |
if (vlandev->mtu <= dev->mtu) continue; dev_set_mtu(vlandev, dev->mtu); } |
8c979c26a [VLAN]: Fix MAC a... |
386 |
break; |
5fb135705 [VLAN]: Propagate... |
387 388 |
case NETDEV_FEAT_CHANGE: /* Propagate device features to underlying device */ |
1fd9b1fc3 net: vlan: prepar... |
389 |
vlan_group_for_each_dev(grp, i, vlandev) |
5fb135705 [VLAN]: Propagate... |
390 |
vlan_transfer_features(dev, vlandev); |
5fb135705 [VLAN]: Propagate... |
391 |
break; |
99c4a26a1 net: Fix high ove... |
392 393 394 |
case NETDEV_DOWN: { struct net_device *tmp; LIST_HEAD(close_list); |
f646968f8 net: vlan: rename... |
395 |
if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) |
80d5c3689 net: vlan: prepar... |
396 |
vlan_vid_del(dev, htons(ETH_P_8021Q), 0); |
efc73f4bb net: Fix memory l... |
397 |
|
1da177e4c Linux-2.6.12-rc2 |
398 |
/* Put all VLANs for this dev in the down state too. */ |
1fd9b1fc3 net: vlan: prepar... |
399 |
vlan_group_for_each_dev(grp, i, vlandev) { |
1da177e4c Linux-2.6.12-rc2 |
400 401 402 |
flgs = vlandev->flags; if (!(flgs & IFF_UP)) continue; |
7da82c06d vlan: rename vlan... |
403 |
vlan = vlan_dev_priv(vlandev); |
5e7565930 vlan: support "lo... |
404 |
if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
99c4a26a1 net: Fix high ove... |
405 406 407 408 409 410 |
list_add(&vlandev->close_list, &close_list); } dev_close_many(&close_list, false); list_for_each_entry_safe(vlandev, tmp, &close_list, close_list) { |
fc4a74896 netdevice: provid... |
411 |
netif_stacked_transfer_operstate(dev, vlandev); |
99c4a26a1 net: Fix high ove... |
412 |
list_del_init(&vlandev->close_list); |
1da177e4c Linux-2.6.12-rc2 |
413 |
} |
99c4a26a1 net: Fix high ove... |
414 |
list_del(&close_list); |
1da177e4c Linux-2.6.12-rc2 |
415 |
break; |
99c4a26a1 net: Fix high ove... |
416 |
} |
1da177e4c Linux-2.6.12-rc2 |
417 418 |
case NETDEV_UP: /* Put all VLANs for this dev in the up state too. */ |
1fd9b1fc3 net: vlan: prepar... |
419 |
vlan_group_for_each_dev(grp, i, vlandev) { |
be346ffaa vlan: Correctly p... |
420 |
flgs = dev_get_flags(vlandev); |
1da177e4c Linux-2.6.12-rc2 |
421 422 |
if (flgs & IFF_UP) continue; |
7da82c06d vlan: rename vlan... |
423 |
vlan = vlan_dev_priv(vlandev); |
5e7565930 vlan: support "lo... |
424 425 |
if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) dev_change_flags(vlandev, flgs | IFF_UP); |
fc4a74896 netdevice: provid... |
426 |
netif_stacked_transfer_operstate(dev, vlandev); |
1da177e4c Linux-2.6.12-rc2 |
427 428 |
} break; |
122952fc2 [NET] 8021Q: Fix ... |
429 |
|
1da177e4c Linux-2.6.12-rc2 |
430 |
case NETDEV_UNREGISTER: |
3b27e1055 netns: keep vlan ... |
431 432 433 |
/* twiddle thumbs on netns device moves */ if (dev->reg_state != NETREG_UNREGISTERING) break; |
1fd9b1fc3 net: vlan: prepar... |
434 |
vlan_group_for_each_dev(grp, i, vlandev) { |
5b9ea6e02 vlan: introduce v... |
435 |
/* removal of last vid destroys vlan_info, abort |
29906f6a4 vlan: cleanup mul... |
436 |
* afterwards */ |
5b9ea6e02 vlan: introduce v... |
437 |
if (vlan_info->nr_vids == 1) |
1fd9b1fc3 net: vlan: prepar... |
438 |
last = true; |
29906f6a4 vlan: cleanup mul... |
439 440 |
unregister_vlan_dev(vlandev, &list); |
1fd9b1fc3 net: vlan: prepar... |
441 442 |
if (last) break; |
29906f6a4 vlan: cleanup mul... |
443 444 |
} unregister_netdevice_many(&list); |
1da177e4c Linux-2.6.12-rc2 |
445 |
break; |
1c01fe14a net: forbid under... |
446 447 448 |
case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ |
18c22a03a vlan: allow to ch... |
449 450 451 |
if (vlan_uses_dev(dev)) return NOTIFY_BAD; break; |
99606477a vlan: Propagate N... |
452 453 |
case NETDEV_NOTIFY_PEERS: |
7c8994323 bonding, ipv4, ip... |
454 |
case NETDEV_BONDING_FAILOVER: |
4aa5dee4d net: convert rese... |
455 |
case NETDEV_RESEND_IGMP: |
99606477a vlan: Propagate N... |
456 |
/* Propagate to vlan devices */ |
1fd9b1fc3 net: vlan: prepar... |
457 |
vlan_group_for_each_dev(grp, i, vlandev) |
7c8994323 bonding, ipv4, ip... |
458 |
call_netdevice_notifiers(event, vlandev); |
99606477a vlan: Propagate N... |
459 |
break; |
3ff50b799 [NET]: cleanup ex... |
460 |
} |
1da177e4c Linux-2.6.12-rc2 |
461 462 463 464 |
out: return NOTIFY_DONE; } |
69ab4b7d6 [VLAN]: Clean up ... |
465 466 467 |
static struct notifier_block vlan_notifier_block __read_mostly = { .notifier_call = vlan_device_event, }; |
1da177e4c Linux-2.6.12-rc2 |
468 469 470 471 472 |
/* * VLAN IOCTL handler. * o execute requested action or pass command to the device driver * arg is really a struct vlan_ioctl_args __user *. */ |
881d966b4 [NET]: Make the d... |
473 |
static int vlan_ioctl_handler(struct net *net, void __user *arg) |
1da177e4c Linux-2.6.12-rc2 |
474 |
{ |
c17d8874f [VLAN]: Convert n... |
475 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
476 |
struct vlan_ioctl_args args; |
c17d8874f [VLAN]: Convert n... |
477 |
struct net_device *dev = NULL; |
1da177e4c Linux-2.6.12-rc2 |
478 479 480 481 482 483 484 |
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; |
c17d8874f [VLAN]: Convert n... |
485 |
rtnl_lock(); |
1da177e4c Linux-2.6.12-rc2 |
486 487 |
switch (args.cmd) { case SET_VLAN_INGRESS_PRIORITY_CMD: |
c17d8874f [VLAN]: Convert n... |
488 489 490 491 492 493 494 |
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; |
65d292a2e [VLAN]: Allow vla... |
495 |
dev = __dev_get_by_name(net, args.device1); |
c17d8874f [VLAN]: Convert n... |
496 497 498 499 |
if (!dev) goto out; err = -EINVAL; |
26a25239d vlan: Use is_vlan... |
500 |
if (args.cmd != ADD_VLAN_CMD && !is_vlan_dev(dev)) |
c17d8874f [VLAN]: Convert n... |
501 502 503 504 505 506 |
goto out; } switch (args.cmd) { case SET_VLAN_INGRESS_PRIORITY_CMD: err = -EPERM; |
276996fda net: Allow the us... |
507 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
c17d8874f [VLAN]: Convert n... |
508 509 510 511 |
break; vlan_dev_set_ingress_priority(dev, args.u.skb_priority, args.vlan_qos); |
fffe470a8 [VLAN]: Fix SET_V... |
512 |
err = 0; |
1da177e4c Linux-2.6.12-rc2 |
513 514 515 |
break; case SET_VLAN_EGRESS_PRIORITY_CMD: |
c17d8874f [VLAN]: Convert n... |
516 |
err = -EPERM; |
276996fda net: Allow the us... |
517 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
c17d8874f [VLAN]: Convert n... |
518 519 |
break; err = vlan_dev_set_egress_priority(dev, |
1da177e4c Linux-2.6.12-rc2 |
520 521 522 523 524 |
args.u.skb_priority, args.vlan_qos); break; case SET_VLAN_FLAG_CMD: |
c17d8874f [VLAN]: Convert n... |
525 |
err = -EPERM; |
276996fda net: Allow the us... |
526 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
c17d8874f [VLAN]: Convert n... |
527 |
break; |
b3ce0325f vlan: Change vlan... |
528 529 530 |
err = vlan_dev_change_flags(dev, args.vlan_qos ? args.u.flag : 0, args.u.flag); |
1da177e4c Linux-2.6.12-rc2 |
531 532 533 |
break; case SET_VLAN_NAME_TYPE_CMD: |
c17d8874f [VLAN]: Convert n... |
534 |
err = -EPERM; |
276996fda net: Allow the us... |
535 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
e35de0261 [VLAN]: Lost rtnl... |
536 |
break; |
c17d8874f [VLAN]: Convert n... |
537 538 |
if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { |
7a17a2f79 [VLAN]: Make the ... |
539 540 541 542 |
struct vlan_net *vn; vn = net_generic(net, vlan_net_id); vn->name_type = args.u.name_type; |
1da177e4c Linux-2.6.12-rc2 |
543 544 545 546 547 548 549 |
err = 0; } else { err = -EINVAL; } break; case ADD_VLAN_CMD: |
c17d8874f [VLAN]: Convert n... |
550 |
err = -EPERM; |
276996fda net: Allow the us... |
551 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
c17d8874f [VLAN]: Convert n... |
552 |
break; |
2ae0bf69b [VLAN]: Return pr... |
553 |
err = register_vlan_device(dev, args.u.VID); |
1da177e4c Linux-2.6.12-rc2 |
554 555 556 |
break; case DEL_VLAN_CMD: |
c17d8874f [VLAN]: Convert n... |
557 |
err = -EPERM; |
276996fda net: Allow the us... |
558 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
c17d8874f [VLAN]: Convert n... |
559 |
break; |
23289a37e net: add a list_h... |
560 |
unregister_vlan_dev(dev, NULL); |
af3015170 [VLAN]: Simplify ... |
561 |
err = 0; |
1da177e4c Linux-2.6.12-rc2 |
562 |
break; |
1da177e4c Linux-2.6.12-rc2 |
563 |
case GET_VLAN_REALDEV_NAME_CMD: |
3f5f4346b [8021Q]: vlan_ioc... |
564 |
err = 0; |
c17d8874f [VLAN]: Convert n... |
565 |
vlan_dev_get_realdev_name(dev, args.u.device2); |
1da177e4c Linux-2.6.12-rc2 |
566 |
if (copy_to_user(arg, &args, |
2029cc2c8 [VLAN]: checkpatc... |
567 |
sizeof(struct vlan_ioctl_args))) |
1da177e4c Linux-2.6.12-rc2 |
568 |
err = -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
569 570 571 |
break; case GET_VLAN_VID_CMD: |
3f5f4346b [8021Q]: vlan_ioc... |
572 |
err = 0; |
22d1ba74b vlan: move struct... |
573 |
args.u.VID = vlan_dev_vlan_id(dev); |
1da177e4c Linux-2.6.12-rc2 |
574 |
if (copy_to_user(arg, &args, |
2029cc2c8 [VLAN]: checkpatc... |
575 |
sizeof(struct vlan_ioctl_args))) |
122952fc2 [NET] 8021Q: Fix ... |
576 |
err = -EFAULT; |
1da177e4c Linux-2.6.12-rc2 |
577 578 579 |
break; default: |
198a291ce [VLAN]: Remove no... |
580 |
err = -EOPNOTSUPP; |
c17d8874f [VLAN]: Convert n... |
581 |
break; |
3ff50b799 [NET]: cleanup ex... |
582 |
} |
7eb1b3d37 [VLAN]: Add two m... |
583 |
out: |
c17d8874f [VLAN]: Convert n... |
584 |
rtnl_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
585 586 |
return err; } |
66e5133f1 vlan: Add GRO sup... |
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
static struct sk_buff **vlan_gro_receive(struct sk_buff **head, struct sk_buff *skb) { struct sk_buff *p, **pp = NULL; struct vlan_hdr *vhdr; unsigned int hlen, off_vlan; const struct packet_offload *ptype; __be16 type; int flush = 1; off_vlan = skb_gro_offset(skb); hlen = off_vlan + sizeof(*vhdr); vhdr = skb_gro_header_fast(skb, off_vlan); if (skb_gro_header_hard(skb, hlen)) { vhdr = skb_gro_header_slow(skb, hlen, off_vlan); if (unlikely(!vhdr)) goto out; } type = vhdr->h_vlan_encapsulated_proto; rcu_read_lock(); ptype = gro_find_receive_by_type(type); if (!ptype) goto out_unlock; flush = 0; for (p = *head; p; p = p->next) { struct vlan_hdr *vhdr2; if (!NAPI_GRO_CB(p)->same_flow) continue; vhdr2 = (struct vlan_hdr *)(p->data + off_vlan); if (compare_vlan_header(vhdr, vhdr2)) NAPI_GRO_CB(p)->same_flow = 0; } skb_gro_pull(skb, sizeof(*vhdr)); skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr)); |
fcd91dd44 net: add recursio... |
628 |
pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); |
66e5133f1 vlan: Add GRO sup... |
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
out_unlock: rcu_read_unlock(); out: NAPI_GRO_CB(skb)->flush |= flush; return pp; } static int vlan_gro_complete(struct sk_buff *skb, int nhoff) { struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + nhoff); __be16 type = vhdr->h_vlan_encapsulated_proto; struct packet_offload *ptype; int err = -ENOENT; rcu_read_lock(); ptype = gro_find_complete_by_type(type); if (ptype) err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(*vhdr)); rcu_read_unlock(); return err; } static struct packet_offload vlan_packet_offloads[] __read_mostly = { { .type = cpu_to_be16(ETH_P_8021Q), .priority = 10, .callbacks = { .gro_receive = vlan_gro_receive, .gro_complete = vlan_gro_complete, }, }, { .type = cpu_to_be16(ETH_P_8021AD), .priority = 10, .callbacks = { .gro_receive = vlan_gro_receive, .gro_complete = vlan_gro_complete, }, }, }; |
2c8c1e729 net: spread __net... |
672 |
static int __net_init vlan_init_net(struct net *net) |
d9ed0f0e2 [VLAN]: Introduce... |
673 |
{ |
946d1a929 net: Simplify vla... |
674 |
struct vlan_net *vn = net_generic(net, vlan_net_id); |
d9ed0f0e2 [VLAN]: Introduce... |
675 |
int err; |
d9ed0f0e2 [VLAN]: Introduce... |
676 |
|
7a17a2f79 [VLAN]: Make the ... |
677 |
vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; |
cd1c70143 [VLAN]: Add a net... |
678 |
err = vlan_proc_init(net); |
cd1c70143 [VLAN]: Add a net... |
679 |
|
d9ed0f0e2 [VLAN]: Introduce... |
680 681 |
return err; } |
2c8c1e729 net: spread __net... |
682 |
static void __net_exit vlan_exit_net(struct net *net) |
d9ed0f0e2 [VLAN]: Introduce... |
683 |
{ |
cd1c70143 [VLAN]: Add a net... |
684 |
vlan_proc_cleanup(net); |
d9ed0f0e2 [VLAN]: Introduce... |
685 686 687 688 689 |
} static struct pernet_operations vlan_net_ops = { .init = vlan_init_net, .exit = vlan_exit_net, |
946d1a929 net: Simplify vla... |
690 691 |
.id = &vlan_net_id, .size = sizeof(struct vlan_net), |
d9ed0f0e2 [VLAN]: Introduce... |
692 |
}; |
69ab4b7d6 [VLAN]: Clean up ... |
693 694 695 |
static int __init vlan_proto_init(void) { int err; |
66e5133f1 vlan: Add GRO sup... |
696 |
unsigned int i; |
69ab4b7d6 [VLAN]: Clean up ... |
697 |
|
da7c06c4a net:8021q:vlan.c ... |
698 699 |
pr_info("%s v%s ", vlan_fullname, vlan_version); |
69ab4b7d6 [VLAN]: Clean up ... |
700 |
|
91e2ff352 net: Teach vlans ... |
701 |
err = register_pernet_subsys(&vlan_net_ops); |
d9ed0f0e2 [VLAN]: Introduce... |
702 703 |
if (err < 0) goto err0; |
69ab4b7d6 [VLAN]: Clean up ... |
704 705 706 |
err = register_netdevice_notifier(&vlan_notifier_block); if (err < 0) goto err2; |
70c03b49b vlan: Add GVRP su... |
707 |
err = vlan_gvrp_init(); |
69ab4b7d6 [VLAN]: Clean up ... |
708 709 |
if (err < 0) goto err3; |
86fbe9bb5 net/8021q: Implem... |
710 |
err = vlan_mvrp_init(); |
70c03b49b vlan: Add GVRP su... |
711 712 |
if (err < 0) goto err4; |
86fbe9bb5 net/8021q: Implem... |
713 714 715 |
err = vlan_netlink_init(); if (err < 0) goto err5; |
66e5133f1 vlan: Add GRO sup... |
716 717 |
for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) dev_add_offload(&vlan_packet_offloads[i]); |
69ab4b7d6 [VLAN]: Clean up ... |
718 719 |
vlan_ioctl_set(vlan_ioctl_handler); return 0; |
86fbe9bb5 net/8021q: Implem... |
720 721 |
err5: vlan_mvrp_uninit(); |
70c03b49b vlan: Add GVRP su... |
722 723 |
err4: vlan_gvrp_uninit(); |
69ab4b7d6 [VLAN]: Clean up ... |
724 725 726 |
err3: unregister_netdevice_notifier(&vlan_notifier_block); err2: |
91e2ff352 net: Teach vlans ... |
727 |
unregister_pernet_subsys(&vlan_net_ops); |
d9ed0f0e2 [VLAN]: Introduce... |
728 |
err0: |
69ab4b7d6 [VLAN]: Clean up ... |
729 730 731 732 733 |
return err; } static void __exit vlan_cleanup_module(void) { |
66e5133f1 vlan: Add GRO sup... |
734 |
unsigned int i; |
69ab4b7d6 [VLAN]: Clean up ... |
735 |
vlan_ioctl_set(NULL); |
66e5133f1 vlan: Add GRO sup... |
736 737 738 |
for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) dev_remove_offload(&vlan_packet_offloads[i]); |
69ab4b7d6 [VLAN]: Clean up ... |
739 740 741 |
vlan_netlink_fini(); unregister_netdevice_notifier(&vlan_notifier_block); |
91e2ff352 net: Teach vlans ... |
742 |
unregister_pernet_subsys(&vlan_net_ops); |
6e327c11a 8021q: Vlan drive... |
743 |
rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
70c03b49b vlan: Add GVRP su... |
744 |
|
86fbe9bb5 net/8021q: Implem... |
745 |
vlan_mvrp_uninit(); |
70c03b49b vlan: Add GVRP su... |
746 |
vlan_gvrp_uninit(); |
69ab4b7d6 [VLAN]: Clean up ... |
747 748 749 750 |
} module_init(vlan_proto_init); module_exit(vlan_cleanup_module); |
1da177e4c Linux-2.6.12-rc2 |
751 752 |
MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); |