WifiAwareNativeApi.java revision ff05cbcaccc03d1f64d1cb232a3c40a664c4be57
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 17package com.android.server.wifi.aware; 18 19import android.hardware.wifi.V1_0.IWifiNanIface; 20import android.hardware.wifi.V1_0.NanBandIndex; 21import android.hardware.wifi.V1_0.NanBandSpecificConfig; 22import android.hardware.wifi.V1_0.NanCipherSuiteType; 23import android.hardware.wifi.V1_0.NanConfigRequest; 24import android.hardware.wifi.V1_0.NanDataPathSecurityType; 25import android.hardware.wifi.V1_0.NanEnableRequest; 26import android.hardware.wifi.V1_0.NanInitiateDataPathRequest; 27import android.hardware.wifi.V1_0.NanMatchAlg; 28import android.hardware.wifi.V1_0.NanPublishRequest; 29import android.hardware.wifi.V1_0.NanRespondToDataPathIndicationRequest; 30import android.hardware.wifi.V1_0.NanSubscribeRequest; 31import android.hardware.wifi.V1_0.NanTransmitFollowupRequest; 32import android.hardware.wifi.V1_0.NanTxType; 33import android.hardware.wifi.V1_0.WifiStatus; 34import android.hardware.wifi.V1_0.WifiStatusCode; 35import android.net.wifi.aware.ConfigRequest; 36import android.net.wifi.aware.PublishConfig; 37import android.net.wifi.aware.SubscribeConfig; 38import android.os.RemoteException; 39import android.util.Log; 40 41import libcore.util.HexEncoding; 42 43import java.io.FileDescriptor; 44import java.io.PrintWriter; 45import java.nio.charset.StandardCharsets; 46import java.util.ArrayList; 47 48/** 49 * Translates Wi-Fi Aware requests from the framework to the HAL (HIDL). 50 * 51 * Delegates the management of the NAN interface to WifiAwareNativeManager. 52 */ 53public class WifiAwareNativeApi { 54 private static final String TAG = "WifiAwareNativeApi"; 55 private static final boolean DBG = false; 56 private static final boolean VDBG = false; // STOPSHIP if true 57 58 private static final String SERVICE_NAME_FOR_OOB_DATA_PATH = "Wi-Fi Aware Data Path"; 59 60 private final WifiAwareNativeManager mHal; 61 62 public WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager) { 63 mHal = wifiAwareNativeManager; 64 } 65 66 /** 67 * Query the firmware's capabilities. 68 * 69 * @param transactionId Transaction ID for the transaction - used in the async callback to 70 * match with the original request. 71 */ 72 public boolean getCapabilities(short transactionId) { 73 if (VDBG) Log.v(TAG, "getCapabilities: transactionId=" + transactionId); 74 75 IWifiNanIface iface = mHal.getWifiNanIface(); 76 if (iface == null) { 77 Log.e(TAG, "getCapabilities: null interface"); 78 return false; 79 } 80 81 try { 82 WifiStatus status = iface.getCapabilitiesRequest(transactionId); 83 if (status.code == WifiStatusCode.SUCCESS) { 84 return true; 85 } else { 86 Log.e(TAG, "getCapabilities: error: " + statusString(status)); 87 return false; 88 } 89 } catch (RemoteException e) { 90 Log.e(TAG, "getCapabilities: exception: " + e); 91 return false; 92 } 93 } 94 95 /** 96 * Enable and configure Aware. 97 * 98 * @param transactionId Transaction ID for the transaction - used in the 99 * async callback to match with the original request. 100 * @param configRequest Requested Aware configuration. 101 * @param notifyIdentityChange Indicates whether or not to get address change callbacks. 102 * @param initialConfiguration Specifies whether initial configuration 103 * (true) or an update (false) to the configuration. 104 */ 105 public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest, 106 boolean notifyIdentityChange, boolean initialConfiguration) { 107 if (VDBG) { 108 Log.v(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest=" 109 + configRequest + ", notifyIdentityChange=" + notifyIdentityChange 110 + ", initialConfiguration=" + initialConfiguration); 111 } 112 113 IWifiNanIface iface = mHal.getWifiNanIface(); 114 if (iface == null) { 115 Log.e(TAG, "enableAndConfigure: null interface"); 116 return false; 117 } 118 119 try { 120 WifiStatus status; 121 if (initialConfiguration) { 122 // translate framework to HIDL configuration 123 NanEnableRequest req = new NanEnableRequest(); 124 125 req.operateInBand[NanBandIndex.NAN_BAND_24GHZ] = true; 126 req.operateInBand[NanBandIndex.NAN_BAND_5GHZ] = configRequest.mSupport5gBand; 127 req.hopCountMax = 2; 128 req.configParams.masterPref = (byte) configRequest.mMasterPreference; 129 req.configParams.disableDiscoveryAddressChangeIndication = !notifyIdentityChange; 130 req.configParams.disableStartedClusterIndication = !notifyIdentityChange; 131 req.configParams.disableJoinedClusterIndication = !notifyIdentityChange; 132 req.configParams.includePublishServiceIdsInBeacon = true; 133 req.configParams.numberOfPublishServiceIdsInBeacon = 0; 134 req.configParams.includeSubscribeServiceIdsInBeacon = true; 135 req.configParams.numberOfSubscribeServiceIdsInBeacon = 0; 136 req.configParams.rssiWindowSize = 8; 137 req.configParams.macAddressRandomizationIntervalSec = 1800; 138 139 NanBandSpecificConfig config24 = new NanBandSpecificConfig(); 140 config24.rssiClose = 60; 141 config24.rssiMiddle = 70; 142 config24.rssiCloseProximity = 60; 143 config24.dwellTimeMs = (byte) 200; 144 config24.scanPeriodSec = 20; 145 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ] 146 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 147 config24.validDiscoveryWindowIntervalVal = false; 148 } else { 149 config24.validDiscoveryWindowIntervalVal = true; 150 config24.discoveryWindowIntervalVal = 151 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 152 .NAN_BAND_24GHZ]; 153 } 154 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24; 155 156 NanBandSpecificConfig config5 = new NanBandSpecificConfig(); 157 config5.rssiClose = 60; 158 config5.rssiMiddle = 75; 159 config5.rssiCloseProximity = 60; 160 config5.dwellTimeMs = (byte) 200; 161 config5.scanPeriodSec = 20; 162 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] 163 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 164 config5.validDiscoveryWindowIntervalVal = false; 165 } else { 166 config5.validDiscoveryWindowIntervalVal = true; 167 config5.discoveryWindowIntervalVal = 168 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 169 .NAN_BAND_5GHZ]; 170 } 171 req.configParams.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; 172 173 req.debugConfigs.validClusterIdVals = true; 174 req.debugConfigs.clusterIdTopRangeVal = (short) configRequest.mClusterHigh; 175 req.debugConfigs.clusterIdBottomRangeVal = (short) configRequest.mClusterLow; 176 req.debugConfigs.validIntfAddrVal = false; 177 req.debugConfigs.validOuiVal = false; 178 req.debugConfigs.ouiVal = 0; 179 req.debugConfigs.validRandomFactorForceVal = false; 180 req.debugConfigs.randomFactorForceVal = 0; 181 req.debugConfigs.validHopCountForceVal = false; 182 req.debugConfigs.hopCountForceVal = 0; 183 req.debugConfigs.validDiscoveryChannelVal = false; 184 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_24GHZ] = 0; 185 req.debugConfigs.discoveryChannelMhzVal[NanBandIndex.NAN_BAND_5GHZ] = 0; 186 req.debugConfigs.validUseBeaconsInBandVal = false; 187 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; 188 req.debugConfigs.useBeaconsInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; 189 req.debugConfigs.validUseSdfInBandVal = false; 190 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_24GHZ] = true; 191 req.debugConfigs.useSdfInBandVal[NanBandIndex.NAN_BAND_5GHZ] = true; 192 193 status = iface.enableRequest(transactionId, req); 194 } else { 195 NanConfigRequest req = new NanConfigRequest(); 196 req.masterPref = (byte) configRequest.mMasterPreference; 197 req.disableDiscoveryAddressChangeIndication = !notifyIdentityChange; 198 req.disableStartedClusterIndication = !notifyIdentityChange; 199 req.disableJoinedClusterIndication = !notifyIdentityChange; 200 req.includePublishServiceIdsInBeacon = true; 201 req.numberOfPublishServiceIdsInBeacon = 0; 202 req.includeSubscribeServiceIdsInBeacon = true; 203 req.numberOfSubscribeServiceIdsInBeacon = 0; 204 req.rssiWindowSize = 8; 205 req.macAddressRandomizationIntervalSec = 1800; 206 207 NanBandSpecificConfig config24 = new NanBandSpecificConfig(); 208 config24.rssiClose = 60; 209 config24.rssiMiddle = 70; 210 config24.rssiCloseProximity = 60; 211 config24.dwellTimeMs = (byte) 200; 212 config24.scanPeriodSec = 20; 213 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ] 214 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 215 config24.validDiscoveryWindowIntervalVal = false; 216 } else { 217 config24.validDiscoveryWindowIntervalVal = true; 218 config24.discoveryWindowIntervalVal = 219 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 220 .NAN_BAND_24GHZ]; 221 } 222 req.bandSpecificConfig[NanBandIndex.NAN_BAND_24GHZ] = config24; 223 224 NanBandSpecificConfig config5 = new NanBandSpecificConfig(); 225 config5.rssiClose = 60; 226 config5.rssiMiddle = 75; 227 config5.rssiCloseProximity = 60; 228 config5.dwellTimeMs = (byte) 200; 229 config5.scanPeriodSec = 20; 230 if (configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] 231 == ConfigRequest.DW_INTERVAL_NOT_INIT) { 232 config5.validDiscoveryWindowIntervalVal = false; 233 } else { 234 config5.validDiscoveryWindowIntervalVal = true; 235 config5.discoveryWindowIntervalVal = 236 (byte) configRequest.mDiscoveryWindowInterval[ConfigRequest 237 .NAN_BAND_5GHZ]; 238 } 239 req.bandSpecificConfig[NanBandIndex.NAN_BAND_5GHZ] = config5; 240 241 status = iface.configRequest(transactionId, req); 242 } 243 if (status.code == WifiStatusCode.SUCCESS) { 244 return true; 245 } else { 246 Log.e(TAG, "enableAndConfigure: error: " + statusString(status)); 247 return false; 248 } 249 } catch (RemoteException e) { 250 Log.e(TAG, "enableAndConfigure: exception: " + e); 251 return false; 252 } 253 } 254 255 /** 256 * Disable Aware. 257 * 258 * @param transactionId transactionId Transaction ID for the transaction - 259 * used in the async callback to match with the original request. 260 */ 261 public boolean disable(short transactionId) { 262 if (VDBG) Log.d(TAG, "disable"); 263 264 IWifiNanIface iface = mHal.getWifiNanIface(); 265 if (iface == null) { 266 Log.e(TAG, "disable: null interface"); 267 return false; 268 } 269 270 try { 271 WifiStatus status = iface.disableRequest(transactionId); 272 if (status.code == WifiStatusCode.SUCCESS) { 273 return true; 274 } else { 275 Log.e(TAG, "disable: error: " + statusString(status)); 276 return false; 277 } 278 } catch (RemoteException e) { 279 Log.e(TAG, "disable: exception: " + e); 280 return false; 281 } 282 } 283 284 /** 285 * Start or modify a service publish session. 286 * 287 * @param transactionId transactionId Transaction ID for the transaction - 288 * used in the async callback to match with the original request. 289 * @param publishId ID of the requested session - 0 to request a new publish 290 * session. 291 * @param publishConfig Configuration of the discovery session. 292 */ 293 public boolean publish(short transactionId, int publishId, PublishConfig publishConfig) { 294 if (VDBG) { 295 Log.d(TAG, "publish: transactionId=" + transactionId + ", config=" + publishConfig); 296 } 297 298 IWifiNanIface iface = mHal.getWifiNanIface(); 299 if (iface == null) { 300 Log.e(TAG, "publish: null interface"); 301 return false; 302 } 303 304 NanPublishRequest req = new NanPublishRequest(); 305 req.baseConfigs.sessionId = 0; 306 req.baseConfigs.ttlSec = (short) publishConfig.mTtlSec; 307 req.baseConfigs.discoveryWindowPeriod = 1; 308 req.baseConfigs.discoveryCount = 0; 309 convertNativeByteArrayToArrayList(publishConfig.mServiceName, req.baseConfigs.serviceName); 310 // TODO: what's the right value on publish? 311 req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_ONCE; 312 convertNativeByteArrayToArrayList(publishConfig.mServiceSpecificInfo, 313 req.baseConfigs.serviceSpecificInfo); 314 convertNativeByteArrayToArrayList(publishConfig.mMatchFilter, 315 publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED 316 ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter); 317 req.baseConfigs.useRssiThreshold = false; 318 req.baseConfigs.disableDiscoveryTerminationIndication = 319 !publishConfig.mEnableTerminateNotification; 320 req.baseConfigs.disableMatchExpirationIndication = true; 321 req.baseConfigs.disableFollowupReceivedIndication = false; 322 323 // TODO: configure ranging and security 324 req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN; 325 req.baseConfigs.rangingRequired = false; 326 req.autoAcceptDataPathRequests = false; 327 328 req.publishType = publishConfig.mPublishType; 329 req.txType = NanTxType.BROADCAST; 330 331 try { 332 WifiStatus status = iface.startPublishRequest(transactionId, req); 333 if (status.code == WifiStatusCode.SUCCESS) { 334 return true; 335 } else { 336 Log.e(TAG, "publish: error: " + statusString(status)); 337 return false; 338 } 339 } catch (RemoteException e) { 340 Log.e(TAG, "publish: exception: " + e); 341 return false; 342 } 343 } 344 345 /** 346 * Start or modify a service subscription session. 347 * 348 * @param transactionId transactionId Transaction ID for the transaction - 349 * used in the async callback to match with the original request. 350 * @param subscribeId ID of the requested session - 0 to request a new 351 * subscribe session. 352 * @param subscribeConfig Configuration of the discovery session. 353 */ 354 public boolean subscribe(short transactionId, int subscribeId, 355 SubscribeConfig subscribeConfig) { 356 if (VDBG) { 357 Log.d(TAG, "subscribe: transactionId=" + transactionId + ", config=" + subscribeConfig); 358 } 359 360 IWifiNanIface iface = mHal.getWifiNanIface(); 361 if (iface == null) { 362 Log.e(TAG, "subscribe: null interface"); 363 return false; 364 } 365 366 NanSubscribeRequest req = new NanSubscribeRequest(); 367 req.baseConfigs.sessionId = 0; 368 req.baseConfigs.ttlSec = (short) subscribeConfig.mTtlSec; 369 req.baseConfigs.discoveryWindowPeriod = 1; 370 req.baseConfigs.discoveryCount = 0; 371 convertNativeByteArrayToArrayList(subscribeConfig.mServiceName, 372 req.baseConfigs.serviceName); 373 req.baseConfigs.discoveryMatchIndicator = NanMatchAlg.MATCH_ONCE; 374 convertNativeByteArrayToArrayList(subscribeConfig.mServiceSpecificInfo, 375 req.baseConfigs.serviceSpecificInfo); 376 convertNativeByteArrayToArrayList(subscribeConfig.mMatchFilter, 377 subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE 378 ? req.baseConfigs.txMatchFilter : req.baseConfigs.rxMatchFilter); 379 req.baseConfigs.useRssiThreshold = false; 380 req.baseConfigs.disableDiscoveryTerminationIndication = 381 !subscribeConfig.mEnableTerminateNotification; 382 req.baseConfigs.disableMatchExpirationIndication = true; 383 req.baseConfigs.disableFollowupReceivedIndication = false; 384 385 // TODO: configure ranging and security 386 req.baseConfigs.securityConfig.securityType = NanDataPathSecurityType.OPEN; 387 req.baseConfigs.rangingRequired = false; 388 389 req.subscribeType = subscribeConfig.mSubscribeType; 390 391 try { 392 WifiStatus status = iface.startSubscribeRequest(transactionId, req); 393 if (status.code == WifiStatusCode.SUCCESS) { 394 return true; 395 } else { 396 Log.e(TAG, "subscribe: error: " + statusString(status)); 397 return false; 398 } 399 } catch (RemoteException e) { 400 Log.e(TAG, "subscribe: exception: " + e); 401 return false; 402 } 403 } 404 405 /** 406 * Send a message through an existing discovery session. 407 * 408 * @param transactionId transactionId Transaction ID for the transaction - 409 * used in the async callback to match with the original request. 410 * @param pubSubId ID of the existing publish/subscribe session. 411 * @param requestorInstanceId ID of the peer to communicate with - obtained 412 * through a previous discovery (match) operation with that peer. 413 * @param dest MAC address of the peer to communicate with - obtained 414 * together with requestorInstanceId. 415 * @param message Message. 416 * @param messageId Arbitary integer from host (not sent to HAL - useful for 417 * testing/debugging at this level) 418 */ 419 public boolean sendMessage(short transactionId, int pubSubId, int requestorInstanceId, 420 byte[] dest, byte[] message, int messageId) { 421 if (VDBG) { 422 Log.d(TAG, 423 "sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId 424 + ", requestorInstanceId=" + requestorInstanceId + ", dest=" 425 + String.valueOf(HexEncoding.encode(dest)) + ", messageId=" 426 + messageId); 427 } 428 429 IWifiNanIface iface = mHal.getWifiNanIface(); 430 if (iface == null) { 431 Log.e(TAG, "sendMessage: null interface"); 432 return false; 433 } 434 435 NanTransmitFollowupRequest req = new NanTransmitFollowupRequest(); 436 req.discoverySessionId = (byte) pubSubId; 437 req.peerId = requestorInstanceId; 438 copyArray(dest, req.addr); 439 req.isHighPriority = false; 440 req.shouldUseDiscoveryWindow = true; 441 convertNativeByteArrayToArrayList(message, req.serviceSpecificInfo); 442 req.disableFollowupResultIndication = false; 443 444 try { 445 WifiStatus status = iface.transmitFollowupRequest(transactionId, req); 446 if (status.code == WifiStatusCode.SUCCESS) { 447 return true; 448 } else { 449 Log.e(TAG, "sendMessage: error: " + statusString(status)); 450 return false; 451 } 452 } catch (RemoteException e) { 453 Log.e(TAG, "sendMessage: exception: " + e); 454 return false; 455 } 456 } 457 458 /** 459 * Terminate a publish discovery session. 460 * 461 * @param transactionId transactionId Transaction ID for the transaction - 462 * used in the async callback to match with the original request. 463 * @param pubSubId ID of the publish/subscribe session - obtained when 464 * creating a session. 465 */ 466 public boolean stopPublish(short transactionId, int pubSubId) { 467 if (VDBG) { 468 Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 469 } 470 471 IWifiNanIface iface = mHal.getWifiNanIface(); 472 if (iface == null) { 473 Log.e(TAG, "stopPublish: null interface"); 474 return false; 475 } 476 477 try { 478 WifiStatus status = iface.stopPublishRequest(transactionId, (byte) pubSubId); 479 if (status.code == WifiStatusCode.SUCCESS) { 480 return true; 481 } else { 482 Log.e(TAG, "stopPublish: error: " + statusString(status)); 483 return false; 484 } 485 } catch (RemoteException e) { 486 Log.e(TAG, "stopPublish: exception: " + e); 487 return false; 488 } 489 } 490 491 /** 492 * Terminate a subscribe discovery session. 493 * 494 * @param transactionId transactionId Transaction ID for the transaction - 495 * used in the async callback to match with the original request. 496 * @param pubSubId ID of the publish/subscribe session - obtained when 497 * creating a session. 498 */ 499 public boolean stopSubscribe(short transactionId, int pubSubId) { 500 if (VDBG) { 501 Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId); 502 } 503 504 IWifiNanIface iface = mHal.getWifiNanIface(); 505 if (iface == null) { 506 Log.e(TAG, "stopSubscribe: null interface"); 507 return false; 508 } 509 510 try { 511 WifiStatus status = iface.stopSubscribeRequest(transactionId, (byte) pubSubId); 512 if (status.code == WifiStatusCode.SUCCESS) { 513 return true; 514 } else { 515 Log.e(TAG, "stopSubscribe: error: " + statusString(status)); 516 return false; 517 } 518 } catch (RemoteException e) { 519 Log.e(TAG, "stopSubscribe: exception: " + e); 520 return false; 521 } 522 } 523 524 /** 525 * Create a Aware network interface. This only creates the Linux interface - it doesn't actually 526 * create the data connection. 527 * 528 * @param transactionId Transaction ID for the transaction - used in the async callback to 529 * match with the original request. 530 * @param interfaceName The name of the interface, e.g. "aware0". 531 */ 532 public boolean createAwareNetworkInterface(short transactionId, String interfaceName) { 533 if (VDBG) { 534 Log.v(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", " 535 + "interfaceName=" + interfaceName); 536 } 537 538 IWifiNanIface iface = mHal.getWifiNanIface(); 539 if (iface == null) { 540 Log.e(TAG, "createAwareNetworkInterface: null interface"); 541 return false; 542 } 543 544 try { 545 WifiStatus status = iface.createDataInterfaceRequest(transactionId, interfaceName); 546 if (status.code == WifiStatusCode.SUCCESS) { 547 return true; 548 } else { 549 Log.e(TAG, "createAwareNetworkInterface: error: " + statusString(status)); 550 return false; 551 } 552 } catch (RemoteException e) { 553 Log.e(TAG, "createAwareNetworkInterface: exception: " + e); 554 return false; 555 } 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 */ 565 public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) { 566 if (VDBG) { 567 Log.v(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", " 568 + "interfaceName=" + interfaceName); 569 } 570 571 IWifiNanIface iface = mHal.getWifiNanIface(); 572 if (iface == null) { 573 Log.e(TAG, "deleteAwareNetworkInterface: null interface"); 574 return false; 575 } 576 577 try { 578 WifiStatus status = iface.deleteDataInterfaceRequest(transactionId, interfaceName); 579 if (status.code == WifiStatusCode.SUCCESS) { 580 return true; 581 } else { 582 Log.e(TAG, "deleteAwareNetworkInterface: error: " + statusString(status)); 583 return false; 584 } 585 } catch (RemoteException e) { 586 Log.e(TAG, "deleteAwareNetworkInterface: exception: " + e); 587 return false; 588 } 589 } 590 591 /** 592 * Initiates setting up a data-path between device and peer. Security is provided by either 593 * PMK or Passphrase (not both) - if both are null then an open (unencrypted) link is set up. 594 * 595 * @param transactionId Transaction ID for the transaction - used in the async callback to 596 * match with the original request. 597 * @param peerId ID of the peer ID to associate the data path with. A value of 0 598 * indicates that not associated with an existing session. 599 * @param channelRequestType Indicates whether the specified channel is available, if available 600 * requested or forced (resulting in failure if cannot be 601 * accommodated). 602 * @param channel The channel on which to set up the data-path. 603 * @param peer The MAC address of the peer to create a connection with. 604 * @param interfaceName The interface on which to create the data connection. 605 * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path. 606 * @param passphrase Passphrase for the data-path. 607 * @param capabilities The capabilities of the firmware. 608 */ 609 public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType, 610 int channel, byte[] peer, String interfaceName, byte[] pmk, String passphrase, 611 boolean isOutOfBand, Capabilities capabilities) { 612 if (VDBG) { 613 Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId 614 + ", channelRequestType=" + channelRequestType + ", channel=" + channel 615 + ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName=" 616 + interfaceName); 617 } 618 619 IWifiNanIface iface = mHal.getWifiNanIface(); 620 if (iface == null) { 621 Log.e(TAG, "initiateDataPath: null interface"); 622 return false; 623 } 624 625 if (capabilities == null) { 626 Log.e(TAG, "initiateDataPath: null capabilities"); 627 return false; 628 } 629 630 NanInitiateDataPathRequest req = new NanInitiateDataPathRequest(); 631 req.peerId = peerId; 632 copyArray(peer, req.peerDiscMacAddr); 633 req.channelRequestType = channelRequestType; 634 req.channel = channel; 635 req.ifaceName = interfaceName; 636 req.securityConfig.securityType = NanDataPathSecurityType.OPEN; 637 if (pmk != null && pmk.length != 0) { 638 req.securityConfig.cipherType = getStrongestCipherSuiteType( 639 capabilities.supportedCipherSuites); 640 req.securityConfig.securityType = NanDataPathSecurityType.PMK; 641 copyArray(pmk, req.securityConfig.pmk); 642 } 643 if (passphrase != null && passphrase.length() != 0) { 644 req.securityConfig.cipherType = getStrongestCipherSuiteType( 645 capabilities.supportedCipherSuites); 646 req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE; 647 convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase); 648 649 if (isOutOfBand) { // only relevant when using passphrase 650 convertNativeByteArrayToArrayList( 651 SERVICE_NAME_FOR_OOB_DATA_PATH.getBytes(StandardCharsets.UTF_8), 652 req.serviceNameOutOfBand); 653 } 654 } 655 656 try { 657 WifiStatus status = iface.initiateDataPathRequest(transactionId, req); 658 if (status.code == WifiStatusCode.SUCCESS) { 659 return true; 660 } else { 661 Log.e(TAG, "initiateDataPath: error: " + statusString(status)); 662 return false; 663 } 664 } catch (RemoteException e) { 665 Log.e(TAG, "initiateDataPath: exception: " + e); 666 return false; 667 } 668 } 669 670 /** 671 * Responds to a data request from a peer. Security is provided by either PMK or Passphrase (not 672 * both) - if both are null then an open (unencrypted) link is set up. 673 * 674 * @param transactionId Transaction ID for the transaction - used in the async callback to 675 * match with the original request. 676 * @param accept Accept (true) or reject (false) the original call. 677 * @param ndpId The NDP (Aware data path) ID. Obtained from the request callback. 678 * @param interfaceName The interface on which the data path will be setup. Obtained from the 679 * request callback. 680 * @param pmk Pairwise master key (PMK - see IEEE 802.11i) for the data-path. 681 * @param passphrase Passphrase for the data-path. 682 * @param capabilities The capabilities of the firmware. 683 */ 684 public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId, 685 String interfaceName, byte[] pmk, String passphrase, Capabilities capabilities) { 686 if (VDBG) { 687 Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept=" 688 + accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName); 689 } 690 691 IWifiNanIface iface = mHal.getWifiNanIface(); 692 if (iface == null) { 693 Log.e(TAG, "respondToDataPathRequest: null interface"); 694 return false; 695 } 696 697 if (capabilities == null) { 698 Log.e(TAG, "initiateDataPath: null capabilities"); 699 return false; 700 } 701 702 NanRespondToDataPathIndicationRequest req = new NanRespondToDataPathIndicationRequest(); 703 req.acceptRequest = accept; 704 req.ndpInstanceId = ndpId; 705 req.ifaceName = interfaceName; 706 req.securityConfig.securityType = NanDataPathSecurityType.OPEN; 707 if (pmk != null && pmk.length != 0) { 708 req.securityConfig.cipherType = getStrongestCipherSuiteType( 709 capabilities.supportedCipherSuites); 710 req.securityConfig.securityType = NanDataPathSecurityType.PMK; 711 copyArray(pmk, req.securityConfig.pmk); 712 } 713 if (passphrase != null && passphrase.length() != 0) { 714 req.securityConfig.cipherType = getStrongestCipherSuiteType( 715 capabilities.supportedCipherSuites); 716 req.securityConfig.securityType = NanDataPathSecurityType.PASSPHRASE; 717 convertNativeByteArrayToArrayList(passphrase.getBytes(), req.securityConfig.passphrase); 718 } 719 720 try { 721 WifiStatus status = iface.respondToDataPathIndicationRequest(transactionId, req); 722 if (status.code == WifiStatusCode.SUCCESS) { 723 return true; 724 } else { 725 Log.e(TAG, "respondToDataPathRequest: error: " + statusString(status)); 726 return false; 727 } 728 } catch (RemoteException e) { 729 Log.e(TAG, "respondToDataPathRequest: exception: " + e); 730 return false; 731 } 732 } 733 734 /** 735 * Terminate an existing data-path (does not delete the interface). 736 * 737 * @param transactionId Transaction ID for the transaction - used in the async callback to 738 * match with the original request. 739 * @param ndpId The NDP (Aware data path) ID to be terminated. 740 */ 741 public boolean endDataPath(short transactionId, int ndpId) { 742 if (VDBG) { 743 Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId); 744 } 745 746 IWifiNanIface iface = mHal.getWifiNanIface(); 747 if (iface == null) { 748 Log.e(TAG, "endDataPath: null interface"); 749 return false; 750 } 751 752 try { 753 WifiStatus status = iface.terminateDataPathRequest(transactionId, ndpId); 754 if (status.code == WifiStatusCode.SUCCESS) { 755 return true; 756 } else { 757 Log.e(TAG, "endDataPath: error: " + statusString(status)); 758 return false; 759 } 760 } catch (RemoteException e) { 761 Log.e(TAG, "endDataPath: exception: " + e); 762 return false; 763 } 764 } 765 766 767 // utilities 768 769 /** 770 * Returns the strongest supported cipher suite. 771 * 772 * Baseline is very simple: 256 > 128 > 0. 773 */ 774 private int getStrongestCipherSuiteType(int supportedCipherSuites) { 775 if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_256_MASK) != 0) { 776 return NanCipherSuiteType.SHARED_KEY_256_MASK; 777 } 778 if ((supportedCipherSuites & NanCipherSuiteType.SHARED_KEY_128_MASK) != 0) { 779 return NanCipherSuiteType.SHARED_KEY_128_MASK; 780 } 781 return NanCipherSuiteType.NONE; 782 } 783 784 /** 785 * Converts a byte[] to an ArrayList<Byte>. Fills in the entries of the 'to' array if 786 * provided (non-null), otherwise creates and returns a new ArrayList<>. 787 * 788 * @param from The input byte[] to convert from. 789 * @param to An optional ArrayList<> to fill in from 'from'. 790 * 791 * @return A newly allocated ArrayList<> if 'to' is null, otherwise null. 792 */ 793 private ArrayList<Byte> convertNativeByteArrayToArrayList(byte[] from, ArrayList<Byte> to) { 794 if (from == null) { 795 from = new byte[0]; 796 } 797 798 if (to == null) { 799 to = new ArrayList<>(from.length); 800 } else { 801 to.ensureCapacity(from.length); 802 } 803 for (int i = 0; i < from.length; ++i) { 804 to.add(from[i]); 805 } 806 return to; 807 } 808 809 private void copyArray(byte[] from, byte[] to) { 810 if (from == null || to == null || from.length != to.length) { 811 Log.e(TAG, "copyArray error: from=" + from + ", to=" + to); 812 return; 813 } 814 for (int i = 0; i < from.length; ++i) { 815 to[i] = from[i]; 816 } 817 } 818 819 private static String statusString(WifiStatus status) { 820 if (status == null) { 821 return "status=null"; 822 } 823 StringBuilder sb = new StringBuilder(); 824 sb.append(status.code).append(" (").append(status.description).append(")"); 825 return sb.toString(); 826 } 827 828 /** 829 * Dump the internal state of the class. 830 */ 831 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 832 mHal.dump(fd, pw, args); 833 } 834} 835