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 cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1]; struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_ap_settings params; struct cfg80211_ap_settings *params;
int err; int err;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 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) if (wdev->beacon_interval)
return -EALREADY; return -EALREADY;
memset(&params, 0, sizeof(params));
/* these are required for START_AP */ /* these are required for START_AP */
if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] || if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
!info->attrs[NL80211_ATTR_DTIM_PERIOD] || !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
!info->attrs[NL80211_ATTR_BEACON_HEAD]) !info->attrs[NL80211_ATTR_BEACON_HEAD])
return -EINVAL; return -EINVAL;
err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon); params = kzalloc(sizeof(*params), GFP_KERNEL);
if (err) if (!params)
return err; 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]); nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
params.dtim_period = params->dtim_period =
nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype, err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
params.beacon_interval); params->beacon_interval);
if (err) if (err)
return err; goto out;
/* /*
* In theory, some of these attributes should be required here * 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! * additional information -- drivers must check!
*/ */
if (info->attrs[NL80211_ATTR_SSID]) { if (info->attrs[NL80211_ATTR_SSID]) {
params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); params->ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
params.ssid_len = params->ssid_len =
nla_len(info->attrs[NL80211_ATTR_SSID]); nla_len(info->attrs[NL80211_ATTR_SSID]);
if (params.ssid_len == 0) if (params->ssid_len == 0) {
return -EINVAL; err = -EINVAL;
goto out;
}
} }
if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) 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]); 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]) { 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]); info->attrs[NL80211_ATTR_AUTH_TYPE]);
if (!nl80211_valid_auth_type(rdev, params.auth_type, if (!nl80211_valid_auth_type(rdev, params->auth_type,
NL80211_CMD_START_AP)) NL80211_CMD_START_AP)) {
return -EINVAL; err = -EINVAL;
goto out;
}
} else } 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); NL80211_MAX_NR_CIPHER_SUITES);
if (err) if (err)
return err; goto out;
if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) { if (info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]) {
if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) if (!(rdev->wiphy.features & NL80211_FEATURE_INACTIVITY_TIMER)) {
return -EOPNOTSUPP; err = -EOPNOTSUPP;
params.inactivity_timeout = nla_get_u16( goto out;
}
params->inactivity_timeout = nla_get_u16(
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
} }
if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) { if (info->attrs[NL80211_ATTR_P2P_CTWINDOW]) {
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
return -EINVAL; err = -EINVAL;
params.p2p_ctwindow = goto out;
}
params->p2p_ctwindow =
nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]); nla_get_u8(info->attrs[NL80211_ATTR_P2P_CTWINDOW]);
if (params.p2p_ctwindow != 0 && if (params->p2p_ctwindow != 0 &&
!(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_CTWIN)) {
return -EINVAL; err = -EINVAL;
goto out;
}
} }
if (info->attrs[NL80211_ATTR_P2P_OPPPS]) { if (info->attrs[NL80211_ATTR_P2P_OPPPS]) {
u8 tmp; u8 tmp;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
return -EINVAL; err = -EINVAL;
goto out;
}
tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]); tmp = nla_get_u8(info->attrs[NL80211_ATTR_P2P_OPPPS]);
params.p2p_opp_ps = tmp; params->p2p_opp_ps = tmp;
if (params.p2p_opp_ps != 0 && if (params->p2p_opp_ps != 0 &&
!(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) !(rdev->wiphy.features & NL80211_FEATURE_P2P_GO_OPPPS)) {
return -EINVAL; err = -EINVAL;
goto out;
}
} }
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 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) if (err)
return err; goto out;
} else if (wdev->preset_chandef.chan) { } else if (wdev->preset_chandef.chan) {
params.chandef = wdev->preset_chandef; params->chandef = wdev->preset_chandef;
} else if (!nl80211_get_ap_channel(rdev, &params)) } else if (!nl80211_get_ap_channel(rdev, params)) {
return -EINVAL; err = -EINVAL;
goto out;
}
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef, if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params->chandef,
wdev->iftype)) wdev->iftype)) {
return -EINVAL; err = -EINVAL;
goto out;
}
if (info->attrs[NL80211_ATTR_TX_RATES]) { if (info->attrs[NL80211_ATTR_TX_RATES]) {
err = nl80211_parse_tx_bitrate_mask(info, info->attrs, err = nl80211_parse_tx_bitrate_mask(info, info->attrs,
NL80211_ATTR_TX_RATES, NL80211_ATTR_TX_RATES,
&params.beacon_rate, &params->beacon_rate,
dev, false); dev, false);
if (err) if (err)
return err; goto out;
err = validate_beacon_tx_rate(rdev, params.chandef.chan->band, err = validate_beacon_tx_rate(rdev, params->chandef.chan->band,
&params.beacon_rate); &params->beacon_rate);
if (err) if (err)
return err; goto out;
} }
if (info->attrs[NL80211_ATTR_SMPS_MODE]) { if (info->attrs[NL80211_ATTR_SMPS_MODE]) {
params.smps_mode = params->smps_mode =
nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]); nla_get_u8(info->attrs[NL80211_ATTR_SMPS_MODE]);
switch (params.smps_mode) { switch (params->smps_mode) {
case NL80211_SMPS_OFF: case NL80211_SMPS_OFF:
break; break;
case NL80211_SMPS_STATIC: case NL80211_SMPS_STATIC:
if (!(rdev->wiphy.features & if (!(rdev->wiphy.features &
NL80211_FEATURE_STATIC_SMPS)) NL80211_FEATURE_STATIC_SMPS)) {
return -EINVAL; err = -EINVAL;
goto out;
}
break; break;
case NL80211_SMPS_DYNAMIC: case NL80211_SMPS_DYNAMIC:
if (!(rdev->wiphy.features & if (!(rdev->wiphy.features &
NL80211_FEATURE_DYNAMIC_SMPS)) NL80211_FEATURE_DYNAMIC_SMPS)) {
return -EINVAL; err = -EINVAL;
goto out;
}
break; break;
default: default:
return -EINVAL; err = -EINVAL;
goto out;
} }
} else { } else {
params.smps_mode = NL80211_SMPS_OFF; params->smps_mode = NL80211_SMPS_OFF;
} }
params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); params->pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
if (params.pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) if (params->pbss && !rdev->wiphy.bands[NL80211_BAND_60GHZ]) {
return -EOPNOTSUPP; err = -EOPNOTSUPP;
goto out;
}
if (info->attrs[NL80211_ATTR_ACL_POLICY]) { if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
params.acl = parse_acl_data(&rdev->wiphy, info); params->acl = parse_acl_data(&rdev->wiphy, info);
if (IS_ERR(params.acl)) if (IS_ERR(params->acl)) {
return PTR_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]); nla_get_flag(info->attrs[NL80211_ATTR_TWT_RESPONDER]);
if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) { if (info->attrs[NL80211_ATTR_HE_OBSS_PD]) {
err = nl80211_parse_he_obss_pd( err = nl80211_parse_he_obss_pd(
info->attrs[NL80211_ATTR_HE_OBSS_PD], info->attrs[NL80211_ATTR_HE_OBSS_PD],
&params.he_obss_pd); &params->he_obss_pd);
if (err) if (err)
goto out; 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]) { if (info->attrs[NL80211_ATTR_HE_BSS_COLOR]) {
err = nl80211_parse_he_bss_color( err = nl80211_parse_he_bss_color(
info->attrs[NL80211_ATTR_HE_BSS_COLOR], info->attrs[NL80211_ATTR_HE_BSS_COLOR],
&params.he_bss_color); &params->he_bss_color);
if (err) if (err)
goto out; 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]) { if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
err = nl80211_parse_fils_discovery(rdev, err = nl80211_parse_fils_discovery(rdev,
info->attrs[NL80211_ATTR_FILS_DISCOVERY], info->attrs[NL80211_ATTR_FILS_DISCOVERY],
&params); params);
if (err) if (err)
goto out; 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]) { if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
err = nl80211_parse_unsol_bcast_probe_resp( err = nl80211_parse_unsol_bcast_probe_resp(
rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP], rdev, info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
&params); params);
if (err) if (err)
goto out; goto out;
} }
nl80211_calculate_ap_params(&params); nl80211_calculate_ap_params(params);
if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) 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); wdev_lock(wdev);
err = rdev_start_ap(rdev, dev, &params); err = rdev_start_ap(rdev, dev, params);
if (!err) { if (!err) {
wdev->preset_chandef = params.chandef; wdev->preset_chandef = params->chandef;
wdev->beacon_interval = params.beacon_interval; wdev->beacon_interval = params->beacon_interval;
wdev->chandef = params.chandef; wdev->chandef = params->chandef;
wdev->ssid_len = params.ssid_len; wdev->ssid_len = params->ssid_len;
memcpy(wdev->ssid, params.ssid, wdev->ssid_len); memcpy(wdev->ssid, params->ssid, wdev->ssid_len);
if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
wdev->conn_owner_nlportid = info->snd_portid; 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); wdev_unlock(wdev);
out: out:
kfree(params.acl); kfree(params->acl);
kfree(params);
return err; return err;
} }