Commit 9e263e19 authored by Johannes Berg's avatar Johannes Berg
Browse files

nl80211: don't put struct cfg80211_ap_settings on stack

This struct has grown quite a bit, so dynamically allocate
it instead of putting it on the stack.

Link: https://lore.kernel.org/r/20210923161836.5813d881eae3.I0fc0f83905b0bfa332c4f1505e00c13abfca3545@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 5d24828d
Loading
Loading
Loading
Loading
+108 −78
Original line number Diff line number Diff line
@@ -5323,7 +5323,7 @@ static int nl80211_start_ap(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_ap_settings params;
	struct cfg80211_ap_settings *params;
	int err;

	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
@@ -5336,27 +5336,29 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
	if (wdev->beacon_interval)
		return -EALREADY;

	memset(&params, 0, sizeof(params));

	/* these are required for START_AP */
	if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
	    !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
	    !info->attrs[NL80211_ATTR_BEACON_HEAD])
		return -EINVAL;

	err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon);
	params = kzalloc(sizeof(*params), GFP_KERNEL);
	if (!params)
		return -ENOMEM;

	err = nl80211_parse_beacon(rdev, info->attrs, &params->beacon);
	if (err)
		return err;
		goto out;

	params.beacon_interval =
	params->beacon_interval =
		nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
	params.dtim_period =
	params->dtim_period =
		nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);

	err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
					   params.beacon_interval);
					   params->beacon_interval);
	if (err)
		return err;
		goto out;

	/*
	 * In theory, some of these attributes should be required here
@@ -5366,129 +5368,156 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
	 * additional information -- drivers must check!
	 */
	if (info->attrs[NL80211_ATTR_SSID]) {
		params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
		params.ssid_len =
		params->ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
		params->ssid_len =
			nla_len(info->attrs[NL80211_ATTR_SSID]);
		if (params.ssid_len == 0)
			return -EINVAL;
		if (params->ssid_len == 0) {
			err = -EINVAL;
			goto out;
		}
	}

	if (info->attrs[NL80211_ATTR_HIDDEN_SSID])
		params.hidden_ssid = nla_get_u32(
		params->hidden_ssid = nla_get_u32(
			info->attrs[NL80211_ATTR_HIDDEN_SSID]);

	params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
	params->privacy = !!info->attrs[NL80211_ATTR_PRIVACY];

	if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
		params.auth_type = nla_get_u32(
		params->auth_type = nla_get_u32(
			info->attrs[NL80211_ATTR_AUTH_TYPE]);
		if (!nl80211_valid_auth_type(rdev, params.auth_type,
					     NL80211_CMD_START_AP))
			return -EINVAL;
		if (!nl80211_valid_auth_type(rdev, params->auth_type,
					     NL80211_CMD_START_AP)) {
			err = -EINVAL;
			goto out;
		}
	} else
		params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
		params->auth_type = NL80211_AUTHTYPE_AUTOMATIC;

	err = nl80211_crypto_settings(rdev, info, &params.crypto,
	err = nl80211_crypto_settings(rdev, info, &params->crypto,
				      NL80211_MAX_NR_CIPHER_SUITES);
	if (err)
		return err;
		goto out;

	if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
		if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER))
			return -EOPNOTSUPP;
		params.inactivity_timeout = nla_get_u16(
		if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) {
			err = -EOPNOTSUPP;
			goto out;
		}
		params->inactivity_timeout = nla_get_u16(
			info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
	}

	if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
		params.p2p_ctwindow =
		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
			err = -EINVAL;
			goto out;
		}
		params->p2p_ctwindow =
			nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
		if (params.p2p_ctwindow != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN))
			return -EINVAL;
		if (params->p2p_ctwindow != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) {
			err = -EINVAL;
			goto out;
		}
	}

	if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
		u8 tmp;

		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
			return -EINVAL;
		if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
			err = -EINVAL;
			goto out;
		}
		tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
		params.p2p_opp_ps = tmp;
		if (params.p2p_opp_ps != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS))
			return -EINVAL;
		params->p2p_opp_ps = tmp;
		if (params->p2p_opp_ps != 0 &&
		    !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) {
			err = -EINVAL;
			goto out;
		}
	}

	if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
		err = nl80211_parse_chandef(rdev, info, &params.chandef);
		err = nl80211_parse_chandef(rdev, info, &params->chandef);
		if (err)
			return err;
			goto out;
	} else if (wdev->preset_chandef.chan) {
		params.chandef = wdev->preset_chandef;
	} else if (!nl80211_get_ap_channel(rdev, &params))
		return -EINVAL;
		params->chandef = wdev->preset_chandef;
	} else if (!nl80211_get_ap_channel(rdev, params)) {
		err = -EINVAL;
		goto out;
	}

	if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
					   wdev->iftype))
		return -EINVAL;
	if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params->chandef,
					   wdev->iftype)) {
		err = -EINVAL;
		goto out;
	}

	if (info->attrs[NL80211_ATTR_TX_RATES]) {
		err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
						    NL80211_ATTR_TX_RATES,
						    &params.beacon_rate,
						    &params->beacon_rate,
						    dev, false);
		if (err)
			return err;
			goto out;

		err = validate_beacon_tx_rate(rdev, params.chandef.chan->band,
					      &params.beacon_rate);
		err = validate_beacon_tx_rate(rdev, params->chandef.chan->band,
					      &params->beacon_rate);
		if (err)
			return err;
			goto out;
	}

	if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
		params.smps_mode =
		params->smps_mode =
			nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
		switch (params.smps_mode) {
		switch (params->smps_mode) {
		case NL80211_SMPS_OFF:
			break;
		case NL80211_SMPS_STATIC:
			if (!(rdev->wiphy.features &
			      NL80211_FEATURE_STATIC_SMPS))
				return -EINVAL;
			      NL80211_FEATURE_STATIC_SMPS)) {
				err = -EINVAL;
				goto out;
			}
			break;
		case NL80211_SMPS_DYNAMIC:
			if (!(rdev->wiphy.features &
			      NL80211_FEATURE_DYNAMIC_SMPS))
				return -EINVAL;
			      NL80211_FEATURE_DYNAMIC_SMPS)) {
				err = -EINVAL;
				goto out;
			}
			break;
		default:
			return -EINVAL;
			err = -EINVAL;
			goto out;
		}
	} else {
		params.smps_mode = NL80211_SMPS_OFF;
		params->smps_mode = NL80211_SMPS_OFF;
	}

	params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
	if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ])
		return -EOPNOTSUPP;
	params->pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
	if (params->pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
		err = -EOPNOTSUPP;
		goto out;
	}

	if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
		params.acl = parse_acl_data(&rdev->wiphy, info);
		if (IS_ERR(params.acl))
			return PTR_ERR(params.acl);
		params->acl = parse_acl_data(&rdev->wiphy, info);
		if (IS_ERR(params->acl)) {
			err = PTR_ERR(params->acl);
			goto out;
		}
	}

	params.twt_responder =
	params->twt_responder =
		    nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);

	if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
		err = nl80211_parse_he_obss_pd(
					info->attrs[NL80211_ATTR_HE_OBSS_PD],
					&params.he_obss_pd);
					&params->he_obss_pd);
		if (err)
			goto out;
	}
