mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	cfg80211: implement IWRATE
For now, let's implement that using a very hackish way: simply mirror the wext API in the cfg80211 API. This will have to be changed later when we implement proper bitrate API. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
		
							parent
							
								
									ab737a4f7d
								
							
						
					
					
						commit
						9930380f0b
					
				
					 4 changed files with 140 additions and 74 deletions
				
			
		| 
						 | 
				
			
			@ -815,6 +815,26 @@ enum tx_power_setting {
 | 
			
		|||
	TX_POWER_FIXED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cfg80211_bitrate_mask - masks for bitrate control
 | 
			
		||||
 */
 | 
			
		||||
struct cfg80211_bitrate_mask {
 | 
			
		||||
/*
 | 
			
		||||
 * As discussed in Berlin, this struct really
 | 
			
		||||
 * should look like this:
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		u32 legacy;
 | 
			
		||||
		u8 mcs[IEEE80211_HT_MCS_MASK_LEN];
 | 
			
		||||
	} control[IEEE80211_NUM_BANDS];
 | 
			
		||||
 | 
			
		||||
 * Since we can always fix in-kernel users, let's keep
 | 
			
		||||
 * it simpler for now:
 | 
			
		||||
 */
 | 
			
		||||
	u32 fixed;   /* fixed bitrate, 0 == not fixed */
 | 
			
		||||
	u32 maxrate; /* in kbps, 0 == no limit */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct cfg80211_ops - backend description for wireless configuration
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -1027,6 +1047,11 @@ struct cfg80211_ops {
 | 
			
		|||
	int	(*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	int	(*set_bitrate_mask)(struct wiphy *wiphy,
 | 
			
		||||
				    struct net_device *dev,
 | 
			
		||||
				    const u8 *peer,
 | 
			
		||||
				    const struct cfg80211_bitrate_mask *mask);
 | 
			
		||||
 | 
			
		||||
	/* some temporary stuff to finish wext */
 | 
			
		||||
	int	(*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
 | 
			
		||||
				  bool enabled, int timeout);
 | 
			
		||||
| 
						 | 
				
			
			@ -1581,6 +1606,13 @@ int cfg80211_wext_giwauth(struct net_device *dev,
 | 
			
		|||
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
 | 
			
		||||
					     struct iw_freq *freq);
 | 
			
		||||
 | 
			
		||||
int cfg80211_wext_siwrate(struct net_device *dev,
 | 
			
		||||
			  struct iw_request_info *info,
 | 
			
		||||
			  struct iw_param *rate, char *extra);
 | 
			
		||||
int cfg80211_wext_giwrate(struct net_device *dev,
 | 
			
		||||
			  struct iw_request_info *info,
 | 
			
		||||
			  struct iw_param *rate, char *extra);
 | 
			
		||||
 | 
			
		||||
int cfg80211_wext_siwrts(struct net_device *dev,
 | 
			
		||||
			 struct iw_request_info *info,
 | 
			
		||||
			 struct iw_param *rts, char *extra);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1423,6 +1423,48 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 | 
			
		||||
				      struct net_device *dev,
 | 
			
		||||
				      const u8 *addr,
 | 
			
		||||
				      const struct cfg80211_bitrate_mask *mask)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
			
		||||
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 | 
			
		||||
	int i, err = -EINVAL;
 | 
			
		||||
	u32 target_rate;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
 | 
			
		||||
	/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
 | 
			
		||||
	 * target_rate = X, rate->fixed = 1 means only rate X
 | 
			
		||||
	 * target_rate = X, rate->fixed = 0 means all rates <= X */
 | 
			
		||||
	sdata->max_ratectrl_rateidx = -1;
 | 
			
		||||
	sdata->force_unicast_rateidx = -1;
 | 
			
		||||
 | 
			
		||||
	if (mask->fixed)
 | 
			
		||||
		target_rate = mask->fixed / 100;
 | 
			
		||||
	else if (mask->maxrate)
 | 
			
		||||
		target_rate = mask->maxrate / 100;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	for (i=0; i< sband->n_bitrates; i++) {
 | 
			
		||||
		struct ieee80211_rate *brate = &sband->bitrates[i];
 | 
			
		||||
		int this_rate = brate->bitrate;
 | 
			
		||||
 | 
			
		||||
		if (target_rate == this_rate) {
 | 
			
		||||
			sdata->max_ratectrl_rateidx = i;
 | 
			
		||||
			if (mask->fixed)
 | 
			
		||||
				sdata->force_unicast_rateidx = i;
 | 
			
		||||
			err = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cfg80211_ops mac80211_config_ops = {
 | 
			
		||||
	.add_virtual_intf = ieee80211_add_iface,
 | 
			
		||||
	.del_virtual_intf = ieee80211_del_iface,
 | 
			
		||||
| 
						 | 
				
			
			@ -1468,4 +1510,5 @@ struct cfg80211_ops mac80211_config_ops = {
 | 
			
		|||
	.rfkill_poll = ieee80211_rfkill_poll,
 | 
			
		||||
	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
 | 
			
		||||
	.set_power_mgmt = ieee80211_set_power_mgmt,
 | 
			
		||||
	.set_bitrate_mask = ieee80211_set_bitrate_mask,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -165,78 +165,6 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int ieee80211_ioctl_siwrate(struct net_device *dev,
 | 
			
		||||
				  struct iw_request_info *info,
 | 
			
		||||
				  struct iw_param *rate, char *extra)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 | 
			
		||||
	int i, err = -EINVAL;
 | 
			
		||||
	u32 target_rate = rate->value / 100000;
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
 | 
			
		||||
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
			
		||||
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
 | 
			
		||||
	/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
 | 
			
		||||
	 * target_rate = X, rate->fixed = 1 means only rate X
 | 
			
		||||
	 * target_rate = X, rate->fixed = 0 means all rates <= X */
 | 
			
		||||
	sdata->max_ratectrl_rateidx = -1;
 | 
			
		||||
	sdata->force_unicast_rateidx = -1;
 | 
			
		||||
	if (rate->value < 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	for (i=0; i< sband->n_bitrates; i++) {
 | 
			
		||||
		struct ieee80211_rate *brate = &sband->bitrates[i];
 | 
			
		||||
		int this_rate = brate->bitrate;
 | 
			
		||||
 | 
			
		||||
		if (target_rate == this_rate) {
 | 
			
		||||
			sdata->max_ratectrl_rateidx = i;
 | 
			
		||||
			if (rate->fixed)
 | 
			
		||||
				sdata->force_unicast_rateidx = i;
 | 
			
		||||
			err = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ieee80211_ioctl_giwrate(struct net_device *dev,
 | 
			
		||||
				  struct iw_request_info *info,
 | 
			
		||||
				  struct iw_param *rate, char *extra)
 | 
			
		||||
{
 | 
			
		||||
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 | 
			
		||||
	struct sta_info *sta;
 | 
			
		||||
	struct ieee80211_sub_if_data *sdata;
 | 
			
		||||
	struct ieee80211_supported_band *sband;
 | 
			
		||||
 | 
			
		||||
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 | 
			
		||||
 | 
			
		||||
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
 | 
			
		||||
	sta = sta_info_get(local, sdata->u.mgd.bssid);
 | 
			
		||||
 | 
			
		||||
	if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
 | 
			
		||||
		rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
 | 
			
		||||
	else
 | 
			
		||||
		rate->value = 0;
 | 
			
		||||
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
 | 
			
		||||
	if (!sta)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	rate->value *= 100000;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
 | 
			
		||||
static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -340,8 +268,8 @@ static const iw_handler ieee80211_handler[] =
 | 
			
		|||
	(iw_handler) NULL,				/* SIOCGIWNICKN */
 | 
			
		||||
	(iw_handler) NULL,				/* -- hole -- */
 | 
			
		||||
	(iw_handler) NULL,				/* -- hole -- */
 | 
			
		||||
	(iw_handler) ieee80211_ioctl_siwrate,		/* SIOCSIWRATE */
 | 
			
		||||
	(iw_handler) ieee80211_ioctl_giwrate,		/* SIOCGIWRATE */
 | 
			
		||||
	(iw_handler) cfg80211_wext_siwrate,		/* SIOCSIWRATE */
 | 
			
		||||
	(iw_handler) cfg80211_wext_giwrate,		/* SIOCGIWRATE */
 | 
			
		||||
	(iw_handler) cfg80211_wext_siwrts,		/* SIOCSIWRTS */
 | 
			
		||||
	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */
 | 
			
		||||
	(iw_handler) cfg80211_wext_siwfrag,		/* SIOCSIWFRAG */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1093,3 +1093,66 @@ int cfg80211_wds_wext_giwap(struct net_device *dev,
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(cfg80211_wds_wext_giwap);
 | 
			
		||||
 | 
			
		||||
int cfg80211_wext_siwrate(struct net_device *dev,
 | 
			
		||||
			  struct iw_request_info *info,
 | 
			
		||||
			  struct iw_param *rate, char *extra)
 | 
			
		||||
{
 | 
			
		||||
	struct wireless_dev *wdev = dev->ieee80211_ptr;
 | 
			
		||||
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 | 
			
		||||
	struct cfg80211_bitrate_mask mask;
 | 
			
		||||
 | 
			
		||||
	if (!rdev->ops->set_bitrate_mask)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	mask.fixed = 0;
 | 
			
		||||
	mask.maxrate = 0;
 | 
			
		||||
 | 
			
		||||
	if (rate->value < 0) {
 | 
			
		||||
		/* nothing */
 | 
			
		||||
	} else if (rate->fixed) {
 | 
			
		||||
		mask.fixed = rate->value / 1000; /* kbps */
 | 
			
		||||
	} else {
 | 
			
		||||
		mask.maxrate = rate->value / 1000; /* kbps */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return rdev->ops->set_bitrate_mask(wdev->wiphy, dev, NULL, &mask);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwrate);
 | 
			
		||||
 | 
			
		||||
int cfg80211_wext_giwrate(struct net_device *dev,
 | 
			
		||||
			  struct iw_request_info *info,
 | 
			
		||||
			  struct iw_param *rate, char *extra)
 | 
			
		||||
{
 | 
			
		||||
	struct wireless_dev *wdev = dev->ieee80211_ptr;
 | 
			
		||||
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 | 
			
		||||
	/* we are under RTNL - globally locked - so can use a static struct */
 | 
			
		||||
	static struct station_info sinfo;
 | 
			
		||||
	u8 *addr;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (wdev->iftype != NL80211_IFTYPE_STATION)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	if (!rdev->ops->get_station)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	addr = wdev->wext.connect.bssid;
 | 
			
		||||
	if (!addr)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	err = rdev->ops->get_station(&rdev->wiphy, dev, addr, &sinfo);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	rate->value = 0;
 | 
			
		||||
 | 
			
		||||
	if (!(sinfo.txrate.flags & RATE_INFO_FLAGS_MCS))
 | 
			
		||||
		rate->value = 100000 * sinfo.txrate.legacy;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(cfg80211_wext_giwrate);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue