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