diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2011-10-14 18:14:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-09 16:00:59 -0500 |
commit | c74d084f914e16e42730bcf625ab3f37a4cae8d4 (patch) | |
tree | 2d25a95c18b679d2bd56fae50d2f185851c0d8d5 /net/mac80211/mlme.c | |
parent | fa5e91bc7715c772342b197269a85aa3ced16900 (diff) |
mac80211: handle HT PHY BSS membership selector value correctly
802.11n-2009 extends the supported rates element with a
magic value which can be used to prevent legacy stations
from joining the BSS.
However, this magic value is not a rate like the others
and the magic can simply be ignored/skipped at this late
stage.
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>---
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 90 |
1 files changed, 49 insertions, 41 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d3b408cda08d..b25567a32f92 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1466,6 +1466,47 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1466 | return RX_MGMT_CFG80211_DISASSOC; | 1466 | return RX_MGMT_CFG80211_DISASSOC; |
1467 | } | 1467 | } |
1468 | 1468 | ||
1469 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | ||
1470 | u8 *supp_rates, unsigned int supp_rates_len, | ||
1471 | u32 *rates, u32 *basic_rates, | ||
1472 | bool *have_higher_than_11mbit, | ||
1473 | int *min_rate, int *min_rate_index) | ||
1474 | { | ||
1475 | int i, j; | ||
1476 | |||
1477 | for (i = 0; i < supp_rates_len; i++) { | ||
1478 | int rate = (supp_rates[i] & 0x7f) * 5; | ||
1479 | bool is_basic = !!(supp_rates[i] & 0x80); | ||
1480 | |||
1481 | if (rate > 110) | ||
1482 | *have_higher_than_11mbit = true; | ||
1483 | |||
1484 | /* | ||
1485 | * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009 | ||
1486 | * 7.3.2.2 as a magic value instead of a rate. Hence, skip it. | ||
1487 | * | ||
1488 | * Note: Even through the membership selector and the basic | ||
1489 | * rate flag share the same bit, they are not exactly | ||
1490 | * the same. | ||
1491 | */ | ||
1492 | if (!!(supp_rates[i] & 0x80) && | ||
1493 | (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY) | ||
1494 | continue; | ||
1495 | |||
1496 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1497 | if (sband->bitrates[j].bitrate == rate) { | ||
1498 | *rates |= BIT(j); | ||
1499 | if (is_basic) | ||
1500 | *basic_rates |= BIT(j); | ||
1501 | if (rate < *min_rate) { | ||
1502 | *min_rate = rate; | ||
1503 | *min_rate_index = j; | ||
1504 | } | ||
1505 | break; | ||
1506 | } | ||
1507 | } | ||
1508 | } | ||
1509 | } | ||
1469 | 1510 | ||
1470 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, | 1511 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, |
1471 | struct ieee80211_mgmt *mgmt, size_t len) | 1512 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -1482,7 +1523,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1482 | struct ieee802_11_elems elems; | 1523 | struct ieee802_11_elems elems; |
1483 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1524 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
1484 | u32 changed = 0; | 1525 | u32 changed = 0; |
1485 | int i, j, err; | 1526 | int err; |
1486 | bool have_higher_than_11mbit = false; | 1527 | bool have_higher_than_11mbit = false; |
1487 | u16 ap_ht_cap_flags; | 1528 | u16 ap_ht_cap_flags; |
1488 | int min_rate = INT_MAX, min_rate_index = -1; | 1529 | int min_rate = INT_MAX, min_rate_index = -1; |
@@ -1540,47 +1581,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1540 | basic_rates = 0; | 1581 | basic_rates = 0; |
1541 | sband = local->hw.wiphy->bands[wk->chan->band]; | 1582 | sband = local->hw.wiphy->bands[wk->chan->band]; |
1542 | 1583 | ||
1543 | for (i = 0; i < elems.supp_rates_len; i++) { | 1584 | ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, |
1544 | int rate = (elems.supp_rates[i] & 0x7f) * 5; | 1585 | &rates, &basic_rates, &have_higher_than_11mbit, |
1545 | bool is_basic = !!(elems.supp_rates[i] & 0x80); | 1586 | &min_rate, &min_rate_index); |
1546 | |||
1547 | if (rate > 110) | ||
1548 | have_higher_than_11mbit = true; | ||
1549 | 1587 | ||
1550 | for (j = 0; j < sband->n_bitrates; j++) { | 1588 | ieee80211_get_rates(sband, elems.ext_supp_rates, |
1551 | if (sband->bitrates[j].bitrate == rate) { | 1589 | elems.ext_supp_rates_len, &rates, &basic_rates, |
1552 | rates |= BIT(j); | 1590 | &have_higher_than_11mbit, |
1553 | if (is_basic) | 1591 | &min_rate, &min_rate_index); |
1554 | basic_rates |= BIT(j); | ||
1555 | if (rate < min_rate) { | ||
1556 | min_rate = rate; | ||
1557 | min_rate_index = j; | ||
1558 | } | ||
1559 | break; | ||
1560 | } | ||
1561 | } | ||
1562 | } | ||
1563 | |||
1564 | for (i = 0; i < elems.ext_supp_rates_len; i++) { | ||
1565 | int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; | ||
1566 | bool is_basic = !!(elems.ext_supp_rates[i] & 0x80); | ||
1567 | |||
1568 | if (rate > 110) | ||
1569 | have_higher_than_11mbit = true; | ||
1570 | |||
1571 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1572 | if (sband->bitrates[j].bitrate == rate) { | ||
1573 | rates |= BIT(j); | ||
1574 | if (is_basic) | ||
1575 | basic_rates |= BIT(j); | ||
1576 | if (rate < min_rate) { | ||
1577 | min_rate = rate; | ||
1578 | min_rate_index = j; | ||
1579 | } | ||
1580 | break; | ||
1581 | } | ||
1582 | } | ||
1583 | } | ||
1584 | 1592 | ||
1585 | /* | 1593 | /* |
1586 | * some buggy APs don't advertise basic_rates. use the lowest | 1594 | * some buggy APs don't advertise basic_rates. use the lowest |