summaryrefslogtreecommitdiffstats
path: root/bcmdhd/wifi_hal/link_layer_stats.cpp
blob: 170c7912ec0e9ecca17d192a3168f501600c9535 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

#include <stdint.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <linux/rtnetlink.h>
#include <netpacket/packet.h>
#include <linux/filter.h>
#include <linux/errqueue.h>

#include <linux/pkt_sched.h>
#include <netlink/object-api.h>
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/handlers.h>

#include "sync.h"

#define LOG_TAG  "WifiHAL"

#include <utils/Log.h>

#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"


enum {
    LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
};

class GetLinkStatsCommand : public WifiCommand
{
    wifi_stats_result_handler mHandler;
public:
    GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
        : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
    { }

    virtual int create() {
        // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);

        int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
        if (ret < 0) {
            ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
            return ret;
        }

        return ret;
    }

protected:
    virtual int handleResponse(WifiEvent& reply) {

        // ALOGI("In GetLinkStatsCommand::handleResponse");

        if (reply.get_cmd() != NL80211_CMD_VENDOR) {
            ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
            return NL_SKIP;
        }

        int id = reply.get_vendor_id();
        int subcmd = reply.get_vendor_subcmd();

        // ALOGI("Id = %0x, subcmd = %d", id, subcmd);

        void *data = reply.get_vendor_data();
        int len = reply.get_vendor_data_len();
	unsigned int num_chan = ((wifi_radio_stat *)data)->num_channels;
        if (num_chan > 11) {
           ALOGE("Incorrect number of channels = %d", num_chan);
           // dump data before num_channels
           ALOGE("radio: = %d", ((wifi_radio_stat *)data)->radio);
           ALOGE("on_time: = %d", ((wifi_radio_stat *)data)->on_time);
           ALOGE("tx_time: = %d", ((wifi_radio_stat *)data)->tx_time);
           ALOGE("rx_time: = %d", ((wifi_radio_stat *)data)->rx_time);
           ALOGE("on_time_scan: = %d", ((wifi_radio_stat *)data)->on_time_scan);
           ALOGE("on_time_nbd: = %d", ((wifi_radio_stat *)data)->on_time_nbd);
           ALOGE("on_time_gscan: = %d", ((wifi_radio_stat *)data)->on_time_gscan);
           ALOGE("on_time_pno_scan: = %d", ((wifi_radio_stat *)data)->on_time_pno_scan);
           ALOGE("on_time_hs20: = %d", ((wifi_radio_stat *)data)->on_time_hs20);
           return NL_SKIP;
        }
	(*mHandler.on_link_stats_results)(id,
		(wifi_iface_stat *)((char *)&((wifi_radio_stat *)data)->channels
		+ num_chan*sizeof(wifi_channel_stat)),
		1, (wifi_radio_stat *)data);

        return NL_OK;
    }
};

wifi_error wifi_get_link_stats(wifi_request_id id,
        wifi_interface_handle iface, wifi_stats_result_handler handler)
{
    GetLinkStatsCommand command(iface, handler);
    return (wifi_error) command.requestResponse();
}