.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright 2002-2005, Instant802 Networks, Inc. |
---|
3 | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
---|
4 | 5 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
---|
5 | 6 | * Copyright (C) 2015 - 2017 Intel Deutschland GmbH |
---|
6 | 7 | * Copyright (C) 2018-2021 Intel Corporation |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/module.h> |
---|
.. | .. |
---|
90 | 87 | struct tid_ampdu_tx *tid_tx; |
---|
91 | 88 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
---|
92 | 89 | struct ieee80211_local *local = sdata->local; |
---|
93 | | - struct fq *fq = &local->fq; |
---|
94 | 90 | struct ps_data *ps; |
---|
95 | 91 | |
---|
96 | 92 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
---|
.. | .. |
---|
113 | 109 | |
---|
114 | 110 | if (sta->sta.txq[0]) { |
---|
115 | 111 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
---|
116 | | - struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); |
---|
| 112 | + struct txq_info *txqi; |
---|
117 | 113 | |
---|
118 | | - spin_lock_bh(&fq->lock); |
---|
| 114 | + if (!sta->sta.txq[i]) |
---|
| 115 | + continue; |
---|
| 116 | + |
---|
| 117 | + txqi = to_txq_info(sta->sta.txq[i]); |
---|
| 118 | + |
---|
119 | 119 | ieee80211_txq_purge(local, txqi); |
---|
120 | | - spin_unlock_bh(&fq->lock); |
---|
121 | 120 | } |
---|
122 | 121 | } |
---|
123 | 122 | |
---|
.. | .. |
---|
211 | 210 | return NULL; |
---|
212 | 211 | } |
---|
213 | 212 | |
---|
| 213 | +struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local, |
---|
| 214 | + const u8 *sta_addr, const u8 *vif_addr) |
---|
| 215 | +{ |
---|
| 216 | + struct rhlist_head *tmp; |
---|
| 217 | + struct sta_info *sta; |
---|
| 218 | + |
---|
| 219 | + for_each_sta_info(local, sta_addr, sta, tmp) { |
---|
| 220 | + if (ether_addr_equal(vif_addr, sta->sdata->vif.addr)) |
---|
| 221 | + return sta; |
---|
| 222 | + } |
---|
| 223 | + |
---|
| 224 | + return NULL; |
---|
| 225 | +} |
---|
| 226 | + |
---|
214 | 227 | struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, |
---|
215 | 228 | int idx) |
---|
216 | 229 | { |
---|
.. | .. |
---|
218 | 231 | struct sta_info *sta; |
---|
219 | 232 | int i = 0; |
---|
220 | 233 | |
---|
221 | | - list_for_each_entry_rcu(sta, &local->sta_list, list) { |
---|
| 234 | + list_for_each_entry_rcu(sta, &local->sta_list, list, |
---|
| 235 | + lockdep_is_held(&local->sta_mtx)) { |
---|
222 | 236 | if (sdata != sta->sdata) |
---|
223 | 237 | continue; |
---|
224 | 238 | if (i < idx) { |
---|
.. | .. |
---|
363 | 377 | sta->sta.max_rx_aggregation_subframes = |
---|
364 | 378 | local->hw.max_rx_aggregation_subframes; |
---|
365 | 379 | |
---|
| 380 | + /* Extended Key ID needs to install keys for keyid 0 and 1 Rx-only. |
---|
| 381 | + * The Tx path starts to use a key as soon as the key slot ptk_idx |
---|
| 382 | + * references to is not NULL. To not use the initial Rx-only key |
---|
| 383 | + * prematurely for Tx initialize ptk_idx to an impossible PTK keyid |
---|
| 384 | + * which always will refer to a NULL key. |
---|
| 385 | + */ |
---|
| 386 | + BUILD_BUG_ON(ARRAY_SIZE(sta->ptk) <= INVALID_PTK_KEYIDX); |
---|
| 387 | + sta->ptk_idx = INVALID_PTK_KEYIDX; |
---|
| 388 | + |
---|
366 | 389 | sta->local = local; |
---|
367 | 390 | sta->sdata = sdata; |
---|
368 | 391 | sta->rx_stats.last_rx = jiffies; |
---|
.. | .. |
---|
394 | 417 | for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
---|
395 | 418 | struct txq_info *txq = txq_data + i * size; |
---|
396 | 419 | |
---|
| 420 | + /* might not do anything for the bufferable MMPDU TXQ */ |
---|
397 | 421 | ieee80211_txq_init(sdata, sta, txq, i); |
---|
398 | 422 | } |
---|
399 | 423 | } |
---|
.. | .. |
---|
401 | 425 | if (sta_prepare_rate_control(local, sta, gfp)) |
---|
402 | 426 | goto free_txq; |
---|
403 | 427 | |
---|
| 428 | + sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; |
---|
| 429 | + |
---|
404 | 430 | for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
---|
405 | 431 | skb_queue_head_init(&sta->ps_tx_buf[i]); |
---|
406 | 432 | skb_queue_head_init(&sta->tx_filtered[i]); |
---|
| 433 | + sta->airtime[i].deficit = sta->airtime_weight; |
---|
| 434 | + atomic_set(&sta->airtime[i].aql_tx_pending, 0); |
---|
| 435 | + sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; |
---|
| 436 | + sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; |
---|
407 | 437 | } |
---|
408 | 438 | |
---|
409 | 439 | for (i = 0; i < IEEE80211_NUM_TIDS; i++) |
---|
410 | 440 | sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); |
---|
| 441 | + |
---|
| 442 | + for (i = 0; i < NUM_NL80211_BANDS; i++) { |
---|
| 443 | + u32 mandatory = 0; |
---|
| 444 | + int r; |
---|
| 445 | + |
---|
| 446 | + if (!hw->wiphy->bands[i]) |
---|
| 447 | + continue; |
---|
| 448 | + |
---|
| 449 | + switch (i) { |
---|
| 450 | + case NL80211_BAND_2GHZ: |
---|
| 451 | + /* |
---|
| 452 | + * We use both here, even if we cannot really know for |
---|
| 453 | + * sure the station will support both, but the only use |
---|
| 454 | + * for this is when we don't know anything yet and send |
---|
| 455 | + * management frames, and then we'll pick the lowest |
---|
| 456 | + * possible rate anyway. |
---|
| 457 | + * If we don't include _G here, we cannot find a rate |
---|
| 458 | + * in P2P, and thus trigger the WARN_ONCE() in rate.c |
---|
| 459 | + */ |
---|
| 460 | + mandatory = IEEE80211_RATE_MANDATORY_B | |
---|
| 461 | + IEEE80211_RATE_MANDATORY_G; |
---|
| 462 | + break; |
---|
| 463 | + case NL80211_BAND_5GHZ: |
---|
| 464 | + mandatory = IEEE80211_RATE_MANDATORY_A; |
---|
| 465 | + break; |
---|
| 466 | + case NL80211_BAND_60GHZ: |
---|
| 467 | + WARN_ON(1); |
---|
| 468 | + mandatory = 0; |
---|
| 469 | + break; |
---|
| 470 | + } |
---|
| 471 | + |
---|
| 472 | + for (r = 0; r < hw->wiphy->bands[i]->n_bitrates; r++) { |
---|
| 473 | + struct ieee80211_rate *rate; |
---|
| 474 | + |
---|
| 475 | + rate = &hw->wiphy->bands[i]->bitrates[r]; |
---|
| 476 | + |
---|
| 477 | + if (!(rate->flags & mandatory)) |
---|
| 478 | + continue; |
---|
| 479 | + sta->sta.supp_rates[i] |= BIT(r); |
---|
| 480 | + } |
---|
| 481 | + } |
---|
411 | 482 | |
---|
412 | 483 | sta->sta.smps_mode = IEEE80211_SMPS_OFF; |
---|
413 | 484 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
---|
.. | .. |
---|
574 | 645 | /* check if STA exists already */ |
---|
575 | 646 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
---|
576 | 647 | err = -EEXIST; |
---|
577 | | - goto out_err; |
---|
| 648 | + goto out_cleanup; |
---|
578 | 649 | } |
---|
579 | 650 | |
---|
580 | 651 | sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL); |
---|
581 | 652 | if (!sinfo) { |
---|
582 | 653 | err = -ENOMEM; |
---|
583 | | - goto out_err; |
---|
| 654 | + goto out_cleanup; |
---|
584 | 655 | } |
---|
585 | 656 | |
---|
586 | 657 | local->num_sta++; |
---|
.. | .. |
---|
636 | 707 | out_drop_sta: |
---|
637 | 708 | local->num_sta--; |
---|
638 | 709 | synchronize_net(); |
---|
| 710 | + out_cleanup: |
---|
639 | 711 | cleanup_single_sta(sta); |
---|
640 | | - out_err: |
---|
641 | 712 | mutex_unlock(&local->sta_mtx); |
---|
642 | 713 | kfree(sinfo); |
---|
643 | 714 | rcu_read_lock(); |
---|
.. | .. |
---|
969 | 1040 | list_del_rcu(&sta->list); |
---|
970 | 1041 | sta->removed = true; |
---|
971 | 1042 | |
---|
972 | | - drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
---|
| 1043 | + if (sta->uploaded) |
---|
| 1044 | + drv_sta_pre_rcu_remove(local, sta->sdata, sta); |
---|
973 | 1045 | |
---|
974 | 1046 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && |
---|
975 | 1047 | rcu_access_pointer(sdata->u.vlan.sta) == sta) |
---|
.. | .. |
---|
1031 | 1103 | cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); |
---|
1032 | 1104 | kfree(sinfo); |
---|
1033 | 1105 | |
---|
1034 | | - rate_control_remove_sta_debugfs(sta); |
---|
1035 | 1106 | ieee80211_sta_debugfs_remove(sta); |
---|
1036 | 1107 | |
---|
1037 | 1108 | ieee80211_destroy_frag_cache(&sta->frags); |
---|
.. | .. |
---|
1260 | 1331 | if (!ieee80211_hw_check(&local->hw, AP_LINK_PS)) |
---|
1261 | 1332 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); |
---|
1262 | 1333 | |
---|
1263 | | - if (sta->sta.txq[0]) { |
---|
1264 | | - for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
---|
1265 | | - if (!txq_has_queue(sta->sta.txq[i])) |
---|
1266 | | - continue; |
---|
| 1334 | + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { |
---|
| 1335 | + if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i])) |
---|
| 1336 | + continue; |
---|
1267 | 1337 | |
---|
1268 | | - drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i])); |
---|
1269 | | - } |
---|
| 1338 | + schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i])); |
---|
1270 | 1339 | } |
---|
1271 | 1340 | |
---|
1272 | 1341 | skb_queue_head_init(&pending); |
---|
.. | .. |
---|
1304 | 1373 | spin_unlock(&sta->ps_lock); |
---|
1305 | 1374 | |
---|
1306 | 1375 | atomic_dec(&ps->num_sta_ps); |
---|
1307 | | - |
---|
1308 | | - /* This station just woke up and isn't aware of our SMPS state */ |
---|
1309 | | - if (!ieee80211_vif_is_mesh(&sdata->vif) && |
---|
1310 | | - !ieee80211_smps_is_restrictive(sta->known_smps_mode, |
---|
1311 | | - sdata->smps_mode) && |
---|
1312 | | - sta->known_smps_mode != sdata->bss->req_smps && |
---|
1313 | | - sta_info_tx_streams(sta) != 1) { |
---|
1314 | | - ht_dbg(sdata, |
---|
1315 | | - "%pM just woke up and MIMO capable - update SMPS\n", |
---|
1316 | | - sta->sta.addr); |
---|
1317 | | - ieee80211_send_smps_action(sdata, sdata->bss->req_smps, |
---|
1318 | | - sta->sta.addr, |
---|
1319 | | - sdata->vif.bss_conf.bssid); |
---|
1320 | | - } |
---|
1321 | 1376 | |
---|
1322 | 1377 | local->total_ps_buffered -= buffered; |
---|
1323 | 1378 | |
---|
.. | .. |
---|
1412 | 1467 | } |
---|
1413 | 1468 | |
---|
1414 | 1469 | info->band = chanctx_conf->def.chan->band; |
---|
1415 | | - ieee80211_xmit(sdata, sta, skb, 0); |
---|
| 1470 | + ieee80211_xmit(sdata, sta, skb); |
---|
1416 | 1471 | rcu_read_unlock(); |
---|
1417 | 1472 | } |
---|
1418 | 1473 | |
---|
.. | .. |
---|
1699 | 1754 | return; |
---|
1700 | 1755 | |
---|
1701 | 1756 | for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { |
---|
1702 | | - if (!(driver_release_tids & BIT(tid)) || |
---|
| 1757 | + if (!sta->sta.txq[tid] || |
---|
| 1758 | + !(driver_release_tids & BIT(tid)) || |
---|
1703 | 1759 | txq_has_queue(sta->sta.txq[tid])) |
---|
1704 | 1760 | continue; |
---|
1705 | 1761 | |
---|
.. | .. |
---|
1837 | 1893 | } |
---|
1838 | 1894 | EXPORT_SYMBOL(ieee80211_sta_set_buffered); |
---|
1839 | 1895 | |
---|
| 1896 | +void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, |
---|
| 1897 | + u32 tx_airtime, u32 rx_airtime) |
---|
| 1898 | +{ |
---|
| 1899 | + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
---|
| 1900 | + struct ieee80211_local *local = sta->sdata->local; |
---|
| 1901 | + u8 ac = ieee80211_ac_from_tid(tid); |
---|
| 1902 | + u32 airtime = 0; |
---|
| 1903 | + |
---|
| 1904 | + if (sta->local->airtime_flags & AIRTIME_USE_TX) |
---|
| 1905 | + airtime += tx_airtime; |
---|
| 1906 | + if (sta->local->airtime_flags & AIRTIME_USE_RX) |
---|
| 1907 | + airtime += rx_airtime; |
---|
| 1908 | + |
---|
| 1909 | + spin_lock_bh(&local->active_txq_lock[ac]); |
---|
| 1910 | + sta->airtime[ac].tx_airtime += tx_airtime; |
---|
| 1911 | + sta->airtime[ac].rx_airtime += rx_airtime; |
---|
| 1912 | + sta->airtime[ac].deficit -= airtime; |
---|
| 1913 | + spin_unlock_bh(&local->active_txq_lock[ac]); |
---|
| 1914 | +} |
---|
| 1915 | +EXPORT_SYMBOL(ieee80211_sta_register_airtime); |
---|
| 1916 | + |
---|
| 1917 | +void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, |
---|
| 1918 | + struct sta_info *sta, u8 ac, |
---|
| 1919 | + u16 tx_airtime, bool tx_completed) |
---|
| 1920 | +{ |
---|
| 1921 | + int tx_pending; |
---|
| 1922 | + |
---|
| 1923 | + if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) |
---|
| 1924 | + return; |
---|
| 1925 | + |
---|
| 1926 | + if (!tx_completed) { |
---|
| 1927 | + if (sta) |
---|
| 1928 | + atomic_add(tx_airtime, |
---|
| 1929 | + &sta->airtime[ac].aql_tx_pending); |
---|
| 1930 | + |
---|
| 1931 | + atomic_add(tx_airtime, &local->aql_total_pending_airtime); |
---|
| 1932 | + return; |
---|
| 1933 | + } |
---|
| 1934 | + |
---|
| 1935 | + if (sta) { |
---|
| 1936 | + tx_pending = atomic_sub_return(tx_airtime, |
---|
| 1937 | + &sta->airtime[ac].aql_tx_pending); |
---|
| 1938 | + if (tx_pending < 0) |
---|
| 1939 | + atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending, |
---|
| 1940 | + tx_pending, 0); |
---|
| 1941 | + } |
---|
| 1942 | + |
---|
| 1943 | + tx_pending = atomic_sub_return(tx_airtime, |
---|
| 1944 | + &local->aql_total_pending_airtime); |
---|
| 1945 | + if (WARN_ONCE(tx_pending < 0, |
---|
| 1946 | + "Device %s AC %d pending airtime underflow: %u, %u", |
---|
| 1947 | + wiphy_name(local->hw.wiphy), ac, tx_pending, |
---|
| 1948 | + tx_airtime)) |
---|
| 1949 | + atomic_cmpxchg(&local->aql_total_pending_airtime, |
---|
| 1950 | + tx_pending, 0); |
---|
| 1951 | +} |
---|
| 1952 | + |
---|
1840 | 1953 | int sta_info_move_state(struct sta_info *sta, |
---|
1841 | 1954 | enum ieee80211_sta_state new_state) |
---|
1842 | 1955 | { |
---|
.. | .. |
---|
1905 | 2018 | case IEEE80211_STA_ASSOC: |
---|
1906 | 2019 | if (sta->sta_state == IEEE80211_STA_AUTH) { |
---|
1907 | 2020 | set_bit(WLAN_STA_ASSOC, &sta->_flags); |
---|
| 2021 | + sta->assoc_at = ktime_get_boottime_ns(); |
---|
1908 | 2022 | ieee80211_recalc_min_chandef(sta->sdata); |
---|
1909 | 2023 | if (!sta->sta.support_p2p_ps) |
---|
1910 | 2024 | ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); |
---|
.. | .. |
---|
1975 | 2089 | sta_get_last_rx_stats(struct sta_info *sta) |
---|
1976 | 2090 | { |
---|
1977 | 2091 | struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; |
---|
1978 | | - struct ieee80211_local *local = sta->local; |
---|
1979 | 2092 | int cpu; |
---|
1980 | 2093 | |
---|
1981 | | - if (!ieee80211_hw_check(&local->hw, USES_RSS)) |
---|
| 2094 | + if (!sta->pcpu_rx_stats) |
---|
1982 | 2095 | return stats; |
---|
1983 | 2096 | |
---|
1984 | 2097 | for_each_possible_cpu(cpu) { |
---|
.. | .. |
---|
2047 | 2160 | |
---|
2048 | 2161 | static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) |
---|
2049 | 2162 | { |
---|
2050 | | - u16 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate); |
---|
| 2163 | + u32 rate = READ_ONCE(sta_get_last_rx_stats(sta)->last_rate); |
---|
2051 | 2164 | |
---|
2052 | 2165 | if (rate == STA_STATS_RATE_INVALID) |
---|
2053 | 2166 | return -EINVAL; |
---|
.. | .. |
---|
2056 | 2169 | return 0; |
---|
2057 | 2170 | } |
---|
2058 | 2171 | |
---|
| 2172 | +static inline u64 sta_get_tidstats_msdu(struct ieee80211_sta_rx_stats *rxstats, |
---|
| 2173 | + int tid) |
---|
| 2174 | +{ |
---|
| 2175 | + unsigned int start; |
---|
| 2176 | + u64 value; |
---|
| 2177 | + |
---|
| 2178 | + do { |
---|
| 2179 | + start = u64_stats_fetch_begin_irq(&rxstats->syncp); |
---|
| 2180 | + value = rxstats->msdu[tid]; |
---|
| 2181 | + } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); |
---|
| 2182 | + |
---|
| 2183 | + return value; |
---|
| 2184 | +} |
---|
| 2185 | + |
---|
2059 | 2186 | static void sta_set_tidstats(struct sta_info *sta, |
---|
2060 | 2187 | struct cfg80211_tid_stats *tidstats, |
---|
2061 | 2188 | int tid) |
---|
2062 | 2189 | { |
---|
2063 | 2190 | struct ieee80211_local *local = sta->local; |
---|
| 2191 | + int cpu; |
---|
2064 | 2192 | |
---|
2065 | 2193 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) { |
---|
2066 | | - unsigned int start; |
---|
| 2194 | + tidstats->rx_msdu += sta_get_tidstats_msdu(&sta->rx_stats, tid); |
---|
2067 | 2195 | |
---|
2068 | | - do { |
---|
2069 | | - start = u64_stats_fetch_begin(&sta->rx_stats.syncp); |
---|
2070 | | - tidstats->rx_msdu = sta->rx_stats.msdu[tid]; |
---|
2071 | | - } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start)); |
---|
| 2196 | + if (sta->pcpu_rx_stats) { |
---|
| 2197 | + for_each_possible_cpu(cpu) { |
---|
| 2198 | + struct ieee80211_sta_rx_stats *cpurxs; |
---|
| 2199 | + |
---|
| 2200 | + cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu); |
---|
| 2201 | + tidstats->rx_msdu += |
---|
| 2202 | + sta_get_tidstats_msdu(cpurxs, tid); |
---|
| 2203 | + } |
---|
| 2204 | + } |
---|
2072 | 2205 | |
---|
2073 | 2206 | tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU); |
---|
2074 | 2207 | } |
---|
.. | .. |
---|
2109 | 2242 | u64 value; |
---|
2110 | 2243 | |
---|
2111 | 2244 | do { |
---|
2112 | | - start = u64_stats_fetch_begin(&rxstats->syncp); |
---|
| 2245 | + start = u64_stats_fetch_begin_irq(&rxstats->syncp); |
---|
2113 | 2246 | value = rxstats->bytes; |
---|
2114 | | - } while (u64_stats_fetch_retry(&rxstats->syncp, start)); |
---|
| 2247 | + } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start)); |
---|
2115 | 2248 | |
---|
2116 | 2249 | return value; |
---|
2117 | 2250 | } |
---|
.. | .. |
---|
2137 | 2270 | sinfo->rx_beacon = sdata->u.mgd.count_beacon_signal; |
---|
2138 | 2271 | |
---|
2139 | 2272 | drv_sta_statistics(local, sdata, &sta->sta, sinfo); |
---|
2140 | | - |
---|
2141 | 2273 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME) | |
---|
2142 | 2274 | BIT_ULL(NL80211_STA_INFO_STA_FLAGS) | |
---|
2143 | 2275 | BIT_ULL(NL80211_STA_INFO_BSS_PARAM) | |
---|
2144 | 2276 | BIT_ULL(NL80211_STA_INFO_CONNECTED_TIME) | |
---|
| 2277 | + BIT_ULL(NL80211_STA_INFO_ASSOC_AT_BOOTTIME) | |
---|
2145 | 2278 | BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC); |
---|
2146 | 2279 | |
---|
2147 | 2280 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
---|
.. | .. |
---|
2150 | 2283 | } |
---|
2151 | 2284 | |
---|
2152 | 2285 | sinfo->connected_time = ktime_get_seconds() - sta->last_connected; |
---|
| 2286 | + sinfo->assoc_at = sta->assoc_at; |
---|
2153 | 2287 | sinfo->inactive_time = |
---|
2154 | 2288 | jiffies_to_msecs(jiffies - ieee80211_sta_last_active(sta)); |
---|
2155 | 2289 | |
---|
.. | .. |
---|
2205 | 2339 | if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))) { |
---|
2206 | 2340 | sinfo->tx_failed = sta->status_stats.retry_failed; |
---|
2207 | 2341 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); |
---|
| 2342 | + } |
---|
| 2343 | + |
---|
| 2344 | + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) { |
---|
| 2345 | + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
---|
| 2346 | + sinfo->rx_duration += sta->airtime[ac].rx_airtime; |
---|
| 2347 | + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); |
---|
| 2348 | + } |
---|
| 2349 | + |
---|
| 2350 | + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) { |
---|
| 2351 | + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
---|
| 2352 | + sinfo->tx_duration += sta->airtime[ac].tx_airtime; |
---|
| 2353 | + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); |
---|
| 2354 | + } |
---|
| 2355 | + |
---|
| 2356 | + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { |
---|
| 2357 | + sinfo->airtime_weight = sta->airtime_weight; |
---|
| 2358 | + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); |
---|
2208 | 2359 | } |
---|
2209 | 2360 | |
---|
2210 | 2361 | sinfo->rx_dropped_misc = sta->rx_stats.dropped; |
---|
.. | .. |
---|
2272 | 2423 | } |
---|
2273 | 2424 | |
---|
2274 | 2425 | if (tidstats && !cfg80211_sinfo_alloc_tid_stats(sinfo, GFP_KERNEL)) { |
---|
2275 | | - for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { |
---|
2276 | | - struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i]; |
---|
2277 | | - |
---|
2278 | | - sta_set_tidstats(sta, tidstats, i); |
---|
2279 | | - } |
---|
| 2426 | + for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) |
---|
| 2427 | + sta_set_tidstats(sta, &sinfo->pertid[i], i); |
---|
2280 | 2428 | } |
---|
2281 | 2429 | |
---|
2282 | 2430 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
---|
.. | .. |
---|
2286 | 2434 | BIT_ULL(NL80211_STA_INFO_PLINK_STATE) | |
---|
2287 | 2435 | BIT_ULL(NL80211_STA_INFO_LOCAL_PM) | |
---|
2288 | 2436 | BIT_ULL(NL80211_STA_INFO_PEER_PM) | |
---|
2289 | | - BIT_ULL(NL80211_STA_INFO_NONPEER_PM); |
---|
| 2437 | + BIT_ULL(NL80211_STA_INFO_NONPEER_PM) | |
---|
| 2438 | + BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_GATE) | |
---|
| 2439 | + BIT_ULL(NL80211_STA_INFO_CONNECTED_TO_AS); |
---|
2290 | 2440 | |
---|
2291 | 2441 | sinfo->llid = sta->mesh->llid; |
---|
2292 | 2442 | sinfo->plid = sta->mesh->plid; |
---|
.. | .. |
---|
2298 | 2448 | sinfo->local_pm = sta->mesh->local_pm; |
---|
2299 | 2449 | sinfo->peer_pm = sta->mesh->peer_pm; |
---|
2300 | 2450 | sinfo->nonpeer_pm = sta->mesh->nonpeer_pm; |
---|
| 2451 | + sinfo->connected_to_gate = sta->mesh->connected_to_gate; |
---|
| 2452 | + sinfo->connected_to_as = sta->mesh->connected_to_as; |
---|
2301 | 2453 | #endif |
---|
2302 | 2454 | } |
---|
2303 | 2455 | |
---|
.. | .. |
---|
2347 | 2499 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); |
---|
2348 | 2500 | } |
---|
2349 | 2501 | |
---|
2350 | | - if (ieee80211_hw_check(&sta->local->hw, REPORTS_TX_ACK_STATUS) && |
---|
2351 | | - !(sinfo->filled & BIT_ULL(NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG))) { |
---|
| 2502 | + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG)) && |
---|
| 2503 | + sta->status_stats.ack_signal_filled) { |
---|
2352 | 2504 | sinfo->avg_ack_signal = |
---|
2353 | 2505 | -(s8)ewma_avg_signal_read( |
---|
2354 | 2506 | &sta->status_stats.avg_ack_signal); |
---|
2355 | 2507 | sinfo->filled |= |
---|
2356 | | - BIT_ULL(NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG); |
---|
| 2508 | + BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); |
---|
| 2509 | + } |
---|
| 2510 | + |
---|
| 2511 | + if (ieee80211_vif_is_mesh(&sdata->vif)) { |
---|
| 2512 | + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_LINK_METRIC); |
---|
| 2513 | + sinfo->airtime_link_metric = |
---|
| 2514 | + airtime_link_metric_get(local, sta); |
---|
2357 | 2515 | } |
---|
2358 | 2516 | } |
---|
2359 | 2517 | |
---|