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

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
...@@ -90,7 +90,7 @@ struct cfg80211_internal_bss { ...@@ -90,7 +90,7 @@ struct cfg80211_internal_bss {
struct rb_node rbn; struct rb_node rbn;
unsigned long ts; unsigned long ts;
struct kref ref; struct kref ref;
bool hold; bool hold, ies_allocated;
/* must be last because of priv member */ /* must be last because of priv member */
struct cfg80211_bss pub; struct cfg80211_bss pub;
......
...@@ -58,6 +58,10 @@ static void bss_release(struct kref *ref) ...@@ -58,6 +58,10 @@ static void bss_release(struct kref *ref)
bss = container_of(ref, struct cfg80211_internal_bss, ref); bss = container_of(ref, struct cfg80211_internal_bss, ref);
if (bss->pub.free_priv) if (bss->pub.free_priv)
bss->pub.free_priv(&bss->pub); bss->pub.free_priv(&bss->pub);
if (bss->ies_allocated)
kfree(bss->pub.information_elements);
kfree(bss); kfree(bss);
} }
...@@ -360,21 +364,41 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, ...@@ -360,21 +364,41 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
found = rb_find_bss(dev, res); found = rb_find_bss(dev, res);
if (found && overwrite) { if (found) {
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) {
kref_get(&found->ref); kref_get(&found->ref);
found->pub.beacon_interval = res->pub.beacon_interval; found->pub.beacon_interval = res->pub.beacon_interval;
found->pub.tsf = res->pub.tsf; found->pub.tsf = res->pub.tsf;
found->pub.signal = res->pub.signal; found->pub.signal = res->pub.signal;
found->pub.capability = res->pub.capability; found->pub.capability = res->pub.capability;
found->ts = res->ts; 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); kref_put(&res->ref, bss_release);
} else { } else {
/* this "consumes" the reference */ /* this "consumes" the reference */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment