1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <errno.h>
18 
19 #include "common.h"
20 #include "roamcommand.h"
21 #include "vendor_definitions.h"
22 
RoamCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)23 RoamCommand::RoamCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
24         : WifiVendorCommand(handle, id, vendor_id, subcmd)
25 {
26 }
27 
~RoamCommand()28 RoamCommand::~RoamCommand()
29 {
30 }
31 
32 /* This function implements creation of Vendor command */
create()33 int RoamCommand::create() {
34     int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
35     if (ret < 0) {
36         return ret;
37     }
38 
39     /* Insert the oui in the msg */
40     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
41     if (ret < 0)
42         goto out;
43     /* Insert the subcmd in the msg */
44     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
45     if (ret < 0)
46         goto out;
47 
48      ALOGV("%s: mVendor_id = %d, Subcmd = %d.",
49         __FUNCTION__, mVendor_id, mSubcmd);
50 out:
51     return ret;
52 }
53 
requestResponse()54 int RoamCommand::requestResponse()
55 {
56     return WifiCommand::requestResponse(mMsg);
57 }
58 
wifi_set_bssid_blacklist(wifi_request_id id,wifi_interface_handle iface,wifi_bssid_params params)59 wifi_error wifi_set_bssid_blacklist(wifi_request_id id,
60                                     wifi_interface_handle iface,
61                                     wifi_bssid_params params)
62 {
63     int ret = 0, i;
64     RoamCommand *roamCommand;
65     struct nlattr *nlData, *nlBssids;
66     interface_info *ifaceInfo = getIfaceInfo(iface);
67     wifi_handle wifiHandle = getWifiHandle(iface);
68     hal_info *info = getHalInfo(wifiHandle);
69 
70     if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
71         ALOGE("%s: GSCAN is not supported by driver",
72             __FUNCTION__);
73         return WIFI_ERROR_NOT_SUPPORTED;
74     }
75 
76     for (i = 0; i < params.num_bssid; i++) {
77         ALOGV("BSSID: %d : %02x:%02x:%02x:%02x:%02x:%02x", i,
78                 params.bssids[i][0], params.bssids[i][1],
79                 params.bssids[i][2], params.bssids[i][3],
80                 params.bssids[i][4], params.bssids[i][5]);
81     }
82 
83     roamCommand =
84          new RoamCommand(wifiHandle,
85                           id,
86                           OUI_QCA,
87                           QCA_NL80211_VENDOR_SUBCMD_ROAM);
88     if (roamCommand == NULL) {
89         ALOGE("%s: Error roamCommand NULL", __FUNCTION__);
90         return WIFI_ERROR_UNKNOWN;
91     }
92 
93     /* Create the NL message. */
94     ret = roamCommand->create();
95     if (ret < 0)
96         goto cleanup;
97 
98     /* Set the interface Id of the message. */
99     ret = roamCommand->set_iface_id(ifaceInfo->name);
100     if (ret < 0)
101         goto cleanup;
102 
103     /* Add the vendor specific attributes for the NL command. */
104     nlData = roamCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
105     if (!nlData)
106         goto cleanup;
107 
108     if (roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
109             QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
110         roamCommand->put_u32(
111             QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
112             id) ||
113         roamCommand->put_u32(
114             QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
115             params.num_bssid)) {
116         goto cleanup;
117     }
118 
119     nlBssids = roamCommand->attr_start(
120             QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
121     for (i = 0; i < params.num_bssid; i++) {
122         struct nlattr *nl_ssid = roamCommand->attr_start(i);
123 
124         if (roamCommand->put_addr(
125                 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
126                 (u8 *)params.bssids[i])) {
127             goto cleanup;
128         }
129 
130         roamCommand->attr_end(nl_ssid);
131     }
132     roamCommand->attr_end(nlBssids);
133 
134     roamCommand->attr_end(nlData);
135 
136     ret = roamCommand->requestResponse();
137     if (ret != 0) {
138         ALOGE("wifi_set_bssid_blacklist(): requestResponse Error:%d", ret);
139     }
140 
141 cleanup:
142     delete roamCommand;
143     return (wifi_error)ret;
144 
145 }
146 
wifi_set_ssid_white_list(wifi_request_id id,wifi_interface_handle iface,int num_networks,ssid_t * ssid_list)147 wifi_error wifi_set_ssid_white_list(wifi_request_id id, wifi_interface_handle iface,
148                                     int num_networks, ssid_t *ssid_list)
149 {
150     wifi_error result = WIFI_SUCCESS;
151     int ret = 0, i;
152     RoamCommand *roamCommand;
153     struct nlattr *nlData, *nlSsids;
154     interface_info *ifaceInfo = getIfaceInfo(iface);
155     wifi_handle wifiHandle = getWifiHandle(iface);
156     char ssid[MAX_SSID_LENGTH + 1];
157 
158     ALOGV("%s: Number of SSIDs : %d", __FUNCTION__, num_networks);
159 
160     roamCommand = new RoamCommand(
161                                 wifiHandle,
162                                 id,
163                                 OUI_QCA,
164                                 QCA_NL80211_VENDOR_SUBCMD_ROAM);
165     if (roamCommand == NULL) {
166         ALOGE("%s: Failed to create object of RoamCommand class", __FUNCTION__);
167         return WIFI_ERROR_UNKNOWN;
168     }
169 
170     /* Create the NL message. */
171     ret = roamCommand->create();
172     if (ret < 0) {
173         ALOGE("%s: Failed to create NL message,  Error: %d", __FUNCTION__, ret);
174         result = WIFI_ERROR_UNKNOWN;
175         goto cleanup;
176     }
177 
178     /* Set the interface Id of the message. */
179     ret = roamCommand->set_iface_id(ifaceInfo->name);
180     if (ret < 0) {
181         ALOGE("%s: Failed to set interface Id of message, Error: %d", __FUNCTION__, ret);
182         result = WIFI_ERROR_UNKNOWN;
183         goto cleanup;
184     }
185 
186     /* Add the vendor specific attributes for the NL command. */
187     nlData = roamCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
188     if (!nlData) {
189         result = WIFI_ERROR_UNKNOWN;
190         goto cleanup;
191     }
192 
193     if (roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
194                              QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST) ||
195         roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID, id) ||
196         roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
197                              num_networks)) {
198         ALOGE("%s: Failed to add vendor atributes, Error: %d", __FUNCTION__, ret);
199         result = WIFI_ERROR_UNKNOWN;
200         goto cleanup;
201     }
202 
203     nlSsids = roamCommand->attr_start(QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST);
204     for (i = 0; i < num_networks; i++) {
205         struct nlattr *nl_ssid = roamCommand->attr_start(i);
206 
207         memcpy(ssid, ssid_list[i].ssid_str, ssid_list[i].length);
208         ssid[ssid_list[i].length] = '\0';
209         ALOGV("ssid[%d] : %s", i, ssid);
210 
211         if (roamCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID, ssid,
212                                    (ssid_list[i].length + 1))) {
213             ALOGE("%s: Failed to add ssid atribute, Error: %d", __FUNCTION__, ret);
214             result = WIFI_ERROR_UNKNOWN;
215             goto cleanup;
216         }
217 
218         roamCommand->attr_end(nl_ssid);
219     }
220     roamCommand->attr_end(nlSsids);
221 
222     roamCommand->attr_end(nlData);
223 
224     ret = roamCommand->requestResponse();
225     if (ret != 0) {
226         ALOGE("%s: Failed to send request, Error:%d", __FUNCTION__, ret);
227         result = WIFI_ERROR_UNKNOWN;
228     }
229 
230 cleanup:
231     delete roamCommand;
232     return result;
233 }
234 
wifi_get_roaming_capabilities(wifi_interface_handle iface,wifi_roaming_capabilities * caps)235 wifi_error wifi_get_roaming_capabilities(wifi_interface_handle iface,
236                                          wifi_roaming_capabilities *caps)
237 {
238     wifi_handle wifiHandle = getWifiHandle(iface);
239     hal_info *info = getHalInfo(wifiHandle);
240 
241     if (!caps) {
242         ALOGE("%s: Invalid Buffer provided. Exit", __FUNCTION__);
243         return WIFI_ERROR_INVALID_ARGS;
244     }
245 
246     if (!info) {
247         ALOGE("%s: hal_info is NULL", __FUNCTION__);
248         return WIFI_ERROR_INVALID_ARGS;
249     }
250 
251     memcpy(caps, &info->capa.roaming_capa, sizeof(wifi_roaming_capabilities));
252 
253     return WIFI_SUCCESS;
254 }
255 
wifi_configure_roaming(wifi_interface_handle iface,wifi_roaming_config * roaming_config)256 wifi_error wifi_configure_roaming(wifi_interface_handle iface, wifi_roaming_config *roaming_config)
257 {
258     wifi_error ret;
259     int requestId;
260     wifi_bssid_params bssid_params;
261     wifi_handle wifiHandle = getWifiHandle(iface);
262     hal_info *info = getHalInfo(wifiHandle);
263 
264     if (!roaming_config) {
265         ALOGE("%s: Invalid Buffer provided. Exit", __FUNCTION__);
266         return WIFI_ERROR_INVALID_ARGS;
267     }
268 
269     /* No request id from caller, so generate one and pass it on to the driver.
270      * Generate it randomly.
271      */
272     requestId = get_requestid();
273 
274     /* Set bssid blacklist */
275     if (roaming_config->num_blacklist_bssid > info->capa.roaming_capa.max_blacklist_size) {
276         ALOGE("%s: Number of blacklist bssids(%d) provided is more than maximum blacklist bssids(%d)"
277               " supported", __FUNCTION__, roaming_config->num_blacklist_bssid,
278               info->capa.roaming_capa.max_blacklist_size);
279         return WIFI_ERROR_NOT_SUPPORTED;
280     }
281     bssid_params.num_bssid = roaming_config->num_blacklist_bssid;
282 
283     memcpy(bssid_params.bssids, roaming_config->blacklist_bssid,
284            (bssid_params.num_bssid * sizeof(mac_addr)));
285 
286     ret = wifi_set_bssid_blacklist(requestId, iface, bssid_params);
287     if (ret != WIFI_SUCCESS) {
288         ALOGE("%s: Failed to configure blacklist bssids", __FUNCTION__);
289         return WIFI_ERROR_UNKNOWN;
290     }
291 
292     /* Set ssid whitelist */
293     if (roaming_config->num_whitelist_ssid > info->capa.roaming_capa.max_whitelist_size) {
294         ALOGE("%s: Number of whitelist ssid(%d) provided is more than maximum whitelist ssids(%d) "
295               "supported", __FUNCTION__, roaming_config->num_whitelist_ssid,
296               info->capa.roaming_capa.max_whitelist_size);
297         return WIFI_ERROR_NOT_SUPPORTED;
298     }
299     ret = wifi_set_ssid_white_list(requestId, iface, roaming_config->num_whitelist_ssid,
300                                    roaming_config->whitelist_ssid);
301     if (ret != WIFI_SUCCESS)
302         ALOGE("%s: Failed to configure whitelist ssids", __FUNCTION__);
303 
304     return ret;
305 }
306 
307 /* Enable/disable firmware roaming */
wifi_enable_firmware_roaming(wifi_interface_handle iface,fw_roaming_state_t state)308 wifi_error wifi_enable_firmware_roaming(wifi_interface_handle iface, fw_roaming_state_t state)
309 {
310     wifi_error result = WIFI_SUCCESS;
311     int requestId, ret;
312     RoamCommand *roamCommand;
313     struct nlattr *nlData;
314     interface_info *ifaceInfo = getIfaceInfo(iface);
315     wifi_handle wifiHandle = getWifiHandle(iface);
316     qca_roaming_policy policy;
317 
318     ALOGV("%s: set firmware roam state : %d", __FUNCTION__, state);
319 
320     if (state == ROAMING_ENABLE) {
321         policy = QCA_ROAMING_ALLOWED_WITHIN_ESS;
322     } else if(state == ROAMING_DISABLE) {
323         policy = QCA_ROAMING_NOT_ALLOWED;
324     } else {
325         ALOGE("%s: Invalid state provided: %d. Exit \n", __FUNCTION__, state);
326         return WIFI_ERROR_INVALID_ARGS;
327     }
328 
329     /* No request id from caller, so generate one and pass it on to the driver.
330      * Generate it randomly.
331      */
332     requestId = get_requestid();
333 
334     roamCommand =
335          new RoamCommand(wifiHandle,
336                           requestId,
337                           OUI_QCA,
338                           QCA_NL80211_VENDOR_SUBCMD_ROAMING);
339     if (roamCommand == NULL) {
340         ALOGE("%s: Failed to create object of RoamCommand class", __FUNCTION__);
341         return WIFI_ERROR_UNKNOWN;
342     }
343 
344     /* Create the NL message. */
345     ret = roamCommand->create();
346     if (ret < 0) {
347         ALOGE("%s: Failed to create NL message,  Error: %d", __FUNCTION__, ret);
348         result = WIFI_ERROR_UNKNOWN;
349         goto cleanup;
350     }
351 
352     /* Set the interface Id of the message. */
353     ret = roamCommand->set_iface_id(ifaceInfo->name);
354     if (ret < 0) {
355         ALOGE("%s: Failed to set interface Id of message, Error: %d", __FUNCTION__, ret);
356         result = WIFI_ERROR_UNKNOWN;
357         goto cleanup;
358     }
359 
360     /* Add the vendor specific attributes for the NL command. */
361     nlData = roamCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
362     if (!nlData) {
363         result = WIFI_ERROR_UNKNOWN;
364         goto cleanup;
365     }
366 
367     if (roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY, policy)) {
368         ALOGE("%s: Failed to add roaming policy atribute, Error: %d", __FUNCTION__, ret);
369         result = WIFI_ERROR_UNKNOWN;
370         goto cleanup;
371     }
372 
373     roamCommand->attr_end(nlData);
374 
375     ret = roamCommand->requestResponse();
376     if (ret != 0) {
377         ALOGE("%s: Failed to send request, Error:%d", __FUNCTION__, ret);
378         if (ret == -EBUSY)
379             result = WIFI_ERROR_BUSY;
380         else
381             result = WIFI_ERROR_UNKNOWN;
382     }
383 
384 cleanup:
385     delete roamCommand;
386     return result;
387 }
388