fix up hostapd for mac80211
[librecmc/librecmc.git] / package / mac80211 / patches / 024-nl80211-get-sta.patch
1 Subject: cfg80211/nl80211: implement station attribute retrieval
2
3 After a station is added to the kernel's structures, userspace
4 has to be able to retrieve statistics about that station, especially
5 whether the station was idle and how much bytes were transferred
6 to and from it. This adds the necessary code to nl80211.
7
8 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
9
10 ---
11  include/linux/nl80211.h |   28 ++++++++++++++++
12  include/net/cfg80211.h  |   35 ++++++++++++++++++++
13  net/wireless/nl80211.c  |   82 +++++++++++++++++++++++++++++++++++++++++++++++-
14  3 files changed, 144 insertions(+), 1 deletion(-)
15
16 --- everything.orig/include/linux/nl80211.h     2007-11-08 17:15:15.961529840 +0100
17 +++ everything/include/linux/nl80211.h  2007-11-08 17:17:00.891547364 +0100
18 @@ -157,6 +157,9 @@ enum nl80211_commands {
19   *     restriction (at most %NL80211_MAX_SUPP_RATES).
20   * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
21   *     to, or the AP interface the station was originally added to to.
22 + * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
23 + *     given for %NL80211_CMD_GET_STATION, nested attribute containing
24 + *     info as possible, see &enum nl80211_sta_stats.
25   *
26   * @NL80211_ATTR_MAX: highest attribute number currently defined
27   * @__NL80211_ATTR_AFTER_LAST: internal use
28 @@ -190,6 +193,7 @@ enum nl80211_attrs {
29         NL80211_ATTR_STA_LISTEN_INTERVAL,
30         NL80211_ATTR_STA_SUPPORTED_RATES,
31         NL80211_ATTR_STA_VLAN,
32 +       NL80211_ATTR_STA_STATS,
33  
34         /* add attributes here, update the policy in nl80211.c */
35  
36 @@ -252,4 +256,28 @@ enum nl80211_sta_flags {
37         NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
38  };
39  
40 +/**
41 + * enum nl80211_sta_stats - station statistics
42 + *
43 + * These attribute types are used with %NL80211_ATTR_STA_STATS
44 + * when getting information about a station.
45 + *
46 + * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
47 + * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
48 + * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
49 + * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
50 + * @__NL80211_STA_STAT_AFTER_LAST: internal
51 + * @NL80211_STA_STAT_MAX: highest possible station stats attribute
52 + */
53 +enum nl80211_sta_stats {
54 +       __NL80211_STA_STAT_INVALID,
55 +       NL80211_STA_STAT_INACTIVE_TIME,
56 +       NL80211_STA_STAT_RX_BYTES,
57 +       NL80211_STA_STAT_TX_BYTES,
58 +
59 +       /* keep last */
60 +       __NL80211_STA_STAT_AFTER_LAST,
61 +       NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
62 +};
63 +
64  #endif /* __LINUX_NL80211_H */
65 --- everything.orig/include/net/cfg80211.h      2007-11-08 17:15:15.971532444 +0100
66 +++ everything/include/net/cfg80211.h   2007-11-08 17:17:00.891547364 +0100
67 @@ -130,6 +130,39 @@ struct station_parameters {
68         u8 supported_rates_len;
69  };
70  
71 +/**
72 + * enum station_stats_flags - station statistics flags
73 + *
74 + * Used by the driver to indicate which info in &struct station_stats
75 + * it has filled in during get_station().
76 + *
77 + * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
78 + * @STATION_STAT_RX_BYTES: @rx_bytes filled
79 + * @STATION_STAT_TX_BYTES: @tx_bytes filled
80 + */
81 +enum station_stats_flags {
82 +       STATION_STAT_INACTIVE_TIME      = 1<<0,
83 +       STATION_STAT_RX_BYTES           = 1<<1,
84 +       STATION_STAT_TX_BYTES           = 1<<2,
85 +};
86 +
87 +/**
88 + * struct station_stats - station statistics
89 + *
90 + * Station information filled by driver for get_station().
91 + *
92 + * @filled: bitflag of flags from &enum station_stats_flags
93 + * @inactive_time: time since last station activity (tx/rx) in milliseconds
94 + * @rx_bytes: bytes received from this station
95 + * @tx_bytes: bytes transmitted to this station
96 + */
97 +struct station_stats {
98 +       u32 filled;
99 +       u32 inactive_time;
100 +       u32 rx_bytes;
101 +       u32 tx_bytes;
102 +};
103 +
104  /* from net/wireless.h */
105  struct wiphy;
106  
107 @@ -209,6 +242,8 @@ struct cfg80211_ops {
108                                u8 *mac);
109         int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
110                                   u8 *mac, struct station_parameters *params);
111 +       int     (*get_station)(struct wiphy *wiphy, struct net_device *dev,
112 +                              u8 *mac, struct station_stats *stats);
113  };
114  
115  #endif /* __NET_CFG80211_H */
116 --- everything.orig/net/wireless/nl80211.c      2007-11-08 17:15:15.981533909 +0100
117 +++ everything/net/wireless/nl80211.c   2007-11-08 17:17:00.901534235 +0100
118 @@ -751,9 +751,89 @@ static int parse_station_flags(struct nl
119         return 0;
120  }
121  
122 +static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
123 +                               int flags, struct net_device *dev,
124 +                               u8 *mac_addr, struct station_stats *stats)
125 +{
126 +       void *hdr;
127 +       struct nlattr *statsattr;
128 +
129 +       hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
130 +       if (!hdr)
131 +               return -1;
132 +
133 +       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
134 +       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
135 +
136 +       statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
137 +       if (!statsattr)
138 +               goto nla_put_failure;
139 +       if (stats->filled & STATION_STAT_INACTIVE_TIME)
140 +               NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
141 +                           stats->inactive_time);
142 +       if (stats->filled & STATION_STAT_RX_BYTES)
143 +               NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
144 +                           stats->rx_bytes);
145 +       if (stats->filled & STATION_STAT_TX_BYTES)
146 +               NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
147 +                           stats->tx_bytes);
148 +
149 +       nla_nest_end(msg, statsattr);
150 +
151 +       return genlmsg_end(msg, hdr);
152 +
153 + nla_put_failure:
154 +       return genlmsg_cancel(msg, hdr);
155 +}
156 +
157 +
158  static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
159  {
160 -       return -EOPNOTSUPP;
161 +       struct cfg80211_registered_device *drv;
162 +       int err;
163 +       struct net_device *dev;
164 +       struct station_stats stats;
165 +       struct sk_buff *msg;
166 +       u8 *mac_addr = NULL;
167 +
168 +       memset(&stats, 0, sizeof(stats));
169 +
170 +       if (!info->attrs[NL80211_ATTR_MAC])
171 +               return -EINVAL;
172 +
173 +       mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
174 +
175 +       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
176 +       if (err)
177 +               return err;
178 +
179 +       if (!drv->ops->get_station) {
180 +               err = -EOPNOTSUPP;
181 +               goto out;
182 +       }
183 +
184 +       rtnl_lock();
185 +       err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
186 +       rtnl_unlock();
187 +
188 +       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
189 +       if (!msg)
190 +               goto out;
191 +
192 +       if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
193 +                                dev, mac_addr, &stats) < 0)
194 +               goto out_free;
195 +
196 +       err = genlmsg_unicast(msg, info->snd_pid);
197 +       goto out;
198 +
199 + out_free:
200 +       nlmsg_free(msg);
201 +
202 + out:
203 +       cfg80211_put_dev(drv);
204 +       dev_put(dev);
205 +       return err;
206  }
207  
208  /*