Commit 420e7fabd9c6d907280ed6b3e40eef425c5d8d8d

Authored by Henning Rogge
Committed by John W. Linville
1 parent 221b3d60cb

nl80211: Add signal strength and bandwith to nl80211station info

This patch adds signal strength and transmission bitrate
to the station_info of nl80211.

Signed-off-by: Henning Rogge <rogge@fgan.de>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

Showing 4 changed files with 152 additions and 2 deletions Side-by-side Diff

include/linux/nl80211.h
... ... @@ -425,6 +425,32 @@
425 425 };
426 426  
427 427 /**
  428 + * enum nl80211_rate_info - bitrate information
  429 + *
  430 + * These attribute types are used with %NL80211_STA_INFO_TXRATE
  431 + * when getting information about the bitrate of a station.
  432 + *
  433 + * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
  434 + * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
  435 + * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
  436 + * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
  437 + * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
  438 + * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
  439 + * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  440 + */
  441 +enum nl80211_rate_info {
  442 + __NL80211_RATE_INFO_INVALID,
  443 + NL80211_RATE_INFO_BITRATE,
  444 + NL80211_RATE_INFO_MCS,
  445 + NL80211_RATE_INFO_40_MHZ_WIDTH,
  446 + NL80211_RATE_INFO_SHORT_GI,
  447 +
  448 + /* keep last */
  449 + __NL80211_RATE_INFO_AFTER_LAST,
  450 + NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
  451 +};
  452 +
  453 +/**
428 454 * enum nl80211_sta_info - station information
429 455 *
430 456 * These attribute types are used with %NL80211_ATTR_STA_INFO
... ... @@ -436,6 +462,9 @@
436 462 * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
437 463 * @__NL80211_STA_INFO_AFTER_LAST: internal
438 464 * @NL80211_STA_INFO_MAX: highest possible station info attribute
  465 + * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  466 + * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  467 + * containing info as possible, see &enum nl80211_sta_info_txrate.
439 468 */
440 469 enum nl80211_sta_info {
441 470 __NL80211_STA_INFO_INVALID,
... ... @@ -445,6 +474,8 @@
445 474 NL80211_STA_INFO_LLID,
446 475 NL80211_STA_INFO_PLID,
447 476 NL80211_STA_INFO_PLINK_STATE,
  477 + NL80211_STA_INFO_SIGNAL,
  478 + NL80211_STA_INFO_TX_BITRATE,
448 479  
449 480 /* keep last */
450 481 __NL80211_STA_INFO_AFTER_LAST,
include/net/cfg80211.h
... ... @@ -169,6 +169,9 @@
169 169 * @STATION_INFO_LLID: @llid filled
170 170 * @STATION_INFO_PLID: @plid filled
171 171 * @STATION_INFO_PLINK_STATE: @plink_state filled
  172 + * @STATION_INFO_SIGNAL: @signal filled
  173 + * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
  174 + * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
172 175 */
173 176 enum station_info_flags {
174 177 STATION_INFO_INACTIVE_TIME = 1<<0,
175 178  
... ... @@ -177,9 +180,42 @@
177 180 STATION_INFO_LLID = 1<<3,
178 181 STATION_INFO_PLID = 1<<4,
179 182 STATION_INFO_PLINK_STATE = 1<<5,
  183 + STATION_INFO_SIGNAL = 1<<6,
  184 + STATION_INFO_TX_BITRATE = 1<<7,
180 185 };
181 186  
182 187 /**
  188 + * enum station_info_rate_flags - bitrate info flags
  189 + *
  190 + * Used by the driver to indicate the specific rate transmission
  191 + * type for 802.11n transmissions.
  192 + *
  193 + * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
  194 + * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
  195 + * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
  196 + */
  197 +enum rate_info_flags {
  198 + RATE_INFO_FLAGS_MCS = 1<<0,
  199 + RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1,
  200 + RATE_INFO_FLAGS_SHORT_GI = 1<<2,
  201 +};
  202 +
  203 +/**
  204 + * struct rate_info - bitrate information
  205 + *
  206 + * Information about a receiving or transmitting bitrate
  207 + *
  208 + * @flags: bitflag of flags from &enum rate_info_flags
  209 + * @mcs: mcs index if struct describes a 802.11n bitrate
  210 + * @legacy: bitrate in 100kbit/s for 802.11abg
  211 + */
  212 +struct rate_info {
  213 + u8 flags;
  214 + u8 mcs;
  215 + u16 legacy;
  216 +};
  217 +
  218 +/**
183 219 * struct station_info - station information
184 220 *
185 221 * Station information filled by driver for get_station() and dump_station.
... ... @@ -191,6 +227,8 @@
191 227 * @llid: mesh local link id
192 228 * @plid: mesh peer link id
193 229 * @plink_state: mesh peer link state
  230 + * @signal: signal strength of last received packet in dBm
  231 + * @txrate: current unicast bitrate to this station
194 232 */
195 233 struct station_info {
196 234 u32 filled;
... ... @@ -200,6 +238,8 @@
200 238 u16 llid;
201 239 u16 plid;
202 240 u8 plink_state;
  241 + s8 signal;
  242 + struct rate_info txrate;
203 243 };
204 244  
205 245 /**
... ... @@ -310,11 +310,34 @@
310 310  
311 311 sinfo->filled = STATION_INFO_INACTIVE_TIME |
312 312 STATION_INFO_RX_BYTES |
313   - STATION_INFO_TX_BYTES;
  313 + STATION_INFO_TX_BYTES |
  314 + STATION_INFO_TX_BITRATE;
314 315  
315 316 sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
316 317 sinfo->rx_bytes = sta->rx_bytes;
317 318 sinfo->tx_bytes = sta->tx_bytes;
  319 +
  320 + if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
  321 + sinfo->filled |= STATION_INFO_SIGNAL;
  322 + sinfo->signal = (s8)sta->last_signal;
  323 + }
  324 +
  325 + sinfo->txrate.flags = 0;
  326 + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
  327 + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
  328 + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
  329 + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
  330 + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
  331 + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
  332 +
  333 + if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
  334 + struct ieee80211_supported_band *sband;
  335 + sband = sta->local->hw.wiphy->bands[
  336 + sta->local->hw.conf.channel->band];
  337 + sinfo->txrate.legacy =
  338 + sband->bitrates[sta->last_tx_rate.idx].bitrate;
  339 + } else
  340 + sinfo->txrate.mcs = sta->last_tx_rate.idx;
318 341  
319 342 if (ieee80211_vif_is_mesh(&sdata->vif)) {
320 343 #ifdef CONFIG_MAC80211_MESH
net/wireless/nl80211.c
... ... @@ -1091,12 +1091,46 @@
1091 1091 return 0;
1092 1092 }
1093 1093  
  1094 +static u16 nl80211_calculate_bitrate(struct rate_info *rate)
  1095 +{
  1096 + int modulation, streams, bitrate;
  1097 +
  1098 + if (!(rate->flags & RATE_INFO_FLAGS_MCS))
  1099 + return rate->legacy;
  1100 +
  1101 + /* the formula below does only work for MCS values smaller than 32 */
  1102 + if (rate->mcs >= 32)
  1103 + return 0;
  1104 +
  1105 + modulation = rate->mcs & 7;
  1106 + streams = (rate->mcs >> 3) + 1;
  1107 +
  1108 + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ?
  1109 + 13500000 : 6500000;
  1110 +
  1111 + if (modulation < 4)
  1112 + bitrate *= (modulation + 1);
  1113 + else if (modulation == 4)
  1114 + bitrate *= (modulation + 2);
  1115 + else
  1116 + bitrate *= (modulation + 3);
  1117 +
  1118 + bitrate *= streams;
  1119 +
  1120 + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
  1121 + bitrate = (bitrate / 9) * 10;
  1122 +
  1123 + /* do NOT round down here */
  1124 + return (bitrate + 50000) / 100000;
  1125 +}
  1126 +
