diff options
Diffstat (limited to 'net/mac80211/cfg.c')
| -rw-r--r-- | net/mac80211/cfg.c | 124 | 
1 files changed, 81 insertions, 43 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 67ee34f57df..29ac8e1a509 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -120,6 +120,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,  	struct ieee80211_key *key;  	int err; +	if (!netif_running(dev)) +		return -ENETDOWN; +  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);  	switch (params->cipher) { @@ -140,17 +143,22 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,  		return -EINVAL;  	} +	/* reject WEP and TKIP keys if WEP failed to initialize */ +	if ((alg == ALG_WEP || alg == ALG_TKIP) && +	    IS_ERR(sdata->local->wep_tx_tfm)) +		return -EINVAL; +  	key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,  				  params->seq_len, params->seq);  	if (!key)  		return -ENOMEM; -	rcu_read_lock(); +	mutex_lock(&sdata->local->sta_mtx);  	if (mac_addr) {  		sta = sta_info_get_bss(sdata, mac_addr);  		if (!sta) { -			ieee80211_key_free(key); +			ieee80211_key_free(sdata->local, key);  			err = -ENOENT;  			goto out_unlock;  		} @@ -160,7 +168,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,  	err = 0;   out_unlock: -	rcu_read_unlock(); +	mutex_unlock(&sdata->local->sta_mtx);  	return err;  } @@ -174,7 +182,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,  	sdata = IEEE80211_DEV_TO_SUB_IF(dev); -	rcu_read_lock(); +	mutex_lock(&sdata->local->sta_mtx);  	if (mac_addr) {  		ret = -ENOENT; @@ -184,7 +192,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,  			goto out_unlock;  		if (sta->key) { -			ieee80211_key_free(sta->key); +			ieee80211_key_free(sdata->local, sta->key);  			WARN_ON(sta->key);  			ret = 0;  		} @@ -197,12 +205,12 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,  		goto out_unlock;  	} -	ieee80211_key_free(sdata->keys[key_idx]); +	ieee80211_key_free(sdata->local, sdata->keys[key_idx]);  	WARN_ON(sdata->keys[key_idx]);  	ret = 0;   out_unlock: -	rcu_read_unlock(); +	mutex_unlock(&sdata->local->sta_mtx);  	return ret;  } @@ -305,15 +313,10 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,  					struct net_device *dev,  					u8 key_idx)  { -	struct ieee80211_sub_if_data *sdata; - -	rcu_read_lock(); +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -	sdata = IEEE80211_DEV_TO_SUB_IF(dev);  	ieee80211_set_default_key(sdata, key_idx); -	rcu_read_unlock(); -  	return 0;  } @@ -321,15 +324,10 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,  					     struct net_device *dev,  					     u8 key_idx)  { -	struct ieee80211_sub_if_data *sdata; - -	rcu_read_lock(); +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -	sdata = IEEE80211_DEV_TO_SUB_IF(dev);  	ieee80211_set_default_mgmt_key(sdata, key_idx); -	rcu_read_unlock(); -  	return 0;  } @@ -415,9 +413,6 @@ static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,  {  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -	if (!local->ops->get_survey) -		return -EOPNOTSUPP; -  	return drv_get_survey(local, idx, survey);  } @@ -600,7 +595,7 @@ struct iapp_layer2_update {  	u8 ssap;		/* 0 */  	u8 control;  	u8 xid_info[3]; -} __attribute__ ((packed)); +} __packed;  static void ieee80211_send_layer2_update(struct sta_info *sta)  { @@ -1154,10 +1149,6 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,  		return -EINVAL;  	} -	/* enable WMM or activate new settings */ -	local->hw.conf.flags |= IEEE80211_CONF_QOS; -	drv_config(local, IEEE80211_CONF_CHANGE_QOS); -  	return 0;  } @@ -1331,28 +1322,28 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)  }  static int ieee80211_set_tx_power(struct wiphy *wiphy, -				  enum tx_power_setting type, int dbm) +				  enum nl80211_tx_power_setting type, int mbm)  {  	struct ieee80211_local *local = wiphy_priv(wiphy);  	struct ieee80211_channel *chan = local->hw.conf.channel;  	u32 changes = 0;  	switch (type) { -	case TX_POWER_AUTOMATIC: +	case NL80211_TX_POWER_AUTOMATIC:  		local->user_power_level = -1;  		break; -	case TX_POWER_LIMITED: -		if (dbm < 0) -			return -EINVAL; -		local->user_power_level = dbm; +	case NL80211_TX_POWER_LIMITED: +		if (mbm < 0 || (mbm % 100)) +			return -EOPNOTSUPP; +		local->user_power_level = MBM_TO_DBM(mbm);  		break; -	case TX_POWER_FIXED: -		if (dbm < 0) -			return -EINVAL; +	case NL80211_TX_POWER_FIXED: +		if (mbm < 0 || (mbm % 100)) +			return -EOPNOTSUPP;  		/* TODO: move to cfg80211 when it knows the channel */ -		if (dbm > chan->max_power) +		if (MBM_TO_DBM(mbm) > chan->max_power)  			return -EINVAL; -		local->user_power_level = dbm; +		local->user_power_level = MBM_TO_DBM(mbm);  		break;  	} @@ -1448,7 +1439,6 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,  {  	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);  	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); -	struct ieee80211_conf *conf = &local->hw.conf;  	if (sdata->vif.type != NL80211_IFTYPE_STATION)  		return -EOPNOTSUPP; @@ -1457,11 +1447,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,  		return -EOPNOTSUPP;  	if (enabled == sdata->u.mgd.powersave && -	    timeout == conf->dynamic_ps_forced_timeout) +	    timeout == local->dynamic_ps_forced_timeout)  		return 0;  	sdata->u.mgd.powersave = enabled; -	conf->dynamic_ps_forced_timeout = timeout; +	local->dynamic_ps_forced_timeout = timeout;  	/* no change, but if automatic follow powersave */  	mutex_lock(&sdata->u.mgd.mtx); @@ -1554,10 +1544,58 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,  static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,  			    struct ieee80211_channel *chan,  			    enum nl80211_channel_type channel_type, +			    bool channel_type_valid,  			    const u8 *buf, size_t len, u64 *cookie)  { -	return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan, -				    channel_type, buf, len, cookie); +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +	struct ieee80211_local *local = sdata->local; +	struct sk_buff *skb; +	struct sta_info *sta; +	const struct ieee80211_mgmt *mgmt = (void *)buf; +	u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | +		    IEEE80211_TX_CTL_REQ_TX_STATUS; + +	/* Check that we are on the requested channel for transmission */ +	if (chan != local->tmp_channel && +	    chan != local->oper_channel) +		return -EBUSY; +	if (channel_type_valid && +	    (channel_type != local->tmp_channel_type && +	     channel_type != local->_oper_channel_type)) +		return -EBUSY; + +	switch (sdata->vif.type) { +	case NL80211_IFTYPE_ADHOC: +		if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) +			break; +		rcu_read_lock(); +		sta = sta_info_get(sdata, mgmt->da); +		rcu_read_unlock(); +		if (!sta) +			return -ENOLINK; +		break; +	case NL80211_IFTYPE_STATION: +		if (!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED)) +			flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +		break; +	default: +		return -EOPNOTSUPP; +	} + +	skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); +	if (!skb) +		return -ENOMEM; +	skb_reserve(skb, local->hw.extra_tx_headroom); + +	memcpy(skb_put(skb, len), buf, len); + +	IEEE80211_SKB_CB(skb)->flags = flags; + +	skb->dev = sdata->dev; +	ieee80211_tx_skb(sdata, skb); + +	*cookie = (unsigned long) skb; +	return 0;  }  struct cfg80211_ops mac80211_config_ops = {  |