aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-05-13 04:58:57 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-05-16 14:10:40 -0400
commit7527a782e187d1214a5b3dc2897ce441033bb4ef (patch)
tree3310adf988e72cb91736c0638d4c17edcccebfe1 /net/wireless/core.c
parent805d7d23ef9806e47b550ad80270c4cea4ffc984 (diff)
cfg80211: advertise possible interface combinations
Add the ability to advertise interface combinations in nl80211. This allows the driver to indicate what the combinations are that it supports. "Combinations" of just a single interface are implicit, as previously. Note that cfg80211 will enforce that the restrictions are met, but not for all drivers yet (once all drivers are updated, we can remove the flag and enforce for all). When no combinations are actually supported, an empty list will be exported so that userspace can know if the kernel exported this info or not (although it isn't clear to me what tools using the info should do if the kernel didn't export it). Since some interface types are purely virtual/software and don't fit the restrictions, those are exposed in a new list of pure SW types, not subject to restrictions. This mainly exists to handle AP-VLAN and monitor interfaces in mac80211. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 18b002f16860..c22ef3492ee6 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -416,6 +416,67 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
416} 416}
417EXPORT_SYMBOL(wiphy_new); 417EXPORT_SYMBOL(wiphy_new);
418 418
419static int wiphy_verify_combinations(struct wiphy *wiphy)
420{
421 const struct ieee80211_iface_combination *c;
422 int i, j;
423
424 /* If we have combinations enforce them */
425 if (wiphy->n_iface_combinations)
426 wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS;
427
428 for (i = 0; i < wiphy->n_iface_combinations; i++) {
429 u32 cnt = 0;
430 u16 all_iftypes = 0;
431
432 c = &wiphy->iface_combinations[i];
433
434 /* Combinations with just one interface aren't real */
435 if (WARN_ON(c->max_interfaces < 2))
436 return -EINVAL;
437
438 /* Need at least one channel */
439 if (WARN_ON(!c->num_different_channels))
440 return -EINVAL;
441
442 if (WARN_ON(!c->n_limits))
443 return -EINVAL;
444
445 for (j = 0; j < c->n_limits; j++) {
446 u16 types = c->limits[j].types;
447
448 /*
449 * interface types shouldn't overlap, this is
450 * used in cfg80211_can_change_interface()
451 */
452 if (WARN_ON(types & all_iftypes))
453 return -EINVAL;
454 all_iftypes |= types;
455
456 if (WARN_ON(!c->limits[j].max))
457 return -EINVAL;
458
459 /* Shouldn't list software iftypes in combinations! */
460 if (WARN_ON(wiphy->software_iftypes & types))
461 return -EINVAL;
462
463 cnt += c->limits[j].max;
464 /*
465 * Don't advertise an unsupported type
466 * in a combination.
467 */
468 if (WARN_ON((wiphy->interface_modes & types) != types))
469 return -EINVAL;
470 }
471
472 /* You can't even choose that many! */
473 if (WARN_ON(cnt < c->max_interfaces))
474 return -EINVAL;
475 }
476
477 return 0;
478}
479
419int wiphy_register(struct wiphy *wiphy) 480int wiphy_register(struct wiphy *wiphy)
420{ 481{
421 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 482 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
@@ -444,6 +505,10 @@ int wiphy_register(struct wiphy *wiphy)
444 if (WARN_ON(ifmodes != wiphy->interface_modes)) 505 if (WARN_ON(ifmodes != wiphy->interface_modes))
445 wiphy->interface_modes = ifmodes; 506 wiphy->interface_modes = ifmodes;
446 507
508 res = wiphy_verify_combinations(wiphy);
509 if (res)
510 return res;
511
447 /* sanity check supported bands/channels */ 512 /* sanity check supported bands/channels */
448 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 513 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
449 sband = wiphy->bands[band]; 514 sband = wiphy->bands[band];
@@ -698,6 +763,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
698 struct net_device *dev = ndev; 763 struct net_device *dev = ndev;
699 struct wireless_dev *wdev = dev->ieee80211_ptr; 764 struct wireless_dev *wdev = dev->ieee80211_ptr;
700 struct cfg80211_registered_device *rdev; 765 struct cfg80211_registered_device *rdev;
766 int ret;
701 767
702 if (!wdev) 768 if (!wdev)
703 return NOTIFY_DONE; 769 return NOTIFY_DONE;
@@ -893,6 +959,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
893 return notifier_from_errno(-EOPNOTSUPP); 959 return notifier_from_errno(-EOPNOTSUPP);
894 if (rfkill_blocked(rdev->rfkill)) 960 if (rfkill_blocked(rdev->rfkill))
895 return notifier_from_errno(-ERFKILL); 961 return notifier_from_errno(-ERFKILL);
962 ret = cfg80211_can_add_interface(rdev, wdev->iftype);
963 if (ret)
964 return notifier_from_errno(ret);
896 break; 965 break;
897 } 966 }
898 967