1
2 #include <stdint.h>
3 #include <fcntl.h>
4 #include <sys/socket.h>
5 #include <netlink/genl/genl.h>
6 #include <netlink/genl/family.h>
7 #include <netlink/genl/ctrl.h>
8 #include <linux/rtnetlink.h>
9 #include <netpacket/packet.h>
10 #include <linux/filter.h>
11 #include <linux/errqueue.h>
12
13 #include <linux/pkt_sched.h>
14 #include <netlink/object-api.h>
15 #include <netlink/netlink.h>
16 #include <netlink/socket.h>
17 #include <netlink/handlers.h>
18
19 #include "sync.h"
20
21 #define LOG_TAG "WifiHAL"
22
23 #include <utils/Log.h>
24
25 #include "wifi_hal.h"
26 #include "common.h"
27 #include "cpp_bindings.h"
28
29 /* Internal radio statistics structure in the driver */
30 typedef struct {
31 wifi_radio radio;
32 uint32_t on_time;
33 uint32_t tx_time;
34 uint32_t rx_time;
35 uint32_t on_time_scan;
36 uint32_t on_time_nbd;
37 uint32_t on_time_gscan;
38 uint32_t on_time_roam_scan;
39 uint32_t on_time_pno_scan;
40 uint32_t on_time_hs20;
41 uint32_t num_channels;
42 wifi_channel_stat channels[];
43 } wifi_radio_stat_internal;
44
45 enum {
46 LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
47 };
48
49 class GetLinkStatsCommand : public WifiCommand
50 {
51 wifi_stats_result_handler mHandler;
52 public:
GetLinkStatsCommand(wifi_interface_handle iface,wifi_stats_result_handler handler)53 GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
54 : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
55 { }
56
create()57 virtual int create() {
58 // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
59
60 int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
61 if (ret < 0) {
62 ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
63 return ret;
64 }
65
66 return ret;
67 }
68
69 protected:
handleResponse(WifiEvent & reply)70 virtual int handleResponse(WifiEvent& reply) {
71
72 // ALOGI("In GetLinkStatsCommand::handleResponse");
73
74 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
75 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
76 return NL_SKIP;
77 }
78
79 int id = reply.get_vendor_id();
80 int subcmd = reply.get_vendor_subcmd();
81
82 // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
83
84 void *data = reply.get_vendor_data();
85 int len = reply.get_vendor_data_len();
86 wifi_radio_stat *radio_stat =
87 convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data);
88 if (!radio_stat) {
89 ALOGE("Invalid stats pointer received");
90 return NL_SKIP;
91 }
92 if (radio_stat->num_channels > 11) {
93 ALOGE("Incorrect number of channels = %d", radio_stat->num_channels);
94 // dump data before num_channels
95 ALOGE("radio: = %d", radio_stat->radio);
96 ALOGE("on_time: = %d", radio_stat->on_time);
97 ALOGE("tx_time: = %d", radio_stat->tx_time);
98 ALOGE("rx_time: = %d", radio_stat->rx_time);
99 ALOGE("on_time_scan: = %d", radio_stat->on_time_scan);
100 ALOGE("on_time_nbd: = %d", radio_stat->on_time_nbd);
101 ALOGE("on_time_gscan: = %d", radio_stat->on_time_gscan);
102 ALOGE("on_time_pno_scan: = %d", radio_stat->on_time_pno_scan);
103 ALOGE("on_time_hs20: = %d", radio_stat->on_time_hs20);
104 free(radio_stat);
105 return NL_SKIP;
106 }
107 wifi_iface_stat *iface_stat =
108 (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
109 + radio_stat->num_channels * sizeof(wifi_channel_stat));
110 (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
111 free(radio_stat);
112 return NL_OK;
113 }
114
115 private:
convertToExternalRadioStatStructure(wifi_radio_stat_internal * internal_stat_ptr)116 wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) {
117 wifi_radio_stat *external_stat_ptr = NULL;
118 if (internal_stat_ptr) {
119 uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
120 uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
121 external_stat_ptr = (wifi_radio_stat *)malloc(total_size);
122 if (external_stat_ptr) {
123 external_stat_ptr->radio = internal_stat_ptr->radio;
124 external_stat_ptr->on_time = internal_stat_ptr->on_time;
125 external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
126 external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
127 external_stat_ptr->tx_time_per_levels = NULL;
128 external_stat_ptr->num_tx_levels = 0;
129 external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
130 external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
131 external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
132 external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
133 external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
134 external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
135 external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
136 if (internal_stat_ptr->num_channels) {
137 memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
138 channel_size);
139 }
140 }
141 }
142 return external_stat_ptr;
143 }
144 };
145
wifi_get_link_stats(wifi_request_id id,wifi_interface_handle iface,wifi_stats_result_handler handler)146 wifi_error wifi_get_link_stats(wifi_request_id id,
147 wifi_interface_handle iface, wifi_stats_result_handler handler)
148 {
149 GetLinkStatsCommand command(iface, handler);
150 return (wifi_error) command.requestResponse();
151 }
152
wifi_set_link_stats(wifi_interface_handle,wifi_link_layer_params)153 wifi_error wifi_set_link_stats(
154 wifi_interface_handle /* iface */, wifi_link_layer_params /* params */)
155 {
156 /* Return success here since bcom HAL does not need set link stats. */
157 return WIFI_SUCCESS;
158 }
159
wifi_clear_link_stats(wifi_interface_handle,u32,u32 *,u8,u8 *)160 wifi_error wifi_clear_link_stats(
161 wifi_interface_handle /* iface */, u32 /* stats_clear_req_mask */,
162 u32 * /* stats_clear_rsp_mask */, u8 /* stop_req */, u8 * /* stop_rsp */)
163 {
164 /* Return success here since bcom HAL does not support clear link stats. */
165 return WIFI_SUCCESS;
166 }
167