diff options
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r-- | net/mac80211/ieee80211.c | 54 |
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) { |