137e6d19e7a6f095bacb9e5d78835a8f8bcb4a85
[openwrt.git] / package / mac80211 / patches / 540-mac80211_add_rx_rate.patch
1 --- a/include/net/cfg80211.h
2 +++ b/include/net/cfg80211.h
3 @@ -414,7 +414,7 @@ struct station_parameters {
4   * @STATION_INFO_PLID: @plid filled
5   * @STATION_INFO_PLINK_STATE: @plink_state filled
6   * @STATION_INFO_SIGNAL: @signal filled
7 - * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
8 + * @STATION_INFO_TX_BITRATE: @txrate fields are filled
9   *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
10   * @STATION_INFO_RX_PACKETS: @rx_packets filled
11   * @STATION_INFO_TX_PACKETS: @tx_packets filled
12 @@ -422,6 +422,7 @@ struct station_parameters {
13   * @STATION_INFO_TX_FAILED: @tx_failed filled
14   * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
15   * @STATION_INFO_SIGNAL_AVG: @signal_avg filled
16 + * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
17   */
18  enum station_info_flags {
19         STATION_INFO_INACTIVE_TIME      = 1<<0,
20 @@ -438,6 +439,7 @@ enum station_info_flags {
21         STATION_INFO_TX_FAILED          = 1<<11,
22         STATION_INFO_RX_DROP_MISC       = 1<<12,
23         STATION_INFO_SIGNAL_AVG         = 1<<13,
24 +       STATION_INFO_RX_BITRATE         = 1<<14,
25  };
26  
27  /**
28 @@ -507,6 +509,7 @@ struct station_info {
29         s8 signal;
30         s8 signal_avg;
31         struct rate_info txrate;
32 +       struct rate_info rxrate;
33         u32 rx_packets;
34         u32 tx_packets;
35         u32 tx_retries;
36 --- a/include/linux/nl80211.h
37 +++ b/include/linux/nl80211.h
38 @@ -1243,6 +1243,8 @@ enum nl80211_rate_info {
39   * @NL80211_STA_INFO_LLID: the station's mesh LLID
40   * @NL80211_STA_INFO_PLID: the station's mesh PLID
41   * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
42 + * @NL80211_STA_INFO_RX_BITRATE: last unicast rx rate, nested attribute
43 + *     containing info as possible, see &enum nl80211_sta_info_txrate.
44   * @__NL80211_STA_INFO_AFTER_LAST: internal
45   * @NL80211_STA_INFO_MAX: highest possible station info attribute
46   */
47 @@ -1261,6 +1263,7 @@ enum nl80211_sta_info {
48         NL80211_STA_INFO_TX_RETRIES,
49         NL80211_STA_INFO_TX_FAILED,
50         NL80211_STA_INFO_SIGNAL_AVG,
51 +       NL80211_STA_INFO_RX_BITRATE,
52  
53         /* keep last */
54         __NL80211_STA_INFO_AFTER_LAST,
55 --- a/net/wireless/nl80211.c
56 +++ b/net/wireless/nl80211.c
57 @@ -1968,13 +1968,41 @@ static int parse_station_flags(struct ge
58         return 0;
59  }
60  
61 +static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
62 +                                int attr)
63 +{
64 +       struct nlattr *rate;
65 +       u16 bitrate;
66 +
67 +       rate = nla_nest_start(msg, attr);
68 +       if (!rate)
69 +               goto nla_put_failure;
70 +
71 +       /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
72 +       bitrate = cfg80211_calculate_bitrate(info);
73 +       if (bitrate > 0)
74 +               NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
75 +
76 +       if (info->flags & RATE_INFO_FLAGS_MCS)
77 +               NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, info->mcs);
78 +       if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
79 +               NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
80 +       if (info->flags & RATE_INFO_FLAGS_SHORT_GI)
81 +               NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
82 +
83 +       nla_nest_end(msg, rate);
84 +       return true;
85 +
86 +nla_put_failure:
87 +       return false;
88 +}
89 +
90  static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
91                                 int flags, struct net_device *dev,
92                                 const u8 *mac_addr, struct station_info *sinfo)
93  {
94         void *hdr;
95 -       struct nlattr *sinfoattr, *txrate;
96 -       u16 bitrate;
97 +       struct nlattr *sinfoattr;
98  
99         hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
100         if (!hdr)
101 @@ -2013,24 +2041,14 @@ static int nl80211_send_station(struct s
102                 NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL_AVG,
103                            sinfo->signal_avg);
104         if (sinfo->filled & STATION_INFO_TX_BITRATE) {
105 -               txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE);
106 -               if (!txrate)
107 +               if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
108 +                                         NL80211_STA_INFO_TX_BITRATE))
109 +                       goto nla_put_failure;
110 +       }
111 +       if (sinfo->filled & STATION_INFO_RX_BITRATE) {
112 +               if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
113 +                                         NL80211_STA_INFO_RX_BITRATE))
114                         goto nla_put_failure;
115 -
116 -               /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
117 -               bitrate = cfg80211_calculate_bitrate(&sinfo->txrate);
118 -               if (bitrate > 0)
119 -                       NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate);
120 -
121 -               if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS)
122 -                       NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS,
123 -                                   sinfo->txrate.mcs);
124 -               if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH)
125 -                       NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH);
126 -               if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI)
127 -                       NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI);
128 -
129 -               nla_nest_end(msg, txrate);
130         }
131         if (sinfo->filled & STATION_INFO_RX_PACKETS)
132                 NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,
133 --- a/net/mac80211/sta_info.h
134 +++ b/net/mac80211/sta_info.h
135 @@ -209,6 +209,8 @@ enum plink_state {
136   * @rate_ctrl_priv: rate control private per-STA pointer
137   * @last_tx_rate: rate used for last transmit, to report to userspace as
138   *     "the" transmit rate
139 + * @last_rx_rate_idx: rx status rate index of the last data packet
140 + * @last_rx_rate_flag: rx status flag of the last data packet
141   * @lock: used for locking all fields that require locking, see comments
142   *     in the header file.
143   * @flaglock: spinlock for flags accesses
144 @@ -311,6 +313,8 @@ struct sta_info {
145         unsigned long tx_bytes;
146         unsigned long tx_fragments;
147         struct ieee80211_tx_rate last_tx_rate;
148 +       int last_rx_rate_idx;
149 +       int last_rx_rate_flag;
150         u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
151  
152         /*
153 --- a/net/mac80211/rx.c
154 +++ b/net/mac80211/rx.c
155 @@ -1156,14 +1156,23 @@ ieee80211_rx_h_sta_process(struct ieee80
156         if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
157                 u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
158                                                 NL80211_IFTYPE_ADHOC);
159 -               if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
160 +               if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) {
161                         sta->last_rx = jiffies;
162 +                       if (ieee80211_is_data(hdr->frame_control)) {
163 +                               sta->last_rx_rate_idx = status->rate_idx;
164 +                               sta->last_rx_rate_flag = status->flag;
165 +                       }
166 +               }
167         } else if (!is_multicast_ether_addr(hdr->addr1)) {
168                 /*
169                  * Mesh beacons will update last_rx when if they are found to
170                  * match the current local configuration when processed.
171                  */
172                 sta->last_rx = jiffies;
173 +               if (ieee80211_is_data(hdr->frame_control)) {
174 +                       sta->last_rx_rate_idx = status->rate_idx;
175 +                       sta->last_rx_rate_flag = status->flag;
176 +               }
177         }
178  
179         if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
180 --- a/net/mac80211/cfg.c
181 +++ b/net/mac80211/cfg.c
182 @@ -316,6 +316,17 @@ static int ieee80211_config_default_mgmt
183         return 0;
184  }
185  
186 +static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
187 +{
188 +       if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
189 +               struct ieee80211_supported_band *sband;
190 +               sband = sta->local->hw.wiphy->bands[
191 +                               sta->local->hw.conf.channel->band];
192 +               rate->legacy = sband->bitrates[idx].bitrate;
193 +       } else
194 +               rate->mcs = idx;
195 +}
196 +
197  static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
198  {
199         struct ieee80211_sub_if_data *sdata = sta->sdata;
200 @@ -330,6 +341,7 @@ static void sta_set_sinfo(struct sta_inf
201                         STATION_INFO_TX_RETRIES |
202                         STATION_INFO_TX_FAILED |
203                         STATION_INFO_TX_BITRATE |
204 +                       STATION_INFO_RX_BITRATE |
205                         STATION_INFO_RX_DROP_MISC;
206  
207         sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
208 @@ -355,15 +367,16 @@ static void sta_set_sinfo(struct sta_inf
209                 sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
210         if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI)
211                 sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
212 +       rate_idx_to_bitrate(&sinfo->txrate, sta, sta->last_tx_rate.idx);
213  
214 -       if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) {
215 -               struct ieee80211_supported_band *sband;
216 -               sband = sta->local->hw.wiphy->bands[
217 -                               sta->local->hw.conf.channel->band];
218 -               sinfo->txrate.legacy =
219 -                       sband->bitrates[sta->last_tx_rate.idx].bitrate;
220 -       } else
221 -               sinfo->txrate.mcs = sta->last_tx_rate.idx;
222 +       sinfo->rxrate.flags = 0;
223 +       if (sta->last_rx_rate_flag & RX_FLAG_HT)
224 +               sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
225 +       if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
226 +               sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
227 +       if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
228 +               sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
229 +       rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
230  
231         if (ieee80211_vif_is_mesh(&sdata->vif)) {
232  #ifdef CONFIG_MAC80211_MESH