• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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