aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/scan.c
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2019-03-15 11:39:05 -0400
committerJohannes Berg <johannes.berg@intel.com>2019-04-26 07:02:11 -0400
commitfe806e4992c9047affd263bcc13b2c047029a726 (patch)
tree817e5848f2104c8307ceecf8a5c0f32c1df32034 /net/wireless/scan.c
parent671042a4fb77e0a0c2db595fd8e5ef5f7ba75bbe (diff)
cfg80211: support profile split between elements
Since an element is limited to 255 octets, a profile may be split split to several elements. Support the split as defined in the 11ax draft 3. Detect legacy split and print a net-rate limited warning, since there is no ROI in supporting this probably non-existent split. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r--net/wireless/scan.c109
1 files changed, 103 insertions, 6 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index bda9114ded77..878c867f3f7d 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1456,6 +1456,78 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
1456 return &res->pub; 1456 return &res->pub;
1457} 1457}
1458 1458
1459static const struct element
1460*cfg80211_get_profile_continuation(const u8 *ie, size_t ielen,
1461 const struct element *mbssid_elem,
1462 const struct element *sub_elem)
1463{
1464 const u8 *mbssid_end = mbssid_elem->data + mbssid_elem->datalen;
1465 const struct element *next_mbssid;
1466 const struct element *next_sub;
1467
1468 next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
1469 mbssid_end,
1470 ielen - (mbssid_end - ie));
1471
1472 /*
1473 * If is is not the last subelement in current MBSSID IE or there isn't
1474 * a next MBSSID IE - profile is complete.
1475 */
1476 if ((sub_elem->data + sub_elem->datalen < mbssid_end - 1) ||
1477 !next_mbssid)
1478 return NULL;
1479
1480 /* For any length error, just return NULL */
1481
1482 if (next_mbssid->datalen < 4)
1483 return NULL;
1484
1485 next_sub = (void *)&next_mbssid->data[1];
1486
1487 if (next_mbssid->data + next_mbssid->datalen <
1488 next_sub->data + next_sub->datalen)
1489 return NULL;
1490
1491 if (next_sub->id != 0 || next_sub->datalen < 2)
1492 return NULL;
1493
1494 /*
1495 * Check if the first element in the next sub element is a start
1496 * of a new profile
1497 */
1498 return next_sub->data[0] == WLAN_EID_NON_TX_BSSID_CAP ?
1499 NULL : next_mbssid;
1500}
1501
1502size_t cfg80211_merge_profile(const u8 *ie, size_t ielen,
1503 const struct element *mbssid_elem,
1504 const struct element *sub_elem,
1505 u8 **merged_ie, size_t max_copy_len)
1506{
1507 size_t copied_len = sub_elem->datalen;
1508 const struct element *next_mbssid;
1509
1510 if (sub_elem->datalen > max_copy_len)
1511 return 0;
1512
1513 memcpy(*merged_ie, sub_elem->data, sub_elem->datalen);
1514
1515 while ((next_mbssid = cfg80211_get_profile_continuation(ie, ielen,
1516 mbssid_elem,
1517 sub_elem))) {
1518 const struct element *next_sub = (void *)&next_mbssid->data[1];
1519
1520 if (copied_len + next_sub->datalen > max_copy_len)
1521 break;
1522 memcpy(*merged_ie + copied_len, next_sub->data,
1523 next_sub->datalen);
1524 copied_len += next_sub->datalen;
1525 }
1526
1527 return copied_len;
1528}
1529EXPORT_SYMBOL(cfg80211_merge_profile);
1530
1459static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, 1531static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1460 struct cfg80211_inform_bss *data, 1532 struct cfg80211_inform_bss *data,
1461 enum cfg80211_bss_frame_type ftype, 1533 enum cfg80211_bss_frame_type ftype,
@@ -1469,7 +1541,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1469 const struct element *elem, *sub; 1541 const struct element *elem, *sub;
1470 size_t new_ie_len; 1542 size_t new_ie_len;
1471 u8 new_bssid[ETH_ALEN]; 1543 u8 new_bssid[ETH_ALEN];
1472 u8 *new_ie; 1544 u8 *new_ie, *profile;
1545 u64 seen_indices = 0;
1473 u16 capability; 1546 u16 capability;
1474 struct cfg80211_bss *bss; 1547 struct cfg80211_bss *bss;
1475 1548
@@ -1487,10 +1560,16 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1487 if (!new_ie) 1560 if (!new_ie)
1488 return; 1561 return;
1489 1562
1563 profile = kmalloc(ielen, gfp);
1564 if (!profile)
1565 goto out;
1566
1490 for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) { 1567 for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
1491 if (elem->datalen < 4) 1568 if (elem->datalen < 4)
1492 continue; 1569 continue;
1493 for_each_element(sub, elem->data + 1, elem->datalen - 1) { 1570 for_each_element(sub, elem->data + 1, elem->datalen - 1) {
1571 u8 profile_len;
1572
1494 if (sub->id != 0 || sub->datalen < 4) { 1573 if (sub->id != 0 || sub->datalen < 4) {
1495 /* not a valid BSS profile */ 1574 /* not a valid BSS profile */
1496 continue; 1575 continue;
@@ -1505,16 +1584,31 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1505 continue; 1584 continue;
1506 } 1585 }
1507 1586
1587 memset(profile, 0, ielen);
1588 profile_len = cfg80211_merge_profile(ie, ielen,
1589 elem,
1590 sub,
1591 &profile,
1592 ielen);
1593
1508 /* found a Nontransmitted BSSID Profile */ 1594 /* found a Nontransmitted BSSID Profile */
1509 mbssid_index_ie = cfg80211_find_ie 1595 mbssid_index_ie = cfg80211_find_ie
1510 (WLAN_EID_MULTI_BSSID_IDX, 1596 (WLAN_EID_MULTI_BSSID_IDX,
1511 sub->data, sub->datalen); 1597 profile, profile_len);
1512 if (!mbssid_index_ie || mbssid_index_ie[1] < 1 || 1598 if (!mbssid_index_ie || mbssid_index_ie[1] < 1 ||
1513 mbssid_index_ie[2] == 0) { 1599 mbssid_index_ie[2] == 0 ||
1600 mbssid_index_ie[2] > 46) {
1514 /* No valid Multiple BSSID-Index element */ 1601 /* No valid Multiple BSSID-Index element */
1515 continue; 1602 continue;
1516 } 1603 }
1517 1604
1605 if (seen_indices & BIT(mbssid_index_ie[2]))
1606 /* We don't support legacy split of a profile */
1607 net_dbg_ratelimited("Partial info for BSSID index %d\n",
1608 mbssid_index_ie[2]);
1609
1610 seen_indices |= BIT(mbssid_index_ie[2]);
1611
1518 non_tx_data->bssid_index = mbssid_index_ie[2]; 1612 non_tx_data->bssid_index = mbssid_index_ie[2];
1519 non_tx_data->max_bssid_indicator = elem->data[0]; 1613 non_tx_data->max_bssid_indicator = elem->data[0];
1520 1614
@@ -1523,13 +1617,14 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1523 non_tx_data->bssid_index, 1617 non_tx_data->bssid_index,
1524 new_bssid); 1618 new_bssid);
1525 memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); 1619 memset(new_ie, 0, IEEE80211_MAX_DATA_LEN);
1526 new_ie_len = cfg80211_gen_new_ie(ie, ielen, sub->data, 1620 new_ie_len = cfg80211_gen_new_ie(ie, ielen,
1527 sub->datalen, new_ie, 1621 profile,
1622 profile_len, new_ie,
1528 gfp); 1623 gfp);
1529 if (!new_ie_len) 1624 if (!new_ie_len)
1530 continue; 1625 continue;
1531 1626
1532 capability = get_unaligned_le16(sub->data + 2); 1627 capability = get_unaligned_le16(profile + 2);
1533 bss = cfg80211_inform_single_bss_data(wiphy, data, 1628 bss = cfg80211_inform_single_bss_data(wiphy, data,
1534 ftype, 1629 ftype,
1535 new_bssid, tsf, 1630 new_bssid, tsf,
@@ -1545,7 +1640,9 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
1545 } 1640 }
1546 } 1641 }
1547 1642
1643out:
1548 kfree(new_ie); 1644 kfree(new_ie);
1645 kfree(profile);
1549} 1646}
1550 1647
1551struct cfg80211_bss * 1648struct cfg80211_bss *