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: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2021-09-23 16:18:37 +02:00
parent 5d24828d05
commit 9e263e193a
1 changed files with 109 additions and 79 deletions

View File

@ -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);
if (err)
return err;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
params.beacon_interval =
err = nl80211_parse_beacon(rdev, info->attrs, &params->beacon);
if (err)
goto out;
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;
}