diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/scan.c | 42 |
2 files changed, 34 insertions, 10 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h index d43daa236ef9..0a592e4295f0 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -90,7 +90,7 @@ struct cfg80211_internal_bss { | |||
90 | struct rb_node rbn; | 90 | struct rb_node rbn; |
91 | unsigned long ts; | 91 | unsigned long ts; |
92 | struct kref ref; | 92 | struct kref ref; |
93 | bool hold; | 93 | bool hold, ies_allocated; |
94 | 94 | ||
95 | /* must be last because of priv member */ | 95 | /* must be last because of priv member */ |
96 | struct cfg80211_bss pub; | 96 | struct cfg80211_bss pub; |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 4c77669275eb..2ae65b39b529 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -58,6 +58,10 @@ static void bss_release(struct kref *ref) | |||
58 | bss = container_of(ref, struct cfg80211_internal_bss, ref); | 58 | bss = container_of(ref, struct cfg80211_internal_bss, ref); |
59 | if (bss->pub.free_priv) | 59 | if (bss->pub.free_priv) |
60 | bss->pub.free_priv(&bss->pub); | 60 | bss->pub.free_priv(&bss->pub); |
61 | |||
62 | if (bss->ies_allocated) | ||
63 | kfree(bss->pub.information_elements); | ||
64 | |||
61 | kfree(bss); | 65 | kfree(bss); |
62 | } | 66 | } |
63 | 67 | ||
@@ -360,21 +364,41 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
360 | 364 | ||
361 | found = rb_find_bss(dev, res); | 365 | found = rb_find_bss(dev, res); |
362 | 366 | ||
363 | if (found && overwrite) { | 367 | if (found) { |
364 | list_replace(&found->list, &res->list); | ||
365 | rb_replace_node(&found->rbn, &res->rbn, | ||
366 | &dev->bss_tree); | ||
367 | /* XXX: workaround */ | ||
368 | res->hold = found->hold; | ||
369 | kref_put(&found->ref, bss_release); | ||
370 | found = res; | ||
371 | } else if (found) { | ||
372 | kref_get(&found->ref); | 368 | kref_get(&found->ref); |
373 | found->pub.beacon_interval = res->pub.beacon_interval; | 369 | found->pub.beacon_interval = res->pub.beacon_interval; |
374 | found->pub.tsf = res->pub.tsf; | 370 | found->pub.tsf = res->pub.tsf; |
375 | found->pub.signal = res->pub.signal; | 371 | found->pub.signal = res->pub.signal; |
376 | found->pub.capability = res->pub.capability; | 372 | found->pub.capability = res->pub.capability; |
377 | found->ts = res->ts; | 373 | found->ts = res->ts; |
374 | |||
375 | /* overwrite IEs */ | ||
376 | if (overwrite) { | ||
377 | size_t used = dev->wiphy.bss_priv_size + sizeof(*res); | ||
378 | size_t ielen = res->pub.len_information_elements; | ||
379 | |||
380 | if (ksize(found) >= used + ielen) { | ||
381 | memcpy(found->pub.information_elements, | ||
382 | res->pub.information_elements, ielen); | ||
383 | found->pub.len_information_elements = ielen; | ||
384 | } else { | ||
385 | u8 *ies = found->pub.information_elements; | ||
386 | |||
387 | if (found->ies_allocated) { | ||
388 | if (ksize(ies) < ielen) | ||
389 | ies = krealloc(ies, ielen, | ||
390 | GFP_ATOMIC); | ||
391 | } else | ||
392 | ies = kmalloc(ielen, GFP_ATOMIC); | ||
393 | |||
394 | if (ies) { | ||
395 | memcpy(ies, res->pub.information_elements, ielen); | ||
396 | found->ies_allocated = true; | ||
397 | found->pub.information_elements = ies; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
378 | kref_put(&res->ref, bss_release); | 402 | kref_put(&res->ref, bss_release); |
379 | } else { | 403 | } else { |
380 | /* this "consumes" the reference */ | 404 | /* this "consumes" the reference */ |