diff options
author | Sara Sharon <sara.sharon@intel.com> | 2019-03-15 11:39:05 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2019-04-26 07:02:11 -0400 |
commit | fe806e4992c9047affd263bcc13b2c047029a726 (patch) | |
tree | 817e5848f2104c8307ceecf8a5c0f32c1df32034 /net/wireless/scan.c | |
parent | 671042a4fb77e0a0c2db595fd8e5ef5f7ba75bbe (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.c | 109 |
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 | ||
1459 | static 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 | |||
1502 | size_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 | } | ||
1529 | EXPORT_SYMBOL(cfg80211_merge_profile); | ||
1530 | |||
1459 | static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, | 1531 | static 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 | ||
1643 | out: | ||
1548 | kfree(new_ie); | 1644 | kfree(new_ie); |
1645 | kfree(profile); | ||
1549 | } | 1646 | } |
1550 | 1647 | ||
1551 | struct cfg80211_bss * | 1648 | struct cfg80211_bss * |