On Wednesday 10 December 2008 10:05:50 Johannes Berg wrote: > Uh huh, it's a huge table, and very irregular. Not very inclined to copy > that right now. What's wrong with deferring it until somebody actually > implements these rates? Okay... I will try to implement a complete version of the function when I get access to the table... here is a modified patch with two warnings about the missing datarates. It will return 0 for mcs >= 32. Just a question, did someone with 802.11n hardware test this patches ? I hope I will have some hardware myself at the end of the year, but at the moment it's untested. Henning -------------------------- diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 56450b4..cc93e7a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -431,14 +431,14 @@ enum nl80211_sta_flags { * when getting information about the bitrate of a station. * * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved - * @NL80211_RATE_INFO_LEGACY: bitrate for 802.11abg (u16, 100kbit/s) + * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval */ enum nl80211_rate_info { __NL80211_RATE_INFO_INVALID, - NL80211_RATE_INFO_LEGACY, + NL80211_RATE_INFO_BITRATE, NL80211_RATE_INFO_MCS, NL80211_RATE_INFO_40_MHZ_WIDTH, NL80211_RATE_INFO_SHORT_GI, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3f13928..643dcc1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1079,6 +1079,39 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) return 0; } +static u16 nl80211_calculate_bitrate(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + return rate->legacy; + + /* the formula below does only work for MCS values smaller than 32 */ + if (rate->mcs >= 32) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? + 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, u8 *mac_addr, struct station_info *sinfo) @@ -1122,13 +1155,13 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (!txrate) goto nla_put_failure; - - if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)) - NLA_PUT_U16(msg, NL80211_RATE_INFO_LEGACY, - sinfo->txrate.legacy); - else + /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ + NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, + nl80211_calculate_bitrate(&sinfo->txrate)); + if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, sinfo->txrate.mcs); + if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 56450b4..cc93e7a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -431,14 +431,14 @@ enum nl80211_sta_flags { * when getting information about the bitrate of a station. * * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved - * @NL80211_RATE_INFO_LEGACY: bitrate for 802.11abg (u16, 100kbit/s) + * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval */ enum nl80211_rate_info { __NL80211_RATE_INFO_INVALID, - NL80211_RATE_INFO_LEGACY, + NL80211_RATE_INFO_BITRATE, NL80211_RATE_INFO_MCS, NL80211_RATE_INFO_40_MHZ_WIDTH, NL80211_RATE_INFO_SHORT_GI, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3f13928..643dcc1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1079,6 +1079,39 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) return 0; } +static u16 nl80211_calculate_bitrate(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + return rate->legacy; + + /* the formula below does only work for MCS values smaller than 32 */ + if (rate->mcs >= 32) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? + 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, u8 *mac_addr, struct station_info *sinfo) @@ -1122,13 +1155,13 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (!txrate) goto nla_put_failure; - - if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)) - NLA_PUT_U16(msg, NL80211_RATE_INFO_LEGACY, - sinfo->txrate.legacy); - else + /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ + NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, + nl80211_calculate_bitrate(&sinfo->txrate)); + if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, sinfo->txrate.mcs); + if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
Attachment:
signature.asc
Description: This is a digitally signed message part.