diff options
author | Patrick McHardy <kaber@trash.net> | 2013-04-18 22:04:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-19 14:45:27 -0400 |
commit | 80d5c3689b886308247da295a228a54df49a44f6 (patch) | |
tree | ce7b1e6898c3f9fea945e67fd06b125dfcc61fe7 /net/8021q | |
parent | f646968f8f7c624587de729115d802372b9063dd (diff) |
net: vlan: prepare for 802.1ad VLAN filtering offload
Change the rx_{add,kill}_vid callbacks to take a protocol argument in
preparation of 802.1ad support. The protocol argument used so far is
always htons(ETH_P_8021Q).
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 | 10 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 47 |
2 files changed, 31 insertions, 26 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index d913feed0757..447c5c93434f 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -112,7 +112,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head) | |||
112 | * VLAN is not 0 (leave it there for 802.1p). | 112 | * VLAN is not 0 (leave it there for 802.1p). |
113 | */ | 113 | */ |
114 | if (vlan_id) | 114 | if (vlan_id) |
115 | vlan_vid_del(real_dev, vlan_id); | 115 | vlan_vid_del(real_dev, htons(ETH_P_8021Q), vlan_id); |
116 | 116 | ||
117 | /* Get rid of the vlan's reference to real_dev */ | 117 | /* Get rid of the vlan's reference to real_dev */ |
118 | dev_put(real_dev); | 118 | dev_put(real_dev); |
@@ -142,7 +142,7 @@ int register_vlan_dev(struct net_device *dev) | |||
142 | struct vlan_group *grp; | 142 | struct vlan_group *grp; |
143 | int err; | 143 | int err; |
144 | 144 | ||
145 | err = vlan_vid_add(real_dev, vlan_id); | 145 | err = vlan_vid_add(real_dev, htons(ETH_P_8021Q), vlan_id); |
146 | if (err) | 146 | if (err) |
147 | return err; | 147 | return err; |
148 | 148 | ||
@@ -195,7 +195,7 @@ out_uninit_gvrp: | |||
195 | if (grp->nr_vlan_devs == 0) | 195 | if (grp->nr_vlan_devs == 0) |
196 | vlan_gvrp_uninit_applicant(real_dev); | 196 | vlan_gvrp_uninit_applicant(real_dev); |
197 | out_vid_del: | 197 | out_vid_del: |
198 | vlan_vid_del(real_dev, vlan_id); | 198 | vlan_vid_del(real_dev, htons(ETH_P_8021Q), vlan_id); |
199 | return err; | 199 | return err; |
200 | } | 200 | } |
201 | 201 | ||
@@ -350,7 +350,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
350 | (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { | 350 | (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { |
351 | pr_info("adding VLAN 0 to HW filter on device %s\n", | 351 | pr_info("adding VLAN 0 to HW filter on device %s\n", |
352 | dev->name); | 352 | dev->name); |
353 | vlan_vid_add(dev, 0); | 353 | vlan_vid_add(dev, htons(ETH_P_8021Q), 0); |
354 | } | 354 | } |
355 | 355 | ||
356 | vlan_info = rtnl_dereference(dev->vlan_info); | 356 | vlan_info = rtnl_dereference(dev->vlan_info); |
@@ -416,7 +416,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
416 | 416 | ||
417 | case NETDEV_DOWN: | 417 | case NETDEV_DOWN: |
418 | if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) | 418 | if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) |
419 | vlan_vid_del(dev, 0); | 419 | vlan_vid_del(dev, htons(ETH_P_8021Q), 0); |
420 | 420 | ||
421 | /* Put all VLANs for this dev in the down state too. */ | 421 | /* Put all VLANs for this dev in the down state too. */ |
422 | for (i = 0; i < VLAN_N_VID; i++) { | 422 | for (i = 0; i < VLAN_N_VID; i++) { |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 3df29d344704..04e3b95a0d48 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -185,35 +185,37 @@ static struct vlan_info *vlan_info_alloc(struct net_device *dev) | |||
185 | 185 | ||
186 | struct vlan_vid_info { | 186 | struct vlan_vid_info { |
187 | struct list_head list; | 187 | struct list_head list; |
188 | unsigned short vid; | 188 | __be16 proto; |
189 | u16 vid; | ||
189 | int refcount; | 190 | int refcount; |
190 | }; | 191 | }; |
191 | 192 | ||
192 | static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info, | 193 | static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info, |
193 | unsigned short vid) | 194 | __be16 proto, u16 vid) |
194 | { | 195 | { |
195 | struct vlan_vid_info *vid_info; | 196 | struct vlan_vid_info *vid_info; |
196 | 197 | ||
197 | list_for_each_entry(vid_info, &vlan_info->vid_list, list) { | 198 | list_for_each_entry(vid_info, &vlan_info->vid_list, list) { |
198 | if (vid_info->vid == vid) | 199 | if (vid_info->proto == proto && vid_info->vid == vid) |
199 | return vid_info; | 200 | return vid_info; |
200 | } | 201 | } |
201 | return NULL; | 202 | return NULL; |
202 | } | 203 | } |
203 | 204 | ||
204 | static struct vlan_vid_info *vlan_vid_info_alloc(unsigned short vid) | 205 | static struct vlan_vid_info *vlan_vid_info_alloc(__be16 proto, u16 vid) |
205 | { | 206 | { |
206 | struct vlan_vid_info *vid_info; | 207 | struct vlan_vid_info *vid_info; |
207 | 208 | ||
208 | vid_info = kzalloc(sizeof(struct vlan_vid_info), GFP_KERNEL); | 209 | vid_info = kzalloc(sizeof(struct vlan_vid_info), GFP_KERNEL); |
209 | if (!vid_info) | 210 | if (!vid_info) |
210 | return NULL; | 211 | return NULL; |
212 | vid_info->proto = proto; | ||
211 | vid_info->vid = vid; | 213 | vid_info->vid = vid; |
212 | 214 | ||
213 | return vid_info; | 215 | return vid_info; |
214 | } | 216 | } |
215 | 217 | ||
216 | static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid, | 218 | static int __vlan_vid_add(struct vlan_info *vlan_info, __be16 proto, u16 vid, |
217 | struct vlan_vid_info **pvid_info) | 219 | struct vlan_vid_info **pvid_info) |
218 | { | 220 | { |
219 | struct net_device *dev = vlan_info->real_dev; | 221 | struct net_device *dev = vlan_info->real_dev; |
@@ -221,12 +223,13 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid, | |||
221 | struct vlan_vid_info *vid_info; | 223 | struct vlan_vid_info *vid_info; |
222 | int err; | 224 | int err; |
223 | 225 | ||
224 | vid_info = vlan_vid_info_alloc(vid); | 226 | vid_info = vlan_vid_info_alloc(proto, vid); |
225 | if (!vid_info) | 227 | if (!vid_info) |
226 | return -ENOMEM; | 228 | return -ENOMEM; |
227 | 229 | ||
228 | if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { | 230 | if (proto == htons(ETH_P_8021Q) && |
229 | err = ops->ndo_vlan_rx_add_vid(dev, vid); | 231 | dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { |
232 | err = ops->ndo_vlan_rx_add_vid(dev, proto, vid); | ||
230 | if (err) { | 233 | if (err) { |
231 | kfree(vid_info); | 234 | kfree(vid_info); |
232 | return err; | 235 | return err; |
@@ -238,7 +241,7 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid, | |||
238 | return 0; | 241 | return 0; |
239 | } | 242 | } |
240 | 243 | ||
241 | int vlan_vid_add(struct net_device *dev, unsigned short vid) | 244 | int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid) |
242 | { | 245 | { |
243 | struct vlan_info *vlan_info; | 246 | struct vlan_info *vlan_info; |
244 | struct vlan_vid_info *vid_info; | 247 | struct vlan_vid_info *vid_info; |
@@ -254,9 +257,9 @@ int vlan_vid_add(struct net_device *dev, unsigned short vid) | |||
254 | return -ENOMEM; | 257 | return -ENOMEM; |
255 | vlan_info_created = true; | 258 | vlan_info_created = true; |
256 | } | 259 | } |
257 | vid_info = vlan_vid_info_get(vlan_info, vid); | 260 | vid_info = vlan_vid_info_get(vlan_info, proto, vid); |
258 | if (!vid_info) { | 261 | if (!vid_info) { |
259 | err = __vlan_vid_add(vlan_info, vid, &vid_info); | 262 | err = __vlan_vid_add(vlan_info, proto, vid, &vid_info); |
260 | if (err) | 263 | if (err) |
261 | goto out_free_vlan_info; | 264 | goto out_free_vlan_info; |
262 | } | 265 | } |
@@ -279,14 +282,16 @@ static void __vlan_vid_del(struct vlan_info *vlan_info, | |||
279 | { | 282 | { |
280 | struct net_device *dev = vlan_info->real_dev; | 283 | struct net_device *dev = vlan_info->real_dev; |
281 | const struct net_device_ops *ops = dev->netdev_ops; | 284 | const struct net_device_ops *ops = dev->netdev_ops; |
282 | unsigned short vid = vid_info->vid; | 285 | __be16 proto = vid_info->proto; |
286 | u16 vid = vid_info->vid; | ||
283 | int err; | 287 | int err; |
284 | 288 | ||
285 | if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { | 289 | if (proto == htons(ETH_P_8021Q) && |
286 | err = ops->ndo_vlan_rx_kill_vid(dev, vid); | 290 | dev->features & NETIF_F_HW_VLAN_CTAG_FILTER) { |
291 | err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid); | ||
287 | if (err) { | 292 | if (err) { |
288 | pr_warn("failed to kill vid %d for device %s\n", | 293 | pr_warn("failed to kill vid %04x/%d for device %s\n", |
289 | vid, dev->name); | 294 | proto, vid, dev->name); |
290 | } | 295 | } |
291 | } | 296 | } |
292 | list_del(&vid_info->list); | 297 | list_del(&vid_info->list); |
@@ -294,7 +299,7 @@ static void __vlan_vid_del(struct vlan_info *vlan_info, | |||
294 | vlan_info->nr_vids--; | 299 | vlan_info->nr_vids--; |
295 | } | 300 | } |
296 | 301 | ||
297 | void vlan_vid_del(struct net_device *dev, unsigned short vid) | 302 | void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid) |
298 | { | 303 | { |
299 | struct vlan_info *vlan_info; | 304 | struct vlan_info *vlan_info; |
300 | struct vlan_vid_info *vid_info; | 305 | struct vlan_vid_info *vid_info; |
@@ -305,7 +310,7 @@ void vlan_vid_del(struct net_device *dev, unsigned short vid) | |||
305 | if (!vlan_info) | 310 | if (!vlan_info) |
306 | return; | 311 | return; |
307 | 312 | ||
308 | vid_info = vlan_vid_info_get(vlan_info, vid); | 313 | vid_info = vlan_vid_info_get(vlan_info, proto, vid); |
309 | if (!vid_info) | 314 | if (!vid_info) |
310 | return; | 315 | return; |
311 | vid_info->refcount--; | 316 | vid_info->refcount--; |
@@ -333,7 +338,7 @@ int vlan_vids_add_by_dev(struct net_device *dev, | |||
333 | return 0; | 338 | return 0; |
334 | 339 | ||
335 | list_for_each_entry(vid_info, &vlan_info->vid_list, list) { | 340 | list_for_each_entry(vid_info, &vlan_info->vid_list, list) { |
336 | err = vlan_vid_add(dev, vid_info->vid); | 341 | err = vlan_vid_add(dev, vid_info->proto, vid_info->vid); |
337 | if (err) | 342 | if (err) |
338 | goto unwind; | 343 | goto unwind; |
339 | } | 344 | } |
@@ -343,7 +348,7 @@ unwind: | |||
343 | list_for_each_entry_continue_reverse(vid_info, | 348 | list_for_each_entry_continue_reverse(vid_info, |
344 | &vlan_info->vid_list, | 349 | &vlan_info->vid_list, |
345 | list) { | 350 | list) { |
346 | vlan_vid_del(dev, vid_info->vid); | 351 | vlan_vid_del(dev, vid_info->proto, vid_info->vid); |
347 | } | 352 | } |
348 | 353 | ||
349 | return err; | 354 | return err; |
@@ -363,7 +368,7 @@ void vlan_vids_del_by_dev(struct net_device *dev, | |||
363 | return; | 368 | return; |
364 | 369 | ||
365 | list_for_each_entry(vid_info, &vlan_info->vid_list, list) | 370 | list_for_each_entry(vid_info, &vlan_info->vid_list, list) |
366 | vlan_vid_del(dev, vid_info->vid); | 371 | vlan_vid_del(dev, vid_info->proto, vid_info->vid); |
367 | } | 372 | } |
368 | EXPORT_SYMBOL(vlan_vids_del_by_dev); | 373 | EXPORT_SYMBOL(vlan_vids_del_by_dev); |
369 | 374 | ||