diff options
Diffstat (limited to 'net/wireless/nl80211.c')
| -rw-r--r-- | net/wireless/nl80211.c | 143 | 
1 files changed, 133 insertions, 10 deletions
| diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c3bc9da30cff..45ba3d0872cc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -7501,6 +7501,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)  	static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];  	int err;  	bool need_new_beacon = false; +	bool need_handle_dfs_flag = true;  	int len, i;  	u32 cs_count; @@ -7512,6 +7513,12 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)  	case NL80211_IFTYPE_AP:  	case NL80211_IFTYPE_P2P_GO:  		need_new_beacon = true; +		/* For all modes except AP the handle_dfs flag needs to be +		 * supplied to tell the kernel that userspace will handle radar +		 * events when they happen. Otherwise a switch to a channel +		 * requiring DFS will be rejected. +		 */ +		need_handle_dfs_flag = false;  		/* useless if AP is not running */  		if (!wdev->beacon_interval) @@ -7634,8 +7641,13 @@ skip_beacons:  	if (err < 0)  		return err; -	if (err > 0) +	if (err > 0) {  		params.radar_required = true; +		if (need_handle_dfs_flag && +		    !nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS])) { +			return -EINVAL; +		} +	}  	if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])  		params.block_tx = true; @@ -8156,6 +8168,15 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,  		memcpy(settings->akm_suites, data, len);  	} +	if (info->attrs[NL80211_ATTR_PMK]) { +		if (nla_len(info->attrs[NL80211_ATTR_PMK]) != WLAN_PMK_LEN) +			return -EINVAL; +		if (!wiphy_ext_feature_isset(&rdev->wiphy, +					     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK)) +			return -EINVAL; +		settings->psk = nla_data(info->attrs[NL80211_ATTR_PMK]); +	} +  	return 0;  } @@ -8860,6 +8881,12 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)  	connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; +	if (info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS] && +	    !wiphy_ext_feature_isset(&rdev->wiphy, +				     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) +		return -EINVAL; +	connect.want_1x = info->attrs[NL80211_ATTR_WANT_1X_4WAY_HS]; +  	err = nl80211_crypto_settings(rdev, info, &connect.crypto,  				      NL80211_MAX_NR_CIPHER_SUITES);  	if (err) @@ -9962,6 +9989,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)  			return err;  	} +	setup.userspace_handles_dfs = +		nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); +  	return cfg80211_join_mesh(rdev, dev, &setup, &cfg);  } @@ -11176,10 +11206,6 @@ static int nl80211_nan_add_func(struct sk_buff *skb,  	if (!info->attrs[NL80211_ATTR_NAN_FUNC])  		return -EINVAL; -	if (wdev->owner_nlportid && -	    wdev->owner_nlportid != info->snd_portid) -		return -ENOTCONN; -  	err = nla_parse_nested(tb, NL80211_NAN_FUNC_ATTR_MAX,  			       info->attrs[NL80211_ATTR_NAN_FUNC],  			       nl80211_nan_func_policy, info->extack); @@ -11411,10 +11437,6 @@ static int nl80211_nan_del_func(struct sk_buff *skb,  	if (!info->attrs[NL80211_ATTR_COOKIE])  		return -EINVAL; -	if (wdev->owner_nlportid && -	    wdev->owner_nlportid != info->snd_portid) -		return -ENOTCONN; -  	cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);  	rdev_del_nan_func(rdev, wdev, cookie); @@ -12241,6 +12263,90 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,  	return rdev_set_multicast_to_unicast(rdev, dev, enabled);  } +static int nl80211_set_pmk(struct sk_buff *skb, struct genl_info *info) +{ +	struct cfg80211_registered_device *rdev = info->user_ptr[0]; +	struct net_device *dev = info->user_ptr[1]; +	struct wireless_dev *wdev = dev->ieee80211_ptr; +	struct cfg80211_pmk_conf pmk_conf = {}; +	int ret; + +	if (wdev->iftype != NL80211_IFTYPE_STATION && +	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) +		return -EOPNOTSUPP; + +	if (!wiphy_ext_feature_isset(&rdev->wiphy, +				     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) +		return -EOPNOTSUPP; + +	if (!info->attrs[NL80211_ATTR_MAC] || !info->attrs[NL80211_ATTR_PMK]) +		return -EINVAL; + +	wdev_lock(wdev); +	if (!wdev->current_bss) { +		ret = -ENOTCONN; +		goto out; +	} + +	pmk_conf.aa = nla_data(info->attrs[NL80211_ATTR_MAC]); +	if (memcmp(pmk_conf.aa, wdev->current_bss->pub.bssid, ETH_ALEN)) { +		ret = -EINVAL; +		goto out; +	} + +	pmk_conf.pmk = nla_data(info->attrs[NL80211_ATTR_PMK]); +	pmk_conf.pmk_len = nla_len(info->attrs[NL80211_ATTR_PMK]); +	if (pmk_conf.pmk_len != WLAN_PMK_LEN && +	    pmk_conf.pmk_len != WLAN_PMK_LEN_SUITE_B_192) { +		ret = -EINVAL; +		goto out; +	} + +	if (info->attrs[NL80211_ATTR_PMKR0_NAME]) { +		int r0_name_len = nla_len(info->attrs[NL80211_ATTR_PMKR0_NAME]); + +		if (r0_name_len != WLAN_PMK_NAME_LEN) { +			ret = -EINVAL; +			goto out; +		} + +		pmk_conf.pmk_r0_name = +			nla_data(info->attrs[NL80211_ATTR_PMKR0_NAME]); +	} + +	ret = rdev_set_pmk(rdev, dev, &pmk_conf); +out: +	wdev_unlock(wdev); +	return ret; +} + +static int nl80211_del_pmk(struct sk_buff *skb, struct genl_info *info) +{ +	struct cfg80211_registered_device *rdev = info->user_ptr[0]; +	struct net_device *dev = info->user_ptr[1]; +	struct wireless_dev *wdev = dev->ieee80211_ptr; +	const u8 *aa; +	int ret; + +	if (wdev->iftype != NL80211_IFTYPE_STATION && +	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) +		return -EOPNOTSUPP; + +	if (!wiphy_ext_feature_isset(&rdev->wiphy, +				     NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) +		return -EOPNOTSUPP; + +	if (!info->attrs[NL80211_ATTR_MAC]) +		return -EINVAL; + +	wdev_lock(wdev); +	aa = nla_data(info->attrs[NL80211_ATTR_MAC]); +	ret = rdev_del_pmk(rdev, dev, aa); +	wdev_unlock(wdev); + +	return ret; +} +  #define NL80211_FLAG_NEED_WIPHY		0x01  #define NL80211_FLAG_NEED_NETDEV	0x02  #define NL80211_FLAG_NEED_RTNL		0x04 @@ -13116,6 +13222,21 @@ static const struct genl_ops nl80211_ops[] = {  		.internal_flags = NL80211_FLAG_NEED_NETDEV |  				  NL80211_FLAG_NEED_RTNL,  	}, +	{ +		.cmd = NL80211_CMD_SET_PMK, +		.doit = nl80211_set_pmk, +		.policy = nl80211_policy, +		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | +				  NL80211_FLAG_NEED_RTNL, +	}, +	{ +		.cmd = NL80211_CMD_DEL_PMK, +		.doit = nl80211_del_pmk, +		.policy = nl80211_policy, +		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP | +				  NL80211_FLAG_NEED_RTNL, +	}, +  };  static struct genl_family nl80211_fam __ro_after_init = { @@ -13671,7 +13792,9 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,  		     info->req_ie)) ||  	    (info->resp_ie &&  	     nla_put(msg, NL80211_ATTR_RESP_IE, info->resp_ie_len, -		     info->resp_ie))) +		     info->resp_ie)) || +	    (info->authorized && +	     nla_put_flag(msg, NL80211_ATTR_PORT_AUTHORIZED)))  		goto nla_put_failure;  	genlmsg_end(msg, hdr); |