99ccea99c258c7162edc92b98c19fbe60bfde7ae
[GitHub/LineageOS/android_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 ALOGD("Successfully set Link Layer Statistics measurement");
122 return result;
123 }
124
125 virtual int clear() {
126 ALOGD("Clearing Link Layer Statistics (%d, %d)", mStatsClearReqMask, mStopReq);
127 WifiRequest request(familyId(), ifaceId());
128 int result = createClearRequest(request);
129 if (result < 0) {
130 ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
131 return result;
132 }
133
134 result = requestResponse(request);
135 if (result < 0) {
136 ALOGE("failed to clear Link Layer Statistics (result:%d)", result);
137 return result;
138 }
139
140 ALOGD("Successfully clear Link Layer Statistics measurement");
141 return result;
142 }
143
144 virtual int handleResponse(WifiEvent& reply) {
145 /* Nothing to do on response! */
146 return NL_SKIP;
147 }
148 };
149
150
151 wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params)
152 {
153 LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, params);
154 wifi_error result = (wifi_error)command->start();
155 if (result != WIFI_SUCCESS) {
156 ALOGE("failed to Set link layer stats", result);
157 }
158 return result;
159 }
160
161 wifi_error wifi_clear_link_stats(wifi_interface_handle iface,
162 u32 stats_clear_req_mask, u32 *stats_clear_rsp_mask, u8 stop_req, u8 *stop_rsp)
163 {
164 LinkLayerStatsCommand *command = new LinkLayerStatsCommand(iface, stats_clear_req_mask, stats_clear_rsp_mask, stop_req, stop_rsp);
165 wifi_error result = (wifi_error)command->clear();
166 if (result != WIFI_SUCCESS) {
167 ALOGE("failed to Clear link layer stats", result);
168 *stats_clear_rsp_mask = 0;
169 *stop_rsp = 0;
170 } else {
171 *stats_clear_rsp_mask = stats_clear_req_mask;
172 *stop_rsp = stop_req;
173 }
174 return result;
175 }
176
177
178 class GetLinkStatsCommand : public WifiCommand
179 {
180 wifi_stats_result_handler mHandler;
181 wifi_interface_handle iface;
182 public:
183 GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
184 : WifiCommand(iface, 0), mHandler(handler)
185 {
186 this->iface = iface;
187 }
188
189 virtual int create() {
190 ALOGI("Creating message to get link statistics");
191
192 int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO);
193 if (ret < 0) {
194 ALOGE("Failed to create %x - %d", SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO, ret);
195 return ret;
196 }
197
198 return ret;
199 }
200
201 protected:
202 virtual int handleResponse(WifiEvent& reply) {
203
204 ALOGI("In GetLinkStatsCommand::handleResponse");
205
206 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
207 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
208 return NL_SKIP;
209 }
210
211 int id = reply.get_vendor_id();
212 int subcmd = reply.get_vendor_subcmd();
213
214 ALOGI("Id = %0x, subcmd = %d", id, subcmd);
215
216 u8 *data = (u8 *)reply.get_vendor_data();
217 int len = reply.get_vendor_data_len();
218
219 // assuming max peers is 16
220 wifi_iface_stat *iface_stat = (wifi_iface_stat *) malloc(sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * 16);
221 if (!iface_stat) {
222 ALOGE("Memory alloc failed for iface_stat in response handler!!!");
223 return NL_SKIP;
224 }
225
226 // max channel is 38 (14 2.4GHz and 24 5GHz)
227 wifi_radio_stat *radio_stat = (wifi_radio_stat *) malloc(sizeof(wifi_radio_stat) + sizeof(wifi_channel_stat) * 38);
228 if (!radio_stat) {
229 ALOGE("Memory alloc failed for radio_stat in response handler!!!");
230 free(iface_stat);
231 return NL_SKIP;
232 }
233
234 /* Data sent from driver does not contain num_tx_levels and tx_time per level. So copy
235 * radio data in two parts - 1st part until num_tx_levels and 2nd part from rx_time.
236 * channel data is copied separately
237 */
238 int radio_data_len1,radio_data_len2;
239 radio_data_len1 = (u8 *)&(radio_stat->num_tx_levels) - (u8*)radio_stat;
240 radio_data_len2 = (u8 *)(radio_stat->channels) - (u8*)&(radio_stat->rx_time);
241
242 //kernel is 64 bit. if userspace is 64 bit, typecastting buffer works else, make corrections
243 if (sizeof(iface_stat->iface) == 8) {
244 memcpy(iface_stat, data, sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers);
245 data += sizeof(wifi_iface_stat) + sizeof(wifi_peer_info) * ((wifi_iface_stat *)data)->num_peers;
246 } else {
247 /* 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
248 * so remove first 4 and 81-84 bytes from NL buffer.*/
249 data += 4;
250 memcpy(iface_stat, data, 80);
251 data += 80 + 4; //for allignment skip 4 bytes
252 memcpy(((u8 *)iface_stat) + 80, data, sizeof(wifi_iface_stat) - 80);
253 data += sizeof(wifi_iface_stat) - 80;
254 memcpy(iface_stat->peer_info, data, sizeof(wifi_peer_info) * iface_stat->num_peers);
255 data += sizeof(wifi_peer_info) * iface_stat->num_peers;
256 }
257 memcpy(radio_stat, data, radio_data_len1);
258 data += radio_data_len1;
259 memcpy(&radio_stat->rx_time, data, radio_data_len2);
260 data += radio_data_len2;
261 memcpy(radio_stat->channels, data, sizeof(wifi_channel_stat)* radio_stat->num_channels);
262 radio_stat->num_tx_levels = 0;
263 radio_stat->tx_time_per_levels = NULL;
264 iface_stat->iface = iface;
265 (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
266 free(iface_stat);
267 free(radio_stat);
268 return NL_OK;
269 }
270 };
271
272 wifi_error wifi_get_link_stats(wifi_request_id id,
273 wifi_interface_handle iface, wifi_stats_result_handler handler)
274 {
275 GetLinkStatsCommand command(iface, handler);
276 return (wifi_error) command.requestResponse();
277 }
278
279