diff options
Diffstat (limited to 'net/8021q')
-rw-r--r-- | net/8021q/vlan.c | 49 |
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 | ||
187 | void 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 | |||
186 | static void vlan_transfer_operstate(const struct net_device *dev, | 215 | static 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 | ||