1094 1127 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
1095 1128 int flags, struct net_device *dev,
1096 1129 u8 *mac_addr, struct station_info *sinfo)
1097 1130 {
1098 1131 void *hdr;
1099   - struct nlattr *sinfoattr;
  1132 + struct nlattr *sinfoattr, *txrate;
  1133 + u16 bitrate;
1100 1134  
1101 1135 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
1102 1136 if (!hdr)
1103 1137  
... ... @@ -1126,7 +1160,29 @@
1126 1160 if (sinfo->filled & STATION_INFO_PLINK_STATE)
1127 1161 NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
1128 1162 sinfo->plink_state);
  1163 + if (sinfo->filled & STATION_INFO_SIGNAL)
  1164 + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL,
  1165 + sinfo->signal);
  1166 + if (sinfo->filled & STATION_INFO_TX_BITRATE) {
  1167 + txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
  1168 + if (!txrate)
  1169 + goto nla_put_failure;
1129 1170  
  1171 + /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */
  1172 + bitrate = nl80211_calculate_bitrate(&sinfo->txrate);
  1173 + if (bitrate > 0)
  1174 + NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
  1175 +
  1176 + if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
  1177 + NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
  1178 + sinfo->txrate.mcs);
  1179 + if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
  1180 + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
  1181 + if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
  1182 + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
  1183 +
  1184 + nla_nest_end(msg, txrate);
  1185 + }
1130 1186 nla_nest_end(msg, sinfoattr);
1131 1187  
1132 1188 return genlmsg_end(msg, hdr);