diff options
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r-- | net/8021q/vlan.c | 76 |
1 files changed, 20 insertions, 56 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index ad34e4a0326a..ac7963854103 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -132,33 +132,17 @@ static void vlan_rcu_free(struct rcu_head *rcu) | |||
132 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); | 132 | vlan_group_free(container_of(rcu, struct vlan_group, rcu)); |
133 | } | 133 | } |
134 | 134 | ||
135 | 135 | void unregister_vlan_dev(struct net_device *dev) | |
136 | /* This returns 0 if everything went fine. | ||
137 | * It will return 1 if the group was killed as a result. | ||
138 | * A negative return indicates failure. | ||
139 | * | ||
140 | * The RTNL lock must be held. | ||
141 | */ | ||
142 | static int unregister_vlan_dev(struct net_device *real_dev, | ||
143 | unsigned short vlan_id) | ||
144 | { | 136 | { |
145 | struct net_device *dev; | 137 | struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev); |
146 | int real_dev_ifindex = real_dev->ifindex; | 138 | struct net_device *real_dev = vlan->real_dev; |
147 | struct vlan_group *grp; | 139 | struct vlan_group *grp; |
148 | unsigned int i; | 140 | unsigned short vlan_id = vlan->vlan_id; |
149 | int ret; | ||
150 | |||
151 | if (vlan_id >= VLAN_VID_MASK) | ||
152 | return -EINVAL; | ||
153 | 141 | ||
154 | ASSERT_RTNL(); | 142 | ASSERT_RTNL(); |
155 | grp = __vlan_find_group(real_dev_ifindex); | ||
156 | if (!grp) | ||
157 | return -ENOENT; | ||
158 | 143 | ||
159 | dev = vlan_group_get_device(grp, vlan_id); | 144 | grp = __vlan_find_group(real_dev->ifindex); |
160 | if (!dev) | 145 | BUG_ON(!grp); |
161 | return -ENOENT; | ||
162 | 146 | ||
163 | vlan_proc_rem_dev(dev); | 147 | vlan_proc_rem_dev(dev); |
164 | 148 | ||
@@ -169,20 +153,12 @@ static int unregister_vlan_dev(struct net_device *real_dev, | |||
169 | real_dev->vlan_rx_kill_vid(real_dev, vlan_id); | 153 | real_dev->vlan_rx_kill_vid(real_dev, vlan_id); |
170 | 154 | ||
171 | vlan_group_set_device(grp, vlan_id, NULL); | 155 | vlan_group_set_device(grp, vlan_id, NULL); |
172 | synchronize_net(); | 156 | grp->nr_vlans--; |
173 | 157 | ||
174 | /* Caller unregisters (and if necessary, puts) VLAN device, but we | 158 | synchronize_net(); |
175 | * get rid of the reference to real_dev here. | ||
176 | */ | ||
177 | dev_put(real_dev); | ||
178 | 159 | ||
179 | /* If the group is now empty, kill off the group. */ | 160 | /* If the group is now empty, kill off the group. */ |
180 | ret = 0; | 161 | if (grp->nr_vlans == 0) { |
181 | for (i = 0; i < VLAN_VID_MASK; i++) | ||
182 | if (vlan_group_get_device(grp, i)) | ||
183 | break; | ||
184 | |||
185 | if (i == VLAN_VID_MASK) { | ||
186 | if (real_dev->features & NETIF_F_HW_VLAN_RX) | 162 | if (real_dev->features & NETIF_F_HW_VLAN_RX) |
187 | real_dev->vlan_rx_register(real_dev, NULL); | 163 | real_dev->vlan_rx_register(real_dev, NULL); |
188 | 164 | ||
@@ -190,23 +166,12 @@ static int unregister_vlan_dev(struct net_device *real_dev, | |||
190 | 166 | ||
191 | /* Free the group, after all cpu's are done. */ | 167 | /* Free the group, after all cpu's are done. */ |
192 | call_rcu(&grp->rcu, vlan_rcu_free); | 168 | call_rcu(&grp->rcu, vlan_rcu_free); |
193 | ret = 1; | ||
194 | } | 169 | } |
195 | 170 | ||
196 | return ret; | 171 | /* Get rid of the vlan's reference to real_dev */ |
197 | } | 172 | dev_put(real_dev); |
198 | |||
199 | int unregister_vlan_device(struct net_device *dev) | ||
200 | { | ||
201 | int ret; | ||
202 | 173 | ||
203 | ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev, | ||
204 | VLAN_DEV_INFO(dev)->vlan_id); | ||
205 | unregister_netdevice(dev); | 174 | unregister_netdevice(dev); |
206 | |||
207 | if (ret == 1) | ||
208 | ret = 0; | ||
209 | return ret; | ||
210 | } | 175 | } |
211 | 176 | ||
212 | static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) | 177 | static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) |
@@ -291,6 +256,8 @@ int register_vlan_dev(struct net_device *dev) | |||
291 | * it into our local structure. | 256 | * it into our local structure. |
292 | */ | 257 | */ |
293 | vlan_group_set_device(grp, vlan_id, dev); | 258 | vlan_group_set_device(grp, vlan_id, dev); |
259 | grp->nr_vlans++; | ||
260 | |||
294 | if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX) | 261 | if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX) |
295 | real_dev->vlan_rx_register(real_dev, ngrp); | 262 | real_dev->vlan_rx_register(real_dev, ngrp); |
296 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | 263 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) |
@@ -479,20 +446,16 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, | |||
479 | case NETDEV_UNREGISTER: | 446 | case NETDEV_UNREGISTER: |
480 | /* Delete all VLANs for this dev. */ | 447 | /* Delete all VLANs for this dev. */ |
481 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { | 448 | for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { |
482 | int ret; | ||
483 | |||
484 | vlandev = vlan_group_get_device(grp, i); | 449 | vlandev = vlan_group_get_device(grp, i); |
485 | if (!vlandev) | 450 | if (!vlandev) |
486 | continue; | 451 | continue; |
487 | 452 | ||
488 | ret = unregister_vlan_dev(dev, | 453 | /* unregistration of last vlan destroys group, abort |
489 | VLAN_DEV_INFO(vlandev)->vlan_id); | 454 | * afterwards */ |
490 | 455 | if (grp->nr_vlans == 1) | |
491 | unregister_netdevice(vlandev); | 456 | i = VLAN_GROUP_ARRAY_LEN; |
492 | 457 | ||
493 | /* Group was destroyed? */ | 458 | unregister_vlan_dev(vlandev); |
494 | if (ret == 1) | ||
495 | break; | ||
496 | } | 459 | } |
497 | break; | 460 | break; |
498 | } | 461 | } |
@@ -598,7 +561,8 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) | |||
598 | err = -EPERM; | 561 | err = -EPERM; |
599 | if (!capable(CAP_NET_ADMIN)) | 562 | if (!capable(CAP_NET_ADMIN)) |
600 | break; | 563 | break; |
601 | err = unregister_vlan_device(dev); | 564 | unregister_vlan_dev(dev); |
565 | err = 0; | ||
602 | break; | 566 | break; |
603 | 567 | ||
604 | case GET_VLAN_REALDEV_NAME_CMD: | 568 | case GET_VLAN_REALDEV_NAME_CMD: |