diff options
author | Patrick McHardy <kaber@trash.net> | 2013-04-18 22:04:29 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-19 14:45:27 -0400 |
commit | 1fd9b1fc310314911f66d2f14a8e4f0ef37bf47b (patch) | |
tree | 20422146c46fb38a5cdd0d14e671a0793c3389b4 /net/8021q | |
parent | 80d5c3689b886308247da295a228a54df49a44f6 (diff) |
net: vlan: prepare for 802.1ad support
Make the encapsulation protocol value a property of VLAN devices and change
the device lookup functions to take the protocol value into account.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/vlan.c | 87 | ||||
-rw-r--r-- | net/8021q/vlan.h | 54 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 10 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 7 | ||||
-rw-r--r-- | net/8021q/vlan_gvrp.c | 4 | ||||
-rw-r--r-- | net/8021q/vlan_mvrp.c | 4 | ||||
-rw-r--r-- | net/8021q/vlan_netlink.c | 9 |
7 files changed, 98 insertions, 77 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 447c5c93434f..9424f3718ea7 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -51,14 +51,18 @@ const char vlan_version[] = DRV_VERSION; | |||
51 | 51 | ||
52 | /* End of global variables definitions. */ | 52 | /* End of global variables definitions. */ |
53 | 53 | ||
54 | static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id) | 54 | static int vlan_group_prealloc_vid(struct vlan_group *vg, |
55 | __be16 vlan_proto, u16 vlan_id) | ||
55 | { | 56 | { |
56 | struct net_device **array; | 57 | struct net_device **array; |
58 | unsigned int pidx, vidx; | ||
57 | unsigned int size; | 59 | unsigned int size; |
58 | 60 | ||
59 | ASSERT_RTNL(); | 61 | ASSERT_RTNL(); |
60 | 62 | ||
61 | array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | 63 | pidx = vlan_proto_idx(vlan_proto); |
64 | vidx = vlan_id / VLAN_GROUP_ARRAY_PART_LEN; | ||
65 | array = vg->vlan_devices_arrays[pidx][vidx]; | ||
62 | if (array != NULL) | 66 | if (array != NULL) |
63 | return 0; | 67 | return 0; |
64 | 68 | ||
@@ -67,7 +71,7 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id) | |||
67 | if (array == NULL) | 71 | if (array == NULL) |
68 | return -ENOBUFS; | 72 | return -ENOBUFS; |
69 | 73 | ||
70 | vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN] = array; | 74 | vg->vlan_devices_arrays[pidx][vidx] = array; |
71 | return 0; | 75 | return 0; |
72 | } | 76 | } |
73 | 77 | ||
@@ -93,7 +97,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
93 | if (vlan->flags & VLAN_FLAG_GVRP) | 97 | if (vlan->flags & VLAN_FLAG_GVRP) |
94 | vlan_gvrp_request_leave(dev); | 98 | vlan_gvrp_request_leave(dev); |
95 | 99 | ||
96 | vlan_group_set_device(grp, vlan_id, NULL); | 100 | vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL); |
97 | /* Because unregister_netdevice_queue() makes sure at least one rcu | 101 | /* Because unregister_netdevice_queue() makes sure at least one rcu |
98 | * grace period is respected before device freeing, | 102 | * grace period is respected before device freeing, |
99 | * we dont need to call synchronize_net() here. | 103 | * we dont need to call synchronize_net() here. |
@@ -112,13 +116,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
112 | * VLAN is not 0 (leave it there for 802.1p). | 116 | * VLAN is not 0 (leave it there for 802.1p). |
113 | */ | 117 | */ |
114 | if (vlan_id) | 118 | if (vlan_id) |
115 | vlan_vid_del(real_dev, htons(ETH_P_8021Q), vlan_id); | 119 | vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); |
116 | 120 | ||
117 | /* Get rid of the vlan's reference to real_dev */ | 121 | /* Get rid of the vlan's reference to real_dev */ |
118 | dev_put(real_dev); | 122 | dev_put(real_dev); |
119 | } | 123 | } |
120 | 124 | ||
121 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) | 125 | int vlan_check_real_dev(struct net_device *real_dev, |
126 | __be16 protocol, u16 vlan_id) | ||
122 | { | 127 | { |
123 | const char *name = real_dev->name; | 128 | const char *name = real_dev->name; |
124 | 129 | ||
@@ -127,7 +132,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) | |||
127 | return -EOPNOTSUPP; | 132 | return -EOPNOTSUPP; |
128 | } | 133 | } |
129 | 134 | ||
130 | if (vlan_find_dev(real_dev, vlan_id) != NULL) | 135 | if (vlan_find_dev(real_dev, protocol, vlan_id) != NULL) |
131 | return -EEXIST; | 136 | return -EEXIST; |
132 | 137 | ||
133 | return 0; | 138 | return 0; |
@@ -142,7 +147,7 @@ int register_vlan_dev(struct net_device *dev) | |||
142 | struct vlan_group *grp; | 147 | struct vlan_group *grp; |
143 | int err; | 148 | int err; |
144 | 149 | ||
145 | err = vlan_vid_add(real_dev, htons(ETH_P_8021Q), vlan_id); | 150 | err = vlan_vid_add(real_dev, vlan->vlan_proto, vlan_id); |
146 | if (err) | 151 | if (err) |
147 | return err; | 152 | return err; |
148 | 153 | ||
@@ -160,7 +165,7 @@ int register_vlan_dev(struct net_device *dev) | |||
160 | goto out_uninit_gvrp; | 165 | goto out_uninit_gvrp; |
161 | } | 166 | } |
162 | 167 | ||
163 | err = vlan_group_prealloc_vid(grp, vlan_id); | 168 | err = vlan_group_prealloc_vid(grp, vlan->vlan_proto, vlan_id); |
164 | if (err < 0) | 169 | if (err < 0) |
165 | goto out_uninit_mvrp; | 170 | goto out_uninit_mvrp; |
166 | 171 | ||
@@ -181,7 +186,7 @@ int register_vlan_dev(struct net_device *dev) | |||
181 | /* So, got the sucker initialized, now lets place | 186 | /* So, got the sucker initialized, now lets place |
182 | * it into our local structure. | 187 | * it into our local structure. |
183 | */ | 188 | */ |
184 | vlan_group_set_device(grp, vlan_id, dev); | 189 | vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, dev); |
185 | grp->nr_vlan_devs++; | 190 | grp->nr_vlan_devs++; |
186 | 191 | ||
187 | return 0; | 192 | return 0; |
@@ -195,7 +200,7 @@ out_uninit_gvrp: | |||
195 | if (grp->nr_vlan_devs == 0) | 200 | if (grp->nr_vlan_devs == 0) |
196 | vlan_gvrp_uninit_applicant(real_dev); | 201 | vlan_gvrp_uninit_applicant(real_dev); |
197 | out_vid_del: | 202 | out_vid_del: |
198 | vlan_vid_del(real_dev, htons(ETH_P_8021Q), vlan_id); | 203 | vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id); |
199 | return err; | 204 | return err; |
200 | } | 205 | } |
201 | 206 | ||
@@ -213,7 +218,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) | |||
213 | if (vlan_id >= VLAN_VID_MASK) | 218 | if (vlan_id >= VLAN_VID_MASK) |
214 | return -ERANGE; | 219 | return -ERANGE; |
215 | 220 | ||
216 | err = vlan_check_real_dev(real_dev, vlan_id); | 221 | err = vlan_check_real_dev(real_dev, htons(ETH_P_8021Q), vlan_id); |
217 | if (err < 0) | 222 | if (err < 0) |
218 | return err; | 223 | return err; |
219 | 224 | ||
@@ -255,6 +260,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id) | |||
255 | new_dev->mtu = real_dev->mtu; | 260 | new_dev->mtu = real_dev->mtu; |
256 | new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT); | 261 | new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT); |
257 | 262 | ||
263 | vlan_dev_priv(new_dev)->vlan_proto = htons(ETH_P_8021Q); | ||
258 | vlan_dev_priv(new_dev)->vlan_id = vlan_id; | 264 | vlan_dev_priv(new_dev)->vlan_id = vlan_id; |
259 | vlan_dev_priv(new_dev)->real_dev = real_dev; | 265 | vlan_dev_priv(new_dev)->real_dev = real_dev; |
260 | vlan_dev_priv(new_dev)->dent = NULL; | 266 | vlan_dev_priv(new_dev)->dent = NULL; |
@@ -341,6 +347,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
341 | int i, flgs; | 347 | int i, flgs; |
342 | struct net_device *vlandev; | 348 | struct net_device *vlandev; |
343 | struct vlan_dev_priv *vlan; | 349 | struct vlan_dev_priv *vlan; |
350 | bool last = false; | ||
344 | LIST_HEAD(list); | 351 | LIST_HEAD(list); |
345 | 352 | ||
346 | if (is_vlan_dev(dev)) | 353 | if (is_vlan_dev(dev)) |
@@ -365,22 +372,13 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
365 | switch (event) { | 372 | switch (event) { |
366 | case NETDEV_CHANGE: | 373 | case NETDEV_CHANGE: |
367 | /* Propagate real device state to vlan devices */ | 374 | /* Propagate real device state to vlan devices */ |
368 | for (i = 0; i < VLAN_N_VID; i++) { | 375 | vlan_group_for_each_dev(grp, i, vlandev) |
369 | vlandev = vlan_group_get_device(grp, i); | ||
370 | if (!vlandev) | ||
371 | continue; | ||
372 | |||
373 | netif_stacked_transfer_operstate(dev, vlandev); | 376 | netif_stacked_transfer_operstate(dev, vlandev); |
374 | } | ||
375 | break; | 377 | break; |
376 | 378 | ||
377 | case NETDEV_CHANGEADDR: | 379 | case NETDEV_CHANGEADDR: |
378 | /* Adjust unicast filters on underlying device */ | 380 | /* Adjust unicast filters on underlying device */ |
379 | for (i = 0; i < VLAN_N_VID; i++) { | 381 | vlan_group_for_each_dev(grp, i, vlandev) { |
380 | vlandev = vlan_group_get_device(grp, i); | ||
381 | if (!vlandev) | ||
382 | continue; | ||
383 | |||
384 | flgs = vlandev->flags; | 382 | flgs = vlandev->flags; |
385 | if (!(flgs & IFF_UP)) | 383 | if (!(flgs & IFF_UP)) |
386 | continue; | 384 | continue; |
@@ -390,11 +388,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
390 | break; | 388 | break; |
391 | 389 | ||
392 | case NETDEV_CHANGEMTU: | 390 | case NETDEV_CHANGEMTU: |
393 | for (i = 0; i < VLAN_N_VID; i++) { | 391 | vlan_group_for_each_dev(grp, i, vlandev) { |
394 | vlandev = vlan_group_get_device(grp, i); | ||
395 | if (!vlandev) | ||
396 | continue; | ||
397 | |||
398 | if (vlandev->mtu <= dev->mtu) | 392 | if (vlandev->mtu <= dev->mtu) |
399 | continue; | 393 | continue; |
400 | 394 | ||
@@ -404,14 +398,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
404 | 398 | ||
405 | case NETDEV_FEAT_CHANGE: | 399 | case NETDEV_FEAT_CHANGE: |
406 | /* Propagate device features to underlying device */ | 400 | /* Propagate device features to underlying device */ |
407 | for (i = 0; i < VLAN_N_VID; i++) { | 401 | vlan_group_for_each_dev(grp, i, vlandev) |
408 | vlandev = vlan_group_get_device(grp, i); | ||
409 | if (!vlandev) | ||
410 | continue; | ||
411 | |||
412 | vlan_transfer_features(dev, vlandev); | 402 | vlan_transfer_features(dev, vlandev); |
413 | } | ||
414 | |||
415 | break; | 403 | break; |
416 | 404 | ||
417 | case NETDEV_DOWN: | 405 | case NETDEV_DOWN: |
@@ -419,11 +407,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
419 | vlan_vid_del(dev, htons(ETH_P_8021Q), 0); | 407 | vlan_vid_del(dev, htons(ETH_P_8021Q), 0); |
420 | 408 | ||
421 | /* Put all VLANs for this dev in the down state too. */ | 409 | /* Put all VLANs for this dev in the down state too. */ |
422 | for (i = 0; i < VLAN_N_VID; i++) { | 410 | vlan_group_for_each_dev(grp, i, vlandev) { |
423 | vlandev = vlan_group_get_device(grp, i); | ||
424 | if (!vlandev) | ||
425 | continue; | ||
426 | |||
427 | flgs = vlandev->flags; | 411 | flgs = vlandev->flags; |
428 | if (!(flgs & IFF_UP)) | 412 | if (!(flgs & IFF_UP)) |
429 | continue; | 413 | continue; |
@@ -437,11 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
437 | 421 | ||
438 | case NETDEV_UP: | 422 | case NETDEV_UP: |
439 | /* Put all VLANs for this dev in the up state too. */ | 423 | /* Put all VLANs for this dev in the up state too. */ |
440 | for (i = 0; i < VLAN_N_VID; i++) { | 424 | vlan_group_for_each_dev(grp, i, vlandev) { |
441 | vlandev = vlan_group_get_device(grp, i); | ||
442 | if (!vlandev) | ||
443 | continue; | ||
444 | |||
445 | flgs = vlandev->flags; | 425 | flgs = vlandev->flags; |
446 | if (flgs & IFF_UP) | 426 | if (flgs & IFF_UP) |
447 | continue; | 427 | continue; |
@@ -458,17 +438,15 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
458 | if (dev->reg_state != NETREG_UNREGISTERING) | 438 | if (dev->reg_state != NETREG_UNREGISTERING) |
459 | break; | 439 | break; |
460 | 440 | ||
461 | for (i = 0; i < VLAN_N_VID; i++) { | 441 | vlan_group_for_each_dev(grp, i, vlandev) { |
462 | vlandev = vlan_group_get_device(grp, i); | ||
463 | if (!vlandev) | ||
464 | continue; | ||
465 | |||
466 | /* removal of last vid destroys vlan_info, abort | 442 | /* removal of last vid destroys vlan_info, abort |
467 | * afterwards */ | 443 | * afterwards */ |
468 | if (vlan_info->nr_vids == 1) | 444 | if (vlan_info->nr_vids == 1) |
469 | i = VLAN_N_VID; | 445 | last = true; |
470 | 446 | ||
471 | unregister_vlan_dev(vlandev, &list); | 447 | unregister_vlan_dev(vlandev, &list); |
448 | if (last) | ||
449 | break; | ||
472 | } | 450 | } |
473 | unregister_netdevice_many(&list); | 451 | unregister_netdevice_many(&list); |
474 | break; | 452 | break; |
@@ -482,13 +460,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
482 | case NETDEV_NOTIFY_PEERS: | 460 | case NETDEV_NOTIFY_PEERS: |
483 | case NETDEV_BONDING_FAILOVER: | 461 | case NETDEV_BONDING_FAILOVER: |
484 | /* Propagate to vlan devices */ | 462 | /* Propagate to vlan devices */ |
485 | for (i = 0; i < VLAN_N_VID; i++) { | 463 | vlan_group_for_each_dev(grp, i, vlandev) |
486 | vlandev = vlan_group_get_device(grp, i); | ||
487 | if (!vlandev) | ||
488 | continue; | ||
489 | |||
490 | call_netdevice_notifiers(event, vlandev); | 464 | call_netdevice_notifiers(event, vlandev); |
491 | } | ||
492 | break; | 465 | break; |
493 | } | 466 | } |
494 | 467 | ||
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 670f1e8cfc0f..245de9653db0 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h | |||
@@ -49,6 +49,7 @@ struct netpoll; | |||
49 | * @ingress_priority_map: ingress priority mappings | 49 | * @ingress_priority_map: ingress priority mappings |
50 | * @nr_egress_mappings: number of egress priority mappings | 50 | * @nr_egress_mappings: number of egress priority mappings |
51 | * @egress_priority_map: hash of egress priority mappings | 51 | * @egress_priority_map: hash of egress priority mappings |
52 | * @vlan_proto: VLAN encapsulation protocol | ||
52 | * @vlan_id: VLAN identifier | 53 | * @vlan_id: VLAN identifier |
53 | * @flags: device flags | 54 | * @flags: device flags |
54 | * @real_dev: underlying netdevice | 55 | * @real_dev: underlying netdevice |
@@ -62,6 +63,7 @@ struct vlan_dev_priv { | |||
62 | unsigned int nr_egress_mappings; | 63 | unsigned int nr_egress_mappings; |
63 | struct vlan_priority_tci_mapping *egress_priority_map[16]; | 64 | struct vlan_priority_tci_mapping *egress_priority_map[16]; |
64 | 65 | ||
66 | __be16 vlan_proto; | ||
65 | u16 vlan_id; | 67 | u16 vlan_id; |
66 | u16 flags; | 68 | u16 flags; |
67 | 69 | ||
@@ -87,10 +89,16 @@ static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) | |||
87 | #define VLAN_GROUP_ARRAY_SPLIT_PARTS 8 | 89 | #define VLAN_GROUP_ARRAY_SPLIT_PARTS 8 |
88 | #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS) | 90 | #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS) |
89 | 91 | ||
92 | enum vlan_protos { | ||
93 | VLAN_PROTO_8021Q = 0, | ||
94 | VLAN_PROTO_NUM, | ||
95 | }; | ||
96 | |||
90 | struct vlan_group { | 97 | struct vlan_group { |
91 | unsigned int nr_vlan_devs; | 98 | unsigned int nr_vlan_devs; |
92 | struct hlist_node hlist; /* linked list */ | 99 | struct hlist_node hlist; /* linked list */ |
93 | struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; | 100 | struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM] |
101 | [VLAN_GROUP_ARRAY_SPLIT_PARTS]; | ||
94 | }; | 102 | }; |
95 | 103 | ||
96 | struct vlan_info { | 104 | struct vlan_info { |
@@ -103,37 +111,64 @@ struct vlan_info { | |||
103 | struct rcu_head rcu; | 111 | struct rcu_head rcu; |
104 | }; | 112 | }; |
105 | 113 | ||
106 | static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, | 114 | static inline unsigned int vlan_proto_idx(__be16 proto) |
107 | u16 vlan_id) | 115 | { |
116 | switch (proto) { | ||
117 | case __constant_htons(ETH_P_8021Q): | ||
118 | return VLAN_PROTO_8021Q; | ||
119 | default: | ||
120 | BUG(); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg, | ||
125 | unsigned int pidx, | ||
126 | u16 vlan_id) | ||
108 | { | 127 | { |
109 | struct net_device **array; | 128 | struct net_device **array; |
110 | array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | 129 | |
130 | array = vg->vlan_devices_arrays[pidx] | ||
131 | [vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | ||
111 | return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL; | 132 | return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL; |
112 | } | 133 | } |
113 | 134 | ||
135 | static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, | ||
136 | __be16 vlan_proto, | ||
137 | u16 vlan_id) | ||
138 | { | ||
139 | return __vlan_group_get_device(vg, vlan_proto_idx(vlan_proto), vlan_id); | ||
140 | } | ||
141 | |||
114 | static inline void vlan_group_set_device(struct vlan_group *vg, | 142 | static inline void vlan_group_set_device(struct vlan_group *vg, |
115 | u16 vlan_id, | 143 | __be16 vlan_proto, u16 vlan_id, |
116 | struct net_device *dev) | 144 | struct net_device *dev) |
117 | { | 145 | { |
118 | struct net_device **array; | 146 | struct net_device **array; |
119 | if (!vg) | 147 | if (!vg) |
120 | return; | 148 | return; |
121 | array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | 149 | array = vg->vlan_devices_arrays[vlan_proto_idx(vlan_proto)] |
150 | [vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; | ||
122 | array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; | 151 | array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev; |
123 | } | 152 | } |
124 | 153 | ||
125 | /* Must be invoked with rcu_read_lock or with RTNL. */ | 154 | /* Must be invoked with rcu_read_lock or with RTNL. */ |
126 | static inline struct net_device *vlan_find_dev(struct net_device *real_dev, | 155 | static inline struct net_device *vlan_find_dev(struct net_device *real_dev, |
127 | u16 vlan_id) | 156 | __be16 vlan_proto, u16 vlan_id) |
128 | { | 157 | { |
129 | struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info); | 158 | struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info); |
130 | 159 | ||
131 | if (vlan_info) | 160 | if (vlan_info) |
132 | return vlan_group_get_device(&vlan_info->grp, vlan_id); | 161 | return vlan_group_get_device(&vlan_info->grp, |
162 | vlan_proto, vlan_id); | ||
133 | 163 | ||
134 | return NULL; | 164 | return NULL; |
135 | } | 165 | } |
136 | 166 | ||
167 | #define vlan_group_for_each_dev(grp, i, dev) \ | ||
168 | for ((i) = 0; i < VLAN_PROTO_NUM * VLAN_N_VID; i++) \ | ||
169 | if (((dev) = __vlan_group_get_device((grp), (i) / VLAN_N_VID, \ | ||
170 | (i) % VLAN_N_VID))) | ||
171 | |||
137 | /* found in vlan_dev.c */ | 172 | /* found in vlan_dev.c */ |
138 | void vlan_dev_set_ingress_priority(const struct net_device *dev, | 173 | void vlan_dev_set_ingress_priority(const struct net_device *dev, |
139 | u32 skb_prio, u16 vlan_prio); | 174 | u32 skb_prio, u16 vlan_prio); |
@@ -142,7 +177,8 @@ int vlan_dev_set_egress_priority(const struct net_device *dev, | |||
142 | int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask); | 177 | int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask); |
143 | void vlan_dev_get_realdev_name(const struct net_device *dev, char *result); | 178 | void vlan_dev_get_realdev_name(const struct net_device *dev, char *result); |
144 | 179 | ||
145 | int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id); | 180 | int vlan_check_real_dev(struct net_device *real_dev, |
181 | __be16 protocol, u16 vlan_id); | ||
146 | void vlan_setup(struct net_device *dev); | 182 | void vlan_setup(struct net_device *dev); |
147 | int register_vlan_dev(struct net_device *dev); | 183 | int register_vlan_dev(struct net_device *dev); |
148 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head); | 184 | void unregister_vlan_dev(struct net_device *dev, struct list_head *head); |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 04e3b95a0d48..4e4c360353ea 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -12,7 +12,7 @@ bool vlan_do_receive(struct sk_buff **skbp) | |||
12 | struct net_device *vlan_dev; | 12 | struct net_device *vlan_dev; |
13 | struct vlan_pcpu_stats *rx_stats; | 13 | struct vlan_pcpu_stats *rx_stats; |
14 | 14 | ||
15 | vlan_dev = vlan_find_dev(skb->dev, vlan_id); | 15 | vlan_dev = vlan_find_dev(skb->dev, htons(ETH_P_8021Q), vlan_id); |
16 | if (!vlan_dev) | 16 | if (!vlan_dev) |
17 | return false; | 17 | return false; |
18 | 18 | ||
@@ -62,12 +62,13 @@ bool vlan_do_receive(struct sk_buff **skbp) | |||
62 | 62 | ||
63 | /* Must be invoked with rcu_read_lock. */ | 63 | /* Must be invoked with rcu_read_lock. */ |
64 | struct net_device *__vlan_find_dev_deep(struct net_device *dev, | 64 | struct net_device *__vlan_find_dev_deep(struct net_device *dev, |
65 | u16 vlan_id) | 65 | __be16 vlan_proto, u16 vlan_id) |
66 | { | 66 | { |
67 | struct vlan_info *vlan_info = rcu_dereference(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, |
71 | vlan_proto, vlan_id); | ||
71 | } else { | 72 | } else { |
72 | /* | 73 | /* |
73 | * Lower devices of master uppers (bonding, team) do not have | 74 | * Lower devices of master uppers (bonding, team) do not have |
@@ -78,7 +79,8 @@ struct net_device *__vlan_find_dev_deep(struct net_device *dev, | |||
78 | 79 | ||
79 | upper_dev = netdev_master_upper_dev_get_rcu(dev); | 80 | upper_dev = netdev_master_upper_dev_get_rcu(dev); |
80 | if (upper_dev) | 81 | if (upper_dev) |
81 | return __vlan_find_dev_deep(upper_dev, vlan_id); | 82 | return __vlan_find_dev_deep(upper_dev, |
83 | vlan_proto, vlan_id); | ||
82 | } | 84 | } |
83 | 85 | ||
84 | return NULL; | 86 | return NULL; |
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 5c4892a86410..d7457b7e1b95 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c | |||
@@ -99,6 +99,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
99 | const void *daddr, const void *saddr, | 99 | const void *daddr, const void *saddr, |
100 | unsigned int len) | 100 | unsigned int len) |
101 | { | 101 | { |
102 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | ||
102 | struct vlan_hdr *vhdr; | 103 | struct vlan_hdr *vhdr; |
103 | unsigned int vhdrlen = 0; | 104 | unsigned int vhdrlen = 0; |
104 | u16 vlan_tci = 0; | 105 | u16 vlan_tci = 0; |
@@ -120,8 +121,8 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
120 | else | 121 | else |
121 | vhdr->h_vlan_encapsulated_proto = htons(len); | 122 | vhdr->h_vlan_encapsulated_proto = htons(len); |
122 | 123 | ||
123 | skb->protocol = htons(ETH_P_8021Q); | 124 | skb->protocol = vlan->vlan_proto; |
124 | type = ETH_P_8021Q; | 125 | type = ntohs(vlan->vlan_proto); |
125 | vhdrlen = VLAN_HLEN; | 126 | vhdrlen = VLAN_HLEN; |
126 | } | 127 | } |
127 | 128 | ||
@@ -161,7 +162,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb, | |||
161 | * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING | 162 | * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING |
162 | * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs... | 163 | * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs... |
163 | */ | 164 | */ |
164 | if (veth->h_vlan_proto != htons(ETH_P_8021Q) || | 165 | if (veth->h_vlan_proto != vlan->vlan_proto || |
165 | vlan->flags & VLAN_FLAG_REORDER_HDR) { | 166 | vlan->flags & VLAN_FLAG_REORDER_HDR) { |
166 | u16 vlan_tci; | 167 | u16 vlan_tci; |
167 | vlan_tci = vlan->vlan_id; | 168 | vlan_tci = vlan->vlan_id; |
diff --git a/net/8021q/vlan_gvrp.c b/net/8021q/vlan_gvrp.c index 6f9755352760..66a80320b032 100644 --- a/net/8021q/vlan_gvrp.c +++ b/net/8021q/vlan_gvrp.c | |||
@@ -32,6 +32,8 @@ int vlan_gvrp_request_join(const struct net_device *dev) | |||
32 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 32 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
33 | __be16 vlan_id = htons(vlan->vlan_id); | 33 | __be16 vlan_id = htons(vlan->vlan_id); |
34 | 34 | ||
35 | if (vlan->vlan_proto != htons(ETH_P_8021Q)) | ||
36 | return 0; | ||
35 | return garp_request_join(vlan->real_dev, &vlan_gvrp_app, | 37 | return garp_request_join(vlan->real_dev, &vlan_gvrp_app, |
36 | &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); | 38 | &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); |
37 | } | 39 | } |
@@ -41,6 +43,8 @@ void vlan_gvrp_request_leave(const struct net_device *dev) | |||
41 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 43 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
42 | __be16 vlan_id = htons(vlan->vlan_id); | 44 | __be16 vlan_id = htons(vlan->vlan_id); |
43 | 45 | ||
46 | if (vlan->vlan_proto != htons(ETH_P_8021Q)) | ||
47 | return; | ||
44 | garp_request_leave(vlan->real_dev, &vlan_gvrp_app, | 48 | garp_request_leave(vlan->real_dev, &vlan_gvrp_app, |
45 | &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); | 49 | &vlan_id, sizeof(vlan_id), GVRP_ATTR_VID); |
46 | } | 50 | } |
diff --git a/net/8021q/vlan_mvrp.c b/net/8021q/vlan_mvrp.c index d9ec1d5964aa..e0fe091801b0 100644 --- a/net/8021q/vlan_mvrp.c +++ b/net/8021q/vlan_mvrp.c | |||
@@ -38,6 +38,8 @@ int vlan_mvrp_request_join(const struct net_device *dev) | |||
38 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 38 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
39 | __be16 vlan_id = htons(vlan->vlan_id); | 39 | __be16 vlan_id = htons(vlan->vlan_id); |
40 | 40 | ||
41 | if (vlan->vlan_proto != htons(ETH_P_8021Q)) | ||
42 | return 0; | ||
41 | return mrp_request_join(vlan->real_dev, &vlan_mrp_app, | 43 | return mrp_request_join(vlan->real_dev, &vlan_mrp_app, |
42 | &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID); | 44 | &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID); |
43 | } | 45 | } |
@@ -47,6 +49,8 @@ void vlan_mvrp_request_leave(const struct net_device *dev) | |||
47 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 49 | const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
48 | __be16 vlan_id = htons(vlan->vlan_id); | 50 | __be16 vlan_id = htons(vlan->vlan_id); |
49 | 51 | ||
52 | if (vlan->vlan_proto != htons(ETH_P_8021Q)) | ||
53 | return; | ||
50 | mrp_request_leave(vlan->real_dev, &vlan_mrp_app, | 54 | mrp_request_leave(vlan->real_dev, &vlan_mrp_app, |
51 | &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID); | 55 | &vlan_id, sizeof(vlan_id), MVRP_ATTR_VID); |
52 | } | 56 | } |
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 1789658b7cd7..a1a956ab39a5 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c | |||
@@ -118,11 +118,12 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, | |||
118 | if (!real_dev) | 118 | if (!real_dev) |
119 | return -ENODEV; | 119 | return -ENODEV; |
120 | 120 | ||
121 | vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]); | 121 | vlan->vlan_proto = htons(ETH_P_8021Q); |
122 | vlan->real_dev = real_dev; | 122 | vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]); |
123 | vlan->flags = VLAN_FLAG_REORDER_HDR; | 123 | vlan->real_dev = real_dev; |
124 | vlan->flags = VLAN_FLAG_REORDER_HDR; | ||
124 | 125 | ||
125 | err = vlan_check_real_dev(real_dev, vlan->vlan_id); | 126 | err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id); |
126 | if (err < 0) | 127 | if (err < 0) |
127 | return err; | 128 | return err; |
128 | 129 | ||