aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r--net/mac80211/ieee80211.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 319ec2a1d84f..4e345f82f044 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -314,22 +314,43 @@ static int ieee80211_open(struct net_device *dev)
314 int res; 314 int res;
315 315
316 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 316 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
317
317 read_lock(&local->sub_if_lock); 318 read_lock(&local->sub_if_lock);
318 list_for_each_entry(nsdata, &local->sub_if_list, list) { 319 list_for_each_entry(nsdata, &local->sub_if_list, list) {
319 struct net_device *ndev = nsdata->dev; 320 struct net_device *ndev = nsdata->dev;
320 321
321 if (ndev != dev && ndev != local->mdev && netif_running(ndev) && 322 if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
322 compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && 323 compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
323 !identical_mac_addr_allowed(sdata->type, nsdata->type)) { 324 /*
324 read_unlock(&local->sub_if_lock); 325 * check whether it may have the same address
325 return -ENOTUNIQ; 326 */
327 if (!identical_mac_addr_allowed(sdata->type,
328 nsdata->type)) {
329 read_unlock(&local->sub_if_lock);
330 return -ENOTUNIQ;
331 }
332
333 /*
334 * can only add VLANs to enabled APs
335 */
336 if (sdata->type == IEEE80211_IF_TYPE_VLAN &&
337 nsdata->type == IEEE80211_IF_TYPE_AP &&
338 netif_running(nsdata->dev))
339 sdata->u.vlan.ap = nsdata;
326 } 340 }
327 } 341 }
328 read_unlock(&local->sub_if_lock); 342 read_unlock(&local->sub_if_lock);
329 343
330 if (sdata->type == IEEE80211_IF_TYPE_WDS && 344 switch (sdata->type) {
331 is_zero_ether_addr(sdata->u.wds.remote_addr)) 345 case IEEE80211_IF_TYPE_WDS:
332 return -ENOLINK; 346 if (is_zero_ether_addr(sdata->u.wds.remote_addr))
347 return -ENOLINK;
348 break;
349 case IEEE80211_IF_TYPE_VLAN:
350 if (!sdata->u.vlan.ap)
351 return -ENOLINK;
352 break;
353 }
333 354
334 if (local->open_count == 0) { 355 if (local->open_count == 0) {
335 res = 0; 356 res = 0;
@@ -340,6 +361,10 @@ static int ieee80211_open(struct net_device *dev)
340 } 361 }
341 362
342 switch (sdata->type) { 363 switch (sdata->type) {
364 case IEEE80211_IF_TYPE_VLAN:
365 list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
366 /* no need to tell driver */
367 break;
343 case IEEE80211_IF_TYPE_MNTR: 368 case IEEE80211_IF_TYPE_MNTR:
344 /* must be before the call to ieee80211_configure_filter */ 369 /* must be before the call to ieee80211_configure_filter */
345 local->monitors++; 370 local->monitors++;
@@ -407,9 +432,24 @@ static int ieee80211_stop(struct net_device *dev)
407 432
408 dev_mc_unsync(local->mdev, dev); 433 dev_mc_unsync(local->mdev, dev);
409 434
435 /* down all dependent devices, that is VLANs */
436 if (sdata->type == IEEE80211_IF_TYPE_AP) {
437 struct ieee80211_sub_if_data *vlan, *tmp;
438
439 list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans,
440 u.vlan.list)
441 dev_close(vlan->dev);
442 WARN_ON(!list_empty(&sdata->u.ap.vlans));
443 }
444
410 local->open_count--; 445 local->open_count--;
411 446
412 switch (sdata->type) { 447 switch (sdata->type) {
448 case IEEE80211_IF_TYPE_VLAN:
449 list_del(&sdata->u.vlan.list);
450 sdata->u.vlan.ap = NULL;
451 /* no need to tell driver */
452 break;
413 case IEEE80211_IF_TYPE_MNTR: 453 case IEEE80211_IF_TYPE_MNTR:
414 local->monitors--; 454 local->monitors--;
415 if (local->monitors == 0) { 455 if (local->monitors == 0) {