1 /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in
10 * the documentation and/or other materials provided with the
11 * distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 * Changes from Qualcomm Innovation Center are provided under the following license:
29
30 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
31 * SPDX-License-Identifier: BSD-3-Clause-Clear
32 */
33
34 #include "sync.h"
35
36 #include <utils/Log.h>
37
38 #include <hardware_legacy/wifi_hal.h>
39 #include "common.h"
40 #include "cpp_bindings.h"
41 #include "radio_mode.h"
42 #include "vendor_definitions.h"
43 #include <netlink/genl/genl.h>
44 #include <string.h>
45 #include <net/if.h>
46
47 /* Used to handle radio command events from driver/firmware. */
48 typedef struct radio_event_handler_s {
49 RADIOModeCommand* mRADIOModeCommandInstance;
50 } radio_event_handlers;
51
initializeRadioHandler(hal_info * info)52 wifi_error initializeRadioHandler(hal_info *info)
53 {
54 info->radio_handlers = (radio_event_handlers *)malloc(
55 sizeof(radio_event_handlers));
56 if (info->radio_handlers) {
57 memset(info->radio_handlers, 0, sizeof(radio_event_handlers));
58 } else {
59 ALOGE("%s: Allocation of radio event handlers failed",
60 __FUNCTION__);
61 return WIFI_ERROR_OUT_OF_MEMORY;
62 }
63 return WIFI_SUCCESS;
64 }
65
cleanupRadioHandler(hal_info * info)66 wifi_error cleanupRadioHandler(hal_info *info) {
67 radio_event_handlers* event_handlers;
68 if (info && info->radio_handlers) {
69 event_handlers = (radio_event_handlers*) info->radio_handlers;
70 if (event_handlers->mRADIOModeCommandInstance) {
71 delete event_handlers->mRADIOModeCommandInstance;
72 }
73 memset(event_handlers, 0, sizeof(radio_event_handlers));
74 free(info->radio_handlers);
75 info->radio_handlers = NULL;
76 return WIFI_SUCCESS;
77 }
78 ALOGE ("%s: info or info->radio_handlers NULL", __FUNCTION__);
79 return WIFI_ERROR_UNKNOWN;
80 }
81
82 /* Used to handle radio mode command events from driver/firmware.*/
setCallbackHandler(wifi_radio_mode_change_handler handler)83 void RADIOModeCommand::setCallbackHandler(wifi_radio_mode_change_handler handler)
84 {
85 mHandler = handler;
86 }
87
setReqId(wifi_request_id id)88 void RADIOModeCommand::setReqId(wifi_request_id id)
89 {
90 mreqId = id;
91 }
92
RADIOModeCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)93 RADIOModeCommand::RADIOModeCommand(wifi_handle handle, int id,
94 u32 vendor_id, u32 subcmd)
95 : WifiVendorCommand(handle, id, vendor_id, subcmd)
96 {
97 memset(&mHandler, 0, sizeof(mHandler));
98 if (registerVendorHandler(vendor_id, subcmd)) {
99 /* Error case should not happen print log */
100 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
101 __FUNCTION__, vendor_id, subcmd);
102 }
103 }
104
~RADIOModeCommand()105 RADIOModeCommand::~RADIOModeCommand()
106 {
107 unregisterVendorHandler(mVendor_id, mSubcmd);
108 }
109
110
instance(wifi_handle handle,wifi_request_id id)111 RADIOModeCommand* RADIOModeCommand::instance(wifi_handle handle,
112 wifi_request_id id)
113 {
114 if (handle == NULL) {
115 ALOGE("Interface Handle is invalid");
116 return NULL;
117 }
118 hal_info *info = getHalInfo(handle);
119 if (!info) {
120 ALOGE("hal_info is invalid");
121 return NULL;
122 }
123 RADIOModeCommand* instance = info->radio_handlers->mRADIOModeCommandInstance;
124 if (instance) {
125 if (handle != getWifiHandle(instance->mInfo)) {
126 ALOGV("%s - Handle different, update the handle", __FUNCTION__);
127 instance->mInfo = (hal_info *)handle;
128 }
129 instance->setReqId(id);
130 } else {
131 info->radio_handlers->mRADIOModeCommandInstance =
132 new RADIOModeCommand(handle, id, OUI_QCA,
133 QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO);
134 instance = info->radio_handlers->mRADIOModeCommandInstance;
135 }
136 return instance;
137 }
138
139 /* This function will be the main handler for incoming event.
140 * Call the appropriate callback handler after parsing the vendor data.
141 */
handleEvent(WifiEvent & event)142 int RADIOModeCommand::handleEvent(WifiEvent &event)
143 {
144 wifi_error ret = WIFI_ERROR_UNKNOWN;
145 int num_of_mac = 0;
146 wifi_mac_info mode_info;
147 memset(&mode_info, 0, sizeof(mode_info));
148
149 WifiVendorCommand::handleEvent(event);
150
151 /* Parse the vendordata and get the attribute */
152 switch(mSubcmd)
153 {
154 case QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO:
155 {
156 struct nlattr *mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_MAX + 1];
157 struct nlattr *modeInfo;
158 int rem;
159
160 nla_parse(mtb_vendor, QCA_WLAN_VENDOR_ATTR_MAC_MAX,
161 (struct nlattr *)mVendorData,
162 mDataLen, NULL);
163
164 if (mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO])
165 {
166 for (modeInfo = (struct nlattr *) nla_data(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]),
167 rem = nla_len(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]);
168 nla_ok(modeInfo, rem);modeInfo = nla_next(modeInfo, &(rem))) {
169
170 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX+ 1];
171 nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX,
172 (struct nlattr *) nla_data(modeInfo), nla_len(modeInfo), NULL);
173 if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID])
174 {
175 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID"
176 " not found", __FUNCTION__);
177 ret = WIFI_ERROR_INVALID_ARGS;
178 goto cleanup;
179 }
180 mode_info.wlan_mac_id = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID]);
181 ALOGV("mac_id[%d]: %d ", num_of_mac, mode_info.wlan_mac_id);
182
183 if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND])
184 {
185 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND"
186 " NOT FOUND", __FUNCTION__);
187 ret = WIFI_ERROR_INVALID_ARGS;
188 goto cleanup;
189 }
190 mode_info.mac_band = (wlan_mac_band) nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND]);
191 ALOGV("mac_band[%d]: %d ", num_of_mac, mode_info.mac_band);
192
193 if (tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO])
194 {
195 int num_of_iface = 0;
196 struct nlattr *tb_iface;
197 int rem_info;
198
199 for (tb_iface = (struct nlattr *) nla_data(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]),
200 rem_info = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]);
201 nla_ok(tb_iface, rem_info);tb_iface = nla_next(tb_iface, &(rem_info))) {
202
203 struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX+ 1];
204 wifi_iface_info miface_info;
205
206 nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX,
207 (struct nlattr *) nla_data(tb_iface), nla_len(tb_iface), NULL);
208
209 if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX])
210 {
211 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX"
212 " NOT FOUND", __FUNCTION__);
213 ret = WIFI_ERROR_INVALID_ARGS;
214 goto cleanup;
215 }
216 if (if_indextoname(nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX]),
217 miface_info.iface_name) == NULL)
218 {
219 ALOGE("%s: Failed to convert %d IFINDEX to IFNAME", __FUNCTION__,
220 nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX]));
221 }
222 ALOGV("ifname[%d]: %s ", num_of_iface, miface_info.iface_name);
223
224 if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ])
225 {
226 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ"
227 " NOT FOUND", __FUNCTION__);
228 ret = WIFI_ERROR_INVALID_ARGS;
229 goto cleanup;
230 }
231 miface_info.channel = nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ]);
232 ALOGV("channel[%d]: %d ", num_of_iface, miface_info.channel);
233
234 if (!num_of_iface)
235 mode_info.iface_info = (wifi_iface_info *)
236 malloc(sizeof(wifi_iface_info));
237 else
238 mode_info.iface_info = (wifi_iface_info *)
239 realloc(mode_info.iface_info, (num_of_iface + 1) * sizeof(wifi_iface_info));
240
241 if (mode_info.iface_info != NULL) {
242 memcpy(&mode_info.iface_info[num_of_iface], &miface_info, sizeof(wifi_iface_info));
243 num_of_iface++;
244 mode_info.num_iface = num_of_iface;
245 }
246 }
247 }
248 if (!num_of_mac)
249 mwifi_iface_mac_info = (wifi_mac_info *)
250 malloc(sizeof(wifi_mac_info));
251 else
252 mwifi_iface_mac_info = (wifi_mac_info *)
253 realloc(mwifi_iface_mac_info, (num_of_mac + 1) * (sizeof(wifi_mac_info)));
254
255 if (mwifi_iface_mac_info != NULL) {
256 memcpy(&mwifi_iface_mac_info[num_of_mac], &mode_info, sizeof(wifi_mac_info));
257 num_of_mac++;
258 }
259 }
260 }
261
262 if (mHandler.on_radio_mode_change && num_of_mac) {
263 (*mHandler.on_radio_mode_change)(mreqId, num_of_mac, mwifi_iface_mac_info);
264 }
265 else {
266 ALOGE("No Callback registered: on radio mode change");
267 ret = WIFI_ERROR_UNKNOWN;
268 goto cleanup;
269 }
270 ret = WIFI_SUCCESS;
271 }
272 break;
273
274 default:
275 /* Error case should not happen print log */
276 ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
277 }
278
279 cleanup:
280 if (mode_info.iface_info != NULL) {
281 free(mode_info.iface_info);
282 mode_info.iface_info = NULL;
283 }
284 if (mwifi_iface_mac_info != NULL) {
285 free(mwifi_iface_mac_info);
286 mwifi_iface_mac_info = NULL;
287 }
288
289 return ret;
290 }
291
wifi_set_radio_mode_change_handler(wifi_request_id id,wifi_interface_handle iface,wifi_radio_mode_change_handler eh)292 wifi_error wifi_set_radio_mode_change_handler(wifi_request_id id,
293 wifi_interface_handle iface,
294 wifi_radio_mode_change_handler eh)
295 {
296 wifi_error ret;
297 WifiVendorCommand *vCommand = NULL;
298 wifi_handle wifiHandle = getWifiHandle(iface);
299 RADIOModeCommand *radiomodeCommand;
300
301 ret = initialize_vendor_cmd(iface, id,
302 QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO,
303 &vCommand);
304 if (ret != WIFI_SUCCESS) {
305 ALOGE("%s: Initialization failed", __FUNCTION__);
306 return ret;
307 }
308
309 radiomodeCommand = RADIOModeCommand::instance(wifiHandle, id);
310 if (radiomodeCommand == NULL) {
311 ALOGE("%s: Error RadioModeCommand NULL", __FUNCTION__);
312 ret = WIFI_ERROR_OUT_OF_MEMORY;
313 goto cleanup;
314 }
315 radiomodeCommand->setCallbackHandler(eh);
316 radiomodeCommand->setReqId(id);
317
318 cleanup:
319 delete vCommand;
320 return mapKernelErrortoWifiHalError(ret);
321 }
322