1 /* Copyright (c) 2017, 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 
29 #include "sync.h"
30 
31 #include <utils/Log.h>
32 
33 #include "wifi_hal.h"
34 #include "common.h"
35 #include "cpp_bindings.h"
36 #include "radio_mode.h"
37 #include "vendor_definitions.h"
38 #include <netlink/genl/genl.h>
39 #include <string.h>
40 #include <net/if.h>
41 
42 /* Used to handle radio mode command events from driver/firmware.*/
setCallbackHandler(wifi_radio_mode_change_handler handler)43 void RADIOModeCommand::setCallbackHandler(wifi_radio_mode_change_handler handler)
44 {
45     mHandler = handler;
46 }
47 
setReqId(wifi_request_id id)48 void RADIOModeCommand::setReqId(wifi_request_id id)
49 {
50     mreqId =  id;
51 }
52 
RADIOModeCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)53 RADIOModeCommand::RADIOModeCommand(wifi_handle handle, int id,
54                                    u32 vendor_id, u32 subcmd)
55         : WifiVendorCommand(handle, id, vendor_id, subcmd)
56 {
57     memset(&mHandler, 0, sizeof(mHandler));
58     if (registerVendorHandler(vendor_id, subcmd)) {
59         /* Error case should not happen print log */
60         ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
61               __FUNCTION__, vendor_id, subcmd);
62     }
63 }
64 
~RADIOModeCommand()65 RADIOModeCommand::~RADIOModeCommand()
66 {
67     unregisterVendorHandler(mVendor_id, mSubcmd);
68 }
69 
70 
instance(wifi_handle handle,wifi_request_id id)71 RADIOModeCommand* RADIOModeCommand::instance(wifi_handle handle,
72                                              wifi_request_id id)
73 {
74     RADIOModeCommand* mRADIOModeCommandInstance;
75 
76     if (handle == NULL) {
77         ALOGE("Interface Handle is invalid");
78         return NULL;
79     }
80     hal_info *info = getHalInfo(handle);
81     if (!info) {
82         ALOGE("hal_info is invalid");
83         return NULL;
84     }
85     mRADIOModeCommandInstance = new RADIOModeCommand(handle, id,
86                 OUI_QCA,
87                 QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO);
88     return mRADIOModeCommandInstance;
89 }
90 
91 /* This function will be the main handler for incoming event.
92  * Call the appropriate callback handler after parsing the vendor data.
93  */
handleEvent(WifiEvent & event)94 int RADIOModeCommand::handleEvent(WifiEvent &event)
95 {
96     wifi_error ret = WIFI_SUCCESS;
97     int num_of_mac = 0;
98     wifi_mac_info mode_info;
99 
100     memset(&mode_info, 0, sizeof(mode_info));
101     WifiVendorCommand::handleEvent(event);
102 
103     /* Parse the vendordata and get the attribute */
104     switch(mSubcmd)
105     {
106         case QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO:
107         {
108             struct nlattr *mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_MAX + 1];
109             struct nlattr *modeInfo;
110             int rem;
111 
112             nla_parse(mtb_vendor, QCA_WLAN_VENDOR_ATTR_MAC_MAX,
113                       (struct nlattr *)mVendorData,
114                       mDataLen, NULL);
115 
116             if (mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO])
117             {
118                 for (modeInfo = (struct nlattr *) nla_data(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]),
119                      rem = nla_len(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]);
120                      nla_ok(modeInfo, rem);modeInfo = nla_next(modeInfo, &(rem))) {
121 
122                      struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX+ 1];
123                      nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX,
124                                 (struct nlattr *) nla_data(modeInfo), nla_len(modeInfo), NULL);
125                      if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID])
126                      {
127                         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID"
128                                " not found", __FUNCTION__);
129                         return WIFI_ERROR_INVALID_ARGS;
130                      }
131                      mode_info.wlan_mac_id = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID]);
132                      ALOGV("mac_id[%d]: %d ", num_of_mac, mode_info.wlan_mac_id);
133 
134                      if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND])
135                      {
136                          ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND"
137                                " NOT FOUND", __FUNCTION__);
138                          return WIFI_ERROR_INVALID_ARGS;
139                      }
140                      mode_info.mac_band = (wlan_mac_band) nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND]);
141                      ALOGV("mac_band[%d]: %d ", num_of_mac, mode_info.mac_band);
142 
143                      if (tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO])
144                      {
145                        int num_of_iface = 0;
146                        struct nlattr *tb_iface;
147                        int rem_info;
148 
149                        for (tb_iface = (struct nlattr *) nla_data(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]),
150                             rem_info = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]);
151                             nla_ok(tb_iface, rem_info);tb_iface = nla_next(tb_iface, &(rem_info))) {
152 
153                             struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX+ 1];
154                             wifi_iface_info miface_info;
155 
156                             nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX,
157                                       (struct nlattr *) nla_data(tb_iface), nla_len(tb_iface), NULL);
158 
159                             if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX])
160                             {
161                                 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX"
162                                       " NOT FOUND", __FUNCTION__);
163                                 return WIFI_ERROR_INVALID_ARGS;
164                             }
165                             if (if_indextoname(nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX]),
166                                                miface_info.iface_name) == NULL)
167                             {
168                                 ALOGE("%s: Failed to convert %d IFINDEX to IFNAME", __FUNCTION__,
169                                       nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX]));
170                             }
171                             ALOGV("ifname[%d]: %s ", num_of_iface, miface_info.iface_name);
172 
173                             if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ])
174                             {
175                                 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ"
176                                       " NOT FOUND", __FUNCTION__);
177                                 return WIFI_ERROR_INVALID_ARGS;
178                             }
179                             miface_info.channel = nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ]);
180                             ALOGV("channel[%d]: %d ", num_of_iface, miface_info.channel);
181 
182                             if (!num_of_iface)
183                                mode_info.iface_info = (wifi_iface_info *)
184                                          malloc(sizeof(wifi_iface_info));
185                             else
186                                mode_info.iface_info = (wifi_iface_info *)
187                                          realloc(mode_info.iface_info, (num_of_iface + 1) * sizeof(wifi_iface_info));
188 
189                             memcpy(&mode_info.iface_info[num_of_iface], &miface_info, sizeof(wifi_iface_info));
190                             num_of_iface++;
191                             mode_info.num_iface = num_of_iface;
192                        }
193                     }
194                     if (!num_of_mac)
195                        mwifi_iface_mac_info = (wifi_mac_info *)
196                           malloc(sizeof(wifi_mac_info));
197                     else
198                        mwifi_iface_mac_info = (wifi_mac_info *)
199                           realloc(mwifi_iface_mac_info, (num_of_mac + 1) * (sizeof(wifi_mac_info)));
200 
201                     memcpy(&mwifi_iface_mac_info[num_of_mac], &mode_info, sizeof(wifi_mac_info));
202                     num_of_mac++;
203                 }
204             }
205 
206             if (mHandler.on_radio_mode_change && num_of_mac) {
207                 (*mHandler.on_radio_mode_change)(mreqId, num_of_mac, mwifi_iface_mac_info);
208                 free(mwifi_iface_mac_info);
209                 mwifi_iface_mac_info = NULL;
210             }
211             else {
212                   ALOGE("No Callback registered: on radio mode change");
213                   free(mwifi_iface_mac_info);
214                   mwifi_iface_mac_info = NULL;
215             }
216         }
217         break;
218 
219         default:
220             /* Error case should not happen print log */
221             ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
222     }
223 
224     return ret;
225 }
226 
wifi_set_radio_mode_change_handler(wifi_request_id id,wifi_interface_handle iface,wifi_radio_mode_change_handler eh)227 wifi_error wifi_set_radio_mode_change_handler(wifi_request_id id,
228                                       wifi_interface_handle iface,
229                                       wifi_radio_mode_change_handler eh)
230 {
231     wifi_error ret;
232     WifiVendorCommand *vCommand = NULL;
233     wifi_handle wifiHandle = getWifiHandle(iface);
234     RADIOModeCommand *radiomodeCommand;
235 
236     ret = initialize_vendor_cmd(iface, id,
237                                 QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO,
238                                 &vCommand);
239     if (ret != WIFI_SUCCESS) {
240         ALOGE("%s: Initialization failed", __FUNCTION__);
241         return ret;
242     }
243 
244     radiomodeCommand = RADIOModeCommand::instance(wifiHandle, id);
245     if (radiomodeCommand == NULL) {
246         ALOGE("%s: Error RadioModeCommand NULL", __FUNCTION__);
247         ret = WIFI_ERROR_OUT_OF_MEMORY;
248         goto cleanup;
249     }
250     radiomodeCommand->setCallbackHandler(eh);
251     radiomodeCommand->setReqId(id);
252 
253 cleanup:
254     delete vCommand;
255     return mapKernelErrortoWifiHalError(ret);
256 }
257