diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 211 |
1 files changed, 183 insertions, 28 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a9b46d8ea22f..a1e433b88c66 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
101 | 101 | ||
102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER) || |
104 | test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { | ||
104 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 105 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
105 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 106 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
106 | ps = &sdata->bss->ps; | 107 | ps = &sdata->bss->ps; |
@@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
111 | 112 | ||
112 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 113 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
113 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 114 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); |
115 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
114 | 116 | ||
115 | atomic_dec(&ps->num_sta_ps); | 117 | atomic_dec(&ps->num_sta_ps); |
116 | sta_info_recalc_tim(sta); | 118 | sta_info_recalc_tim(sta); |
@@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct sta_info *sta) | |||
125 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 127 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
126 | mesh_sta_cleanup(sta); | 128 | mesh_sta_cleanup(sta); |
127 | 129 | ||
128 | cancel_work_sync(&sta->drv_unblock_wk); | 130 | cancel_work_sync(&sta->drv_deliver_wk); |
129 | 131 | ||
130 | /* | 132 | /* |
131 | * Destroy aggregation state here. It would be nice to wait for the | 133 | * Destroy aggregation state here. It would be nice to wait for the |
@@ -253,33 +255,23 @@ static void sta_info_hash_add(struct ieee80211_local *local, | |||
253 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); | 255 | rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); |
254 | } | 256 | } |
255 | 257 | ||
256 | static void sta_unblock(struct work_struct *wk) | 258 | static void sta_deliver_ps_frames(struct work_struct *wk) |
257 | { | 259 | { |
258 | struct sta_info *sta; | 260 | struct sta_info *sta; |
259 | 261 | ||
260 | sta = container_of(wk, struct sta_info, drv_unblock_wk); | 262 | sta = container_of(wk, struct sta_info, drv_deliver_wk); |
261 | 263 | ||
262 | if (sta->dead) | 264 | if (sta->dead) |
263 | return; | 265 | return; |
264 | 266 | ||
265 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | 267 | local_bh_disable(); |
266 | local_bh_disable(); | 268 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) |
267 | ieee80211_sta_ps_deliver_wakeup(sta); | 269 | ieee80211_sta_ps_deliver_wakeup(sta); |
268 | local_bh_enable(); | 270 | else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) |
269 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { | ||
270 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
271 | |||
272 | local_bh_disable(); | ||
273 | ieee80211_sta_ps_deliver_poll_response(sta); | 271 | ieee80211_sta_ps_deliver_poll_response(sta); |
274 | local_bh_enable(); | 272 | else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) |
275 | } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
276 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
277 | |||
278 | local_bh_disable(); | ||
279 | ieee80211_sta_ps_deliver_uapsd(sta); | 273 | ieee80211_sta_ps_deliver_uapsd(sta); |
280 | local_bh_enable(); | 274 | local_bh_enable(); |
281 | } else | ||
282 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
283 | } | 275 | } |
284 | 276 | ||
285 | static int sta_prepare_rate_control(struct ieee80211_local *local, | 277 | static int sta_prepare_rate_control(struct ieee80211_local *local, |
@@ -341,7 +333,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
341 | 333 | ||
342 | spin_lock_init(&sta->lock); | 334 | spin_lock_init(&sta->lock); |
343 | spin_lock_init(&sta->ps_lock); | 335 | spin_lock_init(&sta->ps_lock); |
344 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 336 | INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); |
345 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 337 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
346 | mutex_init(&sta->ampdu_mlme.mtx); | 338 | mutex_init(&sta->ampdu_mlme.mtx); |
347 | #ifdef CONFIG_MAC80211_MESH | 339 | #ifdef CONFIG_MAC80211_MESH |
@@ -358,7 +350,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
358 | 350 | ||
359 | sta->sta_state = IEEE80211_STA_NONE; | 351 | sta->sta_state = IEEE80211_STA_NONE; |
360 | 352 | ||
361 | do_posix_clock_monotonic_gettime(&uptime); | 353 | ktime_get_ts(&uptime); |
362 | sta->last_connected = uptime.tv_sec; | 354 | sta->last_connected = uptime.tv_sec; |
363 | ewma_init(&sta->avg_signal, 1024, 8); | 355 | ewma_init(&sta->avg_signal, 1024, 8); |
364 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) | 356 | for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) |
@@ -1102,8 +1094,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1102 | unsigned long flags; | 1094 | unsigned long flags; |
1103 | struct ps_data *ps; | 1095 | struct ps_data *ps; |
1104 | 1096 | ||
1105 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 1097 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1106 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1098 | sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, |
1099 | u.ap); | ||
1100 | |||
1101 | if (sdata->vif.type == NL80211_IFTYPE_AP) | ||
1107 | ps = &sdata->bss->ps; | 1102 | ps = &sdata->bss->ps; |
1108 | else if (ieee80211_vif_is_mesh(&sdata->vif)) | 1103 | else if (ieee80211_vif_is_mesh(&sdata->vif)) |
1109 | ps = &sdata->u.mesh.ps; | 1104 | ps = &sdata->u.mesh.ps; |
@@ -1141,8 +1136,15 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1141 | } | 1136 | } |
1142 | 1137 | ||
1143 | ieee80211_add_pending_skbs(local, &pending); | 1138 | ieee80211_add_pending_skbs(local, &pending); |
1144 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1139 | |
1145 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 1140 | /* now we're no longer in the deliver code */ |
1141 | clear_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1142 | |||
1143 | /* The station might have polled and then woken up before we responded, | ||
1144 | * so clear these flags now to avoid them sticking around. | ||
1145 | */ | ||
1146 | clear_sta_flag(sta, WLAN_STA_PSPOLL); | ||
1147 | clear_sta_flag(sta, WLAN_STA_UAPSD); | ||
1146 | spin_unlock(&sta->ps_lock); | 1148 | spin_unlock(&sta->ps_lock); |
1147 | 1149 | ||
1148 | atomic_dec(&ps->num_sta_ps); | 1150 | atomic_dec(&ps->num_sta_ps); |
@@ -1543,10 +1545,26 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | |||
1543 | 1545 | ||
1544 | trace_api_sta_block_awake(sta->local, pubsta, block); | 1546 | trace_api_sta_block_awake(sta->local, pubsta, block); |
1545 | 1547 | ||
1546 | if (block) | 1548 | if (block) { |
1547 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); | 1549 | set_sta_flag(sta, WLAN_STA_PS_DRIVER); |
1548 | else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | 1550 | return; |
1549 | ieee80211_queue_work(hw, &sta->drv_unblock_wk); | 1551 | } |
1552 | |||
1553 | if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | ||
1554 | return; | ||
1555 | |||
1556 | if (!test_sta_flag(sta, WLAN_STA_PS_STA)) { | ||
1557 | set_sta_flag(sta, WLAN_STA_PS_DELIVER); | ||
1558 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1559 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
1560 | } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) || | ||
1561 | test_sta_flag(sta, WLAN_STA_UAPSD)) { | ||
1562 | /* must be asleep in this case */ | ||
1563 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1564 | ieee80211_queue_work(hw, &sta->drv_deliver_wk); | ||
1565 | } else { | ||
1566 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1567 | } | ||
1550 | } | 1568 | } |
1551 | EXPORT_SYMBOL(ieee80211_sta_block_awake); | 1569 | EXPORT_SYMBOL(ieee80211_sta_block_awake); |
1552 | 1570 | ||
@@ -1704,3 +1722,140 @@ u8 sta_info_tx_streams(struct sta_info *sta) | |||
1704 | return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) | 1722 | return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) |
1705 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; | 1723 | >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; |
1706 | } | 1724 | } |
1725 | |||
1726 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | ||
1727 | { | ||
1728 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1729 | struct ieee80211_local *local = sdata->local; | ||
1730 | struct rate_control_ref *ref = NULL; | ||
1731 | struct timespec uptime; | ||
1732 | u64 packets = 0; | ||
1733 | u32 thr = 0; | ||
1734 | int i, ac; | ||
1735 | |||
1736 | if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) | ||
1737 | ref = local->rate_ctrl; | ||
1738 | |||
1739 | sinfo->generation = sdata->local->sta_generation; | ||
1740 | |||
1741 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | ||
1742 | STATION_INFO_RX_BYTES64 | | ||
1743 | STATION_INFO_TX_BYTES64 | | ||
1744 | STATION_INFO_RX_PACKETS | | ||
1745 | STATION_INFO_TX_PACKETS | | ||
1746 | STATION_INFO_TX_RETRIES | | ||
1747 | STATION_INFO_TX_FAILED | | ||
1748 | STATION_INFO_TX_BITRATE | | ||
1749 | STATION_INFO_RX_BITRATE | | ||
1750 | STATION_INFO_RX_DROP_MISC | | ||
1751 | STATION_INFO_BSS_PARAM | | ||
1752 | STATION_INFO_CONNECTED_TIME | | ||
1753 | STATION_INFO_STA_FLAGS | | ||
1754 | STATION_INFO_BEACON_LOSS_COUNT; | ||
1755 | |||
1756 | ktime_get_ts(&uptime); | ||
1757 | sinfo->connected_time = uptime.tv_sec - sta->last_connected; | ||
1758 | |||
1759 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | ||
1760 | sinfo->tx_bytes = 0; | ||
1761 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | ||
1762 | sinfo->tx_bytes += sta->tx_bytes[ac]; | ||
1763 | packets += sta->tx_packets[ac]; | ||
1764 | } | ||
1765 | sinfo->tx_packets = packets; | ||
1766 | sinfo->rx_bytes = sta->rx_bytes; | ||
1767 | sinfo->rx_packets = sta->rx_packets; | ||
1768 | sinfo->tx_retries = sta->tx_retry_count; | ||
1769 | sinfo->tx_failed = sta->tx_retry_failed; | ||
1770 | sinfo->rx_dropped_misc = sta->rx_dropped; | ||
1771 | sinfo->beacon_loss_count = sta->beacon_loss_count; | ||
1772 | |||
1773 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | ||
1774 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | ||
1775 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | ||
1776 | if (!local->ops->get_rssi || | ||
1777 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
1778 | sinfo->signal = (s8)sta->last_signal; | ||
1779 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
1780 | } | ||
1781 | if (sta->chains) { | ||
1782 | sinfo->filled |= STATION_INFO_CHAIN_SIGNAL | | ||
1783 | STATION_INFO_CHAIN_SIGNAL_AVG; | ||
1784 | |||
1785 | sinfo->chains = sta->chains; | ||
1786 | for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { | ||
1787 | sinfo->chain_signal[i] = sta->chain_signal_last[i]; | ||
1788 | sinfo->chain_signal_avg[i] = | ||
1789 | (s8) -ewma_read(&sta->chain_signal_avg[i]); | ||
1790 | } | ||
1791 | } | ||
1792 | |||
1793 | sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate); | ||
1794 | sta_set_rate_info_rx(sta, &sinfo->rxrate); | ||
1795 | |||
1796 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
1797 | #ifdef CONFIG_MAC80211_MESH | ||
1798 | sinfo->filled |= STATION_INFO_LLID | | ||
1799 | STATION_INFO_PLID | | ||
1800 | STATION_INFO_PLINK_STATE | | ||
1801 | STATION_INFO_LOCAL_PM | | ||
1802 | STATION_INFO_PEER_PM | | ||
1803 | STATION_INFO_NONPEER_PM; | ||
1804 | |||
1805 | sinfo->llid = sta->llid; | ||
1806 | sinfo->plid = sta->plid; | ||
1807 | sinfo->plink_state = sta->plink_state; | ||
1808 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
1809 | sinfo->filled |= STATION_INFO_T_OFFSET; | ||
1810 | sinfo->t_offset = sta->t_offset; | ||
1811 | } | ||
1812 | sinfo->local_pm = sta->local_pm; | ||
1813 | sinfo->peer_pm = sta->peer_pm; | ||
1814 | sinfo->nonpeer_pm = sta->nonpeer_pm; | ||
1815 | #endif | ||
1816 | } | ||
1817 | |||
1818 | sinfo->bss_param.flags = 0; | ||
1819 | if (sdata->vif.bss_conf.use_cts_prot) | ||
1820 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_CTS_PROT; | ||
1821 | if (sdata->vif.bss_conf.use_short_preamble) | ||
1822 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; | ||
1823 | if (sdata->vif.bss_conf.use_short_slot) | ||
1824 | sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; | ||
1825 | sinfo->bss_param.dtim_period = sdata->vif.bss_conf.dtim_period; | ||
1826 | sinfo->bss_param.beacon_interval = sdata->vif.bss_conf.beacon_int; | ||
1827 | |||
1828 | sinfo->sta_flags.set = 0; | ||
1829 | sinfo->sta_flags.mask = BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
1830 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | ||
1831 | BIT(NL80211_STA_FLAG_WME) | | ||
1832 | BIT(NL80211_STA_FLAG_MFP) | | ||
1833 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | | ||
1834 | BIT(NL80211_STA_FLAG_ASSOCIATED) | | ||
1835 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
1836 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | ||
1837 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | ||
1838 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | ||
1839 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE); | ||
1840 | if (test_sta_flag(sta, WLAN_STA_WME)) | ||
1841 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME); | ||
1842 | if (test_sta_flag(sta, WLAN_STA_MFP)) | ||
1843 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | ||
1844 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | ||
1845 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | ||
1846 | if (test_sta_flag(sta, WLAN_STA_ASSOC)) | ||
1847 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_ASSOCIATED); | ||
1848 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
1849 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
1850 | |||
1851 | /* check if the driver has a SW RC implementation */ | ||
1852 | if (ref && ref->ops->get_expected_throughput) | ||
1853 | thr = ref->ops->get_expected_throughput(sta->rate_ctrl_priv); | ||
1854 | else | ||
1855 | thr = drv_get_expected_throughput(local, &sta->sta); | ||
1856 | |||
1857 | if (thr != 0) { | ||
1858 | sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT; | ||
1859 | sinfo->expected_throughput = thr; | ||
1860 | } | ||
1861 | } | ||