diff options
-rw-r--r-- | net/8021q/vlan.c | 72 |
1 files changed, 32 insertions, 40 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 006d9a9bac90..ad34e4a0326a 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -142,63 +142,55 @@ static void vlan_rcu_free(struct rcu_head *rcu) | |||
142 | static int unregister_vlan_dev(struct net_device *real_dev, | 142 | static int unregister_vlan_dev(struct net_device *real_dev, |
143 | unsigned short vlan_id) | 143 | unsigned short vlan_id) |
144 | { | 144 | { |
145 | struct net_device *dev = NULL; | 145 | struct net_device *dev; |
146 | int real_dev_ifindex = real_dev->ifindex; | 146 | int real_dev_ifindex = real_dev->ifindex; |
147 | struct vlan_group *grp; | 147 | struct vlan_group *grp; |
148 | int i, ret; | 148 | unsigned int i; |
149 | int ret; | ||
149 | 150 | ||
150 | /* sanity check */ | ||
151 | if (vlan_id >= VLAN_VID_MASK) | 151 | if (vlan_id >= VLAN_VID_MASK) |
152 | return -EINVAL; | 152 | return -EINVAL; |
153 | 153 | ||
154 | ASSERT_RTNL(); | 154 | ASSERT_RTNL(); |
155 | grp = __vlan_find_group(real_dev_ifindex); | 155 | grp = __vlan_find_group(real_dev_ifindex); |
156 | if (!grp) | ||
157 | return -ENOENT; | ||
156 | 158 | ||
157 | ret = 0; | 159 | dev = vlan_group_get_device(grp, vlan_id); |
158 | 160 | if (!dev) | |
159 | if (grp) { | 161 | return -ENOENT; |
160 | dev = vlan_group_get_device(grp, vlan_id); | ||
161 | if (dev) { | ||
162 | /* Remove proc entry */ | ||
163 | vlan_proc_rem_dev(dev); | ||
164 | |||
165 | /* Take it out of our own structures, but be sure to | ||
166 | * interlock with HW accelerating devices or SW vlan | ||
167 | * input packet processing. | ||
168 | */ | ||
169 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | ||
170 | real_dev->vlan_rx_kill_vid(real_dev, vlan_id); | ||
171 | 162 | ||
172 | vlan_group_set_device(grp, vlan_id, NULL); | 163 | vlan_proc_rem_dev(dev); |
173 | synchronize_net(); | ||
174 | 164 | ||
165 | /* Take it out of our own structures, but be sure to interlock with | ||
166 | * HW accelerating devices or SW vlan input packet processing. | ||
167 | */ | ||
168 | if (real_dev->features & NETIF_F_HW_VLAN_FILTER) | ||
169 | real_dev->vlan_rx_kill_vid(real_dev, vlan_id); | ||
175 | 170 | ||
176 | /* Caller unregisters (and if necessary, puts) | 171 | vlan_group_set_device(grp, vlan_id, NULL); |
177 | * VLAN device, but we get rid of the reference to | 172 | synchronize_net(); |
178 | * real_dev here. | ||
179 | */ | ||
180 | dev_put(real_dev); | ||
181 | 173 | ||
182 | /* If the group is now empty, kill off the | 174 | /* Caller unregisters (and if necessary, puts) VLAN device, but we |
183 | * group. | 175 | * get rid of the reference to real_dev here. |
184 | */ | 176 | */ |
185 | for (i = 0; i < VLAN_VID_MASK; i++) | 177 | dev_put(real_dev); |
186 | if (vlan_group_get_device(grp, i)) | ||
187 | break; | ||
188 | 178 | ||
189 | if (i == VLAN_VID_MASK) { | 179 | /* If the group is now empty, kill off the group. */ |
190 | if (real_dev->features & NETIF_F_HW_VLAN_RX) | 180 | ret = 0; |
191 | real_dev->vlan_rx_register(real_dev, NULL); | 181 | for (i = 0; i < VLAN_VID_MASK; i++) |
182 | if (vlan_group_get_device(grp, i)) | ||
183 | break; | ||
192 | 184 | ||
193 | hlist_del_rcu(&grp->hlist); | 185 | if (i == VLAN_VID_MASK) { |
186 | if (real_dev->features & NETIF_F_HW_VLAN_RX) | ||
187 | real_dev->vlan_rx_register(real_dev, NULL); | ||
194 | 188 | ||
195 | /* Free the group, after all cpu's are done. */ | 189 | hlist_del_rcu(&grp->hlist); |
196 | call_rcu(&grp->rcu, vlan_rcu_free); | ||
197 | 190 | ||
198 | grp = NULL; | 191 | /* Free the group, after all cpu's are done. */ |
199 | ret = 1; | 192 | call_rcu(&grp->rcu, vlan_rcu_free); |
200 | } | 193 | ret = 1; |
201 | } | ||
202 | } | 194 | } |
203 | 195 | ||
204 | return ret; | 196 | return ret; |