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