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