aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q/vlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/8021q/vlan.c')
-rw-r--r--net/8021q/vlan.c76
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 135void 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 */
142static 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
199int 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
212static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev) 177static 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: