diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 4 | ||||
-rw-r--r-- | net/wireless/reg.c | 22 | ||||
-rw-r--r-- | net/wireless/scan.c | 41 |
4 files changed, 55 insertions, 14 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/nl80211.c b/net/wireless/nl80211.c index 353e1a4ece83..2456e4ee445e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3334,7 +3334,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
3334 | struct sk_buff *msg; | 3334 | struct sk_buff *msg; |
3335 | void *hdr; | 3335 | void *hdr; |
3336 | 3336 | ||
3337 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3337 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); |
3338 | if (!msg) | 3338 | if (!msg) |
3339 | return; | 3339 | return; |
3340 | 3340 | ||
@@ -3353,7 +3353,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
3353 | return; | 3353 | return; |
3354 | } | 3354 | } |
3355 | 3355 | ||
3356 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | 3356 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); |
3357 | return; | 3357 | return; |
3358 | 3358 | ||
3359 | nla_put_failure: | 3359 | nla_put_failure: |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6327e1617acb..08265ca15785 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -907,6 +907,7 @@ EXPORT_SYMBOL(freq_reg_info); | |||
907 | int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, | 907 | int freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 *bandwidth, |
908 | const struct ieee80211_reg_rule **reg_rule) | 908 | const struct ieee80211_reg_rule **reg_rule) |
909 | { | 909 | { |
910 | assert_cfg80211_lock(); | ||
910 | return freq_reg_info_regd(wiphy, center_freq, | 911 | return freq_reg_info_regd(wiphy, center_freq, |
911 | bandwidth, reg_rule, NULL); | 912 | bandwidth, reg_rule, NULL); |
912 | } | 913 | } |
@@ -1133,7 +1134,8 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) | |||
1133 | if (is_world_regdom(cfg80211_regdomain->alpha2) || | 1134 | if (is_world_regdom(cfg80211_regdomain->alpha2) || |
1134 | (wiphy->regd && is_world_regdom(wiphy->regd->alpha2))) | 1135 | (wiphy->regd && is_world_regdom(wiphy->regd->alpha2))) |
1135 | return true; | 1136 | return true; |
1136 | if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | 1137 | if (last_request && |
1138 | last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
1137 | wiphy->custom_regulatory) | 1139 | wiphy->custom_regulatory) |
1138 | return true; | 1140 | return true; |
1139 | return false; | 1141 | return false; |
@@ -1142,6 +1144,12 @@ static bool reg_is_world_roaming(struct wiphy *wiphy) | |||
1142 | /* Reap the advantages of previously found beacons */ | 1144 | /* Reap the advantages of previously found beacons */ |
1143 | static void reg_process_beacons(struct wiphy *wiphy) | 1145 | static void reg_process_beacons(struct wiphy *wiphy) |
1144 | { | 1146 | { |
1147 | /* | ||
1148 | * Means we are just firing up cfg80211, so no beacons would | ||
1149 | * have been processed yet. | ||
1150 | */ | ||
1151 | if (!last_request) | ||
1152 | return; | ||
1145 | if (!reg_is_world_roaming(wiphy)) | 1153 | if (!reg_is_world_roaming(wiphy)) |
1146 | return; | 1154 | return; |
1147 | wiphy_update_beacon_reg(wiphy); | 1155 | wiphy_update_beacon_reg(wiphy); |
@@ -1176,6 +1184,8 @@ static void handle_channel_custom(struct wiphy *wiphy, | |||
1176 | struct ieee80211_supported_band *sband; | 1184 | struct ieee80211_supported_band *sband; |
1177 | struct ieee80211_channel *chan; | 1185 | struct ieee80211_channel *chan; |
1178 | 1186 | ||
1187 | assert_cfg80211_lock(); | ||
1188 | |||
1179 | sband = wiphy->bands[band]; | 1189 | sband = wiphy->bands[band]; |
1180 | BUG_ON(chan_idx >= sband->n_channels); | 1190 | BUG_ON(chan_idx >= sband->n_channels); |
1181 | chan = &sband->channels[chan_idx]; | 1191 | chan = &sband->channels[chan_idx]; |
@@ -1214,10 +1224,13 @@ void wiphy_apply_custom_regulatory(struct wiphy *wiphy, | |||
1214 | const struct ieee80211_regdomain *regd) | 1224 | const struct ieee80211_regdomain *regd) |
1215 | { | 1225 | { |
1216 | enum ieee80211_band band; | 1226 | enum ieee80211_band band; |
1227 | |||
1228 | mutex_lock(&cfg80211_mutex); | ||
1217 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1229 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1218 | if (wiphy->bands[band]) | 1230 | if (wiphy->bands[band]) |
1219 | handle_band_custom(wiphy, band, regd); | 1231 | handle_band_custom(wiphy, band, regd); |
1220 | } | 1232 | } |
1233 | mutex_unlock(&cfg80211_mutex); | ||
1221 | } | 1234 | } |
1222 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); | 1235 | EXPORT_SYMBOL(wiphy_apply_custom_regulatory); |
1223 | 1236 | ||
@@ -1423,7 +1436,7 @@ new_request: | |||
1423 | return call_crda(last_request->alpha2); | 1436 | return call_crda(last_request->alpha2); |
1424 | } | 1437 | } |
1425 | 1438 | ||
1426 | /* This currently only processes user and driver regulatory hints */ | 1439 | /* This processes *all* regulatory hints */ |
1427 | static void reg_process_hint(struct regulatory_request *reg_request) | 1440 | static void reg_process_hint(struct regulatory_request *reg_request) |
1428 | { | 1441 | { |
1429 | int r = 0; | 1442 | int r = 0; |
@@ -2095,11 +2108,12 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
2095 | /* Caller must hold cfg80211_mutex */ | 2108 | /* Caller must hold cfg80211_mutex */ |
2096 | void reg_device_remove(struct wiphy *wiphy) | 2109 | void reg_device_remove(struct wiphy *wiphy) |
2097 | { | 2110 | { |
2098 | struct wiphy *request_wiphy; | 2111 | struct wiphy *request_wiphy = NULL; |
2099 | 2112 | ||
2100 | assert_cfg80211_lock(); | 2113 | assert_cfg80211_lock(); |
2101 | 2114 | ||
2102 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 2115 | if (last_request) |
2116 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
2103 | 2117 | ||
2104 | kfree(wiphy->regd); | 2118 | kfree(wiphy->regd); |
2105 | if (!last_request || !request_wiphy) | 2119 | if (!last_request || !request_wiphy) |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2a00e362f5fe..1f260c40b6ca 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,19 +364,42 @@ 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 | kref_put(&found->ref, bss_release); | ||
368 | found = res; | ||
369 | } else if (found) { | ||
370 | kref_get(&found->ref); | 368 | kref_get(&found->ref); |
371 | found->pub.beacon_interval = res->pub.beacon_interval; | 369 | found->pub.beacon_interval = res->pub.beacon_interval; |
372 | found->pub.tsf = res->pub.tsf; | 370 | found->pub.tsf = res->pub.tsf; |
373 | found->pub.signal = res->pub.signal; | 371 | found->pub.signal = res->pub.signal; |
374 | found->pub.capability = res->pub.capability; | 372 | found->pub.capability = res->pub.capability; |
375 | 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 | found->pub.len_information_elements = ielen; | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | |||
376 | kref_put(&res->ref, bss_release); | 403 | kref_put(&res->ref, bss_release); |
377 | } else { | 404 | } else { |
378 | /* this "consumes" the reference */ | 405 | /* this "consumes" the reference */ |