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_MODE);
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 WifiVendorCommand::handleEvent(event);
101
102 /* Parse the vendordata and get the attribute */
103 switch(mSubcmd)
104 {
105 case QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_MODE:
106 {
107 struct nlattr *mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_MAX + 1];
108 struct nlattr *modeInfo;
109 int rem;
110
111 nla_parse(mtb_vendor, QCA_WLAN_VENDOR_ATTR_MAC_MAX,
112 (struct nlattr *)mVendorData,
113 mDataLen, NULL);
114
115 if (mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO])
116 {
117 for (modeInfo = (struct nlattr *) nla_data(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]),
118 rem = nla_len(mtb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_INFO]);
119 nla_ok(modeInfo, rem);modeInfo = nla_next(modeInfo, &(rem))) {
120
121 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX+ 1];
122 nla_parse(tb2, QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAX,
123 (struct nlattr *) nla_data(modeInfo), nla_len(modeInfo), NULL);
124 if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID])
125 {
126 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID"
127 " not found", __FUNCTION__);
128 return WIFI_ERROR_INVALID_ARGS;
129 }
130 mode_info.wlan_mac_id = nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID]);
131 ALOGV("mac_id[%d]: %d ", num_of_mac, mode_info.wlan_mac_id);
132
133 if (!tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND])
134 {
135 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND"
136 " NOT FOUND", __FUNCTION__);
137 return WIFI_ERROR_INVALID_ARGS;
138 }
139 mode_info.mac_band = (wlan_mac_band) nla_get_u32(tb2[QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND]);
140 ALOGV("mac_band[%d]: %d ", num_of_mac, mode_info.mac_band);
141
142 if (tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO])
143 {
144 int num_of_iface = 0;
145 struct nlattr *tb_iface;
146 int rem_info;
147
148 for (tb_iface = (struct nlattr *) nla_data(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]),
149 rem_info = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO]);
150 nla_ok(tb_iface, rem_info);tb_iface = nla_next(tb_iface, &(rem_info))) {
151
152 struct nlattr *tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX+ 1];
153 wifi_iface_info miface_info;
154
155 nla_parse(tb3, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_MAX,
156 (struct nlattr *) nla_data(tb_iface), nla_len(tb_iface), NULL);
157
158 if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID])
159 {
160 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID"
161 " NOT FOUND", __FUNCTION__);
162 return WIFI_ERROR_INVALID_ARGS;
163 }
164 if (if_indextoname(nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID]),
165 miface_info.iface_name) == NULL)
166 {
167 ALOGE("%s: Failed to convert %d IFINDEX to IFNAME", __FUNCTION__,
168 nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_ID]));
169 }
170 ALOGV("ifname[%d]: %s ", num_of_iface, miface_info.iface_name);
171
172 if (!tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ])
173 {
174 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ"
175 " NOT FOUND", __FUNCTION__);
176 return WIFI_ERROR_INVALID_ARGS;
177 }
178 miface_info.channel = nla_get_u32(tb3[QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ]);
179 ALOGV("channel[%d]: %d ", num_of_iface, miface_info.channel);
180
181 if (!num_of_iface)
182 mode_info.iface_info = (wifi_iface_info *)
183 malloc(sizeof(wifi_iface_info));
184 else
185 mode_info.iface_info = (wifi_iface_info *)
186 realloc(mode_info.iface_info, (num_of_iface + 1) * sizeof(wifi_iface_info));
187
188 memcpy(&mode_info.iface_info[num_of_iface], &miface_info, sizeof(wifi_iface_info));
189 num_of_iface++;
190 mode_info.num_iface = num_of_iface;
191 }
192 }
193 if (!num_of_mac)
194 mwifi_iface_mac_info = (wifi_mac_info *)
195 malloc(sizeof(wifi_mac_info));
196 else
197 mwifi_iface_mac_info = (wifi_mac_info *)
198 realloc(mwifi_iface_mac_info, (num_of_mac + 1) * (sizeof(wifi_mac_info)));
199
200 memcpy(&mwifi_iface_mac_info[num_of_mac], &mode_info, sizeof(wifi_mac_info));
201 num_of_mac++;
202 }
203 }
204
205 if (mHandler.on_radio_mode_change && num_of_mac) {
206 (*mHandler.on_radio_mode_change)(mreqId, num_of_mac, mwifi_iface_mac_info);
207 free(mwifi_iface_mac_info);
208 mwifi_iface_mac_info = NULL;
209 }
210 else {
211 ALOGE("No Callback registered: on radio mode change");
212 free(mwifi_iface_mac_info);
213 mwifi_iface_mac_info = NULL;
214 }
215 }
216 break;
217
218 default:
219 /* Error case should not happen print log */
220 ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
221 }
222
223 return ret;
224 }
225
wifi_set_radio_mode_change_handler(wifi_request_id id,wifi_interface_handle iface,wifi_radio_mode_change_handler eh)226 wifi_error wifi_set_radio_mode_change_handler(wifi_request_id id,
227 wifi_interface_handle iface,
228 wifi_radio_mode_change_handler eh)
229 {
230 wifi_error ret;
231 WifiVendorCommand *vCommand = NULL;
232 wifi_handle wifiHandle = getWifiHandle(iface);
233 RADIOModeCommand *radiomodeCommand;
234
235 ret = initialize_vendor_cmd(iface, id,
236 QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_MODE,
237 &vCommand);
238 if (ret != WIFI_SUCCESS) {
239 ALOGE("%s: Initialization failed", __FUNCTION__);
240 return ret;
241 }
242
243 radiomodeCommand = RADIOModeCommand::instance(wifiHandle, id);
244 if (radiomodeCommand == NULL) {
245 ALOGE("%s: Error RadioModeCommand NULL", __FUNCTION__);
246 ret = WIFI_ERROR_OUT_OF_MEMORY;
247 goto cleanup;
248 }
249 radiomodeCommand->setCallbackHandler(eh);
250 radiomodeCommand->setReqId(id);
251
252 cleanup:
253 delete vCommand;
254 return mapKernelErrortoWifiHalError(ret);
255 }
256