diff options
-rw-r--r-- | include/net/cfg80211.h | 32 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 43 | ||||
-rw-r--r-- | net/mac80211/wext.c | 76 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 63 |
4 files changed, 140 insertions, 74 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index b396d11564bc..579085564883 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -815,6 +815,26 @@ enum tx_power_setting { | |||
815 | TX_POWER_FIXED, | 815 | TX_POWER_FIXED, |
816 | }; | 816 | }; |
817 | 817 | ||
818 | /* | ||
819 | * cfg80211_bitrate_mask - masks for bitrate control | ||
820 | */ | ||
821 | struct cfg80211_bitrate_mask { | ||
822 | /* | ||
823 | * As discussed in Berlin, this struct really | ||
824 | * should look like this: | ||
825 | |||
826 | struct { | ||
827 | u32 legacy; | ||
828 | u8 mcs[IEEE80211_HT_MCS_MASK_LEN]; | ||
829 | } control[IEEE80211_NUM_BANDS]; | ||
830 | |||
831 | * Since we can always fix in-kernel users, let's keep | ||
832 | * it simpler for now: | ||
833 | */ | ||
834 | u32 fixed; /* fixed bitrate, 0 == not fixed */ | ||
835 | u32 maxrate; /* in kbps, 0 == no limit */ | ||
836 | }; | ||
837 | |||
818 | /** | 838 | /** |
819 | * struct cfg80211_ops - backend description for wireless configuration | 839 | * struct cfg80211_ops - backend description for wireless configuration |
820 | * | 840 | * |
@@ -1027,6 +1047,11 @@ struct cfg80211_ops { | |||
1027 | int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); | 1047 | int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len); |
1028 | #endif | 1048 | #endif |
1029 | 1049 | ||
1050 | int (*set_bitrate_mask)(struct wiphy *wiphy, | ||
1051 | struct net_device *dev, | ||
1052 | const u8 *peer, | ||
1053 | const struct cfg80211_bitrate_mask *mask); | ||
1054 | |||
1030 | /* some temporary stuff to finish wext */ | 1055 | /* some temporary stuff to finish wext */ |
1031 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, | 1056 | int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, |
1032 | bool enabled, int timeout); | 1057 | bool enabled, int timeout); |
@@ -1581,6 +1606,13 @@ int cfg80211_wext_giwauth(struct net_device *dev, | |||
1581 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, | 1606 | struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, |
1582 | struct iw_freq *freq); | 1607 | struct iw_freq *freq); |
1583 | 1608 | ||
1609 | int cfg80211_wext_siwrate(struct net_device *dev, | ||
1610 | struct iw_request_info *info, | ||
1611 | struct iw_param *rate, char *extra); | ||
1612 | int cfg80211_wext_giwrate(struct net_device *dev, | ||
1613 | struct iw_request_info *info, | ||
1614 | struct iw_param *rate, char *extra); | ||
1615 | |||
1584 | int cfg80211_wext_siwrts(struct net_device *dev, | 1616 | int cfg80211_wext_siwrts(struct net_device *dev, |
1585 | struct iw_request_info *info, | 1617 | struct iw_request_info *info, |
1586 | struct iw_param *rts, char *extra); | 1618 | struct iw_param *rts, char *extra); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2cf5bf6378e4..028f6430879d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1423,6 +1423,48 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
1423 | return 0; | 1423 | return 0; |
1424 | } | 1424 | } |
1425 | 1425 | ||
1426 | static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | ||
1427 | struct net_device *dev, | ||
1428 | const u8 *addr, | ||
1429 | const struct cfg80211_bitrate_mask *mask) | ||
1430 | { | ||
1431 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1432 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1433 | int i, err = -EINVAL; | ||
1434 | u32 target_rate; | ||
1435 | struct ieee80211_supported_band *sband; | ||
1436 | |||
1437 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1438 | |||
1439 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
1440 | * target_rate = X, rate->fixed = 1 means only rate X | ||
1441 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
1442 | sdata->max_ratectrl_rateidx = -1; | ||
1443 | sdata->force_unicast_rateidx = -1; | ||
1444 | |||
1445 | if (mask->fixed) | ||
1446 | target_rate = mask->fixed / 100; | ||
1447 | else if (mask->maxrate) | ||
1448 | target_rate = mask->maxrate / 100; | ||
1449 | else | ||
1450 | return 0; | ||
1451 | |||
1452 | for (i=0; i< sband->n_bitrates; i++) { | ||
1453 | struct ieee80211_rate *brate = &sband->bitrates[i]; | ||
1454 | int this_rate = brate->bitrate; | ||
1455 | |||
1456 | if (target_rate == this_rate) { | ||
1457 | sdata->max_ratectrl_rateidx = i; | ||
1458 | if (mask->fixed) | ||
1459 | sdata->force_unicast_rateidx = i; | ||
1460 | err = 0; | ||
1461 | break; | ||
1462 | } | ||
1463 | } | ||
1464 | |||
1465 | return err; | ||
1466 | } | ||
1467 | |||
1426 | struct cfg80211_ops mac80211_config_ops = { | 1468 | struct cfg80211_ops mac80211_config_ops = { |
1427 | .add_virtual_intf = ieee80211_add_iface, | 1469 | .add_virtual_intf = ieee80211_add_iface, |
1428 | .del_virtual_intf = ieee80211_del_iface, | 1470 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1468,4 +1510,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1468 | .rfkill_poll = ieee80211_rfkill_poll, | 1510 | .rfkill_poll = ieee80211_rfkill_poll, |
1469 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) | 1511 | CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) |
1470 | .set_power_mgmt = ieee80211_set_power_mgmt, | 1512 | .set_power_mgmt = ieee80211_set_power_mgmt, |
1513 | .set_bitrate_mask = ieee80211_set_bitrate_mask, | ||
1471 | }; | 1514 | }; |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 4053d766af2d..244d830f5cfb 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -165,78 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
165 | } | 165 | } |
166 | 166 | ||
167 | 167 | ||
168 | static int ieee80211_ioctl_siwrate(struct net_device *dev, | ||
169 | struct iw_request_info *info, | ||
170 | struct iw_param *rate, char *extra) | ||
171 | { | ||
172 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
173 | int i, err = -EINVAL; | ||
174 | u32 target_rate = rate->value / 100000; | ||
175 | struct ieee80211_sub_if_data *sdata; | ||
176 | struct ieee80211_supported_band *sband; | ||
177 | |||
178 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
179 | |||
180 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
181 | |||
182 | /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates | ||
183 | * target_rate = X, rate->fixed = 1 means only rate X | ||
184 | * target_rate = X, rate->fixed = 0 means all rates <= X */ | ||
185 | sdata->max_ratectrl_rateidx = -1; | ||
186 | sdata->force_unicast_rateidx = -1; | ||
187 | if (rate->value < 0) | ||
188 | return 0; | ||
189 | |||
190 | for (i=0; i< sband->n_bitrates; i++) { | ||
191 | struct ieee80211_rate *brate = &sband->bitrates[i]; | ||
192 | int this_rate = brate->bitrate; | ||
193 | |||
194 | if (target_rate == this_rate) { | ||
195 | sdata->max_ratectrl_rateidx = i; | ||
196 | if (rate->fixed) | ||
197 | sdata->force_unicast_rateidx = i; | ||
198 | err = 0; | ||
199 | break; | ||
200 | } | ||
201 | } | ||
202 | return err; | ||
203 | } | ||
204 | |||
205 | static int ieee80211_ioctl_giwrate(struct net_device *dev, | ||
206 | struct iw_request_info *info, | ||
207 | struct iw_param *rate, char *extra) | ||
208 | { | ||
209 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
210 | struct sta_info *sta; | ||
211 | struct ieee80211_sub_if_data *sdata; | ||
212 | struct ieee80211_supported_band *sband; | ||
213 | |||
214 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
215 | |||
216 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
217 | return -EOPNOTSUPP; | ||
218 | |||
219 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
220 | |||
221 | rcu_read_lock(); | ||
222 | |||
223 | sta = sta_info_get(local, sdata->u.mgd.bssid); | ||
224 | |||
225 | if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) | ||
226 | rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; | ||
227 | else | ||
228 | rate->value = 0; | ||
229 | |||
230 | rcu_read_unlock(); | ||
231 | |||
232 | if (!sta) | ||
233 | return -ENODEV; | ||
234 | |||
235 | rate->value *= 100000; | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ | 168 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ |
241 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) | 169 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) |
242 | { | 170 | { |
@@ -340,8 +268,8 @@ static const iw_handler ieee80211_handler[] = | |||
340 | (iw_handler) NULL, /* SIOCGIWNICKN */ | 268 | (iw_handler) NULL, /* SIOCGIWNICKN */ |
341 | (iw_handler) NULL, /* -- hole -- */ | 269 | (iw_handler) NULL, /* -- hole -- */ |
342 | (iw_handler) NULL, /* -- hole -- */ | 270 | (iw_handler) NULL, /* -- hole -- */ |
343 | (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ | 271 | (iw_handler) cfg80211_wext_siwrate, /* SIOCSIWRATE */ |
344 | (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ | 272 | (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */ |
345 | (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ | 273 | (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ |
346 | (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ | 274 | (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ |
347 | (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ | 275 | (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 2f72dae2634f..3a5f999703f1 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1093,3 +1093,66 @@ int cfg80211_wds_wext_giwap(struct net_device *dev, | |||
1093 | return 0; | 1093 | return 0; |
1094 | } | 1094 | } |
1095 | EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); | 1095 | EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); |
1096 | |||
1097 | int cfg80211_wext_siwrate(struct net_device *dev, | ||
1098 | struct iw_request_info *info, | ||
1099 | struct iw_param *rate, char *extra) | ||
1100 | { | ||
1101 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1102 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
1103 | struct cfg80211_bitrate_mask mask; | ||
1104 | |||
1105 | if (!rdev->ops->set_bitrate_mask) | ||
1106 | return -EOPNOTSUPP; | ||
1107 | |||
1108 | mask.fixed = 0; | ||
1109 | mask.maxrate = 0; | ||
1110 | |||
1111 | if (rate->value < 0) { | ||
1112 | /* nothing */ | ||
1113 | } else if (rate->fixed) { | ||
1114 | mask.fixed = rate->value / 1000; /* kbps */ | ||
1115 | } else { | ||
1116 | mask.maxrate = rate->value / 1000; /* kbps */ | ||
1117 | } | ||
1118 | |||
1119 | return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask); | ||
1120 | } | ||
1121 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate); | ||
1122 | |||
1123 | int cfg80211_wext_giwrate(struct net_device *dev, | ||
1124 | struct iw_request_info *info, | ||
1125 | struct iw_param *rate, char *extra) | ||
1126 | { | ||
1127 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1128 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
1129 | /* we are under RTNL - globally locked - so can use a static struct */ | ||
1130 | static struct station_info sinfo; | ||
1131 | u8 *addr; | ||
1132 | int err; | ||
1133 | |||
1134 | if (wdev->iftype != NL80211_IFTYPE_STATION) | ||
1135 | return -EOPNOTSUPP; | ||
1136 | |||
1137 | if (!rdev->ops->get_station) | ||
1138 | return -EOPNOTSUPP; | ||
1139 | |||
1140 | addr = wdev->wext.connect.bssid; | ||
1141 | if (!addr) | ||
1142 | return -EOPNOTSUPP; | ||
1143 | |||
1144 | err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo); | ||
1145 | if (err) | ||
1146 | return err; | ||
1147 | |||
1148 | if (!(sinfo.filled & STATION_INFO_TX_BITRATE)) | ||
1149 | return -EOPNOTSUPP; | ||
1150 | |||
1151 | rate->value = 0; | ||
1152 | |||
1153 | if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS)) | ||
1154 | rate->value = 100000 * sinfo.txrate.legacy; | ||
1155 | |||
1156 | return 0; | ||
1157 | } | ||
1158 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate); | ||