[9610][7885] wlbt :Revert setScanningMacOui support as feature and only pass VTS.
[GitHub/MotorolaMobilityLLC/hardware-samsung_slsi-scsc_wifibt-wifi_hal.git] / link_layer_stats.cpp
1 #include <stdint.h>
2 #include <fcntl.h>
3 #include <sys/socket.h>
4 #include <netlink/genl/genl.h>
5 #include <netlink/genl/family.h>
6 #include <netlink/genl/ctrl.h>
7 #include <linux/rtnetlink.h>
8 #include <netpacket/packet.h>
9 #include <linux/filter.h>
10 #include <linux/errqueue.h>
11
12 #include <linux/pkt_sched.h>
13 #include <netlink/object-api.h>
14 #include <netlink/netlink.h>
15 #include <netlink/socket.h>
16 #include <netlink/handlers.h>
17
18 #include "sync.h"
19
20 #define LOG_TAG "WifiHAL"
21
22 #include <utils/Log.h>
23
24 #include "wifi_hal.h"
25 #include "common.h"
26 #include "cpp_bindings.h"
27
28 typedef enum {
29
30 LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD = 1,
31 LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING,
32 LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK,
33 LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST,
34
35 LSTATS_ATTRIBUTE_MAX
36
37 } LSTATS_ATTRIBUTE;
38
39 class LinkLayerStatsCommand : public WifiCommand
40 {
41 wifi_link_layer_params mParams;
42 u32 mStatsClearReqMask;
43 u32 *mStatsClearRspMask;
44 u8 mStopReq;
45 u8 *mStopRsp;
46 public:
47 LinkLayerStatsCommand(wifi_interface_handle handle, wifi_link_layer_params params)
48 : WifiCommand(handle, 0), mParams(params)
49 {
50 mStatsClearReqMask = 0;
51 mStatsClearRspMask = 0;
52 mStopReq = 0 ;
53 mStopRsp = NULL;
54
55 }
56
57 LinkLayerStatsCommand(wifi_interface_handle handle,
58 u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
59 : WifiCommand(handle, 0), mStatsClearReqMask(stats_clear_req_mask), mStatsClearRspMask(stats_clear_rsp_mask),
60 mStopReq(stop_req), mStopRsp(stop_rsp)
61 {
62 memset(&mParams,0,sizeof(wifi_link_layer_params));
63 }
64
65 int createSetRequest(WifiRequest& request) {
66 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_SET_INFO);
67 if (result < 0) {
68 return result;
69 }
70
71 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
72
73 result = request.put_u32(LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD, mParams.mpdu_size_threshold);
74 if (result < 0) {
75 return result;
76 }
77
78 result = request.put_u32(LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING, mParams.aggressive_statistics_gathering);
79 if (result < 0) {
80 return result;
81 }
82 request.attr_end(data);
83 return result;
84 }
85
86 int createClearRequest(WifiRequest& request) {
87 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_CLEAR_INFO);
88 if (result < 0) {
89 return result;
90 }
91 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
92
93 result = request.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK, mStatsClearReqMask);
94 if (result < 0) {
95 return result;
96 }
97
98 result = request.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST, mStopReq);
99 if (result < 0) {
100 return result;
101 }
102 request.attr_end(data);
103 return result;
104 }
105
106 int start() {
107 ALOGD("Starting Link Layer Statistics measurement (%d, %d)", mParams.mpdu_size_threshold, mParams.aggressive_statistics_gathering);
108 WifiRequest request(familyId(), ifaceId());
109 int result = createSetRequest(request);
110 if (result < 0) {
111 ALOGE("failed to set Link Layer Statistics (result:%d)", result);
112 return result;
113 }
114
115 result = requestResponse(request);
116 if (result < 0) {
117 ALOGE("failed to Set Link Layer Statistics (result:%d)", result);
118 return result;
119 }
120
121 return result;
122 }
123
124 virtual int clear() {
125 ALOGD("Clearing Link Layer Statistics (%d, %d)", mStatsClearReqMask, mStopReq);
126 WifiRequest request(familyId(), ifaceId());
127 int result = createClearRequest(request);
128 if (result < 0) {
129 ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
130 return result;
131 }
132
133 result = requestResponse(request);
134 if (result < 0) {
135 ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
136 return result;
137 }
138
139 return result;
140 }
141
142 virtual int handleResponse(WifiEvent& reply) {
143 /* Nothing to do on response! */
144 return NL_SKIP;
145 }
146 };
147
148
149 wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params)
150 {
151 LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, params);
152 wifi_error result = (wifi_error)command->start();
153 if (result != WIFI_SUCCESS) {
154 ALOGE("failed to Set link layer stats", result);
155 }
156 return result;
157 }
158
159 wifi_error wifi_clear_link_stats(wifi_interface_handle iface,
160 u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
161 {
162 LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, stats_clear_req_mask, stats_clear_rsp_mask, stop_req, stop_rsp);
163 wifi_error result = (wifi_error)command->clear();
164 if (result != WIFI_SUCCESS) {
165 ALOGE("failed to Clear link layer stats", result);
166 *stats_clear_rsp_mask = 0;
167 *stop_rsp = 0;
168 } else {
169 *stats_clear_rsp_mask = stats_clear_req_mask;
170 *stop_rsp = stop_req;
171 }
172 return result;
173 }
174
175
176 class GetLinkStatsCommand : public WifiCommand
177 {
178 wifi_stats_result_handler mHandler;
179 wifi_interface_handle iface;
180 public:
181 GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
182 : WifiCommand(iface, 0), mHandler(handler)
183 {
184 this->iface = iface;
185 }
186
187 virtual int create() {
188 int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO);
189 if (ret < 0) {
190 ALOGE("Failed to create %x - %d", SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO, ret);
191 return ret;
192 }
193
194 return ret;
195 }
196
197 protected:
198 virtual int handleResponse(WifiEvent& reply) {
199 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
200 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
201 return NL_SKIP;
202 }
203 int id = reply.get_vendor_id();
204 int subcmd = reply.get_vendor_subcmd();
205 u8 *data = (u8 *)reply.get_vendor_data();
206 int len = reply.get_vendor_data_len();
207 int num_radios = 0, i = 0;
208 num_radios = data[0];
209 data += sizeof(data[0]);
210
211 // assuming max peers is 16
212 wifi_iface_stat *iface_stat = (wifi_iface_stat *) malloc(sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * 16);
213 if (!iface_stat) {
214 ALOGE("Memory alloc failed for iface_stat in response handler!!!");
215 return NL_SKIP;
216 }
217
218 // max channel is 39 (14 2.4GHz and 25 5GHz)
219 wifi_radio_stat *radio_stat = (wifi_radio_stat *) malloc((num_radios * sizeof(wifi_radio_stat)) + sizeof(wifi_channel_stat) * 39);
220 wifi_radio_stat *radio_stat2;
221 radio_stat2 = radio_stat;
222 if (!radio_stat) {
223 ALOGE("Memory alloc failed for radio_stat in response handler!!!");
224 free(iface_stat);
225 return NL_SKIP;
226 }
227
228 /* Data sent from driver does not contain num_tx_levels and tx_time per level. So copy
229 * radio data in two parts - 1st part until num_tx_levels and 2nd part from rx_time.
230 * channel data is copied separately
231 */
232 int radio_data_len1,radio_data_len2;
233 radio_data_len1 = (u8 *)&(radio_stat->num_tx_levels) - (u8*)radio_stat;
234 radio_data_len2 = (u8 *)(radio_stat->channels) - (u8*)&(radio_stat->rx_time);
235
236 //kernel is 64 bit. if userspace is 64 bit, typecastting buffer works else, make corrections
237 if (sizeof(iface_stat->iface) == 8) {
238 memcpy(iface_stat, data, sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers);
239 data += sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers;
240 } else {
241 /* for 64 bit kernel ad 32 bit user space, there is 4 byte extra at the begining and another 4 byte pad after 80 bytes
242 * so remove first 4 and 81-84 bytes from NL buffer.*/
243 data += 4;
244 memcpy(iface_stat, data, 80);
245 data += 80 + 4; //for allignment skip 4 bytes
246 memcpy(((u8 *)iface_stat) + 80, data, sizeof(wifi_iface_stat) - 80);
247 data += sizeof(wifi_iface_stat) - 80;
248 memcpy(iface_stat->peer_info, data, sizeof(wifi_peer_info) * iface_stat->num_peers);
249 data += sizeof(wifi_peer_info) * iface_stat->num_peers;
250 }
251 for (i = 0; i < num_radios; i++) {
252 memcpy(radio_stat2, data, radio_data_len1);
253 data += radio_data_len1;
254 memcpy(&radio_stat2->rx_time, data, radio_data_len2);
255 data += radio_data_len2;
256 memcpy(radio_stat2->channels, data, sizeof(wifi_channel_stat)* radio_stat2->num_channels);
257 radio_stat2->num_tx_levels = 0;
258 radio_stat2->tx_time_per_levels = NULL;
259 data += sizeof(wifi_channel_stat)* radio_stat2->num_channels;
260 radio_stat2=(wifi_radio_stat *) ((u8 *)radio_stat2+ sizeof(wifi_radio_stat) +
261 (sizeof(wifi_channel_stat) * radio_stat2->num_channels ));
262 }
263 iface_stat->iface = iface;
264 (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat);
265 free(iface_stat);
266 free(radio_stat);
267 return NL_OK;
268 }
269 };
270
271 wifi_error wifi_get_link_stats(wifi_request_id id,
272 wifi_interface_handle iface, wifi_stats_result_handler handler)
273 {
274 GetLinkStatsCommand command(iface, handler);
275 return (wifi_error) command.requestResponse();
276 }
277
278