aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorBenjamin Berg <benjamin.berg@intel.com>2023-06-16 09:54:05 +0300
committerJohannes Berg <johannes.berg@intel.com>2023-06-19 12:05:29 +0200
commitf837a653a09700daa136a3db49c0c97d7295ca30 (patch)
tree90346dcd83b8a7178a635eb5fed80ff0c5c4de0a /net/wireless
parent39432f8a3752a87a53fd8d5e51824a43aaae5cab (diff)
downloadlinux-f837a653a09700daa136a3db49c0c97d7295ca30.tar.gz
wifi: cfg80211: add element defragmentation helper
This is already needed within mac80211 and support is also needed by cfg80211 to parse ML elements. Signed-off-by: Benjamin Berg <benjamin.berg@intel.com> Signed-off-by: Gregory Greenman <gregory.greenman@intel.com> Link: https://lore.kernel.org/r/20230616094949.29c3ebeed10d.I009c049289dd0162c2e858ed8b68d2875a672ed6@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/scan.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 75e6e032bb3a32..dc71c6ac5bf5dd 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -2288,6 +2288,66 @@ out:
kfree(profile);
}
+ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies,
+ size_t ieslen, u8 *data, size_t data_len,
+ u8 frag_id)
+{
+ const struct element *next;
+ ssize_t copied;
+ u8 elem_datalen;
+
+ if (!elem)
+ return -EINVAL;
+
+ /* elem might be invalid after the memmove */
+ next = (void *)(elem->data + elem->datalen);
+
+ elem_datalen = elem->datalen;
+ if (elem->id == WLAN_EID_EXTENSION) {
+ copied = elem->datalen - 1;
+ 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);
+ }
+
+ /* Fragmented elements must have 255 bytes */
+ if (elem_datalen < 255)
+ return copied;
+
+ for (elem = next;
+ elem->data < ies + ieslen &&
+ elem->data + elem->datalen < ies + ieslen;
+ elem = next) {
+ /* elem might be invalid after the memmove */
+ next = (void *)(elem->data + elem->datalen);
+
+ if (elem->id != frag_id)
+ break;
+
+ elem_datalen = elem->datalen;
+
+ if (copied + elem_datalen > data_len)
+ return -ENOSPC;
+
+ memmove(data + copied, elem->data, elem_datalen);
+ copied += elem_datalen;
+
+ /* Only the last fragment may be short */
+ if (elem_datalen != 255)
+ break;
+ }
+
+ return copied;
+}
+EXPORT_SYMBOL(cfg80211_defragment_element);
+
struct cfg80211_bss *
cfg80211_inform_bss_data(struct wiphy *wiphy,
struct cfg80211_inform_bss *data,