aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/main.c16
-rw-r--r--net/wireless/core.c69
-rw-r--r--net/wireless/core.h11
-rw-r--r--net/wireless/nl80211.c105
-rw-r--r--net/wireless/util.c80
5 files changed, 263 insertions, 18 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 7f89011fa22d..79a2281678bf 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -685,7 +685,7 @@ EXPORT_SYMBOL(ieee80211_alloc_hw);
685int ieee80211_register_hw(struct ieee80211_hw *hw) 685int ieee80211_register_hw(struct ieee80211_hw *hw)
686{ 686{
687 struct ieee80211_local *local = hw_to_local(hw); 687 struct ieee80211_local *local = hw_to_local(hw);
688 int result; 688 int result, i;
689 enum ieee80211_band band; 689 enum ieee80211_band band;
690 int channels, max_bitrates; 690 int channels, max_bitrates;
691 bool supp_ht; 691 bool supp_ht;
@@ -743,11 +743,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
743 return -ENOMEM; 743 return -ENOMEM;
744 744
745 /* if low-level driver supports AP, we also support VLAN */ 745 /* if low-level driver supports AP, we also support VLAN */
746 if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) 746 if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
747 local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN); 747 hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
748 hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
749 }
748 750
749 /* mac80211 always supports monitor */ 751 /* mac80211 always supports monitor */
750 local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); 752 hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
753 hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
754
755 /* mac80211 doesn't support more than 1 channel */
756 for (i = 0; i < hw->wiphy->n_iface_combinations; i++)
757 if (hw->wiphy->iface_combinations[i].num_different_channels > 1)
758 return -EINVAL;
751 759
752#ifndef CONFIG_MAC80211_MESH 760#ifndef CONFIG_MAC80211_MESH
753 /* mesh depends on Kconfig, but drivers should set it if they want */ 761 /* mesh depends on Kconfig, but drivers should set it if they want */
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
diff --git a/net/wireless/core.h b/net/wireless/core.h
index d4b8f4c0bbbb..bf0fb40e3c8b 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -422,6 +422,17 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
422 u32 *flags, struct vif_params *params); 422 u32 *flags, struct vif_params *params);
423void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); 423void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
424 424
425int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
426 struct wireless_dev *wdev,
427 enum nl80211_iftype iftype);
428
429static inline int
430cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
431 enum nl80211_iftype iftype)
432{
433 return cfg80211_can_change_interface(rdev, NULL, iftype);
434}
435
425struct ieee80211_channel * 436struct ieee80211_channel *
426rdev_freq_to_chan(struct cfg80211_registered_device *rdev, 437rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
427 int freq, enum nl80211_channel_type channel_type); 438 int freq, enum nl80211_channel_type channel_type);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 9ef8e287d61b..beac296b1fde 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -564,6 +564,88 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
564 return 0; 564 return 0;
565} 565}
566 566
567static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
568{
569 struct nlattr *nl_modes = nla_nest_start(msg, attr);
570 int i;
571
572 if (!nl_modes)
573 goto nla_put_failure;
574
575 i = 0;
576 while (ifmodes) {
577 if (ifmodes & 1)
578 NLA_PUT_FLAG(msg, i);
579 ifmodes >>= 1;
580 i++;
581 }
582
583 nla_nest_end(msg, nl_modes);
584 return 0;
585
586nla_put_failure:
587 return -ENOBUFS;
588}
589
590static int nl80211_put_iface_combinations(struct wiphy *wiphy,
591 struct sk_buff *msg)
592{
593 struct nlattr *nl_combis;
594 int i, j;
595
596 nl_combis = nla_nest_start(msg,
597 NL80211_ATTR_INTERFACE_COMBINATIONS);
598 if (!nl_combis)
599 goto nla_put_failure;
600
601 for (i = 0; i < wiphy->n_iface_combinations; i++) {
602 const struct ieee80211_iface_combination *c;
603 struct nlattr *nl_combi, *nl_limits;
604
605 c = &wiphy->iface_combinations[i];
606
607 nl_combi = nla_nest_start(msg, i + 1);
608 if (!nl_combi)
609 goto nla_put_failure;
610
611 nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
612 if (!nl_limits)
613 goto nla_put_failure;
614
615 for (j = 0; j < c->n_limits; j++) {
616 struct nlattr *nl_limit;
617
618 nl_limit = nla_nest_start(msg, j + 1);
619 if (!nl_limit)
620 goto nla_put_failure;
621 NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX,
622 c->limits[j].max);
623 if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
624 c->limits[j].types))
625 goto nla_put_failure;
626 nla_nest_end(msg, nl_limit);
627 }
628
629 nla_nest_end(msg, nl_limits);
630
631 if (c->beacon_int_infra_match)
632 NLA_PUT_FLAG(msg,
633 NL80211_IFACE_COMB_STA_AP_BI_MATCH);
634 NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
635 c->num_different_channels);
636 NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM,
637 c->max_interfaces);
638
639 nla_nest_end(msg, nl_combi);
640 }
641
642 nla_nest_end(msg, nl_combis);
643
644 return 0;
645nla_put_failure:
646 return -ENOBUFS;
647}
648
567static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, 649static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
568 struct cfg80211_registered_device *dev) 650 struct cfg80211_registered_device *dev)
569{ 651{
@@ -571,13 +653,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
571 struct nlattr *nl_bands, *nl_band; 653 struct nlattr *nl_bands, *nl_band;
572 struct nlattr *nl_freqs, *nl_freq; 654 struct nlattr *nl_freqs, *nl_freq;
573 struct nlattr *nl_rates, *nl_rate; 655 struct nlattr *nl_rates, *nl_rate;
574 struct nlattr *nl_modes;
575 struct nlattr *nl_cmds; 656 struct nlattr *nl_cmds;
576 enum ieee80211_band band; 657 enum ieee80211_band band;
577 struct ieee80211_channel *chan; 658 struct ieee80211_channel *chan;
578 struct ieee80211_rate *rate; 659 struct ieee80211_rate *rate;
579 int i; 660 int i;
580 u16 ifmodes = dev->wiphy.interface_modes;
581 const struct ieee80211_txrx_stypes *mgmt_stypes = 661 const struct ieee80211_txrx_stypes *mgmt_stypes =
582 dev->wiphy.mgmt_stypes; 662 dev->wiphy.mgmt_stypes;
583 663
@@ -637,20 +717,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
637 } 717 }
638 } 718 }
639 719
640 nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); 720 if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
641 if (!nl_modes) 721 dev->wiphy.interface_modes))
642 goto nla_put_failure; 722 goto nla_put_failure;
643 723
644 i = 0;
645 while (ifmodes) {
646 if (ifmodes & 1)
647 NLA_PUT_FLAG(msg, i);
648 ifmodes >>= 1;
649 i++;
650 }
651
652 nla_nest_end(msg, nl_modes);
653
654 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); 724 nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
655 if (!nl_bands) 725 if (!nl_bands)
656 goto nla_put_failure; 726 goto nla_put_failure;
@@ -865,6 +935,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
865 nla_nest_end(msg, nl_wowlan); 935 nla_nest_end(msg, nl_wowlan);
866 } 936 }
867 937
938 if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
939 dev->wiphy.software_iftypes))
940 goto nla_put_failure;
941
942 if (nl80211_put_iface_combinations(&dev->wiphy, msg))
943 goto nla_put_failure;
944
868 return genlmsg_end(msg, hdr); 945 return genlmsg_end(msg, hdr);
869 946
870 nla_put_failure: 947 nla_put_failure:
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 414c9f604df6..95e4e254da0a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -803,6 +803,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
803 return -EBUSY; 803 return -EBUSY;
804 804
805 if (ntype != otype) { 805 if (ntype != otype) {
806 err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
807 ntype);
808 if (err)
809 return err;
810
806 dev->ieee80211_ptr->use_4addr = false; 811 dev->ieee80211_ptr->use_4addr = false;
807 dev->ieee80211_ptr->mesh_id_up_len = 0; 812 dev->ieee80211_ptr->mesh_id_up_len = 0;
808 813
@@ -921,3 +926,78 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
921 926
922 return res; 927 return res;
923} 928}
929
930int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
931 struct wireless_dev *wdev,
932 enum nl80211_iftype iftype)
933{
934 struct wireless_dev *wdev_iter;
935 int num[NUM_NL80211_IFTYPES];
936 int total = 1;
937 int i, j;
938
939 ASSERT_RTNL();
940
941 /* Always allow software iftypes */
942 if (rdev->wiphy.software_iftypes & BIT(iftype))
943 return 0;
944
945 /*
946 * Drivers will gradually all set this flag, until all
947 * have it we only enforce for those that set it.
948 */
949 if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS))
950 return 0;
951
952 memset(num, 0, sizeof(num));
953
954 num[iftype] = 1;
955
956 mutex_lock(&rdev->devlist_mtx);
957 list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
958 if (wdev_iter == wdev)
959 continue;
960 if (!netif_running(wdev_iter->netdev))
961 continue;
962
963 if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
964 continue;
965
966 num[wdev_iter->iftype]++;
967 total++;
968 }
969 mutex_unlock(&rdev->devlist_mtx);
970
971 for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
972 const struct ieee80211_iface_combination *c;
973 struct ieee80211_iface_limit *limits;
974
975 c = &rdev->wiphy.iface_combinations[i];
976
977 limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
978 GFP_KERNEL);
979 if (!limits)
980 return -ENOMEM;
981 if (total > c->max_interfaces)
982 goto cont;
983
984 for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
985 if (rdev->wiphy.software_iftypes & BIT(iftype))
986 continue;
987 for (j = 0; j < c->n_limits; j++) {
988 if (!(limits[j].types & iftype))
989 continue;
990 if (limits[j].max < num[iftype])
991 goto cont;
992 limits[j].max -= num[iftype];
993 }
994 }
995 /* yay, it fits */
996 kfree(limits);
997 return 0;
998 cont:
999 kfree(limits);
1000 }
1001
1002 return -EBUSY;
1003}