ethtool.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. * mac80211 ethtool hooks for cfg80211
  3. *
  4. * Copied from cfg.c - originally
  5. * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  6. * Copyright 2014 Intel Corporation (Author: Johannes Berg)
  7. *
  8. * This file is GPLv2 as found in COPYING.
  9. */
  10. #include <linux/types.h>
  11. #include <net/cfg80211.h>
  12. #include "ieee80211_i.h"
  13. #include "sta_info.h"
  14. #include "driver-ops.h"
  15. static int ieee80211_set_ringparam(struct net_device *dev,
  16. struct ethtool_ringparam *rp)
  17. {
  18. struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy);
  19. if (rp->rx_mini_pending != 0 || rp->rx_jumbo_pending != 0)
  20. return -EINVAL;
  21. return drv_set_ringparam(local, rp->tx_pending, rp->rx_pending);
  22. }
  23. static void ieee80211_get_ringparam(struct net_device *dev,
  24. struct ethtool_ringparam *rp)
  25. {
  26. struct ieee80211_local *local = wiphy_priv(dev->ieee80211_ptr->wiphy);
  27. memset(rp, 0, sizeof(*rp));
  28. drv_get_ringparam(local, &rp->tx_pending, &rp->tx_max_pending,
  29. &rp->rx_pending, &rp->rx_max_pending);
  30. }
  31. static const char ieee80211_gstrings_sta_stats[][ETH_GSTRING_LEN] = {
  32. "rx_packets", "rx_bytes",
  33. "rx_duplicates", "rx_fragments", "rx_dropped",
  34. "tx_packets", "tx_bytes",
  35. "tx_filtered", "tx_retry_failed", "tx_retries",
  36. "beacon_loss", "sta_state", "txrate", "rxrate", "signal",
  37. "channel", "noise", "ch_time", "ch_time_busy",
  38. "ch_time_ext_busy", "ch_time_rx", "ch_time_tx"
  39. };
  40. #define STA_STATS_LEN ARRAY_SIZE(ieee80211_gstrings_sta_stats)
  41. static int ieee80211_get_sset_count(struct net_device *dev, int sset)
  42. {
  43. struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  44. int rv = 0;
  45. if (sset == ETH_SS_STATS)
  46. rv += STA_STATS_LEN;
  47. rv += drv_get_et_sset_count(sdata, sset);
  48. if (rv == 0)
  49. return -EOPNOTSUPP;
  50. return rv;
  51. }
  52. static void ieee80211_get_stats(struct net_device *dev,
  53. struct ethtool_stats *stats,
  54. u64 *data)
  55. {
  56. struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  57. struct ieee80211_chanctx_conf *chanctx_conf;
  58. struct ieee80211_channel *channel;
  59. struct sta_info *sta;
  60. struct ieee80211_local *local = sdata->local;
  61. struct station_info sinfo;
  62. struct survey_info survey;
  63. int i, q;
  64. #define STA_STATS_SURVEY_LEN 7
  65. memset(data, 0, sizeof(u64) * STA_STATS_LEN);
  66. #define ADD_STA_STATS(sta) \
  67. do { \
  68. data[i++] += sta->rx_packets; \
  69. data[i++] += sta->rx_bytes; \
  70. data[i++] += sta->num_duplicates; \
  71. data[i++] += sta->rx_fragments; \
  72. data[i++] += sta->rx_dropped; \
  73. \
  74. data[i++] += sinfo.tx_packets; \
  75. data[i++] += sinfo.tx_bytes; \
  76. data[i++] += sta->tx_filtered_count; \
  77. data[i++] += sta->tx_retry_failed; \
  78. data[i++] += sta->tx_retry_count; \
  79. data[i++] += sta->beacon_loss_count; \
  80. } while (0)
  81. /* For Managed stations, find the single station based on BSSID
  82. * and use that. For interface types, iterate through all available
  83. * stations and add stats for any station that is assigned to this
  84. * network device.
  85. */
  86. mutex_lock(&local->sta_mtx);
  87. if (sdata->vif.type == NL80211_IFTYPE_STATION) {
  88. sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid);
  89. if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
  90. goto do_survey;
  91. sinfo.filled = 0;
  92. sta_set_sinfo(sta, &sinfo);
  93. i = 0;
  94. ADD_STA_STATS(sta);
  95. data[i++] = sta->sta_state;
  96. if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
  97. data[i] = 100000 *
  98. cfg80211_calculate_bitrate(&sinfo.txrate);
  99. i++;
  100. if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE))
  101. data[i] = 100000 *
  102. cfg80211_calculate_bitrate(&sinfo.rxrate);
  103. i++;
  104. if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
  105. data[i] = (u8)sinfo.signal_avg;
  106. i++;
  107. } else {
  108. list_for_each_entry(sta, &local->sta_list, list) {
  109. /* Make sure this station belongs to the proper dev */
  110. if (sta->sdata->dev != dev)
  111. continue;
  112. sinfo.filled = 0;
  113. sta_set_sinfo(sta, &sinfo);
  114. i = 0;
  115. ADD_STA_STATS(sta);
  116. }
  117. }
  118. do_survey:
  119. i = STA_STATS_LEN - STA_STATS_SURVEY_LEN;
  120. /* Get survey stats for current channel */
  121. survey.filled = 0;
  122. rcu_read_lock();
  123. chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
  124. if (chanctx_conf)
  125. channel = chanctx_conf->def.chan;
  126. else
  127. channel = NULL;
  128. rcu_read_unlock();
  129. if (channel) {
  130. q = 0;
  131. do {
  132. survey.filled = 0;
  133. if (drv_get_survey(local, q, &survey) != 0) {
  134. survey.filled = 0;
  135. break;
  136. }
  137. q++;
  138. } while (channel != survey.channel);
  139. }
  140. if (survey.filled)
  141. data[i++] = survey.channel->center_freq;
  142. else
  143. data[i++] = 0;
  144. if (survey.filled & SURVEY_INFO_NOISE_DBM)
  145. data[i++] = (u8)survey.noise;
  146. else
  147. data[i++] = -1LL;
  148. if (survey.filled & SURVEY_INFO_TIME)
  149. data[i++] = survey.time;
  150. else
  151. data[i++] = -1LL;
  152. if (survey.filled & SURVEY_INFO_TIME_BUSY)
  153. data[i++] = survey.time_busy;
  154. else
  155. data[i++] = -1LL;
  156. if (survey.filled & SURVEY_INFO_TIME_EXT_BUSY)
  157. data[i++] = survey.time_ext_busy;
  158. else
  159. data[i++] = -1LL;
  160. if (survey.filled & SURVEY_INFO_TIME_RX)
  161. data[i++] = survey.time_rx;
  162. else
  163. data[i++] = -1LL;
  164. if (survey.filled & SURVEY_INFO_TIME_TX)
  165. data[i++] = survey.time_tx;
  166. else
  167. data[i++] = -1LL;
  168. mutex_unlock(&local->sta_mtx);
  169. if (WARN_ON(i != STA_STATS_LEN))
  170. return;
  171. drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
  172. }
  173. static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
  174. {
  175. struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
  176. int sz_sta_stats = 0;
  177. if (sset == ETH_SS_STATS) {
  178. sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
  179. memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
  180. }
  181. drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
  182. }
  183. static int ieee80211_get_regs_len(struct net_device *dev)
  184. {
  185. return 0;
  186. }
  187. static void ieee80211_get_regs(struct net_device *dev,
  188. struct ethtool_regs *regs,
  189. void *data)
  190. {
  191. struct wireless_dev *wdev = dev->ieee80211_ptr;
  192. regs->version = wdev->wiphy->hw_version;
  193. regs->len = 0;
  194. }
  195. const struct ethtool_ops ieee80211_ethtool_ops = {
  196. .get_drvinfo = cfg80211_get_drvinfo,
  197. .get_regs_len = ieee80211_get_regs_len,
  198. .get_regs = ieee80211_get_regs,
  199. .get_link = ethtool_op_get_link,
  200. .get_ringparam = ieee80211_get_ringparam,
  201. .set_ringparam = ieee80211_set_ringparam,
  202. .get_strings = ieee80211_get_strings,
  203. .get_ethtool_stats = ieee80211_get_stats,
  204. .get_sset_count = ieee80211_get_sset_count,
  205. };