diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 139 |
1 files changed, 85 insertions, 54 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b1b1bb368f70..ecb4c84c1bb3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -209,6 +209,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
209 | channel_type = NL80211_CHAN_HT20; | 209 | channel_type = NL80211_CHAN_HT20; |
210 | 210 | ||
211 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && | 211 | if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && |
212 | !ieee80111_cfg_override_disables_ht40(sdata) && | ||
212 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && | 213 | (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && |
213 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { | 214 | (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { |
214 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | 215 | switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { |
@@ -818,7 +819,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
818 | } | 819 | } |
819 | 820 | ||
820 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 821 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
821 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { | 822 | !(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { |
822 | netif_tx_stop_all_queues(sdata->dev); | 823 | netif_tx_stop_all_queues(sdata->dev); |
823 | 824 | ||
824 | if (drv_tx_frames_pending(local)) | 825 | if (drv_tx_frames_pending(local)) |
@@ -1120,6 +1121,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1120 | 1121 | ||
1121 | /* on the next assoc, re-program HT parameters */ | 1122 | /* on the next assoc, re-program HT parameters */ |
1122 | sdata->ht_opmode_valid = false; | 1123 | sdata->ht_opmode_valid = false; |
1124 | memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa)); | ||
1125 | memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); | ||
1123 | 1126 | ||
1124 | local->power_constr_level = 0; | 1127 | local->power_constr_level = 0; |
1125 | 1128 | ||
@@ -1359,9 +1362,6 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1359 | ieee80211_set_disassoc(sdata, true, true); | 1362 | ieee80211_set_disassoc(sdata, true, true); |
1360 | mutex_unlock(&ifmgd->mtx); | 1363 | mutex_unlock(&ifmgd->mtx); |
1361 | 1364 | ||
1362 | mutex_lock(&local->mtx); | ||
1363 | ieee80211_recalc_idle(local); | ||
1364 | mutex_unlock(&local->mtx); | ||
1365 | /* | 1365 | /* |
1366 | * must be outside lock due to cfg80211, | 1366 | * must be outside lock due to cfg80211, |
1367 | * but that's not a problem. | 1367 | * but that's not a problem. |
@@ -1370,6 +1370,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1370 | IEEE80211_STYPE_DEAUTH, | 1370 | IEEE80211_STYPE_DEAUTH, |
1371 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1371 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1372 | NULL, true); | 1372 | NULL, true); |
1373 | |||
1374 | mutex_lock(&local->mtx); | ||
1375 | ieee80211_recalc_idle(local); | ||
1376 | mutex_unlock(&local->mtx); | ||
1373 | } | 1377 | } |
1374 | 1378 | ||
1375 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) | 1379 | void ieee80211_beacon_connection_loss_work(struct work_struct *work) |
@@ -1377,6 +1381,16 @@ void ieee80211_beacon_connection_loss_work(struct work_struct *work) | |||
1377 | struct ieee80211_sub_if_data *sdata = | 1381 | struct ieee80211_sub_if_data *sdata = |
1378 | container_of(work, struct ieee80211_sub_if_data, | 1382 | container_of(work, struct ieee80211_sub_if_data, |
1379 | u.mgd.beacon_connection_loss_work); | 1383 | u.mgd.beacon_connection_loss_work); |
1384 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1385 | struct sta_info *sta; | ||
1386 | |||
1387 | if (ifmgd->associated) { | ||
1388 | rcu_read_lock(); | ||
1389 | sta = sta_info_get(sdata, ifmgd->bssid); | ||
1390 | if (sta) | ||
1391 | sta->beacon_loss_count++; | ||
1392 | rcu_read_unlock(); | ||
1393 | } | ||
1380 | 1394 | ||
1381 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1395 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
1382 | __ieee80211_connection_loss(sdata); | 1396 | __ieee80211_connection_loss(sdata); |
@@ -1468,6 +1482,47 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1468 | return RX_MGMT_CFG80211_DISASSOC; | 1482 | return RX_MGMT_CFG80211_DISASSOC; |
1469 | } | 1483 | } |
1470 | 1484 | ||
1485 | static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | ||
1486 | u8 *supp_rates, unsigned int supp_rates_len, | ||
1487 | u32 *rates, u32 *basic_rates, | ||
1488 | bool *have_higher_than_11mbit, | ||
1489 | int *min_rate, int *min_rate_index) | ||
1490 | { | ||
1491 | int i, j; | ||
1492 | |||
1493 | for (i = 0; i < supp_rates_len; i++) { | ||
1494 | int rate = (supp_rates[i] & 0x7f) * 5; | ||
1495 | bool is_basic = !!(supp_rates[i] & 0x80); | ||
1496 | |||
1497 | if (rate > 110) | ||
1498 | *have_higher_than_11mbit = true; | ||
1499 | |||
1500 | /* | ||
1501 | * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009 | ||
1502 | * 7.3.2.2 as a magic value instead of a rate. Hence, skip it. | ||
1503 | * | ||
1504 | * Note: Even through the membership selector and the basic | ||
1505 | * rate flag share the same bit, they are not exactly | ||
1506 | * the same. | ||
1507 | */ | ||
1508 | if (!!(supp_rates[i] & 0x80) && | ||
1509 | (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY) | ||
1510 | continue; | ||
1511 | |||
1512 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1513 | if (sband->bitrates[j].bitrate == rate) { | ||
1514 | *rates |= BIT(j); | ||
1515 | if (is_basic) | ||
1516 | *basic_rates |= BIT(j); | ||
1517 | if (rate < *min_rate) { | ||
1518 | *min_rate = rate; | ||
1519 | *min_rate_index = j; | ||
1520 | } | ||
1521 | break; | ||
1522 | } | ||
1523 | } | ||
1524 | } | ||
1525 | } | ||
1471 | 1526 | ||
1472 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, | 1527 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, |
1473 | struct ieee80211_mgmt *mgmt, size_t len) | 1528 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -1484,7 +1539,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1484 | struct ieee802_11_elems elems; | 1539 | struct ieee802_11_elems elems; |
1485 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 1540 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
1486 | u32 changed = 0; | 1541 | u32 changed = 0; |
1487 | int i, j, err; | 1542 | int err; |
1488 | bool have_higher_than_11mbit = false; | 1543 | bool have_higher_than_11mbit = false; |
1489 | u16 ap_ht_cap_flags; | 1544 | u16 ap_ht_cap_flags; |
1490 | int min_rate = INT_MAX, min_rate_index = -1; | 1545 | int min_rate = INT_MAX, min_rate_index = -1; |
@@ -1532,57 +1587,23 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1532 | return false; | 1587 | return false; |
1533 | } | 1588 | } |
1534 | 1589 | ||
1535 | set_sta_flag(sta, WLAN_STA_AUTH); | 1590 | sta_info_move_state(sta, IEEE80211_STA_AUTH); |
1536 | set_sta_flag(sta, WLAN_STA_ASSOC); | 1591 | sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
1537 | set_sta_flag(sta, WLAN_STA_ASSOC_AP); | ||
1538 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | 1592 | if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) |
1539 | set_sta_flag(sta, WLAN_STA_AUTHORIZED); | 1593 | sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); |
1540 | 1594 | ||
1541 | rates = 0; | 1595 | rates = 0; |
1542 | basic_rates = 0; | 1596 | basic_rates = 0; |
1543 | sband = local->hw.wiphy->bands[wk->chan->band]; | 1597 | sband = local->hw.wiphy->bands[wk->chan->band]; |
1544 | 1598 | ||
1545 | for (i = 0; i < elems.supp_rates_len; i++) { | 1599 | ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, |
1546 | int rate = (elems.supp_rates[i] & 0x7f) * 5; | 1600 | &rates, &basic_rates, &have_higher_than_11mbit, |
1547 | bool is_basic = !!(elems.supp_rates[i] & 0x80); | 1601 | &min_rate, &min_rate_index); |
1548 | 1602 | ||
1549 | if (rate > 110) | 1603 | ieee80211_get_rates(sband, elems.ext_supp_rates, |
1550 | have_higher_than_11mbit = true; | 1604 | elems.ext_supp_rates_len, &rates, &basic_rates, |
1551 | 1605 | &have_higher_than_11mbit, | |
1552 | for (j = 0; j < sband->n_bitrates; j++) { | 1606 | &min_rate, &min_rate_index); |
1553 | if (sband->bitrates[j].bitrate == rate) { | ||
1554 | rates |= BIT(j); | ||
1555 | if (is_basic) | ||
1556 | basic_rates |= BIT(j); | ||
1557 | if (rate < min_rate) { | ||
1558 | min_rate = rate; | ||
1559 | min_rate_index = j; | ||
1560 | } | ||
1561 | break; | ||
1562 | } | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | for (i = 0; i < elems.ext_supp_rates_len; i++) { | ||
1567 | int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; | ||
1568 | bool is_basic = !!(elems.ext_supp_rates[i] & 0x80); | ||
1569 | |||
1570 | if (rate > 110) | ||
1571 | have_higher_than_11mbit = true; | ||
1572 | |||
1573 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1574 | if (sband->bitrates[j].bitrate == rate) { | ||
1575 | rates |= BIT(j); | ||
1576 | if (is_basic) | ||
1577 | basic_rates |= BIT(j); | ||
1578 | if (rate < min_rate) { | ||
1579 | min_rate = rate; | ||
1580 | min_rate_index = j; | ||
1581 | } | ||
1582 | break; | ||
1583 | } | ||
1584 | } | ||
1585 | } | ||
1586 | 1607 | ||
1587 | /* | 1608 | /* |
1588 | * some buggy APs don't advertise basic_rates. use the lowest | 1609 | * some buggy APs don't advertise basic_rates. use the lowest |
@@ -1605,7 +1626,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1605 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | 1626 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; |
1606 | 1627 | ||
1607 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1628 | if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
1608 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1629 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1609 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1630 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1610 | 1631 | ||
1611 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 1632 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
@@ -1974,7 +1995,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1974 | 1995 | ||
1975 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1996 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
1976 | 1997 | ||
1977 | ieee80211_ht_cap_ie_to_sta_ht_cap(sband, | 1998 | ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, |
1978 | elems.ht_cap_elem, &sta->sta.ht_cap); | 1999 | elems.ht_cap_elem, &sta->sta.ht_cap); |
1979 | 2000 | ||
1980 | ap_ht_cap_flags = sta->sta.ht_cap.cap; | 2001 | ap_ht_cap_flags = sta->sta.ht_cap.cap; |
@@ -2128,9 +2149,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2128 | 2149 | ||
2129 | ieee80211_set_disassoc(sdata, true, true); | 2150 | ieee80211_set_disassoc(sdata, true, true); |
2130 | mutex_unlock(&ifmgd->mtx); | 2151 | mutex_unlock(&ifmgd->mtx); |
2131 | mutex_lock(&local->mtx); | ||
2132 | ieee80211_recalc_idle(local); | ||
2133 | mutex_unlock(&local->mtx); | ||
2134 | /* | 2152 | /* |
2135 | * must be outside lock due to cfg80211, | 2153 | * must be outside lock due to cfg80211, |
2136 | * but that's not a problem. | 2154 | * but that's not a problem. |
@@ -2138,6 +2156,11 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2138 | ieee80211_send_deauth_disassoc(sdata, bssid, | 2156 | ieee80211_send_deauth_disassoc(sdata, bssid, |
2139 | IEEE80211_STYPE_DEAUTH, reason, | 2157 | IEEE80211_STYPE_DEAUTH, reason, |
2140 | NULL, true); | 2158 | NULL, true); |
2159 | |||
2160 | mutex_lock(&local->mtx); | ||
2161 | ieee80211_recalc_idle(local); | ||
2162 | mutex_unlock(&local->mtx); | ||
2163 | |||
2141 | mutex_lock(&ifmgd->mtx); | 2164 | mutex_lock(&ifmgd->mtx); |
2142 | } | 2165 | } |
2143 | 2166 | ||
@@ -2358,6 +2381,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2358 | (unsigned long) sdata); | 2381 | (unsigned long) sdata); |
2359 | 2382 | ||
2360 | ifmgd->flags = 0; | 2383 | ifmgd->flags = 0; |
2384 | ifmgd->powersave = sdata->wdev.ps; | ||
2361 | 2385 | ||
2362 | mutex_init(&ifmgd->mtx); | 2386 | mutex_init(&ifmgd->mtx); |
2363 | 2387 | ||
@@ -2632,6 +2656,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2632 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 2656 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2633 | 2657 | ||
2634 | 2658 | ||
2659 | if (req->flags & ASSOC_REQ_DISABLE_HT) | ||
2660 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | ||
2661 | |||
2662 | memcpy(&ifmgd->ht_capa, &req->ht_capa, sizeof(ifmgd->ht_capa)); | ||
2663 | memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask, | ||
2664 | sizeof(ifmgd->ht_capa_mask)); | ||
2665 | |||
2635 | if (req->ie && req->ie_len) { | 2666 | if (req->ie && req->ie_len) { |
2636 | memcpy(wk->ie, req->ie, req->ie_len); | 2667 | memcpy(wk->ie, req->ie, req->ie_len); |
2637 | wk->ie_len = req->ie_len; | 2668 | wk->ie_len = req->ie_len; |