diff options
| author | Jouni Malinen <j@w1.fi> | 2009-04-20 18:39:05 +0200 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2009-04-22 16:57:17 -0400 | 
| commit | b9a5f8cab751d362f7c2d94899ca788c22fcd1ef (patch) | |
| tree | e769e2f59ef845cf7c7cc93b64d33eeed49bb9f7 | |
| parent | 9e52b0623c6eb49c3f23a326c1fb97bdecc49ba1 (diff) | |
| download | olio-linux-3.10-b9a5f8cab751d362f7c2d94899ca788c22fcd1ef.tar.xz olio-linux-3.10-b9a5f8cab751d362f7c2d94899ca788c22fcd1ef.zip  | |
nl80211: Add set/get for frag/rts threshold and retry limits
Add new nl80211 attributes that can be used with NL80211_CMD_SET_WIPHY
and NL80211_CMD_GET_WIPHY to manage fragmentation/RTS threshold and
retry limits.
Since these values are stored in struct wiphy, remove the local copy
from mac80211 where feasible (frag & rts threshold). The retry limits
are currently needed in struct ieee80211_conf, but these could be
eventually removed since the driver should have access to the values
in struct wiphy.
Signed-off-by: Jouni Malinen <j@w1.fi>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
| -rw-r--r-- | include/linux/nl80211.h | 24 | ||||
| -rw-r--r-- | include/net/cfg80211.h | 50 | ||||
| -rw-r--r-- | net/mac80211/cfg.c | 27 | ||||
| -rw-r--r-- | net/mac80211/debugfs.c | 8 | ||||
| -rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
| -rw-r--r-- | net/mac80211/main.c | 6 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 9 | ||||
| -rw-r--r-- | net/mac80211/util.c | 2 | ||||
| -rw-r--r-- | net/mac80211/wext.c | 138 | ||||
| -rw-r--r-- | net/wireless/core.c | 10 | ||||
| -rw-r--r-- | net/wireless/nl80211.c | 95 | ||||
| -rw-r--r-- | net/wireless/wext-compat.c | 151 | 
12 files changed, 372 insertions, 151 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 25ce3e42bd1..dc9d9ec5d1a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -46,8 +46,10 @@   *	to get a list of all present wiphys.   * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or   *	%NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, - *	%NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or - *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE. + *	%NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, + *	%NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, + *	%NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, + *	and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.   * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request   *	or rename notification. Has attributes %NL80211_ATTR_WIPHY and   *	%NL80211_ATTR_WIPHY_NAME. @@ -337,6 +339,18 @@ enum nl80211_commands {   *	NL80211_CHAN_HT20 = HT20 only   *	NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel   *	NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel + * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is + *	less than or equal to the RTS threshold; allowed range: 1..255; + *	dot11ShortRetryLimit; u8 + * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is + *	greater than the RTS threshold; allowed range: 1..255; + *	dot11ShortLongLimit; u8 + * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum + *	length in octets for frames; allowed range: 256..8000, disable + *	fragmentation with (u32)-1; dot11FragmentationThreshold; u32 + * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length + *	larger than or equal to this use RTS/CTS handshake); allowed range: + *	0..65536, disable with (u32)-1; dot11RTSThreshold; u32   *   * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on   * @NL80211_ATTR_IFNAME: network interface name @@ -565,6 +579,12 @@ enum nl80211_attrs {  	NL80211_ATTR_FREQ_FIXED, + +	NL80211_ATTR_WIPHY_RETRY_SHORT, +	NL80211_ATTR_WIPHY_RETRY_LONG, +	NL80211_ATTR_WIPHY_FRAG_THRESHOLD, +	NL80211_ATTR_WIPHY_RTS_THRESHOLD, +  	/* add attributes here, update the policy in nl80211.c */  	__NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 601eac64b02..54bc69c8369 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -744,6 +744,20 @@ struct cfg80211_ibss_params {  };  /** + * enum wiphy_params_flags - set_wiphy_params bitfield values + * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed + * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed + * WIPHY_PARAM_FRAG_THRESHOLD: wiphy->frag_threshold has changed + * WIPHY_PARAM_RTS_THRESHOLD: wiphy->rts_threshold has changed + */ +enum wiphy_params_flags { +	WIPHY_PARAM_RETRY_SHORT		= 1 << 0, +	WIPHY_PARAM_RETRY_LONG		= 1 << 1, +	WIPHY_PARAM_FRAG_THRESHOLD	= 1 << 2, +	WIPHY_PARAM_RTS_THRESHOLD	= 1 << 3, +}; + +/**   * struct cfg80211_ops - backend description for wireless configuration   *   * This struct is registered by fullmac card drivers and/or wireless stacks @@ -823,6 +837,11 @@ struct cfg80211_ibss_params {   *	cfg80211_ibss_joined(), also call that function when changing BSSID due   *	to a merge.   * @leave_ibss: Leave the IBSS. + * + * @set_wiphy_params: Notify that wiphy parameters have changed; + *	@changed bitfield (see &enum wiphy_params_flags) describes which values + *	have changed. The actual parameter values are available in + *	struct wiphy. If returning an error, no value should be changed.   */  struct cfg80211_ops {  	int	(*suspend)(struct wiphy *wiphy); @@ -912,6 +931,8 @@ struct cfg80211_ops {  	int	(*join_ibss)(struct wiphy *wiphy, struct net_device *dev,  			     struct cfg80211_ibss_params *params);  	int	(*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); + +	int	(*set_wiphy_params)(struct wiphy *wiphy, u32 changed);  };  /* @@ -945,6 +966,11 @@ struct cfg80211_ops {   * @signal_type: signal type reported in &struct cfg80211_bss.   * @cipher_suites: supported cipher suites   * @n_cipher_suites: number of supported cipher suites + * @retry_short: Retry limit for short frames (dot11ShortRetryLimit) + * @retry_long: Retry limit for long frames (dot11LongRetryLimit) + * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold); + *	-1 = fragmentation disabled, only odd values >= 256 used + * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled   */  struct wiphy {  	/* assign these fields before you register the wiphy */ @@ -967,6 +993,11 @@ struct wiphy {  	int n_cipher_suites;  	const u32 *cipher_suites; +	u8 retry_short; +	u8 retry_long; +	u32 frag_threshold; +	u32 rts_threshold; +  	/* If multiple wiphys are registered and you're handed e.g.  	 * a regular netdev with assigned ieee80211_ptr, you won't  	 * know whether it points to a wiphy your driver has registered @@ -1345,6 +1376,25 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,  struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,  					     struct iw_freq *freq); +int cfg80211_wext_siwrts(struct net_device *dev, +			 struct iw_request_info *info, +			 struct iw_param *rts, char *extra); +int cfg80211_wext_giwrts(struct net_device *dev, +			 struct iw_request_info *info, +			 struct iw_param *rts, char *extra); +int cfg80211_wext_siwfrag(struct net_device *dev, +			  struct iw_request_info *info, +			  struct iw_param *frag, char *extra); +int cfg80211_wext_giwfrag(struct net_device *dev, +			  struct iw_request_info *info, +			  struct iw_param *frag, char *extra); +int cfg80211_wext_siwretry(struct net_device *dev, +			   struct iw_request_info *info, +			   struct iw_param *retry, char *extra); +int cfg80211_wext_giwretry(struct net_device *dev, +			   struct iw_request_info *info, +			   struct iw_param *retry, char *extra); +  /*   * callbacks for asynchronous cfg80211 methods, notification   * functions and BSS handling helpers diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 14013dc6447..5e1c230744b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1298,6 +1298,32 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)  	return ieee80211_ibss_leave(sdata);  } +static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ +	struct ieee80211_local *local = wiphy_priv(wiphy); + +	if (changed & WIPHY_PARAM_RTS_THRESHOLD) { +		int err; + +		if (local->ops->set_rts_threshold) { +			err = local->ops->set_rts_threshold( +				local_to_hw(local), wiphy->rts_threshold); +			if (err) +				return err; +		} +	} + +	if (changed & WIPHY_PARAM_RETRY_SHORT) +		local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; +	if (changed & WIPHY_PARAM_RETRY_LONG) +		local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; +	if (changed & +	    (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG)) +		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); + +	return 0; +} +  struct cfg80211_ops mac80211_config_ops = {  	.add_virtual_intf = ieee80211_add_iface,  	.del_virtual_intf = ieee80211_del_iface, @@ -1336,4 +1362,5 @@ struct cfg80211_ops mac80211_config_ops = {  	.disassoc = ieee80211_disassoc,  	.join_ibss = ieee80211_join_ibss,  	.leave_ibss = ieee80211_leave_ibss, +	.set_wiphy_params = ieee80211_set_wiphy_params,  }; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 210b9b6fecd..5001328be46 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -52,13 +52,13 @@ static const struct file_operations name## _ops = {			\  DEBUGFS_READONLY_FILE(frequency, 20, "%d",  		      local->hw.conf.channel->center_freq);  DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", -		      local->rts_threshold); +		      local->hw.wiphy->rts_threshold);  DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", -		      local->fragmentation_threshold); +		      local->hw.wiphy->frag_threshold);  DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", -		      local->hw.conf.short_frame_max_tx_count); +		      local->hw.wiphy->retry_short);  DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", -		      local->hw.conf.long_frame_max_tx_count); +		      local->hw.wiphy->retry_long);  DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",  		      local->total_ps_buffered);  DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x", diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 92a573bf103..dba78d89a10 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -643,9 +643,6 @@ struct ieee80211_local {  	struct rate_control_ref *rate_ctrl; -	int rts_threshold; -	int fragmentation_threshold; -  	struct crypto_blkcipher *wep_tx_tfm;  	struct crypto_blkcipher *wep_rx_tfm;  	u32 wep_iv; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d26fc399285..5320e08434a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -776,10 +776,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  	/* set up some defaults */  	local->hw.queues = 1;  	local->hw.max_rates = 1; -	local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; -	local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; -	local->hw.conf.long_frame_max_tx_count = 4; -	local->hw.conf.short_frame_max_tx_count = 7; +	local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; +	local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;  	local->hw.conf.radio_enabled = true;  	INIT_LIST_HEAD(&local->interfaces); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c53d77db3e4..9ab49826c15 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -516,7 +516,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)  	sband = tx->local->hw.wiphy->bands[tx->channel->band];  	len = min_t(int, tx->skb->len + FCS_LEN, -			 tx->local->fragmentation_threshold); +			 tx->local->hw.wiphy->frag_threshold);  	/* set up the tx rate control struct we give the RC algo */  	txrc.hw = local_to_hw(tx->local); @@ -527,8 +527,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)  	txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;  	/* set up RTS protection if desired */ -	if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD && -	    len > tx->local->rts_threshold) { +	if (len > tx->local->hw.wiphy->rts_threshold) {  		txrc.rts = rts = true;  	} @@ -770,7 +769,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)  	struct sk_buff *skb = tx->skb;  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);  	struct ieee80211_hdr *hdr = (void *)skb->data; -	int frag_threshold = tx->local->fragmentation_threshold; +	int frag_threshold = tx->local->hw.wiphy->frag_threshold;  	int hdrlen;  	int fragnum; @@ -1088,7 +1087,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,  	if (tx->flags & IEEE80211_TX_FRAGMENTED) {  		if ((tx->flags & IEEE80211_TX_UNICAST) && -		    skb->len + FCS_LEN > local->fragmentation_threshold && +		    skb->len + FCS_LEN > local->hw.wiphy->frag_threshold &&  		    !(info->flags & IEEE80211_TX_CTL_AMPDU))  			tx->flags |= IEEE80211_TX_FRAGMENTED;  		else diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3dd490fa4b6..11244212f41 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1044,7 +1044,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)  	/* setup RTS threshold */  	if (local->ops->set_rts_threshold) -		local->ops->set_rts_threshold(hw, local->rts_threshold); +		local->ops->set_rts_threshold(hw, hw->wiphy->rts_threshold);  	/* reconfigure hardware */  	ieee80211_hw_config(local, ~0); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index eb63fc14801..1eb6d8642a7 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -472,132 +472,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev,  	return 0;  } -static int ieee80211_ioctl_siwrts(struct net_device *dev, -				  struct iw_request_info *info, -				  struct iw_param *rts, char *extra) -{ -	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - -	if (rts->disabled) -		local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; -	else if (!rts->fixed) -		/* if the rts value is not fixed, then take default */ -		local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; -	else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) -		return -EINVAL; -	else -		local->rts_threshold = rts->value; - -	/* If the wlan card performs RTS/CTS in hardware/firmware, -	 * configure it here */ - -	if (local->ops->set_rts_threshold) -		local->ops->set_rts_threshold(local_to_hw(local), -					     local->rts_threshold); - -	return 0; -} - -static int ieee80211_ioctl_giwrts(struct net_device *dev, -				  struct iw_request_info *info, -				  struct iw_param *rts, char *extra) -{ -	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - -	rts->value = local->rts_threshold; -	rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); -	rts->fixed = 1; - -	return 0; -} - - -static int ieee80211_ioctl_siwfrag(struct net_device *dev, -				   struct iw_request_info *info, -				   struct iw_param *frag, char *extra) -{ -	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - -	if (frag->disabled) -		local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; -	else if (!frag->fixed) -		local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; -	else if (frag->value < 256 || -		 frag->value > IEEE80211_MAX_FRAG_THRESHOLD) -		return -EINVAL; -	else { -		/* Fragment length must be even, so strip LSB. */ -		local->fragmentation_threshold = frag->value & ~0x1; -	} - -	return 0; -} - -static int ieee80211_ioctl_giwfrag(struct net_device *dev, -				   struct iw_request_info *info, -				   struct iw_param *frag, char *extra) -{ -	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - -	frag->value = local->fragmentation_threshold; -	frag->disabled = (frag->value >= IEEE80211_MAX_FRAG_THRESHOLD); -	frag->fixed = 1; - -	return 0; -} - - -static int ieee80211_ioctl_siwretry(struct net_device *dev, -				    struct iw_request_info *info, -				    struct iw_param *retry, char *extra) -{ -	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - -	if (retry->disabled || -	    (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) -		return -EINVAL; - -	if (retry->flags & IW_RETRY_MAX) { -		local->hw.conf.long_frame_max_tx_count = retry->value; -	} else if (retry->flags & IW_RETRY_MIN) { -		local->hw.conf.short_frame_max_tx_count = retry->value; -	} else { -		local->hw.conf.long_frame_max_tx_count = retry->value; -		local->hw.conf.short_frame_max_tx_count = retry->value; -	} - -	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); - -	return 0; -} - - -static int ieee80211_ioctl_giwretry(struct net_device *dev, -				    struct iw_request_info *info, -				    struct iw_param *retry, char *extra) -{ -	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - -	retry->disabled = 0; -	if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { -		/* first return min value, iwconfig will ask max value -		 * later if needed */ -		retry->flags |= IW_RETRY_LIMIT; -		retry->value = local->hw.conf.short_frame_max_tx_count; -		if (local->hw.conf.long_frame_max_tx_count != -		    local->hw.conf.short_frame_max_tx_count) -			retry->flags |= IW_RETRY_MIN; -		return 0; -	} -	if (retry->flags & IW_RETRY_MAX) { -		retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; -		retry->value = local->hw.conf.long_frame_max_tx_count; -	} - -	return 0; -} - -  static int ieee80211_ioctl_siwencode(struct net_device *dev,  				     struct iw_request_info *info,  				     struct iw_point *erq, char *keybuf) @@ -1050,14 +924,14 @@ static const iw_handler ieee80211_handler[] =  	(iw_handler) NULL,				/* -- hole -- */  	(iw_handler) ieee80211_ioctl_siwrate,		/* SIOCSIWRATE */  	(iw_handler) ieee80211_ioctl_giwrate,		/* SIOCGIWRATE */ -	(iw_handler) ieee80211_ioctl_siwrts,		/* SIOCSIWRTS */ -	(iw_handler) ieee80211_ioctl_giwrts,		/* SIOCGIWRTS */ -	(iw_handler) ieee80211_ioctl_siwfrag,		/* SIOCSIWFRAG */ -	(iw_handler) ieee80211_ioctl_giwfrag,		/* SIOCGIWFRAG */ +	(iw_handler) cfg80211_wext_siwrts,		/* SIOCSIWRTS */ +	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */ +	(iw_handler) cfg80211_wext_siwfrag,		/* SIOCSIWFRAG */ +	(iw_handler) cfg80211_wext_giwfrag,		/* SIOCGIWFRAG */  	(iw_handler) ieee80211_ioctl_siwtxpower,	/* SIOCSIWTXPOW */  	(iw_handler) ieee80211_ioctl_giwtxpower,	/* SIOCGIWTXPOW */ -	(iw_handler) ieee80211_ioctl_siwretry,		/* SIOCSIWRETRY */ -	(iw_handler) ieee80211_ioctl_giwretry,		/* SIOCGIWRETRY */ +	(iw_handler) cfg80211_wext_siwretry,		/* SIOCSIWRETRY */ +	(iw_handler) cfg80211_wext_giwretry,		/* SIOCGIWRETRY */  	(iw_handler) ieee80211_ioctl_siwencode,		/* SIOCSIWENCODE */  	(iw_handler) ieee80211_ioctl_giwencode,		/* SIOCGIWENCODE */  	(iw_handler) ieee80211_ioctl_siwpower,		/* SIOCSIWPOWER */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 827a5626355..f256b4f7e83 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -273,6 +273,16 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)  	drv->wiphy.dev.class = &ieee80211_class;  	drv->wiphy.dev.platform_data = drv; +	/* +	 * Initialize wiphy parameters to IEEE 802.11 MIB default values. +	 * Fragmentation and RTS threshold are disabled by default with the +	 * special -1 value. +	 */ +	drv->wiphy.retry_short = 7; +	drv->wiphy.retry_long = 4; +	drv->wiphy.frag_threshold = (u32) -1; +	drv->wiphy.rts_threshold = (u32) -1; +  	return &drv->wiphy;  }  EXPORT_SYMBOL(wiphy_new); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 16f86356ac9..5a9a5c6c71d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -61,6 +61,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {  	[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },  	[NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },  	[NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, +	[NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, +	[NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, +	[NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, +	[NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },  	[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },  	[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -204,6 +208,16 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,  	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);  	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + +	NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, +		   dev->wiphy.retry_short); +	NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, +		   dev->wiphy.retry_long); +	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, +		    dev->wiphy.frag_threshold); +	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, +		    dev->wiphy.rts_threshold); +  	NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,  		   dev->wiphy.max_scan_ssids);  	NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, @@ -416,6 +430,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)  	struct cfg80211_registered_device *rdev;  	int result = 0, rem_txq_params = 0;  	struct nlattr *nl_txq_params; +	u32 changed; +	u8 retry_short = 0, retry_long = 0; +	u32 frag_threshold = 0, rts_threshold = 0;  	rtnl_lock(); @@ -530,6 +547,84 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)  			goto bad_res;  	} +	changed = 0; + +	if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { +		retry_short = nla_get_u8( +			info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); +		if (retry_short == 0) { +			result = -EINVAL; +			goto bad_res; +		} +		changed |= WIPHY_PARAM_RETRY_SHORT; +	} + +	if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { +		retry_long = nla_get_u8( +			info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); +		if (retry_long == 0) { +			result = -EINVAL; +			goto bad_res; +		} +		changed |= WIPHY_PARAM_RETRY_LONG; +	} + +	if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { +		frag_threshold = nla_get_u32( +			info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); +		if (frag_threshold < 256) { +			result = -EINVAL; +			goto bad_res; +		} +		if (frag_threshold != (u32) -1) { +			/* +			 * Fragments (apart from the last one) are required to +			 * have even length. Make the fragmentation code +			 * simpler by stripping LSB should someone try to use +			 * odd threshold value. +			 */ +			frag_threshold &= ~0x1; +		} +		changed |= WIPHY_PARAM_FRAG_THRESHOLD; +	} + +	if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { +		rts_threshold = nla_get_u32( +			info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); +		changed |= WIPHY_PARAM_RTS_THRESHOLD; +	} + +	if (changed) { +		u8 old_retry_short, old_retry_long; +		u32 old_frag_threshold, old_rts_threshold; + +		if (!rdev->ops->set_wiphy_params) { +			result = -EOPNOTSUPP; +			goto bad_res; +		} + +		old_retry_short = rdev->wiphy.retry_short; +		old_retry_long = rdev->wiphy.retry_long; +		old_frag_threshold = rdev->wiphy.frag_threshold; +		old_rts_threshold = rdev->wiphy.rts_threshold; + +		if (changed & WIPHY_PARAM_RETRY_SHORT) +			rdev->wiphy.retry_short = retry_short; +		if (changed & WIPHY_PARAM_RETRY_LONG) +			rdev->wiphy.retry_long = retry_long; +		if (changed & WIPHY_PARAM_FRAG_THRESHOLD) +			rdev->wiphy.frag_threshold = frag_threshold; +		if (changed & WIPHY_PARAM_RTS_THRESHOLD) +			rdev->wiphy.rts_threshold = rts_threshold; + +		result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); +		if (result) { +			rdev->wiphy.retry_short = old_retry_short; +			rdev->wiphy.retry_long = old_retry_long; +			rdev->wiphy.frag_threshold = old_frag_threshold; +			rdev->wiphy.rts_threshold = old_rts_threshold; +		} +	}   bad_res:  	mutex_unlock(&rdev->mtx); diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 4e054ea9c0a..3279e7f038d 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -314,3 +314,154 @@ struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,  }  EXPORT_SYMBOL(cfg80211_wext_freq); + +int cfg80211_wext_siwrts(struct net_device *dev, +			 struct iw_request_info *info, +			 struct iw_param *rts, char *extra) +{ +	struct wireless_dev *wdev = dev->ieee80211_ptr; +	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); +	u32 orts = wdev->wiphy->rts_threshold; +	int err; + +	if (rts->disabled || !rts->fixed) +		wdev->wiphy->rts_threshold = (u32) -1; +	else if (rts->value < 0) +		return -EINVAL; +	else +		wdev->wiphy->rts_threshold = rts->value; + +	err = rdev->ops->set_wiphy_params(wdev->wiphy, +					  WIPHY_PARAM_RTS_THRESHOLD); +	if (err) +		wdev->wiphy->rts_threshold = orts; + +	return err; +} +EXPORT_SYMBOL(cfg80211_wext_siwrts); + +int cfg80211_wext_giwrts(struct net_device *dev, +			 struct iw_request_info *info, +			 struct iw_param *rts, char *extra) +{ +	struct wireless_dev *wdev = dev->ieee80211_ptr; + +	rts->value = wdev->wiphy->rts_threshold; +	rts->disabled = rts->value == (u32) -1; +	rts->fixed = 1; + +	return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwrts); + +int cfg80211_wext_siwfrag(struct net_device *dev, +			  struct iw_request_info *info, +			  struct iw_param *frag, char *extra) +{ +	struct wireless_dev *wdev = dev->ieee80211_ptr; +	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); +	u32 ofrag = wdev->wiphy->frag_threshold; +	int err; + +	if (frag->disabled || !frag->fixed) +		wdev->wiphy->frag_threshold = (u32) -1; +	else if (frag->value < 256) +		return -EINVAL; +	else { +		/* Fragment length must be even, so strip LSB. */ +		wdev->wiphy->frag_threshold = frag->value & ~0x1; +	} + +	err = rdev->ops->set_wiphy_params(wdev->wiphy, +					  WIPHY_PARAM_FRAG_THRESHOLD); +	if (err) +		wdev->wiphy->frag_threshold = ofrag; + +	return err; +} +EXPORT_SYMBOL(cfg80211_wext_siwfrag); + +int cfg80211_wext_giwfrag(struct net_device *dev, +			  struct iw_request_info *info, +			  struct iw_param *frag, char *extra) +{ +	struct wireless_dev *wdev = dev->ieee80211_ptr; + +	frag->value = wdev->wiphy->frag_threshold; +	frag->disabled = frag->value == (u32) -1; +	frag->fixed = 1; + +	return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwfrag); + +int cfg80211_wext_siwretry(struct net_device *dev, +			   struct iw_request_info *info, +			   struct iw_param *retry, char *extra) +{ +	struct wireless_dev *wdev = dev->ieee80211_ptr; +	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); +	u32 changed = 0; +	u8 olong = wdev->wiphy->retry_long; +	u8 oshort = wdev->wiphy->retry_short; +	int err; + +	if (retry->disabled || +	    (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) +		return -EINVAL; + +	if (retry->flags & IW_RETRY_LONG) { +		wdev->wiphy->retry_long = retry->value; +		changed |= WIPHY_PARAM_RETRY_LONG; +	} else if (retry->flags & IW_RETRY_SHORT) { +		wdev->wiphy->retry_short = retry->value; +		changed |= WIPHY_PARAM_RETRY_SHORT; +	} else { +		wdev->wiphy->retry_short = retry->value; +		wdev->wiphy->retry_long = retry->value; +		changed |= WIPHY_PARAM_RETRY_LONG; +		changed |= WIPHY_PARAM_RETRY_SHORT; +	} + +	if (!changed) +		return 0; + +	err = rdev->ops->set_wiphy_params(wdev->wiphy, changed); +	if (err) { +		wdev->wiphy->retry_short = oshort; +		wdev->wiphy->retry_long = olong; +	} + +	return err; +} +EXPORT_SYMBOL(cfg80211_wext_siwretry); + +int cfg80211_wext_giwretry(struct net_device *dev, +			   struct iw_request_info *info, +			   struct iw_param *retry, char *extra) +{ +	struct wireless_dev *wdev = dev->ieee80211_ptr; + +	retry->disabled = 0; + +	if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) { +		/* +		 * First return short value, iwconfig will ask long value +		 * later if needed +		 */ +		retry->flags |= IW_RETRY_LIMIT; +		retry->value = wdev->wiphy->retry_short; +		if (wdev->wiphy->retry_long != wdev->wiphy->retry_short) +			retry->flags |= IW_RETRY_LONG; + +		return 0; +	} + +	if (retry->flags & IW_RETRY_LONG) { +		retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; +		retry->value = wdev->wiphy->retry_long; +	} + +	return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwretry);  |