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 package com.android.server.wifi.aware; 18 19 import android.hardware.wifi.V1_0.IWifiNanIface; 20 import android.hardware.wifi.V1_0.NanBandIndex; 21 import android.hardware.wifi.V1_0.NanBandSpecificConfig; 22 import android.hardware.wifi.V1_0.NanCipherSuiteType; 23 import android.hardware.wifi.V1_0.NanConfigRequest; 24 import android.hardware.wifi.V1_0.NanDataPathSecurityType; 25 import android.hardware.wifi.V1_0.NanEnableRequest; 26 import android.hardware.wifi.V1_0.NanInitiateDataPathRequest; 27 import android.hardware.wifi.V1_0.NanMatchAlg; 28 import android.hardware.wifi.V1_0.NanPublishRequest; 29 import android.hardware.wifi.V1_0.NanRangingIndication; 30 import android.hardware.wifi.V1_0.NanRespondToDataPathIndicationRequest; 31 import android.hardware.wifi.V1_0.NanSubscribeRequest; 32 import android.hardware.wifi.V1_0.NanTransmitFollowupRequest; 33 import android.hardware.wifi.V1_0.NanTxType; 34 import android.hardware.wifi.V1_0.WifiStatus; 35 import android.hardware.wifi.V1_0.WifiStatusCode; 36 import android.hardware.wifi.V1_2.NanConfigRequestSupplemental; 37 import android.net.wifi.aware.ConfigRequest; 38 import android.net.wifi.aware.PublishConfig; 39 import android.net.wifi.aware.SubscribeConfig; 40 import android.os.RemoteException; 41 import android.os.ShellCommand; 42 import android.text.TextUtils; 43 import android.util.Log; 44 import android.util.SparseIntArray; 45 46 import com.android.internal.annotations.VisibleForTesting; 47 48 import libcore.util.HexEncoding; 49 50 import java.io.FileDescriptor; 51 import java.io.PrintWriter; 52 import java.nio.charset.StandardCharsets; 53 import java.util.ArrayList; 54 import java.util.HashMap; 55 import java.util.Map; 56 57 /** 58 * Translates Wi-Fi Aware requests from the framework to the HAL (HIDL). 59 * 60 * Delegates the management of the NAN interface to WifiAwareNativeManager. 61 */ 62 public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellCommand { 63 private static final String TAG = "WifiAwareNativeApi"; 64 private static final boolean VDBG = false; // STOPSHIP if true 65 /* package */ boolean mDbg = false; 66 67 @VisibleForTesting 68 static final String SERVICE_NAME_FOR_OOB_DATA_PATH = "Wi-Fi Aware Data Path"; 69 70 private final WifiAwareNativeManager mHal; 71 private SparseIntArray mTransactionIds; // VDBG only! 72 WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager)73 public WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager) { 74 mHal = wifiAwareNativeManager; 75 onReset(); 76 if (VDBG) { 77 mTransactionIds = new SparseIntArray(); 78 } 79 } 80 recordTransactionId(int transactionId)81 private void recordTransactionId(int transactionId) { 82 if (!VDBG) return; 83 84 if (transactionId == 0) { 85 return; // tid == 0 is used as a dummy transaction ID in several commands - acceptable 86 } 87 88 int count = mTransactionIds.get(transactionId); 89 if (count != 0) { 90 Log.wtf(TAG, "Repeated transaction ID == " + transactionId); 91 } 92 mTransactionIds.append(transactionId, count + 1); 93 } 94 95 /** 96 * (HIDL) Cast the input to a 1.2 NAN interface (possibly resulting in a null). 97 * 98 * Separate function so can be mocked in unit tests. 99 */ mockableCastTo_1_2(IWifiNanIface iface)100 public android.hardware.wifi.V1_2.IWifiNanIface mockableCastTo_1_2(IWifiNanIface iface) { 101 return android.hardware.wifi.V1_2.IWifiNanIface.castFrom(iface); 102 } 103 104 /* 105 * Parameters settable through the shell command. 106 * see wifi/1.0/types.hal NanBandSpecificConfig.discoveryWindowIntervalVal and 107 * wifi/1.2/types.hal NanConfigRequestSupplemental_1_2 for description 108 */ 109 /* package */ static final String POWER_PARAM_DEFAULT_KEY = "default"; 110 /* package */ static final String POWER_PARAM_INACTIVE_KEY = "inactive"; 111 /* package */ static final String POWER_PARAM_IDLE_KEY = "idle"; 112 113 /* package */ static final String PARAM_DW_24GHZ = "dw_24ghz"; 114 private static final int PARAM_DW_24GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms 115 private static final int PARAM_DW_24GHZ_INACTIVE = 4; // 4 -> DW=8, latency=4s 116 private static final int PARAM_DW_24GHZ_IDLE = 4; // == inactive 117 118 /* package */ static final String PARAM_DW_5GHZ = "dw_5ghz"; 119 private static final int PARAM_DW_5GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms 120 private static final int PARAM_DW_5GHZ_INACTIVE = 0; // 0 = disabled 121 private static final int PARAM_DW_5GHZ_IDLE = 0; // == inactive 122 123 /* package */ static final String PARAM_DISCOVERY_BEACON_INTERVAL_MS = 124 "disc_beacon_interval_ms"; 125 private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT = 0; // Firmware defaults 126 private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE = 0; // Firmware defaults 127 private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE = 0; // Firmware defaults 128 129 /* package */ static final String PARAM_NUM_SS_IN_DISCOVERY = "num_ss_in_discovery"; 130 private static final int PARAM_NUM_SS_IN_DISCOVERY_DEFAULT = 0; // Firmware defaults 131 private static final int PARAM_NUM_SS_IN_DISCOVERY_INACTIVE = 0; // Firmware defaults 132 private static final int PARAM_NUM_SS_IN_DISCOVERY_IDLE = 0; // Firmware defaults 133 134 /* package */ static final String PARAM_ENABLE_DW_EARLY_TERM = "enable_dw_early_term"; 135 private static final int PARAM_ENABLE_DW_EARLY_TERM_DEFAULT = 0; // boolean: 0 = false 136 private static final int PARAM_ENABLE_DW_EARLY_TERM_INACTIVE = 0; // boolean: 0 = false 137 private static final int PARAM_ENABLE_DW_EARLY_TERM_IDLE = 0; // boolean: 0 = false 138 139 /* package */ static final String PARAM_MAC_RANDOM_INTERVAL_SEC = "mac_random_interval_sec"; 140 private static final int PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT = 1800; // 30 minutes 141 142 private Map<String, Map<String, Integer>> mSettablePowerParameters = new HashMap<>(); 143 private Map<String, Integer> mSettableParameters = new HashMap<>(); 144 145 /** 146 * Interpreter of adb shell command 'adb shell wifiaware native_api ...'. 147 * 148 * @return -1 if parameter not recognized or invalid value, 0 otherwise. 149 */ 150 @Override onCommand(ShellCommand parentShell)151 public int onCommand(ShellCommand parentShell) { 152 final PrintWriter pw = parentShell.getErrPrintWriter(); 153 154 String subCmd = parentShell.getNextArgRequired(); 155 if (VDBG) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'"); 156 switch (subCmd) { 157 case "set": { 158 String name = parentShell.getNextArgRequired(); 159 if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'"); 160 if (!mSettableParameters.containsKey(name)) { 161 pw.println("Unknown parameter name -- '" + name + "'"); 162 return -1; 163 } 164 165 String valueStr = parentShell.getNextArgRequired(); 166 if (VDBG) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'"); 167 int value; 168 try { 169 value = Integer.valueOf(valueStr); 170 } catch (NumberFormatException e) { 171 pw.println("Can't convert value to integer -- '" + valueStr + "'"); 172 return -1; 173 } 174 mSettableParameters.put(name, value); 175 return 0; 176 } 177 case "set-power": { 178 String mode = parentShell.getNextArgRequired(); 179 String name = parentShell.getNextArgRequired(); 180 String valueStr = parentShell.getNextArgRequired(); 181 182 if (VDBG) { 183 Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'" + ", value='" 184 + valueStr + "'"); 185 } 186 187 if (!mSettablePowerParameters.containsKey(mode)) { 188 pw.println("Unknown mode name -- '" + mode + "'"); 189 return -1; 190 } 191 if (!mSettablePowerParameters.get(mode).containsKey(name)) { 192 pw.println("Unknown parameter name '" + name + "' in mode '" + mode + "'"); 193 return -1; 194 } 195 196 int value; 197 try { 198 value = Integer.valueOf(valueStr); 199 } catch (NumberFormatException e) { 200 pw.println("Can't convert value to integer -- '" + valueStr + "'"); 201 return -1; 202 } 203 mSettablePowerParameters.get(mode).put(name, value); 204 return 0; 205 } 206 case "get": { 207 String name = parentShell.getNextArgRequired(); 208 if (VDBG) Log.v(TAG, "onCommand: name='" + name + "'"); 209 if (!mSettableParameters.containsKey(name)) { 210 pw.println("Unknown parameter name -- '" + name + "'"); 211 return -1; 212 } 213 214 parentShell.getOutPrintWriter().println((int) mSettableParameters.get(name)); 215 return 0; 216 } 217 case "get-power": { 218 String mode = parentShell.getNextArgRequired(); 219 String name = parentShell.getNextArgRequired(); 220 if (VDBG) Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'"); 221 if (!mSettablePowerParameters.containsKey(mode)) { 222 pw.println("Unknown mode -- '" + mode + "'"); 223 return -1; 224 } 225 if (!mSettablePowerParameters.get(mode).containsKey(name)) { 226 pw.println("Unknown parameter name -- '" + name + "' in mode '" + mode + "'"); 227 return -1; 228 } 229 230 parentShell.getOutPrintWriter().println( 231 (int) mSettablePowerParameters.get(mode).get(name)); 232 return 0; 233 } 234 default: 235 pw.println("Unknown 'wifiaware native_api <cmd>'"); 236 } 237 238 return -1; 239 } 240 241 @Override onReset()242 public void onReset() { 243 Map<String, Integer> defaultMap = new HashMap<>(); 244 defaultMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_DEFAULT); 245 defaultMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_DEFAULT); 246 defaultMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 247 PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT); 248 defaultMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_DEFAULT); 249 defaultMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_DEFAULT); 250 251 Map<String, Integer> inactiveMap = new HashMap<>(); 252 inactiveMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_INACTIVE); 253 inactiveMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_INACTIVE); 254 inactiveMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 255 PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE); 256 inactiveMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_INACTIVE); 257 inactiveMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_INACTIVE); 258 259 Map<String, Integer> idleMap = new HashMap<>(); 260 idleMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_IDLE); 261 idleMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_IDLE); 262 idleMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 263 PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE); 264 idleMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_IDLE); 265 idleMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_IDLE); 266 267 mSettablePowerParameters.put(POWER_PARAM_DEFAULT_KEY, defaultMap); 268 mSettablePowerParameters.put(POWER_PARAM_INACTIVE_KEY, inactiveMap); 269 mSettablePowerParameters.put(POWER_PARAM_IDLE_KEY, idleMap); 270 271 mSettableParameters.put(PARAM_MAC_RANDOM_INTERVAL_SEC, 272 PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT); 273 } 274 275 @Override onHelp(String command, ShellCommand parentShell)276 public void onHelp(String command, ShellCommand parentShell) { 277 final PrintWriter pw = parentShell.getOutPrintWriter(); 278 279 pw.println(" " + command); 280 pw.println(" set <name> <value>: sets named parameter to value. Names: " 281 + mSettableParameters.keySet()); 282 pw.println(" set-power <mode> <name> <value>: sets named power parameter to value." 283 + " Modes: " + mSettablePowerParameters.keySet() 284 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet()); 285 pw.println(" get <name>: gets named parameter value. Names: " 286 + mSettableParameters.keySet()); 287 pw.println(" get-power <mode> <name>: gets named parameter value." 288 + " Modes: " + mSettablePowerParameters.keySet() 289 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet()); 290 } 291 292 /** 293 * Query the firmware's capabilities. 294 * 295 * @param transactionId Transaction ID for the transaction - used in the async callback to 296 * match with the original request. 297 */ getCapabilities(short transactionId)298 public boolean getCapabilities(short transactionId) { 299 if (mDbg) Log.v(TAG, "getCapabilities: transactionId=" + transactionId); 300 recordTransactionId(transactionId); 301 302 IWifiNanIface iface = mHal.getWifiNanIface(); 303 if (iface == null) { 304 Log.e(TAG, "getCapabilities: null interface"); 305 return false; 306 } 307 308 try { 309 WifiStatus status = iface.getCapabilitiesRequest(transactionId); 310 if (status.code == WifiStatusCode.SUCCESS) { 311 return true; 312 } else { 313 Log.e(TAG, "getCapabilities: error: " + statusString(status)); 314 return false; 315 } 316 } catch (RemoteException e) { 317 Log.e(TAG, "getCapabilities: exception: " + e); 318 return false; 319 } 320 } 321 322 /** 323 * Enable and configure Aware. 324 * 325 * @param transactionId Transaction ID for the transaction - used in the 326 * async callback to match with the original request. 327 * @param configRequest Requested Aware configuration. 328 * @param notifyIdentityChange Indicates whether or not to get address change callbacks. 329 * @param initialConfiguration Specifies whether initial configuration 330 * (true) or an update (false) to the configuration. 331 * @param isInteractive PowerManager.isInteractive 332 * @param isIdle PowerManager.isIdle 333 */ enableAndConfigure(short transactionId, ConfigRequest configRequest, boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive, boolean isIdle)334 public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest, 335 boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive, 336 boolean isIdle) { 337 if (mDbg) { 338 Log.v(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest=" 339 + configRequest + ", notifyIdentityChange=" + notifyIdentityChange 340 + ", initialConfiguration=" + initialConfiguration 341 + ", isInteractive=" + isInteractive + ", isIdle=" + isIdle); 342 } 343 recordTransactionId(transactionId); 344 345 IWifiNanIface iface = mHal.getWifiNanIface(); 346 if (iface == null) { 347 Log.e(TAG, "enableAndConfigure: null interface"); 348 return false; 349 } 350 android.hardware.wifi.V1_2.IWifiNanIface iface12 = mockableCastTo_1_2(iface); 351 NanConfigRequestSupplemental configSupplemental12 = new NanConfigRequestSupplemental(); 352 if (iface12 != null) { 353 if (VDBG) Log.v(TAG, "HAL 1.2 detected"); 354 configSupplemental12.discoveryBeaconIntervalMs = 0; 355 configSupplemental12.numberOfSpatialStreamsInDiscovery = 0; 356 configSupplemental12.enableDiscoveryWindowEarlyTermination = false; 357 configSupplemental12.enableRanging = true; 358 } 359 360 try { 361 WifiStatus status; 362 if (initialConfiguration) { 363 // translate framework to HIDL configuration 364 NanEnableRequest req = new NanEnableRequest(); 365 366 req.operateInBand[NanBandIndex.NAN_BAND_24GHZ] = true; 367 req.operateInBand[NanBandIndex.NAN_BAND_5GHZ] = configRequest.mSupport5gBand; 368 req.hopCountMax = 2; 369 req.configParams.masterPref = (byte) configRequest.mMasterPreference; 370 req.configParams.disableDiscoveryAddressChangeIndication = !notifyIdentityChange; 371 req.configParams.disableStartedClusterIndication = !notifyIdentityChange; 372 req.configParams.disableJoinedClusterIndication = !notifyIdentityChange; 373 req.configParams.includePublishServiceIdsInBeacon = true; 374 req.configParams.numberOfPublishServiceIdsInBeacon = 0; 375 req.configParams.includeSubscribeServiceIdsInBeacon = true; 376 req.configParams.numberOfSubscribeServiceIdsInBeacon = 0; 377 req.configParams.rssiWindowSize = 8; 378 req.configParams.macAddressRandomizationIntervalSec = mSettableParameters.get( 379 PARAM_MAC_RANDOM_INTERVAL_SEC); 380 381 NanBandSpecificConfig config24 = new NanBandSpecificConfig(); 382 config24.rssiClose = 60; 383 config24.rssiMiddle = 70; 384 config24.rssiCloseProximity = 60; 385 config24.dwellTimeMs = (byte) 200; 386 config24.scanPeriodSec = 20; 387 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ] 388 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 389 config24.validDiscoveryWindowIntervalVal = false; 390 } else { 391 config24.validDiscoveryWindowIntervalVal = true; 392 config24.discoveryWindowIntervalVal = 393 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 394 .NAN_BAND_24GHZ]; 395 } 396 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24; 397 398 NanBandSpecificConfig config5 = new NanBandSpecificConfig(); 399 config5.rssiClose = 60; 400 config5.rssiMiddle = 75; 401 config5.rssiCloseProximity = 60; 402 config5.dwellTimeMs = (byte) 200; 403 config5.scanPeriodSec = 20; 404 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] 405 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 406 config5.validDiscoveryWindowIntervalVal = false; 407 } else { 408 config5.validDiscoveryWindowIntervalVal = true; 409 config5.discoveryWindowIntervalVal = 410 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 411 .NAN_BAND_5GHZ]; 412 } 413 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; 414 415 req.debugConfigs.validClusterIdVals = true; 416 req.debugConfigs.clusterIdTopRangeVal = (short) configRequest.mClusterHigh; 417 req.debugConfigs.clusterIdBottomRangeVal = (short) configRequest.mClusterLow; 418 req.debugConfigs.validIntfAddrVal = false; 419 req.debugConfigs.validOuiVal = false; 420 req.debugConfigs.ouiVal = 0; 421 req.debugConfigs.validRandomFactorForceVal = false; 422 req.debugConfigs.randomFactorForceVal = 0; 423 req.debugConfigs.validHopCountForceVal = false; 424 req.debugConfigs.hopCountForceVal = 0; 425 req.debugConfigs.validDiscoveryChannelVal = false; 426 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_24GHZ] = 0; 427 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_5GHZ] = 0; 428 req.debugConfigs.validUseBeaconsInBandVal = false; 429 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; 430 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; 431 req.debugConfigs.validUseSdfInBandVal = false; 432 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; 433 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; 434 435 updateConfigForPowerSettings(req.configParams, configSupplemental12, isInteractive, 436 isIdle); 437 438 if (iface12 != null) { 439 status = iface12.enableRequest_1_2(transactionId, req, configSupplemental12); 440 } else { 441 status = iface.enableRequest(transactionId, req); 442 } 443 } else { 444 NanConfigRequest req = new NanConfigRequest(); 445 req.masterPref = (byte) configRequest.mMasterPreference; 446 req.disableDiscoveryAddressChangeIndication = !notifyIdentityChange; 447 req.disableStartedClusterIndication = !notifyIdentityChange; 448 req.disableJoinedClusterIndication = !notifyIdentityChange; 449 req.includePublishServiceIdsInBeacon = true; 450 req.numberOfPublishServiceIdsInBeacon = 0; 451 req.includeSubscribeServiceIdsInBeacon = true; 452 req.numberOfSubscribeServiceIdsInBeacon = 0; 453 req.rssiWindowSize = 8; 454 req.macAddressRandomizationIntervalSec = mSettableParameters.get( 455 PARAM_MAC_RANDOM_INTERVAL_SEC); 456 457 NanBandSpecificConfig config24 = new NanBandSpecificConfig(); 458 config24.rssiClose = 60; 459 config24.rssiMiddle = 70; 460 config24.rssiCloseProximity = 60; 461 config24.dwellTimeMs = (byte) 200; 462 config24.scanPeriodSec = 20; 463 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ] 464 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 465 config24.validDiscoveryWindowIntervalVal = false; 466 } else { 467 config24.validDiscoveryWindowIntervalVal = true; 468 config24.discoveryWindowIntervalVal = 469 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 470 .NAN_BAND_24GHZ]; 471 } 472 req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24; 473 474 NanBandSpecificConfig config5 = new NanBandSpecificConfig(); 475 config5.rssiClose = 60; 476 config5.rssiMiddle = 75; 477 config5.rssiCloseProximity = 60; 478 config5.dwellTimeMs = (byte) 200; 479 config5.scanPeriodSec = 20; 480 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] 481 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 482 config5.validDiscoveryWindowIntervalVal = false; 483 } else { 484 config5.validDiscoveryWindowIntervalVal = true; 485 config5.discoveryWindowIntervalVal = 486 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 487 .NAN_BAND_5GHZ]; 488 } 489 req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; 490 491 updateConfigForPowerSettings(req, configSupplemental12, isInteractive, isIdle); 492 493 if (iface12 != null) { 494 status = iface12.configRequest_1_2(transactionId, req, configSupplemental12); 495 } else { 496 status = iface.configRequest(transactionId, req); 497 } 498 } 499 if (status.code == WifiStatusCode.SUCCESS) { 500 return true; 501 } else { 502 Log.e(TAG, "enableAndConfigure: error: " + statusString(status)); 503 return false; 504 } 505 } catch (RemoteException e) { 506 Log.e(TAG, "enableAndConfigure: exception: " + e); 507 return false; 508 } 509 } 510 511 /** 512 * Disable Aware. 513 * 514 * @param transactionId transactionId Transaction ID for the transaction - 515 * used in the async callback to match with the original request. 516 */ disable(short transactionId)517 public boolean disable(short transactionId) { 518 if (mDbg) Log.d(TAG, "disable"); 519 recordTransactionId(transactionId); 520 521 IWifiNanIface iface = mHal.getWifiNanIface(); 522 if (iface == null) { 523 Log.e(TAG, "disable: null interface"); 524 return false; 525 } 526 527 try { 528 WifiStatus status = iface.disableRequest(transactionId); 529 if (status.code == WifiStatusCode.SUCCESS) { 530 return true; 531 } else { 532 Log.e(TAG, "disable: error: " + statusString(status)); 533 return false; 534 } 535 } catch (RemoteException e) { 536 Log.e(TAG, "disable: exception: " + e); 537 return false; 538 } 539 } 540 541 /** 542 * Start or modify a service publish session. 543 * 544 * @param transactionId transactionId Transaction ID for the transaction - 545 * used in the async callback to match with the original request. 546 * @param publishId ID of the requested session - 0 to request a new publish 547 * session. 548 * @param publishConfig Configuration of the discovery session. 549 */ publish(short transactionId, byte publishId, PublishConfig publishConfig)550 public boolean publish(short transactionId, byte publishId, PublishConfig publishConfig) { 551 if (mDbg) { 552 Log.d(TAG, "publish: transactionId=" + transactionId + ", publishId=" + publishId 553 + ", config=" + publishConfig); 554 } 555 recordTransactionId(transactionId); 556 557 IWifiNanIface iface = mHal.getWifiNanIface(); 558 if (iface == null) { 559 Log.e(TAG, "publish: null interface"); 560 return false; 561 } 562 563 NanPublishRequest req = new NanPublishRequest(); 564 req.baseConfigs.sessionId = publishId; 565 req.baseConfigs.ttlSec = (short) publishConfig.mTtlSec; 566 req.baseConfigs.discoveryWindowPeriod = 1; 567 req.baseConfigs.discoveryCount = 0; 568 convertNativeByteArrayToArrayList(publishConfig.mServiceName, req.baseConfigs.serviceName); 569 req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_NEVER; 570 convertNativeByteArrayToArrayList(publishConfig.mServiceSpecificInfo, 571 req.baseConfigs.serviceSpecificInfo); 572 convertNativeByteArrayToArrayList(publishConfig.mMatchFilter, 573 publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED 574 ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter); 575 req.baseConfigs.useRssiThreshold = false; 576 req.baseConfigs.disableDiscoveryTerminationIndication = 577 !publishConfig.mEnableTerminateNotification; 578 req.baseConfigs.disableMatchExpirationIndication = true; 579 req.baseConfigs.disableFollowupReceivedIndication = false; 580 581 req.autoAcceptDataPathRequests = false; 582 583 req.baseConfigs.rangingRequired = publishConfig.mEnableRanging; 584 585 // TODO: configure security 586 req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN; 587 588 req.publishType = publishConfig.mPublishType; 589 req.txType = NanTxType.BROADCAST; 590 591 try { 592 WifiStatus status = iface.startPublishRequest(transactionId, req); 593 if (status.code == WifiStatusCode.SUCCESS) { 594 return true; 595 } else { 596 Log.e(TAG, "publish: error: " + statusString(status)); 597 return false; 598 } 599 } catch (RemoteException e) { 600 Log.e(TAG, "publish: exception: " + e); 601 return false; 602 } 603 } 604 605 /** 606 * Start or modify a service subscription session. 607 * 608 * @param transactionId transactionId Transaction ID for the transaction - 609 * used in the async callback to match with the original request. 610 * @param subscribeId ID of the requested session - 0 to request a new 611 * subscribe session. 612 * @param subscribeConfig Configuration of the discovery session. 613 */ subscribe(short transactionId, byte subscribeId, SubscribeConfig subscribeConfig)614 public boolean subscribe(short transactionId, byte subscribeId, 615 SubscribeConfig subscribeConfig) { 616 if (mDbg) { 617 Log.d(TAG, "subscribe: transactionId=" + transactionId + ", subscribeId=" + subscribeId 618 + ", config=" + subscribeConfig); 619 } 620 recordTransactionId(transactionId); 621 622 IWifiNanIface iface = mHal.getWifiNanIface(); 623 if (iface == null) { 624 Log.e(TAG, "subscribe: null interface"); 625 return false; 626 } 627 628 NanSubscribeRequest req = new NanSubscribeRequest(); 629 req.baseConfigs.sessionId = subscribeId; 630 req.baseConfigs.ttlSec = (short) subscribeConfig.mTtlSec; 631 req.baseConfigs.discoveryWindowPeriod = 1; 632 req.baseConfigs.discoveryCount = 0; 633 convertNativeByteArrayToArrayList(subscribeConfig.mServiceName, 634 req.baseConfigs.serviceName); 635 req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_ONCE; 636 convertNativeByteArrayToArrayList(subscribeConfig.mServiceSpecificInfo, 637 req.baseConfigs.serviceSpecificInfo); 638 convertNativeByteArrayToArrayList(subscribeConfig.mMatchFilter, 639 subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE 640 ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter); 641 req.baseConfigs.useRssiThreshold = false; 642 req.baseConfigs.disableDiscoveryTerminationIndication = 643 !subscribeConfig.mEnableTerminateNotification; 644 req.baseConfigs.disableMatchExpirationIndication = true; 645 req.baseConfigs.disableFollowupReceivedIndication = false; 646 647 req.baseConfigs.rangingRequired = 648 subscribeConfig.mMinDistanceMmSet || subscribeConfig.mMaxDistanceMmSet; 649 req.baseConfigs.configRangingIndications = 0; 650 // TODO: b/69428593 remove correction factors once HAL converted from CM to MM 651 if (subscribeConfig.mMinDistanceMmSet) { 652 req.baseConfigs.distanceEgressCm = (short) Math.min( 653 subscribeConfig.mMinDistanceMm / 10, Short.MAX_VALUE); 654 req.baseConfigs.configRangingIndications |= NanRangingIndication.EGRESS_MET_MASK; 655 } 656 if (subscribeConfig.mMaxDistanceMmSet) { 657 req.baseConfigs.distanceIngressCm = (short) Math.min( 658 subscribeConfig.mMaxDistanceMm / 10, Short.MAX_VALUE); 659 req.baseConfigs.configRangingIndications |= NanRangingIndication.INGRESS_MET_MASK; 660 } 661 662 // TODO: configure security 663 req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN; 664 665 req.subscribeType = subscribeConfig.mSubscribeType; 666 667 try { 668 WifiStatus status = iface.startSubscribeRequest(transactionId, req); 669 if (status.code == WifiStatusCode.SUCCESS) { 670 return true; 671 } else { 672 Log.e(TAG, "subscribe: error: " + statusString(status)); 673 return false; 674 } 675 } catch (RemoteException e) { 676 Log.e(TAG, "subscribe: exception: " + e); 677 return false; 678 } 679 } 680 681 /** 682 * Send a message through an existing discovery session. 683 * 684 * @param transactionId transactionId Transaction ID for the transaction - 685 * used in the async callback to match with the original request. 686 * @param pubSubId ID of the existing publish/subscribe session. 687 * @param requestorInstanceId ID of the peer to communicate with - obtained 688 * through a previous discovery (match) operation with that peer. 689 * @param dest MAC address of the peer to communicate with - obtained 690 * together with requestorInstanceId. 691 * @param message Message. 692 * @param messageId Arbitary integer from host (not sent to HAL - useful for 693 * testing/debugging at this level) 694 */ sendMessage(short transactionId, byte pubSubId, int requestorInstanceId, byte[] dest, byte[] message, int messageId)695 public boolean sendMessage(short transactionId, byte pubSubId, int requestorInstanceId, 696 byte[] dest, byte[] message, int messageId) { 697 if (mDbg) { 698 Log.d(TAG, 699 "sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId 700 + ", requestorInstanceId=" + requestorInstanceId + ", dest=" 701 + String.valueOf(HexEncoding.encode(dest)) + ", messageId=" + messageId 702 + ", message=" + (message == null ? "<null>" 703 : HexEncoding.encode(message)) + ", message.length=" + (message == null 704 ? 0 : message.length)); 705 } 706 recordTransactionId(transactionId); 707 708 IWifiNanIface iface = mHal.getWifiNanIface(); 709 if (iface == null) { 710 Log.e(TAG, "sendMessage: null interface"); 711 return false; 712 } 713 714 NanTransmitFollowupRequest req = new NanTransmitFollowupRequest(); 715 req.discoverySessionId = pubSubId; 716 req.peerId = requestorInstanceId; 717 copyArray(dest, req.addr); 718 req.isHighPriority = false; 719 req.shouldUseDiscoveryWindow = true; 720 convertNativeByteArrayToArrayList(message, req.serviceSpecificInfo); 721 req.disableFollowupResultIndication = false; 722 723 try { 724 WifiStatus status = iface.transmitFollowupRequest(transactionId, req); 725 if (status.code == WifiStatusCode.SUCCESS) { 726 return true; 727 } else { 728 Log.e(TAG, "sendMessage: error: " + statusString(status)); 729 return false; 730 } 731 } catch (RemoteException e) { 732 Log.e(TAG, "sendMessage: exception: " + e); 733 return false; 734 } 735 } 736 737 /** 738 * Terminate a publish discovery session. 739 * 740 * @param transactionId transactionId Transaction ID for the transaction - 741 * used in the async callback to match with the original request. 742 * @param pubSubId ID of the publish/subscribe session - obtained when 743 * creating a session. 744 */ stopPublish(short transactionId, byte pubSubId)745 public boolean stopPublish(short transactionId, byte pubSubId) { 746 if (mDbg) { 747 Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 748 } 749 recordTransactionId(transactionId); 750 751 IWifiNanIface iface = mHal.getWifiNanIface(); 752 if (iface == null) { 753 Log.e(TAG, "stopPublish: null interface"); 754 return false; 755 } 756 757 try { 758 WifiStatus status = iface.stopPublishRequest(transactionId, pubSubId); 759 if (status.code == WifiStatusCode.SUCCESS) { 760 return true; 761 } else { 762 Log.e(TAG, "stopPublish: error: " + statusString(status)); 763 return false; 764 } 765 } catch (RemoteException e) { 766 Log.e(TAG, "stopPublish: exception: " + e); 767 return false; 768 } 769 } 770 771 /** 772 * Terminate a subscribe discovery session. 773 * 774 * @param transactionId transactionId Transaction ID for the transaction - 775 * used in the async callback to match with the original request. 776 * @param pubSubId ID of the publish/subscribe session - obtained when 777 * creating a session. 778 */ stopSubscribe(short transactionId, byte pubSubId)779 public boolean stopSubscribe(short transactionId, byte pubSubId) { 780 if (mDbg) { 781 Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 782 } 783 recordTransactionId(transactionId); 784 785 IWifiNanIface iface = mHal.getWifiNanIface(); 786 if (iface == null) { 787 Log.e(TAG, "stopSubscribe: null interface"); 788 return false; 789 } 790 791 try { 792 WifiStatus status = iface.stopSubscribeRequest(transactionId, pubSubId); 793 if (status.code == WifiStatusCode.SUCCESS) { 794 return true; 795 } else { 796 Log.e(TAG, "stopSubscribe: error: " + statusString(status)); 797 return false; 798 } 799 } catch (RemoteException e) { 800 Log.e(TAG, "stopSubscribe: exception: " + e); 801 return false; 802 } 803 } 804 805 /** 806 * Create a Aware network interface. This only creates the Linux interface - it doesn't actually 807 * create the data connection. 808 * 809 * @param transactionId Transaction ID for the transaction - used in the async callback to 810 * match with the original request. 811 * @param interfaceName The name of the interface, e.g. "aware0". 812 */ createAwareNetworkInterface(short transactionId, String interfaceName)813 public boolean createAwareNetworkInterface(short transactionId, String interfaceName) { 814 if (mDbg) { 815 Log.v(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", " 816 + "interfaceName=" + interfaceName); 817 } 818 recordTransactionId(transactionId); 819 820 IWifiNanIface iface = mHal.getWifiNanIface(); 821 if (iface == null) { 822 Log.e(TAG, "createAwareNetworkInterface: null interface"); 823 return false; 824 } 825 826 try { 827 WifiStatus status = iface.createDataInterfaceRequest(transactionId, interfaceName); 828 if (status.code == WifiStatusCode.SUCCESS) { 829 return true; 830 } else { 831 Log.e(TAG, "createAwareNetworkInterface: error: " + statusString(status)); 832 return false; 833 } 834 } catch (RemoteException e) { 835 Log.e(TAG, "createAwareNetworkInterface: exception: " + e); 836 return false; 837 } 838 } 839 840 /** 841 * Deletes a Aware network interface. The data connection can (should?) be torn down previously. 842 * 843 * @param transactionId Transaction ID for the transaction - used in the async callback to 844 * match with the original request. 845 * @param interfaceName The name of the interface, e.g. "aware0". 846 */ deleteAwareNetworkInterface(short transactionId, String interfaceName)847 public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) { 848 if (mDbg) { 849 Log.v(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", " 850 + "interfaceName=" + interfaceName); 851 } 852 recordTransactionId(transactionId); 853 854 IWifiNanIface iface = mHal.getWifiNanIface(); 855 if (iface == null) { 856 Log.e(TAG, "deleteAwareNetworkInterface: null interface"); 857 return false; 858 } 859 860 try { 861 WifiStatus status = iface.deleteDataInterfaceRequest(transactionId, interfaceName); 862 if (status.code == WifiStatusCode.SUCCESS) { 863 return true; 864 } else { 865 Log.e(TAG, "deleteAwareNetworkInterface: error: " + statusString(status)); 866 return false; 867 } 868 } catch (RemoteException e) { 869 Log.e(TAG, "deleteAwareNetworkInterface: exception: " + e); 870 return false; 871 } 872 } 873 874 /** 875 * Initiates setting up a data-path between device and peer. Security is provided by either 876 * PMK or Passphrase (not both) - if both are null then an open (unencrypted) link is set up. 877 * 878 * @param transactionId Transaction ID for the transaction - used in the async callback to 879 * match with the original request. 880 * @param peerId ID of the peer ID to associate the data path with. A value of 0 881 * indicates that not associated with an existing session. 882 * @param channelRequestType Indicates whether the specified channel is available, if available 883 * requested or forced (resulting in failure if cannot be 884 * accommodated). 885 * @param channel The channel on which to set up the data-path. 886 * @param peer The MAC address of the peer to create a connection with. 887 * @param interfaceName The interface on which to create the data connection. 888 * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path. 889 * @param passphrase Passphrase for the data-path. 890 * @param isOutOfBand Is the data-path out-of-band (i.e. without a corresponding Aware discovery 891 * session). 892 * @param appInfo Arbitrary binary blob transmitted to the peer. 893 * @param capabilities The capabilities of the firmware. 894 */ initiateDataPath(short transactionId, int peerId, int channelRequestType, int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase, boolean isOutOfBand, byte[] appInfo, Capabilities capabilities)895 public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType, 896 int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase, 897 boolean isOutOfBand, byte[] appInfo, Capabilities capabilities) { 898 if (mDbg) { 899 Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId 900 + ", channelRequestType=" + channelRequestType + ", channel=" + channel 901 + ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName=" 902 + interfaceName + ", pmk=" + ((pmk == null) ? "<null>" : "<*>") 903 + ", passphrase=" + (TextUtils.isEmpty(passphrase) ? "<empty>" : "<*>") 904 + ", isOutOfBand=" + isOutOfBand + ", appInfo.length=" 905 + ((appInfo == null) ? 0 : appInfo.length) + ", capabilities=" + capabilities); 906 } 907 recordTransactionId(transactionId); 908 909 IWifiNanIface iface = mHal.getWifiNanIface(); 910 if (iface == null) { 911 Log.e(TAG, "initiateDataPath: null interface"); 912 return false; 913 } 914 915 if (capabilities == null) { 916 Log.e(TAG, "initiateDataPath: null capabilities"); 917 return false; 918 } 919 920 NanInitiateDataPathRequest req = new NanInitiateDataPathRequest(); 921 req.peerId = peerId; 922 copyArray(peer, req.peerDiscMacAddr); 923 req.channelRequestType = channelRequestType; 924 req.channel = channel; 925 req.ifaceName = interfaceName; 926 req.securityConfig.securityType = NanDataPathSecurityType.OPEN; 927 if (pmk != null && pmk.length != 0) { 928 req.securityConfig.cipherType = getStrongestCipherSuiteType( 929 capabilities.supportedCipherSuites); 930 req.securityConfig.securityType = NanDataPathSecurityType.PMK; 931 copyArray(pmk, req.securityConfig.pmk); 932 } 933 if (passphrase != null && passphrase.length() != 0) { 934 req.securityConfig.cipherType = getStrongestCipherSuiteType( 935 capabilities.supportedCipherSuites); 936 req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE; 937 convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase); 938 } 939 940 if (req.securityConfig.securityType != NanDataPathSecurityType.OPEN && isOutOfBand) { 941 convertNativeByteArrayToArrayList( 942 SERVICE_NAME_FOR_OOB_DATA_PATH.getBytes(StandardCharsets.UTF_8), 943 req.serviceNameOutOfBand); 944 } 945 convertNativeByteArrayToArrayList(appInfo, req.appInfo); 946 947 try { 948 WifiStatus status = iface.initiateDataPathRequest(transactionId, req); 949 if (status.code == WifiStatusCode.SUCCESS) { 950 return true; 951 } else { 952 Log.e(TAG, "initiateDataPath: error: " + statusString(status)); 953 return false; 954 } 955 } catch (RemoteException e) { 956 Log.e(TAG, "initiateDataPath: exception: " + e); 957 return false; 958 } 959 } 960 961 /** 962 * Responds to a data request from a peer. Security is provided by either PMK or Passphrase (not 963 * both) - if both are null then an open (unencrypted) link is set up. 964 * 965 * @param transactionId Transaction ID for the transaction - used in the async callback to 966 * match with the original request. 967 * @param accept Accept (true) or reject (false) the original call. 968 * @param ndpId The NDP (Aware data path) ID. Obtained from the request callback. 969 * @param interfaceName The interface on which the data path will be setup. Obtained from the 970 * request callback. 971 * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path. 972 * @param passphrase Passphrase for the data-path. 973 * @param appInfo Arbitrary binary blob transmitted to the peer. 974 * @param isOutOfBand Is the data-path out-of-band (i.e. without a corresponding Aware discovery 975 * session). 976 * @param capabilities The capabilities of the firmware. 977 */ respondToDataPathRequest(short transactionId, boolean accept, int ndpId, String interfaceName, byte[] pmk, String passphrase, byte[] appInfo, boolean isOutOfBand, Capabilities capabilities)978 public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId, 979 String interfaceName, byte[] pmk, String passphrase, byte[] appInfo, 980 boolean isOutOfBand, Capabilities capabilities) { 981 if (mDbg) { 982 Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept=" 983 + accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName 984 + ", appInfo.length=" + ((appInfo == null) ? 0 : appInfo.length)); 985 } 986 recordTransactionId(transactionId); 987 988 IWifiNanIface iface = mHal.getWifiNanIface(); 989 if (iface == null) { 990 Log.e(TAG, "respondToDataPathRequest: null interface"); 991 return false; 992 } 993 994 if (capabilities == null) { 995 Log.e(TAG, "initiateDataPath: null capabilities"); 996 return false; 997 } 998 999 NanRespondToDataPathIndicationRequest req = new NanRespondToDataPathIndicationRequest(); 1000 req.acceptRequest = accept; 1001 req.ndpInstanceId = ndpId; 1002 req.ifaceName = interfaceName; 1003 req.securityConfig.securityType = NanDataPathSecurityType.OPEN; 1004 if (pmk != null && pmk.length != 0) { 1005 req.securityConfig.cipherType = getStrongestCipherSuiteType( 1006 capabilities.supportedCipherSuites); 1007 req.securityConfig.securityType = NanDataPathSecurityType.PMK; 1008 copyArray(pmk, req.securityConfig.pmk); 1009 } 1010 if (passphrase != null && passphrase.length() != 0) { 1011 req.securityConfig.cipherType = getStrongestCipherSuiteType( 1012 capabilities.supportedCipherSuites); 1013 req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE; 1014 convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase); 1015 } 1016 1017 if (req.securityConfig.securityType != NanDataPathSecurityType.OPEN && isOutOfBand) { 1018 convertNativeByteArrayToArrayList( 1019 SERVICE_NAME_FOR_OOB_DATA_PATH.getBytes(StandardCharsets.UTF_8), 1020 req.serviceNameOutOfBand); 1021 } 1022 convertNativeByteArrayToArrayList(appInfo, req.appInfo); 1023 1024 try { 1025 WifiStatus status = iface.respondToDataPathIndicationRequest(transactionId, req); 1026 if (status.code == WifiStatusCode.SUCCESS) { 1027 return true; 1028 } else { 1029 Log.e(TAG, "respondToDataPathRequest: error: " + statusString(status)); 1030 return false; 1031 } 1032 } catch (RemoteException e) { 1033 Log.e(TAG, "respondToDataPathRequest: exception: " + e); 1034 return false; 1035 } 1036 } 1037 1038 /** 1039 * Terminate an existing data-path (does not delete the interface). 1040 * 1041 * @param transactionId Transaction ID for the transaction - used in the async callback to 1042 * match with the original request. 1043 * @param ndpId The NDP (Aware data path) ID to be terminated. 1044 */ endDataPath(short transactionId, int ndpId)1045 public boolean endDataPath(short transactionId, int ndpId) { 1046 if (mDbg) { 1047 Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId); 1048 } 1049 recordTransactionId(transactionId); 1050 1051 IWifiNanIface iface = mHal.getWifiNanIface(); 1052 if (iface == null) { 1053 Log.e(TAG, "endDataPath: null interface"); 1054 return false; 1055 } 1056 1057 try { 1058 WifiStatus status = iface.terminateDataPathRequest(transactionId, ndpId); 1059 if (status.code == WifiStatusCode.SUCCESS) { 1060 return true; 1061 } else { 1062 Log.e(TAG, "endDataPath: error: " + statusString(status)); 1063 return false; 1064 } 1065 } catch (RemoteException e) { 1066 Log.e(TAG, "endDataPath: exception: " + e); 1067 return false; 1068 } 1069 } 1070 1071 1072 // utilities 1073 1074 /** 1075 * Update the NAN configuration to reflect the current power settings. 1076 */ updateConfigForPowerSettings(NanConfigRequest req, NanConfigRequestSupplemental configSupplemental12, boolean isInteractive, boolean isIdle)1077 private void updateConfigForPowerSettings(NanConfigRequest req, 1078 NanConfigRequestSupplemental configSupplemental12, boolean isInteractive, 1079 boolean isIdle) { 1080 String key = POWER_PARAM_DEFAULT_KEY; 1081 if (isIdle) { 1082 key = POWER_PARAM_IDLE_KEY; 1083 } else if (!isInteractive) { 1084 key = POWER_PARAM_INACTIVE_KEY; 1085 } 1086 1087 updateSingleConfigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ], 1088 mSettablePowerParameters.get(key).get(PARAM_DW_5GHZ)); 1089 updateSingleConfigForPowerSettings(req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ], 1090 mSettablePowerParameters.get(key).get(PARAM_DW_24GHZ)); 1091 1092 configSupplemental12.discoveryBeaconIntervalMs = mSettablePowerParameters.get(key).get( 1093 PARAM_DISCOVERY_BEACON_INTERVAL_MS); 1094 configSupplemental12.numberOfSpatialStreamsInDiscovery = mSettablePowerParameters.get( 1095 key).get(PARAM_NUM_SS_IN_DISCOVERY); 1096 configSupplemental12.enableDiscoveryWindowEarlyTermination = mSettablePowerParameters.get( 1097 key).get(PARAM_ENABLE_DW_EARLY_TERM) != 0; 1098 } 1099 updateSingleConfigForPowerSettings(NanBandSpecificConfig cfg, int override)1100 private void updateSingleConfigForPowerSettings(NanBandSpecificConfig cfg, int override) { 1101 if (override != -1) { 1102 cfg.validDiscoveryWindowIntervalVal = true; 1103 cfg.discoveryWindowIntervalVal = (byte) override; 1104 } 1105 } 1106 1107 /** 1108 * Returns the strongest supported cipher suite. 1109 * 1110 * Baseline is very simple: 256 > 128 > 0. 1111 */ getStrongestCipherSuiteType(int supportedCipherSuites)1112 private int getStrongestCipherSuiteType(int supportedCipherSuites) { 1113 if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_256_MASK) != 0) { 1114 return NanCipherSuiteType.SHARED_KEY_256_MASK; 1115 } 1116 if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_128_MASK) != 0) { 1117 return NanCipherSuiteType.SHARED_KEY_128_MASK; 1118 } 1119 return NanCipherSuiteType.NONE; 1120 } 1121 1122 /** 1123 * Converts a byte[] to an ArrayList<Byte>. Fills in the entries of the 'to' array if 1124 * provided (non-null), otherwise creates and returns a new ArrayList<>. 1125 * 1126 * @param from The input byte[] to convert from. 1127 * @param to An optional ArrayList<> to fill in from 'from'. 1128 * 1129 * @return A newly allocated ArrayList<> if 'to' is null, otherwise null. 1130 */ convertNativeByteArrayToArrayList(byte[] from, ArrayList<Byte> to)1131 private ArrayList<Byte> convertNativeByteArrayToArrayList(byte[] from, ArrayList<Byte> to) { 1132 if (from == null) { 1133 from = new byte[0]; 1134 } 1135 1136 if (to == null) { 1137 to = new ArrayList<>(from.length); 1138 } else { 1139 to.ensureCapacity(from.length); 1140 } 1141 for (int i = 0; i < from.length; ++i) { 1142 to.add(from[i]); 1143 } 1144 return to; 1145 } 1146 copyArray(byte[] from, byte[] to)1147 private void copyArray(byte[] from, byte[] to) { 1148 if (from == null || to == null || from.length != to.length) { 1149 Log.e(TAG, "copyArray error: from=" + from + ", to=" + to); 1150 return; 1151 } 1152 for (int i = 0; i < from.length; ++i) { 1153 to[i] = from[i]; 1154 } 1155 } 1156 statusString(WifiStatus status)1157 private static String statusString(WifiStatus status) { 1158 if (status == null) { 1159 return "status=null"; 1160 } 1161 StringBuilder sb = new StringBuilder(); 1162 sb.append(status.code).append(" (").append(status.description).append(")"); 1163 return sb.toString(); 1164 } 1165 1166 /** 1167 * Dump the internal state of the class. 1168 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)1169 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1170 pw.println("WifiAwareNativeApi:"); 1171 pw.println(" mSettableParameters: " + mSettableParameters); 1172 mHal.dump(fd, pw, args); 1173 } 1174 } 1175