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

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>

authored by

Henning Rogge and committed by
John W. Linville
420e7fab 221b3d60

+152 -2
+31
include/linux/nl80211.h
··· 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 ··· 462 436 * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) 463 437 * @__NL80211_STA_INFO_AFTER_LAST: internal 464 438 * @NL80211_STA_INFO_MAX: highest possible station info attribute 439 + * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) 440 + * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute 441 + * containing info as possible, see &enum nl80211_sta_info_txrate. 465 442 */ 466 443 enum nl80211_sta_info { 467 444 __NL80211_STA_INFO_INVALID, ··· 474 445 NL80211_STA_INFO_LLID, 475 446 NL80211_STA_INFO_PLID, 476 447 NL80211_STA_INFO_PLINK_STATE, 448 + NL80211_STA_INFO_SIGNAL, 449 + NL80211_STA_INFO_TX_BITRATE, 477 450 478 451 /* keep last */ 479 452 __NL80211_STA_INFO_AFTER_LAST,
+40
include/net/cfg80211.h
··· 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, ··· 180 177 STATION_INFO_LLID = 1<<3, 181 178 STATION_INFO_PLID = 1<<4, 182 179 STATION_INFO_PLINK_STATE = 1<<5, 180 + STATION_INFO_SIGNAL = 1<<6, 181 + STATION_INFO_TX_BITRATE = 1<<7, 182 + }; 183 + 184 + /** 185 + * enum station_info_rate_flags - bitrate info flags 186 + * 187 + * Used by the driver to indicate the specific rate transmission 188 + * type for 802.11n transmissions. 189 + * 190 + * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled 191 + * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission 192 + * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval 193 + */ 194 + enum rate_info_flags { 195 + RATE_INFO_FLAGS_MCS = 1<<0, 196 + RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, 197 + RATE_INFO_FLAGS_SHORT_GI = 1<<2, 198 + }; 199 + 200 + /** 201 + * struct rate_info - bitrate information 202 + * 203 + * Information about a receiving or transmitting bitrate 204 + * 205 + * @flags: bitflag of flags from &enum rate_info_flags 206 + * @mcs: mcs index if struct describes a 802.11n bitrate 207 + * @legacy: bitrate in 100kbit/s for 802.11abg 208 + */ 209 + struct rate_info { 210 + u8 flags; 211 + u8 mcs; 212 + u16 legacy; 183 213 }; 184 214 185 215 /** ··· 227 191 * @llid: mesh local link id 228 192 * @plid: mesh peer link id 229 193 * @plink_state: mesh peer link state 194 + * @signal: signal strength of last received packet in dBm 195 + * @txrate: current unicast bitrate to this station 230 196 */ 231 197 struct station_info { 232 198 u32 filled; ··· 238 200 u16 llid; 239 201 u16 plid; 240 202 u8 plink_state; 203 + s8 signal; 204 + struct rate_info txrate; 241 205 }; 242 206 243 207 /**
+24 -1
net/mac80211/cfg.c
··· 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
+57 -1
net/wireless/nl80211.c
··· 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) ··· 1160 1126 if (sinfo->filled & STATION_INFO_PLINK_STATE) 1161 1127 NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, 1162 1128 sinfo->plink_state); 1129 + if (sinfo->filled & STATION_INFO_SIGNAL) 1130 + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, 1131 + sinfo->signal); 1132 + if (sinfo->filled & STATION_INFO_TX_BITRATE) { 1133 + txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); 1134 + if (!txrate) 1135 + goto nla_put_failure; 1163 1136 1137 + /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ 1138 + bitrate = nl80211_calculate_bitrate(&sinfo->txrate); 1139 + if (bitrate > 0) 1140 + NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); 1141 + 1142 + if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) 1143 + NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, 1144 + sinfo->txrate.mcs); 1145 + if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) 1146 + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); 1147 + if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) 1148 + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); 1149 + 1150 + nla_nest_end(msg, txrate); 1151 + } 1164 1152 nla_nest_end(msg, sinfoattr); 1165 1153 1166 1154 return genlmsg_end(msg, hdr);