Commit 420e7fabd9c6d907280ed6b3e40eef425c5d8d8d
Committed by
John W. Linville
1 parent
221b3d60cb
Exists in
master
and in
7 other branches
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 | /** |
net/mac80211/cfg.c
... | ... | @@ -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); |