aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h32
-rw-r--r--net/mac80211/cfg.c43
-rw-r--r--net/mac80211/wext.c76
-rw-r--r--net/wireless/wext-compat.c63
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 */
821struct 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,
1581struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, 1606struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
1582 struct iw_freq *freq); 1607 struct iw_freq *freq);
1583 1608
1609int cfg80211_wext_siwrate(struct net_device *dev,
1610 struct iw_request_info *info,
1611 struct iw_param *rate, char *extra);
1612int cfg80211_wext_giwrate(struct net_device *dev,
1613 struct iw_request_info *info,
1614 struct iw_param *rate, char *extra);
1615
1584int cfg80211_wext_siwrts(struct net_device *dev, 1616int 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
1426static 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
1426struct cfg80211_ops mac80211_config_ops = { 1468struct 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
168static 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
205static 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 */
241static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) 169static 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}
1095EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap); 1095EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);
1096
1097int 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}
1121EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
1122
1123int 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}
1158EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate);