aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-12-18 20:03:36 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:59:52 -0500
commitfd5b74dcb88cfc109d6576b22deaef6f47f82c12 (patch)
treeeebd528e684a4a127d906257b4727a6d134c85ef
parent5727ef1b2e797a1922f5bc239b6afb2b4cfb80bc (diff)
cfg80211/nl80211: implement station attribute retrieval
After a station is added to the kernel's structures, userspace has to be able to retrieve statistics about that station, especially whether the station was idle and how much bytes were transferred to and from it. This adds the necessary code to nl80211. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/nl80211.h28
-rw-r--r--include/net/cfg80211.h35
-rw-r--r--net/wireless/nl80211.c82
3 files changed, 144 insertions, 1 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 85e2d7d1f9e3..9fecf902419c 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -157,6 +157,9 @@ enum nl80211_commands {
157 * restriction (at most %NL80211_MAX_SUPP_RATES). 157 * restriction (at most %NL80211_MAX_SUPP_RATES).
158 * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station 158 * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
159 * to, or the AP interface the station was originally added to to. 159 * to, or the AP interface the station was originally added to to.
160 * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
161 * given for %NL80211_CMD_GET_STATION, nested attribute containing
162 * info as possible, see &enum nl80211_sta_stats.
160 * 163 *
161 * @NL80211_ATTR_MAX: highest attribute number currently defined 164 * @NL80211_ATTR_MAX: highest attribute number currently defined
162 * @__NL80211_ATTR_AFTER_LAST: internal use 165 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -190,6 +193,7 @@ enum nl80211_attrs {
190 NL80211_ATTR_STA_LISTEN_INTERVAL, 193 NL80211_ATTR_STA_LISTEN_INTERVAL,
191 NL80211_ATTR_STA_SUPPORTED_RATES, 194 NL80211_ATTR_STA_SUPPORTED_RATES,
192 NL80211_ATTR_STA_VLAN, 195 NL80211_ATTR_STA_VLAN,
196 NL80211_ATTR_STA_STATS,
193 197
194 /* add attributes here, update the policy in nl80211.c */ 198 /* add attributes here, update the policy in nl80211.c */
195 199
@@ -252,4 +256,28 @@ enum nl80211_sta_flags {
252 NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 256 NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
253}; 257};
254 258
259/**
260 * enum nl80211_sta_stats - station statistics
261 *
262 * These attribute types are used with %NL80211_ATTR_STA_STATS
263 * when getting information about a station.
264 *
265 * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
266 * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
267 * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
268 * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
269 * @__NL80211_STA_STAT_AFTER_LAST: internal
270 * @NL80211_STA_STAT_MAX: highest possible station stats attribute
271 */
272enum nl80211_sta_stats {
273 __NL80211_STA_STAT_INVALID,
274 NL80211_STA_STAT_INACTIVE_TIME,
275 NL80211_STA_STAT_RX_BYTES,
276 NL80211_STA_STAT_TX_BYTES,
277
278 /* keep last */
279 __NL80211_STA_STAT_AFTER_LAST,
280 NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
281};
282
255#endif /* __LINUX_NL80211_H */ 283#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index df650935e268..bcc480b8892a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -130,6 +130,39 @@ struct station_parameters {
130 u8 supported_rates_len; 130 u8 supported_rates_len;
131}; 131};
132 132
133/**
134 * enum station_stats_flags - station statistics flags
135 *
136 * Used by the driver to indicate which info in &struct station_stats
137 * it has filled in during get_station().
138 *
139 * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
140 * @STATION_STAT_RX_BYTES: @rx_bytes filled
141 * @STATION_STAT_TX_BYTES: @tx_bytes filled
142 */
143enum station_stats_flags {
144 STATION_STAT_INACTIVE_TIME = 1<<0,
145 STATION_STAT_RX_BYTES = 1<<1,
146 STATION_STAT_TX_BYTES = 1<<2,
147};
148
149/**
150 * struct station_stats - station statistics
151 *
152 * Station information filled by driver for get_station().
153 *
154 * @filled: bitflag of flags from &enum station_stats_flags
155 * @inactive_time: time since last station activity (tx/rx) in milliseconds
156 * @rx_bytes: bytes received from this station
157 * @tx_bytes: bytes transmitted to this station
158 */
159struct station_stats {
160 u32 filled;
161 u32 inactive_time;
162 u32 rx_bytes;
163 u32 tx_bytes;
164};
165
133/* from net/wireless.h */ 166/* from net/wireless.h */
134struct wiphy; 167struct wiphy;
135 168
@@ -210,6 +243,8 @@ struct cfg80211_ops {
210 u8 *mac); 243 u8 *mac);
211 int (*change_station)(struct wiphy *wiphy, struct net_device *dev, 244 int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
212 u8 *mac, struct station_parameters *params); 245 u8 *mac, struct station_parameters *params);
246 int (*get_station)(struct wiphy *wiphy, struct net_device *dev,
247 u8 *mac, struct station_stats *stats);
213}; 248};
214 249
215#endif /* __NET_CFG80211_H */ 250#endif /* __NET_CFG80211_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 431835126e88..e3a214f63f91 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -750,9 +750,89 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
750 return 0; 750 return 0;
751} 751}
752 752
753static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
754 int flags, struct net_device *dev,
755 u8 *mac_addr, struct station_stats *stats)
756{
757 void *hdr;
758 struct nlattr *statsattr;
759
760 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
761 if (!hdr)
762 return -1;
763
764 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
765 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
766
767 statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
768 if (!statsattr)
769 goto nla_put_failure;
770 if (stats->filled & STATION_STAT_INACTIVE_TIME)
771 NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
772 stats->inactive_time);
773 if (stats->filled & STATION_STAT_RX_BYTES)
774 NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
775 stats->rx_bytes);
776 if (stats->filled & STATION_STAT_TX_BYTES)
777 NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
778 stats->tx_bytes);
779
780 nla_nest_end(msg, statsattr);
781
782 return genlmsg_end(msg, hdr);
783
784 nla_put_failure:
785 return genlmsg_cancel(msg, hdr);
786}
787
788
753static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) 789static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
754{ 790{
755 return -EOPNOTSUPP; 791 struct cfg80211_registered_device *drv;
792 int err;
793 struct net_device *dev;
794 struct station_stats stats;
795 struct sk_buff *msg;
796 u8 *mac_addr = NULL;
797
798 memset(&stats, 0, sizeof(stats));
799
800 if (!info->attrs[NL80211_ATTR_MAC])
801 return -EINVAL;
802
803 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
804
805 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
806 if (err)
807 return err;
808
809 if (!drv->ops->get_station) {
810 err = -EOPNOTSUPP;
811 goto out;
812 }
813
814 rtnl_lock();
815 err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
816 rtnl_unlock();
817
818 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
819 if (!msg)
820 goto out;
821
822 if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
823 dev, mac_addr, &stats) < 0)
824 goto out_free;
825
826 err = genlmsg_unicast(msg, info->snd_pid);
827 goto out;
828
829 out_free:
830 nlmsg_free(msg);
831
832 out:
833 cfg80211_put_dev(drv);
834 dev_put(dev);
835 return err;
756} 836}
757 837
758/* 838/*