aboutsummaryrefslogtreecommitdiffstats
path: root/net/8021q
diff options
context:
space:
mode:
Diffstat (limited to 'net/8021q')
-rw-r--r--net/8021q/vlan.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 6b5c9dddaa72..511afe72af31 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -159,11 +159,12 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
159 if (real_dev->features & NETIF_F_HW_VLAN_FILTER) 159 if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
160 ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); 160 ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id);
161 161
162 vlan_group_set_device(grp, vlan_id, NULL);
163 grp->nr_vlans--; 162 grp->nr_vlans--;
164 163
165 synchronize_net(); 164 if (!grp->killall) {
166 165 vlan_group_set_device(grp, vlan_id, NULL);
166 synchronize_net();
167 }
167 unregister_netdevice_queue(dev, head); 168 unregister_netdevice_queue(dev, head);
168 169
169 /* If the group is now empty, kill off the group. */ 170 /* If the group is now empty, kill off the group. */
@@ -183,6 +184,34 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
183 dev_put(real_dev); 184 dev_put(real_dev);
184} 185}
185 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
186static void vlan_transfer_operstate(const struct net_device *dev, 215static void vlan_transfer_operstate(const struct net_device *dev,
187 struct net_device *vlandev) 216 struct net_device *vlandev)
188{ 217{
@@ -524,19 +553,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
524 break; 553 break;
525 554
526 case NETDEV_UNREGISTER: 555 case NETDEV_UNREGISTER:
527 /* Delete all VLANs for this dev. */ 556 unregister_vlan_dev_alls(grp);
528 for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
529 vlandev = vlan_group_get_device(grp, i);
530 if (!vlandev)
531 continue;
532
533 /* unregistration of last vlan destroys group, abort
534 * afterwards */
535 if (grp->nr_vlans == 1)
536 i = VLAN_GROUP_ARRAY_LEN;
537
538 unregister_vlan_dev(vlandev, NULL);
539 }
540 break; 557 break;
541 } 558 }
542 559