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: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
committed by
John W. Linville
parent
160002fe84
commit
cd1658f592
@@ -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)
|
|||||||
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,
|
|||||||
|
|
||||||
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 */
|
||||||
|
Reference in New Issue
Block a user