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