@@ -5496,7 +5525,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
	if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
		err = nl80211_parse_he_bss_color(
					info->attrs[NL80211_ATTR_HE_BSS_COLOR],
					&params.he_bss_color);
					&params->he_bss_color);
		if (err)
			goto out;
	}
@@ -5504,7 +5533,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
	if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
		err = nl80211_parse_fils_discovery(rdev,
						   info->attrs[NL80211_ATTR_FILS_DISCOVERY],
						   &params);
						   params);
		if (err)
			goto out;
	}
@@ -5512,24 +5541,24 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
	if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
		err = nl80211_parse_unsol_bcast_probe_resp(
			rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
			&params);
			params);
		if (err)
			goto out;
	}

	nl80211_calculate_ap_params(&params);
	nl80211_calculate_ap_params(params);

	if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
		params.flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;
		params->flags |= AP_SETTINGS_EXTERNAL_AUTH_SUPPORT;

	wdev_lock(wdev);
	err = rdev_start_ap(rdev, dev, &params);
	err = rdev_start_ap(rdev, dev, params);
	if (!err) {
		wdev->preset_chandef = params.chandef;
		wdev->beacon_interval = params.beacon_interval;
		wdev->chandef = params.chandef;
		wdev->ssid_len = params.ssid_len;
		memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
		wdev->preset_chandef = params->chandef;
		wdev->beacon_interval = params->beacon_interval;
		wdev->chandef = params->chandef;
		wdev->ssid_len = params->ssid_len;
		memcpy(wdev->ssid, params->ssid, wdev->ssid_len);

		if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
			wdev->conn_owner_nlportid = info->snd_portid;
@@ -5537,7 +5566,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
	wdev_unlock(wdev);

out:
	kfree(params.acl);
	kfree(params->acl);
	kfree(params);

	return err;
}