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.net.MacAddress; 20 import android.net.wifi.aware.AwareParams; 21 import android.net.wifi.aware.ConfigRequest; 22 import android.net.wifi.aware.PublishConfig; 23 import android.net.wifi.aware.SubscribeConfig; 24 import android.net.wifi.aware.WifiAwareDataPathSecurityConfig; 25 import android.net.wifi.util.HexEncoding; 26 import android.util.ArrayMap; 27 import android.util.Log; 28 import android.util.SparseIntArray; 29 30 import com.android.modules.utils.BasicShellCommandHandler; 31 import com.android.server.wifi.hal.WifiNanIface; 32 import com.android.server.wifi.hal.WifiNanIface.PowerParameters; 33 34 import java.io.FileDescriptor; 35 import java.io.PrintWriter; 36 import java.util.Arrays; 37 import java.util.HashMap; 38 import java.util.Map; 39 40 /** 41 * Translates Wi-Fi Aware requests from the framework to the HAL. 42 * 43 * Delegates the management of the NAN interface to WifiAwareNativeManager. 44 */ 45 public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellCommand { 46 private static final String TAG = "WifiAwareNativeApi"; 47 private boolean mVdbg = false; // STOPSHIP if true 48 private boolean mVerboseLoggingEnabled = false; 49 50 private final WifiAwareNativeManager mHal; 51 private SparseIntArray mTransactionIds; // VDBG only! 52 WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager)53 public WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager) { 54 mHal = wifiAwareNativeManager; 55 onReset(); 56 } 57 58 /** 59 * Enable/Disable verbose logging. 60 * 61 */ enableVerboseLogging(boolean verboseEnabled, boolean vDbg)62 public void enableVerboseLogging(boolean verboseEnabled, boolean vDbg) { 63 mVerboseLoggingEnabled = verboseEnabled; 64 mVdbg = vDbg; 65 } 66 recordTransactionId(int transactionId)67 private void recordTransactionId(int transactionId) { 68 if (!mVdbg) return; 69 70 if (transactionId == 0) { 71 return; // tid == 0 is used as a placeholder transaction ID in several commands 72 } 73 74 if (mTransactionIds == null) { 75 mTransactionIds = new SparseIntArray(); 76 } 77 int count = mTransactionIds.get(transactionId); 78 if (count != 0) { 79 Log.wtf(TAG, "Repeated transaction ID == " + transactionId); 80 } 81 mTransactionIds.append(transactionId, count + 1); 82 } 83 84 /* 85 * Parameters settable through the shell command. 86 * see wifi/1.0/types.hal NanBandSpecificConfig.discoveryWindowIntervalVal and 87 * wifi/1.2/types.hal NanConfigRequestSupplemental_1_2 for description 88 */ 89 /* package */ static final String POWER_PARAM_DEFAULT_KEY = "default"; 90 /* package */ static final String POWER_PARAM_INACTIVE_KEY = "inactive"; 91 /* package */ static final String POWER_PARAM_IDLE_KEY = "idle"; 92 93 /* package */ static final String PARAM_DW_24GHZ = "dw_24ghz"; 94 private static final int PARAM_DW_24GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms 95 private static final int PARAM_DW_24GHZ_INACTIVE = 4; // 4 -> DW=8, latency=4s 96 private static final int PARAM_DW_24GHZ_IDLE = 4; // == inactive 97 98 /* package */ static final String PARAM_DW_5GHZ = "dw_5ghz"; 99 private static final int PARAM_DW_5GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms 100 private static final int PARAM_DW_5GHZ_INACTIVE = 0; // 0 = disabled 101 private static final int PARAM_DW_5GHZ_IDLE = 0; // == inactive 102 103 /* package */ static final String PARAM_DW_6GHZ = "dw_6ghz"; 104 private static final int PARAM_DW_6GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms 105 private static final int PARAM_DW_6GHZ_INACTIVE = 0; // 0 = disabled 106 private static final int PARAM_DW_6GHZ_IDLE = 0; // == inactive 107 108 /* package */ static final String PARAM_DISCOVERY_BEACON_INTERVAL_MS = 109 "disc_beacon_interval_ms"; 110 private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT = 0; // Firmware defaults 111 private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE = 0; // Firmware defaults 112 private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE = 0; // Firmware defaults 113 114 /* package */ static final String PARAM_NUM_SS_IN_DISCOVERY = "num_ss_in_discovery"; 115 private static final int PARAM_NUM_SS_IN_DISCOVERY_DEFAULT = 0; // Firmware defaults 116 private static final int PARAM_NUM_SS_IN_DISCOVERY_INACTIVE = 0; // Firmware defaults 117 private static final int PARAM_NUM_SS_IN_DISCOVERY_IDLE = 0; // Firmware defaults 118 119 /* package */ static final String PARAM_ENABLE_DW_EARLY_TERM = "enable_dw_early_term"; 120 private static final int PARAM_ENABLE_DW_EARLY_TERM_DEFAULT = 0; // boolean: 0 = false 121 private static final int PARAM_ENABLE_DW_EARLY_TERM_INACTIVE = 0; // boolean: 0 = false 122 private static final int PARAM_ENABLE_DW_EARLY_TERM_IDLE = 0; // boolean: 0 = false 123 124 /* package */ static final String PARAM_MAC_RANDOM_INTERVAL_SEC = "mac_random_interval_sec"; 125 private static final int PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT = 1800; // 30 minutes 126 127 private final Map<String, Map<String, Integer>> mSettablePowerParameters = new HashMap<>(); 128 private final Map<String, Integer> mSettableParameters = new HashMap<>(); 129 private final Map<String, Integer> mExternalSetParams = new ArrayMap<>(); 130 131 /** 132 * Accept using parameter from external to config the Aware 133 */ setAwareParams(AwareParams parameters)134 public void setAwareParams(AwareParams parameters) { 135 mExternalSetParams.clear(); 136 if (parameters == null) { 137 return; 138 } 139 if (mVerboseLoggingEnabled) { 140 Log.v(TAG, "setting Aware Parameters=" + parameters); 141 } 142 if (parameters.getDiscoveryWindowWakeInterval24Ghz() > 0 143 && parameters.getDiscoveryWindowWakeInterval24Ghz() <= 5) { 144 mExternalSetParams.put(PARAM_DW_24GHZ, 145 parameters.getDiscoveryWindowWakeInterval24Ghz()); 146 } 147 if (parameters.getDiscoveryWindowWakeInterval5Ghz() >= 0 148 && parameters.getDiscoveryWindowWakeInterval5Ghz() <= 5) { 149 mExternalSetParams.put(PARAM_DW_5GHZ, parameters.getDiscoveryWindowWakeInterval5Ghz()); 150 } 151 if (parameters.getDiscoveryBeaconIntervalMillis() > 0) { 152 mExternalSetParams.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 153 parameters.getDiscoveryBeaconIntervalMillis()); 154 } 155 if (parameters.getNumSpatialStreamsInDiscovery() > 0) { 156 mExternalSetParams.put(PARAM_NUM_SS_IN_DISCOVERY, 157 parameters.getNumSpatialStreamsInDiscovery()); 158 } 159 if (parameters.getMacRandomizationIntervalSeconds() > 0 160 && parameters.getMacRandomizationIntervalSeconds() <= 1800) { 161 mExternalSetParams.put(PARAM_MAC_RANDOM_INTERVAL_SEC, 162 parameters.getMacRandomizationIntervalSeconds()); 163 } 164 if (parameters.isDwEarlyTerminationEnabled()) { 165 mExternalSetParams.put(PARAM_ENABLE_DW_EARLY_TERM, 1); 166 } 167 } 168 169 170 /** 171 * Interpreter of adb shell command 'adb shell wifiaware native_api ...'. 172 * 173 * @return -1 if parameter not recognized or invalid value, 0 otherwise. 174 */ 175 @Override onCommand(BasicShellCommandHandler parentShell)176 public int onCommand(BasicShellCommandHandler parentShell) { 177 final PrintWriter pw = parentShell.getErrPrintWriter(); 178 179 String subCmd = parentShell.getNextArgRequired(); 180 if (mVdbg) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'"); 181 switch (subCmd) { 182 case "set": { 183 String name = parentShell.getNextArgRequired(); 184 if (mVdbg) Log.v(TAG, "onCommand: name='" + name + "'"); 185 if (!mSettableParameters.containsKey(name)) { 186 pw.println("Unknown parameter name -- '" + name + "'"); 187 return -1; 188 } 189 190 String valueStr = parentShell.getNextArgRequired(); 191 if (mVdbg) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'"); 192 int value; 193 try { 194 value = Integer.valueOf(valueStr); 195 } catch (NumberFormatException e) { 196 pw.println("Can't convert value to integer -- '" + valueStr + "'"); 197 return -1; 198 } 199 mSettableParameters.put(name, value); 200 return 0; 201 } 202 case "set-power": { 203 String mode = parentShell.getNextArgRequired(); 204 String name = parentShell.getNextArgRequired(); 205 String valueStr = parentShell.getNextArgRequired(); 206 207 if (mVdbg) { 208 Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'" + ", value='" 209 + valueStr + "'"); 210 } 211 212 if (!mSettablePowerParameters.containsKey(mode)) { 213 pw.println("Unknown mode name -- '" + mode + "'"); 214 return -1; 215 } 216 if (!mSettablePowerParameters.get(mode).containsKey(name)) { 217 pw.println("Unknown parameter name '" + name + "' in mode '" + mode + "'"); 218 return -1; 219 } 220 221 int value; 222 try { 223 value = Integer.valueOf(valueStr); 224 } catch (NumberFormatException e) { 225 pw.println("Can't convert value to integer -- '" + valueStr + "'"); 226 return -1; 227 } 228 mSettablePowerParameters.get(mode).put(name, value); 229 return 0; 230 } 231 case "get": { 232 String name = parentShell.getNextArgRequired(); 233 if (mVdbg) Log.v(TAG, "onCommand: name='" + name + "'"); 234 if (!mSettableParameters.containsKey(name)) { 235 pw.println("Unknown parameter name -- '" + name + "'"); 236 return -1; 237 } 238 239 parentShell.getOutPrintWriter().println((int) mSettableParameters.get(name)); 240 return 0; 241 } 242 case "get-power": { 243 String mode = parentShell.getNextArgRequired(); 244 String name = parentShell.getNextArgRequired(); 245 if (mVdbg) Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'"); 246 if (!mSettablePowerParameters.containsKey(mode)) { 247 pw.println("Unknown mode -- '" + mode + "'"); 248 return -1; 249 } 250 if (!mSettablePowerParameters.get(mode).containsKey(name)) { 251 pw.println("Unknown parameter name -- '" + name + "' in mode '" + mode + "'"); 252 return -1; 253 } 254 255 parentShell.getOutPrintWriter().println( 256 (int) mSettablePowerParameters.get(mode).get(name)); 257 return 0; 258 } 259 default: 260 pw.println("Unknown 'wifiaware native_api <cmd>'"); 261 } 262 263 return -1; 264 } 265 266 @Override onReset()267 public void onReset() { 268 Map<String, Integer> defaultMap = new HashMap<>(); 269 defaultMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_DEFAULT); 270 defaultMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_DEFAULT); 271 defaultMap.put(PARAM_DW_6GHZ, PARAM_DW_6GHZ_DEFAULT); 272 defaultMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 273 PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT); 274 defaultMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_DEFAULT); 275 defaultMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_DEFAULT); 276 277 Map<String, Integer> inactiveMap = new HashMap<>(); 278 inactiveMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_INACTIVE); 279 inactiveMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_INACTIVE); 280 inactiveMap.put(PARAM_DW_6GHZ, PARAM_DW_6GHZ_INACTIVE); 281 inactiveMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 282 PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE); 283 inactiveMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_INACTIVE); 284 inactiveMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_INACTIVE); 285 286 Map<String, Integer> idleMap = new HashMap<>(); 287 idleMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_IDLE); 288 idleMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_IDLE); 289 idleMap.put(PARAM_DW_6GHZ, PARAM_DW_6GHZ_IDLE); 290 idleMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS, 291 PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE); 292 idleMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_IDLE); 293 idleMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_IDLE); 294 295 mSettablePowerParameters.put(POWER_PARAM_DEFAULT_KEY, defaultMap); 296 mSettablePowerParameters.put(POWER_PARAM_INACTIVE_KEY, inactiveMap); 297 mSettablePowerParameters.put(POWER_PARAM_IDLE_KEY, idleMap); 298 299 mSettableParameters.put(PARAM_MAC_RANDOM_INTERVAL_SEC, 300 PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT); 301 mExternalSetParams.clear(); 302 } 303 304 @Override onHelp(String command, BasicShellCommandHandler parentShell)305 public void onHelp(String command, BasicShellCommandHandler parentShell) { 306 final PrintWriter pw = parentShell.getOutPrintWriter(); 307 308 pw.println(" " + command); 309 pw.println(" set <name> <value>: sets named parameter to value. Names: " 310 + mSettableParameters.keySet()); 311 pw.println(" set-power <mode> <name> <value>: sets named power parameter to value." 312 + " Modes: " + mSettablePowerParameters.keySet() 313 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet()); 314 pw.println(" get <name>: gets named parameter value. Names: " 315 + mSettableParameters.keySet()); 316 pw.println(" get-power <mode> <name>: gets named parameter value." 317 + " Modes: " + mSettablePowerParameters.keySet() 318 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet()); 319 } 320 321 /** 322 * Query the firmware's capabilities. 323 * 324 * @param transactionId Transaction ID for the transaction - used in the async callback to 325 * match with the original request. 326 */ getCapabilities(short transactionId)327 public boolean getCapabilities(short transactionId) { 328 if (mVerboseLoggingEnabled) Log.v(TAG, "getCapabilities: transactionId=" + transactionId); 329 recordTransactionId(transactionId); 330 331 WifiNanIface iface = mHal.getWifiNanIface(); 332 if (iface == null) { 333 Log.e(TAG, "getCapabilities: null interface"); 334 return false; 335 } 336 return iface.getCapabilities(transactionId); 337 } 338 339 /** 340 * Enable and configure Aware. 341 * @param transactionId Transaction ID for the transaction - used in the 342 * async callback to match with the original request. 343 * @param configRequest Requested Aware configuration. 344 * @param notifyIdentityChange Indicates whether or not to get address change callbacks. 345 * @param initialConfiguration Specifies whether initial configuration 346 * (true) or an update (false) to the configuration. 347 * @param isInteractive PowerManager.isInteractive 348 * @param isIdle PowerManager.isIdle 349 * @param rangingEnabled Indicates whether or not enable ranging. 350 * @param isInstantCommunicationEnabled Indicates whether or not enable instant communication 351 * @param instantModeChannel 352 * @param clusterId the id of the cluster to join. 353 */ enableAndConfigure(short transactionId, ConfigRequest configRequest, boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive, boolean isIdle, boolean rangingEnabled, boolean isInstantCommunicationEnabled, int instantModeChannel, int clusterId)354 public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest, 355 boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive, 356 boolean isIdle, boolean rangingEnabled, boolean isInstantCommunicationEnabled, 357 int instantModeChannel, int clusterId) { 358 Log.d(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest=" 359 + configRequest + ", notifyIdentityChange=" + notifyIdentityChange 360 + ", initialConfiguration=" + initialConfiguration 361 + ", isInteractive=" + isInteractive + ", isIdle=" + isIdle 362 + ", isRangingEnabled=" + rangingEnabled 363 + ", isInstantCommunicationEnabled=" + isInstantCommunicationEnabled 364 + ", instantModeChannel=" + instantModeChannel 365 + ", clusterId=" + clusterId); 366 recordTransactionId(transactionId); 367 368 WifiNanIface iface = mHal.getWifiNanIface(); 369 if (iface == null) { 370 Log.e(TAG, "enableAndConfigure: null interface"); 371 return false; 372 } 373 return iface.enableAndConfigure(transactionId, configRequest, notifyIdentityChange, 374 initialConfiguration, rangingEnabled, 375 isInstantCommunicationEnabled, instantModeChannel, clusterId, 376 mExternalSetParams.getOrDefault(PARAM_MAC_RANDOM_INTERVAL_SEC, 377 mSettableParameters.get(PARAM_MAC_RANDOM_INTERVAL_SEC)), 378 getPowerParameters(isInteractive, isIdle)); 379 } 380 381 /** 382 * Disable Aware. 383 * 384 * @param transactionId transactionId Transaction ID for the transaction - 385 * used in the async callback to match with the original request. 386 */ disable(short transactionId)387 public boolean disable(short transactionId) { 388 if (mVerboseLoggingEnabled) Log.d(TAG, "disable"); 389 recordTransactionId(transactionId); 390 391 WifiNanIface iface = mHal.getWifiNanIface(); 392 if (iface == null) { 393 Log.e(TAG, "disable: null interface"); 394 return false; 395 } 396 boolean result = iface.disable(transactionId); 397 return result; 398 } 399 400 /** 401 * Start or modify a service publish session. 402 * @param transactionId transactionId Transaction ID for the transaction - 403 * used in the async callback to match with the original request. 404 * @param publishId ID of the requested session - 0 to request a new publish 405 * session. 406 * @param publishConfig Configuration of the discovery session. 407 * @param nik 408 */ publish(short transactionId, byte publishId, PublishConfig publishConfig, byte[] nik)409 public boolean publish(short transactionId, byte publishId, PublishConfig publishConfig, 410 byte[] nik) { 411 if (mVerboseLoggingEnabled) { 412 Log.d(TAG, "publish: transactionId=" + transactionId + ", publishId=" + publishId 413 + ", config=" + publishConfig); 414 } 415 recordTransactionId(transactionId); 416 417 WifiNanIface iface = mHal.getWifiNanIface(); 418 if (iface == null) { 419 Log.e(TAG, "publish: null interface"); 420 return false; 421 } 422 return iface.publish(transactionId, publishId, publishConfig, nik); 423 } 424 425 /** 426 * Start or modify a service subscription session. 427 * @param transactionId transactionId Transaction ID for the transaction - 428 * used in the async callback to match with the original request. 429 * @param subscribeId ID of the requested session - 0 to request a new 430 * subscribe session. 431 * @param subscribeConfig Configuration of the discovery session. 432 * @param nik 433 */ subscribe(short transactionId, byte subscribeId, SubscribeConfig subscribeConfig, byte[] nik)434 public boolean subscribe(short transactionId, byte subscribeId, 435 SubscribeConfig subscribeConfig, byte[] nik) { 436 if (mVerboseLoggingEnabled) { 437 Log.d(TAG, "subscribe: transactionId=" + transactionId + ", subscribeId=" + subscribeId 438 + ", config=" + subscribeConfig); 439 } 440 recordTransactionId(transactionId); 441 442 WifiNanIface iface = mHal.getWifiNanIface(); 443 if (iface == null) { 444 Log.e(TAG, "subscribe: null interface"); 445 return false; 446 } 447 return iface.subscribe(transactionId, subscribeId, subscribeConfig, nik); 448 } 449 450 /** 451 * Send a message through an existing discovery session. 452 * 453 * @param transactionId transactionId Transaction ID for the transaction - 454 * used in the async callback to match with the original request. 455 * @param pubSubId ID of the existing publish/subscribe session. 456 * @param requestorInstanceId ID of the peer to communicate with - obtained 457 * through a previous discovery (match) operation with that peer. 458 * @param dest MAC address of the peer to communicate with - obtained 459 * together with requestorInstanceId. 460 * @param message Message. 461 * @param messageId Arbitary integer from host (not sent to HAL - useful for 462 * testing/debugging at this level) 463 */ sendMessage(short transactionId, byte pubSubId, int requestorInstanceId, byte[] dest, byte[] message, int messageId)464 public boolean sendMessage(short transactionId, byte pubSubId, int requestorInstanceId, 465 byte[] dest, byte[] message, int messageId) { 466 if (mVerboseLoggingEnabled) { 467 Log.d(TAG, 468 "sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId 469 + ", requestorInstanceId=" + requestorInstanceId + ", dest=" 470 + String.valueOf(HexEncoding.encode(dest)) + ", messageId=" + messageId 471 + ", message=" + (message == null ? "<null>" 472 : HexEncoding.encode(message)) + ", message.length=" + (message == null 473 ? 0 : message.length)); 474 } 475 recordTransactionId(transactionId); 476 477 WifiNanIface iface = mHal.getWifiNanIface(); 478 if (iface == null) { 479 Log.e(TAG, "sendMessage: null interface"); 480 return false; 481 } 482 483 try { 484 MacAddress destMac = MacAddress.fromBytes(dest); 485 return iface.sendMessage( 486 transactionId, pubSubId, requestorInstanceId, destMac, message); 487 } catch (IllegalArgumentException e) { 488 Log.e(TAG, "Invalid dest mac received: " + Arrays.toString(dest)); 489 return false; 490 } 491 } 492 493 /** 494 * Terminate a publish discovery session. 495 * 496 * @param transactionId transactionId Transaction ID for the transaction - 497 * used in the async callback to match with the original request. 498 * @param pubSubId ID of the publish/subscribe session - obtained when 499 * creating a session. 500 */ stopPublish(short transactionId, byte pubSubId)501 public boolean stopPublish(short transactionId, byte pubSubId) { 502 if (mVerboseLoggingEnabled) { 503 Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 504 } 505 recordTransactionId(transactionId); 506 507 WifiNanIface iface = mHal.getWifiNanIface(); 508 if (iface == null) { 509 Log.e(TAG, "stopPublish: null interface"); 510 return false; 511 } 512 return iface.stopPublish(transactionId, pubSubId); 513 } 514 515 /** 516 * Terminate a subscribe discovery session. 517 * 518 * @param transactionId transactionId Transaction ID for the transaction - 519 * used in the async callback to match with the original request. 520 * @param pubSubId ID of the publish/subscribe session - obtained when 521 * creating a session. 522 */ stopSubscribe(short transactionId, byte pubSubId)523 public boolean stopSubscribe(short transactionId, byte pubSubId) { 524 if (mVerboseLoggingEnabled) { 525 Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 526 } 527 recordTransactionId(transactionId); 528 529 WifiNanIface iface = mHal.getWifiNanIface(); 530 if (iface == null) { 531 Log.e(TAG, "stopSubscribe: null interface"); 532 return false; 533 } 534 return iface.stopSubscribe(transactionId, pubSubId); 535 } 536 537 /** 538 * Create a Aware network interface. This only creates the Linux interface - it doesn't actually 539 * create the data connection. 540 * 541 * @param transactionId Transaction ID for the transaction - used in the async callback to 542 * match with the original request. 543 * @param interfaceName The name of the interface, e.g. "aware0". 544 */ createAwareNetworkInterface(short transactionId, String interfaceName)545 public boolean createAwareNetworkInterface(short transactionId, String interfaceName) { 546 Log.d(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", " 547 + "interfaceName=" + interfaceName); 548 recordTransactionId(transactionId); 549 550 WifiNanIface iface = mHal.getWifiNanIface(); 551 if (iface == null) { 552 Log.e(TAG, "createAwareNetworkInterface: null interface"); 553 return false; 554 } 555 return iface.createAwareNetworkInterface(transactionId, interfaceName); 556 } 557 558 /** 559 * Deletes a Aware network interface. The data connection can (should?) be torn down previously. 560 * 561 * @param transactionId Transaction ID for the transaction - used in the async callback to 562 * match with the original request. 563 * @param interfaceName The name of the interface, e.g. "aware0". 564 */ deleteAwareNetworkInterface(short transactionId, String interfaceName)565 public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) { 566 Log.d(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", " 567 + "interfaceName=" + interfaceName); 568 recordTransactionId(transactionId); 569 570 WifiNanIface iface = mHal.getWifiNanIface(); 571 if (iface == null) { 572 Log.e(TAG, "deleteAwareNetworkInterface: null interface"); 573 return false; 574 } 575 return iface.deleteAwareNetworkInterface(transactionId, interfaceName); 576 } 577 578 /** 579 * Initiates setting up a data-path between device and peer. Security is provided by either 580 * PMK or Passphrase (not both) - if both are null then an open (unencrypted) link is set up. 581 * 582 * @param transactionId Transaction ID for the transaction - used in the async callback to 583 * match with the original request. 584 * @param peerId ID of the peer ID to associate the data path with. A value of 0 585 * indicates that not associated with an existing session. 586 * @param channelRequestType Indicates whether the specified channel is available, if available 587 * requested or forced (resulting in failure if cannot be 588 * accommodated). 589 * @param channel The channel on which to set up the data-path. 590 * @param peer The MAC address of the peer to create a connection with. 591 * @param interfaceName The interface on which to create the data connection. 592 * @param isOutOfBand Is the data-path out-of-band (i.e. without a corresponding Aware 593 * discovery 594 * session). 595 * @param appInfo Arbitrary binary blob transmitted to the peer. 596 * @param capabilities The capabilities of the firmware. 597 * @param securityConfig Security config to encrypt the data-path 598 */ initiateDataPath(short transactionId, int peerId, int channelRequestType, int channel, byte[] peer, String interfaceName, boolean isOutOfBand, byte[] appInfo, Capabilities capabilities, WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId)599 public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType, 600 int channel, byte[] peer, String interfaceName, 601 boolean isOutOfBand, byte[] appInfo, Capabilities capabilities, 602 WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId) { 603 if (mVerboseLoggingEnabled) { 604 Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId 605 + ", channelRequestType=" + channelRequestType + ", channel=" + channel 606 + ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName=" 607 + interfaceName + ", securityConfig=" + securityConfig 608 + ", isOutOfBand=" + isOutOfBand + ", appInfo.length=" 609 + ((appInfo == null) ? 0 : appInfo.length) + ", capabilities=" + capabilities); 610 } 611 recordTransactionId(transactionId); 612 613 WifiNanIface iface = mHal.getWifiNanIface(); 614 if (iface == null) { 615 Log.e(TAG, "initiateDataPath: null interface"); 616 return false; 617 } 618 619 try { 620 MacAddress peerMac = MacAddress.fromBytes(peer); 621 return iface.initiateDataPath(transactionId, peerId, channelRequestType, channel, 622 peerMac, interfaceName, isOutOfBand, appInfo, capabilities, securityConfig, 623 pubSubId); 624 } catch (IllegalArgumentException e) { 625 Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer)); 626 return false; 627 } 628 } 629 630 /** 631 * Responds to a data request from a peer. Security is provided by either PMK or Passphrase (not 632 * both) - if both are null then an open (unencrypted) link is set up. 633 * 634 * @param transactionId Transaction ID for the transaction - used in the async callback to 635 * match with the original request. 636 * @param accept Accept (true) or reject (false) the original call. 637 * @param ndpId The NDP (Aware data path) ID. Obtained from the request callback. 638 * @param interfaceName The interface on which the data path will be setup. Obtained from the 639 * request callback. 640 * @param appInfo Arbitrary binary blob transmitted to the peer. 641 * @param isOutOfBand Is the data-path out-of-band (i.e. without a corresponding Aware 642 * discovery 643 * session). 644 * @param capabilities The capabilities of the firmware. 645 * @param securityConfig Security config to encrypt the data-path 646 */ respondToDataPathRequest(short transactionId, boolean accept, int ndpId, String interfaceName, byte[] appInfo, boolean isOutOfBand, Capabilities capabilities, WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId)647 public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId, 648 String interfaceName, byte[] appInfo, 649 boolean isOutOfBand, Capabilities capabilities, 650 WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId) { 651 if (mVerboseLoggingEnabled) { 652 Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept=" 653 + accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName 654 + ", appInfo.length=" + ((appInfo == null) ? 0 : appInfo.length) 655 + ", securityConfig" + securityConfig); 656 } 657 recordTransactionId(transactionId); 658 659 WifiNanIface iface = mHal.getWifiNanIface(); 660 if (iface == null) { 661 Log.e(TAG, "respondToDataPathRequest: null interface"); 662 return false; 663 } 664 return iface.respondToDataPathRequest(transactionId, accept, ndpId, interfaceName, appInfo, 665 isOutOfBand, capabilities, securityConfig, pubSubId); 666 } 667 668 /** 669 * Terminate an existing data-path (does not delete the interface). 670 * 671 * @param transactionId Transaction ID for the transaction - used in the async callback to 672 * match with the original request. 673 * @param ndpId The NDP (Aware data path) ID to be terminated. 674 */ endDataPath(short transactionId, int ndpId)675 public boolean endDataPath(short transactionId, int ndpId) { 676 if (mVerboseLoggingEnabled) { 677 Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId); 678 } 679 recordTransactionId(transactionId); 680 681 WifiNanIface iface = mHal.getWifiNanIface(); 682 if (iface == null) { 683 Log.e(TAG, "endDataPath: null interface"); 684 return false; 685 } 686 return iface.endDataPath(transactionId, ndpId); 687 } 688 689 /** 690 * Terminate an existing pairing setup 691 * 692 * @param transactionId Transaction ID for the transaction - used in the async callback to 693 * match with the original request. 694 * @param pairId The id of the pairing session 695 */ endPairing(short transactionId, int pairId)696 public boolean endPairing(short transactionId, int pairId) { 697 if (mVerboseLoggingEnabled) { 698 Log.v(TAG, "endPairing: transactionId=" + transactionId + ", ndpId=" + pairId); 699 } 700 recordTransactionId(transactionId); 701 702 WifiNanIface iface = mHal.getWifiNanIface(); 703 if (iface == null) { 704 Log.e(TAG, "endDataPath: null interface"); 705 return false; 706 } 707 return iface.endPairing(transactionId, pairId); 708 } 709 710 /** 711 * Initiate a NAN pairing request for this publish/subscribe session 712 * 713 * @param transactionId Transaction ID for the transaction - used in the 714 * async callback to match with the original request. 715 * @param peerId ID of the peer. Obtained through previous communication (a 716 * match indication). 717 * @param pairingIdentityKey NAN identity key 718 * @param requestType Setup or verification 719 * @param pmk credential for the pairing verification 720 * @param password credential for the pairing setup 721 * @param akm Key exchange method is used for pairing 722 * @return True is the request send succeed. 723 */ initiatePairing(short transactionId, int peerId, byte[] peer, byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk, String password, int akm, int cipherSuite)724 public boolean initiatePairing(short transactionId, int peerId, byte[] peer, 725 byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk, 726 String password, int akm, int cipherSuite) { 727 if (mVerboseLoggingEnabled) { 728 Log.v(TAG, "initiatePairing: transactionId=" + transactionId + ", peerId=" + peerId 729 + ", requestType=" + requestType + ", enablePairingCache=" + enablePairingCache 730 + ", peer=" + String.valueOf(HexEncoding.encode(peer))); 731 } 732 recordTransactionId(transactionId); 733 734 WifiNanIface iface = mHal.getWifiNanIface(); 735 if (iface == null) { 736 Log.e(TAG, "initiatePairing: null interface"); 737 return false; 738 } 739 740 try { 741 MacAddress peerMac = MacAddress.fromBytes(peer); 742 return iface.initiatePairing(transactionId, peerId, peerMac, pairingIdentityKey, 743 enablePairingCache, requestType, pmk, password, akm, cipherSuite); 744 } catch (IllegalArgumentException e) { 745 Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer)); 746 return false; 747 } 748 } 749 750 /** 751 * Response to a NAN pairing request for this from this session 752 * 753 * @param transactionId Transaction ID for the transaction - used in the 754 * async callback to match with the original request. 755 * @param pairingId The id of the current pairing session 756 * @param accept True if accpect, false otherwise 757 * @param pairingIdentityKey NAN identity key 758 * @param requestType Setup or verification 759 * @param pmk credential for the pairing verification 760 * @param password credential for the pairing setup 761 * @param akm Key exchange method is used for pairing 762 * @return True is the request send succeed. 763 */ respondToPairingRequest(short transactionId, int pairingId, boolean accept, byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk, String password, int akm, int cipherSuite)764 public boolean respondToPairingRequest(short transactionId, int pairingId, boolean accept, 765 byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk, 766 String password, int akm, int cipherSuite) { 767 if (mVerboseLoggingEnabled) { 768 Log.v( 769 TAG, 770 "respondToPairingRequest: transactionId=" 771 + transactionId 772 + ", accept=" 773 + accept 774 + ", int pairingId=" 775 + pairingId 776 + ", enablePairingCache=" 777 + enablePairingCache 778 + ", requestType" 779 + requestType); 780 } 781 recordTransactionId(transactionId); 782 783 WifiNanIface iface = mHal.getWifiNanIface(); 784 if (iface == null) { 785 Log.e(TAG, "respondToPairingRequest: null interface"); 786 return false; 787 } 788 return iface.respondToPairingRequest(transactionId, pairingId, accept, pairingIdentityKey, 789 enablePairingCache, requestType, pmk, password, akm, cipherSuite); 790 } 791 792 /** 793 * Initiate a Bootstrapping request for this publish/subscribe session 794 * 795 * @param transactionId Transaction ID for the transaction - used in the 796 * async callback to match with the original request. 797 * @param peerId ID of the peer. Obtained through previous communication (a match 798 * indication). 799 * @param peer The MAC address of the peer to create a connection with. 800 * @param method proposed bootstrapping method 801 * @param pubSubId ID of the publish/subscribe session - obtained when creating a session. 802 * @param isComeBack If the request is for a previous comeback response 803 * @return True if the request send success 804 */ initiateBootstrapping(short transactionId, int peerId, byte[] peer, int method, byte[] cookie, byte pubSubId, boolean isComeBack)805 public boolean initiateBootstrapping(short transactionId, int peerId, byte[] peer, int method, 806 byte[] cookie, byte pubSubId, boolean isComeBack) { 807 if (mVerboseLoggingEnabled) { 808 Log.v(TAG, "initiateBootstrapping: transactionId=" + transactionId 809 + ", peerId=" + peerId + ", method=" + method 810 + ", peer=" + String.valueOf(HexEncoding.encode(peer))); 811 } 812 recordTransactionId(transactionId); 813 814 WifiNanIface iface = mHal.getWifiNanIface(); 815 if (iface == null) { 816 Log.e(TAG, "initiateBootstrapping: null interface"); 817 return false; 818 } 819 820 try { 821 MacAddress peerMac = MacAddress.fromBytes(peer); 822 return iface.initiateBootstrapping(transactionId, peerId, peerMac, method, cookie, 823 pubSubId, isComeBack); 824 } catch (IllegalArgumentException e) { 825 Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer)); 826 return false; 827 } 828 } 829 830 /** 831 * Response to a bootstrapping request for this from this session 832 * 833 * @param transactionId Transaction ID for the transaction - used in the 834 * async callback to match with the original request. 835 * @param bootstrappingId The id of the current boostraping session 836 * @param accept True is proposed method is accepte 837 * @param pubSubId ID of the publish/subscribe session - obtained when creating a 838 * session. 839 * @return True if the request send success 840 */ respondToBootstrappingRequest(short transactionId, int bootstrappingId, boolean accept, byte pubSubId)841 public boolean respondToBootstrappingRequest(short transactionId, int bootstrappingId, 842 boolean accept, byte pubSubId) { 843 if (mVerboseLoggingEnabled) { 844 Log.v(TAG, "respondToBootstrappingRequest: transactionId=" + transactionId); 845 } 846 recordTransactionId(transactionId); 847 848 WifiNanIface iface = mHal.getWifiNanIface(); 849 if (iface == null) { 850 Log.e(TAG, "respondToBootstrappingRequest: null interface"); 851 return false; 852 } 853 854 return iface.respondToBootstrappingRequest(transactionId, bootstrappingId, accept, 855 pubSubId); 856 } 857 858 /** 859 * Suspends the specified Aware session. 860 * @param transactionId transactionId Transaction ID for the transaction - 861 * used in the async callback to match with the original request. 862 * @param pubSubId ID of the existing publish/subscribe session. 863 * @return True if the request is sent successfully. 864 */ suspendRequest(short transactionId, byte pubSubId)865 public boolean suspendRequest(short transactionId, byte pubSubId) { 866 if (mVerboseLoggingEnabled) { 867 Log.v(TAG, "suspendRequest: transactionId=" + transactionId); 868 } 869 recordTransactionId(transactionId); 870 871 WifiNanIface iface = mHal.getWifiNanIface(); 872 if (iface == null) { 873 Log.e(TAG, "suspendRequest: null interface"); 874 return false; 875 } 876 877 return iface.suspendRequest(transactionId, pubSubId); 878 } 879 880 /** 881 * Resumes the specified (suspended) Aware session. 882 * @param transactionId transactionId Transaction ID for the transaction - 883 * used in the async callback to match with the original request. 884 * @param pubSubId ID of the existing publish/subscribe session. 885 * @return True if the request is sent successfully. 886 */ resumeRequest(short transactionId, byte pubSubId)887 public boolean resumeRequest(short transactionId, byte pubSubId) { 888 if (mVerboseLoggingEnabled) { 889 Log.v(TAG, "resumeRequest: transactionId=" + transactionId); 890 } 891 recordTransactionId(transactionId); 892 893 WifiNanIface iface = mHal.getWifiNanIface(); 894 if (iface == null) { 895 Log.e(TAG, "resumeRequest: null interface"); 896 return false; 897 } 898 899 return iface.resumeRequest(transactionId, pubSubId); 900 } 901 902 // utilities 903 904 /** 905 * Create a PowerParameters object to pass our cached parameters to the HAL. 906 */ getPowerParameters( boolean isInteractive, boolean isIdle)907 private PowerParameters getPowerParameters( 908 boolean isInteractive, boolean isIdle) { 909 PowerParameters params = new PowerParameters(); 910 String key = POWER_PARAM_DEFAULT_KEY; 911 if (isIdle) { 912 key = POWER_PARAM_IDLE_KEY; 913 } else if (!isInteractive) { 914 key = POWER_PARAM_INACTIVE_KEY; 915 } 916 917 params.discoveryWindow24Ghz = getSettablePowerParameters(key, PARAM_DW_24GHZ); 918 params.discoveryWindow5Ghz = getSettablePowerParameters(key, PARAM_DW_5GHZ); 919 params.discoveryWindow6Ghz = getSettablePowerParameters(key, PARAM_DW_6GHZ); 920 params.discoveryBeaconIntervalMs = getSettablePowerParameters(key, 921 PARAM_DISCOVERY_BEACON_INTERVAL_MS); 922 params.numberOfSpatialStreamsInDiscovery = getSettablePowerParameters(key, 923 PARAM_NUM_SS_IN_DISCOVERY); 924 params.enableDiscoveryWindowEarlyTermination = getSettablePowerParameters(key, 925 PARAM_ENABLE_DW_EARLY_TERM) != 0; 926 return params; 927 } 928 getSettablePowerParameters(String state, String key)929 private int getSettablePowerParameters(String state, String key) { 930 if (mExternalSetParams.containsKey(key)) { 931 return mExternalSetParams.get(key); 932 } 933 return mSettablePowerParameters.get(state).get(key); 934 } 935 936 /** 937 * Dump the internal state of the class. 938 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)939 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 940 pw.println("WifiAwareNativeApi:"); 941 pw.println(" mSettableParameters: " + mSettableParameters); 942 pw.println(" mExternalSetParams" + mExternalSetParams); 943 mHal.dump(fd, pw, args); 944 } 945 } 946