diff mbox series

[RFCv1,1/2] nl80211: Support >4096 byte NEW_WIPHY event nlmsg

Message ID 20190801071455.4974-1-denkenz@gmail.com (mailing list archive)
State RFC
Delegated to: Johannes Berg
Headers show
Series [RFCv1,1/2] nl80211: Support >4096 byte NEW_WIPHY event nlmsg | expand

Commit Message

Denis Kenzior Aug. 1, 2019, 7:14 a.m. UTC
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 mbox series

Patch

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;