1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Portions copyright (C) 2017 Broadcom Limited
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <stdint.h>
20 #include <fcntl.h>
21 #include <sys/socket.h>
22 #include <netlink/genl/genl.h>
23 #include <netlink/genl/family.h>
24 #include <netlink/genl/ctrl.h>
25 #include <linux/rtnetlink.h>
26 #include <netpacket/packet.h>
27 #include <linux/filter.h>
28 #include <linux/errqueue.h>
29 
30 #include <linux/pkt_sched.h>
31 #include <netlink/object-api.h>
32 #include <netlink/netlink.h>
33 #include <netlink/socket.h>
34 #include <netlink/handlers.h>
35 
36 #include "sync.h"
37 
38 #define LOG_TAG  "WifiHAL"
39 
40 #include <log/log.h>
41 
42 #include "wifi_hal.h"
43 #include "common.h"
44 #include "cpp_bindings.h"
45 
46 enum {
47     LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
48 };
49 
50 class GetLinkStatsCommand : public WifiCommand
51 {
52     wifi_stats_result_handler mHandler;
53 public:
GetLinkStatsCommand(wifi_interface_handle iface,wifi_stats_result_handler handler)54     GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
55         : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
56     { }
57 
create()58     virtual int create() {
59         // ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
60 
61         int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
62         if (ret < 0) {
63             ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
64             return ret;
65         }
66 
67         return ret;
68     }
69 
70 protected:
handleResponse(WifiEvent & reply)71     virtual int handleResponse(WifiEvent& reply) {
72 
73         // ALOGI("In GetLinkStatsCommand::handleResponse");
74 
75         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
76             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
77             return NL_SKIP;
78         }
79 
80         int id = reply.get_vendor_id();
81         int subcmd = reply.get_vendor_subcmd();
82 
83         // ALOGI("Id = %0x, subcmd = %d", id, subcmd);
84 
85         void *data = reply.get_vendor_data();
86         int len = reply.get_vendor_data_len();
87         wifi_radio_stat *radio_stat = (wifi_radio_stat *)data;
88         if (!radio_stat) {
89             ALOGE("Invalid stats pointer received");
90             return NL_SKIP;
91         }
92 	radio_stat->tx_time_per_levels = (u32*)((char*)data + sizeof(wifi_radio_stat) + sizeof(wifi_iface_stat));
93         if (radio_stat->num_channels > 11) {
94             ALOGE("Incorrect number of channels = %d", radio_stat->num_channels);
95             // dump data before num_channels
96             ALOGE("radio: = %d", radio_stat->radio);
97             ALOGE("on_time: = %d", radio_stat->on_time);
98             ALOGE("tx_time: = %d", radio_stat->tx_time);
99             ALOGE("rx_time: = %d", radio_stat->rx_time);
100             ALOGE("on_time_scan: = %d", radio_stat->on_time_scan);
101             ALOGE("on_time_nbd: = %d", radio_stat->on_time_nbd);
102             ALOGE("on_time_gscan: = %d", radio_stat->on_time_gscan);
103             ALOGE("on_time_pno_scan: = %d", radio_stat->on_time_pno_scan);
104             ALOGE("on_time_hs20: = %d", radio_stat->on_time_hs20);
105             return NL_SKIP;
106         }
107         wifi_iface_stat *iface_stat = (wifi_iface_stat *)((char* )data + sizeof(wifi_radio_stat));
108 
109 	if(*mHandler.on_link_stats_results == NULL) {
110 		ALOGE("*mHandler.on_link_stats_results is NULL");
111 	} else {
112         	(*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
113 	}
114         return NL_OK;
115     }
116 
117 };
118 
wifi_get_link_stats(wifi_request_id id,wifi_interface_handle iface,wifi_stats_result_handler handler)119 wifi_error wifi_get_link_stats(wifi_request_id id,
120         wifi_interface_handle iface, wifi_stats_result_handler handler)
121 {
122     GetLinkStatsCommand command(iface, handler);
123     return (wifi_error) command.requestResponse();
124 }
125 
wifi_set_link_stats(wifi_interface_handle,wifi_link_layer_params)126 wifi_error wifi_set_link_stats(
127         wifi_interface_handle /* iface */, wifi_link_layer_params /* params */)
128 {
129     /* Return success here since bcom HAL does not need set link stats. */
130     return WIFI_SUCCESS;
131 }
132 
wifi_clear_link_stats(wifi_interface_handle,u32,u32 *,u8,u8 *)133 wifi_error wifi_clear_link_stats(
134         wifi_interface_handle /* iface */, u32 /* stats_clear_req_mask */,
135         u32 * /* stats_clear_rsp_mask */, u8 /* stop_req */, u8 * /* stop_rsp */)
136 {
137     /* Return success here since bcom HAL does not support clear link stats. */
138     return WIFI_SUCCESS;
139 }
140