diff options
author | David S. Miller <davem@davemloft.net> | 2018-06-30 08:08:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-06-30 08:08:12 -0400 |
commit | 8365da2c0570f02615e7f1d2d729d854029202b0 (patch) | |
tree | 223ab9641411c401269e5da80f260cafaf40eedc /net/mac80211/util.c | |
parent | a1be5a20f137bdf436bab86c18998229908ce951 (diff) | |
parent | a4217750586975dee7d6dd8829a1be24a7678b3d (diff) |
Merge tag 'mac80211-next-for-davem-2018-06-29' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Small merge conflict in net/mac80211/scan.c, I preserved
the kcalloc() conversion. -DaveM
Johannes Berg says:
====================
This round's updates:
* finally some of the promised HE code, but it turns
out to be small - but everything kept changing, so
one part I did in the driver was >30 patches for
what was ultimately <200 lines of code ... similar
here for this code.
* improved scan privacy support - can now specify scan
flags for randomizing the sequence number as well as
reducing the probe request element content
* rfkill cleanups
* a timekeeping cleanup from Arnd
* various other cleanups
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 159 |
1 files changed, 127 insertions, 32 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5e2e511c4a6f..3e68132a41fa 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1095,6 +1095,21 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, | |||
1095 | if (elen >= sizeof(*elems->max_idle_period_ie)) | 1095 | if (elen >= sizeof(*elems->max_idle_period_ie)) |
1096 | elems->max_idle_period_ie = (void *)pos; | 1096 | elems->max_idle_period_ie = (void *)pos; |
1097 | break; | 1097 | break; |
1098 | case WLAN_EID_EXTENSION: | ||
1099 | if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA && | ||
1100 | elen >= (sizeof(*elems->mu_edca_param_set) + 1)) { | ||
1101 | elems->mu_edca_param_set = (void *)&pos[1]; | ||
1102 | } else if (pos[0] == WLAN_EID_EXT_HE_CAPABILITY) { | ||
1103 | elems->he_cap = (void *)&pos[1]; | ||
1104 | elems->he_cap_len = elen - 1; | ||
1105 | } else if (pos[0] == WLAN_EID_EXT_HE_OPERATION && | ||
1106 | elen >= sizeof(*elems->he_operation) && | ||
1107 | elen >= ieee80211_he_oper_size(&pos[1])) { | ||
1108 | elems->he_operation = (void *)&pos[1]; | ||
1109 | } else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) { | ||
1110 | elems->uora_element = (void *)&pos[1]; | ||
1111 | } | ||
1112 | break; | ||
1098 | default: | 1113 | default: |
1099 | break; | 1114 | break; |
1100 | } | 1115 | } |
@@ -1353,9 +1368,10 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
1353 | enum nl80211_band band, | 1368 | enum nl80211_band band, |
1354 | u32 rate_mask, | 1369 | u32 rate_mask, |
1355 | struct cfg80211_chan_def *chandef, | 1370 | struct cfg80211_chan_def *chandef, |
1356 | size_t *offset) | 1371 | size_t *offset, u32 flags) |
1357 | { | 1372 | { |
1358 | struct ieee80211_supported_band *sband; | 1373 | struct ieee80211_supported_band *sband; |
1374 | const struct ieee80211_sta_he_cap *he_cap; | ||
1359 | u8 *pos = buffer, *end = buffer + buffer_len; | 1375 | u8 *pos = buffer, *end = buffer + buffer_len; |
1360 | size_t noffset; | 1376 | size_t noffset; |
1361 | int supp_rates_len, i; | 1377 | int supp_rates_len, i; |
@@ -1433,6 +1449,9 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
1433 | chandef->chan->center_freq); | 1449 | chandef->chan->center_freq); |
1434 | } | 1450 | } |
1435 | 1451 | ||
1452 | if (flags & IEEE80211_PROBE_FLAG_MIN_CONTENT) | ||
1453 | goto done; | ||
1454 | |||
1436 | /* insert custom IEs that go before HT */ | 1455 | /* insert custom IEs that go before HT */ |
1437 | if (ie && ie_len) { | 1456 | if (ie && ie_len) { |
1438 | static const u8 before_ht[] = { | 1457 | static const u8 before_ht[] = { |
@@ -1460,11 +1479,6 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
1460 | sband->ht_cap.cap); | 1479 | sband->ht_cap.cap); |
1461 | } | 1480 | } |
1462 | 1481 | ||
1463 | /* | ||
1464 | * If adding more here, adjust code in main.c | ||
1465 | * that calculates local->scan_ies_len. | ||
1466 | */ | ||
1467 | |||
1468 | /* insert custom IEs that go before VHT */ | 1482 | /* insert custom IEs that go before VHT */ |
1469 | if (ie && ie_len) { | 1483 | if (ie && ie_len) { |
1470 | static const u8 before_vht[] = { | 1484 | static const u8 before_vht[] = { |
@@ -1507,9 +1521,43 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local, | |||
1507 | sband->vht_cap.cap); | 1521 | sband->vht_cap.cap); |
1508 | } | 1522 | } |
1509 | 1523 | ||
1524 | /* insert custom IEs that go before HE */ | ||
1525 | if (ie && ie_len) { | ||
1526 | static const u8 before_he[] = { | ||
1527 | /* | ||
1528 | * no need to list the ones split off before VHT | ||
1529 | * or generated here | ||
1530 | */ | ||
1531 | WLAN_EID_EXTENSION, WLAN_EID_EXT_FILS_REQ_PARAMS, | ||
1532 | WLAN_EID_AP_CSN, | ||
1533 | /* TODO: add 11ah/11aj/11ak elements */ | ||
1534 | }; | ||
1535 | noffset = ieee80211_ie_split(ie, ie_len, | ||
1536 | before_he, ARRAY_SIZE(before_he), | ||
1537 | *offset); | ||
1538 | if (end - pos < noffset - *offset) | ||
1539 | goto out_err; | ||
1540 | memcpy(pos, ie + *offset, noffset - *offset); | ||
1541 | pos += noffset - *offset; | ||
1542 | *offset = noffset; | ||
1543 | } | ||
1544 | |||
1545 | he_cap = ieee80211_get_he_sta_cap(sband); | ||
1546 | if (he_cap) { | ||
1547 | pos = ieee80211_ie_build_he_cap(pos, he_cap, end); | ||
1548 | if (!pos) | ||
1549 | goto out_err; | ||
1550 | } | ||
1551 | |||
1552 | /* | ||
1553 | * If adding more here, adjust code in main.c | ||
1554 | * that calculates local->scan_ies_len. | ||
1555 | */ | ||
1556 | |||
1510 | return pos - buffer; | 1557 | return pos - buffer; |
1511 | out_err: | 1558 | out_err: |
1512 | WARN_ONCE(1, "not enough space for preq IEs\n"); | 1559 | WARN_ONCE(1, "not enough space for preq IEs\n"); |
1560 | done: | ||
1513 | return pos - buffer; | 1561 | return pos - buffer; |
1514 | } | 1562 | } |
1515 | 1563 | ||
@@ -1518,7 +1566,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1518 | struct ieee80211_scan_ies *ie_desc, | 1566 | struct ieee80211_scan_ies *ie_desc, |
1519 | const u8 *ie, size_t ie_len, | 1567 | const u8 *ie, size_t ie_len, |
1520 | u8 bands_used, u32 *rate_masks, | 1568 | u8 bands_used, u32 *rate_masks, |
1521 | struct cfg80211_chan_def *chandef) | 1569 | struct cfg80211_chan_def *chandef, |
1570 | u32 flags) | ||
1522 | { | 1571 | { |
1523 | size_t pos = 0, old_pos = 0, custom_ie_offset = 0; | 1572 | size_t pos = 0, old_pos = 0, custom_ie_offset = 0; |
1524 | int i; | 1573 | int i; |
@@ -1533,7 +1582,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1533 | ie, ie_len, i, | 1582 | ie, ie_len, i, |
1534 | rate_masks[i], | 1583 | rate_masks[i], |
1535 | chandef, | 1584 | chandef, |
1536 | &custom_ie_offset); | 1585 | &custom_ie_offset, |
1586 | flags); | ||
1537 | ie_desc->ies[i] = buffer + old_pos; | 1587 | ie_desc->ies[i] = buffer + old_pos; |
1538 | ie_desc->len[i] = pos - old_pos; | 1588 | ie_desc->len[i] = pos - old_pos; |
1539 | old_pos = pos; | 1589 | old_pos = pos; |
@@ -1561,7 +1611,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1561 | struct ieee80211_channel *chan, | 1611 | struct ieee80211_channel *chan, |
1562 | const u8 *ssid, size_t ssid_len, | 1612 | const u8 *ssid, size_t ssid_len, |
1563 | const u8 *ie, size_t ie_len, | 1613 | const u8 *ie, size_t ie_len, |
1564 | bool directed) | 1614 | u32 flags) |
1565 | { | 1615 | { |
1566 | struct ieee80211_local *local = sdata->local; | 1616 | struct ieee80211_local *local = sdata->local; |
1567 | struct cfg80211_chan_def chandef; | 1617 | struct cfg80211_chan_def chandef; |
@@ -1577,7 +1627,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1577 | * badly-behaved APs don't respond when this parameter is included. | 1627 | * badly-behaved APs don't respond when this parameter is included. |
1578 | */ | 1628 | */ |
1579 | chandef.width = sdata->vif.bss_conf.chandef.width; | 1629 | chandef.width = sdata->vif.bss_conf.chandef.width; |
1580 | if (directed) | 1630 | if (flags & IEEE80211_PROBE_FLAG_DIRECTED) |
1581 | chandef.chan = NULL; | 1631 | chandef.chan = NULL; |
1582 | else | 1632 | else |
1583 | chandef.chan = chan; | 1633 | chandef.chan = chan; |
@@ -1591,7 +1641,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1591 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | 1641 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), |
1592 | skb_tailroom(skb), &dummy_ie_desc, | 1642 | skb_tailroom(skb), &dummy_ie_desc, |
1593 | ie, ie_len, BIT(chan->band), | 1643 | ie, ie_len, BIT(chan->band), |
1594 | rate_masks, &chandef); | 1644 | rate_masks, &chandef, flags); |
1595 | skb_put(skb, ies_len); | 1645 | skb_put(skb, ies_len); |
1596 | 1646 | ||
1597 | if (dst) { | 1647 | if (dst) { |
@@ -1605,27 +1655,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1605 | return skb; | 1655 | return skb; |
1606 | } | 1656 | } |
1607 | 1657 | ||
1608 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, | ||
1609 | const u8 *src, const u8 *dst, | ||
1610 | const u8 *ssid, size_t ssid_len, | ||
1611 | const u8 *ie, size_t ie_len, | ||
1612 | u32 ratemask, bool directed, u32 tx_flags, | ||
1613 | struct ieee80211_channel *channel, bool scan) | ||
1614 | { | ||
1615 | struct sk_buff *skb; | ||
1616 | |||
1617 | skb = ieee80211_build_probe_req(sdata, src, dst, ratemask, channel, | ||
1618 | ssid, ssid_len, | ||
1619 | ie, ie_len, directed); | ||
1620 | if (skb) { | ||
1621 | IEEE80211_SKB_CB(skb)->flags |= tx_flags; | ||
1622 | if (scan) | ||
1623 | ieee80211_tx_skb_tid_band(sdata, skb, 7, channel->band); | ||
1624 | else | ||
1625 | ieee80211_tx_skb(sdata, skb); | ||
1626 | } | ||
1627 | } | ||
1628 | |||
1629 | u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, | 1658 | u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, |
1630 | struct ieee802_11_elems *elems, | 1659 | struct ieee802_11_elems *elems, |
1631 | enum nl80211_band band, u32 *basic_rates) | 1660 | enum nl80211_band band, u32 *basic_rates) |
@@ -2412,6 +2441,72 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, | |||
2412 | return pos; | 2441 | return pos; |
2413 | } | 2442 | } |
2414 | 2443 | ||
2444 | u8 *ieee80211_ie_build_he_cap(u8 *pos, | ||
2445 | const struct ieee80211_sta_he_cap *he_cap, | ||
2446 | u8 *end) | ||
2447 | { | ||
2448 | u8 n; | ||
2449 | u8 ie_len; | ||
2450 | u8 *orig_pos = pos; | ||
2451 | |||
2452 | /* Make sure we have place for the IE */ | ||
2453 | /* | ||
2454 | * TODO: the 1 added is because this temporarily is under the EXTENSION | ||
2455 | * IE. Get rid of it when it moves. | ||
2456 | */ | ||
2457 | if (!he_cap) | ||
2458 | return orig_pos; | ||
2459 | |||
2460 | n = ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem); | ||
2461 | ie_len = 2 + 1 + | ||
2462 | sizeof(he_cap->he_cap_elem) + n + | ||
2463 | ieee80211_he_ppe_size(he_cap->ppe_thres[0], | ||
2464 | he_cap->he_cap_elem.phy_cap_info); | ||
2465 | |||
2466 | if ((end - pos) < ie_len) | ||
2467 | return orig_pos; | ||
2468 | |||
2469 | *pos++ = WLAN_EID_EXTENSION; | ||
2470 | pos++; /* We'll set the size later below */ | ||
2471 | *pos++ = WLAN_EID_EXT_HE_CAPABILITY; | ||
2472 | |||
2473 | /* Fixed data */ | ||
2474 | memcpy(pos, &he_cap->he_cap_elem, sizeof(he_cap->he_cap_elem)); | ||
2475 | pos += sizeof(he_cap->he_cap_elem); | ||
2476 | |||
2477 | memcpy(pos, &he_cap->he_mcs_nss_supp, n); | ||
2478 | pos += n; | ||
2479 | |||
2480 | /* Check if PPE Threshold should be present */ | ||
2481 | if ((he_cap->he_cap_elem.phy_cap_info[6] & | ||
2482 | IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) == 0) | ||
2483 | goto end; | ||
2484 | |||
2485 | /* | ||
2486 | * Calculate how many PPET16/PPET8 pairs are to come. Algorithm: | ||
2487 | * (NSS_M1 + 1) x (num of 1 bits in RU_INDEX_BITMASK) | ||
2488 | */ | ||
2489 | n = hweight8(he_cap->ppe_thres[0] & | ||
2490 | IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK); | ||
2491 | n *= (1 + ((he_cap->ppe_thres[0] & IEEE80211_PPE_THRES_NSS_MASK) >> | ||
2492 | IEEE80211_PPE_THRES_NSS_POS)); | ||
2493 | |||
2494 | /* | ||
2495 | * Each pair is 6 bits, and we need to add the 7 "header" bits to the | ||
2496 | * total size. | ||
2497 | */ | ||
2498 | n = (n * IEEE80211_PPE_THRES_INFO_PPET_SIZE * 2) + 7; | ||
2499 | n = DIV_ROUND_UP(n, 8); | ||
2500 | |||
2501 | /* Copy PPE Thresholds */ | ||
2502 | memcpy(pos, &he_cap->ppe_thres, n); | ||
2503 | pos += n; | ||
2504 | |||
2505 | end: | ||
2506 | orig_pos[1] = (pos - orig_pos) - 2; | ||
2507 | return pos; | ||
2508 | } | ||
2509 | |||
2415 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, | 2510 | u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, |
2416 | const struct cfg80211_chan_def *chandef, | 2511 | const struct cfg80211_chan_def *chandef, |
2417 | u16 prot_mode, bool rifs_mode) | 2512 | u16 prot_mode, bool rifs_mode) |