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 23 RoamCommand::RoamCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd) 24 : WifiVendorCommand(handle, id, vendor_id, subcmd) 25 { 26 } 27 28 RoamCommand::~RoamCommand() 29 { 30 } 31 32 /* This function implements creation of Vendor command */ 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 54 int RoamCommand::requestResponse() 55 { 56 return WifiCommand::requestResponse(mMsg); 57 } 58 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 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 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 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 */ 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