diff options
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 171 |
1 files changed, 152 insertions, 19 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd00914f..26f8cd30f712 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) | |||
35 | { | 35 | { |
36 | /* see 802.11 17.3.8.3.2 and Annex J | 36 | /* see 802.11 17.3.8.3.2 and Annex J |
37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ | 37 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ |
38 | if (band == IEEE80211_BAND_5GHZ) { | 38 | if (chan <= 0) |
39 | if (chan >= 182 && chan <= 196) | 39 | return 0; /* not supported */ |
40 | return 4000 + chan * 5; | 40 | switch (band) { |
41 | else | 41 | case IEEE80211_BAND_2GHZ: |
42 | return 5000 + chan * 5; | ||
43 | } else { /* IEEE80211_BAND_2GHZ */ | ||
44 | if (chan == 14) | 42 | if (chan == 14) |
45 | return 2484; | 43 | return 2484; |
46 | else if (chan < 14) | 44 | else if (chan < 14) |
47 | return 2407 + chan * 5; | 45 | return 2407 + chan * 5; |
46 | break; | ||
47 | case IEEE80211_BAND_5GHZ: | ||
48 | if (chan >= 182 && chan <= 196) | ||
49 | return 4000 + chan * 5; | ||
48 | else | 50 | else |
49 | return 0; /* not supported */ | 51 | return 5000 + chan * 5; |
52 | break; | ||
53 | case IEEE80211_BAND_60GHZ: | ||
54 | if (chan < 5) | ||
55 | return 56160 + chan * 2160; | ||
56 | break; | ||
57 | default: | ||
58 | ; | ||
50 | } | 59 | } |
60 | return 0; /* not supported */ | ||
51 | } | 61 | } |
52 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); | 62 | EXPORT_SYMBOL(ieee80211_channel_to_frequency); |
53 | 63 | ||
@@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq) | |||
60 | return (freq - 2407) / 5; | 70 | return (freq - 2407) / 5; |
61 | else if (freq >= 4910 && freq <= 4980) | 71 | else if (freq >= 4910 && freq <= 4980) |
62 | return (freq - 4000) / 5; | 72 | return (freq - 4000) / 5; |
63 | else | 73 | else if (freq <= 45000) /* DMG band lower limit */ |
64 | return (freq - 5000) / 5; | 74 | return (freq - 5000) / 5; |
75 | else if (freq >= 58320 && freq <= 64800) | ||
76 | return (freq - 56160) / 2160; | ||
77 | else | ||
78 | return 0; | ||
65 | } | 79 | } |
66 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); | 80 | EXPORT_SYMBOL(ieee80211_frequency_to_channel); |
67 | 81 | ||
@@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, | |||
137 | } | 151 | } |
138 | WARN_ON(want != 0 && want != 3 && want != 6); | 152 | WARN_ON(want != 0 && want != 3 && want != 6); |
139 | break; | 153 | break; |
154 | case IEEE80211_BAND_60GHZ: | ||
155 | /* check for mandatory HT MCS 1..4 */ | ||
156 | WARN_ON(!sband->ht_cap.ht_supported); | ||
157 | WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); | ||
158 | break; | ||
140 | case IEEE80211_NUM_BANDS: | 159 | case IEEE80211_NUM_BANDS: |
141 | WARN_ON(1); | 160 | WARN_ON(1); |
142 | break; | 161 | break; |
@@ -774,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) | |||
774 | 793 | ||
775 | mutex_lock(&rdev->devlist_mtx); | 794 | mutex_lock(&rdev->devlist_mtx); |
776 | 795 | ||
777 | list_for_each_entry(wdev, &rdev->netdev_list, list) | 796 | list_for_each_entry(wdev, &rdev->wdev_list, list) |
778 | cfg80211_process_wdev_events(wdev); | 797 | cfg80211_process_wdev_events(wdev); |
779 | 798 | ||
780 | mutex_unlock(&rdev->devlist_mtx); | 799 | mutex_unlock(&rdev->devlist_mtx); |
@@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
805 | return -EBUSY; | 824 | return -EBUSY; |
806 | 825 | ||
807 | if (ntype != otype && netif_running(dev)) { | 826 | if (ntype != otype && netif_running(dev)) { |
827 | mutex_lock(&rdev->devlist_mtx); | ||
808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 828 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
809 | ntype); | 829 | ntype); |
830 | mutex_unlock(&rdev->devlist_mtx); | ||
810 | if (err) | 831 | if (err) |
811 | return err; | 832 | return err; |
812 | 833 | ||
@@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
814 | dev->ieee80211_ptr->mesh_id_up_len = 0; | 835 | dev->ieee80211_ptr->mesh_id_up_len = 0; |
815 | 836 | ||
816 | switch (otype) { | 837 | switch (otype) { |
838 | case NL80211_IFTYPE_AP: | ||
839 | cfg80211_stop_ap(rdev, dev); | ||
840 | break; | ||
817 | case NL80211_IFTYPE_ADHOC: | 841 | case NL80211_IFTYPE_ADHOC: |
818 | cfg80211_leave_ibss(rdev, dev, false); | 842 | cfg80211_leave_ibss(rdev, dev, false); |
819 | break; | 843 | break; |
@@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
868 | } | 892 | } |
869 | } | 893 | } |
870 | 894 | ||
895 | if (!err && ntype != otype && netif_running(dev)) { | ||
896 | cfg80211_update_iface_num(rdev, ntype, 1); | ||
897 | cfg80211_update_iface_num(rdev, otype, -1); | ||
898 | } | ||
899 | |||
871 | return err; | 900 | return err; |
872 | } | 901 | } |
873 | 902 | ||
874 | u16 cfg80211_calculate_bitrate(struct rate_info *rate) | 903 | static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) |
904 | { | ||
905 | static const u32 __mcs2bitrate[] = { | ||
906 | /* control PHY */ | ||
907 | [0] = 275, | ||
908 | /* SC PHY */ | ||
909 | [1] = 3850, | ||
910 | [2] = 7700, | ||
911 | [3] = 9625, | ||
912 | [4] = 11550, | ||
913 | [5] = 12512, /* 1251.25 mbps */ | ||
914 | [6] = 15400, | ||
915 | [7] = 19250, | ||
916 | [8] = 23100, | ||
917 | [9] = 25025, | ||
918 | [10] = 30800, | ||
919 | [11] = 38500, | ||
920 | [12] = 46200, | ||
921 | /* OFDM PHY */ | ||
922 | [13] = 6930, | ||
923 | [14] = 8662, /* 866.25 mbps */ | ||
924 | [15] = 13860, | ||
925 | [16] = 17325, | ||
926 | [17] = 20790, | ||
927 | [18] = 27720, | ||
928 | [19] = 34650, | ||
929 | [20] = 41580, | ||
930 | [21] = 45045, | ||
931 | [22] = 51975, | ||
932 | [23] = 62370, | ||
933 | [24] = 67568, /* 6756.75 mbps */ | ||
934 | /* LP-SC PHY */ | ||
935 | [25] = 6260, | ||
936 | [26] = 8340, | ||
937 | [27] = 11120, | ||
938 | [28] = 12510, | ||
939 | [29] = 16680, | ||
940 | [30] = 22240, | ||
941 | [31] = 25030, | ||
942 | }; | ||
943 | |||
944 | if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) | ||
945 | return 0; | ||
946 | |||
947 | return __mcs2bitrate[rate->mcs]; | ||
948 | } | ||
949 | |||
950 | u32 cfg80211_calculate_bitrate(struct rate_info *rate) | ||
875 | { | 951 | { |
876 | int modulation, streams, bitrate; | 952 | int modulation, streams, bitrate; |
877 | 953 | ||
878 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) | 954 | if (!(rate->flags & RATE_INFO_FLAGS_MCS)) |
879 | return rate->legacy; | 955 | return rate->legacy; |
956 | if (rate->flags & RATE_INFO_FLAGS_60G) | ||
957 | return cfg80211_calculate_bitrate_60g(rate); | ||
880 | 958 | ||
881 | /* the formula below does only work for MCS values smaller than 32 */ | 959 | /* the formula below does only work for MCS values smaller than 32 */ |
882 | if (WARN_ON_ONCE(rate->mcs >= 32)) | 960 | if (WARN_ON_ONCE(rate->mcs >= 32)) |
@@ -916,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
916 | 994 | ||
917 | mutex_lock(&rdev->devlist_mtx); | 995 | mutex_lock(&rdev->devlist_mtx); |
918 | 996 | ||
919 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 997 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
920 | if (!wdev->beacon_interval) | 998 | if (!wdev->beacon_interval) |
921 | continue; | 999 | continue; |
922 | if (wdev->beacon_interval != beacon_int) { | 1000 | if (wdev->beacon_interval != beacon_int) { |
@@ -930,28 +1008,49 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
930 | return res; | 1008 | return res; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 1011 | int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, |
934 | struct wireless_dev *wdev, | 1012 | struct wireless_dev *wdev, |
935 | enum nl80211_iftype iftype) | 1013 | enum nl80211_iftype iftype, |
1014 | struct ieee80211_channel *chan, | ||
1015 | enum cfg80211_chan_mode chanmode) | ||
936 | { | 1016 | { |
937 | struct wireless_dev *wdev_iter; | 1017 | struct wireless_dev *wdev_iter; |
938 | u32 used_iftypes = BIT(iftype); | 1018 | u32 used_iftypes = BIT(iftype); |
939 | int num[NUM_NL80211_IFTYPES]; | 1019 | int num[NUM_NL80211_IFTYPES]; |
1020 | struct ieee80211_channel | ||
1021 | *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; | ||
1022 | struct ieee80211_channel *ch; | ||
1023 | enum cfg80211_chan_mode chmode; | ||
1024 | int num_different_channels = 0; | ||
940 | int total = 1; | 1025 | int total = 1; |
941 | int i, j; | 1026 | int i, j; |
942 | 1027 | ||
943 | ASSERT_RTNL(); | 1028 | ASSERT_RTNL(); |
1029 | lockdep_assert_held(&rdev->devlist_mtx); | ||
944 | 1030 | ||
945 | /* Always allow software iftypes */ | 1031 | /* Always allow software iftypes */ |
946 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1032 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
947 | return 0; | 1033 | return 0; |
948 | 1034 | ||
949 | memset(num, 0, sizeof(num)); | 1035 | memset(num, 0, sizeof(num)); |
1036 | memset(used_channels, 0, sizeof(used_channels)); | ||
950 | 1037 | ||
951 | num[iftype] = 1; | 1038 | num[iftype] = 1; |
952 | 1039 | ||
953 | mutex_lock(&rdev->devlist_mtx); | 1040 | switch (chanmode) { |
954 | list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { | 1041 | case CHAN_MODE_UNDEFINED: |
1042 | break; | ||
1043 | case CHAN_MODE_SHARED: | ||
1044 | WARN_ON(!chan); | ||
1045 | used_channels[0] = chan; | ||
1046 | num_different_channels++; | ||
1047 | break; | ||
1048 | case CHAN_MODE_EXCLUSIVE: | ||
1049 | num_different_channels++; | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
1053 | list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { | ||
955 | if (wdev_iter == wdev) | 1054 | if (wdev_iter == wdev) |
956 | continue; | 1055 | continue; |
957 | if (!netif_running(wdev_iter->netdev)) | 1056 | if (!netif_running(wdev_iter->netdev)) |
@@ -960,11 +1059,42 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
960 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) | 1059 | if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) |
961 | continue; | 1060 | continue; |
962 | 1061 | ||
1062 | /* | ||
1063 | * We may be holding the "wdev" mutex, but now need to lock | ||
1064 | * wdev_iter. This is OK because once we get here wdev_iter | ||
1065 | * is not wdev (tested above), but we need to use the nested | ||
1066 | * locking for lockdep. | ||
1067 | */ | ||
1068 | mutex_lock_nested(&wdev_iter->mtx, 1); | ||
1069 | __acquire(wdev_iter->mtx); | ||
1070 | cfg80211_get_chan_state(wdev_iter, &ch, &chmode); | ||
1071 | wdev_unlock(wdev_iter); | ||
1072 | |||
1073 | switch (chmode) { | ||
1074 | case CHAN_MODE_UNDEFINED: | ||
1075 | break; | ||
1076 | case CHAN_MODE_SHARED: | ||
1077 | for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) | ||
1078 | if (!used_channels[i] || used_channels[i] == ch) | ||
1079 | break; | ||
1080 | |||
1081 | if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) | ||
1082 | return -EBUSY; | ||
1083 | |||
1084 | if (used_channels[i] == NULL) { | ||
1085 | used_channels[i] = ch; | ||
1086 | num_different_channels++; | ||
1087 | } | ||
1088 | break; | ||
1089 | case CHAN_MODE_EXCLUSIVE: | ||
1090 | num_different_channels++; | ||
1091 | break; | ||
1092 | } | ||
1093 | |||
963 | num[wdev_iter->iftype]++; | 1094 | num[wdev_iter->iftype]++; |
964 | total++; | 1095 | total++; |
965 | used_iftypes |= BIT(wdev_iter->iftype); | 1096 | used_iftypes |= BIT(wdev_iter->iftype); |
966 | } | 1097 | } |
967 | mutex_unlock(&rdev->devlist_mtx); | ||
968 | 1098 | ||
969 | if (total == 1) | 1099 | if (total == 1) |
970 | return 0; | 1100 | return 0; |
@@ -976,12 +1106,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
976 | 1106 | ||
977 | c = &rdev->wiphy.iface_combinations[i]; | 1107 | c = &rdev->wiphy.iface_combinations[i]; |
978 | 1108 | ||
1109 | if (total > c->max_interfaces) | ||
1110 | continue; | ||
1111 | if (num_different_channels > c->num_different_channels) | ||
1112 | continue; | ||
1113 | |||
979 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, | 1114 | limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, |
980 | GFP_KERNEL); | 1115 | GFP_KERNEL); |
981 | if (!limits) | 1116 | if (!limits) |
982 | return -ENOMEM; | 1117 | return -ENOMEM; |
983 | if (total > c->max_interfaces) | ||
984 | goto cont; | ||
985 | 1118 | ||
986 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { | 1119 | for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { |
987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 1120 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |