Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'mac80211-next-for-davem-2015-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
There isn't much left, but we have
* new mac80211 internal software queue to allow drivers to have
shorter hardware queues and pull on-demand
* use rhashtable for mac80211 station table
* minstrel rate control debug improvements and some refactoring
* fix noisy message about TX power reduction
* fix continuous message printing and activity if CRDA doesn't respond
* fix VHT-related capabilities with "iw connect" or "iwconfig ..."
* fix Kconfig for cfg80211 wireless extensions compatibility
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1282 -439
+58
include/net/cfg80211.h
··· 5001 5001 u8 *buf, unsigned int bufsize); 5002 5002 5003 5003 /** 5004 + * ieee80211_ie_split_ric - split an IE buffer according to ordering (with RIC) 5005 + * @ies: the IE buffer 5006 + * @ielen: the length of the IE buffer 5007 + * @ids: an array with element IDs that are allowed before 5008 + * the split 5009 + * @n_ids: the size of the element ID array 5010 + * @after_ric: array IE types that come after the RIC element 5011 + * @n_after_ric: size of the @after_ric array 5012 + * @offset: offset where to start splitting in the buffer 5013 + * 5014 + * This function splits an IE buffer by updating the @offset 5015 + * variable to point to the location where the buffer should be 5016 + * split. 5017 + * 5018 + * It assumes that the given IE buffer is well-formed, this 5019 + * has to be guaranteed by the caller! 5020 + * 5021 + * It also assumes that the IEs in the buffer are ordered 5022 + * correctly, if not the result of using this function will not 5023 + * be ordered correctly either, i.e. it does no reordering. 5024 + * 5025 + * The function returns the offset where the next part of the 5026 + * buffer starts, which may be @ielen if the entire (remainder) 5027 + * of the buffer should be used. 5028 + */ 5029 + size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, 5030 + const u8 *ids, int n_ids, 5031 + const u8 *after_ric, int n_after_ric, 5032 + size_t offset); 5033 + 5034 + /** 5035 + * ieee80211_ie_split - split an IE buffer according to ordering 5036 + * @ies: the IE buffer 5037 + * @ielen: the length of the IE buffer 5038 + * @ids: an array with element IDs that are allowed before 5039 + * the split 5040 + * @n_ids: the size of the element ID array 5041 + * @offset: offset where to start splitting in the buffer 5042 + * 5043 + * This function splits an IE buffer by updating the @offset 5044 + * variable to point to the location where the buffer should be 5045 + * split. 5046 + * 5047 + * It assumes that the given IE buffer is well-formed, this 5048 + * has to be guaranteed by the caller! 5049 + * 5050 + * It also assumes that the IEs in the buffer are ordered 5051 + * correctly, if not the result of using this function will not 5052 + * be ordered correctly either, i.e. it does no reordering. 5053 + * 5054 + * The function returns the offset where the next part of the 5055 + * buffer starts, which may be @ielen if the entire (remainder) 5056 + * of the buffer should be used. 5057 + */ 5058 + size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 5059 + const u8 *ids, int n_ids, size_t offset); 5060 + 5061 + /** 5004 5062 * cfg80211_report_wowlan_wakeup - report wakeup from WoWLAN 5005 5063 * @wdev: the wireless device reporting the wakeup 5006 5064 * @wakeup: the wakeup report
+78 -23
include/net/mac80211.h
··· 84 84 * 85 85 */ 86 86 87 + /** 88 + * DOC: mac80211 software tx queueing 89 + * 90 + * mac80211 provides an optional intermediate queueing implementation designed 91 + * to allow the driver to keep hardware queues short and provide some fairness 92 + * between different stations/interfaces. 93 + * In this model, the driver pulls data frames from the mac80211 queue instead 94 + * of letting mac80211 push them via drv_tx(). 95 + * Other frames (e.g. control or management) are still pushed using drv_tx(). 96 + * 97 + * Drivers indicate that they use this model by implementing the .wake_tx_queue 98 + * driver operation. 99 + * 100 + * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with a 101 + * single per-vif queue for multicast data frames. 102 + * 103 + * The driver is expected to initialize its private per-queue data for stations 104 + * and interfaces in the .add_interface and .sta_add ops. 105 + * 106 + * The driver can't access the queue directly. To dequeue a frame, it calls 107 + * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it 108 + * calls the .wake_tx_queue driver op. 109 + * 110 + * For AP powersave TIM handling, the driver only needs to indicate if it has 111 + * buffered packets in the driver specific data structures by calling 112 + * ieee80211_sta_set_buffered(). For frames buffered in the ieee80211_txq 113 + * struct, mac80211 sets the appropriate TIM PVB bits and calls 114 + * .release_buffered_frames(). 115 + * In that callback the driver is therefore expected to release its own 116 + * buffered frames and afterwards also frames from the ieee80211_txq (obtained 117 + * via the usual ieee80211_tx_dequeue). 118 + */ 119 + 87 120 struct device; 88 121 89 122 /** ··· 1339 1306 * monitor interface (if that is requested.) 1340 1307 * @drv_priv: data area for driver use, will always be aligned to 1341 1308 * sizeof(void *). 1309 + * @txq: the multicast data TX queue (if driver uses the TXQ abstraction) 1342 1310 */ 1343 1311 struct ieee80211_vif { 1344 1312 enum nl80211_iftype type; ··· 1350 1316 1351 1317 u8 cab_queue; 1352 1318 u8 hw_queue[IEEE80211_NUM_ACS]; 1319 + 1320 + struct ieee80211_txq *txq; 1353 1321 1354 1322 struct ieee80211_chanctx_conf __rcu *chanctx_conf; 1355 1323 ··· 1611 1575 * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only 1612 1576 * valid if the STA is a TDLS peer in the first place. 1613 1577 * @mfp: indicates whether the STA uses management frame protection or not. 1578 + * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) 1614 1579 */ 1615 1580 struct ieee80211_sta { 1616 1581 u32 supp_rates[IEEE80211_NUM_BANDS]; ··· 1629 1592 bool tdls; 1630 1593 bool tdls_initiator; 1631 1594 bool mfp; 1595 + 1596 + struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; 1632 1597 1633 1598 /* must be last */ 1634 1599 u8 drv_priv[0] __aligned(sizeof(void *)); ··· 1657 1618 */ 1658 1619 struct ieee80211_tx_control { 1659 1620 struct ieee80211_sta *sta; 1621 + }; 1622 + 1623 + /** 1624 + * struct ieee80211_txq - Software intermediate tx queue 1625 + * 1626 + * @vif: &struct ieee80211_vif pointer from the add_interface callback. 1627 + * @sta: station table entry, %NULL for per-vif queue 1628 + * @tid: the TID for this queue (unused for per-vif queue) 1629 + * @ac: the AC for this queue 1630 + * 1631 + * The driver can obtain packets from this queue by calling 1632 + * ieee80211_tx_dequeue(). 1633 + */ 1634 + struct ieee80211_txq { 1635 + struct ieee80211_vif *vif; 1636 + struct ieee80211_sta *sta; 1637 + u8 tid; 1638 + u8 ac; 1639 + 1640 + /* must be last */ 1641 + u8 drv_priv[0] __aligned(sizeof(void *)); 1660 1642 }; 1661 1643 1662 1644 /** ··· 1904 1844 * within &struct ieee80211_sta. 1905 1845 * @chanctx_data_size: size (in bytes) of the drv_priv data area 1906 1846 * within &struct ieee80211_chanctx_conf. 1847 + * @txq_data_size: size (in bytes) of the drv_priv data area 1848 + * within @struct ieee80211_txq. 1907 1849 * 1908 1850 * @max_rates: maximum number of alternate rate retry stages the hw 1909 1851 * can handle. ··· 1954 1892 * @n_cipher_schemes: a size of an array of cipher schemes definitions. 1955 1893 * @cipher_schemes: a pointer to an array of cipher scheme definitions 1956 1894 * supported by HW. 1895 + * 1896 + * @txq_ac_max_pending: maximum number of frames per AC pending in all txq 1897 + * entries for a vif. 1957 1898 */ 1958 1899 struct ieee80211_hw { 1959 1900 struct ieee80211_conf conf; ··· 1969 1904 int vif_data_size; 1970 1905 int sta_data_size; 1971 1906 int chanctx_data_size; 1907 + int txq_data_size; 1972 1908 u16 queues; 1973 1909 u16 max_listen_interval; 1974 1910 s8 max_signal; ··· 1986 1920 u8 uapsd_max_sp_len; 1987 1921 u8 n_cipher_schemes; 1988 1922 const struct ieee80211_cipher_scheme *cipher_schemes; 1923 + int txq_ac_max_pending; 1989 1924 }; 1990 1925 1991 1926 /** ··· 3149 3082 * response template is provided, together with the location of the 3150 3083 * switch-timing IE within the template. The skb can only be used within 3151 3084 * the function call. 3085 + * 3086 + * @wake_tx_queue: Called when new packets have been added to the queue. 3152 3087 */ 3153 3088 struct ieee80211_ops { 3154 3089 void (*tx)(struct ieee80211_hw *hw, ··· 3382 3313 void (*tdls_recv_channel_switch)(struct ieee80211_hw *hw, 3383 3314 struct ieee80211_vif *vif, 3384 3315 struct ieee80211_tdls_ch_sw_params *params); 3316 + 3317 + void (*wake_tx_queue)(struct ieee80211_hw *hw, 3318 + struct ieee80211_txq *txq); 3385 3319 }; 3386 3320 3387 3321 /** ··· 5380 5308 void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid); 5381 5309 5382 5310 /** 5383 - * ieee80211_ie_split - split an IE buffer according to ordering 5311 + * ieee80211_tx_dequeue - dequeue a packet from a software tx queue 5384 5312 * 5385 - * @ies: the IE buffer 5386 - * @ielen: the length of the IE buffer 5387 - * @ids: an array with element IDs that are allowed before 5388 - * the split 5389 - * @n_ids: the size of the element ID array 5390 - * @offset: offset where to start splitting in the buffer 5313 + * @hw: pointer as obtained from ieee80211_alloc_hw() 5314 + * @txq: pointer obtained from station or virtual interface 5391 5315 * 5392 - * This function splits an IE buffer by updating the @offset 5393 - * variable to point to the location where the buffer should be 5394 - * split. 5395 - * 5396 - * It assumes that the given IE buffer is well-formed, this 5397 - * has to be guaranteed by the caller! 5398 - * 5399 - * It also assumes that the IEs in the buffer are ordered 5400 - * correctly, if not the result of using this function will not 5401 - * be ordered correctly either, i.e. it does no reordering. 5402 - * 5403 - * The function returns the offset where the next part of the 5404 - * buffer starts, which may be @ielen if the entire (remainder) 5405 - * of the buffer should be used. 5316 + * Returns the skb if successful, %NULL if no frame was available. 5406 5317 */ 5407 - size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 5408 - const u8 *ids, int n_ids, size_t offset); 5318 + struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, 5319 + struct ieee80211_txq *txq); 5409 5320 #endif /* MAC80211_H */
+44
net/mac80211/agg-tx.c
··· 188 188 __release(agg_queue); 189 189 } 190 190 191 + static void 192 + ieee80211_agg_stop_txq(struct sta_info *sta, int tid) 193 + { 194 + struct ieee80211_txq *txq = sta->sta.txq[tid]; 195 + struct txq_info *txqi; 196 + 197 + if (!txq) 198 + return; 199 + 200 + txqi = to_txq_info(txq); 201 + 202 + /* Lock here to protect against further seqno updates on dequeue */ 203 + spin_lock_bh(&txqi->queue.lock); 204 + set_bit(IEEE80211_TXQ_STOP, &txqi->flags); 205 + spin_unlock_bh(&txqi->queue.lock); 206 + } 207 + 208 + static void 209 + ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable) 210 + { 211 + struct ieee80211_txq *txq = sta->sta.txq[tid]; 212 + struct txq_info *txqi; 213 + 214 + if (!txq) 215 + return; 216 + 217 + txqi = to_txq_info(txq); 218 + 219 + if (enable) 220 + set_bit(IEEE80211_TXQ_AMPDU, &txqi->flags); 221 + else 222 + clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags); 223 + 224 + clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); 225 + drv_wake_tx_queue(sta->sdata->local, txqi); 226 + } 227 + 191 228 /* 192 229 * splice packets from the STA's pending to the local pending, 193 230 * requires a call to ieee80211_agg_splice_finish later ··· 284 247 ieee80211_assign_tid_tx(sta, tid, NULL); 285 248 286 249 ieee80211_agg_splice_finish(sta->sdata, tid); 250 + ieee80211_agg_start_txq(sta, tid, false); 287 251 288 252 kfree_rcu(tid_tx, rcu_head); 289 253 } ··· 456 418 */ 457 419 clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); 458 420 421 + ieee80211_agg_stop_txq(sta, tid); 422 + 459 423 /* 460 424 * Make sure no packets are being processed. This ensures that 461 425 * we have a valid starting sequence number and that in-flight ··· 479 439 ieee80211_assign_tid_tx(sta, tid, NULL); 480 440 ieee80211_agg_splice_finish(sdata, tid); 481 441 spin_unlock_bh(&sta->lock); 442 + 443 + ieee80211_agg_start_txq(sta, tid, false); 482 444 483 445 kfree_rcu(tid_tx, rcu_head); 484 446 return; ··· 711 669 ieee80211_agg_splice_finish(sta->sdata, tid); 712 670 713 671 spin_unlock_bh(&sta->lock); 672 + 673 + ieee80211_agg_start_txq(sta, tid, true); 714 674 } 715 675 716 676 void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
+12
net/mac80211/driver-ops.h
··· 1367 1367 trace_drv_return_void(local); 1368 1368 } 1369 1369 1370 + static inline void drv_wake_tx_queue(struct ieee80211_local *local, 1371 + struct txq_info *txq) 1372 + { 1373 + struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif); 1374 + 1375 + if (!check_sdata_in_driver(sdata)) 1376 + return; 1377 + 1378 + trace_drv_wake_tx_queue(local, sdata, txq); 1379 + local->ops->wake_tx_queue(&local->hw, &txq->txq); 1380 + } 1381 + 1370 1382 #endif /* __MAC80211_DRIVER_OPS */
+23 -5
net/mac80211/ieee80211_i.h
··· 26 26 #include <linux/etherdevice.h> 27 27 #include <linux/leds.h> 28 28 #include <linux/idr.h> 29 + #include <linux/rhashtable.h> 29 30 #include <net/ieee80211_radiotap.h> 30 31 #include <net/cfg80211.h> 31 32 #include <net/mac80211.h> ··· 811 810 struct rcu_head rcu_head; 812 811 }; 813 812 813 + enum txq_info_flags { 814 + IEEE80211_TXQ_STOP, 815 + IEEE80211_TXQ_AMPDU, 816 + }; 817 + 818 + struct txq_info { 819 + struct sk_buff_head queue; 820 + unsigned long flags; 821 + 822 + /* keep last! */ 823 + struct ieee80211_txq txq; 824 + }; 825 + 814 826 struct ieee80211_sub_if_data { 815 827 struct list_head list; 816 828 ··· 866 852 bool control_port_no_encrypt; 867 853 int encrypt_headroom; 868 854 855 + atomic_t txqs_len[IEEE80211_NUM_ACS]; 869 856 struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; 870 857 struct mac80211_qos_map __rcu *qos_map; 871 858 ··· 1202 1187 spinlock_t tim_lock; 1203 1188 unsigned long num_sta; 1204 1189 struct list_head sta_list; 1205 - struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; 1190 + struct rhashtable sta_hash; 1206 1191 struct timer_list sta_cleanup; 1207 1192 int sta_generation; 1208 1193 ··· 1464 1449 return container_of(hw, struct ieee80211_local, hw); 1465 1450 } 1466 1451 1452 + static inline struct txq_info *to_txq_info(struct ieee80211_txq *txq) 1453 + { 1454 + return container_of(txq, struct txq_info, txq); 1455 + } 1467 1456 1468 1457 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) 1469 1458 { ··· 1924 1905 return true; 1925 1906 } 1926 1907 1908 + void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata, 1909 + struct sta_info *sta, 1910 + struct txq_info *txq, int tid); 1927 1911 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 1928 1912 u16 transaction, u16 auth_alg, u16 status, 1929 1913 const u8 *extra, size_t extra_len, const u8 *bssid, ··· 1965 1943 void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata); 1966 1944 void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata); 1967 1945 1968 - size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, 1969 - const u8 *ids, int n_ids, 1970 - const u8 *after_ric, int n_after_ric, 1971 - size_t offset); 1972 1946 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); 1973 1947 u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, 1974 1948 u16 cap);
+22 -1
net/mac80211/iface.c
··· 969 969 } 970 970 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 971 971 972 + if (sdata->vif.txq) { 973 + struct txq_info *txqi = to_txq_info(sdata->vif.txq); 974 + 975 + ieee80211_purge_tx_queue(&local->hw, &txqi->queue); 976 + atomic_set(&sdata->txqs_len[txqi->txq.ac], 0); 977 + } 978 + 972 979 if (local->open_count == 0) 973 980 ieee80211_clear_tx_pending(local); 974 981 ··· 1661 1654 { 1662 1655 struct net_device *ndev = NULL; 1663 1656 struct ieee80211_sub_if_data *sdata = NULL; 1657 + struct txq_info *txqi; 1664 1658 int ret, i; 1665 1659 int txqs = 1; 1666 1660 ··· 1681 1673 ieee80211_assign_perm_addr(local, wdev->address, type); 1682 1674 memcpy(sdata->vif.addr, wdev->address, ETH_ALEN); 1683 1675 } else { 1676 + int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size, 1677 + sizeof(void *)); 1678 + int txq_size = 0; 1679 + 1680 + if (local->ops->wake_tx_queue) 1681 + txq_size += sizeof(struct txq_info) + 1682 + local->hw.txq_data_size; 1683 + 1684 1684 if (local->hw.queues >= IEEE80211_NUM_ACS) 1685 1685 txqs = IEEE80211_NUM_ACS; 1686 1686 1687 - ndev = alloc_netdev_mqs(sizeof(*sdata) + local->hw.vif_data_size, 1687 + ndev = alloc_netdev_mqs(size + txq_size, 1688 1688 name, name_assign_type, 1689 1689 ieee80211_if_setup, txqs, 1); 1690 1690 if (!ndev) ··· 1726 1710 ndev->ieee80211_ptr = &sdata->wdev; 1727 1711 memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); 1728 1712 memcpy(sdata->name, ndev->name, IFNAMSIZ); 1713 + 1714 + if (txq_size) { 1715 + txqi = netdev_priv(ndev) + size; 1716 + ieee80211_init_tx_queue(sdata, NULL, txqi, 0); 1717 + } 1729 1718 1730 1719 sdata->dev = ndev; 1731 1720 }
+9 -3
net/mac80211/main.c
··· 557 557 558 558 local = wiphy_priv(wiphy); 559 559 560 + if (sta_info_init(local)) 561 + goto err_free; 562 + 560 563 local->hw.wiphy = wiphy; 561 564 562 565 local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); ··· 632 629 spin_lock_init(&local->ack_status_lock); 633 630 idr_init(&local->ack_status_frames); 634 631 635 - sta_info_init(local); 636 - 637 632 for (i = 0; i < IEEE80211_MAX_QUEUES; i++) { 638 633 skb_queue_head_init(&local->pending[i]); 639 634 atomic_set(&local->agg_queue_stop[i], 0); ··· 651 650 ieee80211_roc_setup(local); 652 651 653 652 return &local->hw; 653 + err_free: 654 + wiphy_free(wiphy); 655 + return NULL; 654 656 } 655 657 EXPORT_SYMBOL(ieee80211_alloc_hw_nm); 656 658 ··· 1039 1035 1040 1036 local->dynamic_ps_forced_timeout = -1; 1041 1037 1038 + if (!local->hw.txq_ac_max_pending) 1039 + local->hw.txq_ac_max_pending = 64; 1040 + 1042 1041 result = ieee80211_wep_init(local); 1043 1042 if (result < 0) 1044 1043 wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", ··· 1180 1173 1181 1174 destroy_workqueue(local->workqueue); 1182 1175 wiphy_unregister(local->hw.wiphy); 1183 - sta_info_stop(local); 1184 1176 ieee80211_wep_free(local); 1185 1177 ieee80211_led_exit(local); 1186 1178 kfree(local->int_scan_req);
+7 -7
net/mac80211/mlme.c
··· 1348 1348 */ 1349 1349 if (has_80211h_pwr && 1350 1350 (!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) { 1351 - sdata_info(sdata, 1352 - "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", 1353 - pwr_level_80211h, chan_pwr, pwr_reduction_80211h, 1354 - sdata->u.mgd.bssid); 1351 + sdata_dbg(sdata, 1352 + "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n", 1353 + pwr_level_80211h, chan_pwr, pwr_reduction_80211h, 1354 + sdata->u.mgd.bssid); 1355 1355 new_ap_level = pwr_level_80211h; 1356 1356 } else { /* has_cisco_pwr is always true here. */ 1357 - sdata_info(sdata, 1358 - "Limiting TX power to %d dBm as advertised by %pM\n", 1359 - pwr_level_cisco, sdata->u.mgd.bssid); 1357 + sdata_dbg(sdata, 1358 + "Limiting TX power to %d dBm as advertised by %pM\n", 1359 + pwr_level_cisco, sdata->u.mgd.bssid); 1360 1360 new_ap_level = pwr_level_cisco; 1361 1361 } 1362 1362
+85 -40
net/mac80211/rc80211_minstrel.c
··· 69 69 return i; 70 70 } 71 71 72 + /* return current EMWA throughput */ 73 + int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma) 74 + { 75 + int usecs; 76 + 77 + usecs = mr->perfect_tx_time; 78 + if (!usecs) 79 + usecs = 1000000; 80 + 81 + /* reset thr. below 10% success */ 82 + if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) 83 + return 0; 84 + 85 + if (prob_ewma > MINSTREL_FRAC(90, 100)) 86 + return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs)); 87 + else 88 + return MINSTREL_TRUNC(100000 * (prob_ewma / usecs)); 89 + } 90 + 72 91 /* find & sort topmost throughput rates */ 73 92 static inline void 74 93 minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) 75 94 { 76 95 int j = MAX_THR_RATES; 96 + struct minstrel_rate_stats *tmp_mrs = &mi->r[j - 1].stats; 97 + struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats; 77 98 78 - while (j > 0 && mi->r[i].stats.cur_tp > mi->r[tp_list[j - 1]].stats.cur_tp) 99 + while (j > 0 && (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) > 100 + minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))) { 79 101 j--; 102 + tmp_mrs = &mi->r[tp_list[j - 1]].stats; 103 + } 104 + 80 105 if (j < MAX_THR_RATES - 1) 81 106 memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); 82 107 if (j < MAX_THR_RATES) ··· 152 127 rate_control_set_rates(mp->hw, mi->sta, ratetbl); 153 128 } 154 129 130 + /* 131 + * Recalculate statistics and counters of a given rate 132 + */ 133 + void 134 + minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) 135 + { 136 + if (unlikely(mrs->attempts > 0)) { 137 + mrs->sample_skipped = 0; 138 + mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); 139 + if (unlikely(!mrs->att_hist)) { 140 + mrs->prob_ewma = mrs->cur_prob; 141 + } else { 142 + /* update exponential weighted moving variance */ 143 + mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd, 144 + mrs->cur_prob, 145 + mrs->prob_ewma, 146 + EWMA_LEVEL); 147 + 148 + /*update exponential weighted moving avarage */ 149 + mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, 150 + mrs->cur_prob, 151 + EWMA_LEVEL); 152 + } 153 + mrs->att_hist += mrs->attempts; 154 + mrs->succ_hist += mrs->success; 155 + } else { 156 + mrs->sample_skipped++; 157 + } 158 + 159 + mrs->last_success = mrs->success; 160 + mrs->last_attempts = mrs->attempts; 161 + mrs->success = 0; 162 + mrs->attempts = 0; 163 + } 164 + 155 165 static void 156 166 minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) 157 167 { 158 168 u8 tmp_tp_rate[MAX_THR_RATES]; 159 169 u8 tmp_prob_rate = 0; 160 - u32 usecs; 161 - int i; 170 + int i, tmp_cur_tp, tmp_prob_tp; 162 171 163 172 for (i = 0; i < MAX_THR_RATES; i++) 164 173 tmp_tp_rate[i] = 0; ··· 200 141 for (i = 0; i < mi->n_rates; i++) { 201 142 struct minstrel_rate *mr = &mi->r[i]; 202 143 struct minstrel_rate_stats *mrs = &mi->r[i].stats; 144 + struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; 203 145 204 - usecs = mr->perfect_tx_time; 205 - if (!usecs) 206 - usecs = 1000000; 207 - 208 - if (unlikely(mrs->attempts > 0)) { 209 - mrs->sample_skipped = 0; 210 - mrs->cur_prob = MINSTREL_FRAC(mrs->success, 211 - mrs->attempts); 212 - mrs->succ_hist += mrs->success; 213 - mrs->att_hist += mrs->attempts; 214 - mrs->probability = minstrel_ewma(mrs->probability, 215 - mrs->cur_prob, 216 - EWMA_LEVEL); 217 - } else 218 - mrs->sample_skipped++; 219 - 220 - mrs->last_success = mrs->success; 221 - mrs->last_attempts = mrs->attempts; 222 - mrs->success = 0; 223 - mrs->attempts = 0; 224 - 225 - /* Update throughput per rate, reset thr. below 10% success */ 226 - if (mrs->probability < MINSTREL_FRAC(10, 100)) 227 - mrs->cur_tp = 0; 228 - else 229 - mrs->cur_tp = mrs->probability * (1000000 / usecs); 146 + /* Update statistics of success probability per rate */ 147 + minstrel_calc_rate_stats(mrs); 230 148 231 149 /* Sample less often below the 10% chance of success. 232 150 * Sample less often above the 95% chance of success. */ 233 - if (mrs->probability > MINSTREL_FRAC(95, 100) || 234 - mrs->probability < MINSTREL_FRAC(10, 100)) { 151 + if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) || 152 + mrs->prob_ewma < MINSTREL_FRAC(10, 100)) { 235 153 mr->adjusted_retry_count = mrs->retry_count >> 1; 236 154 if (mr->adjusted_retry_count > 2) 237 155 mr->adjusted_retry_count = 2; ··· 228 192 * choose the maximum throughput rate as max_prob_rate 229 193 * (2) if all success probabilities < 95%, the rate with 230 194 * highest success probability is chosen as max_prob_rate */ 231 - if (mrs->probability >= MINSTREL_FRAC(95, 100)) { 232 - if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp) 195 + if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { 196 + tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma); 197 + tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate], 198 + tmp_mrs->prob_ewma); 199 + if (tmp_cur_tp >= tmp_prob_tp) 233 200 tmp_prob_rate = i; 234 201 } else { 235 - if (mrs->probability >= mi->r[tmp_prob_rate].stats.probability) 202 + if (mrs->prob_ewma >= tmp_mrs->prob_ewma) 236 203 tmp_prob_rate = i; 237 204 } 238 205 } ··· 254 215 #endif 255 216 256 217 /* Reset update timer */ 257 - mi->stats_update = jiffies; 218 + mi->last_stats_update = jiffies; 258 219 259 220 minstrel_update_rates(mp, mi); 260 221 } ··· 292 253 if (mi->sample_deferred > 0) 293 254 mi->sample_deferred--; 294 255 295 - if (time_after(jiffies, mi->stats_update + 256 + if (time_after(jiffies, mi->last_stats_update + 296 257 (mp->update_interval * HZ) / 1000)) 297 258 minstrel_update_stats(mp, mi); 298 259 } ··· 424 385 * has a probability of >95%, we shouldn't be attempting 425 386 * to use it, as this only wastes precious airtime */ 426 387 if (!mrr_capable && 427 - (mi->r[ndx].stats.probability > MINSTREL_FRAC(95, 100))) 388 + (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100))) 428 389 return; 429 390 430 391 mi->prev_sample = true; ··· 558 519 } 559 520 560 521 mi->n_rates = n; 561 - mi->stats_update = jiffies; 522 + mi->last_stats_update = jiffies; 562 523 563 524 init_sample_table(mi); 564 525 minstrel_update_rates(mp, mi); ··· 592 553 if (!mi->sample_table) 593 554 goto error1; 594 555 595 - mi->stats_update = jiffies; 556 + mi->last_stats_update = jiffies; 596 557 return mi; 597 558 598 559 error1: ··· 702 663 static u32 minstrel_get_expected_throughput(void *priv_sta) 703 664 { 704 665 struct minstrel_sta_info *mi = priv_sta; 666 + struct minstrel_rate_stats *tmp_mrs; 705 667 int idx = mi->max_tp_rate[0]; 668 + int tmp_cur_tp; 706 669 707 670 /* convert pkt per sec in kbps (1200 is the average pkt size used for 708 671 * computing cur_tp 709 672 */ 710 - return MINSTREL_TRUNC(mi->r[idx].stats.cur_tp) * 1200 * 8 / 1024; 673 + tmp_mrs = &mi->r[idx].stats; 674 + tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma); 675 + tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; 676 + 677 + return tmp_cur_tp; 711 678 } 712 679 713 680 const struct rate_control_ops mac80211_minstrel = {
+39 -10
net/mac80211/rc80211_minstrel.h
··· 13 13 #define EWMA_DIV 128 14 14 #define SAMPLE_COLUMNS 10 /* number of columns in sample table */ 15 15 16 - 17 16 /* scaled fraction values */ 18 17 #define MINSTREL_SCALE 16 19 18 #define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) ··· 23 24 24 25 /* 25 26 * Perform EWMA (Exponentially Weighted Moving Average) calculation 26 - */ 27 + */ 27 28 static inline int 28 29 minstrel_ewma(int old, int new, int weight) 29 30 { 30 - return (new * (EWMA_DIV - weight) + old * weight) / EWMA_DIV; 31 + int diff, incr; 32 + 33 + diff = new - old; 34 + incr = (EWMA_DIV - weight) * diff / EWMA_DIV; 35 + 36 + return old + incr; 37 + } 38 + 39 + /* 40 + * Perform EWMSD (Exponentially Weighted Moving Standard Deviation) calculation 41 + */ 42 + static inline int 43 + minstrel_ewmsd(int old_ewmsd, int cur_prob, int prob_ewma, int weight) 44 + { 45 + int diff, incr, tmp_var; 46 + 47 + /* calculate exponential weighted moving variance */ 48 + diff = MINSTREL_TRUNC((cur_prob - prob_ewma) * 1000000); 49 + incr = (EWMA_DIV - weight) * diff / EWMA_DIV; 50 + tmp_var = old_ewmsd * old_ewmsd; 51 + tmp_var = weight * (tmp_var + diff * incr / 1000000) / EWMA_DIV; 52 + 53 + /* return standard deviation */ 54 + return (u16) int_sqrt(tmp_var); 31 55 } 32 56 33 57 struct minstrel_rate_stats { ··· 61 39 /* total attempts/success counters */ 62 40 u64 att_hist, succ_hist; 63 41 64 - /* current throughput */ 65 - unsigned int cur_tp; 66 - 67 - /* packet delivery probabilities */ 68 - unsigned int cur_prob, probability; 42 + /* statistis of packet delivery probability 43 + * cur_prob - current prob within last update intervall 44 + * prob_ewma - exponential weighted moving average of prob 45 + * prob_ewmsd - exp. weighted moving standard deviation of prob */ 46 + unsigned int cur_prob; 47 + unsigned int prob_ewma; 48 + u16 prob_ewmsd; 69 49 70 50 /* maximum retry counts */ 71 51 u8 retry_count; ··· 95 71 struct minstrel_sta_info { 96 72 struct ieee80211_sta *sta; 97 73 98 - unsigned long stats_update; 74 + unsigned long last_stats_update; 99 75 unsigned int sp_ack_dur; 100 76 unsigned int rate_avg; 101 77 ··· 119 95 120 96 #ifdef CONFIG_MAC80211_DEBUGFS 121 97 struct dentry *dbg_stats; 98 + struct dentry *dbg_stats_csv; 122 99 #endif 123 100 }; 124 101 ··· 146 121 u32 fixed_rate_idx; 147 122 struct dentry *dbg_fixed_rate; 148 123 #endif 149 - 150 124 }; 151 125 152 126 struct minstrel_debugfs_info { ··· 157 133 void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); 158 134 void minstrel_remove_sta_debugfs(void *priv, void *priv_sta); 159 135 136 + /* Recalculate success probabilities and counters for a given rate using EWMA */ 137 + void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); 138 + int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma); 139 + 160 140 /* debugfs */ 161 141 int minstrel_stats_open(struct inode *inode, struct file *file); 142 + int minstrel_stats_csv_open(struct inode *inode, struct file *file); 162 143 ssize_t minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos); 163 144 int minstrel_stats_release(struct inode *inode, struct file *file); 164 145
+138 -53
net/mac80211/rc80211_minstrel_debugfs.c
··· 54 54 #include <net/mac80211.h> 55 55 #include "rc80211_minstrel.h" 56 56 57 - int 58 - minstrel_stats_open(struct inode *inode, struct file *file) 59 - { 60 - struct minstrel_sta_info *mi = inode->i_private; 61 - struct minstrel_debugfs_info *ms; 62 - unsigned int i, tp, prob, eprob; 63 - char *p; 64 - 65 - ms = kmalloc(2048, GFP_KERNEL); 66 - if (!ms) 67 - return -ENOMEM; 68 - 69 - file->private_data = ms; 70 - p = ms->buf; 71 - p += sprintf(p, "rate tpt eprob *prob" 72 - " *ok(*cum) ok( cum)\n"); 73 - for (i = 0; i < mi->n_rates; i++) { 74 - struct minstrel_rate *mr = &mi->r[i]; 75 - struct minstrel_rate_stats *mrs = &mi->r[i].stats; 76 - 77 - *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; 78 - *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; 79 - *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' '; 80 - *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' '; 81 - *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; 82 - p += sprintf(p, "%3u%s", mr->bitrate / 2, 83 - (mr->bitrate & 1 ? ".5" : " ")); 84 - 85 - tp = MINSTREL_TRUNC(mrs->cur_tp / 10); 86 - prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 87 - eprob = MINSTREL_TRUNC(mrs->probability * 1000); 88 - 89 - p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u" 90 - " %4u(%4u) %9llu(%9llu)\n", 91 - tp / 10, tp % 10, 92 - eprob / 10, eprob % 10, 93 - prob / 10, prob % 10, 94 - mrs->last_success, 95 - mrs->last_attempts, 96 - (unsigned long long)mrs->succ_hist, 97 - (unsigned long long)mrs->att_hist); 98 - } 99 - p += sprintf(p, "\nTotal packet count:: ideal %d " 100 - "lookaround %d\n\n", 101 - mi->total_packets - mi->sample_packets, 102 - mi->sample_packets); 103 - ms->len = p - ms->buf; 104 - 105 - WARN_ON(ms->len + sizeof(*ms) > 2048); 106 - 107 - return 0; 108 - } 109 - 110 57 ssize_t 111 58 minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) 112 59 { ··· 70 123 return 0; 71 124 } 72 125 126 + int 127 + minstrel_stats_open(struct inode *inode, struct file *file) 128 + { 129 + struct minstrel_sta_info *mi = inode->i_private; 130 + struct minstrel_debugfs_info *ms; 131 + unsigned int i, tp_max, tp_avg, prob, eprob; 132 + char *p; 133 + 134 + ms = kmalloc(2048, GFP_KERNEL); 135 + if (!ms) 136 + return -ENOMEM; 137 + 138 + file->private_data = ms; 139 + p = ms->buf; 140 + p += sprintf(p, "\n"); 141 + p += sprintf(p, "best __________rate_________ ______" 142 + "statistics______ ________last_______ " 143 + "______sum-of________\n"); 144 + p += sprintf(p, "rate [name idx airtime max_tp] [ ø(tp) ø(prob) " 145 + "sd(prob)] [prob.|retry|suc|att] " 146 + "[#success | #attempts]\n"); 147 + 148 + for (i = 0; i < mi->n_rates; i++) { 149 + struct minstrel_rate *mr = &mi->r[i]; 150 + struct minstrel_rate_stats *mrs = &mi->r[i].stats; 151 + 152 + *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; 153 + *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; 154 + *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' '; 155 + *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' '; 156 + *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; 157 + 158 + p += sprintf(p, " %3u%s ", mr->bitrate / 2, 159 + (mr->bitrate & 1 ? ".5" : " ")); 160 + p += sprintf(p, "%3u ", i); 161 + p += sprintf(p, "%6u ", mr->perfect_tx_time); 162 + 163 + tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); 164 + tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); 165 + prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 166 + eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 167 + 168 + p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" 169 + " %3u.%1u %3u %3u %-3u " 170 + "%9llu %-9llu\n", 171 + tp_max / 10, tp_max % 10, 172 + tp_avg / 10, tp_avg % 10, 173 + eprob / 10, eprob % 10, 174 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 175 + prob / 10, prob % 10, 176 + mrs->retry_count, 177 + mrs->last_success, 178 + mrs->last_attempts, 179 + (unsigned long long)mrs->succ_hist, 180 + (unsigned long long)mrs->att_hist); 181 + } 182 + p += sprintf(p, "\nTotal packet count:: ideal %d " 183 + "lookaround %d\n\n", 184 + mi->total_packets - mi->sample_packets, 185 + mi->sample_packets); 186 + ms->len = p - ms->buf; 187 + 188 + WARN_ON(ms->len + sizeof(*ms) > 2048); 189 + 190 + return 0; 191 + } 192 + 73 193 static const struct file_operations minstrel_stat_fops = { 74 194 .owner = THIS_MODULE, 75 195 .open = minstrel_stats_open, 196 + .read = minstrel_stats_read, 197 + .release = minstrel_stats_release, 198 + .llseek = default_llseek, 199 + }; 200 + 201 + int 202 + minstrel_stats_csv_open(struct inode *inode, struct file *file) 203 + { 204 + struct minstrel_sta_info *mi = inode->i_private; 205 + struct minstrel_debugfs_info *ms; 206 + unsigned int i, tp_max, tp_avg, prob, eprob; 207 + char *p; 208 + 209 + ms = kmalloc(2048, GFP_KERNEL); 210 + if (!ms) 211 + return -ENOMEM; 212 + 213 + file->private_data = ms; 214 + p = ms->buf; 215 + 216 + for (i = 0; i < mi->n_rates; i++) { 217 + struct minstrel_rate *mr = &mi->r[i]; 218 + struct minstrel_rate_stats *mrs = &mi->r[i].stats; 219 + 220 + p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : "")); 221 + p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : "")); 222 + p += sprintf(p, "%s" ,((i == mi->max_tp_rate[2]) ? "C" : "")); 223 + p += sprintf(p, "%s" ,((i == mi->max_tp_rate[3]) ? "D" : "")); 224 + p += sprintf(p, "%s" ,((i == mi->max_prob_rate) ? "P" : "")); 225 + 226 + p += sprintf(p, ",%u%s", mr->bitrate / 2, 227 + (mr->bitrate & 1 ? ".5," : ",")); 228 + p += sprintf(p, "%u,", i); 229 + p += sprintf(p, "%u,",mr->perfect_tx_time); 230 + 231 + tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); 232 + tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); 233 + prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 234 + eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 235 + 236 + p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u,%u," 237 + "%llu,%llu,%d,%d\n", 238 + tp_max / 10, tp_max % 10, 239 + tp_avg / 10, tp_avg % 10, 240 + eprob / 10, eprob % 10, 241 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 242 + prob / 10, prob % 10, 243 + mrs->retry_count, 244 + mrs->last_success, 245 + mrs->last_attempts, 246 + (unsigned long long)mrs->succ_hist, 247 + (unsigned long long)mrs->att_hist, 248 + mi->total_packets - mi->sample_packets, 249 + mi->sample_packets); 250 + 251 + } 252 + ms->len = p - ms->buf; 253 + 254 + WARN_ON(ms->len + sizeof(*ms) > 2048); 255 + 256 + return 0; 257 + } 258 + 259 + static const struct file_operations minstrel_stat_csv_fops = { 260 + .owner = THIS_MODULE, 261 + .open = minstrel_stats_csv_open, 76 262 .read = minstrel_stats_read, 77 263 .release = minstrel_stats_release, 78 264 .llseek = default_llseek, ··· 218 138 219 139 mi->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, mi, 220 140 &minstrel_stat_fops); 141 + 142 + mi->dbg_stats_csv = debugfs_create_file("rc_stats_csv", S_IRUGO, dir, 143 + mi, &minstrel_stat_csv_fops); 221 144 } 222 145 223 146 void ··· 229 146 struct minstrel_sta_info *mi = priv_sta; 230 147 231 148 debugfs_remove(mi->dbg_stats); 149 + 150 + debugfs_remove(mi->dbg_stats_csv); 232 151 }
+105 -112
net/mac80211/rc80211_minstrel_ht.c
··· 313 313 return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; 314 314 } 315 315 316 - 317 316 /* 318 - * Recalculate success probabilities and counters for a rate using EWMA 317 + * Return current throughput based on the average A-MPDU length, taking into 318 + * account the expected number of retransmissions and their expected length 319 319 */ 320 - static void 321 - minstrel_calc_rate_ewma(struct minstrel_rate_stats *mr) 320 + int 321 + minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, 322 + int prob_ewma) 322 323 { 323 - if (unlikely(mr->attempts > 0)) { 324 - mr->sample_skipped = 0; 325 - mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); 326 - if (!mr->att_hist) 327 - mr->probability = mr->cur_prob; 328 - else 329 - mr->probability = minstrel_ewma(mr->probability, 330 - mr->cur_prob, EWMA_LEVEL); 331 - mr->att_hist += mr->attempts; 332 - mr->succ_hist += mr->success; 333 - } else { 334 - mr->sample_skipped++; 335 - } 336 - mr->last_success = mr->success; 337 - mr->last_attempts = mr->attempts; 338 - mr->success = 0; 339 - mr->attempts = 0; 340 - } 341 - 342 - /* 343 - * Calculate throughput based on the average A-MPDU length, taking into account 344 - * the expected number of retransmissions and their expected length 345 - */ 346 - static void 347 - minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate) 348 - { 349 - struct minstrel_rate_stats *mr; 350 324 unsigned int nsecs = 0; 351 - unsigned int tp; 352 - unsigned int prob; 353 325 354 - mr = &mi->groups[group].rates[rate]; 355 - prob = mr->probability; 356 - 357 - if (prob < MINSTREL_FRAC(1, 10)) { 358 - mr->cur_tp = 0; 359 - return; 360 - } 361 - 362 - /* 363 - * For the throughput calculation, limit the probability value to 90% to 364 - * account for collision related packet error rate fluctuation 365 - */ 366 - if (prob > MINSTREL_FRAC(9, 10)) 367 - prob = MINSTREL_FRAC(9, 10); 326 + /* do not account throughput if sucess prob is below 10% */ 327 + if (prob_ewma < MINSTREL_FRAC(10, 100)) 328 + return 0; 368 329 369 330 if (group != MINSTREL_CCK_GROUP) 370 331 nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len); 371 332 372 333 nsecs += minstrel_mcs_groups[group].duration[rate]; 373 334 374 - /* prob is scaled - see MINSTREL_FRAC above */ 375 - tp = 1000000 * ((prob * 1000) / nsecs); 376 - mr->cur_tp = MINSTREL_TRUNC(tp); 335 + /* 336 + * For the throughput calculation, limit the probability value to 90% to 337 + * account for collision related packet error rate fluctuation 338 + * (prob is scaled - see MINSTREL_FRAC above) 339 + */ 340 + if (prob_ewma > MINSTREL_FRAC(90, 100)) 341 + return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000) 342 + / nsecs)); 343 + else 344 + return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs)); 377 345 } 378 346 379 347 /* ··· 355 387 minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, 356 388 u16 *tp_list) 357 389 { 358 - int cur_group, cur_idx, cur_thr, cur_prob; 359 - int tmp_group, tmp_idx, tmp_thr, tmp_prob; 390 + int cur_group, cur_idx, cur_tp_avg, cur_prob; 391 + int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; 360 392 int j = MAX_THR_RATES; 361 393 362 394 cur_group = index / MCS_GROUP_RATES; 363 395 cur_idx = index % MCS_GROUP_RATES; 364 - cur_thr = mi->groups[cur_group].rates[cur_idx].cur_tp; 365 - cur_prob = mi->groups[cur_group].rates[cur_idx].probability; 396 + cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; 397 + cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); 366 398 367 399 do { 368 400 tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; 369 401 tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; 370 - tmp_thr = mi->groups[tmp_group].rates[tmp_idx].cur_tp; 371 - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability; 372 - if (cur_thr < tmp_thr || 373 - (cur_thr == tmp_thr && cur_prob <= tmp_prob)) 402 + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; 403 + tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, 404 + tmp_prob); 405 + if (cur_tp_avg < tmp_tp_avg || 406 + (cur_tp_avg == tmp_tp_avg && cur_prob <= tmp_prob)) 374 407 break; 375 408 j--; 376 409 } while (j > 0); ··· 391 422 minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) 392 423 { 393 424 struct minstrel_mcs_group_data *mg; 394 - struct minstrel_rate_stats *mr; 395 - int tmp_group, tmp_idx, tmp_tp, tmp_prob, max_tp_group; 425 + struct minstrel_rate_stats *mrs; 426 + int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; 427 + int max_tp_group, cur_tp_avg, cur_group, cur_idx; 428 + int max_gpr_group, max_gpr_idx; 429 + int max_gpr_tp_avg, max_gpr_prob; 396 430 431 + cur_group = index / MCS_GROUP_RATES; 432 + cur_idx = index % MCS_GROUP_RATES; 397 433 mg = &mi->groups[index / MCS_GROUP_RATES]; 398 - mr = &mg->rates[index % MCS_GROUP_RATES]; 434 + mrs = &mg->rates[index % MCS_GROUP_RATES]; 399 435 400 436 tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; 401 437 tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; 402 - tmp_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp; 403 - tmp_prob = mi->groups[tmp_group].rates[tmp_idx].probability; 438 + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; 439 + tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); 404 440 405 441 /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from 406 442 * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ ··· 414 440 (max_tp_group != MINSTREL_CCK_GROUP)) 415 441 return; 416 442 417 - if (mr->probability > MINSTREL_FRAC(75, 100)) { 418 - if (mr->cur_tp > tmp_tp) 443 + if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { 444 + cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, 445 + mrs->prob_ewma); 446 + if (cur_tp_avg > tmp_tp_avg) 419 447 mi->max_prob_rate = index; 420 - if (mr->cur_tp > mg->rates[mg->max_group_prob_rate].cur_tp) 448 + 449 + max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; 450 + max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; 451 + max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma; 452 + max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group, 453 + max_gpr_idx, 454 + max_gpr_prob); 455 + if (cur_tp_avg > max_gpr_tp_avg) 421 456 mg->max_group_prob_rate = index; 422 457 } else { 423 - if (mr->probability > tmp_prob) 458 + if (mrs->prob_ewma > tmp_prob) 424 459 mi->max_prob_rate = index; 425 - if (mr->probability > mg->rates[mg->max_group_prob_rate].probability) 460 + if (mrs->prob_ewma > mg->rates[mg->max_group_prob_rate].prob_ewma) 426 461 mg->max_group_prob_rate = index; 427 462 } 428 463 } ··· 448 465 u16 tmp_mcs_tp_rate[MAX_THR_RATES], 449 466 u16 tmp_cck_tp_rate[MAX_THR_RATES]) 450 467 { 451 - unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp; 468 + unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; 452 469 int i; 453 470 454 471 tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; 455 472 tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; 456 - tmp_cck_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp; 473 + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; 474 + tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); 457 475 458 476 tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; 459 477 tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; 460 - tmp_mcs_tp = mi->groups[tmp_group].rates[tmp_idx].cur_tp; 478 + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; 479 + tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); 461 480 462 481 if (tmp_cck_tp > tmp_mcs_tp) { 463 482 for(i = 0; i < MAX_THR_RATES; i++) { ··· 478 493 minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) 479 494 { 480 495 struct minstrel_mcs_group_data *mg; 481 - struct minstrel_rate_stats *mr; 482 - int tmp_max_streams, group; 496 + int tmp_max_streams, group, tmp_idx, tmp_prob; 483 497 int tmp_tp = 0; 484 498 485 499 tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / ··· 487 503 mg = &mi->groups[group]; 488 504 if (!mg->supported || group == MINSTREL_CCK_GROUP) 489 505 continue; 490 - mr = minstrel_get_ratestats(mi, mg->max_group_prob_rate); 491 - if (tmp_tp < mr->cur_tp && 506 + 507 + tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; 508 + tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma; 509 + 510 + if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && 492 511 (minstrel_mcs_groups[group].streams < tmp_max_streams)) { 493 512 mi->max_prob_rate = mg->max_group_prob_rate; 494 - tmp_tp = mr->cur_tp; 513 + tmp_tp = minstrel_ht_get_tp_avg(mi, group, 514 + tmp_idx, 515 + tmp_prob); 495 516 } 496 517 } 497 518 } ··· 514 525 minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) 515 526 { 516 527 struct minstrel_mcs_group_data *mg; 517 - struct minstrel_rate_stats *mr; 518 - int group, i, j; 528 + struct minstrel_rate_stats *mrs; 529 + int group, i, j, cur_prob; 519 530 u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; 520 531 u16 tmp_cck_tp_rate[MAX_THR_RATES], index; 521 532 ··· 554 565 555 566 index = MCS_GROUP_RATES * group + i; 556 567 557 - mr = &mg->rates[i]; 558 - mr->retry_updated = false; 559 - minstrel_calc_rate_ewma(mr); 560 - minstrel_ht_calc_tp(mi, group, i); 568 + mrs = &mg->rates[i]; 569 + mrs->retry_updated = false; 570 + minstrel_calc_rate_stats(mrs); 571 + cur_prob = mrs->prob_ewma; 561 572 562 - if (!mr->cur_tp) 573 + if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) 563 574 continue; 564 575 565 576 /* Find max throughput rate set */ ··· 603 614 #endif 604 615 605 616 /* Reset update timer */ 606 - mi->stats_update = jiffies; 617 + mi->last_stats_update = jiffies; 607 618 } 608 619 609 620 static bool ··· 626 637 } 627 638 628 639 static void 629 - minstrel_next_sample_idx(struct minstrel_ht_sta *mi) 640 + minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi) 630 641 { 631 642 struct minstrel_mcs_group_data *mg; 632 643 ··· 767 778 update = true; 768 779 } 769 780 770 - if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) { 781 + if (time_after(jiffies, mi->last_stats_update + 782 + (mp->update_interval / 2 * HZ) / 1000)) { 771 783 update = true; 772 784 minstrel_ht_update_stats(mp, mi); 773 785 } ··· 781 791 minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, 782 792 int index) 783 793 { 784 - struct minstrel_rate_stats *mr; 794 + struct minstrel_rate_stats *mrs; 785 795 const struct mcs_group *group; 786 796 unsigned int tx_time, tx_time_rtscts, tx_time_data; 787 797 unsigned int cw = mp->cw_min; ··· 790 800 unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len); 791 801 unsigned int overhead = 0, overhead_rtscts = 0; 792 802 793 - mr = minstrel_get_ratestats(mi, index); 794 - if (mr->probability < MINSTREL_FRAC(1, 10)) { 795 - mr->retry_count = 1; 796 - mr->retry_count_rtscts = 1; 803 + mrs = minstrel_get_ratestats(mi, index); 804 + if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) { 805 + mrs->retry_count = 1; 806 + mrs->retry_count_rtscts = 1; 797 807 return; 798 808 } 799 809 800 - mr->retry_count = 2; 801 - mr->retry_count_rtscts = 2; 802 - mr->retry_updated = true; 810 + mrs->retry_count = 2; 811 + mrs->retry_count_rtscts = 2; 812 + mrs->retry_updated = true; 803 813 804 814 group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 805 815 tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000; ··· 830 840 tx_time_rtscts += ctime + overhead_rtscts + tx_time_data; 831 841 832 842 if (tx_time_rtscts < mp->segment_size) 833 - mr->retry_count_rtscts++; 843 + mrs->retry_count_rtscts++; 834 844 } while ((tx_time < mp->segment_size) && 835 - (++mr->retry_count < mp->max_retry)); 845 + (++mrs->retry_count < mp->max_retry)); 836 846 } 837 847 838 848 ··· 841 851 struct ieee80211_sta_rates *ratetbl, int offset, int index) 842 852 { 843 853 const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; 844 - struct minstrel_rate_stats *mr; 854 + struct minstrel_rate_stats *mrs; 845 855 u8 idx; 846 856 u16 flags = group->flags; 847 857 848 - mr = minstrel_get_ratestats(mi, index); 849 - if (!mr->retry_updated) 858 + mrs = minstrel_get_ratestats(mi, index); 859 + if (!mrs->retry_updated) 850 860 minstrel_calc_retransmit(mp, mi, index); 851 861 852 - if (mr->probability < MINSTREL_FRAC(20, 100) || !mr->retry_count) { 862 + if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) { 853 863 ratetbl->rate[offset].count = 2; 854 864 ratetbl->rate[offset].count_rts = 2; 855 865 ratetbl->rate[offset].count_cts = 2; 856 866 } else { 857 - ratetbl->rate[offset].count = mr->retry_count; 858 - ratetbl->rate[offset].count_cts = mr->retry_count; 859 - ratetbl->rate[offset].count_rts = mr->retry_count_rtscts; 867 + ratetbl->rate[offset].count = mrs->retry_count; 868 + ratetbl->rate[offset].count_cts = mrs->retry_count; 869 + ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; 860 870 } 861 871 862 872 if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) ··· 914 924 static int 915 925 minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) 916 926 { 917 - struct minstrel_rate_stats *mr; 927 + struct minstrel_rate_stats *mrs; 918 928 struct minstrel_mcs_group_data *mg; 919 929 unsigned int sample_dur, sample_group, cur_max_tp_streams; 920 930 int sample_idx = 0; ··· 930 940 sample_group = mi->sample_group; 931 941 mg = &mi->groups[sample_group]; 932 942 sample_idx = sample_table[mg->column][mg->index]; 933 - minstrel_next_sample_idx(mi); 943 + minstrel_set_next_sample_idx(mi); 934 944 935 945 if (!(mg->supported & BIT(sample_idx))) 936 946 return -1; 937 947 938 - mr = &mg->rates[sample_idx]; 948 + mrs = &mg->rates[sample_idx]; 939 949 sample_idx += sample_group * MCS_GROUP_RATES; 940 950 941 951 /* ··· 952 962 * Do not sample if the probability is already higher than 95% 953 963 * to avoid wasting airtime. 954 964 */ 955 - if (mr->probability > MINSTREL_FRAC(95, 100)) 965 + if (mrs->prob_ewma > MINSTREL_FRAC(95, 100)) 956 966 return -1; 957 967 958 968 /* ··· 967 977 (cur_max_tp_streams - 1 < 968 978 minstrel_mcs_groups[sample_group].streams || 969 979 sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { 970 - if (mr->sample_skipped < 20) 980 + if (mrs->sample_skipped < 20) 971 981 return -1; 972 982 973 983 if (mi->sample_slow++ > 2) ··· 1121 1131 memset(mi, 0, sizeof(*mi)); 1122 1132 1123 1133 mi->sta = sta; 1124 - mi->stats_update = jiffies; 1134 + mi->last_stats_update = jiffies; 1125 1135 1126 1136 ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0); 1127 1137 mi->overhead = ieee80211_frame_duration(sband->band, 0, 60, 1, 1, 0); ··· 1318 1328 { 1319 1329 struct minstrel_ht_sta_priv *msp = priv_sta; 1320 1330 struct minstrel_ht_sta *mi = &msp->ht; 1321 - int i, j; 1331 + int i, j, prob, tp_avg; 1322 1332 1323 1333 if (!msp->is_ht) 1324 1334 return mac80211_minstrel.get_expected_throughput(priv_sta); 1325 1335 1326 1336 i = mi->max_tp_rate[0] / MCS_GROUP_RATES; 1327 1337 j = mi->max_tp_rate[0] % MCS_GROUP_RATES; 1338 + prob = mi->groups[i].rates[j].prob_ewma; 1328 1339 1329 - /* convert cur_tp from pkt per second in kbps */ 1330 - return mi->groups[i].rates[j].cur_tp * AVG_PKT_SIZE * 8 / 1024; 1340 + /* convert tp_avg from pkt per second in kbps */ 1341 + tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024; 1342 + 1343 + return tp_avg; 1331 1344 } 1332 1345 1333 1346 static const struct rate_control_ops mac80211_minstrel_ht = {
+4 -1
net/mac80211/rc80211_minstrel_ht.h
··· 78 78 u16 max_prob_rate; 79 79 80 80 /* time of last status update */ 81 - unsigned long stats_update; 81 + unsigned long last_stats_update; 82 82 83 83 /* overhead time in usec for each frame */ 84 84 unsigned int overhead; ··· 112 112 }; 113 113 #ifdef CONFIG_MAC80211_DEBUGFS 114 114 struct dentry *dbg_stats; 115 + struct dentry *dbg_stats_csv; 115 116 #endif 116 117 void *ratelist; 117 118 void *sample_table; ··· 121 120 122 121 void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); 123 122 void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta); 123 + int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, 124 + int prob_ewma); 124 125 125 126 #endif
+189 -27
net/mac80211/rc80211_minstrel_ht_debugfs.c
··· 19 19 minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) 20 20 { 21 21 const struct mcs_group *mg; 22 - unsigned int j, tp, prob, eprob; 22 + unsigned int j, tp_max, tp_avg, prob, eprob, tx_time; 23 23 char htmode = '2'; 24 24 char gimode = 'L'; 25 25 u32 gflags; ··· 38 38 gimode = 'S'; 39 39 40 40 for (j = 0; j < MCS_GROUP_RATES; j++) { 41 - struct minstrel_rate_stats *mr = &mi->groups[i].rates[j]; 41 + struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; 42 42 static const int bitrates[4] = { 10, 20, 55, 110 }; 43 43 int idx = i * MCS_GROUP_RATES + j; 44 44 45 45 if (!(mi->groups[i].supported & BIT(j))) 46 46 continue; 47 47 48 - if (gflags & IEEE80211_TX_RC_MCS) 49 - p += sprintf(p, " HT%c0/%cGI ", htmode, gimode); 50 - else if (gflags & IEEE80211_TX_RC_VHT_MCS) 51 - p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode); 52 - else 53 - p += sprintf(p, " CCK/%cP ", j < 4 ? 'L' : 'S'); 48 + if (gflags & IEEE80211_TX_RC_MCS) { 49 + p += sprintf(p, "HT%c0 ", htmode); 50 + p += sprintf(p, "%cGI ", gimode); 51 + p += sprintf(p, "%d ", mg->streams); 52 + } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { 53 + p += sprintf(p, "VHT%c0 ", htmode); 54 + p += sprintf(p, "%cGI ", gimode); 55 + p += sprintf(p, "%d ", mg->streams); 56 + } else { 57 + p += sprintf(p, "CCK "); 58 + p += sprintf(p, "%cP ", j < 4 ? 'L' : 'S'); 59 + p += sprintf(p, "1 "); 60 + } 54 61 55 62 *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' '; 56 63 *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' '; ··· 66 59 *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; 67 60 68 61 if (gflags & IEEE80211_TX_RC_MCS) { 69 - p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j); 62 + p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); 70 63 } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { 71 - p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); 64 + p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); 72 65 } else { 73 66 int r = bitrates[j % 4]; 74 67 75 - p += sprintf(p, " %2u.%1uM ", r / 10, r % 10); 68 + p += sprintf(p, " %2u.%1uM", r / 10, r % 10); 76 69 } 77 70 78 - tp = mr->cur_tp / 10; 79 - prob = MINSTREL_TRUNC(mr->cur_prob * 1000); 80 - eprob = MINSTREL_TRUNC(mr->probability * 1000); 71 + p += sprintf(p, " %3u ", idx); 81 72 82 - p += sprintf(p, " %4u.%1u %3u.%1u %3u.%1u " 83 - "%3u %4u(%4u) %9llu(%9llu)\n", 84 - tp / 10, tp % 10, 73 + /* tx_time[rate(i)] in usec */ 74 + tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); 75 + p += sprintf(p, "%6u ", tx_time); 76 + 77 + tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); 78 + tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); 79 + prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 80 + eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 81 + 82 + p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u %3u.%1u" 83 + " %3u.%1u %3u %3u %-3u " 84 + "%9llu %-9llu\n", 85 + tp_max / 10, tp_max % 10, 86 + tp_avg / 10, tp_avg % 10, 85 87 eprob / 10, eprob % 10, 88 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 86 89 prob / 10, prob % 10, 87 - mr->retry_count, 88 - mr->last_success, 89 - mr->last_attempts, 90 - (unsigned long long)mr->succ_hist, 91 - (unsigned long long)mr->att_hist); 90 + mrs->retry_count, 91 + mrs->last_success, 92 + mrs->last_attempts, 93 + (unsigned long long)mrs->succ_hist, 94 + (unsigned long long)mrs->att_hist); 92 95 } 93 96 94 97 return p; ··· 111 94 struct minstrel_ht_sta *mi = &msp->ht; 112 95 struct minstrel_debugfs_info *ms; 113 96 unsigned int i; 114 - char *p; 115 97 int ret; 98 + char *p; 116 99 117 100 if (!msp->is_ht) { 118 101 inode->i_private = &msp->legacy; ··· 127 110 128 111 file->private_data = ms; 129 112 p = ms->buf; 130 - p += sprintf(p, " type rate tpt eprob *prob " 131 - "ret *ok(*cum) ok( cum)\n"); 113 + 114 + p += sprintf(p, "\n"); 115 + p += sprintf(p, " best ____________rate__________ " 116 + "______statistics______ ________last_______ " 117 + "______sum-of________\n"); 118 + p += sprintf(p, "mode guard # rate [name idx airtime max_tp] " 119 + "[ ø(tp) ø(prob) sd(prob)] [prob.|retry|suc|att] [#success | " 120 + "#attempts]\n"); 132 121 133 122 p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); 134 123 for (i = 0; i < MINSTREL_CCK_GROUP; i++) ··· 146 123 "lookaround %d\n", 147 124 max(0, (int) mi->total_packets - (int) mi->sample_packets), 148 125 mi->sample_packets); 149 - p += sprintf(p, "Average A-MPDU length: %d.%d\n", 126 + p += sprintf(p, "Average # of aggregated frames per A-MPDU: %d.%d\n", 150 127 MINSTREL_TRUNC(mi->avg_ampdu_len), 151 128 MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); 152 129 ms->len = p - ms->buf; 153 - 154 130 WARN_ON(ms->len + sizeof(*ms) > 32768); 155 131 156 132 return nonseekable_open(inode, file); ··· 163 141 .llseek = no_llseek, 164 142 }; 165 143 144 + static char * 145 + minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) 146 + { 147 + const struct mcs_group *mg; 148 + unsigned int j, tp_max, tp_avg, prob, eprob, tx_time; 149 + char htmode = '2'; 150 + char gimode = 'L'; 151 + u32 gflags; 152 + 153 + if (!mi->groups[i].supported) 154 + return p; 155 + 156 + mg = &minstrel_mcs_groups[i]; 157 + gflags = mg->flags; 158 + 159 + if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) 160 + htmode = '4'; 161 + else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) 162 + htmode = '8'; 163 + if (gflags & IEEE80211_TX_RC_SHORT_GI) 164 + gimode = 'S'; 165 + 166 + for (j = 0; j < MCS_GROUP_RATES; j++) { 167 + struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; 168 + static const int bitrates[4] = { 10, 20, 55, 110 }; 169 + int idx = i * MCS_GROUP_RATES + j; 170 + 171 + if (!(mi->groups[i].supported & BIT(j))) 172 + continue; 173 + 174 + if (gflags & IEEE80211_TX_RC_MCS) { 175 + p += sprintf(p, "HT%c0,", htmode); 176 + p += sprintf(p, "%cGI,", gimode); 177 + p += sprintf(p, "%d,", mg->streams); 178 + } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { 179 + p += sprintf(p, "VHT%c0,", htmode); 180 + p += sprintf(p, "%cGI,", gimode); 181 + p += sprintf(p, "%d,", mg->streams); 182 + } else { 183 + p += sprintf(p, "CCK,"); 184 + p += sprintf(p, "%cP,", j < 4 ? 'L' : 'S'); 185 + p += sprintf(p, "1,"); 186 + } 187 + 188 + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[0]) ? "A" : "")); 189 + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[1]) ? "B" : "")); 190 + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : "")); 191 + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : "")); 192 + p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); 193 + 194 + if (gflags & IEEE80211_TX_RC_MCS) { 195 + p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j); 196 + } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { 197 + p += sprintf(p, ",MCS%-1u/%1u,", j, mg->streams); 198 + } else { 199 + int r = bitrates[j % 4]; 200 + p += sprintf(p, ",%2u.%1uM,", r / 10, r % 10); 201 + } 202 + 203 + p += sprintf(p, "%u,", idx); 204 + tx_time = DIV_ROUND_CLOSEST(mg->duration[j], 1000); 205 + p += sprintf(p, "%u,", tx_time); 206 + 207 + tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); 208 + tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); 209 + prob = MINSTREL_TRUNC(mrs->cur_prob * 1000); 210 + eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); 211 + 212 + p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u.%u,%u.%u,%u,%u," 213 + "%u,%llu,%llu,", 214 + tp_max / 10, tp_max % 10, 215 + tp_avg / 10, tp_avg % 10, 216 + eprob / 10, eprob % 10, 217 + mrs->prob_ewmsd / 10, mrs->prob_ewmsd % 10, 218 + prob / 10, prob % 10, 219 + mrs->retry_count, 220 + mrs->last_success, 221 + mrs->last_attempts, 222 + (unsigned long long)mrs->succ_hist, 223 + (unsigned long long)mrs->att_hist); 224 + p += sprintf(p, "%d,%d,%d.%d\n", 225 + max(0, (int) mi->total_packets - 226 + (int) mi->sample_packets), 227 + mi->sample_packets, 228 + MINSTREL_TRUNC(mi->avg_ampdu_len), 229 + MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10); 230 + } 231 + 232 + return p; 233 + } 234 + 235 + static int 236 + minstrel_ht_stats_csv_open(struct inode *inode, struct file *file) 237 + { 238 + struct minstrel_ht_sta_priv *msp = inode->i_private; 239 + struct minstrel_ht_sta *mi = &msp->ht; 240 + struct minstrel_debugfs_info *ms; 241 + unsigned int i; 242 + int ret; 243 + char *p; 244 + 245 + if (!msp->is_ht) { 246 + inode->i_private = &msp->legacy; 247 + ret = minstrel_stats_csv_open(inode, file); 248 + inode->i_private = msp; 249 + return ret; 250 + } 251 + 252 + ms = kmalloc(32768, GFP_KERNEL); 253 + 254 + if (!ms) 255 + return -ENOMEM; 256 + 257 + file->private_data = ms; 258 + 259 + p = ms->buf; 260 + 261 + p = minstrel_ht_stats_csv_dump(mi, MINSTREL_CCK_GROUP, p); 262 + for (i = 0; i < MINSTREL_CCK_GROUP; i++) 263 + p = minstrel_ht_stats_csv_dump(mi, i, p); 264 + for (i++; i < ARRAY_SIZE(mi->groups); i++) 265 + p = minstrel_ht_stats_csv_dump(mi, i, p); 266 + 267 + ms->len = p - ms->buf; 268 + WARN_ON(ms->len + sizeof(*ms) > 32768); 269 + 270 + return nonseekable_open(inode, file); 271 + } 272 + 273 + static const struct file_operations minstrel_ht_stat_csv_fops = { 274 + .owner = THIS_MODULE, 275 + .open = minstrel_ht_stats_csv_open, 276 + .read = minstrel_stats_read, 277 + .release = minstrel_stats_release, 278 + .llseek = no_llseek, 279 + }; 280 + 166 281 void 167 282 minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) 168 283 { ··· 307 148 308 149 msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp, 309 150 &minstrel_ht_stat_fops); 151 + msp->dbg_stats_csv = debugfs_create_file("rc_stats_csv", S_IRUGO, 152 + dir, msp, &minstrel_ht_stat_csv_fops); 310 153 } 311 154 312 155 void ··· 317 156 struct minstrel_ht_sta_priv *msp = priv_sta; 318 157 319 158 debugfs_remove(msp->dbg_stats); 159 + debugfs_remove(msp->dbg_stats_csv); 320 160 }
+20 -2
net/mac80211/rx.c
··· 1185 1185 struct ieee80211_sub_if_data *sdata = sta->sdata; 1186 1186 struct ieee80211_local *local = sdata->local; 1187 1187 struct ps_data *ps; 1188 + int tid; 1188 1189 1189 1190 if (sta->sdata->vif.type == NL80211_IFTYPE_AP || 1190 1191 sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) ··· 1199 1198 drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); 1200 1199 ps_dbg(sdata, "STA %pM aid %d enters power save mode\n", 1201 1200 sta->sta.addr, sta->sta.aid); 1201 + 1202 + if (!sta->sta.txq[0]) 1203 + return; 1204 + 1205 + for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { 1206 + struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); 1207 + 1208 + if (!skb_queue_len(&txqi->queue)) 1209 + set_bit(tid, &sta->txq_buffered_tids); 1210 + else 1211 + clear_bit(tid, &sta->txq_buffered_tids); 1212 + } 1202 1213 } 1203 1214 1204 1215 static void sta_ps_end(struct sta_info *sta) ··· 3437 3424 __le16 fc; 3438 3425 struct ieee80211_rx_data rx; 3439 3426 struct ieee80211_sub_if_data *prev; 3440 - struct sta_info *sta, *tmp, *prev_sta; 3427 + struct sta_info *sta, *prev_sta; 3428 + struct rhash_head *tmp; 3441 3429 int err = 0; 3442 3430 3443 3431 fc = ((struct ieee80211_hdr *)skb->data)->frame_control; ··· 3473 3459 ieee80211_scan_rx(local, skb); 3474 3460 3475 3461 if (ieee80211_is_data(fc)) { 3462 + const struct bucket_table *tbl; 3463 + 3476 3464 prev_sta = NULL; 3477 3465 3478 - for_each_sta_info(local, hdr->addr2, sta, tmp) { 3466 + tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 3467 + 3468 + for_each_sta_info(local, tbl, hdr->addr2, sta, tmp) { 3479 3469 if (!prev_sta) { 3480 3470 prev_sta = sta; 3481 3471 continue;
+127 -59
net/mac80211/sta_info.c
··· 64 64 * freed before they are done using it. 65 65 */ 66 66 67 + static const struct rhashtable_params sta_rht_params = { 68 + .nelem_hint = 3, /* start small */ 69 + .head_offset = offsetof(struct sta_info, hash_node), 70 + .key_offset = offsetof(struct sta_info, sta.addr), 71 + .key_len = ETH_ALEN, 72 + .hashfn = sta_addr_hash, 73 + }; 74 + 67 75 /* Caller must hold local->sta_mtx */ 68 76 static int sta_info_hash_del(struct ieee80211_local *local, 69 77 struct sta_info *sta) 70 78 { 71 - struct sta_info *s; 72 - 73 - s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], 74 - lockdep_is_held(&local->sta_mtx)); 75 - if (!s) 76 - return -ENOENT; 77 - if (s == sta) { 78 - rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], 79 - s->hnext); 80 - return 0; 81 - } 82 - 83 - while (rcu_access_pointer(s->hnext) && 84 - rcu_access_pointer(s->hnext) != sta) 85 - s = rcu_dereference_protected(s->hnext, 86 - lockdep_is_held(&local->sta_mtx)); 87 - if (rcu_access_pointer(s->hnext)) { 88 - rcu_assign_pointer(s->hnext, sta->hnext); 89 - return 0; 90 - } 91 - 92 - return -ENOENT; 79 + return rhashtable_remove_fast(&local->sta_hash, &sta->hash_node, 80 + sta_rht_params); 93 81 } 94 82 95 83 static void __cleanup_single_sta(struct sta_info *sta) ··· 104 116 clear_sta_flag(sta, WLAN_STA_PS_DELIVER); 105 117 106 118 atomic_dec(&ps->num_sta_ps); 119 + } 120 + 121 + if (sta->sta.txq[0]) { 122 + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 123 + struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); 124 + int n = skb_queue_len(&txqi->queue); 125 + 126 + ieee80211_purge_tx_queue(&local->hw, &txqi->queue); 127 + atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]); 128 + } 107 129 } 108 130 109 131 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { ··· 157 159 const u8 *addr) 158 160 { 159 161 struct ieee80211_local *local = sdata->local; 160 - struct sta_info *sta; 161 162 162 - sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], 163 - lockdep_is_held(&local->sta_mtx)); 164 - while (sta) { 165 - if (sta->sdata == sdata && 166 - ether_addr_equal(sta->sta.addr, addr)) 167 - break; 168 - sta = rcu_dereference_check(sta->hnext, 169 - lockdep_is_held(&local->sta_mtx)); 170 - } 171 - return sta; 163 + return rhashtable_lookup_fast(&local->sta_hash, addr, sta_rht_params); 172 164 } 173 165 174 166 /* ··· 170 182 { 171 183 struct ieee80211_local *local = sdata->local; 172 184 struct sta_info *sta; 185 + struct rhash_head *tmp; 186 + const struct bucket_table *tbl; 173 187 174 - sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], 175 - lockdep_is_held(&local->sta_mtx)); 176 - while (sta) { 177 - if ((sta->sdata == sdata || 178 - (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && 179 - ether_addr_equal(sta->sta.addr, addr)) 180 - break; 181 - sta = rcu_dereference_check(sta->hnext, 182 - lockdep_is_held(&local->sta_mtx)); 188 + rcu_read_lock(); 189 + tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 190 + 191 + for_each_sta_info(local, tbl, addr, sta, tmp) { 192 + if (sta->sdata == sdata || 193 + (sta->sdata->bss && sta->sdata->bss == sdata->bss)) { 194 + rcu_read_unlock(); 195 + /* this is safe as the caller must already hold 196 + * another rcu read section or the mutex 197 + */ 198 + return sta; 199 + } 183 200 } 184 - return sta; 201 + rcu_read_unlock(); 202 + return NULL; 185 203 } 186 204 187 205 struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, ··· 228 234 229 235 sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); 230 236 237 + if (sta->sta.txq[0]) 238 + kfree(to_txq_info(sta->sta.txq[0])); 231 239 kfree(rcu_dereference_raw(sta->sta.rates)); 232 240 kfree(sta); 233 241 } ··· 238 242 static void sta_info_hash_add(struct ieee80211_local *local, 239 243 struct sta_info *sta) 240 244 { 241 - lockdep_assert_held(&local->sta_mtx); 242 - sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)]; 243 - rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta); 245 + rhashtable_insert_fast(&local->sta_hash, &sta->hash_node, 246 + sta_rht_params); 244 247 } 245 248 246 249 static void sta_deliver_ps_frames(struct work_struct *wk) ··· 280 285 const u8 *addr, gfp_t gfp) 281 286 { 282 287 struct ieee80211_local *local = sdata->local; 288 + struct ieee80211_hw *hw = &local->hw; 283 289 struct sta_info *sta; 284 290 struct timespec uptime; 285 291 int i; 286 292 287 - sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); 293 + sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp); 288 294 if (!sta) 289 295 return NULL; 290 296 ··· 317 321 for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) 318 322 ewma_init(&sta->chain_signal_avg[i], 1024, 8); 319 323 320 - if (sta_prepare_rate_control(local, sta, gfp)) { 321 - kfree(sta); 322 - return NULL; 324 + if (local->ops->wake_tx_queue) { 325 + void *txq_data; 326 + int size = sizeof(struct txq_info) + 327 + ALIGN(hw->txq_data_size, sizeof(void *)); 328 + 329 + txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp); 330 + if (!txq_data) 331 + goto free; 332 + 333 + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 334 + struct txq_info *txq = txq_data + i * size; 335 + 336 + ieee80211_init_tx_queue(sdata, sta, txq, i); 337 + } 323 338 } 339 + 340 + if (sta_prepare_rate_control(local, sta, gfp)) 341 + goto free_txq; 324 342 325 343 for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 326 344 /* ··· 356 346 if (sdata->vif.type == NL80211_IFTYPE_AP || 357 347 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 358 348 struct ieee80211_supported_band *sband = 359 - local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; 349 + hw->wiphy->bands[ieee80211_get_sdata_band(sdata)]; 360 350 u8 smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 361 351 IEEE80211_HT_CAP_SM_PS_SHIFT; 362 352 /* ··· 381 371 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); 382 372 383 373 return sta; 374 + 375 + free_txq: 376 + if (sta->sta.txq[0]) 377 + kfree(to_txq_info(sta->sta.txq[0])); 378 + free: 379 + kfree(sta); 380 + return NULL; 384 381 } 385 382 386 383 static int sta_info_insert_check(struct sta_info *sta) ··· 657 640 658 641 indicate_tim |= 659 642 sta->driver_buffered_tids & tids; 643 + indicate_tim |= 644 + sta->txq_buffered_tids & tids; 660 645 } 661 646 662 647 done: ··· 967 948 round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); 968 949 } 969 950 970 - void sta_info_init(struct ieee80211_local *local) 951 + u32 sta_addr_hash(const void *key, u32 length, u32 seed) 971 952 { 953 + return jhash(key, ETH_ALEN, seed); 954 + } 955 + 956 + int sta_info_init(struct ieee80211_local *local) 957 + { 958 + int err; 959 + 960 + err = rhashtable_init(&local->sta_hash, &sta_rht_params); 961 + if (err) 962 + return err; 963 + 972 964 spin_lock_init(&local->tim_lock); 973 965 mutex_init(&local->sta_mtx); 974 966 INIT_LIST_HEAD(&local->sta_list); 975 967 976 968 setup_timer(&local->sta_cleanup, sta_info_cleanup, 977 969 (unsigned long)local); 970 + return 0; 978 971 } 979 972 980 973 void sta_info_stop(struct ieee80211_local *local) 981 974 { 982 975 del_timer_sync(&local->sta_cleanup); 976 + rhashtable_destroy(&local->sta_hash); 983 977 } 984 978 985 979 ··· 1056 1024 } 1057 1025 1058 1026 struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw, 1059 - const u8 *addr, 1060 - const u8 *localaddr) 1027 + const u8 *addr, 1028 + const u8 *localaddr) 1061 1029 { 1062 - struct sta_info *sta, *nxt; 1030 + struct ieee80211_local *local = hw_to_local(hw); 1031 + struct sta_info *sta; 1032 + struct rhash_head *tmp; 1033 + const struct bucket_table *tbl; 1034 + 1035 + tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 1063 1036 1064 1037 /* 1065 1038 * Just return a random station if localaddr is NULL 1066 1039 * ... first in list. 1067 1040 */ 1068 - for_each_sta_info(hw_to_local(hw), addr, sta, nxt) { 1041 + for_each_sta_info(local, tbl, addr, sta, tmp) { 1069 1042 if (localaddr && 1070 1043 !ether_addr_equal(sta->sdata->vif.addr, localaddr)) 1071 1044 continue; ··· 1108 1071 struct ieee80211_sub_if_data *sdata = sta->sdata; 1109 1072 struct ieee80211_local *local = sdata->local; 1110 1073 struct sk_buff_head pending; 1111 - int filtered = 0, buffered = 0, ac; 1074 + int filtered = 0, buffered = 0, ac, i; 1112 1075 unsigned long flags; 1113 1076 struct ps_data *ps; 1114 1077 ··· 1127 1090 1128 1091 BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); 1129 1092 sta->driver_buffered_tids = 0; 1093 + sta->txq_buffered_tids = 0; 1130 1094 1131 1095 if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) 1132 1096 drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); 1097 + 1098 + if (sta->sta.txq[0]) { 1099 + for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) { 1100 + struct txq_info *txqi = to_txq_info(sta->sta.txq[i]); 1101 + 1102 + if (!skb_queue_len(&txqi->queue)) 1103 + continue; 1104 + 1105 + drv_wake_tx_queue(local, txqi); 1106 + } 1107 + } 1133 1108 1134 1109 skb_queue_head_init(&pending); 1135 1110 ··· 1324 1275 /* if we already have frames from software, then we can't also 1325 1276 * release from hardware queues 1326 1277 */ 1327 - if (skb_queue_empty(&frames)) 1278 + if (skb_queue_empty(&frames)) { 1328 1279 driver_release_tids |= sta->driver_buffered_tids & tids; 1280 + driver_release_tids |= sta->txq_buffered_tids & tids; 1281 + } 1329 1282 1330 1283 if (driver_release_tids) { 1331 1284 /* If the driver has data on more than one TID then ··· 1498 1447 1499 1448 sta_info_recalc_tim(sta); 1500 1449 } else { 1450 + unsigned long tids = sta->txq_buffered_tids & driver_release_tids; 1451 + int tid; 1452 + 1501 1453 /* 1502 1454 * We need to release a frame that is buffered somewhere in the 1503 1455 * driver ... it'll have to handle that. ··· 1520 1466 * that the TID(s) became empty before returning here from the 1521 1467 * release function. 1522 1468 * Either way, however, when the driver tells us that the TID(s) 1523 - * became empty we'll do the TIM recalculation. 1469 + * became empty or we find that a txq became empty, we'll do the 1470 + * TIM recalculation. 1524 1471 */ 1472 + 1473 + if (!sta->sta.txq[0]) 1474 + return; 1475 + 1476 + for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { 1477 + struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); 1478 + 1479 + if (!(tids & BIT(tid)) || skb_queue_len(&txqi->queue)) 1480 + continue; 1481 + 1482 + sta_info_recalc_tim(sta); 1483 + break; 1484 + } 1525 1485 } 1526 1486 } 1527 1487
+14 -26
net/mac80211/sta_info.h
··· 16 16 #include <linux/workqueue.h> 17 17 #include <linux/average.h> 18 18 #include <linux/etherdevice.h> 19 + #include <linux/rhashtable.h> 19 20 #include "key.h" 20 21 21 22 /** ··· 249 248 * 250 249 * @list: global linked list entry 251 250 * @free_list: list entry for keeping track of stations to free 252 - * @hnext: hash table linked list pointer 251 + * @hash_node: hash node for rhashtable 253 252 * @local: pointer to the global information 254 253 * @sdata: virtual interface this station belongs to 255 254 * @ptk: peer keys negotiated with this station, if any ··· 277 276 * entered power saving state, these are also delivered to 278 277 * the station when it leaves powersave or polls for frames 279 278 * @driver_buffered_tids: bitmap of TIDs the driver has data buffered on 279 + * @txq_buffered_tids: bitmap of TIDs that mac80211 has txq data buffered on 280 280 * @rx_packets: Number of MSDUs received from this STA 281 281 * @rx_bytes: Number of bytes received from this STA 282 282 * @last_rx: time (in jiffies) when last frame was received from this STA ··· 343 341 /* General information, mostly static */ 344 342 struct list_head list, free_list; 345 343 struct rcu_head rcu_head; 346 - struct sta_info __rcu *hnext; 344 + struct rhash_head hash_node; 347 345 struct ieee80211_local *local; 348 346 struct ieee80211_sub_if_data *sdata; 349 347 struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; ··· 372 370 struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; 373 371 struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; 374 372 unsigned long driver_buffered_tids; 373 + unsigned long txq_buffered_tids; 375 374 376 375 /* Updated from RX path only, no locking requirements */ 377 376 unsigned long rx_packets; ··· 540 537 lockdep_is_held(&sta->ampdu_mlme.mtx)); 541 538 } 542 539 543 - #define STA_HASH_SIZE 256 544 - #define STA_HASH(sta) (sta[5]) 545 - 546 - 547 540 /* Maximum number of frames to buffer per power saving station per AC */ 548 541 #define STA_MAX_TX_BUFFER 64 549 542 ··· 560 561 struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, 561 562 const u8 *addr); 562 563 563 - static inline 564 - void for_each_sta_info_type_check(struct ieee80211_local *local, 565 - const u8 *addr, 566 - struct sta_info *sta, 567 - struct sta_info *nxt) 568 - { 569 - } 564 + u32 sta_addr_hash(const void *key, u32 length, u32 seed); 570 565 571 - #define for_each_sta_info(local, _addr, _sta, nxt) \ 572 - for ( /* initialise loop */ \ 573 - _sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\ 574 - nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \ 575 - /* typecheck */ \ 576 - for_each_sta_info_type_check(local, (_addr), _sta, nxt),\ 577 - /* continue condition */ \ 578 - _sta; \ 579 - /* advance loop */ \ 580 - _sta = nxt, \ 581 - nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \ 582 - ) \ 566 + #define _sta_bucket_idx(_tbl, _a) \ 567 + rht_bucket_index(_tbl, sta_addr_hash(_a, ETH_ALEN, (_tbl)->hash_rnd)) 568 + 569 + #define for_each_sta_info(local, tbl, _addr, _sta, _tmp) \ 570 + rht_for_each_entry_rcu(_sta, _tmp, tbl, \ 571 + _sta_bucket_idx(tbl, _addr), \ 572 + hash_node) \ 583 573 /* compare address and run code only if it matches */ \ 584 574 if (ether_addr_equal(_sta->sta.addr, (_addr))) 585 575 ··· 605 617 606 618 void sta_info_recalc_tim(struct sta_info *sta); 607 619 608 - void sta_info_init(struct ieee80211_local *local); 620 + int sta_info_init(struct ieee80211_local *local); 609 621 void sta_info_stop(struct ieee80211_local *local); 610 622 611 623 /**
+6 -2
net/mac80211/status.c
··· 654 654 struct ieee80211_supported_band *sband; 655 655 struct ieee80211_sub_if_data *sdata; 656 656 struct net_device *prev_dev = NULL; 657 - struct sta_info *sta, *tmp; 657 + struct sta_info *sta; 658 + struct rhash_head *tmp; 658 659 int retry_count; 659 660 int rates_idx; 660 661 bool send_to_cooked; ··· 664 663 int rtap_len; 665 664 int shift = 0; 666 665 int tid = IEEE80211_NUM_TIDS; 666 + const struct bucket_table *tbl; 667 667 668 668 rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); 669 669 ··· 673 671 sband = local->hw.wiphy->bands[info->band]; 674 672 fc = hdr->frame_control; 675 673 676 - for_each_sta_info(local, hdr->addr1, sta, tmp) { 674 + tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 675 + 676 + for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) { 677 677 /* skip wrong virtual interface */ 678 678 if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr)) 679 679 continue;
+31
net/mac80211/trace.h
··· 2312 2312 ) 2313 2313 ); 2314 2314 2315 + TRACE_EVENT(drv_wake_tx_queue, 2316 + TP_PROTO(struct ieee80211_local *local, 2317 + struct ieee80211_sub_if_data *sdata, 2318 + struct txq_info *txq), 2319 + 2320 + TP_ARGS(local, sdata, txq), 2321 + 2322 + TP_STRUCT__entry( 2323 + LOCAL_ENTRY 2324 + VIF_ENTRY 2325 + STA_ENTRY 2326 + __field(u8, ac) 2327 + __field(u8, tid) 2328 + ), 2329 + 2330 + TP_fast_assign( 2331 + struct ieee80211_sta *sta = txq->txq.sta; 2332 + 2333 + LOCAL_ASSIGN; 2334 + VIF_ASSIGN; 2335 + STA_ASSIGN; 2336 + __entry->ac = txq->txq.ac; 2337 + __entry->tid = txq->txq.tid; 2338 + ), 2339 + 2340 + TP_printk( 2341 + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ac:%d tid:%d", 2342 + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ac, __entry->tid 2343 + ) 2344 + ); 2345 + 2315 2346 #ifdef CONFIG_MAC80211_MESSAGE_TRACING 2316 2347 #undef TRACE_SYSTEM 2317 2348 #define TRACE_SYSTEM mac80211_msg
+105 -10
net/mac80211/tx.c
··· 767 767 return TX_CONTINUE; 768 768 } 769 769 770 + static __le16 ieee80211_tx_next_seq(struct sta_info *sta, int tid) 771 + { 772 + u16 *seq = &sta->tid_seq[tid]; 773 + __le16 ret = cpu_to_le16(*seq); 774 + 775 + /* Increase the sequence number. */ 776 + *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ; 777 + 778 + return ret; 779 + } 780 + 770 781 static ieee80211_tx_result debug_noinline 771 782 ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) 772 783 { 773 784 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); 774 785 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; 775 - u16 *seq; 776 786 u8 *qc; 777 787 int tid; 778 788 ··· 833 823 834 824 qc = ieee80211_get_qos_ctl(hdr); 835 825 tid = *qc & IEEE80211_QOS_CTL_TID_MASK; 836 - seq = &tx->sta->tid_seq[tid]; 837 826 tx->sta->tx_msdu[tid]++; 838 827 839 - hdr->seq_ctrl = cpu_to_le16(*seq); 840 - 841 - /* Increase the sequence number. */ 842 - *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ; 828 + if (!tx->sta->sta.txq[0]) 829 + hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); 843 830 844 831 return TX_CONTINUE; 845 832 } ··· 1077 1070 * nothing -- this aggregation session is being started 1078 1071 * but that might still fail with the driver 1079 1072 */ 1080 - } else { 1073 + } else if (!tx->sta->sta.txq[tid]) { 1081 1074 spin_lock(&tx->sta->lock); 1082 1075 /* 1083 1076 * Need to re-check now, because we may get here ··· 1218 1211 return TX_CONTINUE; 1219 1212 } 1220 1213 1214 + static void ieee80211_drv_tx(struct ieee80211_local *local, 1215 + struct ieee80211_vif *vif, 1216 + struct ieee80211_sta *pubsta, 1217 + struct sk_buff *skb) 1218 + { 1219 + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1220 + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1221 + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1222 + struct ieee80211_tx_control control = { 1223 + .sta = pubsta, 1224 + }; 1225 + struct ieee80211_txq *txq = NULL; 1226 + struct txq_info *txqi; 1227 + u8 ac; 1228 + 1229 + if (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE) 1230 + goto tx_normal; 1231 + 1232 + if (!ieee80211_is_data(hdr->frame_control)) 1233 + goto tx_normal; 1234 + 1235 + if (pubsta) { 1236 + u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; 1237 + 1238 + txq = pubsta->txq[tid]; 1239 + } else if (vif) { 1240 + txq = vif->txq; 1241 + } 1242 + 1243 + if (!txq) 1244 + goto tx_normal; 1245 + 1246 + ac = txq->ac; 1247 + txqi = to_txq_info(txq); 1248 + atomic_inc(&sdata->txqs_len[ac]); 1249 + if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending) 1250 + netif_stop_subqueue(sdata->dev, ac); 1251 + 1252 + skb_queue_tail(&txqi->queue, skb); 1253 + drv_wake_tx_queue(local, txqi); 1254 + 1255 + return; 1256 + 1257 + tx_normal: 1258 + drv_tx(local, &control, skb); 1259 + } 1260 + 1261 + struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, 1262 + struct ieee80211_txq *txq) 1263 + { 1264 + struct ieee80211_local *local = hw_to_local(hw); 1265 + struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif); 1266 + struct txq_info *txqi = container_of(txq, struct txq_info, txq); 1267 + struct ieee80211_hdr *hdr; 1268 + struct sk_buff *skb = NULL; 1269 + u8 ac = txq->ac; 1270 + 1271 + spin_lock_bh(&txqi->queue.lock); 1272 + 1273 + if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) 1274 + goto out; 1275 + 1276 + skb = __skb_dequeue(&txqi->queue); 1277 + if (!skb) 1278 + goto out; 1279 + 1280 + atomic_dec(&sdata->txqs_len[ac]); 1281 + if (__netif_subqueue_stopped(sdata->dev, ac)) 1282 + ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]); 1283 + 1284 + hdr = (struct ieee80211_hdr *)skb->data; 1285 + if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) { 1286 + struct sta_info *sta = container_of(txq->sta, struct sta_info, 1287 + sta); 1288 + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 1289 + 1290 + hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid); 1291 + if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags)) 1292 + info->flags |= IEEE80211_TX_CTL_AMPDU; 1293 + else 1294 + info->flags &= ~IEEE80211_TX_CTL_AMPDU; 1295 + } 1296 + 1297 + out: 1298 + spin_unlock_bh(&txqi->queue.lock); 1299 + 1300 + return skb; 1301 + } 1302 + EXPORT_SYMBOL(ieee80211_tx_dequeue); 1303 + 1221 1304 static bool ieee80211_tx_frags(struct ieee80211_local *local, 1222 1305 struct ieee80211_vif *vif, 1223 1306 struct ieee80211_sta *sta, 1224 1307 struct sk_buff_head *skbs, 1225 1308 bool txpending) 1226 1309 { 1227 - struct ieee80211_tx_control control; 1228 1310 struct sk_buff *skb, *tmp; 1229 1311 unsigned long flags; 1230 1312 ··· 1371 1275 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 1372 1276 1373 1277 info->control.vif = vif; 1374 - control.sta = sta; 1375 1278 1376 1279 __skb_unlink(skb, skbs); 1377 - drv_tx(local, &control, skb); 1280 + ieee80211_drv_tx(local, vif, sta, skb); 1378 1281 } 1379 1282 1380 1283 return true;
+22 -40
net/mac80211/util.c
··· 308 308 for (ac = 0; ac < n_acs; ac++) { 309 309 int ac_queue = sdata->vif.hw_queue[ac]; 310 310 311 + if (local->ops->wake_tx_queue && 312 + (atomic_read(&sdata->txqs_len[ac]) > 313 + local->hw.txq_ac_max_pending)) 314 + continue; 315 + 311 316 if (ac_queue == queue || 312 317 (sdata->vif.cab_queue == queue && 313 318 local->queue_stop_reasons[ac_queue] == 0 && ··· 2194 2189 mutex_unlock(&local->chanctx_mtx); 2195 2190 } 2196 2191 2197 - static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 2198 - { 2199 - int i; 2200 - 2201 - for (i = 0; i < n_ids; i++) 2202 - if (ids[i] == id) 2203 - return true; 2204 - return false; 2205 - } 2206 - 2207 - size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, 2208 - const u8 *ids, int n_ids, 2209 - const u8 *after_ric, int n_after_ric, 2210 - size_t offset) 2211 - { 2212 - size_t pos = offset; 2213 - 2214 - while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) { 2215 - if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { 2216 - pos += 2 + ies[pos + 1]; 2217 - 2218 - while (pos < ielen && 2219 - !ieee80211_id_in_list(after_ric, n_after_ric, 2220 - ies[pos])) 2221 - pos += 2 + ies[pos + 1]; 2222 - } else { 2223 - pos += 2 + ies[pos + 1]; 2224 - } 2225 - } 2226 - 2227 - return pos; 2228 - } 2229 - 2230 - size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 2231 - const u8 *ids, int n_ids, size_t offset) 2232 - { 2233 - return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset); 2234 - } 2235 - EXPORT_SYMBOL(ieee80211_ie_split); 2236 - 2237 2192 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) 2238 2193 { 2239 2194 size_t pos = offset; ··· 3316 3351 *buf++ = qosinfo; /* U-APSD no in use */ 3317 3352 3318 3353 return buf; 3354 + } 3355 + 3356 + void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata, 3357 + struct sta_info *sta, 3358 + struct txq_info *txqi, int tid) 3359 + { 3360 + skb_queue_head_init(&txqi->queue); 3361 + txqi->txq.vif = &sdata->vif; 3362 + 3363 + if (sta) { 3364 + txqi->txq.sta = &sta->sta; 3365 + sta->sta.txq[tid] = &txqi->txq; 3366 + txqi->txq.ac = ieee802_1d_to_ac[tid & 7]; 3367 + } else { 3368 + sdata->vif.txq = &txqi->txq; 3369 + txqi->txq.ac = IEEE80211_AC_BE; 3370 + } 3319 3371 }
+1 -1
net/wireless/Kconfig
··· 175 175 Most distributions have a CRDA package. So if unsure, say N. 176 176 177 177 config CFG80211_WEXT 178 - bool "cfg80211 wireless extensions compatibility" 178 + bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT 179 179 depends on CFG80211 180 180 select WEXT_CORE 181 181 default y if CFG80211_WEXT_EXPORT
+1 -1
net/wireless/nl80211.c
··· 5664 5664 } 5665 5665 } 5666 5666 5667 - r = set_regdom(rd); 5667 + r = set_regdom(rd, REGD_SOURCE_CRDA); 5668 5668 /* set_regdom took ownership */ 5669 5669 rd = NULL; 5670 5670
+29 -5
net/wireless/reg.c
··· 135 135 /* Used to track the userspace process controlling the indoor setting */ 136 136 static u32 reg_is_indoor_portid; 137 137 138 + /* Max number of consecutive attempts to communicate with CRDA */ 139 + #define REG_MAX_CRDA_TIMEOUTS 10 140 + 141 + static u32 reg_crda_timeouts; 142 + 138 143 static const struct ieee80211_regdomain *get_cfg80211_regdom(void) 139 144 { 140 145 return rtnl_dereference(cfg80211_regdomain); ··· 490 485 mutex_unlock(&reg_regdb_search_mutex); 491 486 492 487 if (!IS_ERR_OR_NULL(regdom)) 493 - set_regdom(regdom); 488 + set_regdom(regdom, REGD_SOURCE_INTERNAL_DB); 494 489 495 490 rtnl_unlock(); 496 491 } ··· 540 535 snprintf(country, sizeof(country), "COUNTRY=%c%c", 541 536 alpha2[0], alpha2[1]); 542 537 538 + /* query internal regulatory database (if it exists) */ 539 + reg_regdb_query(alpha2); 540 + 541 + if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) { 542 + pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n"); 543 + return -EINVAL; 544 + } 545 + 543 546 if (!is_world_regdom((char *) alpha2)) 544 547 pr_info("Calling CRDA for country: %c%c\n", 545 548 alpha2[0], alpha2[1]); 546 549 else 547 550 pr_info("Calling CRDA to update world regulatory domain\n"); 548 - 549 - /* query internal regulatory database (if it exists) */ 550 - reg_regdb_query(alpha2); 551 551 552 552 return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env); 553 553 } ··· 2303 2293 request->initiator = NL80211_REGDOM_SET_BY_USER; 2304 2294 request->user_reg_hint_type = user_reg_hint_type; 2305 2295 2296 + /* Allow calling CRDA again */ 2297 + reg_crda_timeouts = 0; 2298 + 2306 2299 queue_regulatory_request(request); 2307 2300 2308 2301 return 0; ··· 2375 2362 request->alpha2[1] = alpha2[1]; 2376 2363 request->initiator = NL80211_REGDOM_SET_BY_DRIVER; 2377 2364 2365 + /* Allow calling CRDA again */ 2366 + reg_crda_timeouts = 0; 2367 + 2378 2368 queue_regulatory_request(request); 2379 2369 2380 2370 return 0; ··· 2430 2414 request->alpha2[1] = alpha2[1]; 2431 2415 request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE; 2432 2416 request->country_ie_env = env; 2417 + 2418 + /* Allow calling CRDA again */ 2419 + reg_crda_timeouts = 0; 2433 2420 2434 2421 queue_regulatory_request(request); 2435 2422 request = NULL; ··· 2912 2893 * multiple drivers can be ironed out later. Caller must've already 2913 2894 * kmalloc'd the rd structure. 2914 2895 */ 2915 - int set_regdom(const struct ieee80211_regdomain *rd) 2896 + int set_regdom(const struct ieee80211_regdomain *rd, 2897 + enum ieee80211_regd_source regd_src) 2916 2898 { 2917 2899 struct regulatory_request *lr; 2918 2900 bool user_reset = false; ··· 2923 2903 kfree(rd); 2924 2904 return -EINVAL; 2925 2905 } 2906 + 2907 + if (regd_src == REGD_SOURCE_CRDA) 2908 + reg_crda_timeouts = 0; 2926 2909 2927 2910 lr = get_last_request(); 2928 2911 ··· 3086 3063 { 3087 3064 REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n"); 3088 3065 rtnl_lock(); 3066 + reg_crda_timeouts++; 3089 3067 restore_regulatory_settings(true); 3090 3068 rtnl_unlock(); 3091 3069 }
+8 -1
net/wireless/reg.h
··· 16 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 17 */ 18 18 19 + enum ieee80211_regd_source { 20 + REGD_SOURCE_INTERNAL_DB, 21 + REGD_SOURCE_CRDA, 22 + }; 23 + 19 24 extern const struct ieee80211_regdomain __rcu *cfg80211_regdomain; 20 25 21 26 bool reg_is_valid_request(const char *alpha2); ··· 51 46 int __init regulatory_init(void); 52 47 void regulatory_exit(void); 53 48 54 - int set_regdom(const struct ieee80211_regdomain *rd); 49 + int set_regdom(const struct ieee80211_regdomain *rd, 50 + enum ieee80211_regd_source regd_src); 51 + 55 52 unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd, 56 53 const struct ieee80211_reg_rule *rule); 57 54
+64 -10
net/wireless/sme.c
··· 42 42 CFG80211_CONN_CONNECTED, 43 43 } state; 44 44 u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; 45 - u8 *ie; 45 + const u8 *ie; 46 46 size_t ie_len; 47 47 bool auto_auth, prev_bssid_valid; 48 48 }; ··· 423 423 schedule_work(&rdev->conn_work); 424 424 } 425 425 426 + static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev, 427 + const u8 *ies, size_t ies_len, 428 + const u8 **out_ies, size_t *out_ies_len) 429 + { 430 + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 431 + u8 *buf; 432 + size_t offs; 433 + 434 + if (!rdev->wiphy.extended_capabilities_len || 435 + (ies && cfg80211_find_ie(WLAN_EID_EXT_CAPABILITY, ies, ies_len))) { 436 + *out_ies = kmemdup(ies, ies_len, GFP_KERNEL); 437 + if (!*out_ies) 438 + return -ENOMEM; 439 + *out_ies_len = ies_len; 440 + return 0; 441 + } 442 + 443 + buf = kmalloc(ies_len + rdev->wiphy.extended_capabilities_len + 2, 444 + GFP_KERNEL); 445 + if (!buf) 446 + return -ENOMEM; 447 + 448 + if (ies_len) { 449 + static const u8 before_extcapa[] = { 450 + /* not listing IEs expected to be created by driver */ 451 + WLAN_EID_RSN, 452 + WLAN_EID_QOS_CAPA, 453 + WLAN_EID_RRM_ENABLED_CAPABILITIES, 454 + WLAN_EID_MOBILITY_DOMAIN, 455 + WLAN_EID_SUPPORTED_REGULATORY_CLASSES, 456 + WLAN_EID_BSS_COEX_2040, 457 + }; 458 + 459 + offs = ieee80211_ie_split(ies, ies_len, before_extcapa, 460 + ARRAY_SIZE(before_extcapa), 0); 461 + memcpy(buf, ies, offs); 462 + /* leave a whole for extended capabilities IE */ 463 + memcpy(buf + offs + rdev->wiphy.extended_capabilities_len + 2, 464 + ies + offs, ies_len - offs); 465 + } else { 466 + offs = 0; 467 + } 468 + 469 + /* place extended capabilities IE (with only driver capabilities) */ 470 + buf[offs] = WLAN_EID_EXT_CAPABILITY; 471 + buf[offs + 1] = rdev->wiphy.extended_capabilities_len; 472 + memcpy(buf + offs + 2, 473 + rdev->wiphy.extended_capabilities, 474 + rdev->wiphy.extended_capabilities_len); 475 + 476 + *out_ies = buf; 477 + *out_ies_len = ies_len + rdev->wiphy.extended_capabilities_len + 2; 478 + 479 + return 0; 480 + } 481 + 426 482 static int cfg80211_sme_connect(struct wireless_dev *wdev, 427 483 struct cfg80211_connect_params *connect, 428 484 const u8 *prev_bssid) ··· 509 453 memcpy(wdev->conn->bssid, connect->bssid, ETH_ALEN); 510 454 } 511 455 512 - if (connect->ie) { 513 - wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, 514 - GFP_KERNEL); 515 - wdev->conn->params.ie = wdev->conn->ie; 516 - if (!wdev->conn->ie) { 517 - kfree(wdev->conn); 518 - wdev->conn = NULL; 519 - return -ENOMEM; 520 - } 456 + if (cfg80211_sme_get_conn_ies(wdev, connect->ie, connect->ie_len, 457 + &wdev->conn->ie, 458 + &wdev->conn->params.ie_len)) { 459 + kfree(wdev->conn); 460 + wdev->conn = NULL; 461 + return -ENOMEM; 521 462 } 463 + wdev->conn->params.ie = wdev->conn->ie; 522 464 523 465 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { 524 466 wdev->conn->auto_auth = true;
+41
net/wireless/util.c
··· 1290 1290 } 1291 1291 EXPORT_SYMBOL(cfg80211_get_p2p_attr); 1292 1292 1293 + static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) 1294 + { 1295 + int i; 1296 + 1297 + for (i = 0; i < n_ids; i++) 1298 + if (ids[i] == id) 1299 + return true; 1300 + return false; 1301 + } 1302 + 1303 + size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen, 1304 + const u8 *ids, int n_ids, 1305 + const u8 *after_ric, int n_after_ric, 1306 + size_t offset) 1307 + { 1308 + size_t pos = offset; 1309 + 1310 + while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) { 1311 + if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) { 1312 + pos += 2 + ies[pos + 1]; 1313 + 1314 + while (pos < ielen && 1315 + !ieee80211_id_in_list(after_ric, n_after_ric, 1316 + ies[pos])) 1317 + pos += 2 + ies[pos + 1]; 1318 + } else { 1319 + pos += 2 + ies[pos + 1]; 1320 + } 1321 + } 1322 + 1323 + return pos; 1324 + } 1325 + EXPORT_SYMBOL(ieee80211_ie_split_ric); 1326 + 1327 + size_t ieee80211_ie_split(const u8 *ies, size_t ielen, 1328 + const u8 *ids, int n_ids, size_t offset) 1329 + { 1330 + return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset); 1331 + } 1332 + EXPORT_SYMBOL(ieee80211_ie_split); 1333 + 1293 1334 bool ieee80211_operating_class_to_band(u8 operating_class, 1294 1335 enum ieee80211_band *band) 1295 1336 {