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