1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Portions copyright (C) 2023 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 <utils/Log.h>
41 #include <hardware_legacy/wifi_hal.h>
42 #include "common.h"
43 #include "cpp_bindings.h"
44
45 #define CACHE_SCAN_RESULT_SIZE sizeof(wifi_cached_scan_result)
46 #define MAX_CACHE_SCAN_RESULT_SIZE (MAX_CACHED_SCAN_RESULT*CACHE_SCAN_RESULT_SIZE)
47 typedef enum {
48 WIFI_ATTRIBUTE_CACHED_SCAN_INVALID = 0,
49 WIFI_ATTRIBUTE_CACHED_SCAN_BOOT_TIMESTAMP = 1,
50 WIFI_ATTRIBUTE_CACHED_SCANNED_FREQ_NUM = 2,
51 WIFI_ATTRIBUTE_CACHED_SCANNED_FREQ_LIST = 3,
52 WIFI_ATTRIBUTE_CACHED_SCAN_RESULT_CNT = 4,
53 WIFI_ATTRIBUTE_CACHED_SCAN_RESULTS = 5,
54 WIFI_ATTRIBUTE_CACHED_SCAN_MAX
55 } SCAN_ATTRIBUTE;
56 /////////////////////////////////////////////////////////////////////////////
57
58 class GetCachedScanResultsCommand : public WifiCommand {
59 wifi_cached_scan_result_handler mHandler;
60 wifi_cached_scan_report *mReport;
61
62 public:
GetCachedScanResultsCommand(wifi_interface_handle iface,int id,wifi_cached_scan_result_handler handler)63 GetCachedScanResultsCommand(wifi_interface_handle iface, int id,
64 wifi_cached_scan_result_handler handler)
65 : WifiCommand("GetCachedScanResultsCommand", iface, id), mHandler(handler)
66 {
67 mReport = NULL;
68 }
69
create()70 virtual int create() {
71 ALOGE("Creating message to get cached scan results");
72
73 int ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_CACHED_SCAN_RESULTS);
74 if (ret < 0) {
75 return ret;
76 }
77
78 return ret;
79 }
80
81 protected:
handleResponse(WifiEvent & reply)82 virtual int handleResponse(WifiEvent& reply) {
83 ALOGI("In GetCachedScanResultsCommand::handleResponse");
84
85 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
86 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
87 return NL_SKIP;
88 }
89
90 int id = reply.get_vendor_id();
91 int subcmd = reply.get_vendor_subcmd();
92 int valid_entries = 0;
93 int result_size = 0;
94 wifi_timestamp timestamp = 0;
95 int size = 0;
96
97 ALOGV("Id = %0x, subcmd = %d", id, subcmd);
98
99 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
100 int len = reply.get_vendor_data_len();
101
102 if (vendor_data == NULL || len == 0) {
103 ALOGE("no vendor data in GetCachedScanResults response; ignoring it");
104 return NL_SKIP;
105 }
106
107 mReport = (wifi_cached_scan_report *)malloc(sizeof(wifi_cached_scan_report));
108 if (mReport == NULL) {
109 ALOGE("Failed to allocate!!\n");
110 return NL_SKIP;
111 }
112 memset(mReport, 0, sizeof(wifi_cached_scan_report));
113
114 ALOGV("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
115 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
116 if (it.get_type() == WIFI_ATTRIBUTE_CACHED_SCAN_BOOT_TIMESTAMP) {
117 timestamp = it.get_u32();
118 ALOGV("Time since boot_ms: %ld\n", timestamp);
119 } else if (it.get_type() == WIFI_ATTRIBUTE_CACHED_SCAN_RESULT_CNT) {
120 valid_entries = min(it.get_u16(), MAX_CACHED_SCAN_RESULT);
121 ALOGV("cached scan result cnt: %d", valid_entries);
122 } else if ((it.get_type() == WIFI_ATTRIBUTE_CACHED_SCAN_RESULTS) &&
123 valid_entries && timestamp) {
124 size = min(it.get_len(), MAX_CACHE_SCAN_RESULT_SIZE);
125 if (size > (valid_entries*CACHE_SCAN_RESULT_SIZE)) {
126 ALOGE("Not enough space to copy!!\n");
127 return NL_SKIP;
128 }
129 result_size = valid_entries * CACHE_SCAN_RESULT_SIZE;
130 mReport->results = (wifi_cached_scan_result *)malloc(result_size);
131 if (mReport->results == NULL) {
132 ALOGE("Failed to allocate!!\n");
133 return NL_SKIP;
134 }
135 memcpy((void *)mReport->results, (void *)it.get_data(), size);
136 } else {
137 ALOGW("Ignoring invalid attribute type = %d, size = %d",
138 it.get_type(), it.get_len());
139 }
140 }
141
142 mReport->ts = timestamp;
143 mReport->result_cnt = valid_entries;
144
145 if (*mHandler.on_cached_scan_results && mReport) {
146 (*mHandler.on_cached_scan_results)(mReport);
147 ALOGV("Notified cache scan report!!");
148 }
149
150 if (mReport) {
151 if (mReport->results) {
152 free((void *)mReport->results);
153 }
154 free(mReport);
155 }
156 return NL_OK;
157 }
158 };
159
wifi_get_cached_scan_results(wifi_interface_handle iface,wifi_cached_scan_result_handler handler)160 wifi_error wifi_get_cached_scan_results(wifi_interface_handle iface,
161 wifi_cached_scan_result_handler handler)
162 {
163 ALOGI("Getting cached scan results, iface handle = %p", iface);
164 GetCachedScanResultsCommand command(iface, 0, handler);
165 return (wifi_error) command.requestResponse();
166 }
167