Search Linux Wireless

[PATCH 2/8] wifi: cfg80211: allow cfg80211_defragment_element() without output

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Johannes Berg <johannes.berg@xxxxxxxxx>

If we just want to determine the length of the fragmented
data, we basically need the same logic, and really we want
it to be _literally_ the same logic, so it cannot be out
of sync in any way.

Allow calling cfg80211_defragment_element() without an output
buffer, where it then just returns the required output size.

Also add this to the tests, just to exercise it, using the
pre-calculated length to really do the defragmentation, which
checks that this is sufficient.

Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@xxxxxxxxx>
Reviewed-by: Benjamin Berg <benjamin.berg@xxxxxxxxx>
Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx>
---
 include/net/cfg80211.h             |  4 ++--
 net/wireless/scan.c                | 27 ++++++++++++++++++---------
 net/wireless/tests/fragmentation.c | 30 +++++++++++++++++++++++++-----
 3 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 53653d234d39..2e2be4fd2bb6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6908,8 +6908,8 @@ bool cfg80211_iter_rnr(const u8 *elems, size_t elems_len,
  * @elem: the element to defragment
  * @ies: elements where @elem is contained
  * @ieslen: length of @ies
- * @data: buffer to store element data
- * @data_len: length of @data
+ * @data: buffer to store element data, or %NULL to just determine size
+ * @data_len: length of @data, or 0
  * @frag_id: the element ID of fragments
  *
  * Return: length of @data, or -EINVAL on error
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 9377a43aa5f7..5a5dd3ce497f 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -2504,16 +2504,22 @@ ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies,
 
 	if (elem->id == WLAN_EID_EXTENSION) {
 		copied = elem->datalen - 1;
-		if (copied > data_len)
-			return -ENOSPC;
 
-		memmove(data, elem->data + 1, copied);
+		if (data) {
+			if (copied > data_len)
+				return -ENOSPC;
+
+			memmove(data, elem->data + 1, copied);
+		}
 	} else {
 		copied = elem->datalen;
-		if (copied > data_len)
-			return -ENOSPC;
 
-		memmove(data, elem->data, copied);
+		if (data) {
+			if (copied > data_len)
+				return -ENOSPC;
+
+			memmove(data, elem->data, copied);
+		}
 	}
 
 	/* Fragmented elements must have 255 bytes */
@@ -2532,10 +2538,13 @@ ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies,
 
 		elem_datalen = elem->datalen;
 
-		if (copied + elem_datalen > data_len)
-			return -ENOSPC;
+		if (data) {
+			if (copied + elem_datalen > data_len)
+				return -ENOSPC;
+
+			memmove(data + copied, elem->data, elem_datalen);
+		}
 
-		memmove(data + copied, elem->data, elem_datalen);
 		copied += elem_datalen;
 
 		/* Only the last fragment may be short */
diff --git a/net/wireless/tests/fragmentation.c b/net/wireless/tests/fragmentation.c
index 49a339ca8880..411fae18cd88 100644
--- a/net/wireless/tests/fragmentation.c
+++ b/net/wireless/tests/fragmentation.c
@@ -2,7 +2,7 @@
 /*
  * KUnit tests for element fragmentation
  *
- * Copyright (C) 2023 Intel Corporation
+ * Copyright (C) 2023-2024 Intel Corporation
  */
 #include <linux/ieee80211.h>
 #include <net/cfg80211.h>
@@ -27,7 +27,12 @@ static void defragment_0(struct kunit *test)
 
 	ret = cfg80211_defragment_element((void *)input,
 					  input, sizeof(input),
-					  data, sizeof(input),
+					  NULL, 0,
+					  WLAN_EID_FRAGMENT);
+	KUNIT_EXPECT_EQ(test, ret, 253);
+	ret = cfg80211_defragment_element((void *)input,
+					  input, sizeof(input),
+					  data, ret,
 					  WLAN_EID_FRAGMENT);
 	KUNIT_EXPECT_EQ(test, ret, 253);
 	KUNIT_EXPECT_MEMEQ(test, data, input + 3, 253);
@@ -63,7 +68,12 @@ static void defragment_1(struct kunit *test)
 
 	ret = cfg80211_defragment_element((void *)input,
 					  input, sizeof(input),
-					  data, sizeof(input),
+					  NULL, 0,
+					  WLAN_EID_FRAGMENT);
+	KUNIT_EXPECT_EQ(test, ret, 254 + 7);
+	ret = cfg80211_defragment_element((void *)input,
+					  input, sizeof(input),
+					  data, ret,
 					  WLAN_EID_FRAGMENT);
 	/* this means the last fragment was not used */
 	KUNIT_EXPECT_EQ(test, ret, 254 + 7);
@@ -106,10 +116,15 @@ static void defragment_2(struct kunit *test)
 
 	ret = cfg80211_defragment_element((void *)input,
 					  input, sizeof(input),
-					  data, sizeof(input),
+					  NULL, 0,
 					  WLAN_EID_FRAGMENT);
 	/* this means the last fragment was not used */
 	KUNIT_EXPECT_EQ(test, ret, 254 + 255 + 1);
+	ret = cfg80211_defragment_element((void *)input,
+					  input, sizeof(input),
+					  data, ret,
+					  WLAN_EID_FRAGMENT);
+	KUNIT_EXPECT_EQ(test, ret, 254 + 255 + 1);
 	KUNIT_EXPECT_MEMEQ(test, data, input + 3, 254);
 	KUNIT_EXPECT_MEMEQ(test, data + 254, input + 257 + 2, 255);
 	KUNIT_EXPECT_MEMEQ(test, data + 254 + 255, input + 2 * 257 + 2, 1);
@@ -134,7 +149,12 @@ static void defragment_at_end(struct kunit *test)
 
 	ret = cfg80211_defragment_element((void *)input,
 					  input, sizeof(input),
-					  data, sizeof(input),
+					  NULL, 0,
+					  WLAN_EID_FRAGMENT);
+	KUNIT_EXPECT_EQ(test, ret, 254 + 7);
+	ret = cfg80211_defragment_element((void *)input,
+					  input, sizeof(input),
+					  data, ret,
 					  WLAN_EID_FRAGMENT);
 	KUNIT_EXPECT_EQ(test, ret, 254 + 7);
 	KUNIT_EXPECT_MEMEQ(test, data, input + 3, 254);
-- 
2.43.2





[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux