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>
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>
20 #define LOG_TAG "WifiHAL"
22 #include <utils/Log.h>
26 #include "cpp_bindings.h"
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
,
39 class LinkLayerStatsCommand
: public WifiCommand
41 wifi_link_layer_params mParams
;
42 u32 mStatsClearReqMask
;
43 u32
*mStatsClearRspMask
;
47 LinkLayerStatsCommand(wifi_interface_handle handle
, wifi_link_layer_params params
)
48 : WifiCommand(handle
, 0), mParams(params
)
50 mStatsClearReqMask
= 0;
51 mStatsClearRspMask
= 0;
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
)
62 memset(&mParams
,0,sizeof(wifi_link_layer_params
));
65 int createSetRequest(WifiRequest
& request
) {
66 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_LLS_SET_INFO
);
71 nlattr
*data
= request
.attr_start(NL80211_ATTR_VENDOR_DATA
);
73 result
= request
.put_u32(LSTATS_ATTRIBUTE_SET_MPDU_SIZE_THRESHOLD
, mParams
.mpdu_size_threshold
);
78 result
= request
.put_u32(LSTATS_ATTRIBUTE_SET_AGGR_STATISTICS_GATHERING
, mParams
.aggressive_statistics_gathering
);
82 request
.attr_end(data
);
86 int createClearRequest(WifiRequest
& request
) {
87 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_LLS_CLEAR_INFO
);
91 nlattr
*data
= request
.attr_start(NL80211_ATTR_VENDOR_DATA
);
93 result
= request
.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST_MASK
, mStatsClearReqMask
);
98 result
= request
.put_u32(LSTATS_ATTRIBUTE_CLEAR_STOP_REQUEST
, mStopReq
);
102 request
.attr_end(data
);
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
);
111 ALOGE("failed to set Link Layer Statistics (result:%d)", result
);
115 result
= requestResponse(request
);
117 ALOGE("failed to Set Link Layer Statistics (result:%d)", result
);
124 virtual int clear() {
125 ALOGD("Clearing Link Layer Statistics (%d, %d)", mStatsClearReqMask
, mStopReq
);
126 WifiRequest
request(familyId(), ifaceId());
127 int result
= createClearRequest(request
);
129 ALOGE("failed to clear Link Layer Statistics (result:%d)", result
);
133 result
= requestResponse(request
);
135 ALOGE("failed to clear Link Layer Statistics (result:%d)", result
);
142 virtual int handleResponse(WifiEvent
& reply
) {
143 /* Nothing to do on response! */
149 wifi_error
wifi_set_link_stats(wifi_interface_handle iface
, wifi_link_layer_params params
)
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
);
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
)
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;
169 *stats_clear_rsp_mask
= stats_clear_req_mask
;
170 *stop_rsp
= stop_req
;
176 class GetLinkStatsCommand
: public WifiCommand
178 wifi_stats_result_handler mHandler
;
179 wifi_interface_handle iface
;
181 GetLinkStatsCommand(wifi_interface_handle iface
, wifi_stats_result_handler handler
)
182 : WifiCommand(iface
, 0), mHandler(handler
)
187 virtual int create() {
188 int ret
= mMsg
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO
);
190 ALOGE("Failed to create %x - %d", SLSI_NL80211_VENDOR_SUBCMD_LLS_GET_INFO
, ret
);
198 virtual int handleResponse(WifiEvent
& reply
) {
199 if (reply
.get_cmd() != NL80211_CMD_VENDOR
) {
200 ALOGD("Ignoring reply with cmd = %d", reply
.get_cmd());
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]);
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);
214 ALOGE("Memory alloc failed for iface_stat in response handler!!!");
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
;
223 ALOGE("Memory alloc failed for radio_stat in response handler!!!");
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
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
);
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
;
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.*/
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
;
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
));
263 iface_stat
->iface
= iface
;
264 (*mHandler
.on_link_stats_results
)(id
, iface_stat
, num_radios
, radio_stat
);
271 wifi_error
wifi_get_link_stats(wifi_request_id id
,
272 wifi_interface_handle iface
, wifi_stats_result_handler handler
)
274 GetLinkStatsCommand
command(iface
, handler
);
275 return (wifi_error
) command
.requestResponse();