diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/nl80211.c | 82 |
1 files changed, 81 insertions, 1 deletions
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 | /* |