Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd1658f5 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

cfg80211: do not replace BSS structs



Instead, allocate extra IE memory if necessary. Normally,
this isn't even necessary since there's enough space.

This is a better way of correcting the "held BSS can
disappear" issue, but also a lot more code. It is also
necessary for proper auth/assoc BSS handling in the
future.

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 160002fe
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ struct cfg80211_internal_bss {
	struct rb_node rbn;
	unsigned long ts;
	struct kref ref;
	bool hold;
	bool hold, ies_allocated;

	/* must be last because of priv member */
	struct cfg80211_bss pub;
+33 −9
Original line number Diff line number Diff line
@@ -58,6 +58,10 @@ static void bss_release(struct kref *ref)
	bss = container_of(ref, struct cfg80211_internal_bss, ref);
	if (bss->pub.free_priv)
		bss->pub.free_priv(&bss->pub);

	if (bss->ies_allocated)
		kfree(bss->pub.information_elements);

	kfree(bss);
}

@@ -360,21 +364,41 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,

	found = rb_find_bss(dev, res);

	if (found && overwrite) {
		list_replace(&found->list, &res->list);
		rb_replace_node(&found->rbn, &res->rbn,
				&dev->bss_tree);
		/* XXX: workaround */
		res->hold = found->hold;
		kref_put(&found->ref, bss_release);
		found = res;
	} else if (found) {
	if (found) {
		kref_get(&found->ref);
		found->pub.beacon_interval = res->pub.beacon_interval;
		found->pub.tsf = res->pub.tsf;
		found->pub.signal = res->pub.signal;
		found->pub.capability = res->pub.capability;
		found->ts = res->ts;

		/* overwrite IEs */
		if (overwrite) {
			size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
			size_t ielen = res->pub.len_information_elements;

			if (ksize(found) >= used + ielen) {
				memcpy(found->pub.information_elements,
				       res->pub.information_elements, ielen);
				found->pub.len_information_elements = ielen;
			} else {
				u8 *ies = found->pub.information_elements;

				if (found->ies_allocated) {
					if (ksize(ies) < ielen)
						ies = krealloc(ies, ielen,
							       GFP_ATOMIC);
				} else
					ies = kmalloc(ielen, GFP_ATOMIC);

				if (ies) {
					memcpy(ies, res->pub.information_elements, ielen);
					found->ies_allocated = true;
					found->pub.information_elements = ies;
				}
			}
		}

		kref_put(&res->ref, bss_release);
	} else {
		/* this "consumes" the reference */