summaryrefslogtreecommitdiffstats
path: root/net/wireless/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r--net/wireless/scan.c508
1 files changed, 470 insertions, 38 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index d2c9ca5f4f57..531c2e56413f 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -5,6 +5,7 @@
5 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> 5 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
6 * Copyright 2013-2014 Intel Mobile Communications GmbH 6 * Copyright 2013-2014 Intel Mobile Communications GmbH
7 * Copyright 2016 Intel Deutschland GmbH 7 * Copyright 2016 Intel Deutschland GmbH
8 * Copyright (C) 2018-2019 Intel Corporation
8 */ 9 */
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <linux/slab.h> 11#include <linux/slab.h>
@@ -150,6 +151,7 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
150 } 151 }
151 152
152 list_del_init(&bss->list); 153 list_del_init(&bss->list);
154 list_del_init(&bss->nontrans_list);
153 rb_erase(&bss->rbn, &rdev->bss_tree); 155 rb_erase(&bss->rbn, &rdev->bss_tree);
154 rdev->bss_entries--; 156 rdev->bss_entries--;
155 WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list), 157 WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
@@ -159,6 +161,172 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
159 return true; 161 return true;
160} 162}
161 163
164static void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,
165 u8 mbssid_index, u8 *new_bssid_addr)
166{
167 u64 bssid_tmp, new_bssid = 0;
168 u64 lsb_n;
169
170 bssid_tmp = ether_addr_to_u64(bssid);
171
172 lsb_n = bssid_tmp & ((1 << max_bssid) - 1);
173 new_bssid = bssid_tmp;
174 new_bssid &= ~((1 << max_bssid) - 1);
175 new_bssid |= (lsb_n + mbssid_index) % (1 << max_bssid);
176
177 u64_to_ether_addr(new_bssid, new_bssid_addr);
178}
179
180static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
181 const u8 *subelement, size_t subie_len,
182 u8 *new_ie, gfp_t gfp)
183{
184 u8 *pos, *tmp;
185 const u8 *tmp_old, *tmp_new;
186 u8 *sub_copy;
187
188 /* copy subelement as we need to change its content to
189 * mark an ie after it is processed.
190 */
191 sub_copy = kmalloc(subie_len, gfp);
192 if (!sub_copy)
193 return 0;
194 memcpy(sub_copy, subelement, subie_len);
195
196 pos = &new_ie[0];
197
198 /* set new ssid */
199 tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len);
200 if (tmp_new) {
201 memcpy(pos, tmp_new, tmp_new[1] + 2);
202 pos += (tmp_new[1] + 2);
203 }
204
205 /* go through IEs in ie (skip SSID) and subelement,
206 * merge them into new_ie
207 */
208 tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
209 tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
210
211 while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
212 if (tmp_old[0] == 0) {
213 tmp_old++;
214 continue;
215 }
216
217 tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy, subie_len);
218 if (!tmp) {
219 /* ie in old ie but not in subelement */
220 if (tmp_old[0] != WLAN_EID_MULTIPLE_BSSID) {
221 memcpy(pos, tmp_old, tmp_old[1] + 2);
222 pos += tmp_old[1] + 2;
223 }
224 } else {
225 /* ie in transmitting ie also in subelement,
226 * copy from subelement and flag the ie in subelement
227 * as copied (by setting eid field to 0xff). For
228 * vendor ie, compare OUI + type + subType to
229 * determine if they are the same ie.
230 */
231 if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) {
232 if (!memcmp(tmp_old + 2, tmp + 2, 5)) {
233 /* same vendor ie, copy from
234 * subelement
235 */
236 memcpy(pos, tmp, tmp[1] + 2);
237 pos += tmp[1] + 2;
238 tmp[0] = 0xff;
239 } else {
240 memcpy(pos, tmp_old, tmp_old[1] + 2);
241 pos += tmp_old[1] + 2;
242 }
243 } else {
244 /* copy ie from subelement into new ie */
245 memcpy(pos, tmp, tmp[1] + 2);
246 pos += tmp[1] + 2;
247 tmp[0] = 0xff;
248 }
249 }
250
251 if (tmp_old + tmp_old[1] + 2 - ie == ielen)
252 break;
253
254 tmp_old += tmp_old[1] + 2;
255 }
256
257 /* go through subelement again to check if there is any ie not
258 * copied to new ie, skip ssid, capability, bssid-index ie
259 */
260 tmp_new = sub_copy;
261 while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
262 if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
263 tmp_new[0] == WLAN_EID_SSID ||
264 tmp_new[0] == WLAN_EID_MULTI_BSSID_IDX ||
265 tmp_new[0] == 0xff)) {
266 memcpy(pos, tmp_new, tmp_new[1] + 2);
267 pos += tmp_new[1] + 2;
268 }
269 if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len)
270 break;
271 tmp_new += tmp_new[1] + 2;
272 }
273
274 kfree(sub_copy);
275 return pos - new_ie;
276}
277
278static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
279 const u8 *ssid, size_t ssid_len)
280{
281 const struct cfg80211_bss_ies *ies;
282 const u8 *ssidie;
283
284 if (bssid && !ether_addr_equal(a->bssid, bssid))
285 return false;
286
287 if (!ssid)
288 return true;
289
290 ies = rcu_access_pointer(a->ies);
291 if (!ies)
292 return false;
293 ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
294 if (!ssidie)
295 return false;
296 if (ssidie[1] != ssid_len)
297 return false;
298 return memcmp(ssidie + 2, ssid, ssid_len) == 0;
299}
300
301static int
302cfg80211_add_nontrans_list(struct cfg80211_internal_bss *trans_bss,
303 struct cfg80211_internal_bss *nontrans_bss)
304{
305 const u8 *ssid;
306 size_t ssid_len;
307 struct cfg80211_internal_bss *bss = NULL;
308
309 rcu_read_lock();
310 ssid = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID);
311 if (!ssid) {
312 rcu_read_unlock();
313 return -EINVAL;
314 }
315 ssid_len = ssid[1];
316 ssid = ssid + 2;
317 rcu_read_unlock();
318
319 /* check if nontrans_bss is in the list */
320 list_for_each_entry(bss, &trans_bss->nontrans_list, nontrans_list) {
321 if (is_bss(&bss->pub, nontrans_bss->pub.bssid, ssid, ssid_len))
322 return 0;
323 }
324
325 /* add to the list */
326 list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
327 return 0;
328}
329
162static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev, 330static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
163 unsigned long expire_time) 331 unsigned long expire_time)
164{ 332{
@@ -518,29 +686,6 @@ const struct element *cfg80211_find_vendor_elem(unsigned int oui, int oui_type,
518} 686}
519EXPORT_SYMBOL(cfg80211_find_vendor_elem); 687EXPORT_SYMBOL(cfg80211_find_vendor_elem);
520 688
521static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
522 const u8 *ssid, size_t ssid_len)
523{
524 const struct cfg80211_bss_ies *ies;
525 const u8 *ssidie;
526
527 if (bssid && !ether_addr_equal(a->bssid, bssid))
528 return false;
529
530 if (!ssid)
531 return true;
532
533 ies = rcu_access_pointer(a->ies);
534 if (!ies)
535 return false;
536 ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
537 if (!ssidie)
538 return false;
539 if (ssidie[1] != ssid_len)
540 return false;
541 return memcmp(ssidie + 2, ssid, ssid_len) == 0;
542}
543
544/** 689/**
545 * enum bss_compare_mode - BSS compare mode 690 * enum bss_compare_mode - BSS compare mode
546 * @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find) 691 * @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find)
@@ -1002,6 +1147,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
1002 memcpy(new, tmp, sizeof(*new)); 1147 memcpy(new, tmp, sizeof(*new));
1003 new->refcount = 1; 1148 new->refcount = 1;
1004 INIT_LIST_HEAD(&new->hidden_list); 1149 INIT_LIST_HEAD(&new->hidden_list);
1150 INIT_LIST_HEAD(&new->nontrans_list);
1005 1151
1006 if (rcu_access_pointer(tmp->pub.proberesp_ies)) { 1152 if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
1007 hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN); 1153 hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
@@ -1123,17 +1269,19 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
1123} 1269}
1124 1270
1125/* Returned bss is reference counted and must be cleaned up appropriately. */ 1271/* Returned bss is reference counted and must be cleaned up appropriately. */
1126struct cfg80211_bss * 1272static struct cfg80211_bss *
1127cfg80211_inform_bss_data(struct wiphy *wiphy, 1273cfg80211_inform_single_bss_data(struct wiphy *wiphy,
1128 struct cfg80211_inform_bss *data, 1274 struct cfg80211_inform_bss *data,
1129 enum cfg80211_bss_frame_type ftype, 1275 enum cfg80211_bss_frame_type ftype,
1130 const u8 *bssid, u64 tsf, u16 capability, 1276 const u8 *bssid, u64 tsf, u16 capability,
1131 u16 beacon_interval, const u8 *ie, size_t ielen, 1277 u16 beacon_interval, const u8 *ie, size_t ielen,
1132 gfp_t gfp) 1278 struct cfg80211_bss *trans_bss,
1279 gfp_t gfp)
1133{ 1280{
1281 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1134 struct cfg80211_bss_ies *ies; 1282 struct cfg80211_bss_ies *ies;
1135 struct ieee80211_channel *channel; 1283 struct ieee80211_channel *channel;
1136 struct cfg80211_internal_bss tmp = {}, *res; 1284 struct cfg80211_internal_bss tmp = {}, *res, *trans_internal;
1137 int bss_type; 1285 int bss_type;
1138 bool signal_valid; 1286 bool signal_valid;
1139 1287
@@ -1202,19 +1350,252 @@ cfg80211_inform_bss_data(struct wiphy *wiphy,
1202 regulatory_hint_found_beacon(wiphy, channel, gfp); 1350 regulatory_hint_found_beacon(wiphy, channel, gfp);
1203 } 1351 }
1204 1352
1353 if (trans_bss) {
1354 /* this is a nontransmitting bss, we need to add it to
1355 * transmitting bss' list if it is not there
1356 */
1357 trans_internal = container_of(trans_bss,
1358 struct cfg80211_internal_bss,
1359 pub);
1360 if (cfg80211_add_nontrans_list(trans_internal, res)) {
1361 if (__cfg80211_unlink_bss(rdev, res))
1362 rdev->bss_generation++;
1363 }
1364 }
1365
1205 trace_cfg80211_return_bss(&res->pub); 1366 trace_cfg80211_return_bss(&res->pub);
1206 /* cfg80211_bss_update gives us a referenced result */ 1367 /* cfg80211_bss_update gives us a referenced result */
1207 return &res->pub; 1368 return &res->pub;
1208} 1369}
1209EXPORT_SYMBOL(cfg80211_inform_bss_data);
1210 1370
1211/* cfg80211_inform_bss_width_frame helper */ 1371static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1372 struct cfg80211_inform_bss *data,
1373 enum cfg80211_bss_frame_type ftype,
1374 const u8 *bssid, u64 tsf,
1375 u16 beacon_interval, const u8 *ie,
1376 size_t ielen,
1377 struct cfg80211_bss *trans_bss,
1378 gfp_t gfp)
1379{
1380 const u8 *pos, *subelement, *mbssid_end_pos;
1381 const u8 *tmp, *mbssid_index_ie;
1382 size_t subie_len, new_ie_len;
1383 u8 new_bssid[ETH_ALEN];
1384 u8 *new_ie;
1385 u16 capability;
1386 struct cfg80211_bss *bss;
1387
1388 if (!trans_bss)
1389 return;
1390 if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
1391 return;
1392
1393 pos = ie;
1394
1395 new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp);
1396 if (!new_ie)
1397 return;
1398
1399 while (pos < ie + ielen + 2) {
1400 tmp = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, pos,
1401 ielen - (pos - ie));
1402 if (!tmp)
1403 break;
1404
1405 mbssid_end_pos = tmp + tmp[1] + 2;
1406 /* Skip Element ID, Len, MaxBSSID Indicator */
1407 if (tmp[1] < 4)
1408 break;
1409 for (subelement = tmp + 3; subelement < mbssid_end_pos - 1;
1410 subelement += 2 + subelement[1]) {
1411 subie_len = subelement[1];
1412 if (mbssid_end_pos - subelement < 2 + subie_len)
1413 break;
1414 if (subelement[0] != 0 || subelement[1] < 4) {
1415 /* not a valid BSS profile */
1416 continue;
1417 }
1418
1419 if (subelement[2] != WLAN_EID_NON_TX_BSSID_CAP ||
1420 subelement[3] != 2) {
1421 /* The first element within the Nontransmitted
1422 * BSSID Profile is not the Nontransmitted
1423 * BSSID Capability element.
1424 */
1425 continue;
1426 }
1427
1428 /* found a Nontransmitted BSSID Profile */
1429 mbssid_index_ie = cfg80211_find_ie
1430 (WLAN_EID_MULTI_BSSID_IDX,
1431 subelement + 2, subie_len);
1432 if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
1433 mbssid_index_ie[2] == 0) {
1434 /* No valid Multiple BSSID-Index element */
1435 continue;
1436 }
1437
1438 cfg80211_gen_new_bssid(bssid, tmp[2],
1439 mbssid_index_ie[2],
1440 new_bssid);
1441 memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
1442 new_ie_len = cfg80211_gen_new_ie(ie, ielen,
1443 subelement + 2,
1444 subie_len, new_ie,
1445 gfp);
1446 if (!new_ie_len)
1447 continue;
1448
1449 capability = le16_to_cpup((const __le16 *)
1450 &subelement[4]);
1451 bss = cfg80211_inform_single_bss_data(wiphy, data,
1452 ftype,
1453 new_bssid, tsf,
1454 capability,
1455 beacon_interval,
1456 new_ie,
1457 new_ie_len,
1458 trans_bss, gfp);
1459 if (!bss)
1460 break;
1461 cfg80211_put_bss(wiphy, bss);
1462 }
1463
1464 pos = mbssid_end_pos;
1465 }
1466
1467 kfree(new_ie);
1468}
1469
1212struct cfg80211_bss * 1470struct cfg80211_bss *
1213cfg80211_inform_bss_frame_data(struct wiphy *wiphy, 1471cfg80211_inform_bss_data(struct wiphy *wiphy,
1214 struct cfg80211_inform_bss *data, 1472 struct cfg80211_inform_bss *data,
1215 struct ieee80211_mgmt *mgmt, size_t len, 1473 enum cfg80211_bss_frame_type ftype,
1216 gfp_t gfp) 1474 const u8 *bssid, u64 tsf, u16 capability,
1475 u16 beacon_interval, const u8 *ie, size_t ielen,
1476 gfp_t gfp)
1477{
1478 struct cfg80211_bss *res;
1479
1480 res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf,
1481 capability, beacon_interval, ie,
1482 ielen, NULL, gfp);
1483 cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf,
1484 beacon_interval, ie, ielen, res, gfp);
1485 return res;
1486}
1487EXPORT_SYMBOL(cfg80211_inform_bss_data);
1217 1488
1489static void
1490cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy,
1491 struct cfg80211_inform_bss *data,
1492 struct ieee80211_mgmt *mgmt, size_t len,
1493 struct cfg80211_bss *trans_bss,
1494 gfp_t gfp)
1495{
1496 enum cfg80211_bss_frame_type ftype;
1497 const u8 *ie = mgmt->u.probe_resp.variable;
1498 size_t ielen = len - offsetof(struct ieee80211_mgmt,
1499 u.probe_resp.variable);
1500
1501 ftype = ieee80211_is_beacon(mgmt->frame_control) ?
1502 CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP;
1503
1504 cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid,
1505 le64_to_cpu(mgmt->u.probe_resp.timestamp),
1506 le16_to_cpu(mgmt->u.probe_resp.beacon_int),
1507 ie, ielen, trans_bss, gfp);
1508}
1509
1510static void
1511cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
1512 struct cfg80211_internal_bss *nontrans_bss,
1513 struct ieee80211_mgmt *mgmt, size_t len,
1514 gfp_t gfp)
1515{
1516 u8 *ie, *new_ie, *pos;
1517 const u8 *nontrans_ssid, *trans_ssid, *mbssid;
1518 size_t ielen = len - offsetof(struct ieee80211_mgmt,
1519 u.probe_resp.variable);
1520 size_t new_ie_len;
1521 struct cfg80211_bss_ies *new_ies;
1522 const struct cfg80211_bss_ies *old;
1523 u8 cpy_len;
1524
1525 ie = mgmt->u.probe_resp.variable;
1526
1527 new_ie_len = ielen;
1528 trans_ssid = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
1529 if (!trans_ssid)
1530 return;
1531 new_ie_len -= trans_ssid[1];
1532 mbssid = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen);
1533 if (!mbssid)
1534 return;
1535 new_ie_len -= mbssid[1];
1536 rcu_read_lock();
1537 nontrans_ssid = ieee80211_bss_get_ie(&nontrans_bss->pub, WLAN_EID_SSID);
1538 if (!nontrans_ssid) {
1539 rcu_read_unlock();
1540 return;
1541 }
1542 new_ie_len += nontrans_ssid[1];
1543 rcu_read_unlock();
1544
1545 /* generate new ie for nontrans BSS
1546 * 1. replace SSID with nontrans BSS' SSID
1547 * 2. skip MBSSID IE
1548 */
1549 new_ie = kzalloc(new_ie_len, gfp);
1550 if (!new_ie)
1551 return;
1552 new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, gfp);
1553 if (!new_ies) {
1554 kfree(new_ie);
1555 return;
1556 }
1557
1558 pos = new_ie;
1559
1560 /* copy the nontransmitted SSID */
1561 cpy_len = nontrans_ssid[1] + 2;
1562 memcpy(pos, nontrans_ssid, cpy_len);
1563 pos += cpy_len;
1564 /* copy the IEs between SSID and MBSSID */
1565 cpy_len = trans_ssid[1] + 2;
1566 memcpy(pos, (trans_ssid + cpy_len), (mbssid - (trans_ssid + cpy_len)));
1567 pos += (mbssid - (trans_ssid + cpy_len));
1568 /* copy the IEs after MBSSID */
1569 cpy_len = mbssid[1] + 2;
1570 memcpy(pos, mbssid + cpy_len, ((ie + ielen) - (mbssid + cpy_len)));
1571
1572 /* update ie */
1573 new_ies->len = new_ie_len;
1574 new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
1575 new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
1576 memcpy(new_ies->data, new_ie, new_ie_len);
1577 if (ieee80211_is_probe_resp(mgmt->frame_control)) {
1578 old = rcu_access_pointer(nontrans_bss->pub.proberesp_ies);
1579 rcu_assign_pointer(nontrans_bss->pub.proberesp_ies, new_ies);
1580 rcu_assign_pointer(nontrans_bss->pub.ies, new_ies);
1581 if (old)
1582 kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1583 } else {
1584 old = rcu_access_pointer(nontrans_bss->pub.beacon_ies);
1585 rcu_assign_pointer(nontrans_bss->pub.beacon_ies, new_ies);
1586 rcu_assign_pointer(nontrans_bss->pub.ies, new_ies);
1587 if (old)
1588 kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
1589 }
1590}
1591
1592/* cfg80211_inform_bss_width_frame helper */
1593static struct cfg80211_bss *
1594cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
1595 struct cfg80211_inform_bss *data,
1596 struct ieee80211_mgmt *mgmt, size_t len,
1597 struct cfg80211_bss *trans_bss,
1598 gfp_t gfp)
1218{ 1599{
1219 struct cfg80211_internal_bss tmp = {}, *res; 1600 struct cfg80211_internal_bss tmp = {}, *res;
1220 struct cfg80211_bss_ies *ies; 1601 struct cfg80211_bss_ies *ies;
@@ -1293,6 +1674,50 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
1293 /* cfg80211_bss_update gives us a referenced result */ 1674 /* cfg80211_bss_update gives us a referenced result */
1294 return &res->pub; 1675 return &res->pub;
1295} 1676}
1677
1678struct cfg80211_bss *
1679cfg80211_inform_bss_frame_data(struct wiphy *wiphy,
1680 struct cfg80211_inform_bss *data,
1681 struct ieee80211_mgmt *mgmt, size_t len,
1682 gfp_t gfp)
1683{
1684 struct cfg80211_bss *res;
1685 struct cfg80211_internal_bss *trans_bss, *tmp_bss;
1686 const u8 *ie = mgmt->u.probe_resp.variable;
1687 const struct cfg80211_bss_ies *ies1, *ies2;
1688 size_t ielen = len - offsetof(struct ieee80211_mgmt,
1689 u.probe_resp.variable);
1690
1691 res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
1692 len, NULL, gfp);
1693 if (!res || !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
1694 return res;
1695
1696 /* process each non-transmitting bss */
1697 cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len, res, gfp);
1698
1699 /* check if the res has other nontransmitting bss which is not
1700 * in MBSSID IE
1701 */
1702 ies1 = rcu_access_pointer(res->ies);
1703 trans_bss = container_of(res, struct cfg80211_internal_bss, pub);
1704 if (!trans_bss)
1705 return res;
1706
1707 /* go through nontrans_list, if the timestamp of the BSS is
1708 * earlier than the timestamp of the transmitting BSS then
1709 * update it
1710 */
1711 list_for_each_entry(tmp_bss, &trans_bss->nontrans_list,
1712 nontrans_list) {
1713 ies2 = rcu_access_pointer(tmp_bss->pub.ies);
1714 if (ies2->tsf < ies1->tsf)
1715 cfg80211_update_notlisted_nontrans(wiphy, tmp_bss,
1716 mgmt, len, gfp);
1717 }
1718
1719 return res;
1720}
1296EXPORT_SYMBOL(cfg80211_inform_bss_frame_data); 1721EXPORT_SYMBOL(cfg80211_inform_bss_frame_data);
1297 1722
1298void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) 1723void cfg80211_ref_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
@@ -1330,7 +1755,7 @@ EXPORT_SYMBOL(cfg80211_put_bss);
1330void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) 1755void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
1331{ 1756{
1332 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); 1757 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
1333 struct cfg80211_internal_bss *bss; 1758 struct cfg80211_internal_bss *bss, *nontrans_bss, *tmp;
1334 1759
1335 if (WARN_ON(!pub)) 1760 if (WARN_ON(!pub))
1336 return; 1761 return;
@@ -1339,6 +1764,13 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
1339 1764
1340 spin_lock_bh(&rdev->bss_lock); 1765 spin_lock_bh(&rdev->bss_lock);
1341 if (!list_empty(&bss->list)) { 1766 if (!list_empty(&bss->list)) {
1767 list_for_each_entry_safe(nontrans_bss, tmp,
1768 &bss->nontrans_list,
1769 nontrans_list) {
1770 if (__cfg80211_unlink_bss(rdev, nontrans_bss))
1771 rdev->bss_generation++;
1772 }
1773
1342 if (__cfg80211_unlink_bss(rdev, bss)) 1774 if (__cfg80211_unlink_bss(rdev, bss))
1343 rdev->bss_generation++; 1775 rdev->bss_generation++;
1344 } 1776 }