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