diff options
-rw-r--r-- | include/linux/nl80211.h | 28 | ||||
-rw-r--r-- | include/net/cfg80211.h | 35 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 82 |
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 | */ | ||
272 | enum 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 | */ | ||
143 | enum 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 | */ | ||
159 | struct 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 */ |
134 | struct wiphy; | 167 | struct 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 | ||
753 | static 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 | |||
753 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 789 | static 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 | /* |