aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/8021q/vlan.c52
1 files changed, 20 insertions, 32 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 511afe72af31..39f8d0120104 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -161,10 +161,10 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
161 161
162 grp->nr_vlans--; 162 grp->nr_vlans--;
163 163
164 if (!grp->killall) { 164 vlan_group_set_device(grp, vlan_id, NULL);
165 vlan_group_set_device(grp, vlan_id, NULL); 165 if (!grp->killall)
166 synchronize_net(); 166 synchronize_net();
167 } 167
168 unregister_netdevice_queue(dev, head); 168 unregister_netdevice_queue(dev, head);
169 169
170 /* If the group is now empty, kill off the group. */ 170 /* If the group is now empty, kill off the group. */
@@ -184,34 +184,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
184 dev_put(real_dev); 184 dev_put(real_dev);
185} 185}
186 186
187void unregister_vlan_dev_alls(struct vlan_group *grp)
188{
189 LIST_HEAD(list);
190 int i;
191 struct net_device *vlandev;
192 struct vlan_group save;
193
194 memcpy(&save, grp, sizeof(save));
195 memset(&grp->vlan_devices_arrays, 0, sizeof(grp->vlan_devices_arrays));
196 grp->killall = 1;
197
198 synchronize_net();
199
200 /* Delete all VLANs for this dev. */
201 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
202 vlandev = vlan_group_get_device(&save, i);
203 if (!vlandev)
204 continue;
205
206 unregister_vlan_dev(vlandev, &list);
207 if (grp->nr_vlans == 0)
208 break;
209 }
210 unregister_netdevice_many(&list);
211 for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
212 kfree(save.vlan_devices_arrays[i]);
213}
214
215static void vlan_transfer_operstate(const struct net_device *dev, 187static void vlan_transfer_operstate(const struct net_device *dev,
216 struct net_device *vlandev) 188 struct net_device *vlandev)
217{ 189{
@@ -456,6 +428,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
456 struct vlan_group *grp; 428 struct vlan_group *grp;
457 int i, flgs; 429 int i, flgs;
458 struct net_device *vlandev; 430 struct net_device *vlandev;
431 LIST_HEAD(list);
459 432
460 if (is_vlan_dev(dev)) 433 if (is_vlan_dev(dev))
461 __vlan_device_event(dev, event); 434 __vlan_device_event(dev, event);
@@ -553,7 +526,22 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
553 break; 526 break;
554 527
555 case NETDEV_UNREGISTER: 528 case NETDEV_UNREGISTER:
556 unregister_vlan_dev_alls(grp); 529 /* Delete all VLANs for this dev. */
530 grp->killall = 1;
531
532 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
533 vlandev = vlan_group_get_device(grp, i);
534 if (!vlandev)
535 continue;
536
537 /* unregistration of last vlan destroys group, abort
538 * afterwards */
539 if (grp->nr_vlans == 1)
540 i = VLAN_GROUP_ARRAY_LEN;
541
542 unregister_vlan_dev(vlandev, &list);
543 }
544 unregister_netdevice_many(&list);
557 break; 545 break;
558 } 546 }
559 547