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

Reply via email to