aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/*