Commit f837a653 authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg
Browse files

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: default avatarBenjamin Berg <benjamin.berg@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230616094949.29c3ebeed10d.I009c049289dd0162c2e858ed8b68d2875a672ed6@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 39432f8a
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -6676,6 +6676,28 @@ cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
	return (const void *)cfg80211_find_vendor_elem(oui, oui_type, ies, len);
}

/**
 * cfg80211_defragment_element - Defrag the given element data into a buffer
 *
 * @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
 * @frag_id: the element ID of fragments
 *
 * Return: length of @data, or -EINVAL on error
 *
 * Copy out all data from an element that may be fragmented into @data, while
 * skipping all headers.
 *
 * The function uses memmove() internally. It is acceptable to defragment an
 * element in-place.
 */
ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies,
				    size_t ieslen, u8 *data, size_t data_len,
				    u8 frag_id);

/**
 * cfg80211_send_layer2_update - send layer 2 update frame
 *
+60 −0
Original line number Diff line number Diff line
@@ -2288,6 +2288,66 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
	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,