For historical reasons, NEW_WIPHY messages generated by dumps or GET_WIPHY commands were limited to 4096 bytes due to userspace tools using limited buffers. Once the sizes NEW_WIPHY messages exceeded these sizes, split dumps were introduced. All any non-legacy data was added only to messages using split-dumps (including filtered dumps). When unsolicited NEW_WIPHY events were introduced they inherited the 4096 byte limitation. These messages thus do not contain any non-legacy wiphy dump data. This means that userspace still needs to re-dump the information from the kernel after receiving such NEW_WIPHY event since some of the information is missing. Thus it is desirable to relax such restrictions for these messages and include the non-legacy data in these events. It should be safe to assume that any users of these new unsolicited NEW_WIPHY events are non-legacy clients, which can use a larger receive buffer for netlink messages. Since older, legacy clients did not utilize NEW_WIPHY events (they did not exist), it is assumed that even if the client receives such a message (even if truncated), no harm would result and backwards-compatibility would be kept. --- net/wireless/nl80211.c | 49 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1a107f29016b..6774072e836f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1839,6 +1839,7 @@ struct nl80211_dump_wiphy_state { long start; long split_start, band_start, chan_start, capa_start; bool split; + bool large_message; }; static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, @@ -2168,12 +2169,23 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, * helps ensure that newly added capabilities don't break * older tools by overrunning their buffers. * + * For unsolicited NEW_WIPHY notifications, it is assumed + * that the client can handle larger messages. Unsolicited + * NEW_WIPHY notifications were added relatively recently + * and it is not expected that older tools with limited + * buffers would utilize these messages anyway. E.g. even + * if the message is truncated, it would not have been + * used regardless. + * * We still increment split_start so that in the split * case we'll continue with more data in the next round, - * but break unconditionally so unsplit data stops here. + * but break unless large_messages are requested, so + * legacy unsplit data stops here. */ state->split_start++; - break; + if (state->split || !state->large_message) + break; + /* Fall through */ case 9: if (rdev->wiphy.extended_capabilities && (nla_put(msg, NL80211_ATTR_EXT_CAPA, @@ -2215,7 +2227,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, } state->split_start++; - break; + if (state->split) + break; + /* Fall through */ case 10: if (nl80211_send_coalesce(msg, rdev)) goto nla_put_failure; @@ -2231,7 +2245,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, goto nla_put_failure; state->split_start++; - break; + if (state->split) + break; + /* Fall through */ case 11: if (rdev->wiphy.n_vendor_commands) { const struct nl80211_vendor_cmd_info *info; @@ -2267,7 +2283,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, nla_nest_end(msg, nested); } state->split_start++; - break; + if (state->split) + break; + /* Fall through */ case 12: if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH && nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS, @@ -2309,7 +2327,9 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, } state->split_start++; - break; + if (state->split) + break; + /* Fall through */ case 13: if (rdev->wiphy.num_iftype_ext_capab && rdev->wiphy.iftype_ext_capab) { @@ -2377,13 +2397,17 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, } state->split_start++; - break; + if (state->split) + break; + /* Fall through */ case 14: if (nl80211_send_pmsr_capa(rdev, msg)) goto nla_put_failure; state->split_start++; - break; + if (state->split) + break; + /* Fall through */ case 15: if (rdev->wiphy.akm_suites && nla_put(msg, NL80211_ATTR_AKM_SUITES, @@ -14687,12 +14711,19 @@ void nl80211_notify_wiphy(struct cfg80211_registered_device *rdev, enum nl80211_commands cmd) { struct sk_buff *msg; + size_t alloc_size; struct nl80211_dump_wiphy_state state = {}; WARN_ON(cmd != NL80211_CMD_NEW_WIPHY && cmd != NL80211_CMD_DEL_WIPHY); - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (cmd == NL80211_CMD_NEW_WIPHY) { + state.large_message = true; + alloc_size = 8192UL; + } else + alloc_size = NLMSG_DEFAULT_SIZE; + + msg = nlmsg_new(alloc_size, GFP_KERNEL); if (!msg) return; -- 2.21.0